diff --git a/.gitignore b/.gitignore index f76cd666..6c639861 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.exe *.c *.go +*.orig # Visual Studio Code debug diff --git a/Build/Readme.md b/Build/Readme.md new file mode 100644 index 00000000..6d25d3cb --- /dev/null +++ b/Build/Readme.md @@ -0,0 +1,8 @@ +verpatch.exe is an amazing tool to change resource information in EXEs and DLLs + +https://github.com/pavel-a/ddverpatch/releases + +Call like this +``` +verpatch.exe ..\act.exe /high /va 1.5.0 /pv "1.5.0-RC1+buildnumber-5" /s copyright "(c) 2018-2019 ACT Developers" /s desc "ACT is a code generator for software components" /s productName "Automatic Component Toolkit" +``` \ No newline at end of file diff --git a/Build/build.bat b/Build/build.bat index 3605d641..3f037b3f 100644 --- a/Build/build.bat +++ b/Build/build.bat @@ -3,7 +3,7 @@ set startingDir="%CD%" set basepath="%~dp0" cd %basepath%\..\Source -set Sources=actutils.go automaticcomponenttoolkit.go buildbindingcdynamic.go buildbindingcpp.go buildbindinggo.go buildbindingnode.go buildbindingpascal.go buildbindingpython.go buildimplementationcpp.go buildimplementationpascal.go componentdefinition.go componentdiff.go languagewriter.go languagec.go languagepascal.go +set Sources=actutils.go automaticcomponenttoolkit.go buildbindingccpp.go buildbindingcsharp.go buildbindinggo.go buildbindingnode.go buildbindingpascal.go buildbindingpython.go buildimplementationcpp.go buildimplementationpascal.go componentdefinition.go componentdiff.go languagewriter.go languagec.go languagecpp.go languagepascal.go set GOARCH=amd64 set GOOS=windows diff --git a/Build/build.sh b/Build/build.sh index ab329b5b..297da6e6 100644 --- a/Build/build.sh +++ b/Build/build.sh @@ -4,7 +4,7 @@ startingpath="$(pwd)" basepath="$(cd "$(dirname "$0")" && pwd)" cd "$basepath/../Source" -Sources="actutils.go automaticcomponenttoolkit.go buildbindingcdynamic.go buildbindingcpp.go buildbindinggo.go buildbindingnode.go buildbindingpascal.go buildbindingpython.go buildimplementationcpp.go buildimplementationpascal.go componentdefinition.go componentdiff.go languagewriter.go languagec.go languagepascal.go" +Sources="actutils.go automaticcomponenttoolkit.go buildbindingccpp.go buildbindingcsharp.go buildbindinggo.go buildbindingnode.go buildbindingpascal.go buildbindingpython.go buildimplementationcpp.go buildimplementationpascal.go componentdefinition.go componentdiff.go languagewriter.go languagec.go languagecpp.go languagepascal.go" GOARCH="amd64" echo "Build act.exe" diff --git a/Build/verpatch.exe b/Build/verpatch.exe new file mode 100644 index 00000000..9e4c42cd Binary files /dev/null and b/Build/verpatch.exe differ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb2384eb..9f279ce8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Contributions are welcome and we are looking for people that can improve existin You can also contribute by reporting bugs in the [Issue tracker](../../issues), helping review pull requests, participate in discussions about issues and more. ## Filing issues -1. When filing an issue to report errors or problems, make sure to answer these five questions: +1. When filing an [issue](../../issues) to report errors or problems, make sure to answer these five questions: 1. Which version of ACT are you using? Run
`act.* -v`
to print ACT's version. 2. Which operating system, programming language(s) and development tools (compiler/interpreter) are you using? diff --git a/Documentation/IDL.md b/Documentation/IDL.md index f772b850..94a90418 100644 --- a/Documentation/IDL.md +++ b/Documentation/IDL.md @@ -4,7 +4,7 @@ -| **Version** | 1.3.2 | +| **Version** | 1.5.0 | | --- | --- | ## Disclaimer @@ -76,10 +76,13 @@ Element **\** of type **CT\_Component** | namespace | **ST\_NameSpace** | required | | Specifies the namespace for the components's functionality. | | copyright | **xs:string** | required | | The legal copyright holder. | | basename | **ST\_BaseName** | required | | The basename will be used as prefix for generated filenames and all sorts of identifiers in the generated source code. | -| version | **ST\_Version** | required | | The three digit vesion of this component. | +| version | **ST\_Version** | required | | The semantic version of this component. | | year | **ST\_Year** | optional | the current year | The year associcated with the copyright. | | @anyAttribute | | | | | +It is RECOMMENDED that components generated with ACT follow the [semantic versioning scheme](https://semver.org/). +The "version" attribute encodes the semantic version of this component. Major, Minor and Micro-version info MUST be included. Pre-release information and build information MAY be included. + The \ element is the root element of a ACT-IDL file. There MUST be exactly one \ element in a ACT-IDL file. A component MUST have exactly one child [license](#2-license) element, @@ -147,7 +150,7 @@ of type **CT\_Export** | language | **ST\_Language** | required | | The programming langugage of this export. | | indentation | **ST\_Indentation** | optional | 4spaces | Which string should be used to denote a single level of indentation in the generated source code files. | | stubidentifier | **ST\_StubIdentifier** | optional | "" | Generated sources files of this export will follow the naming schme "...${BaseName}_${stubidentifier}...". Only used in \ right now. | -| classidentifier | **ST\_ClassIdentifier** | optional | "" | Generated classes of this export will follow the naming schme "...${ClassIdentifier}${NameSpace}_${ClassName}...". Only used in \ right now. | +| classidentifier | **ST\_ClassIdentifier** | optional | "" | Generated classes of this export will follow the naming schme "...${ClassIdentifier}_${ClassName}...". The only binding that supports this are the C++-bindings.| ## 7. Global Element **\** of type **CT\_Global** @@ -157,18 +160,38 @@ Element **\** of type **CT\_Global** ##### Attributes | Name | Type | Use | Default | Annotation | | --- | --- | --- | --- | --- | +| baseclassname | **ST\_Name** | required | | Specifies the name of a class that is the base class for all classes of the generated component. | | releasemethod | **ST\_Name** | required | | Specifies the name of the method used to release a class instance owned by the generated component. | -| versionmethod | **ST\_Name** | required | | Specifies the name of the method used to obtain the semantic version of the component. | +| versionmethod | **ST\_Name** | required | | Specifies the name of the method used to obtain the major, minor and micro version of the component. | +| prereleasemethod | **ST\_Name** | required | | Specifies the name of the method used to obtain the prerelease information of the component. | +| buildinfomethod | **ST\_Name** | required | | Specifies the name of the method used to obtain the build information of the component. | +| errormethod | **ST\_Name** | required | | Specifies the name of the method used to query the last error that occured during the call of class's method. | | journalmethod | **ST\_Name** | optional | | Specifies the name of the method used to set the journal file. If ommitted, journalling will not be built into the component. | The \ element contains a list of [method](#9-function-type) elements that define the exported global functions of the component. The names of the \ elements MUST be unique within the \ element. -The `releasemethod`-attribute must be the name of a \ within the \ element of a method that has exactly one parameter with `type="handle"`, `class="BaseClass"` and `pass="in"`. -The `versionmethod`-attribute must be the name of a \ within the \ element of a method that has exactly three parameters with `type="uint32"` and `pass="out"`. +The `baseclassname`-attribute must be the name of a \ element within the components list of classes. +This class will be the base class for all classes of the generated component. + +The `releasemethod`-attribute must be the name of a \ within the \ element of a component that has exactly one parameter with `type="class"`, `class="BaseClass"` and `pass="in"`. +The `versionmethod`-attribute must be the name of a \ within the \ element of a component that has exactly three parameters. The three parameters MUST be of type `type="uint32"` and `pass="out"`. +The `prereleasemethod`-attribute is optional an can be the name of a \ within the \ element of a component that has two parameters. +The first parameter MUST be of type `type="bool"` and `pass="return"`, the second parameter MUST be of type `type="string"` and `pass="out"`. +The `buildinfomethod`-attribute is optional an can be the name of a \ within the \ element of a component that has two parameters. +The first parameter MUST be of type `type="bool"` and `pass="return"`, the second parameter MUST be of type `type="string"` and `pass="out"`. + + +The `errormethod`-attribute must be the name of a \ within the \ element of a method that has exactly three parameters: +1. `type="class"`, `class="$BASECLASSNAME"` and `pass="in"`, where `"$BASECLASSNAME"` is the value of the `baseclassname` attribute of the \ element. +2. `type="string"` and `pass="out"`: outputs the last error message +3. `type="bool"` and `pass="return"`: returns the instance of the baseclass has an error. If the `journalmethod` attribute is given, it must be the name of a \ within the \ element of a method that has exactly one parameter with `type="string"` and `pass="in"`. + **Note** + `type="handle"` is equivalent to `type="class"` for backwards compatibility. It will be removed in a later version. + ## 8. Class Element **\** of type **CT\_Class** @@ -184,6 +207,10 @@ Element **\** of type **CT\_Class** The \ element contains a list of [method](#9-function-type) elements that define the exported member functions of this class. The names of the \ elements MUST be unique in this list. +If the `parent`-attribute is empty, and the name of this class differs from the `baseclassname`-attribute of the \ element, `baseclassname` will be considered as the parent class of this class. + +A class MUST be defined in the list of \ elements before it is used as parent-class of another class. This restiction rules out circular inheritance. Moreover, the default `baseclassname` MUST be defined as the first \ within the IDL-file. + ## 9. Function Type Element **\**
@@ -293,6 +320,9 @@ Element **\** of type **CT\_ErrorList** The \ element contains a list of [\](#16-error) elements. The names and codes of the \ elements in this list MUST be unique within the \ element. +Each ACT-component MUST contain at least the following 8 error codes: + +`NOTIMPLEMENTED`, `INVALIDPARAM`, `INVALIDCAST`, `BUFFERTOOSMALL`, `GENERICEXCEPTION`, `COULDNOTLOADLIBRARY`, `COULDNOTFINDLIBRARYEXPORT`, `INCOMPATIBLEBINARYVERSION` ## 16. Error Element **\** of type **CT\_Error** @@ -312,18 +342,41 @@ The simple types of this specification encode features, concepts, data types, and naming rules used in or required by programming languages. For now, please look the up in the [ACT.xsd](../Source/ACT.xsd). -TODO: add all simple types here. ### 17.1 Type -ST_Type `string` denotes a null-terminated string. If a component requires arbitrary strings that can contain null-characters, on should use the type `basicarray` of class `uint8`. +Supported types are: +- `bool`: denotes a boolean value (`true` or `false`). +Although this can be encoded in a single bit, the thin C89-layer APIs generated by ACT will use an unsigned 8 bit value (a `uint8` in ACT terms) to encode a boolean value. +A numerical value of `0` encodes `false`, all oher values encode `true`. +Implementations and bindings should use the definition of a boolean value that is native to the respective language of the implementation or binding. +- `uint8`, `uint16`, `uint32`, `uint64`: +An _unsigned_ integer vaules ranging from 0 - 28-1, 0 - 216-1, 0 - 232-1, 0 - 264-1, respectively. +- `int8`, `int16`, `int32`, `int64`: +A _signed_ integer vaules ranging from -27 - 27-1, -215 - 215-1, +-231 - 231-1, +-263 - 263-1, respectively. +- `pointer`: An address in memory without knowledge of the kind of data that resides there. In C++, this corresponds to a `void*`. +- `string` denotes a null-terminated string. If a component requires arbitrary strings that can contain null-characters, one should use the type `basicarray` of class `uint8`. +- `single`: Single precision floating point number. +- `double`: Double precision floating point number. +- `struct`: see [13. Struct](#13-struct) +- `enum`: see [11. Enum](#11-enum) +- `basicarray`: an array of [ST\_ScalarTypes](#17-2-scalartype) +- `enumarray`: an array of [enums](#11-enum) +- `structarray`: an array of [structs](#13-struct) +- `handle`: the identifier (address, unique identifier, hash, ...) of a class instance [class instance](#8-class) +- `functiontype`: see [9. Function Type](#9-function-type) ### 17.2 ScalarType -ST_ScalarType `bool` denotes a boolean value (`true` or `false`). -Although this can be encoded in a single bit, the thin C89-layer APIs generated by ACT will use a unsigned 8 bit value (a `uint8` in ACT terms) to encode a boolean value. -A numerical value of `0` encodes `false`, all oher values encode `true`. -Implementations and bindings should use the definition of a boolean value native to the respective language of the implementation or binding. +A subset of scalar or integral of ST\_Type: + +`bool`, `uint8`, `uint16`, `uint32`, `uint64`, `int8`, `int16`, `int32`, `int64`, `single`, `double`, `pointer`. ### 17.3 ComposedType +A subset of more complex types, or types composed of other ST\_Types: + +`string`, `enum`, `basicarray`, `enumarray`, `structarray`, `handle`, `functiontype` + ### 17.4 Name ### 17.5 Description ### 17.6 ErrorName diff --git a/Documentation/images/element_global.png b/Documentation/images/element_global.png index 4931fd68..0204cd42 100644 Binary files a/Documentation/images/element_global.png and b/Documentation/images/element_global.png differ diff --git a/Examples/Primes/LibPrimes_component/Bindings/CSharp/LibPrimes.cs b/Examples/Primes/LibPrimes_component/Bindings/CSharp/LibPrimes.cs new file mode 100644 index 00000000..8f3b4c45 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Bindings/CSharp/LibPrimes.cs @@ -0,0 +1,279 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace LibPrimes { + + public struct sPrimeFactor + { + public UInt64 Prime; + public UInt32 Multiplicity; + } + + + namespace Internal { + + [StructLayout(LayoutKind.Explicit, Size=12)] + public unsafe struct InternalPrimeFactor + { + [FieldOffset(0)] public UInt64 Prime; + [FieldOffset(8)] public UInt32 Multiplicity; + } + + + public class LibPrimesWrapper + { + [DllImport("libprimes.dll", EntryPoint = "libprimes_calculator_getvalue", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 Calculator_GetValue (IntPtr Handle, out UInt64 AValue); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_calculator_setvalue", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 Calculator_SetValue (IntPtr Handle, UInt64 AValue); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_calculator_calculate", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 Calculator_Calculate (IntPtr Handle); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_calculator_setprogresscallback", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 Calculator_SetProgressCallback (IntPtr Handle, IntPtr AProgressCallback); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_factorizationcalculator_getprimefactors", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 FactorizationCalculator_GetPrimeFactors (IntPtr Handle, UInt64 sizePrimeFactors, out UInt64 neededPrimeFactors, IntPtr dataPrimeFactors); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_sievecalculator_getprimes", CallingConvention=CallingConvention.Cdecl)] + public unsafe extern static Int32 SieveCalculator_GetPrimes (IntPtr Handle, UInt64 sizePrimes, out UInt64 neededPrimes, IntPtr dataPrimes); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_getversion", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 GetVersion (out UInt32 AMajor, out UInt32 AMinor, out UInt32 AMicro); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_getlasterror", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 GetLastError (IntPtr AInstance, UInt32 sizeErrorMessage, out UInt32 neededErrorMessage, IntPtr dataErrorMessage, out Byte AHasError); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_releaseinstance", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 ReleaseInstance (IntPtr AInstance); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_createfactorizationcalculator", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 CreateFactorizationCalculator (out IntPtr AInstance); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_createsievecalculator", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 CreateSieveCalculator (out IntPtr AInstance); + + [DllImport("libprimes.dll", EntryPoint = "libprimes_setjournal", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] + public extern static Int32 SetJournal (byte[] AFileName); + + public unsafe static sPrimeFactor convertInternalToStruct_PrimeFactor (InternalPrimeFactor intPrimeFactor) + { + sPrimeFactor PrimeFactor; + PrimeFactor.Prime = intPrimeFactor.Prime; + PrimeFactor.Multiplicity = intPrimeFactor.Multiplicity; + return PrimeFactor; + } + + public unsafe static InternalPrimeFactor convertStructToInternal_PrimeFactor (sPrimeFactor PrimeFactor) + { + InternalPrimeFactor intPrimeFactor; + intPrimeFactor.Prime = PrimeFactor.Prime; + intPrimeFactor.Multiplicity = PrimeFactor.Multiplicity; + return intPrimeFactor; + } + + public static void ThrowError(IntPtr Handle, Int32 errorCode) + { + String sMessage = "LibPrimes Error"; + if (Handle != IntPtr.Zero) { + UInt32 sizeMessage = 0; + UInt32 neededMessage = 0; + Byte hasLastError = 0; + Int32 resultCode1 = GetLastError (Handle, sizeMessage, out neededMessage, IntPtr.Zero, out hasLastError); + if ((resultCode1 == 0) && (hasLastError != 0)) { + sizeMessage = neededMessage + 1; + byte[] bytesMessage = new byte[sizeMessage]; + + GCHandle dataMessage = GCHandle.Alloc(bytesMessage, GCHandleType.Pinned); + Int32 resultCode2 = GetLastError(Handle, sizeMessage, out neededMessage, dataMessage.AddrOfPinnedObject(), out hasLastError); + dataMessage.Free(); + + if ((resultCode2 == 0) && (hasLastError != 0)) { + sMessage = sMessage + ": " + Encoding.UTF8.GetString(bytesMessage).TrimEnd(char.MinValue); + } + } + } + + throw new Exception(sMessage + "(# " + errorCode + ")"); + } + + } + } + + + class CBase + { + protected IntPtr Handle; + + public CBase (IntPtr NewHandle) + { + Handle = NewHandle; + } + + ~CBase () + { + if (Handle != IntPtr.Zero) { + Internal.LibPrimesWrapper.ReleaseInstance (Handle); + Handle = IntPtr.Zero; + } + } + + protected void CheckError (Int32 errorCode) + { + if (errorCode != 0) { + Internal.LibPrimesWrapper.ThrowError (Handle, errorCode); + } + } + + public IntPtr GetHandle () + { + return Handle; + } + + } + + class CCalculator : CBase + { + public CCalculator (IntPtr NewHandle) : base (NewHandle) + { + } + + public UInt64 GetValue () + { + UInt64 resultValue = 0; + + CheckError (Internal.LibPrimesWrapper.Calculator_GetValue (Handle, out resultValue)); + return resultValue; + } + + public void SetValue (UInt64 AValue) + { + + CheckError (Internal.LibPrimesWrapper.Calculator_SetValue (Handle, AValue)); + } + + public void Calculate () + { + + CheckError (Internal.LibPrimesWrapper.Calculator_Calculate (Handle)); + } + + public void SetProgressCallback (IntPtr AProgressCallback) + { + + CheckError (Internal.LibPrimesWrapper.Calculator_SetProgressCallback (Handle, IntPtr.Zero)); + } + + } + + class CFactorizationCalculator : CCalculator + { + public CFactorizationCalculator (IntPtr NewHandle) : base (NewHandle) + { + } + + public void GetPrimeFactors (out sPrimeFactor[] APrimeFactors) + { + UInt64 sizePrimeFactors = 0; + UInt64 neededPrimeFactors = 0; + CheckError (Internal.LibPrimesWrapper.FactorizationCalculator_GetPrimeFactors (Handle, sizePrimeFactors, out neededPrimeFactors, IntPtr.Zero)); + sizePrimeFactors = neededPrimeFactors; + var arrayPrimeFactors = new Internal.InternalPrimeFactor[sizePrimeFactors]; + GCHandle dataPrimeFactors = GCHandle.Alloc(arrayPrimeFactors, GCHandleType.Pinned); + + CheckError (Internal.LibPrimesWrapper.FactorizationCalculator_GetPrimeFactors (Handle, sizePrimeFactors, out neededPrimeFactors, dataPrimeFactors.AddrOfPinnedObject())); + dataPrimeFactors.Free(); + APrimeFactors = new sPrimeFactor[sizePrimeFactors]; + for (int index = 0; index < APrimeFactors.Length; index++) + APrimeFactors[index] = Internal.LibPrimesWrapper.convertInternalToStruct_PrimeFactor(arrayPrimeFactors[index]); + } + + } + + class CSieveCalculator : CCalculator + { + public CSieveCalculator (IntPtr NewHandle) : base (NewHandle) + { + } + + public void GetPrimes (out UInt64[] APrimes) + { + UInt64 sizePrimes = 0; + UInt64 neededPrimes = 0; + CheckError (Internal.LibPrimesWrapper.SieveCalculator_GetPrimes (Handle, sizePrimes, out neededPrimes, IntPtr.Zero)); + sizePrimes = neededPrimes; + APrimes = new UInt64[sizePrimes]; + GCHandle dataPrimes = GCHandle.Alloc(APrimes, GCHandleType.Pinned); + + CheckError (Internal.LibPrimesWrapper.SieveCalculator_GetPrimes (Handle, sizePrimes, out neededPrimes, dataPrimes.AddrOfPinnedObject())); + dataPrimes.Free(); + } + + } + + class Wrapper + { + private static void CheckError (Int32 errorCode) + { + if (errorCode != 0) { + Internal.LibPrimesWrapper.ThrowError (IntPtr.Zero, errorCode); + } + } + + public static void GetVersion (out UInt32 AMajor, out UInt32 AMinor, out UInt32 AMicro) + { + + CheckError (Internal.LibPrimesWrapper.GetVersion (out AMajor, out AMinor, out AMicro)); + } + + public static bool GetLastError (CBase AInstance, out String AErrorMessage) + { + Byte resultHasError = 0; + UInt32 sizeErrorMessage = 0; + UInt32 neededErrorMessage = 0; + CheckError (Internal.LibPrimesWrapper.GetLastError (AInstance.GetHandle(), sizeErrorMessage, out neededErrorMessage, IntPtr.Zero, out resultHasError)); + sizeErrorMessage = neededErrorMessage + 1; + byte[] bytesErrorMessage = new byte[sizeErrorMessage]; + GCHandle dataErrorMessage = GCHandle.Alloc(bytesErrorMessage, GCHandleType.Pinned); + + CheckError (Internal.LibPrimesWrapper.GetLastError (AInstance.GetHandle(), sizeErrorMessage, out neededErrorMessage, dataErrorMessage.AddrOfPinnedObject(), out resultHasError)); + dataErrorMessage.Free(); + AErrorMessage = Encoding.UTF8.GetString(bytesErrorMessage).TrimEnd(char.MinValue); + return (resultHasError != 0); + } + + public static void ReleaseInstance (CBase AInstance) + { + + CheckError (Internal.LibPrimesWrapper.ReleaseInstance (AInstance.GetHandle())); + } + + public static CFactorizationCalculator CreateFactorizationCalculator () + { + IntPtr newInstance = IntPtr.Zero; + + CheckError (Internal.LibPrimesWrapper.CreateFactorizationCalculator (out newInstance)); + return new CFactorizationCalculator (newInstance ); + } + + public static CSieveCalculator CreateSieveCalculator () + { + IntPtr newInstance = IntPtr.Zero; + + CheckError (Internal.LibPrimesWrapper.CreateSieveCalculator (out newInstance)); + return new CSieveCalculator (newInstance ); + } + + public static void SetJournal (String AFileName) + { + byte[] byteFileName = Encoding.UTF8.GetBytes(AFileName + char.MinValue); + + CheckError (Internal.LibPrimesWrapper.SetJournal (byteFileName)); + } + + } + +} diff --git a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.cpp b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.cpp deleted file mode 100644 index 92cda33c..00000000 --- a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/*++ - -Copyright (C) 2018 PrimeDevelopers - -All rights reserved. - -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. - -Abstract: This is an autogenerated C++ Wrapper Implementation file in order to allow -an easy use of Prime Numbers Library - -Interface version: 1.2.0 - -*/ - -#include "libprimes.hpp" - -#include - -namespace LibPrimes { - -/************************************************************************************************************************* - Class ELibPrimesException -**************************************************************************************************************************/ - ELibPrimesException::ELibPrimesException(LibPrimesResult errorCode) - : m_errorMessage("LibPrimes Error " + std::to_string (errorCode)) - { - m_errorCode = errorCode; - } - - LibPrimesResult ELibPrimesException::getErrorCode () - { - return m_errorCode; - } - - const char* ELibPrimesException::what () const noexcept - { - return m_errorMessage.c_str(); - } - -/************************************************************************************************************************* - Class CLibPrimesBaseClass -**************************************************************************************************************************/ - -CLibPrimesBaseClass::CLibPrimesBaseClass(LibPrimesHandle pHandle) -{ - m_pHandle = pHandle; -} - -CLibPrimesBaseClass::~CLibPrimesBaseClass() -{ - CLibPrimesWrapper::ReleaseInstance(this); -} - -void CLibPrimesBaseClass::CheckError(LibPrimesResult nResult) -{ - CLibPrimesWrapper::CheckError(m_pHandle, nResult); -} - -LibPrimesHandle CLibPrimesBaseClass::GetHandle() -{ - return m_pHandle; -} - - -/************************************************************************************************************************* - Class CLibPrimesCalculator -**************************************************************************************************************************/ -/** -* CLibPrimesCalculator::CLibPrimesCalculator - Constructor for Calculator class. -*/ -CLibPrimesCalculator::CLibPrimesCalculator (LibPrimesHandle pHandle) - : CLibPrimesBaseClass (pHandle) -{ } - -/** -* CLibPrimesCalculator::GetValue - Returns the current value of this Calculator -* @return The current value of this Calculator -*/ -LibPrimes_uint64 CLibPrimesCalculator::GetValue () -{ - LibPrimes_uint64 resultValue = 0; - CheckError ( libprimes_calculator_getvalue (m_pHandle, &resultValue) ); - return resultValue; -} - -/** -* CLibPrimesCalculator::SetValue - Sets the value to be factorized -* @param[in] nValue - The value to be factorized -*/ -void CLibPrimesCalculator::SetValue (const LibPrimes_uint64 nValue) -{ - CheckError ( libprimes_calculator_setvalue (m_pHandle, nValue) ); -} - -/** -* CLibPrimesCalculator::Calculate - Performs the specific calculation of this Calculator -*/ -void CLibPrimesCalculator::Calculate () -{ - CheckError ( libprimes_calculator_calculate (m_pHandle) ); -} - -/** -* CLibPrimesCalculator::SetProgressCallback - Sets the progress callback function -* @param[in] pProgressCallback - The progress callback -*/ -void CLibPrimesCalculator::SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) -{ - CheckError ( libprimes_calculator_setprogresscallback (m_pHandle, pProgressCallback) ); -} - -/************************************************************************************************************************* - Class CLibPrimesFactorizationCalculator -**************************************************************************************************************************/ -/** -* CLibPrimesFactorizationCalculator::CLibPrimesFactorizationCalculator - Constructor for FactorizationCalculator class. -*/ -CLibPrimesFactorizationCalculator::CLibPrimesFactorizationCalculator (LibPrimesHandle pHandle) - : CLibPrimesCalculator (pHandle) -{ } - -/** -* CLibPrimesFactorizationCalculator::GetPrimeFactors - Returns the prime factors of this number (without multiplicity) -* @param[out] PrimeFactorsBuffer - The prime factors of this number -*/ -void CLibPrimesFactorizationCalculator::GetPrimeFactors (std::vector & PrimeFactorsBuffer) -{ - LibPrimes_uint64 elementsNeededPrimeFactors = 0; - LibPrimes_uint64 elementsWrittenPrimeFactors = 0; - CheckError ( libprimes_factorizationcalculator_getprimefactors (m_pHandle, 0, &elementsNeededPrimeFactors, nullptr) ); - PrimeFactorsBuffer.resize(elementsNeededPrimeFactors); - CheckError ( libprimes_factorizationcalculator_getprimefactors (m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data()) ); -} - -/************************************************************************************************************************* - Class CLibPrimesSieveCalculator -**************************************************************************************************************************/ -/** -* CLibPrimesSieveCalculator::CLibPrimesSieveCalculator - Constructor for SieveCalculator class. -*/ -CLibPrimesSieveCalculator::CLibPrimesSieveCalculator (LibPrimesHandle pHandle) - : CLibPrimesCalculator (pHandle) -{ } - -/** -* CLibPrimesSieveCalculator::GetPrimes - Returns all prime numbers lower or equal to the sieve's value -* @param[out] PrimesBuffer - The primes lower or equal to the sieve's value -*/ -void CLibPrimesSieveCalculator::GetPrimes (std::vector & PrimesBuffer) -{ - LibPrimes_uint64 elementsNeededPrimes = 0; - LibPrimes_uint64 elementsWrittenPrimes = 0; - CheckError ( libprimes_sievecalculator_getprimes (m_pHandle, 0, &elementsNeededPrimes, nullptr) ); - PrimesBuffer.resize(elementsNeededPrimes); - CheckError ( libprimes_sievecalculator_getprimes (m_pHandle, elementsNeededPrimes, &elementsWrittenPrimes, PrimesBuffer.data()) ); -} - -/** -* CLibPrimesWrapper::ReleaseInstance - Releases the memory of an Instance -* @param[in] pInstance - Instance Handle -*/ -void CLibPrimesWrapper::ReleaseInstance (CLibPrimesBaseClass * pInstance) -{ - LibPrimesHandle hInstance = nullptr; - if (pInstance != nullptr) { - hInstance = pInstance->GetHandle (); - }; - CheckError (nullptr, libprimes_releaseinstance (hInstance) ); -} - -/** -* CLibPrimesWrapper::GetLibraryVersion - retrieves the current version of the library. -* @param[out] nMajor - returns the major version of the library -* @param[out] nMinor - returns the minor version of the library -* @param[out] nMicro - returns the micro version of the library -*/ -void CLibPrimesWrapper::GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) -{ - CheckError (nullptr, libprimes_getlibraryversion (&nMajor, &nMinor, &nMicro) ); -} - -/** -* CLibPrimesWrapper::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance -* @return New FactorizationCalculator instance -*/ -PLibPrimesFactorizationCalculator CLibPrimesWrapper::CreateFactorizationCalculator () -{ - LibPrimesHandle hInstance = nullptr; - CheckError (nullptr, libprimes_createfactorizationcalculator (&hInstance) ); - return std::make_shared (hInstance); -} - -/** -* CLibPrimesWrapper::CreateSieveCalculator - Creates a new SieveCalculator instance -* @return New SieveCalculator instance -*/ -PLibPrimesSieveCalculator CLibPrimesWrapper::CreateSieveCalculator () -{ - LibPrimesHandle hInstance = nullptr; - CheckError (nullptr, libprimes_createsievecalculator (&hInstance) ); - return std::make_shared (hInstance); -} - -/** -* CLibPrimesWrapper::SetJournal - Handles Library Journaling -* @param[in] sFileName - Journal FileName -*/ -void CLibPrimesWrapper::SetJournal (const std::string & sFileName) -{ - CheckError (nullptr, libprimes_setjournal (sFileName.c_str()) ); -} - -void CLibPrimesWrapper::CheckError(LibPrimesHandle handle, LibPrimesResult nResult) -{ - if (nResult != 0) - throw ELibPrimesException (nResult); -} - - -}; // end namespace LibPrimes - diff --git a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.hpp b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.hpp deleted file mode 100644 index bebc5cc1..00000000 --- a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.hpp +++ /dev/null @@ -1,255 +0,0 @@ -/*++ - -Copyright (C) 2018 PrimeDevelopers - -All rights reserved. - -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. - -Abstract: This is an autogenerated C++ Header file in order to allow an easy use - of Prime Numbers Library - -Interface version: 1.2.0 - -*/ - - -#ifndef __LIBPRIMES_CPPHEADER -#define __LIBPRIMES_CPPHEADER - -#include "libprimes.h" -#include -#include -#include -#include - -namespace LibPrimes { - -/************************************************************************************************************************* - Forward Declaration of all classes -**************************************************************************************************************************/ - -class CLibPrimesBaseClass; -class CLibPrimesCalculator; -class CLibPrimesFactorizationCalculator; -class CLibPrimesSieveCalculator; - -/************************************************************************************************************************* - Declaration of shared pointer types -**************************************************************************************************************************/ - -typedef std::shared_ptr PLibPrimesBaseClass; -typedef std::shared_ptr PLibPrimesCalculator; -typedef std::shared_ptr PLibPrimesFactorizationCalculator; -typedef std::shared_ptr PLibPrimesSieveCalculator; - -/************************************************************************************************************************* - Class ELibPrimesException -**************************************************************************************************************************/ -class ELibPrimesException : public std::exception { - protected: - /** - * Error code for the Exception. - */ - LibPrimesResult m_errorCode; - /** - * Error message for the Exception. - */ - std::string m_errorMessage; - - public: - /** - * Exception Constructor. - */ - ELibPrimesException (LibPrimesResult errorCode); - - /** - * Returns error code - */ - LibPrimesResult getErrorCode (); - - /** - * Returns error message - */ - const char* what () const noexcept; - -}; - -/************************************************************************************************************************* - Class CLibPrimesInputVector -**************************************************************************************************************************/ -template -class CLibPrimesInputVector { -private: - - const T* m_data; - size_t m_size; - -public: - - CLibPrimesInputVector( const std::vector& vec) - : m_data( vec.data() ), m_size( vec.size() ) - { - } - - CLibPrimesInputVector( const T* in_data, size_t in_size) - : m_data( in_data ), m_size(in_size ) - { - } - - const T* data() const - { - return m_data; - } - - size_t size() const - { - return m_size; - } - -}; - - -/************************************************************************************************************************* - Class CLibPrimesBaseClass -**************************************************************************************************************************/ -class CLibPrimesBaseClass { -protected: - /* Handle to Instance in library*/ - LibPrimesHandle m_pHandle; - - /* Checks for an Error code and raises Exceptions */ - void CheckError(LibPrimesResult nResult); -public: - - /** - * CLibPrimesBaseClass::CLibPrimesBaseClass - Constructor for Base class. - */ - CLibPrimesBaseClass(LibPrimesHandle pHandle); - - /** - * CLibPrimesBaseClass::~CLibPrimesBaseClass - Destructor for Base class. - */ - virtual ~CLibPrimesBaseClass(); - - /** - * CLibPrimesBaseClass::GetHandle - Returns handle to instance. - */ - LibPrimesHandle GetHandle(); -}; - -/************************************************************************************************************************* - Class CLibPrimesCalculator -**************************************************************************************************************************/ -class CLibPrimesCalculator : public CLibPrimesBaseClass { -public: - - /** - * CLibPrimesCalculator::CLibPrimesCalculator - Constructor for Calculator class. - */ - CLibPrimesCalculator (LibPrimesHandle pHandle); - - /** - * CLibPrimesCalculator::GetValue - Returns the current value of this Calculator - * @return The current value of this Calculator - */ - LibPrimes_uint64 GetValue (); - - /** - * CLibPrimesCalculator::SetValue - Sets the value to be factorized - * @param[in] nValue - The value to be factorized - */ - void SetValue (const LibPrimes_uint64 nValue); - - /** - * CLibPrimesCalculator::Calculate - Performs the specific calculation of this Calculator - */ - void Calculate (); - - /** - * CLibPrimesCalculator::SetProgressCallback - Sets the progress callback function - * @param[in] pProgressCallback - The progress callback - */ - void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback); -}; - -/************************************************************************************************************************* - Class CLibPrimesFactorizationCalculator -**************************************************************************************************************************/ -class CLibPrimesFactorizationCalculator : public CLibPrimesCalculator { -public: - - /** - * CLibPrimesFactorizationCalculator::CLibPrimesFactorizationCalculator - Constructor for FactorizationCalculator class. - */ - CLibPrimesFactorizationCalculator (LibPrimesHandle pHandle); - - /** - * CLibPrimesFactorizationCalculator::GetPrimeFactors - Returns the prime factors of this number (without multiplicity) - * @param[out] PrimeFactorsBuffer - The prime factors of this number - */ - void GetPrimeFactors (std::vector & PrimeFactorsBuffer); -}; - -/************************************************************************************************************************* - Class CLibPrimesSieveCalculator -**************************************************************************************************************************/ -class CLibPrimesSieveCalculator : public CLibPrimesCalculator { -public: - - /** - * CLibPrimesSieveCalculator::CLibPrimesSieveCalculator - Constructor for SieveCalculator class. - */ - CLibPrimesSieveCalculator (LibPrimesHandle pHandle); - - /** - * CLibPrimesSieveCalculator::GetPrimes - Returns all prime numbers lower or equal to the sieve's value - * @param[out] PrimesBuffer - The primes lower or equal to the sieve's value - */ - void GetPrimes (std::vector & PrimesBuffer); -}; - -/************************************************************************************************************************* - Class CLibPrimesWrapper -**************************************************************************************************************************/ -class CLibPrimesWrapper { -public: - static void CheckError(LibPrimesHandle handle, LibPrimesResult nResult); - - /** - * CLibPrimesWrapper::ReleaseInstance - Releases the memory of an Instance - * @param[in] pInstance - Instance Handle - */ - static void ReleaseInstance (CLibPrimesBaseClass * pInstance); - - /** - * CLibPrimesWrapper::GetLibraryVersion - retrieves the current version of the library. - * @param[out] nMajor - returns the major version of the library - * @param[out] nMinor - returns the minor version of the library - * @param[out] nMicro - returns the micro version of the library - */ - static void GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); - - /** - * CLibPrimesWrapper::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance - * @return New FactorizationCalculator instance - */ - static PLibPrimesFactorizationCalculator CreateFactorizationCalculator (); - - /** - * CLibPrimesWrapper::CreateSieveCalculator - Creates a new SieveCalculator instance - * @return New SieveCalculator instance - */ - static PLibPrimesSieveCalculator CreateSieveCalculator (); - - /** - * CLibPrimesWrapper::SetJournal - Handles Library Journaling - * @param[in] sFileName - Journal FileName - */ - static void SetJournal (const std::string & sFileName); -}; - -}; - -#endif // __LIBPRIMES_CPPHEADER - diff --git a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.h b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_abi.hpp similarity index 72% rename from Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.h rename to Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_abi.hpp index ef110e11..a463430b 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes.h +++ b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_abi.hpp @@ -1,35 +1,39 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file in order to allow an easy +Abstract: This is an autogenerated C++-Header file in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_HEADER -#define __LIBPRIMES_HEADER +#ifndef __LIBPRIMES_HEADER_CPP +#define __LIBPRIMES_HEADER_CPP #ifdef __LIBPRIMES_EXPORTS -#ifdef WIN32 +#ifdef _WIN32 #define LIBPRIMES_DECLSPEC __declspec (dllexport) -#else // WIN32 +#else // _WIN32 #define LIBPRIMES_DECLSPEC __attribute__((visibility("default"))) -#endif // WIN32 +#endif // _WIN32 #else // __LIBPRIMES_EXPORTS #define LIBPRIMES_DECLSPEC #endif // __LIBPRIMES_EXPORTS -#include "libprimes_types.h" +#include "libprimes_types.hpp" extern "C" { +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + /************************************************************************************************************************* Class definition for Calculator **************************************************************************************************************************/ @@ -67,7 +71,7 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_calculate(LibPrimes_Calc * @param[in] pProgressCallback - The progress callback * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimesProgressCallback pProgressCallback); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimes::ProgressCallback pProgressCallback); /************************************************************************************************************************* Class definition for FactorizationCalculator @@ -82,7 +86,7 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibP * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); /************************************************************************************************************************* Class definition for SieveCalculator @@ -104,22 +108,34 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_sievecalculator_getprimes(LibPrimes **************************************************************************************************************************/ /** -* Releases the memory of an Instance +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); + +/** +* Returns the last error recorded on this object * * @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_releaseinstance(LibPrimes_BaseClass pInstance); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getlasterror(LibPrimes_Base pInstance, const LibPrimes_uint32 nErrorMessageBufferSize, LibPrimes_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); /** -* retrieves the current version of the library. +* Releases the memory of an Instance * -* @param[out] pMajor - returns the major version of the library -* @param[out] pMinor - returns the minor version of the library -* @param[out] pMicro - returns the micro version of the library +* @param[in] pInstance - Instance Handle * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getlibraryversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_releaseinstance(LibPrimes_Base pInstance); /** * Creates a new FactorizationCalculator instance @@ -147,5 +163,5 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_setjournal(const char * pFileName); } -#endif // __LIBPRIMES_HEADER +#endif // __LIBPRIMES_HEADER_CPP diff --git a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_implicit.hpp b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_implicit.hpp new file mode 100644 index 00000000..a309a608 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_implicit.hpp @@ -0,0 +1,452 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. + +Abstract: This is an autogenerated C++-Header file in order to allow an easy + use of Prime Numbers Library + +Interface version: 1.2.0 + +*/ + +#ifndef __LIBPRIMES_CPPHEADER_IMPLICIT_CPP +#define __LIBPRIMES_CPPHEADER_IMPLICIT_CPP + +#include "libprimes_types.hpp" +#include "libprimes_abi.hpp" + +#ifdef _WIN32 +#include +#else // _WIN32 +#include +#endif // _WIN32 +#include +#include +#include +#include + +namespace LibPrimes { + +/************************************************************************************************************************* + Forward Declaration of all classes +**************************************************************************************************************************/ +class CWrapper; +class CBase; +class CCalculator; +class CFactorizationCalculator; +class CSieveCalculator; + +/************************************************************************************************************************* + Declaration of deprecated class types +**************************************************************************************************************************/ +typedef CWrapper CLibPrimesWrapper; +typedef CBase CLibPrimesBase; +typedef CCalculator CLibPrimesCalculator; +typedef CFactorizationCalculator CLibPrimesFactorizationCalculator; +typedef CSieveCalculator CLibPrimesSieveCalculator; + +/************************************************************************************************************************* + Declaration of shared pointer types +**************************************************************************************************************************/ +typedef std::shared_ptr PWrapper; +typedef std::shared_ptr PBase; +typedef std::shared_ptr PCalculator; +typedef std::shared_ptr PFactorizationCalculator; +typedef std::shared_ptr PSieveCalculator; + +/************************************************************************************************************************* + Declaration of deprecated shared pointer types +**************************************************************************************************************************/ +typedef PWrapper PLibPrimesWrapper; +typedef PBase PLibPrimesBase; +typedef PCalculator PLibPrimesCalculator; +typedef PFactorizationCalculator PLibPrimesFactorizationCalculator; +typedef PSieveCalculator PLibPrimesSieveCalculator; + + +/************************************************************************************************************************* + Class ELibPrimesException +**************************************************************************************************************************/ +class ELibPrimesException : public std::exception { +protected: + /** + * Error code for the Exception. + */ + LibPrimesResult m_errorCode; + /** + * Error message for the Exception. + */ + std::string m_errorMessage; + +public: + /** + * Exception Constructor. + */ + ELibPrimesException(LibPrimesResult errorCode, const std::string & sErrorMessage) + : m_errorMessage("LibPrimes Error " + std::to_string(errorCode) + " (" + sErrorMessage + ")") + { + m_errorCode = errorCode; + } + + /** + * Returns error code + */ + LibPrimesResult getErrorCode() const noexcept + { + return m_errorCode; + } + + /** + * Returns error message + */ + const char* what() const noexcept + { + return m_errorMessage.c_str(); + } + +}; + +/************************************************************************************************************************* + Class CInputVector +**************************************************************************************************************************/ +template +class CInputVector { +private: + + const T* m_data; + size_t m_size; + +public: + + CInputVector( const std::vector& vec) + : m_data( vec.data() ), m_size( vec.size() ) + { + } + + CInputVector( const T* in_data, size_t in_size) + : m_data( in_data ), m_size(in_size ) + { + } + + const T* data() const + { + return m_data; + } + + size_t size() const + { + return m_size; + } + +}; + +// declare deprecated class name +template +using CLibPrimesInputVector = CInputVector; + +/************************************************************************************************************************* + Class CWrapper +**************************************************************************************************************************/ +class CWrapper { +public: + + CWrapper() + { + } + + ~CWrapper() + { + } + static inline PWrapper loadLibrary() + { + return std::make_shared(); + } + + inline void CheckError(CBase * pBaseClass, LibPrimesResult nResult); + + inline void GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); + inline bool GetLastError(CBase * pInstance, std::string & sErrorMessage); + inline void ReleaseInstance(CBase * pInstance); + inline PFactorizationCalculator CreateFactorizationCalculator(); + inline PSieveCalculator CreateSieveCalculator(); + inline void SetJournal(const std::string & sFileName); + +private: + + LibPrimesResult checkBinaryVersion() + { + LibPrimes_uint32 nMajor, nMinor, nMicro; + GetVersion(nMajor, nMinor, nMicro); + if ( (nMajor != LIBPRIMES_VERSION_MAJOR) || (nMinor < LIBPRIMES_VERSION_MINOR) ) { + return LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION; + } + return LIBPRIMES_SUCCESS; + } + + friend class CBase; + friend class CCalculator; + friend class CFactorizationCalculator; + friend class CSieveCalculator; + +}; + + +/************************************************************************************************************************* + Class CBase +**************************************************************************************************************************/ +class CBase { +public: + +protected: + /* Wrapper Object that created the class. */ + CWrapper * m_pWrapper; + /* Handle to Instance in library*/ + LibPrimesHandle m_pHandle; + + /* Checks for an Error code and raises Exceptions */ + void CheckError(LibPrimesResult nResult) + { + if (m_pWrapper != nullptr) + m_pWrapper->CheckError(this, nResult); + } + + /** + * CBase::CBase - Constructor for Base class. + */ + CBase(CWrapper * pWrapper, LibPrimesHandle pHandle) + : m_pWrapper(pWrapper), m_pHandle(pHandle) + { + } + + /** + * CBase::~CBase - Destructor for Base class. + */ + virtual ~CBase() + { + if (m_pWrapper != nullptr) + m_pWrapper->ReleaseInstance(this); + m_pWrapper = nullptr; + } + +public: + /** + * CBase::GetHandle - Returns handle to instance. + */ + LibPrimesHandle GetHandle() + { + return m_pHandle; + } + + friend class CWrapper; +}; + +/************************************************************************************************************************* + Class CCalculator +**************************************************************************************************************************/ +class CCalculator : public CBase { +public: + + /** + * CCalculator::CCalculator - Constructor for Calculator class. + */ + CCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CBase(pWrapper, pHandle) + { + } + + inline LibPrimes_uint64 GetValue(); + inline void SetValue(const LibPrimes_uint64 nValue); + inline void Calculate(); + inline void SetProgressCallback(const ProgressCallback pProgressCallback); +}; + +/************************************************************************************************************************* + Class CFactorizationCalculator +**************************************************************************************************************************/ +class CFactorizationCalculator : public CCalculator { +public: + + /** + * CFactorizationCalculator::CFactorizationCalculator - Constructor for FactorizationCalculator class. + */ + CFactorizationCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CCalculator(pWrapper, pHandle) + { + } + + inline void GetPrimeFactors(std::vector & PrimeFactorsBuffer); +}; + +/************************************************************************************************************************* + Class CSieveCalculator +**************************************************************************************************************************/ +class CSieveCalculator : public CCalculator { +public: + + /** + * CSieveCalculator::CSieveCalculator - Constructor for SieveCalculator class. + */ + CSieveCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CCalculator(pWrapper, pHandle) + { + } + + inline void GetPrimes(std::vector & PrimesBuffer); +}; + + /** + * CWrapper::GetVersion - retrieves the binary version of this library. + * @param[out] nMajor - returns the major version of this library + * @param[out] nMinor - returns the minor version of this library + * @param[out] nMicro - returns the micro version of this library + */ + inline void CWrapper::GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) + { + CheckError(nullptr,libprimes_getversion(&nMajor, &nMinor, &nMicro)); + } + + /** + * CWrapper::GetLastError - Returns the last error recorded on this object + * @param[in] pInstance - Instance Handle + * @param[out] sErrorMessage - Message of the last error + * @return Is there a last error to query + */ + inline bool CWrapper::GetLastError(CBase * pInstance, std::string & sErrorMessage) + { + LibPrimesHandle hInstance = nullptr; + if (pInstance != nullptr) { + hInstance = pInstance->GetHandle(); + }; + LibPrimes_uint32 bytesNeededErrorMessage = 0; + LibPrimes_uint32 bytesWrittenErrorMessage = 0; + bool resultHasError = 0; + CheckError(nullptr,libprimes_getlasterror(hInstance, 0, &bytesNeededErrorMessage, nullptr, &resultHasError)); + std::vector bufferErrorMessage; + bufferErrorMessage.resize(bytesNeededErrorMessage + 2); + CheckError(nullptr,libprimes_getlasterror(hInstance, bytesNeededErrorMessage + 2, &bytesWrittenErrorMessage, &bufferErrorMessage[0], &resultHasError)); + bufferErrorMessage[bytesNeededErrorMessage + 1] = 0; + sErrorMessage = std::string(&bufferErrorMessage[0]); + return resultHasError; + } + + /** + * CWrapper::ReleaseInstance - Releases the memory of an Instance + * @param[in] pInstance - Instance Handle + */ + inline void CWrapper::ReleaseInstance(CBase * pInstance) + { + LibPrimesHandle hInstance = nullptr; + if (pInstance != nullptr) { + hInstance = pInstance->GetHandle(); + }; + CheckError(nullptr,libprimes_releaseinstance(hInstance)); + } + + /** + * CWrapper::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance + * @return New FactorizationCalculator instance + */ + inline PFactorizationCalculator CWrapper::CreateFactorizationCalculator() + { + LibPrimesHandle hInstance = nullptr; + CheckError(nullptr,libprimes_createfactorizationcalculator(&hInstance)); + return std::make_shared(this, hInstance); + } + + /** + * CWrapper::CreateSieveCalculator - Creates a new SieveCalculator instance + * @return New SieveCalculator instance + */ + inline PSieveCalculator CWrapper::CreateSieveCalculator() + { + LibPrimesHandle hInstance = nullptr; + CheckError(nullptr,libprimes_createsievecalculator(&hInstance)); + return std::make_shared(this, hInstance); + } + + /** + * CWrapper::SetJournal - Handles Library Journaling + * @param[in] sFileName - Journal FileName + */ + inline void CWrapper::SetJournal(const std::string & sFileName) + { + CheckError(nullptr,libprimes_setjournal(sFileName.c_str())); + } + + inline void CWrapper::CheckError(CBase * pBaseClass, LibPrimesResult nResult) + { + if (nResult != 0) { + std::string sErrorMessage; + if (pBaseClass != nullptr) { + GetLastError(pBaseClass, sErrorMessage); + } + throw ELibPrimesException(nResult, sErrorMessage); + } + } + + + + /** + * Method definitions for class CBase + */ + + /** + * Method definitions for class CCalculator + */ + + LibPrimes_uint64 CCalculator::GetValue() + { + LibPrimes_uint64 resultValue = 0; + CheckError(libprimes_calculator_getvalue(m_pHandle, &resultValue)); + return resultValue; + } + + void CCalculator::SetValue(const LibPrimes_uint64 nValue) + { + CheckError(libprimes_calculator_setvalue(m_pHandle, nValue)); + } + + void CCalculator::Calculate() + { + CheckError(libprimes_calculator_calculate(m_pHandle)); + } + + void CCalculator::SetProgressCallback(const ProgressCallback pProgressCallback) + { + CheckError(libprimes_calculator_setprogresscallback(m_pHandle, pProgressCallback)); + } + + /** + * Method definitions for class CFactorizationCalculator + */ + + void CFactorizationCalculator::GetPrimeFactors(std::vector & PrimeFactorsBuffer) + { + LibPrimes_uint64 elementsNeededPrimeFactors = 0; + LibPrimes_uint64 elementsWrittenPrimeFactors = 0; + CheckError(libprimes_factorizationcalculator_getprimefactors(m_pHandle, 0, &elementsNeededPrimeFactors, nullptr)); + PrimeFactorsBuffer.resize((size_t) elementsNeededPrimeFactors); + CheckError(libprimes_factorizationcalculator_getprimefactors(m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data())); + } + + /** + * Method definitions for class CSieveCalculator + */ + + void CSieveCalculator::GetPrimes(std::vector & PrimesBuffer) + { + LibPrimes_uint64 elementsNeededPrimes = 0; + LibPrimes_uint64 elementsWrittenPrimes = 0; + CheckError(libprimes_sievecalculator_getprimes(m_pHandle, 0, &elementsNeededPrimes, nullptr)); + PrimesBuffer.resize((size_t) elementsNeededPrimes); + CheckError(libprimes_sievecalculator_getprimes(m_pHandle, elementsNeededPrimes, &elementsWrittenPrimes, PrimesBuffer.data())); + } + +} // namespace LibPrimes + +#endif // __LIBPRIMES_CPPHEADER_IMPLICIT_CPP + diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.h b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.hpp similarity index 65% rename from Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.h rename to Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.hpp index 2b14eea7..e502bbe6 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.h +++ b/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.hpp @@ -1,20 +1,20 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file with basic types in +Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_TYPES_HEADER -#define __LIBPRIMES_TYPES_HEADER +#ifndef __LIBPRIMES_TYPES_HEADER_CPP +#define __LIBPRIMES_TYPES_HEADER_CPP /************************************************************************************************************************* Scalar types definition @@ -55,6 +55,7 @@ typedef double LibPrimes_double; typedef LibPrimes_int32 LibPrimesResult; typedef void * LibPrimesHandle; +typedef void * LibPrimes_pvoid; /************************************************************************************************************************* Version for LibPrimes @@ -63,6 +64,8 @@ typedef void * LibPrimesHandle; #define LIBPRIMES_VERSION_MAJOR 1 #define LIBPRIMES_VERSION_MINOR 2 #define LIBPRIMES_VERSION_MICRO 0 +#define LIBPRIMES_VERSION_PRERELEASEINFO "" +#define LIBPRIMES_VERSION_BUILDINFO "" /************************************************************************************************************************* Error constants for LibPrimes @@ -84,34 +87,42 @@ typedef void * LibPrimesHandle; Declaration of handle classes **************************************************************************************************************************/ -typedef LibPrimesHandle LibPrimes_BaseClass; +typedef LibPrimesHandle LibPrimes_Base; typedef LibPrimesHandle LibPrimes_Calculator; typedef LibPrimesHandle LibPrimes_FactorizationCalculator; typedef LibPrimesHandle LibPrimes_SieveCalculator; -/************************************************************************************************************************* - Declaration of structs -**************************************************************************************************************************/ - -#pragma pack (1) - -typedef struct { - LibPrimes_uint64 m_Prime; - LibPrimes_uint32 m_Multiplicity; -} sLibPrimesPrimeFactor; - -#pragma pack () - -/************************************************************************************************************************* - Declaration of function pointers -**************************************************************************************************************************/ - -/** -* LibPrimesProgressCallback - Callback to report calculation progress and query whether it should be aborted -* -* @param[in] fProgressPercentage - How far has the calculation progressed? -* @param[out] pShouldAbort - Should the calculation be aborted? -*/ -typedef void(*LibPrimesProgressCallback)(LibPrimes_single, bool*); - -#endif // __LIBPRIMES_TYPES_HEADER +namespace LibPrimes { + + /************************************************************************************************************************* + Declaration of structs + **************************************************************************************************************************/ + + #pragma pack (1) + + typedef struct { + LibPrimes_uint64 m_Prime; + LibPrimes_uint32 m_Multiplicity; + } sPrimeFactor; + + #pragma pack () + + /************************************************************************************************************************* + Declaration of function pointers + **************************************************************************************************************************/ + + /** + * ProgressCallback - Callback to report calculation progress and query whether it should be aborted + * + * @param[in] fProgressPercentage - How far has the calculation progressed? + * @param[out] pShouldAbort - Should the calculation be aborted? + */ + typedef void(*ProgressCallback)(LibPrimes_single, bool*); + +} // namespace LibPrimes; + +// define legacy C-names for enums, structs and function types +typedef LibPrimes::sPrimeFactor sLibPrimesPrimeFactor; +typedef LibPrimes::ProgressCallback LibPrimesProgressCallback; + +#endif // __LIBPRIMES_TYPES_HEADER_CPP diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes.h b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_abi.hpp similarity index 72% rename from Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes.h rename to Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_abi.hpp index ef110e11..a463430b 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes.h +++ b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_abi.hpp @@ -1,35 +1,39 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file in order to allow an easy +Abstract: This is an autogenerated C++-Header file in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_HEADER -#define __LIBPRIMES_HEADER +#ifndef __LIBPRIMES_HEADER_CPP +#define __LIBPRIMES_HEADER_CPP #ifdef __LIBPRIMES_EXPORTS -#ifdef WIN32 +#ifdef _WIN32 #define LIBPRIMES_DECLSPEC __declspec (dllexport) -#else // WIN32 +#else // _WIN32 #define LIBPRIMES_DECLSPEC __attribute__((visibility("default"))) -#endif // WIN32 +#endif // _WIN32 #else // __LIBPRIMES_EXPORTS #define LIBPRIMES_DECLSPEC #endif // __LIBPRIMES_EXPORTS -#include "libprimes_types.h" +#include "libprimes_types.hpp" extern "C" { +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + /************************************************************************************************************************* Class definition for Calculator **************************************************************************************************************************/ @@ -67,7 +71,7 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_calculate(LibPrimes_Calc * @param[in] pProgressCallback - The progress callback * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimesProgressCallback pProgressCallback); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimes::ProgressCallback pProgressCallback); /************************************************************************************************************************* Class definition for FactorizationCalculator @@ -82,7 +86,7 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibP * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); /************************************************************************************************************************* Class definition for SieveCalculator @@ -104,22 +108,34 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_sievecalculator_getprimes(LibPrimes **************************************************************************************************************************/ /** -* Releases the memory of an Instance +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); + +/** +* Returns the last error recorded on this object * * @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_releaseinstance(LibPrimes_BaseClass pInstance); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getlasterror(LibPrimes_Base pInstance, const LibPrimes_uint32 nErrorMessageBufferSize, LibPrimes_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); /** -* retrieves the current version of the library. +* Releases the memory of an Instance * -* @param[out] pMajor - returns the major version of the library -* @param[out] pMinor - returns the minor version of the library -* @param[out] pMicro - returns the micro version of the library +* @param[in] pInstance - Instance Handle * @return error code or 0 (success) */ -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getlibraryversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_releaseinstance(LibPrimes_Base pInstance); /** * Creates a new FactorizationCalculator instance @@ -147,5 +163,5 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_setjournal(const char * pFileName); } -#endif // __LIBPRIMES_HEADER +#endif // __LIBPRIMES_HEADER_CPP diff --git a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.h b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.h index b665434a..d9d0f123 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.h +++ b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.h @@ -1,24 +1,28 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file in order to allow an easy +Abstract: This is an autogenerated C++-Header file in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_DYNAMICHEADER -#define __LIBPRIMES_DYNAMICHEADER +#ifndef __LIBPRIMES_DYNAMICHEADER_CPPTYPES +#define __LIBPRIMES_DYNAMICHEADER_CPPTYPES -#include "libprimes_types.h" +#include "libprimes_types.hpp" +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + /************************************************************************************************************************* Class definition for Calculator **************************************************************************************************************************/ @@ -56,7 +60,7 @@ typedef LibPrimesResult (*PLibPrimesCalculator_CalculatePtr) (LibPrimes_Calculat * @param[in] pProgressCallback - The progress callback * @return error code or 0 (success) */ -typedef LibPrimesResult (*PLibPrimesCalculator_SetProgressCallbackPtr) (LibPrimes_Calculator pCalculator, LibPrimesProgressCallback pProgressCallback); +typedef LibPrimesResult (*PLibPrimesCalculator_SetProgressCallbackPtr) (LibPrimes_Calculator pCalculator, LibPrimes::ProgressCallback pProgressCallback); /************************************************************************************************************************* Class definition for FactorizationCalculator @@ -71,7 +75,7 @@ typedef LibPrimesResult (*PLibPrimesCalculator_SetProgressCallbackPtr) (LibPrime * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number * @return error code or 0 (success) */ -typedef LibPrimesResult (*PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) (LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer); +typedef LibPrimesResult (*PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) (LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); /************************************************************************************************************************* Class definition for SieveCalculator @@ -93,22 +97,34 @@ typedef LibPrimesResult (*PLibPrimesSieveCalculator_GetPrimesPtr) (LibPrimes_Sie **************************************************************************************************************************/ /** -* Releases the memory of an Instance +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +typedef LibPrimesResult (*PLibPrimesGetVersionPtr) (LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); + +/** +* Returns the last error recorded on this object * * @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query * @return error code or 0 (success) */ -typedef LibPrimesResult (*PLibPrimesReleaseInstancePtr) (LibPrimes_BaseClass pInstance); +typedef LibPrimesResult (*PLibPrimesGetLastErrorPtr) (LibPrimes_Base pInstance, const LibPrimes_uint32 nErrorMessageBufferSize, LibPrimes_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); /** -* retrieves the current version of the library. +* Releases the memory of an Instance * -* @param[out] pMajor - returns the major version of the library -* @param[out] pMinor - returns the minor version of the library -* @param[out] pMicro - returns the micro version of the library +* @param[in] pInstance - Instance Handle * @return error code or 0 (success) */ -typedef LibPrimesResult (*PLibPrimesGetLibraryVersionPtr) (LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); +typedef LibPrimesResult (*PLibPrimesReleaseInstancePtr) (LibPrimes_Base pInstance); /** * Creates a new FactorizationCalculator instance @@ -146,12 +162,13 @@ typedef struct { PLibPrimesCalculator_SetProgressCallbackPtr m_Calculator_SetProgressCallback; PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr m_FactorizationCalculator_GetPrimeFactors; PLibPrimesSieveCalculator_GetPrimesPtr m_SieveCalculator_GetPrimes; + PLibPrimesGetVersionPtr m_GetVersion; + PLibPrimesGetLastErrorPtr m_GetLastError; PLibPrimesReleaseInstancePtr m_ReleaseInstance; - PLibPrimesGetLibraryVersionPtr m_GetLibraryVersion; PLibPrimesCreateFactorizationCalculatorPtr m_CreateFactorizationCalculator; PLibPrimesCreateSieveCalculatorPtr m_CreateSieveCalculator; PLibPrimesSetJournalPtr m_SetJournal; } sLibPrimesDynamicWrapperTable; -#endif // __LIBPRIMES_DYNAMICHEADER +#endif // __LIBPRIMES_DYNAMICHEADER_CPPTYPES diff --git a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.hpp b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.hpp index 8fde3a7f..e30b984b 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.hpp +++ b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_dynamic.hpp @@ -1,29 +1,29 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated C++ Header file in order to allow an easy +Abstract: This is an autogenerated C++-Header file in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_DYNAMICCPPHEADER -#define __LIBPRIMES_DYNAMICCPPHEADER +#ifndef __LIBPRIMES_CPPHEADER_DYNAMIC_CPP +#define __LIBPRIMES_CPPHEADER_DYNAMIC_CPP -#include "libprimes_types.h" +#include "libprimes_types.hpp" #include "libprimes_dynamic.h" -#ifdef WIN32 +#ifdef _WIN32 #include -#else // WIN32 +#else // _WIN32 #include -#endif // WIN32 +#endif // _WIN32 #include #include #include @@ -32,24 +32,41 @@ Interface version: 1.2.0 namespace LibPrimes { /************************************************************************************************************************* - Forward Declaration of all classes + Forward Declaration of all classes **************************************************************************************************************************/ +class CWrapper; +class CBase; +class CCalculator; +class CFactorizationCalculator; +class CSieveCalculator; -class CLibPrimesBaseClass; -class CLibPrimesWrapper; -class CLibPrimesCalculator; -class CLibPrimesFactorizationCalculator; -class CLibPrimesSieveCalculator; +/************************************************************************************************************************* + Declaration of deprecated class types +**************************************************************************************************************************/ +typedef CWrapper CLibPrimesWrapper; +typedef CBase CLibPrimesBase; +typedef CCalculator CLibPrimesCalculator; +typedef CFactorizationCalculator CLibPrimesFactorizationCalculator; +typedef CSieveCalculator CLibPrimesSieveCalculator; + +/************************************************************************************************************************* + Declaration of shared pointer types +**************************************************************************************************************************/ +typedef std::shared_ptr PWrapper; +typedef std::shared_ptr PBase; +typedef std::shared_ptr PCalculator; +typedef std::shared_ptr PFactorizationCalculator; +typedef std::shared_ptr PSieveCalculator; /************************************************************************************************************************* - Declaration of shared pointer types + Declaration of deprecated shared pointer types **************************************************************************************************************************/ +typedef PWrapper PLibPrimesWrapper; +typedef PBase PLibPrimesBase; +typedef PCalculator PLibPrimesCalculator; +typedef PFactorizationCalculator PLibPrimesFactorizationCalculator; +typedef PSieveCalculator PLibPrimesSieveCalculator; -typedef std::shared_ptr PLibPrimesBaseClass; -typedef std::shared_ptr PLibPrimesWrapper; -typedef std::shared_ptr PLibPrimesCalculator; -typedef std::shared_ptr PLibPrimesFactorizationCalculator; -typedef std::shared_ptr PLibPrimesSieveCalculator; /************************************************************************************************************************* Class ELibPrimesException @@ -69,8 +86,8 @@ class ELibPrimesException : public std::exception { /** * Exception Constructor. */ - ELibPrimesException (LibPrimesResult errorCode) - : m_errorMessage("LibPrimes Error " + std::to_string (errorCode)) + ELibPrimesException(LibPrimesResult errorCode, const std::string & sErrorMessage) + : m_errorMessage("LibPrimes Error " + std::to_string(errorCode) + " (" + sErrorMessage + ")") { m_errorCode = errorCode; } @@ -78,7 +95,7 @@ class ELibPrimesException : public std::exception { /** * Returns error code */ - LibPrimesResult getErrorCode () + LibPrimesResult getErrorCode() const noexcept { return m_errorCode; } @@ -86,7 +103,7 @@ class ELibPrimesException : public std::exception { /** * Returns error message */ - const char* what () const noexcept + const char* what() const noexcept { return m_errorMessage.c_str(); } @@ -94,10 +111,10 @@ class ELibPrimesException : public std::exception { }; /************************************************************************************************************************* - Class CLibPrimesInputVector + Class CInputVector **************************************************************************************************************************/ template -class CLibPrimesInputVector { +class CInputVector { private: const T* m_data; @@ -105,12 +122,12 @@ class CLibPrimesInputVector { public: - CLibPrimesInputVector( const std::vector& vec) + CInputVector( const std::vector& vec) : m_data( vec.data() ), m_size( vec.size() ) { } - CLibPrimesInputVector( const T* in_data, size_t in_size) + CInputVector( const T* in_data, size_t in_size) : m_data( in_data ), m_size(in_size ) { } @@ -127,72 +144,76 @@ class CLibPrimesInputVector { }; +// declare deprecated class name +template +using CLibPrimesInputVector = CInputVector; + /************************************************************************************************************************* - Class CLibPrimesWrapper + Class CWrapper **************************************************************************************************************************/ -class CLibPrimesWrapper { +class CWrapper { public: - CLibPrimesWrapper (const std::string &sFileName) + CWrapper(const std::string &sFileName) { - CheckError (nullptr, initWrapperTable (&m_WrapperTable)); - CheckError (nullptr, loadWrapperTable (&m_WrapperTable, sFileName.c_str ())); + CheckError(nullptr, initWrapperTable(&m_WrapperTable)); + CheckError(nullptr, loadWrapperTable(&m_WrapperTable, sFileName.c_str())); CheckError(nullptr, checkBinaryVersion()); } - static PLibPrimesWrapper loadLibrary (const std::string &sFileName) + static PWrapper loadLibrary(const std::string &sFileName) { - return std::make_shared (sFileName); + return std::make_shared(sFileName); } - ~CLibPrimesWrapper () + ~CWrapper() { - releaseWrapperTable (&m_WrapperTable); - } - - void CheckError(LibPrimesHandle handle, LibPrimesResult nResult) - { - if (nResult != 0) - throw ELibPrimesException (nResult); + releaseWrapperTable(&m_WrapperTable); } + inline void CheckError(CBase * pBaseClass, LibPrimesResult nResult); - inline void ReleaseInstance (CLibPrimesBaseClass * pInstance); - inline void GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); - inline PLibPrimesFactorizationCalculator CreateFactorizationCalculator (); - inline PLibPrimesSieveCalculator CreateSieveCalculator (); - inline void SetJournal (const std::string & sFileName); + inline void GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); + inline bool GetLastError(CBase * pInstance, std::string & sErrorMessage); + inline void ReleaseInstance(CBase * pInstance); + inline PFactorizationCalculator CreateFactorizationCalculator(); + inline PSieveCalculator CreateSieveCalculator(); + inline void SetJournal(const std::string & sFileName); private: sLibPrimesDynamicWrapperTable m_WrapperTable; - + LibPrimesResult checkBinaryVersion() { LibPrimes_uint32 nMajor, nMinor, nMicro; - GetLibraryVersion(nMajor, nMinor, nMicro); + GetVersion(nMajor, nMinor, nMicro); if ( (nMajor != LIBPRIMES_VERSION_MAJOR) || (nMinor < LIBPRIMES_VERSION_MINOR) ) { return LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION; } return LIBPRIMES_SUCCESS; } - LibPrimesResult initWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable); - LibPrimesResult releaseWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable); - LibPrimesResult loadWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName); + LibPrimesResult initWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable); + LibPrimesResult releaseWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable); + LibPrimesResult loadWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName); - friend class CLibPrimesCalculator; - friend class CLibPrimesFactorizationCalculator; - friend class CLibPrimesSieveCalculator; + friend class CBase; + friend class CCalculator; + friend class CFactorizationCalculator; + friend class CSieveCalculator; }; + /************************************************************************************************************************* - Class CLibPrimesBaseClass + Class CBase **************************************************************************************************************************/ -class CLibPrimesBaseClass { +class CBase { +public: + protected: - /* Wrapper Object that created the class..*/ - CLibPrimesWrapper * m_pWrapper; + /* Wrapper Object that created the class. */ + CWrapper * m_pWrapper; /* Handle to Instance in library*/ LibPrimesHandle m_pHandle; @@ -200,149 +221,185 @@ class CLibPrimesBaseClass { void CheckError(LibPrimesResult nResult) { if (m_pWrapper != nullptr) - m_pWrapper->CheckError (m_pHandle, nResult); + m_pWrapper->CheckError(this, nResult); } -public: - /** - * CLibPrimesBaseClass::CLibPrimesBaseClass - Constructor for Base class. + * CBase::CBase - Constructor for Base class. */ - CLibPrimesBaseClass(CLibPrimesWrapper * pWrapper, LibPrimesHandle pHandle) - : m_pWrapper (pWrapper), m_pHandle (pHandle) + CBase(CWrapper * pWrapper, LibPrimesHandle pHandle) + : m_pWrapper(pWrapper), m_pHandle(pHandle) { } /** - * CLibPrimesBaseClass::~CLibPrimesBaseClass - Destructor for Base class. + * CBase::~CBase - Destructor for Base class. */ - virtual ~CLibPrimesBaseClass() + virtual ~CBase() { if (m_pWrapper != nullptr) - m_pWrapper->ReleaseInstance (this); + m_pWrapper->ReleaseInstance(this); m_pWrapper = nullptr; } +public: /** - * CLibPrimesBaseClass::GetHandle - Returns handle to instance. + * CBase::GetHandle - Returns handle to instance. */ LibPrimesHandle GetHandle() { return m_pHandle; } -}; + friend class CWrapper; +}; /************************************************************************************************************************* - Class CLibPrimesCalculator + Class CCalculator **************************************************************************************************************************/ -class CLibPrimesCalculator : public CLibPrimesBaseClass { +class CCalculator : public CBase { public: /** - * CLibPrimesCalculator::CLibPrimesCalculator - Constructor for Calculator class. + * CCalculator::CCalculator - Constructor for Calculator class. */ - CLibPrimesCalculator (CLibPrimesWrapper * pWrapper, LibPrimesHandle pHandle) - : CLibPrimesBaseClass (pWrapper, pHandle) + CCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CBase(pWrapper, pHandle) { } - inline LibPrimes_uint64 GetValue (); - inline void SetValue (const LibPrimes_uint64 nValue); - inline void Calculate (); - inline void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback); + inline LibPrimes_uint64 GetValue(); + inline void SetValue(const LibPrimes_uint64 nValue); + inline void Calculate(); + inline void SetProgressCallback(const ProgressCallback pProgressCallback); }; /************************************************************************************************************************* - Class CLibPrimesFactorizationCalculator + Class CFactorizationCalculator **************************************************************************************************************************/ -class CLibPrimesFactorizationCalculator : public CLibPrimesCalculator { +class CFactorizationCalculator : public CCalculator { public: /** - * CLibPrimesFactorizationCalculator::CLibPrimesFactorizationCalculator - Constructor for FactorizationCalculator class. + * CFactorizationCalculator::CFactorizationCalculator - Constructor for FactorizationCalculator class. */ - CLibPrimesFactorizationCalculator (CLibPrimesWrapper * pWrapper, LibPrimesHandle pHandle) - : CLibPrimesCalculator (pWrapper, pHandle) + CFactorizationCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CCalculator(pWrapper, pHandle) { } - inline void GetPrimeFactors (std::vector & PrimeFactorsBuffer); + inline void GetPrimeFactors(std::vector & PrimeFactorsBuffer); }; /************************************************************************************************************************* - Class CLibPrimesSieveCalculator + Class CSieveCalculator **************************************************************************************************************************/ -class CLibPrimesSieveCalculator : public CLibPrimesCalculator { +class CSieveCalculator : public CCalculator { public: /** - * CLibPrimesSieveCalculator::CLibPrimesSieveCalculator - Constructor for SieveCalculator class. + * CSieveCalculator::CSieveCalculator - Constructor for SieveCalculator class. */ - CLibPrimesSieveCalculator (CLibPrimesWrapper * pWrapper, LibPrimesHandle pHandle) - : CLibPrimesCalculator (pWrapper, pHandle) + CSieveCalculator(CWrapper* pWrapper, LibPrimesHandle pHandle) + : CCalculator(pWrapper, pHandle) { } - inline void GetPrimes (std::vector & PrimesBuffer); + inline void GetPrimes(std::vector & PrimesBuffer); }; /** - * CLibPrimesWrapper::ReleaseInstance - Releases the memory of an Instance + * CWrapper::GetVersion - retrieves the binary version of this library. + * @param[out] nMajor - returns the major version of this library + * @param[out] nMinor - returns the minor version of this library + * @param[out] nMicro - returns the micro version of this library + */ + inline void CWrapper::GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) + { + CheckError(nullptr,m_WrapperTable.m_GetVersion(&nMajor, &nMinor, &nMicro)); + } + + /** + * CWrapper::GetLastError - Returns the last error recorded on this object * @param[in] pInstance - Instance Handle + * @param[out] sErrorMessage - Message of the last error + * @return Is there a last error to query */ - inline void CLibPrimesWrapper::ReleaseInstance (CLibPrimesBaseClass * pInstance) + inline bool CWrapper::GetLastError(CBase * pInstance, std::string & sErrorMessage) { LibPrimesHandle hInstance = nullptr; if (pInstance != nullptr) { - hInstance = pInstance->GetHandle (); + hInstance = pInstance->GetHandle(); }; - CheckError (nullptr, m_WrapperTable.m_ReleaseInstance (hInstance) ); + LibPrimes_uint32 bytesNeededErrorMessage = 0; + LibPrimes_uint32 bytesWrittenErrorMessage = 0; + bool resultHasError = 0; + CheckError(nullptr,m_WrapperTable.m_GetLastError(hInstance, 0, &bytesNeededErrorMessage, nullptr, &resultHasError)); + std::vector bufferErrorMessage; + bufferErrorMessage.resize(bytesNeededErrorMessage + 2); + CheckError(nullptr,m_WrapperTable.m_GetLastError(hInstance, bytesNeededErrorMessage + 2, &bytesWrittenErrorMessage, &bufferErrorMessage[0], &resultHasError)); + bufferErrorMessage[bytesNeededErrorMessage + 1] = 0; + sErrorMessage = std::string(&bufferErrorMessage[0]); + return resultHasError; } /** - * CLibPrimesWrapper::GetLibraryVersion - retrieves the current version of the library. - * @param[out] nMajor - returns the major version of the library - * @param[out] nMinor - returns the minor version of the library - * @param[out] nMicro - returns the micro version of the library + * CWrapper::ReleaseInstance - Releases the memory of an Instance + * @param[in] pInstance - Instance Handle */ - inline void CLibPrimesWrapper::GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) + inline void CWrapper::ReleaseInstance(CBase * pInstance) { - CheckError (nullptr, m_WrapperTable.m_GetLibraryVersion (&nMajor, &nMinor, &nMicro) ); + LibPrimesHandle hInstance = nullptr; + if (pInstance != nullptr) { + hInstance = pInstance->GetHandle(); + }; + CheckError(nullptr,m_WrapperTable.m_ReleaseInstance(hInstance)); } /** - * CLibPrimesWrapper::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance + * CWrapper::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance * @return New FactorizationCalculator instance */ - inline PLibPrimesFactorizationCalculator CLibPrimesWrapper::CreateFactorizationCalculator () + inline PFactorizationCalculator CWrapper::CreateFactorizationCalculator() { LibPrimesHandle hInstance = nullptr; - CheckError (nullptr, m_WrapperTable.m_CreateFactorizationCalculator (&hInstance) ); - return std::make_shared (this, hInstance); + CheckError(nullptr,m_WrapperTable.m_CreateFactorizationCalculator(&hInstance)); + return std::make_shared(this, hInstance); } /** - * CLibPrimesWrapper::CreateSieveCalculator - Creates a new SieveCalculator instance + * CWrapper::CreateSieveCalculator - Creates a new SieveCalculator instance * @return New SieveCalculator instance */ - inline PLibPrimesSieveCalculator CLibPrimesWrapper::CreateSieveCalculator () + inline PSieveCalculator CWrapper::CreateSieveCalculator() { LibPrimesHandle hInstance = nullptr; - CheckError (nullptr, m_WrapperTable.m_CreateSieveCalculator (&hInstance) ); - return std::make_shared (this, hInstance); + CheckError(nullptr,m_WrapperTable.m_CreateSieveCalculator(&hInstance)); + return std::make_shared(this, hInstance); } /** - * CLibPrimesWrapper::SetJournal - Handles Library Journaling + * CWrapper::SetJournal - Handles Library Journaling * @param[in] sFileName - Journal FileName */ - inline void CLibPrimesWrapper::SetJournal (const std::string & sFileName) + inline void CWrapper::SetJournal(const std::string & sFileName) { - CheckError (nullptr, m_WrapperTable.m_SetJournal (sFileName.c_str()) ); + CheckError(nullptr,m_WrapperTable.m_SetJournal(sFileName.c_str())); } + + inline void CWrapper::CheckError(CBase * pBaseClass, LibPrimesResult nResult) + { + if (nResult != 0) { + std::string sErrorMessage; + if (pBaseClass != nullptr) { + GetLastError(pBaseClass, sErrorMessage); + } + throw ELibPrimesException(nResult, sErrorMessage); + } + } + - inline LibPrimesResult CLibPrimesWrapper::initWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable) + inline LibPrimesResult CWrapper::initWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable) { if (pWrapperTable == nullptr) return LIBPRIMES_ERROR_INVALIDPARAM; @@ -354,8 +411,9 @@ class CLibPrimesSieveCalculator : public CLibPrimesCalculator { pWrapperTable->m_Calculator_SetProgressCallback = nullptr; pWrapperTable->m_FactorizationCalculator_GetPrimeFactors = nullptr; pWrapperTable->m_SieveCalculator_GetPrimes = nullptr; + pWrapperTable->m_GetVersion = nullptr; + pWrapperTable->m_GetLastError = nullptr; pWrapperTable->m_ReleaseInstance = nullptr; - pWrapperTable->m_GetLibraryVersion = nullptr; pWrapperTable->m_CreateFactorizationCalculator = nullptr; pWrapperTable->m_CreateSieveCalculator = nullptr; pWrapperTable->m_SetJournal = nullptr; @@ -363,138 +421,155 @@ class CLibPrimesSieveCalculator : public CLibPrimesCalculator { return LIBPRIMES_SUCCESS; } - inline LibPrimesResult CLibPrimesWrapper::releaseWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable) + inline LibPrimesResult CWrapper::releaseWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable) { if (pWrapperTable == nullptr) return LIBPRIMES_ERROR_INVALIDPARAM; if (pWrapperTable->m_LibraryHandle != nullptr) { - #ifdef WIN32 + #ifdef _WIN32 HMODULE hModule = (HMODULE) pWrapperTable->m_LibraryHandle; - FreeLibrary (hModule); - #else // WIN32 - dlclose (pWrapperTable->m_LibraryHandle); - #endif // WIN32 - return initWrapperTable (pWrapperTable); + FreeLibrary(hModule); + #else // _WIN32 + dlclose(pWrapperTable->m_LibraryHandle); + #endif // _WIN32 + return initWrapperTable(pWrapperTable); } return LIBPRIMES_SUCCESS; } - inline LibPrimesResult CLibPrimesWrapper::loadWrapperTable (sLibPrimesDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName) + inline LibPrimesResult CWrapper::loadWrapperTable(sLibPrimesDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName) { if (pWrapperTable == nullptr) return LIBPRIMES_ERROR_INVALIDPARAM; if (pLibraryFileName == nullptr) return LIBPRIMES_ERROR_INVALIDPARAM; - #ifdef WIN32 - HMODULE hLibrary = LoadLibraryA (pLibraryFileName); + #ifdef _WIN32 + // Convert filename to UTF16-string + int nLength = (int)strlen(pLibraryFileName); + int nBufferSize = nLength * 2 + 2; + std::vector wsLibraryFileName(nBufferSize); + int nResult = MultiByteToWideChar(CP_UTF8, 0, pLibraryFileName, nLength, &wsLibraryFileName[0], nBufferSize); + if (nResult == 0) + return LIBPRIMES_ERROR_COULDNOTLOADLIBRARY; + + HMODULE hLibrary = LoadLibraryW(wsLibraryFileName.data()); if (hLibrary == 0) return LIBPRIMES_ERROR_COULDNOTLOADLIBRARY; - #else // WIN32 - void* hLibrary = dlopen (pLibraryFileName, RTLD_LAZY); + #else // _WIN32 + void* hLibrary = dlopen(pLibraryFileName, RTLD_LAZY); if (hLibrary == 0) return LIBPRIMES_ERROR_COULDNOTLOADLIBRARY; dlerror(); - #endif // WIN32 + #endif // _WIN32 - #ifdef WIN32 - pWrapperTable->m_Calculator_GetValue = (PLibPrimesCalculator_GetValuePtr) GetProcAddress (hLibrary, "libprimes_calculator_getvalue"); - #else // WIN32 - pWrapperTable->m_Calculator_GetValue = (PLibPrimesCalculator_GetValuePtr) dlsym (hLibrary, "libprimes_calculator_getvalue"); + #ifdef _WIN32 + pWrapperTable->m_Calculator_GetValue = (PLibPrimesCalculator_GetValuePtr) GetProcAddress(hLibrary, "libprimes_calculator_getvalue"); + #else // _WIN32 + pWrapperTable->m_Calculator_GetValue = (PLibPrimesCalculator_GetValuePtr) dlsym(hLibrary, "libprimes_calculator_getvalue"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_Calculator_GetValue == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_Calculator_SetValue = (PLibPrimesCalculator_SetValuePtr) GetProcAddress (hLibrary, "libprimes_calculator_setvalue"); - #else // WIN32 - pWrapperTable->m_Calculator_SetValue = (PLibPrimesCalculator_SetValuePtr) dlsym (hLibrary, "libprimes_calculator_setvalue"); + #ifdef _WIN32 + pWrapperTable->m_Calculator_SetValue = (PLibPrimesCalculator_SetValuePtr) GetProcAddress(hLibrary, "libprimes_calculator_setvalue"); + #else // _WIN32 + pWrapperTable->m_Calculator_SetValue = (PLibPrimesCalculator_SetValuePtr) dlsym(hLibrary, "libprimes_calculator_setvalue"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_Calculator_SetValue == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_Calculator_Calculate = (PLibPrimesCalculator_CalculatePtr) GetProcAddress (hLibrary, "libprimes_calculator_calculate"); - #else // WIN32 - pWrapperTable->m_Calculator_Calculate = (PLibPrimesCalculator_CalculatePtr) dlsym (hLibrary, "libprimes_calculator_calculate"); + #ifdef _WIN32 + pWrapperTable->m_Calculator_Calculate = (PLibPrimesCalculator_CalculatePtr) GetProcAddress(hLibrary, "libprimes_calculator_calculate"); + #else // _WIN32 + pWrapperTable->m_Calculator_Calculate = (PLibPrimesCalculator_CalculatePtr) dlsym(hLibrary, "libprimes_calculator_calculate"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_Calculator_Calculate == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_Calculator_SetProgressCallback = (PLibPrimesCalculator_SetProgressCallbackPtr) GetProcAddress (hLibrary, "libprimes_calculator_setprogresscallback"); - #else // WIN32 - pWrapperTable->m_Calculator_SetProgressCallback = (PLibPrimesCalculator_SetProgressCallbackPtr) dlsym (hLibrary, "libprimes_calculator_setprogresscallback"); + #ifdef _WIN32 + pWrapperTable->m_Calculator_SetProgressCallback = (PLibPrimesCalculator_SetProgressCallbackPtr) GetProcAddress(hLibrary, "libprimes_calculator_setprogresscallback"); + #else // _WIN32 + pWrapperTable->m_Calculator_SetProgressCallback = (PLibPrimesCalculator_SetProgressCallbackPtr) dlsym(hLibrary, "libprimes_calculator_setprogresscallback"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_Calculator_SetProgressCallback == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_FactorizationCalculator_GetPrimeFactors = (PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) GetProcAddress (hLibrary, "libprimes_factorizationcalculator_getprimefactors"); - #else // WIN32 - pWrapperTable->m_FactorizationCalculator_GetPrimeFactors = (PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) dlsym (hLibrary, "libprimes_factorizationcalculator_getprimefactors"); + #ifdef _WIN32 + pWrapperTable->m_FactorizationCalculator_GetPrimeFactors = (PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) GetProcAddress(hLibrary, "libprimes_factorizationcalculator_getprimefactors"); + #else // _WIN32 + pWrapperTable->m_FactorizationCalculator_GetPrimeFactors = (PLibPrimesFactorizationCalculator_GetPrimeFactorsPtr) dlsym(hLibrary, "libprimes_factorizationcalculator_getprimefactors"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_FactorizationCalculator_GetPrimeFactors == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_SieveCalculator_GetPrimes = (PLibPrimesSieveCalculator_GetPrimesPtr) GetProcAddress (hLibrary, "libprimes_sievecalculator_getprimes"); - #else // WIN32 - pWrapperTable->m_SieveCalculator_GetPrimes = (PLibPrimesSieveCalculator_GetPrimesPtr) dlsym (hLibrary, "libprimes_sievecalculator_getprimes"); + #ifdef _WIN32 + pWrapperTable->m_SieveCalculator_GetPrimes = (PLibPrimesSieveCalculator_GetPrimesPtr) GetProcAddress(hLibrary, "libprimes_sievecalculator_getprimes"); + #else // _WIN32 + pWrapperTable->m_SieveCalculator_GetPrimes = (PLibPrimesSieveCalculator_GetPrimesPtr) dlsym(hLibrary, "libprimes_sievecalculator_getprimes"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_SieveCalculator_GetPrimes == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_ReleaseInstance = (PLibPrimesReleaseInstancePtr) GetProcAddress (hLibrary, "libprimes_releaseinstance"); - #else // WIN32 - pWrapperTable->m_ReleaseInstance = (PLibPrimesReleaseInstancePtr) dlsym (hLibrary, "libprimes_releaseinstance"); + #ifdef _WIN32 + pWrapperTable->m_GetVersion = (PLibPrimesGetVersionPtr) GetProcAddress(hLibrary, "libprimes_getversion"); + #else // _WIN32 + pWrapperTable->m_GetVersion = (PLibPrimesGetVersionPtr) dlsym(hLibrary, "libprimes_getversion"); dlerror(); - #endif // WIN32 - if (pWrapperTable->m_ReleaseInstance == nullptr) + #endif // _WIN32 + if (pWrapperTable->m_GetVersion == nullptr) + return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_GetLastError = (PLibPrimesGetLastErrorPtr) GetProcAddress(hLibrary, "libprimes_getlasterror"); + #else // _WIN32 + pWrapperTable->m_GetLastError = (PLibPrimesGetLastErrorPtr) dlsym(hLibrary, "libprimes_getlasterror"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_GetLastError == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_GetLibraryVersion = (PLibPrimesGetLibraryVersionPtr) GetProcAddress (hLibrary, "libprimes_getlibraryversion"); - #else // WIN32 - pWrapperTable->m_GetLibraryVersion = (PLibPrimesGetLibraryVersionPtr) dlsym (hLibrary, "libprimes_getlibraryversion"); + #ifdef _WIN32 + pWrapperTable->m_ReleaseInstance = (PLibPrimesReleaseInstancePtr) GetProcAddress(hLibrary, "libprimes_releaseinstance"); + #else // _WIN32 + pWrapperTable->m_ReleaseInstance = (PLibPrimesReleaseInstancePtr) dlsym(hLibrary, "libprimes_releaseinstance"); dlerror(); - #endif // WIN32 - if (pWrapperTable->m_GetLibraryVersion == nullptr) + #endif // _WIN32 + if (pWrapperTable->m_ReleaseInstance == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_CreateFactorizationCalculator = (PLibPrimesCreateFactorizationCalculatorPtr) GetProcAddress (hLibrary, "libprimes_createfactorizationcalculator"); - #else // WIN32 - pWrapperTable->m_CreateFactorizationCalculator = (PLibPrimesCreateFactorizationCalculatorPtr) dlsym (hLibrary, "libprimes_createfactorizationcalculator"); + #ifdef _WIN32 + pWrapperTable->m_CreateFactorizationCalculator = (PLibPrimesCreateFactorizationCalculatorPtr) GetProcAddress(hLibrary, "libprimes_createfactorizationcalculator"); + #else // _WIN32 + pWrapperTable->m_CreateFactorizationCalculator = (PLibPrimesCreateFactorizationCalculatorPtr) dlsym(hLibrary, "libprimes_createfactorizationcalculator"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_CreateFactorizationCalculator == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_CreateSieveCalculator = (PLibPrimesCreateSieveCalculatorPtr) GetProcAddress (hLibrary, "libprimes_createsievecalculator"); - #else // WIN32 - pWrapperTable->m_CreateSieveCalculator = (PLibPrimesCreateSieveCalculatorPtr) dlsym (hLibrary, "libprimes_createsievecalculator"); + #ifdef _WIN32 + pWrapperTable->m_CreateSieveCalculator = (PLibPrimesCreateSieveCalculatorPtr) GetProcAddress(hLibrary, "libprimes_createsievecalculator"); + #else // _WIN32 + pWrapperTable->m_CreateSieveCalculator = (PLibPrimesCreateSieveCalculatorPtr) dlsym(hLibrary, "libprimes_createsievecalculator"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_CreateSieveCalculator == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; - #ifdef WIN32 - pWrapperTable->m_SetJournal = (PLibPrimesSetJournalPtr) GetProcAddress (hLibrary, "libprimes_setjournal"); - #else // WIN32 - pWrapperTable->m_SetJournal = (PLibPrimesSetJournalPtr) dlsym (hLibrary, "libprimes_setjournal"); + #ifdef _WIN32 + pWrapperTable->m_SetJournal = (PLibPrimesSetJournalPtr) GetProcAddress(hLibrary, "libprimes_setjournal"); + #else // _WIN32 + pWrapperTable->m_SetJournal = (PLibPrimesSetJournalPtr) dlsym(hLibrary, "libprimes_setjournal"); dlerror(); - #endif // WIN32 + #endif // _WIN32 if (pWrapperTable->m_SetJournal == nullptr) return LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -504,58 +579,62 @@ class CLibPrimesSieveCalculator : public CLibPrimesCalculator { /** - * Method definitions for class CLibPrimesCalculator + * Method definitions for class CBase + */ + + /** + * Method definitions for class CCalculator */ - LibPrimes_uint64 CLibPrimesCalculator::GetValue () + LibPrimes_uint64 CCalculator::GetValue() { LibPrimes_uint64 resultValue = 0; - CheckError ( m_pWrapper->m_WrapperTable.m_Calculator_GetValue (m_pHandle, &resultValue) ); + CheckError(m_pWrapper->m_WrapperTable.m_Calculator_GetValue(m_pHandle, &resultValue)); return resultValue; } - void CLibPrimesCalculator::SetValue (const LibPrimes_uint64 nValue) + void CCalculator::SetValue(const LibPrimes_uint64 nValue) { - CheckError ( m_pWrapper->m_WrapperTable.m_Calculator_SetValue (m_pHandle, nValue) ); + CheckError(m_pWrapper->m_WrapperTable.m_Calculator_SetValue(m_pHandle, nValue)); } - void CLibPrimesCalculator::Calculate () + void CCalculator::Calculate() { - CheckError ( m_pWrapper->m_WrapperTable.m_Calculator_Calculate (m_pHandle) ); + CheckError(m_pWrapper->m_WrapperTable.m_Calculator_Calculate(m_pHandle)); } - void CLibPrimesCalculator::SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) + void CCalculator::SetProgressCallback(const ProgressCallback pProgressCallback) { - CheckError ( m_pWrapper->m_WrapperTable.m_Calculator_SetProgressCallback (m_pHandle, pProgressCallback) ); + CheckError(m_pWrapper->m_WrapperTable.m_Calculator_SetProgressCallback(m_pHandle, pProgressCallback)); } /** - * Method definitions for class CLibPrimesFactorizationCalculator + * Method definitions for class CFactorizationCalculator */ - void CLibPrimesFactorizationCalculator::GetPrimeFactors (std::vector & PrimeFactorsBuffer) + void CFactorizationCalculator::GetPrimeFactors(std::vector & PrimeFactorsBuffer) { LibPrimes_uint64 elementsNeededPrimeFactors = 0; LibPrimes_uint64 elementsWrittenPrimeFactors = 0; - CheckError ( m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors (m_pHandle, 0, &elementsNeededPrimeFactors, nullptr) ); - PrimeFactorsBuffer.resize(elementsNeededPrimeFactors); - CheckError ( m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors (m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data()) ); + CheckError(m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors(m_pHandle, 0, &elementsNeededPrimeFactors, nullptr)); + PrimeFactorsBuffer.resize((size_t) elementsNeededPrimeFactors); + CheckError(m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors(m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data())); } /** - * Method definitions for class CLibPrimesSieveCalculator + * Method definitions for class CSieveCalculator */ - void CLibPrimesSieveCalculator::GetPrimes (std::vector & PrimesBuffer) + void CSieveCalculator::GetPrimes(std::vector & PrimesBuffer) { LibPrimes_uint64 elementsNeededPrimes = 0; LibPrimes_uint64 elementsWrittenPrimes = 0; - CheckError ( m_pWrapper->m_WrapperTable.m_SieveCalculator_GetPrimes (m_pHandle, 0, &elementsNeededPrimes, nullptr) ); - PrimesBuffer.resize(elementsNeededPrimes); - CheckError ( m_pWrapper->m_WrapperTable.m_SieveCalculator_GetPrimes (m_pHandle, elementsNeededPrimes, &elementsWrittenPrimes, PrimesBuffer.data()) ); + CheckError(m_pWrapper->m_WrapperTable.m_SieveCalculator_GetPrimes(m_pHandle, 0, &elementsNeededPrimes, nullptr)); + PrimesBuffer.resize((size_t) elementsNeededPrimes); + CheckError(m_pWrapper->m_WrapperTable.m_SieveCalculator_GetPrimes(m_pHandle, elementsNeededPrimes, &elementsWrittenPrimes, PrimesBuffer.data())); } } // namespace LibPrimes -#endif // __LIBPRIMES_DYNAMICCPPHEADER +#endif // __LIBPRIMES_CPPHEADER_DYNAMIC_CPP diff --git a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.h b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.hpp similarity index 65% rename from Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.h rename to Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.hpp index 2b14eea7..e502bbe6 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.h +++ b/Examples/Primes/LibPrimes_component/Bindings/CppDynamic/libprimes_types.hpp @@ -1,20 +1,20 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file with basic types in +Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_TYPES_HEADER -#define __LIBPRIMES_TYPES_HEADER +#ifndef __LIBPRIMES_TYPES_HEADER_CPP +#define __LIBPRIMES_TYPES_HEADER_CPP /************************************************************************************************************************* Scalar types definition @@ -55,6 +55,7 @@ typedef double LibPrimes_double; typedef LibPrimes_int32 LibPrimesResult; typedef void * LibPrimesHandle; +typedef void * LibPrimes_pvoid; /************************************************************************************************************************* Version for LibPrimes @@ -63,6 +64,8 @@ typedef void * LibPrimesHandle; #define LIBPRIMES_VERSION_MAJOR 1 #define LIBPRIMES_VERSION_MINOR 2 #define LIBPRIMES_VERSION_MICRO 0 +#define LIBPRIMES_VERSION_PRERELEASEINFO "" +#define LIBPRIMES_VERSION_BUILDINFO "" /************************************************************************************************************************* Error constants for LibPrimes @@ -84,34 +87,42 @@ typedef void * LibPrimesHandle; Declaration of handle classes **************************************************************************************************************************/ -typedef LibPrimesHandle LibPrimes_BaseClass; +typedef LibPrimesHandle LibPrimes_Base; typedef LibPrimesHandle LibPrimes_Calculator; typedef LibPrimesHandle LibPrimes_FactorizationCalculator; typedef LibPrimesHandle LibPrimes_SieveCalculator; -/************************************************************************************************************************* - Declaration of structs -**************************************************************************************************************************/ - -#pragma pack (1) - -typedef struct { - LibPrimes_uint64 m_Prime; - LibPrimes_uint32 m_Multiplicity; -} sLibPrimesPrimeFactor; - -#pragma pack () - -/************************************************************************************************************************* - Declaration of function pointers -**************************************************************************************************************************/ - -/** -* LibPrimesProgressCallback - Callback to report calculation progress and query whether it should be aborted -* -* @param[in] fProgressPercentage - How far has the calculation progressed? -* @param[out] pShouldAbort - Should the calculation be aborted? -*/ -typedef void(*LibPrimesProgressCallback)(LibPrimes_single, bool*); - -#endif // __LIBPRIMES_TYPES_HEADER +namespace LibPrimes { + + /************************************************************************************************************************* + Declaration of structs + **************************************************************************************************************************/ + + #pragma pack (1) + + typedef struct { + LibPrimes_uint64 m_Prime; + LibPrimes_uint32 m_Multiplicity; + } sPrimeFactor; + + #pragma pack () + + /************************************************************************************************************************* + Declaration of function pointers + **************************************************************************************************************************/ + + /** + * ProgressCallback - Callback to report calculation progress and query whether it should be aborted + * + * @param[in] fProgressPercentage - How far has the calculation progressed? + * @param[out] pShouldAbort - Should the calculation be aborted? + */ + typedef void(*ProgressCallback)(LibPrimes_single, bool*); + +} // namespace LibPrimes; + +// define legacy C-names for enums, structs and function types +typedef LibPrimes::sPrimeFactor sLibPrimesPrimeFactor; +typedef LibPrimes::ProgressCallback LibPrimesProgressCallback; + +#endif // __LIBPRIMES_TYPES_HEADER_CPP diff --git a/Examples/Primes/LibPrimes_component/Bindings/Pascal/Unit_LibPrimes.pas b/Examples/Primes/LibPrimes_component/Bindings/Pascal/Unit_LibPrimes.pas index ab507961..a8bd49d3 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/Pascal/Unit_LibPrimes.pas +++ b/Examples/Primes/LibPrimes_component/Bindings/Pascal/Unit_LibPrimes.pas @@ -1,11 +1,11 @@ {$IFDEF FPC}{$MODE DELPHI}{$ENDIF} (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal Header file in order to allow an easy use of Prime Numbers Library @@ -19,23 +19,25 @@ interface uses - {$IFDEF WINDOWS} - Windows, - {$ELSE} - dynlibs, - {$ENDIF} - Types, - Classes, - SysUtils; + {$IFDEF WINDOWS} + Windows, + {$ELSE} + dynlibs, + {$ENDIF} + Types, + Classes, + SysUtils; (************************************************************************************************************************* Version definition for LibPrimes **************************************************************************************************************************) const - LIBPRIMES_VERSION_MAJOR = 1; - LIBPRIMES_VERSION_MINOR = 2; - LIBPRIMES_VERSION_MICRO = 0; + LIBPRIMES_VERSION_MAJOR = 1; + LIBPRIMES_VERSION_MINOR = 2; + LIBPRIMES_VERSION_MICRO = 0; + LIBPRIMES_VERSION_PRERELEASEINFO = ''; + LIBPRIMES_VERSION_BUILDINFO = ''; (************************************************************************************************************************* @@ -43,28 +45,28 @@ interface **************************************************************************************************************************) type - TLibPrimesResult = Cardinal; - TLibPrimesHandle = Pointer; + TLibPrimesResult = Cardinal; + TLibPrimesHandle = Pointer; - PLibPrimesResult = ^TLibPrimesResult; - PLibPrimesHandle = ^TLibPrimesHandle; + PLibPrimesResult = ^TLibPrimesResult; + PLibPrimesHandle = ^TLibPrimesHandle; (************************************************************************************************************************* Error Constants for LibPrimes **************************************************************************************************************************) const - LIBPRIMES_SUCCESS = 0; - LIBPRIMES_ERROR_NOTIMPLEMENTED = 1; - LIBPRIMES_ERROR_INVALIDPARAM = 2; - LIBPRIMES_ERROR_INVALIDCAST = 3; - LIBPRIMES_ERROR_BUFFERTOOSMALL = 4; - LIBPRIMES_ERROR_GENERICEXCEPTION = 5; - LIBPRIMES_ERROR_COULDNOTLOADLIBRARY = 6; - LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT = 7; - LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION = 8; - LIBPRIMES_ERROR_NORESULTAVAILABLE = 9; - LIBPRIMES_ERROR_CALCULATIONABORTED = 10; + LIBPRIMES_SUCCESS = 0; + LIBPRIMES_ERROR_NOTIMPLEMENTED = 1; + LIBPRIMES_ERROR_INVALIDPARAM = 2; + LIBPRIMES_ERROR_INVALIDCAST = 3; + LIBPRIMES_ERROR_BUFFERTOOSMALL = 4; + LIBPRIMES_ERROR_GENERICEXCEPTION = 5; + LIBPRIMES_ERROR_COULDNOTLOADLIBRARY = 6; + LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT = 7; + LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION = 8; + LIBPRIMES_ERROR_NORESULTAVAILABLE = 9; + LIBPRIMES_ERROR_CALCULATIONABORTED = 10; (************************************************************************************************************************* Declaration of structs @@ -72,18 +74,18 @@ interface type - PLibPrimesPrimeFactor = ^TLibPrimesPrimeFactor; - TLibPrimesPrimeFactor = packed record - FPrime: QWord; - FMultiplicity: Cardinal; - end; + PLibPrimesPrimeFactor = ^TLibPrimesPrimeFactor; + TLibPrimesPrimeFactor = packed record + FPrime: QWord; + FMultiplicity: Cardinal; + end; (************************************************************************************************************************* Declaration of struct arrays **************************************************************************************************************************) - ArrayOfLibPrimesPrimeFactor = array of TLibPrimesPrimeFactor; + ArrayOfLibPrimesPrimeFactor = array of TLibPrimesPrimeFactor; (************************************************************************************************************************* Declaration of function types @@ -91,256 +93,274 @@ interface type - PLibPrimes_ProgressCallback = function(const fProgressPercentage: Single; out pShouldAbort: Byte): Integer; cdecl; + PLibPrimes_ProgressCallback = function(const fProgressPercentage: Single; out pShouldAbort: Byte): Integer; cdecl; (************************************************************************************************************************* Declaration of handle classes **************************************************************************************************************************) type - TLibPrimesBaseClass = class; - TLibPrimesWrapper = class; - TLibPrimesCalculator = class; - TLibPrimesFactorizationCalculator = class; - TLibPrimesSieveCalculator = class; + TLibPrimesWrapper = class; + TLibPrimesBase = class; + TLibPrimesCalculator = class; + TLibPrimesFactorizationCalculator = class; + TLibPrimesSieveCalculator = class; + + +(************************************************************************************************************************* + Function type definitions for Base +**************************************************************************************************************************) (************************************************************************************************************************* Function type definitions for Calculator **************************************************************************************************************************) - (** - * Returns the current value of this Calculator - * - * @param[in] pCalculator - Calculator instance. - * @param[out] pValue - The current value of this Calculator - * @return error code or 0 (success) - *) - TLibPrimesCalculator_GetValueFunc = function (pCalculator: TLibPrimesHandle; out pValue: QWord): TLibPrimesResult; cdecl; - - (** - * Sets the value to be factorized - * - * @param[in] pCalculator - Calculator instance. - * @param[in] nValue - The value to be factorized - * @return error code or 0 (success) - *) - TLibPrimesCalculator_SetValueFunc = function (pCalculator: TLibPrimesHandle; const nValue: QWord): TLibPrimesResult; cdecl; - - (** - * Performs the specific calculation of this Calculator - * - * @param[in] pCalculator - Calculator instance. - * @return error code or 0 (success) - *) - TLibPrimesCalculator_CalculateFunc = function (pCalculator: TLibPrimesHandle): TLibPrimesResult; cdecl; - - (** - * Sets the progress callback function - * - * @param[in] pCalculator - Calculator instance. - * @param[in] pProgressCallback - The progress callback - * @return error code or 0 (success) - *) - TLibPrimesCalculator_SetProgressCallbackFunc = function (pCalculator: TLibPrimesHandle; const pProgressCallback: PLibPrimes_ProgressCallback): TLibPrimesResult; cdecl; - + (** + * Returns the current value of this Calculator + * + * @param[in] pCalculator - Calculator instance. + * @param[out] pValue - The current value of this Calculator + * @return error code or 0 (success) + *) + TLibPrimesCalculator_GetValueFunc = function (pCalculator: TLibPrimesHandle; out pValue: QWord): TLibPrimesResult; cdecl; + + (** + * Sets the value to be factorized + * + * @param[in] pCalculator - Calculator instance. + * @param[in] nValue - The value to be factorized + * @return error code or 0 (success) + *) + TLibPrimesCalculator_SetValueFunc = function (pCalculator: TLibPrimesHandle; const nValue: QWord): TLibPrimesResult; cdecl; + + (** + * Performs the specific calculation of this Calculator + * + * @param[in] pCalculator - Calculator instance. + * @return error code or 0 (success) + *) + TLibPrimesCalculator_CalculateFunc = function (pCalculator: TLibPrimesHandle): TLibPrimesResult; cdecl; + + (** + * Sets the progress callback function + * + * @param[in] pCalculator - Calculator instance. + * @param[in] pProgressCallback - The progress callback + * @return error code or 0 (success) + *) + TLibPrimesCalculator_SetProgressCallbackFunc = function (pCalculator: TLibPrimesHandle; const pProgressCallback: PLibPrimes_ProgressCallback): TLibPrimesResult; cdecl; + (************************************************************************************************************************* Function type definitions for FactorizationCalculator **************************************************************************************************************************) - (** - * Returns the prime factors of this number (without multiplicity) - * - * @param[in] pFactorizationCalculator - FactorizationCalculator instance. - * @param[in] nPrimeFactorsCount - Number of elements in buffer - * @param[out] pPrimeFactorsNeededCount - will be filled with the count of the written elements, or needed buffer size. - * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number - * @return error code or 0 (success) - *) - TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc = function (pFactorizationCalculator: TLibPrimesHandle; const nPrimeFactorsCount: QWord; out pPrimeFactorsNeededCount: QWord; pPrimeFactorsBuffer: PLibPrimesPrimeFactor): TLibPrimesResult; cdecl; - + (** + * Returns the prime factors of this number (without multiplicity) + * + * @param[in] pFactorizationCalculator - FactorizationCalculator instance. + * @param[in] nPrimeFactorsCount - Number of elements in buffer + * @param[out] pPrimeFactorsNeededCount - will be filled with the count of the written elements, or needed buffer size. + * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number + * @return error code or 0 (success) + *) + TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc = function (pFactorizationCalculator: TLibPrimesHandle; const nPrimeFactorsCount: QWord; out pPrimeFactorsNeededCount: QWord; pPrimeFactorsBuffer: PLibPrimesPrimeFactor): TLibPrimesResult; cdecl; + (************************************************************************************************************************* Function type definitions for SieveCalculator **************************************************************************************************************************) - (** - * Returns all prime numbers lower or equal to the sieve's value - * - * @param[in] pSieveCalculator - SieveCalculator instance. - * @param[in] nPrimesCount - Number of elements in buffer - * @param[out] pPrimesNeededCount - will be filled with the count of the written elements, or needed buffer size. - * @param[out] pPrimesBuffer - uint64 buffer of The primes lower or equal to the sieve's value - * @return error code or 0 (success) - *) - TLibPrimesSieveCalculator_GetPrimesFunc = function (pSieveCalculator: TLibPrimesHandle; const nPrimesCount: QWord; out pPrimesNeededCount: QWord; pPrimesBuffer: PQWord): TLibPrimesResult; cdecl; - + (** + * Returns all prime numbers lower or equal to the sieve's value + * + * @param[in] pSieveCalculator - SieveCalculator instance. + * @param[in] nPrimesCount - Number of elements in buffer + * @param[out] pPrimesNeededCount - will be filled with the count of the written elements, or needed buffer size. + * @param[out] pPrimesBuffer - uint64 buffer of The primes lower or equal to the sieve's value + * @return error code or 0 (success) + *) + TLibPrimesSieveCalculator_GetPrimesFunc = function (pSieveCalculator: TLibPrimesHandle; const nPrimesCount: QWord; out pPrimesNeededCount: QWord; pPrimesBuffer: PQWord): TLibPrimesResult; cdecl; + (************************************************************************************************************************* Global function definitions **************************************************************************************************************************) - (** - * Releases the memory of an Instance - * - * @param[in] pInstance - Instance Handle - * @return error code or 0 (success) - *) - TLibPrimesReleaseInstanceFunc = function (const pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; - - (** - * retrieves the current version of the library. - * - * @param[out] pMajor - returns the major version of the library - * @param[out] pMinor - returns the minor version of the library - * @param[out] pMicro - returns the micro version of the library - * @return error code or 0 (success) - *) - TLibPrimesGetLibraryVersionFunc = function (out pMajor: Cardinal; out pMinor: Cardinal; out pMicro: Cardinal): TLibPrimesResult; cdecl; - - (** - * Creates a new FactorizationCalculator instance - * - * @param[out] pInstance - New FactorizationCalculator instance - * @return error code or 0 (success) - *) - TLibPrimesCreateFactorizationCalculatorFunc = function (out pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; - - (** - * Creates a new SieveCalculator instance - * - * @param[out] pInstance - New SieveCalculator instance - * @return error code or 0 (success) - *) - TLibPrimesCreateSieveCalculatorFunc = function (out pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; - - (** - * Handles Library Journaling - * - * @param[in] pFileName - Journal FileName - * @return error code or 0 (success) - *) - TLibPrimesSetJournalFunc = function (const pFileName: PAnsiChar): TLibPrimesResult; cdecl; - + (** + * retrieves the binary version of this library. + * + * @param[out] pMajor - returns the major version of this library + * @param[out] pMinor - returns the minor version of this library + * @param[out] pMicro - returns the micro version of this library + * @return error code or 0 (success) + *) + TLibPrimesGetVersionFunc = function (out pMajor: Cardinal; out pMinor: Cardinal; out pMicro: Cardinal): TLibPrimesResult; cdecl; + + (** + * Returns the last error recorded on this object + * + * @param[in] pInstance - Instance Handle + * @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) + * @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. + * @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL + * @param[out] pHasError - Is there a last error to query + * @return error code or 0 (success) + *) + TLibPrimesGetLastErrorFunc = function (const pInstance: TLibPrimesHandle; const nErrorMessageBufferSize: Cardinal; out pErrorMessageNeededChars: Cardinal; pErrorMessageBuffer: PAnsiChar; out pHasError: Byte): TLibPrimesResult; cdecl; + + (** + * Releases the memory of an Instance + * + * @param[in] pInstance - Instance Handle + * @return error code or 0 (success) + *) + TLibPrimesReleaseInstanceFunc = function (const pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; + + (** + * Creates a new FactorizationCalculator instance + * + * @param[out] pInstance - New FactorizationCalculator instance + * @return error code or 0 (success) + *) + TLibPrimesCreateFactorizationCalculatorFunc = function (out pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; + + (** + * Creates a new SieveCalculator instance + * + * @param[out] pInstance - New SieveCalculator instance + * @return error code or 0 (success) + *) + TLibPrimesCreateSieveCalculatorFunc = function (out pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; + + (** + * Handles Library Journaling + * + * @param[in] pFileName - Journal FileName + * @return error code or 0 (success) + *) + TLibPrimesSetJournalFunc = function (const pFileName: PAnsiChar): TLibPrimesResult; cdecl; + (************************************************************************************************************************* Exception definition **************************************************************************************************************************) - ELibPrimesException = class (Exception) - private - FErrorCode: TLibPrimesResult; - FCustomMessage: String; - public - property ErrorCode: TLibPrimesResult read FErrorCode; - property CustomMessage: String read FCustomMessage; - constructor Create (AErrorCode: TLibPrimesResult); - constructor CreateCustomMessage (AErrorCode: TLibPrimesResult; AMessage: String); - end; + ELibPrimesException = class (Exception) + private + FErrorCode: TLibPrimesResult; + FCustomMessage: String; + public + property ErrorCode: TLibPrimesResult read FErrorCode; + property CustomMessage: String read FCustomMessage; + constructor Create (AErrorCode: TLibPrimesResult; AMessage: String); + constructor CreateCustomMessage (AErrorCode: TLibPrimesResult; AMessage: String); + end; + (************************************************************************************************************************* - Base class definition + Class definition for Base **************************************************************************************************************************) - TLibPrimesBaseClass = class (TObject) - private - FWrapper: TLibPrimesWrapper; - FHandle: TLibPrimesHandle; - public - constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - destructor Destroy; override; - end; + TLibPrimesBase = class (TObject) + private + FWrapper: TLibPrimesWrapper; + FHandle: TLibPrimesHandle; + public + constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + destructor Destroy; override; + end; (************************************************************************************************************************* Class definition for Calculator **************************************************************************************************************************) - TLibPrimesCalculator = class (TLibPrimesBaseClass) - private - public - constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - destructor Destroy; override; - function GetValue(): QWord; - procedure SetValue(const AValue: QWord); - procedure Calculate(); - procedure SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); - end; + TLibPrimesCalculator = class (TLibPrimesBase) + public + constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + destructor Destroy; override; + function GetValue(): QWord; + procedure SetValue(const AValue: QWord); + procedure Calculate(); + procedure SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); + end; (************************************************************************************************************************* Class definition for FactorizationCalculator **************************************************************************************************************************) - TLibPrimesFactorizationCalculator = class (TLibPrimesCalculator) - private - public - constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - destructor Destroy; override; - procedure GetPrimeFactors(out APrimeFactors: ArrayOfLibPrimesPrimeFactor); - end; + TLibPrimesFactorizationCalculator = class (TLibPrimesCalculator) + public + constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + destructor Destroy; override; + procedure GetPrimeFactors(out APrimeFactors: ArrayOfLibPrimesPrimeFactor); + end; (************************************************************************************************************************* Class definition for SieveCalculator **************************************************************************************************************************) - TLibPrimesSieveCalculator = class (TLibPrimesCalculator) - private - public - constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - destructor Destroy; override; - procedure GetPrimes(out APrimes: TQWordDynArray); - end; + TLibPrimesSieveCalculator = class (TLibPrimesCalculator) + public + constructor Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + destructor Destroy; override; + procedure GetPrimes(out APrimes: TQWordDynArray); + end; (************************************************************************************************************************* Wrapper definition **************************************************************************************************************************) - TLibPrimesWrapper = class (TObject) - private - FModule: HMODULE; - FLibPrimesCalculator_GetValueFunc: TLibPrimesCalculator_GetValueFunc; - FLibPrimesCalculator_SetValueFunc: TLibPrimesCalculator_SetValueFunc; - FLibPrimesCalculator_CalculateFunc: TLibPrimesCalculator_CalculateFunc; - FLibPrimesCalculator_SetProgressCallbackFunc: TLibPrimesCalculator_SetProgressCallbackFunc; - FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc: TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc; - FLibPrimesSieveCalculator_GetPrimesFunc: TLibPrimesSieveCalculator_GetPrimesFunc; - FLibPrimesReleaseInstanceFunc: TLibPrimesReleaseInstanceFunc; - FLibPrimesGetLibraryVersionFunc: TLibPrimesGetLibraryVersionFunc; - FLibPrimesCreateFactorizationCalculatorFunc: TLibPrimesCreateFactorizationCalculatorFunc; - FLibPrimesCreateSieveCalculatorFunc: TLibPrimesCreateSieveCalculatorFunc; - FLibPrimesSetJournalFunc: TLibPrimesSetJournalFunc; - - {$IFDEF MSWINDOWS} - function LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean = True): FARPROC; - {$ELSE} - function LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean = True): Pointer; - {$ENDIF MSWINDOWS} - - procedure checkBinaryVersion(); - - protected - property LibPrimesCalculator_GetValueFunc: TLibPrimesCalculator_GetValueFunc read FLibPrimesCalculator_GetValueFunc; - property LibPrimesCalculator_SetValueFunc: TLibPrimesCalculator_SetValueFunc read FLibPrimesCalculator_SetValueFunc; - property LibPrimesCalculator_CalculateFunc: TLibPrimesCalculator_CalculateFunc read FLibPrimesCalculator_CalculateFunc; - property LibPrimesCalculator_SetProgressCallbackFunc: TLibPrimesCalculator_SetProgressCallbackFunc read FLibPrimesCalculator_SetProgressCallbackFunc; - property LibPrimesFactorizationCalculator_GetPrimeFactorsFunc: TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc read FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc; - property LibPrimesSieveCalculator_GetPrimesFunc: TLibPrimesSieveCalculator_GetPrimesFunc read FLibPrimesSieveCalculator_GetPrimesFunc; - property LibPrimesReleaseInstanceFunc: TLibPrimesReleaseInstanceFunc read FLibPrimesReleaseInstanceFunc; - property LibPrimesGetLibraryVersionFunc: TLibPrimesGetLibraryVersionFunc read FLibPrimesGetLibraryVersionFunc; - property LibPrimesCreateFactorizationCalculatorFunc: TLibPrimesCreateFactorizationCalculatorFunc read FLibPrimesCreateFactorizationCalculatorFunc; - property LibPrimesCreateSieveCalculatorFunc: TLibPrimesCreateSieveCalculatorFunc read FLibPrimesCreateSieveCalculatorFunc; - property LibPrimesSetJournalFunc: TLibPrimesSetJournalFunc read FLibPrimesSetJournalFunc; - procedure CheckError (AInstance: TLibPrimesBaseClass; AErrorCode: TLibPrimesResult); - public - constructor Create (ADLLName: String); - destructor Destroy; override; - procedure ReleaseInstance(const AInstance: TLibPrimesBaseClass); - procedure GetLibraryVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); - function CreateFactorizationCalculator(): TLibPrimesFactorizationCalculator; - function CreateSieveCalculator(): TLibPrimesSieveCalculator; - procedure SetJournal(const AFileName: String); - end; + TLibPrimesWrapper = class (TObject) + private + FModule: HMODULE; + FLibPrimesCalculator_GetValueFunc: TLibPrimesCalculator_GetValueFunc; + FLibPrimesCalculator_SetValueFunc: TLibPrimesCalculator_SetValueFunc; + FLibPrimesCalculator_CalculateFunc: TLibPrimesCalculator_CalculateFunc; + FLibPrimesCalculator_SetProgressCallbackFunc: TLibPrimesCalculator_SetProgressCallbackFunc; + FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc: TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc; + FLibPrimesSieveCalculator_GetPrimesFunc: TLibPrimesSieveCalculator_GetPrimesFunc; + FLibPrimesGetVersionFunc: TLibPrimesGetVersionFunc; + FLibPrimesGetLastErrorFunc: TLibPrimesGetLastErrorFunc; + FLibPrimesReleaseInstanceFunc: TLibPrimesReleaseInstanceFunc; + FLibPrimesCreateFactorizationCalculatorFunc: TLibPrimesCreateFactorizationCalculatorFunc; + FLibPrimesCreateSieveCalculatorFunc: TLibPrimesCreateSieveCalculatorFunc; + FLibPrimesSetJournalFunc: TLibPrimesSetJournalFunc; + + {$IFDEF MSWINDOWS} + function LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean = True): FARPROC; + {$ELSE} + function LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean = True): Pointer; + {$ENDIF MSWINDOWS} + + procedure checkBinaryVersion(); + + protected + property LibPrimesCalculator_GetValueFunc: TLibPrimesCalculator_GetValueFunc read FLibPrimesCalculator_GetValueFunc; + property LibPrimesCalculator_SetValueFunc: TLibPrimesCalculator_SetValueFunc read FLibPrimesCalculator_SetValueFunc; + property LibPrimesCalculator_CalculateFunc: TLibPrimesCalculator_CalculateFunc read FLibPrimesCalculator_CalculateFunc; + property LibPrimesCalculator_SetProgressCallbackFunc: TLibPrimesCalculator_SetProgressCallbackFunc read FLibPrimesCalculator_SetProgressCallbackFunc; + property LibPrimesFactorizationCalculator_GetPrimeFactorsFunc: TLibPrimesFactorizationCalculator_GetPrimeFactorsFunc read FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc; + property LibPrimesSieveCalculator_GetPrimesFunc: TLibPrimesSieveCalculator_GetPrimesFunc read FLibPrimesSieveCalculator_GetPrimesFunc; + property LibPrimesGetVersionFunc: TLibPrimesGetVersionFunc read FLibPrimesGetVersionFunc; + property LibPrimesGetLastErrorFunc: TLibPrimesGetLastErrorFunc read FLibPrimesGetLastErrorFunc; + property LibPrimesReleaseInstanceFunc: TLibPrimesReleaseInstanceFunc read FLibPrimesReleaseInstanceFunc; + property LibPrimesCreateFactorizationCalculatorFunc: TLibPrimesCreateFactorizationCalculatorFunc read FLibPrimesCreateFactorizationCalculatorFunc; + property LibPrimesCreateSieveCalculatorFunc: TLibPrimesCreateSieveCalculatorFunc read FLibPrimesCreateSieveCalculatorFunc; + property LibPrimesSetJournalFunc: TLibPrimesSetJournalFunc read FLibPrimesSetJournalFunc; + procedure CheckError (AInstance: TLibPrimesBase; AErrorCode: TLibPrimesResult); + public + constructor Create (ADLLName: String); + destructor Destroy; override; + procedure GetVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); + function GetLastError(const AInstance: TLibPrimesBase; out AErrorMessage: String): Boolean; + procedure ReleaseInstance(const AInstance: TLibPrimesBase); + function CreateFactorizationCalculator(): TLibPrimesFactorizationCalculator; + function CreateSieveCalculator(): TLibPrimesSieveCalculator; + procedure SetJournal(const AFileName: String); + end; implementation @@ -350,266 +370,293 @@ implementation Exception implementation **************************************************************************************************************************) - constructor ELibPrimesException.Create (AErrorCode: TLibPrimesResult); - var - ADescription: String; - begin - FErrorCode := AErrorCode; - case FErrorCode of - LIBPRIMES_ERROR_NOTIMPLEMENTED: ADescription := 'functionality not implemented'; - LIBPRIMES_ERROR_INVALIDPARAM: ADescription := 'an invalid parameter was passed'; - LIBPRIMES_ERROR_INVALIDCAST: ADescription := 'a type cast failed'; - LIBPRIMES_ERROR_BUFFERTOOSMALL: ADescription := 'a provided buffer is too small'; - LIBPRIMES_ERROR_GENERICEXCEPTION: ADescription := 'a generic exception occurred'; - LIBPRIMES_ERROR_COULDNOTLOADLIBRARY: ADescription := 'the library could not be loaded'; - LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT: ADescription := 'a required exported symbol could not be found in the library'; - LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION: ADescription := 'the version of the binary interface does not match the bindings interface'; - LIBPRIMES_ERROR_NORESULTAVAILABLE: ADescription := 'no result is available'; - LIBPRIMES_ERROR_CALCULATIONABORTED: ADescription := 'a calculation has been aborted'; - else - ADescription := 'unknown'; - end; - - inherited Create (Format ('Prime Numbers Library Error - %s (#%d)', [ ADescription, AErrorCode ])); - end; - - constructor ELibPrimesException.CreateCustomMessage (AErrorCode: TLibPrimesResult; AMessage: String); - begin - FCustomMessage := AMessage; - FErrorCode := AErrorCode; - inherited Create (Format ('%s (%d)', [FCustomMessage, AErrorCode])); - end; + constructor ELibPrimesException.Create (AErrorCode: TLibPrimesResult; AMessage: String); + var + ADescription: String; + begin + FErrorCode := AErrorCode; + case FErrorCode of + LIBPRIMES_ERROR_NOTIMPLEMENTED: ADescription := 'functionality not implemented'; + LIBPRIMES_ERROR_INVALIDPARAM: ADescription := 'an invalid parameter was passed'; + LIBPRIMES_ERROR_INVALIDCAST: ADescription := 'a type cast failed'; + LIBPRIMES_ERROR_BUFFERTOOSMALL: ADescription := 'a provided buffer is too small'; + LIBPRIMES_ERROR_GENERICEXCEPTION: ADescription := 'a generic exception occurred'; + LIBPRIMES_ERROR_COULDNOTLOADLIBRARY: ADescription := 'the library could not be loaded'; + LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT: ADescription := 'a required exported symbol could not be found in the library'; + LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION: ADescription := 'the version of the binary interface does not match the bindings interface'; + LIBPRIMES_ERROR_NORESULTAVAILABLE: ADescription := 'no result is available'; + LIBPRIMES_ERROR_CALCULATIONABORTED: ADescription := 'a calculation has been aborted'; + else + ADescription := 'unknown'; + end; + + inherited Create (Format ('Prime Numbers Library Error - %s (#%d, %s)', [ ADescription, AErrorCode, AMessage ])); + end; + + constructor ELibPrimesException.CreateCustomMessage (AErrorCode: TLibPrimesResult; AMessage: String); + begin + FCustomMessage := AMessage; + FErrorCode := AErrorCode; + inherited Create (Format ('%s (%d)', [FCustomMessage, AErrorCode])); + end; (************************************************************************************************************************* - Base class implementation + Class implementation for Base **************************************************************************************************************************) - constructor TLibPrimesBaseClass.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - begin - if not Assigned (AWrapper) then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); - if not Assigned (AHandle) then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); + constructor TLibPrimesBase.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + begin + if not Assigned (AWrapper) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM, ''); + if not Assigned (AHandle) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM, ''); - inherited Create (); - FWrapper := AWrapper; - FHandle := AHandle; - end; + inherited Create (); + FWrapper := AWrapper; + FHandle := AHandle; + end; - destructor TLibPrimesBaseClass.Destroy; - begin - FWrapper.ReleaseInstance(self); - inherited; - end; + destructor TLibPrimesBase.Destroy; + begin + FWrapper.ReleaseInstance(self); + inherited; + end; (************************************************************************************************************************* Class implementation for Calculator **************************************************************************************************************************) - constructor TLibPrimesCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - begin - inherited Create (AWrapper, AHandle); - end; - - destructor TLibPrimesCalculator.Destroy; - begin - inherited; - end; - - function TLibPrimesCalculator.GetValue(): QWord; - begin - FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_GetValueFunc (FHandle, Result)); - end; - - procedure TLibPrimesCalculator.SetValue(const AValue: QWord); - begin - FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_SetValueFunc (FHandle, AValue)); - end; - - procedure TLibPrimesCalculator.Calculate(); - begin - FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_CalculateFunc (FHandle)); - end; - - procedure TLibPrimesCalculator.SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); - begin - if not Assigned (AProgressCallback) then - raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDPARAM, 'AProgressCallback is a nil value.'); - FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_SetProgressCallbackFunc (FHandle, AProgressCallback)); - end; + constructor TLibPrimesCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + begin + inherited Create (AWrapper, AHandle); + end; + + destructor TLibPrimesCalculator.Destroy; + begin + inherited; + end; + + function TLibPrimesCalculator.GetValue(): QWord; + begin + FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_GetValueFunc (FHandle, Result)); + end; + + procedure TLibPrimesCalculator.SetValue(const AValue: QWord); + begin + FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_SetValueFunc (FHandle, AValue)); + end; + + procedure TLibPrimesCalculator.Calculate(); + begin + FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_CalculateFunc (FHandle)); + end; + + procedure TLibPrimesCalculator.SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); + begin + if not Assigned (AProgressCallback) then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDPARAM, 'AProgressCallback is a nil value.'); + FWrapper.CheckError (Self, FWrapper.LibPrimesCalculator_SetProgressCallbackFunc (FHandle, AProgressCallback)); + end; (************************************************************************************************************************* Class implementation for FactorizationCalculator **************************************************************************************************************************) - constructor TLibPrimesFactorizationCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - begin - inherited Create (AWrapper, AHandle); - end; - - destructor TLibPrimesFactorizationCalculator.Destroy; - begin - inherited; - end; - - procedure TLibPrimesFactorizationCalculator.GetPrimeFactors(out APrimeFactors: ArrayOfLibPrimesPrimeFactor); - var - countNeededPrimeFactors: QWord; - countWrittenPrimeFactors: QWord; - begin - countNeededPrimeFactors:= 0; - countWrittenPrimeFactors:= 0; - FWrapper.CheckError (Self, FWrapper.LibPrimesFactorizationCalculator_GetPrimeFactorsFunc (FHandle, 0, countNeededPrimeFactors, nil)); - SetLength (APrimeFactors, countNeededPrimeFactors); - FWrapper.CheckError (Self, FWrapper.LibPrimesFactorizationCalculator_GetPrimeFactorsFunc (FHandle, countNeededPrimeFactors, countWrittenPrimeFactors, @APrimeFactors[0])); - end; + constructor TLibPrimesFactorizationCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + begin + inherited Create (AWrapper, AHandle); + end; + + destructor TLibPrimesFactorizationCalculator.Destroy; + begin + inherited; + end; + + procedure TLibPrimesFactorizationCalculator.GetPrimeFactors(out APrimeFactors: ArrayOfLibPrimesPrimeFactor); + var + countNeededPrimeFactors: QWord; + countWrittenPrimeFactors: QWord; + begin + countNeededPrimeFactors:= 0; + countWrittenPrimeFactors:= 0; + FWrapper.CheckError (Self, FWrapper.LibPrimesFactorizationCalculator_GetPrimeFactorsFunc (FHandle, 0, countNeededPrimeFactors, nil)); + SetLength (APrimeFactors, countNeededPrimeFactors); + FWrapper.CheckError (Self, FWrapper.LibPrimesFactorizationCalculator_GetPrimeFactorsFunc (FHandle, countNeededPrimeFactors, countWrittenPrimeFactors, @APrimeFactors[0])); + end; (************************************************************************************************************************* Class implementation for SieveCalculator **************************************************************************************************************************) - constructor TLibPrimesSieveCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); - begin - inherited Create (AWrapper, AHandle); - end; - - destructor TLibPrimesSieveCalculator.Destroy; - begin - inherited; - end; - - procedure TLibPrimesSieveCalculator.GetPrimes(out APrimes: TQWordDynArray); - var - countNeededPrimes: QWord; - countWrittenPrimes: QWord; - begin - countNeededPrimes:= 0; - countWrittenPrimes:= 0; - FWrapper.CheckError (Self, FWrapper.LibPrimesSieveCalculator_GetPrimesFunc (FHandle, 0, countNeededPrimes, nil)); - SetLength (APrimes, countNeededPrimes); - FWrapper.CheckError (Self, FWrapper.LibPrimesSieveCalculator_GetPrimesFunc (FHandle, countNeededPrimes, countWrittenPrimes, @APrimes[0])); - end; + constructor TLibPrimesSieveCalculator.Create (AWrapper: TLibPrimesWrapper; AHandle: TLibPrimesHandle); + begin + inherited Create (AWrapper, AHandle); + end; + + destructor TLibPrimesSieveCalculator.Destroy; + begin + inherited; + end; + + procedure TLibPrimesSieveCalculator.GetPrimes(out APrimes: TQWordDynArray); + var + countNeededPrimes: QWord; + countWrittenPrimes: QWord; + begin + countNeededPrimes:= 0; + countWrittenPrimes:= 0; + FWrapper.CheckError (Self, FWrapper.LibPrimesSieveCalculator_GetPrimesFunc (FHandle, 0, countNeededPrimes, nil)); + SetLength (APrimes, countNeededPrimes); + FWrapper.CheckError (Self, FWrapper.LibPrimesSieveCalculator_GetPrimesFunc (FHandle, countNeededPrimes, countWrittenPrimes, @APrimes[0])); + end; (************************************************************************************************************************* Wrapper class implementation **************************************************************************************************************************) - constructor TLibPrimesWrapper.Create (ADLLName: String); + constructor TLibPrimesWrapper.Create (ADLLName: String); + {$IFDEF MSWINDOWS} + var + AWideString: WideString; + {$ENDIF MSWINDOWS} + begin + inherited Create; {$IFDEF MSWINDOWS} - var - AWideString: WideString; + AWideString := UTF8Decode(ADLLName + #0); + FModule := LoadLibraryW (PWideChar (AWideString)); + {$ELSE} + FModule := dynlibs.LoadLibrary (ADLLName); {$ENDIF MSWINDOWS} - begin - inherited Create; - {$IFDEF MSWINDOWS} - AWideString := UTF8Decode(ADLLName + #0); - FModule := LoadLibraryW (PWideChar (AWideString)); - {$ELSE} - FModule := dynlibs.LoadLibrary (ADLLName); - {$ENDIF MSWINDOWS} - if FModule = 0 then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_COULDNOTLOADLIBRARY); - - FLibPrimesCalculator_GetValueFunc := LoadFunction ('libprimes_calculator_getvalue'); - FLibPrimesCalculator_SetValueFunc := LoadFunction ('libprimes_calculator_setvalue'); - FLibPrimesCalculator_CalculateFunc := LoadFunction ('libprimes_calculator_calculate'); - FLibPrimesCalculator_SetProgressCallbackFunc := LoadFunction ('libprimes_calculator_setprogresscallback'); - FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc := LoadFunction ('libprimes_factorizationcalculator_getprimefactors'); - FLibPrimesSieveCalculator_GetPrimesFunc := LoadFunction ('libprimes_sievecalculator_getprimes'); - FLibPrimesReleaseInstanceFunc := LoadFunction ('libprimes_releaseinstance'); - FLibPrimesGetLibraryVersionFunc := LoadFunction ('libprimes_getlibraryversion'); - FLibPrimesCreateFactorizationCalculatorFunc := LoadFunction ('libprimes_createfactorizationcalculator'); - FLibPrimesCreateSieveCalculatorFunc := LoadFunction ('libprimes_createsievecalculator'); - FLibPrimesSetJournalFunc := LoadFunction ('libprimes_setjournal'); - - checkBinaryVersion(); - end; - - destructor TLibPrimesWrapper.Destroy; - begin - {$IFDEF MSWINDOWS} - if FModule <> 0 then - FreeLibrary (FModule); - {$ELSE} - if FModule <> 0 then - UnloadLibrary (FModule); - {$ENDIF MSWINDOWS} - inherited; - end; - - procedure TLibPrimesWrapper.CheckError (AInstance: TLibPrimesBaseClass; AErrorCode: TLibPrimesResult); - begin - if AInstance <> nil then begin - if AInstance.FWrapper <> Self then - raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDCAST, 'invalid wrapper call'); - end; - if AErrorCode <> LIBPRIMES_SUCCESS then - raise ELibPrimesException.Create (AErrorCode); - end; + if FModule = 0 then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_COULDNOTLOADLIBRARY, ''); + + FLibPrimesCalculator_GetValueFunc := LoadFunction ('libprimes_calculator_getvalue'); + FLibPrimesCalculator_SetValueFunc := LoadFunction ('libprimes_calculator_setvalue'); + FLibPrimesCalculator_CalculateFunc := LoadFunction ('libprimes_calculator_calculate'); + FLibPrimesCalculator_SetProgressCallbackFunc := LoadFunction ('libprimes_calculator_setprogresscallback'); + FLibPrimesFactorizationCalculator_GetPrimeFactorsFunc := LoadFunction ('libprimes_factorizationcalculator_getprimefactors'); + FLibPrimesSieveCalculator_GetPrimesFunc := LoadFunction ('libprimes_sievecalculator_getprimes'); + FLibPrimesGetVersionFunc := LoadFunction ('libprimes_getversion'); + FLibPrimesGetLastErrorFunc := LoadFunction ('libprimes_getlasterror'); + FLibPrimesReleaseInstanceFunc := LoadFunction ('libprimes_releaseinstance'); + FLibPrimesCreateFactorizationCalculatorFunc := LoadFunction ('libprimes_createfactorizationcalculator'); + FLibPrimesCreateSieveCalculatorFunc := LoadFunction ('libprimes_createsievecalculator'); + FLibPrimesSetJournalFunc := LoadFunction ('libprimes_setjournal'); + + checkBinaryVersion(); + end; + destructor TLibPrimesWrapper.Destroy; + begin {$IFDEF MSWINDOWS} - function TLibPrimesWrapper.LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean): FARPROC; - begin - Result := GetProcAddress (FModule, PAnsiChar (AFunctionName)); - if FailIfNotExistent and not Assigned (Result) then - raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT, 'could not find function ' + AFunctionName); - end; + if FModule <> 0 then + FreeLibrary (FModule); {$ELSE} - function TLibPrimesWrapper.LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean): Pointer; - begin - Result := dynlibs.GetProcAddress (FModule, AFunctionName); - if FailIfNotExistent and not Assigned (Result) then - raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT, 'could not find function ' + AFunctionName); - end; + if FModule <> 0 then + UnloadLibrary (FModule); {$ENDIF MSWINDOWS} - - procedure TLibPrimesWrapper.checkBinaryVersion(); - var - AMajor, AMinor, AMicro: Cardinal; - begin - GetLibraryVersion(AMajor, AMinor, AMicro); - if (AMajor <> LIBPRIMES_VERSION_MAJOR) or (AMinor < LIBPRIMES_VERSION_MINOR) then - raise ELibPrimesException.Create(LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION); - end; - - procedure TLibPrimesWrapper.ReleaseInstance(const AInstance: TLibPrimesBaseClass); - begin - if not Assigned (AInstance) then - raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDPARAM, 'AInstance is a nil value.'); - CheckError (nil, LibPrimesReleaseInstanceFunc (AInstance.FHandle)); - end; - - procedure TLibPrimesWrapper.GetLibraryVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); - begin - CheckError (nil, LibPrimesGetLibraryVersionFunc (AMajor, AMinor, AMicro)); - end; - - function TLibPrimesWrapper.CreateFactorizationCalculator(): TLibPrimesFactorizationCalculator; - var - HInstance: TLibPrimesHandle; - begin - Result := nil; - HInstance := nil; - CheckError (nil, LibPrimesCreateFactorizationCalculatorFunc (HInstance)); - if Assigned (HInstance) then - Result := TLibPrimesFactorizationCalculator.Create (Self, HInstance); - end; - - function TLibPrimesWrapper.CreateSieveCalculator(): TLibPrimesSieveCalculator; - var - HInstance: TLibPrimesHandle; - begin - Result := nil; - HInstance := nil; - CheckError (nil, LibPrimesCreateSieveCalculatorFunc (HInstance)); - if Assigned (HInstance) then - Result := TLibPrimesSieveCalculator.Create (Self, HInstance); - end; - - procedure TLibPrimesWrapper.SetJournal(const AFileName: String); - begin - CheckError (nil, LibPrimesSetJournalFunc (PAnsiChar (AFileName))); - end; + inherited; + end; + + procedure TLibPrimesWrapper.CheckError (AInstance: TLibPrimesBase; AErrorCode: TLibPrimesResult); + var + AErrorMessage: String; + begin + if AInstance <> nil then begin + if AInstance.FWrapper <> Self then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDCAST, 'invalid wrapper call'); + end; + if AErrorCode <> LIBPRIMES_SUCCESS then begin + AErrorMessage := ''; + if Assigned (AInstance) then + GetLastError(AInstance, AErrorMessage); + raise ELibPrimesException.Create (AErrorCode, AErrorMessage); + end; + end; + + {$IFDEF MSWINDOWS} + function TLibPrimesWrapper.LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean): FARPROC; + begin + Result := GetProcAddress (FModule, PAnsiChar (AFunctionName)); + if FailIfNotExistent and not Assigned (Result) then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT, 'could not find function ' + AFunctionName); + end; + {$ELSE} + function TLibPrimesWrapper.LoadFunction (AFunctionName: AnsiString; FailIfNotExistent: Boolean): Pointer; + begin + Result := dynlibs.GetProcAddress (FModule, AFunctionName); + if FailIfNotExistent and not Assigned (Result) then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_COULDNOTFINDLIBRARYEXPORT, 'could not find function ' + AFunctionName); + end; + {$ENDIF MSWINDOWS} + + procedure TLibPrimesWrapper.checkBinaryVersion(); + var + AMajor, AMinor, AMicro: Cardinal; + begin + GetVersion(AMajor, AMinor, AMicro); + if (AMajor <> LIBPRIMES_VERSION_MAJOR) or (AMinor < LIBPRIMES_VERSION_MINOR) then + raise ELibPrimesException.Create(LIBPRIMES_ERROR_INCOMPATIBLEBINARYVERSION, ''); + end; + + procedure TLibPrimesWrapper.GetVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); + begin + CheckError (nil, LibPrimesGetVersionFunc (AMajor, AMinor, AMicro)); + end; + + function TLibPrimesWrapper.GetLastError(const AInstance: TLibPrimesBase; out AErrorMessage: String): Boolean; + var + bytesNeededErrorMessage: Cardinal; + bytesWrittenErrorMessage: Cardinal; + bufferErrorMessage: array of Char; + ResultHasError: Byte; + begin + if not Assigned (AInstance) then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDPARAM, 'AInstance is a nil value.'); + bytesNeededErrorMessage:= 0; + bytesWrittenErrorMessage:= 0; + ResultHasError := 0; + CheckError (nil, LibPrimesGetLastErrorFunc (AInstance.FHandle, 0, bytesNeededErrorMessage, nil, ResultHasError)); + SetLength (bufferErrorMessage, bytesNeededErrorMessage + 2); + CheckError (nil, LibPrimesGetLastErrorFunc (AInstance.FHandle, bytesNeededErrorMessage + 1, bytesWrittenErrorMessage, @bufferErrorMessage[0], ResultHasError)); + bufferErrorMessage[bytesNeededErrorMessage + 1] := #0; + AErrorMessage := StrPas (@bufferErrorMessage[0]); + Result := (ResultHasError <> 0); + end; + + procedure TLibPrimesWrapper.ReleaseInstance(const AInstance: TLibPrimesBase); + begin + if not Assigned (AInstance) then + raise ELibPrimesException.CreateCustomMessage (LIBPRIMES_ERROR_INVALIDPARAM, 'AInstance is a nil value.'); + CheckError (nil, LibPrimesReleaseInstanceFunc (AInstance.FHandle)); + end; + + function TLibPrimesWrapper.CreateFactorizationCalculator(): TLibPrimesFactorizationCalculator; + var + HInstance: TLibPrimesHandle; + begin + Result := nil; + HInstance := nil; + CheckError (nil, LibPrimesCreateFactorizationCalculatorFunc (HInstance)); + if Assigned (HInstance) then + Result := TLibPrimesFactorizationCalculator.Create (Self, HInstance); + end; + + function TLibPrimesWrapper.CreateSieveCalculator(): TLibPrimesSieveCalculator; + var + HInstance: TLibPrimesHandle; + begin + Result := nil; + HInstance := nil; + CheckError (nil, LibPrimesCreateSieveCalculatorFunc (HInstance)); + if Assigned (HInstance) then + Result := TLibPrimesSieveCalculator.Create (Self, HInstance); + end; + + procedure TLibPrimesWrapper.SetJournal(const AFileName: String); + begin + CheckError (nil, LibPrimesSetJournalFunc (PAnsiChar (AFileName))); + end; end. diff --git a/Examples/Primes/LibPrimes_component/Bindings/Python/LibPrimes.py b/Examples/Primes/LibPrimes_component/Bindings/Python/LibPrimes.py index 32645f3c..750a55da 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/Python/LibPrimes.py +++ b/Examples/Primes/LibPrimes_component/Bindings/Python/LibPrimes.py @@ -1,10 +1,10 @@ '''++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Python file in order to allow an easy use of Prime Numbers Library @@ -18,6 +18,8 @@ import platform import enum +name = "libprimes" + '''Definition of domain specific exception ''' class ELibPrimesException(Exception): @@ -32,14 +34,14 @@ def __str__(self): '''Definition of binding API version ''' -class LibPrimesBindingVersion(enum.IntEnum): +class BindingVersion(enum.IntEnum): MAJOR = 1 MINOR = 2 MICRO = 0 '''Definition Error Codes ''' -class LibPrimesErrorCodes(enum.IntEnum): +class ErrorCodes(enum.IntEnum): SUCCESS = 0 NOTIMPLEMENTED = 1 INVALIDPARAM = 2 @@ -54,9 +56,9 @@ class LibPrimesErrorCodes(enum.IntEnum): '''Definition of Structs ''' -'''Definition of LibPrimesPrimeFactor +'''Definition of PrimeFactor ''' -class LibPrimesPrimeFactor(ctypes.Structure): +class PrimeFactor(ctypes.Structure): _pack_ = 1 _fields_ = [ ("Prime", ctypes.c_uint64), @@ -65,17 +67,17 @@ class LibPrimesPrimeFactor(ctypes.Structure): '''Definition of Function Types ''' -'''Definition of LibPrimesProgressCallback +'''Definition of ProgressCallback Callback to report calculation progress and query whether it should be aborted ''' -LibPrimesProgressCallback = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_float, ctypes.POINTER(ctypes.c_bool)) +ProgressCallback = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_float, ctypes.POINTER(ctypes.c_bool)) '''Wrapper Class Implementation ''' -class LibPrimesWrapper: +class Wrapper: - def __init__(self, libraryName): + def __init__(self, libraryName = None): ending = '' if platform.system() == 'Windows': ending = 'dll' @@ -84,14 +86,16 @@ def __init__(self, libraryName): elif platform.system() == 'Darwin': ending = 'dylib' else: - raise ELibPrimesException(LibPrimesErrorCodes.COULDNOTLOADLIBRARY) + raise ELibPrimesException(ErrorCodes.COULDNOTLOADLIBRARY) + if (not libraryName): + libraryName = os.path.join(os.path.dirname(os.path.realpath(__file__)),'libprimes') path = libraryName + '.' + ending try: self.lib = ctypes.CDLL(path) except Exception as e: - raise ELibPrimesException(LibPrimesErrorCodes.COULDNOTLOADLIBRARY, str(e) + '| "'+path + '"' ) + raise ELibPrimesException(ErrorCodes.COULDNOTLOADLIBRARY, str(e) + '| "'+path + '"' ) self._loadFunctionTable() @@ -99,12 +103,15 @@ def __init__(self, libraryName): def _loadFunctionTable(self): try: + self.lib.libprimes_getversion.restype = ctypes.c_int64 + self.lib.libprimes_getversion.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] + + self.lib.libprimes_getlasterror.restype = ctypes.c_int64 + self.lib.libprimes_getlasterror.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64), ctypes.c_char_p, ctypes.POINTER(ctypes.c_bool)] + self.lib.libprimes_releaseinstance.restype = ctypes.c_int64 self.lib.libprimes_releaseinstance.argtypes = [ctypes.c_void_p] - self.lib.libprimes_getlibraryversion.restype = ctypes.c_int64 - self.lib.libprimes_getlibraryversion.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)] - self.lib.libprimes_createfactorizationcalculator.restype = ctypes.c_int64 self.lib.libprimes_createfactorizationcalculator.argtypes = [ctypes.POINTER(ctypes.c_void_p)] @@ -124,61 +131,75 @@ def _loadFunctionTable(self): self.lib.libprimes_calculator_calculate.argtypes = [ctypes.c_void_p] self.lib.libprimes_calculator_setprogresscallback.restype = ctypes.c_int64 - self.lib.libprimes_calculator_setprogresscallback.argtypes = [ctypes.c_void_p, LibPrimesProgressCallback] + self.lib.libprimes_calculator_setprogresscallback.argtypes = [ctypes.c_void_p, ProgressCallback] self.lib.libprimes_factorizationcalculator_getprimefactors.restype = ctypes.c_int64 - self.lib.libprimes_factorizationcalculator_getprimefactors.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(LibPrimesPrimeFactor)] + self.lib.libprimes_factorizationcalculator_getprimefactors.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(PrimeFactor)] self.lib.libprimes_sievecalculator_getprimes.restype = ctypes.c_int64 self.lib.libprimes_sievecalculator_getprimes.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_uint64)] except AttributeError as ae: - raise ELibPrimesException(LibPrimesErrorCodes.COULDNOTFINDLIBRARYEXPORT, ae.args[0]) + raise ELibPrimesException(ErrorCodes.COULDNOTFINDLIBRARYEXPORT, ae.args[0]) def _checkBinaryVersion(self): - nMajor, nMinor, _ = self.GetLibraryVersion() - if (nMajor != LibPrimesBindingVersion.MAJOR) or (nMinor < LibPrimesBindingVersion.MINOR): - raise ELibPrimesException(LibPrimesErrorCodes.INCOMPATIBLEBINARYVERSION) + nMajor, nMinor, _ = self.GetVersion() + if (nMajor != BindingVersion.MAJOR) or (nMinor < BindingVersion.MINOR): + raise ELibPrimesException(ErrorCodes.INCOMPATIBLEBINARYVERSION) def checkError(self, instance, errorCode): - if instance: - if instance._wrapper != self: - raise ELibPrimesException(LibPrimesErrorCodes.INVALIDCAST, 'invalid wrapper call') - if errorCode != LibPrimesErrorCodes.SUCCESS.value: - raise ELibPrimesException(errorCode) + if errorCode != ErrorCodes.SUCCESS.value: + if instance: + if instance._wrapper != self: + raise ELibPrimesException(ErrorCodes.INVALIDCAST, 'invalid wrapper call') + message,_ = self.GetLastError(instance) + raise ELibPrimesException(errorCode, message) - def ReleaseInstance(self, InstanceObject): - self.checkError(None, self.lib.libprimes_releaseinstance(InstanceObject._handle)) - - def GetLibraryVersion(self): + def GetVersion(self): pMajor = ctypes.c_uint32() pMinor = ctypes.c_uint32() pMicro = ctypes.c_uint32() - self.checkError(None, self.lib.libprimes_getlibraryversion(pMajor, pMinor, pMicro)) + self.checkError(None, self.lib.libprimes_getversion(pMajor, pMinor, pMicro)) return pMajor.value, pMinor.value, pMicro.value + def GetLastError(self, InstanceObject): + nErrorMessageBufferSize = ctypes.c_uint64(0) + nErrorMessageNeededChars = ctypes.c_uint64(0) + pErrorMessageBuffer = ctypes.c_char_p(None) + pHasError = ctypes.c_bool() + self.checkError(None, self.lib.libprimes_getlasterror(InstanceObject._handle, nErrorMessageBufferSize, nErrorMessageNeededChars, pErrorMessageBuffer, pHasError)) + nErrorMessageBufferSize = ctypes.c_uint64(nErrorMessageNeededChars.value + 2) + pErrorMessageBuffer = (ctypes.c_char * (nErrorMessageNeededChars.value + 2))() + self.checkError(None, self.lib.libprimes_getlasterror(InstanceObject._handle, nErrorMessageBufferSize, nErrorMessageNeededChars, pErrorMessageBuffer, pHasError)) + return pErrorMessageBuffer.value.decode(), pHasError.value + + def ReleaseInstance(self, InstanceObject): + self.checkError(None, self.lib.libprimes_releaseinstance(InstanceObject._handle)) + def CreateFactorizationCalculator(self): InstanceHandle = ctypes.c_void_p() self.checkError(None, self.lib.libprimes_createfactorizationcalculator(InstanceHandle)) - InstanceObject = LibPrimesFactorizationCalculator(InstanceHandle, self) + InstanceObject = FactorizationCalculator(InstanceHandle, self) return InstanceObject def CreateSieveCalculator(self): InstanceHandle = ctypes.c_void_p() self.checkError(None, self.lib.libprimes_createsievecalculator(InstanceHandle)) - InstanceObject = LibPrimesSieveCalculator(InstanceHandle, self) + InstanceObject = SieveCalculator(InstanceHandle, self) return InstanceObject def SetJournal(self, FileName): pFileName = ctypes.c_char_p(str.encode(FileName)) self.checkError(None, self.lib.libprimes_setjournal(pFileName)) -'''Base Class Implementation + + +''' Class Implementation for Base ''' -class LibPrimesBaseClass(): +class Base: def __init__(self, handle, wrapper): if not handle or not wrapper: - raise ELibPrimesException() + raise ELibPrimesException(ErrorCodes.INVALIDPARAM) self._handle = handle self._wrapper = wrapper @@ -186,12 +207,11 @@ def __del__(self): self._wrapper.ReleaseInstance(self) -'''Calculator Class Implementation +''' Class Implementation for Calculator ''' -class LibPrimesCalculator(LibPrimesBaseClass): +class Calculator(Base): def __init__(self, handle, wrapper): - LibPrimesBaseClass.__init__(self, handle, wrapper) - + Base.__init__(self, handle, wrapper) def GetValue(self): pValue = ctypes.c_uint64() self._wrapper.checkError(self, self._wrapper.lib.libprimes_calculator_getvalue(self._handle, pValue)) @@ -209,30 +229,28 @@ def SetProgressCallback(self, ProgressCallbackFunc): -'''FactorizationCalculator Class Implementation +''' Class Implementation for FactorizationCalculator ''' -class LibPrimesFactorizationCalculator(LibPrimesCalculator): +class FactorizationCalculator(Calculator): def __init__(self, handle, wrapper): - LibPrimesBaseClass.__init__(self, handle, wrapper) - + Calculator.__init__(self, handle, wrapper) def GetPrimeFactors(self): nPrimeFactorsCount = ctypes.c_uint64(0) nPrimeFactorsNeededCount = ctypes.c_uint64(0) - pPrimeFactorsBuffer = (LibPrimesPrimeFactor*0)() + pPrimeFactorsBuffer = (PrimeFactor*0)() self._wrapper.checkError(self, self._wrapper.lib.libprimes_factorizationcalculator_getprimefactors(self._handle, nPrimeFactorsCount, nPrimeFactorsNeededCount, pPrimeFactorsBuffer)) nPrimeFactorsCount = ctypes.c_uint64(nPrimeFactorsNeededCount.value) - pPrimeFactorsBuffer = (LibPrimesPrimeFactor * nPrimeFactorsNeededCount.value)() + pPrimeFactorsBuffer = (PrimeFactor * nPrimeFactorsNeededCount.value)() self._wrapper.checkError(self, self._wrapper.lib.libprimes_factorizationcalculator_getprimefactors(self._handle, nPrimeFactorsCount, nPrimeFactorsNeededCount, pPrimeFactorsBuffer)) return [pPrimeFactorsBuffer[i] for i in range(nPrimeFactorsNeededCount.value)] -'''SieveCalculator Class Implementation +''' Class Implementation for SieveCalculator ''' -class LibPrimesSieveCalculator(LibPrimesCalculator): +class SieveCalculator(Calculator): def __init__(self, handle, wrapper): - LibPrimesBaseClass.__init__(self, handle, wrapper) - + Calculator.__init__(self, handle, wrapper) def GetPrimes(self): nPrimesCount = ctypes.c_uint64(0) nPrimesNeededCount = ctypes.c_uint64(0) diff --git a/Examples/Primes/LibPrimes_component/Examples/CPP/CMakeLists.txt b/Examples/Primes/LibPrimes_component/Examples/CPP/CMakeLists.txt deleted file mode 100644 index d33b1633..00000000 --- a/Examples/Primes/LibPrimes_component/Examples/CPP/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -#[[++ - -Copyright (C) 2018 PrimeDevelopers - -All rights reserved. - -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. - -Abstract: This is an autogenerated CMake Project that demonstrates the - usage of the C++ bindings of Prime Numbers Library - -Interface version: 1.2.0 - - -]] - -cmake_minimum_required(VERSION 3.5) - -project(LibPrimesExample_CPP) -set (CMAKE_CXX_STANDARD 11) -link_directories("PATHTO_LibPrimes_component/Bindings/Cpp") # TODO: put the correct path of the import library here -add_executable(LibPrimesExample_CPP "${CMAKE_CURRENT_SOURCE_DIR}/LibPrimes_example.cpp" - "PATHTO_LibPrimes_component/Bindings/Cpp/libprimes.cpp") -target_link_libraries(LibPrimesExample_CPP libprimes) -target_include_directories(LibPrimesExample_CPP PRIVATE "PATHTO_LibPrimes_component/Bindings/Cpp") diff --git a/Examples/Primes/LibPrimes_component/Examples/CPP/LibPrimes_example.cpp b/Examples/Primes/LibPrimes_component/Examples/CPP/LibPrimes_example.cpp deleted file mode 100644 index 61a09128..00000000 --- a/Examples/Primes/LibPrimes_component/Examples/CPP/LibPrimes_example.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*++ - -Copyright (C) 2018 PrimeDevelopers - -All rights reserved. - -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. - -Abstract: This is an autogenerated C++ application that demonstrates the - usage of the C++ bindings of Prime Numbers Library - -Interface version: 1.2.0 - -*/ - -#include -#include "libprimes.hpp" - - -int main() -{ - try - { - unsigned int nMajor, nMinor, nMicro; - LibPrimes::CLibPrimesWrapper::GetLibraryVersion(nMajor, nMinor, nMicro); - std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro << std::endl; - } - catch (std::exception &e) - { - std::cout << e.what() << std::endl; - return 1; - } - return 0; -} - diff --git a/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.cs b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.cs new file mode 100644 index 00000000..ee26a1b1 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.cs @@ -0,0 +1,47 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. + +Abstract: This is an autogenerated CSharp application that demonstrates the + usage of the CSharp bindings of Prime Numbers Library + +Interface version: 1.2.0 + +*/ + + +using System; +namespace LibPrimes_Example +{ + class LibPrimes_Example + { + static void Main() + { + UInt32 nMajor, nMinor, nMicro; + LibPrimes.Wrapper.GetVersion(out nMajor, out nMinor, out nMicro); + string versionString = string.Format("LibPrimes.version = {0}.{1}.{2}", nMajor, nMinor, nMicro); + Console.WriteLine(versionString); + + LibPrimes.CFactorizationCalculator factorization = LibPrimes.Wrapper.CreateFactorizationCalculator(); + factorization.SetValue(735); + factorization.Calculate(); + LibPrimes.sPrimeFactor[] aPrimeFactors; + factorization.GetPrimeFactors(out aPrimeFactors); + + Console.Write(string.Format("{0} = 1 ", factorization.GetValue())); + foreach (LibPrimes.sPrimeFactor pF in aPrimeFactors) + { + Console.Write(string.Format("* {0}^{1} ", pF.Prime, pF.Multiplicity)); + } + Console.WriteLine(); + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + } +} + diff --git a/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.csproj b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.csproj new file mode 100644 index 00000000..1c8c0965 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp2.0 + LibPrimes_Example.LibPrimes_Example + + x64 + + + true + + + true + + + + + diff --git a/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.sln b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.sln new file mode 100644 index 00000000..c84128a0 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Examples/CSharp/LibPrimes_Example.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.539 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibPrimes_Example", "LibPrimes_Example.csproj", "{88BCAC01-4F12-43A2-84BF-F7FEB394B59C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {88BCAC01-4F12-43A2-84BF-F7FEB394B59C}.Debug|x64.ActiveCfg = Debug|x64 + {88BCAC01-4F12-43A2-84BF-F7FEB394B59C}.Debug|x64.Build.0 = Debug|x64 + {88BCAC01-4F12-43A2-84BF-F7FEB394B59C}.Release|x64.ActiveCfg = Release|x64 + {88BCAC01-4F12-43A2-84BF-F7FEB394B59C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = 63612a47-03f4-4ce0-9e90-97525e224f06 + EndGlobalSection +EndGlobal diff --git a/Examples/Primes/LibPrimes_component/Examples/Cpp/CMakeLists.txt b/Examples/Primes/LibPrimes_component/Examples/Cpp/CMakeLists.txt new file mode 100644 index 00000000..2b0289c9 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Examples/Cpp/CMakeLists.txt @@ -0,0 +1,24 @@ +#[[++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. + +Abstract: This is an autogenerated CMake Project that demonstrates the + usage of the C++ bindings of Prime Numbers Library + +Interface version: 1.0.0 + + +]] + +cmake_minimum_required(VERSION 3.5) + +project(LibPrimesExample_CPPImplicit) +set(CMAKE_CXX_STANDARD 11) +add_executable(LibPrimesExample_CPPImplicit "${CMAKE_CURRENT_SOURCE_DIR}/LibPrimes_example.cpp") +find_library(LIBPRIMESLOCATION libprimes "${CMAKE_CURRENT_SOURCE_DIR}/../../Implementations/*/*/*") +target_link_libraries(LibPrimesExample_CPPImplicit ${LIBPRIMESLOCATION}) +target_include_directories(LibPrimesExample_CPPImplicit PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../Bindings/Cpp") diff --git a/Examples/Primes/LibPrimes_component/Examples/Cpp/LibPrimes_example.cpp b/Examples/Primes/LibPrimes_component/Examples/Cpp/LibPrimes_example.cpp new file mode 100644 index 00000000..510e45a9 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Examples/Cpp/LibPrimes_example.cpp @@ -0,0 +1,59 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. + +Abstract: This is an autogenerated C++ application that demonstrates the + usage of the C++ bindings of Prime Numbers Library + +Interface version: 1.0.0 + +*/ + +#include +#include "libprimes_implicit.hpp" + +void progressCallback(LibPrimes_single progress, bool* shouldAbort) +{ + std::cout << "Progress = " << std::round(progress * 100) << "%" << std::endl; + if (shouldAbort) { + *shouldAbort = progress > 0.5; + } +} + +int main() +{ + try + { + auto wrapper = LibPrimes::CWrapper::loadLibrary(); + wrapper->SetJournal("journal_cpp.xml"); + LibPrimes_uint32 nMajor, nMinor, nMicro; + wrapper->GetVersion(nMajor, nMinor, nMicro); + std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro; + std::cout << std::endl; + + auto factorization = wrapper->CreateFactorizationCalculator(); + factorization->SetValue(735); + factorization->SetProgressCallback(progressCallback); + factorization->Calculate(); + std::vector primeFactors; + factorization->GetPrimeFactors(primeFactors); + + std::cout << factorization->GetValue() << " = "; + for (size_t i = 0; i < primeFactors.size(); i++) { + auto pF = primeFactors[i]; + std::cout << pF.m_Prime << "^" << pF.m_Multiplicity << ((i < (primeFactors.size() - 1)) ? " * " : ""); + } + std::cout << std::endl; + } + catch (std::exception &e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; +} + diff --git a/Examples/Primes/LibPrimes_component/Examples/CppDynamic/CMakeLists.txt b/Examples/Primes/LibPrimes_component/Examples/CppDynamic/CMakeLists.txt index b7d34e0c..6537fe62 100644 --- a/Examples/Primes/LibPrimes_component/Examples/CppDynamic/CMakeLists.txt +++ b/Examples/Primes/LibPrimes_component/Examples/CppDynamic/CMakeLists.txt @@ -1,10 +1,10 @@ #[[++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated CMake Project that demonstrates the usage of the Dynamic C++ bindings of Prime Numbers Library @@ -17,7 +17,7 @@ Interface version: 1.2.0 cmake_minimum_required(VERSION 3.5) project(LibPrimesExample_CPPDynamic) -set (CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 11) add_executable(LibPrimesExample_CPPDynamic "${CMAKE_CURRENT_SOURCE_DIR}/LibPrimes_example.cpp") if (UNIX) target_link_libraries(LibPrimesExample_CPPDynamic ${CMAKE_DL_LIBS}) diff --git a/Examples/Primes/LibPrimes_component/Examples/CppDynamic/LibPrimes_example.cpp b/Examples/Primes/LibPrimes_component/Examples/CppDynamic/LibPrimes_example.cpp index bcee6558..814787f8 100644 --- a/Examples/Primes/LibPrimes_component/Examples/CppDynamic/LibPrimes_example.cpp +++ b/Examples/Primes/LibPrimes_component/Examples/CppDynamic/LibPrimes_example.cpp @@ -1,15 +1,15 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ application that demonstrates the usage of the Dynamic C++ bindings of Prime Numbers Library -Interface version: 1.2.0 +Interface version: 1.0.0 */ @@ -17,8 +17,7 @@ Interface version: 1.2.0 #include "libprimes_dynamic.hpp" #include - -void progressCallback(float progress, bool* shouldAbort) +void progressCallback(LibPrimes_single progress, bool* shouldAbort) { std::cout << "Progress = " << std::round(progress * 100) << "%" << std::endl; if (shouldAbort) { @@ -28,35 +27,35 @@ void progressCallback(float progress, bool* shouldAbort) int main() { - try - { - std::string libpath = ""; // TODO: put the location of the LibPrimes-library file here. - auto wrapper = LibPrimes::CLibPrimesWrapper::loadLibrary(libpath + "/libprimes."); // TODO: add correct suffix of the library - wrapper->SetJournal("journal_cppdynamic.xml"); - - unsigned int nMajor, nMinor, nMicro; - wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); - std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro << std::endl; - - auto factorization = wrapper->CreateFactorizationCalculator(); - factorization->SetValue(735); - factorization->SetProgressCallback(progressCallback); - factorization->Calculate(); - std::vector primeFactors; - factorization->GetPrimeFactors(primeFactors); - - std::cout << factorization->GetValue() << " = "; - for (size_t i = 0; i < primeFactors.size(); i++) { - auto pF = primeFactors[i]; - std::cout << pF.m_Prime << "^" << pF.m_Multiplicity << ((i < (primeFactors.size() - 1)) ? " * " : ""); + try + { + std::string libpath = (""); // TODO: put the location of the LibPrimes-library file here. + auto wrapper = LibPrimes::CWrapper::loadLibrary(libpath + "/libprimes."); // TODO: add correct suffix of the library + wrapper->SetJournal("journal_cppdynamic.xml"); + LibPrimes_uint32 nMajor, nMinor, nMicro; + wrapper->GetVersion(nMajor, nMinor, nMicro); + std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro; + std::cout << std::endl; + + auto factorization = wrapper->CreateFactorizationCalculator(); + factorization->SetValue(735); + factorization->SetProgressCallback(progressCallback); + factorization->Calculate(); + std::vector primeFactors; + factorization->GetPrimeFactors(primeFactors); + + std::cout << factorization->GetValue() << " = "; + for (size_t i = 0; i < primeFactors.size(); i++) { + auto pF = primeFactors[i]; + std::cout << pF.m_Prime << "^" << pF.m_Multiplicity << ((i < (primeFactors.size() - 1)) ? " * " : ""); + } + std::cout << std::endl; + } + catch (std::exception &e) + { + std::cout << e.what() << std::endl; + return 1; } - std::cout << std::endl; - } - catch (std::exception &e) - { - std::cout << e.what() << std::endl; - return 1; - } - return 0; + return 0; } diff --git a/Examples/Primes/LibPrimes_component/Examples/Pascal/.gitignore b/Examples/Primes/LibPrimes_component/Examples/Pascal/.gitignore deleted file mode 100644 index e8a827d6..00000000 --- a/Examples/Primes/LibPrimes_component/Examples/Pascal/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.lps -bin -lib diff --git a/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpi b/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpi index e5e82b7b..b051702c 100644 --- a/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpi +++ b/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpi @@ -1,113 +1,113 @@ - - - - - - - - - - - - - <UseAppBundle Value="False" /> - <ResourceType Value="res" /> - </General> - <BuildModes Count="2"> - <Item1 Name="Release" Default="True"/> - <Item2 Name="Debug"> - <CompilerOptions> - <Version Value="11" /> - <PathDelim Value="\"/> - <Target> - <Filename Value="bin\$(TargetCPU)-$(TargetOS)\Release\LibPrimes_Example"/> - </Target> - <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\..\Bindings\Pascal"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Parsing> - <SyntaxOptions> - <IncludeAssertionCode Value="True"/> - </SyntaxOptions> - </Parsing> - <CodeGeneration> - <RelocatableUnit Value="True" /> - </CodeGeneration> - <Linking> - <Debugging> - <UseExternalDbgSyms Value="True"/> - </Debugging> - <Options> - <ExecutableType Value="Library"/> - </Options> - </Linking> - </CompilerOptions> - </Item2> - </BuildModes> - <PublishOptions> - <Version Value="2"/> - </PublishOptions> - <RunParams> - <local> - <FormatVersion Value="1"/> - </local> - </RunParams> - <Units Count="2"> - <Unit0> - <Filename Value="LibPrimes_Example.lpr"/> - <IsPartOfProject Value="True"/> - </Unit0> - <Unit1> - <Filename Value="Unit_LibPrimes.pas"/> - <IsPartOfProject Value="True"/> - </Unit1> - </Units> - </ProjectOptions> - <CompilerOptions> - <Version Value="11"/> - <PathDelim Value="\"/> - <Target> + <ProjectOptions> + <Version Value="10"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="LibPrimes_Example"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="2"> + <Item1 Name="Release" Default="True"/> + <Item2 Name="Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> <Filename Value="bin\$(TargetCPU)-$(TargetOS)\Release\LibPrimes_Example"/> - </Target> - <SearchPaths> + </Target> + <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="..\..\Bindings\Pascal"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Parsing> + </SearchPaths> + <Parsing> <SyntaxOptions> - <IncludeAssertionCode Value="True"/> + <IncludeAssertionCode Value="True"/> </SyntaxOptions> - </Parsing> - <CodeGeneration> + </Parsing> + <CodeGeneration> <RelocatableUnit Value="True"/> - </CodeGeneration> - <Linking> + </CodeGeneration> + <Linking> <Debugging> - <StripSymbols Value="True"/> - <UseExternalDbgSyms Value="True"/> + <UseExternalDbgSyms Value="True"/> </Debugging> <Options> - <ExecutableType Value="Library"/> + <ExecutableType Value="Library"/> </Options> - </Linking> - </CompilerOptions> - <Debugging> - <Exceptions Count="3"> - <Item1> - <Name Value="EAbort"/> - </Item1> - <Item2> - <Name Value="ECodetoolError"/> - </Item2> - <Item3> - <Name Value="EFOpenError"/> - </Item3> - </Exceptions> - </Debugging> + </Linking> + </CompilerOptions> + </Item2> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <Units Count="2"> + <Unit0> + <Filename Value="LibPrimes_Example.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="Unit_LibPrimes.pas"/> + <IsPartOfProject Value="True"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="bin\$(TargetCPU)-$(TargetOS)\Release\LibPrimes_Example"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\..\Bindings\Pascal"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <RelocatableUnit Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <StripSymbols Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <Options> + <ExecutableType Value="Library"/> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> </CONFIG> diff --git a/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpr b/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpr index a8db4d17..14b80642 100644 --- a/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpr +++ b/Examples/Primes/LibPrimes_component/Examples/Pascal/LibPrimes_Example.lpr @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal application that demonstrates the usage of the Pascal bindings of Prime Numbers Library @@ -16,70 +16,72 @@ program LibPrimesPascalTest; uses - {$IFDEF UNIX}{$IFDEF UseCThreads} - cthreads, - {$ENDIF}{$ENDIF} - Classes, SysUtils, CustApp, - Unit_LibPrimes - { you can add units after this }; + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Classes, SysUtils, CustApp, + Unit_LibPrimes + { you can add units after this }; type TLibPrimes_Example = class(TCustomApplication) protected - procedure DoRun; override; - procedure TestLibPrimes (); + procedure DoRun; override; + procedure TestLibPrimes (); public - constructor Create(TheOwner: TComponent); override; - destructor Destroy; override; + constructor Create(TheOwner: TComponent); override; + destructor Destroy; override; end; procedure TLibPrimes_Example.TestLibPrimes (); var - ALibPrimesWrapper: TLibPrimesWrapper; - AMajor, AMinor, AMicro: Cardinal; - ALibPath: string; + ALibPrimesWrapper: TLibPrimesWrapper; + AMajor, AMinor, AMicro: Cardinal; + AVersionString: string; + ALibPath: string; begin - writeln ('loading DLL'); - ALibPath := ''; // TODO add the location of the shared library binary here - ALibPrimesWrapper := TLibPrimesWrapper.Create (ALibPath + '/' + 'libprimes.dll'); - try - writeln ('loading DLL Done'); - ALibPrimesWrapper.GetLibraryVersion(AMajor, AMinor, AMicro); - writeln (Format('LibPrimes.version = %d.%d.%d', [AMajor, AMinor, AMicro])); - finally - FreeAndNil(ALibPrimesWrapper); - end; + writeln ('loading DLL'); + ALibPath := ''; // TODO add the location of the shared library binary here + ALibPrimesWrapper := TLibPrimesWrapper.Create (ALibPath + '/' + 'libprimes.'); // TODO add the extension of the shared library file here + try + writeln ('loading DLL Done'); + ALibPrimesWrapper.GetVersion(AMajor, AMinor, AMicro); + AVersionString := Format('LibPrimes.version = %d.%d.%d', [AMajor, AMinor, AMicro]); + writeln(AVersionString); + finally + FreeAndNil(ALibPrimesWrapper); + end; end; procedure TLibPrimes_Example.DoRun; begin - try - TestLibPrimes(); - except - On E: Exception do - writeln ('Fatal error: ', E.Message); - end; - Terminate + try + TestLibPrimes(); + except + On E: Exception do + writeln ('Fatal error: ', E.Message); + end; + Terminate end; constructor TLibPrimes_Example.Create(TheOwner: TComponent); begin - inherited Create(TheOwner); - StopOnException:=True; + inherited Create(TheOwner); + StopOnException:=True; end; destructor TLibPrimes_Example.Destroy; begin - inherited Destroy; + inherited Destroy; end; var - Application: TLibPrimes_Example; + Application: TLibPrimes_Example; begin - Application:=TLibPrimes_Example.Create(nil); - Application.Run; - Application.Free; + Application:=TLibPrimes_Example.Create(nil); + Application.Run; + Application.Free; end. diff --git a/Examples/Primes/LibPrimes_component/Examples/Python/LibPrimes_Example.py b/Examples/Primes/LibPrimes_component/Examples/Python/LibPrimes_Example.py index 897f8c4b..d979aa9a 100644 --- a/Examples/Primes/LibPrimes_component/Examples/Python/LibPrimes_Example.py +++ b/Examples/Primes/LibPrimes_component/Examples/Python/LibPrimes_Example.py @@ -1,15 +1,15 @@ '''++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Python application that demonstrates the usage of the Python bindings of Prime Numbers Library -Interface version: 1.2.0 +Interface version: 1.0.0 ''' @@ -26,26 +26,15 @@ def progressCallback(progress, shouldAbort): def main(): libpath = '' # TODO add the location of the shared library binary here - wrapper = LibPrimes.LibPrimesWrapper(os.path.join(libpath, "libprimes")) + wrapper = LibPrimes.Wrapper(os.path.join(libpath, "libprimes")) wrapper.SetJournal('journal_python.xml') - - major, minor, micro = wrapper.GetLibraryVersion() - print("LibPrimes version: {:d}.{:d}.{:d}".format(major, minor, micro)) - sieve = wrapper.CreateSieveCalculator() - sieve.SetValue(105) - sieve.Calculate() - primes = sieve.GetPrimes() - print("Primes <= {:d} = [".format(sieve.GetValue()), end="") - commaString = ", " - for i in range(0, len(primes)): - if i == len(primes) - 1: - commaString = "" - print("{:d}".format(primes[i]), end=commaString) - print("]") + major, minor, micro = wrapper.GetVersion() + print("LibPrimes version: {:d}.{:d}.{:d}".format(major, minor, micro), end="") + print("") factorization = wrapper.CreateFactorizationCalculator() factorization.SetValue(735) - cTypesCallback = LibPrimes.LibPrimesProgressCallback(progressCallback) + cTypesCallback = LibPrimes.ProgressCallback(progressCallback) factorization.SetProgressCallback(cTypesCallback) factorization.Calculate() primeFactors = factorization.GetPrimeFactors() @@ -56,6 +45,7 @@ def main(): if i == len(primeFactors) - 1: productString = "\n" print(" {:d}^{:d} ".format(pF.Prime, pF.Multiplicity), end=productString) + if __name__ == "__main__": try: diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/CMakeLists.txt b/Examples/Primes/LibPrimes_component/Implementations/Cpp/CMakeLists.txt index ccf3ea4d..d5d4ed62 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/CMakeLists.txt +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/CMakeLists.txt @@ -1,14 +1,14 @@ #[[++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated CMakeLists file for the development of Prime Numbers Library. -Interface version: 1.2.0 +Interface version: 1.0.0 ]] @@ -36,6 +36,8 @@ set(LIBPRIMES_SRC ${LIBPRIMES_SRC} ${LIBPRIMES_SRC} ) add_library(libprimes SHARED ${LIBPRIMES_SRC}) +# Do not prefix the binary's name with "lib" on Unix systems: +set_target_properties(libprimes PROPERTIES PREFIX "" IMPORT_PREFIX "" ) # The following two properties are crucial to reduce the number of undesirably exported symbols set_target_properties(libprimes PROPERTIES CXX_VISIBILITY_PRESET hidden) set_target_properties(libprimes PROPERTIES VISIBILITY_INLINES_HIDDEN ON) diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_abi.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_abi.hpp new file mode 100644 index 00000000..a463430b --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_abi.hpp @@ -0,0 +1,167 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. + +Abstract: This is an autogenerated C++-Header file in order to allow an easy + use of Prime Numbers Library + +Interface version: 1.2.0 + +*/ + +#ifndef __LIBPRIMES_HEADER_CPP +#define __LIBPRIMES_HEADER_CPP + +#ifdef __LIBPRIMES_EXPORTS +#ifdef _WIN32 +#define LIBPRIMES_DECLSPEC __declspec (dllexport) +#else // _WIN32 +#define LIBPRIMES_DECLSPEC __attribute__((visibility("default"))) +#endif // _WIN32 +#else // __LIBPRIMES_EXPORTS +#define LIBPRIMES_DECLSPEC +#endif // __LIBPRIMES_EXPORTS + +#include "libprimes_types.hpp" + +extern "C" { + +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + +/************************************************************************************************************************* + Class definition for Calculator +**************************************************************************************************************************/ + +/** +* Returns the current value of this Calculator +* +* @param[in] pCalculator - Calculator instance. +* @param[out] pValue - The current value of this Calculator +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_getvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue); + +/** +* Sets the value to be factorized +* +* @param[in] pCalculator - Calculator instance. +* @param[in] nValue - The value to be factorized +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 nValue); + +/** +* Performs the specific calculation of this Calculator +* +* @param[in] pCalculator - Calculator instance. +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_calculate(LibPrimes_Calculator pCalculator); + +/** +* Sets the progress callback function +* +* @param[in] pCalculator - Calculator instance. +* @param[in] pProgressCallback - The progress callback +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimes::ProgressCallback pProgressCallback); + +/************************************************************************************************************************* + Class definition for FactorizationCalculator +**************************************************************************************************************************/ + +/** +* Returns the prime factors of this number (without multiplicity) +* +* @param[in] pFactorizationCalculator - FactorizationCalculator instance. +* @param[in] nPrimeFactorsBufferSize - Number of elements in buffer +* @param[out] pPrimeFactorsNeededCount - will be filled with the count of the written elements, or needed buffer size. +* @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); + +/************************************************************************************************************************* + Class definition for SieveCalculator +**************************************************************************************************************************/ + +/** +* Returns all prime numbers lower or equal to the sieve's value +* +* @param[in] pSieveCalculator - SieveCalculator instance. +* @param[in] nPrimesBufferSize - Number of elements in buffer +* @param[out] pPrimesNeededCount - will be filled with the count of the written elements, or needed buffer size. +* @param[out] pPrimesBuffer - uint64 buffer of The primes lower or equal to the sieve's value +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_sievecalculator_getprimes(LibPrimes_SieveCalculator pSieveCalculator, const LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer); + +/************************************************************************************************************************* + Global functions +**************************************************************************************************************************/ + +/** +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro); + +/** +* Returns the last error recorded on this object +* +* @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_getlasterror(LibPrimes_Base pInstance, const LibPrimes_uint32 nErrorMessageBufferSize, LibPrimes_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); + +/** +* Releases the memory of an Instance +* +* @param[in] pInstance - Instance Handle +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_releaseinstance(LibPrimes_Base pInstance); + +/** +* Creates a new FactorizationCalculator instance +* +* @param[out] pInstance - New FactorizationCalculator instance +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_createfactorizationcalculator(LibPrimes_FactorizationCalculator * pInstance); + +/** +* Creates a new SieveCalculator instance +* +* @param[out] pInstance - New SieveCalculator instance +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_createsievecalculator(LibPrimes_SieveCalculator * pInstance); + +/** +* Handles Library Journaling +* +* @param[in] pFileName - Journal FileName +* @return error code or 0 (success) +*/ +LIBPRIMES_DECLSPEC LibPrimesResult libprimes_setjournal(const char * pFileName); + +} + +#endif // __LIBPRIMES_HEADER_CPP + diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.cpp index 440b7040..9fd7bfee 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ Implementation file with the basic internal exception type in order to allow an easy use of Prime Numbers Library diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.hpp index 8ea42a10..85b8bbc9 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaceexception.hpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ Header file with the basic internal exception type in order to allow an easy use of Prime Numbers Library @@ -18,7 +18,7 @@ Interface version: 1.2.0 #include <exception> #include <stdexcept> -#include "libprimes_types.h" +#include "libprimes_types.hpp" /************************************************************************************************************************* Class ELibPrimesInterfaceException diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.cpp index d89395c5..4c4432b1 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of Prime Numbers Library. It provides an automatic Journaling mechanism for the library implementation. @@ -154,6 +154,10 @@ void CLibPrimesInterfaceJournalEntry::addDoubleParameter(const std::string & sNa { addParameter(sName, "double", std::to_string(dValue)); } +void CLibPrimesInterfaceJournalEntry::addPointerParameter(const std::string & sName, const LibPrimes_pvoid pValue) +{ + addParameter(sName, "pointer", std::to_string(reinterpret_cast<const LibPrimes_uint64>(pValue))); +} void CLibPrimesInterfaceJournalEntry::addStringParameter(const std::string & sName, const char * pValue) { @@ -170,7 +174,7 @@ void CLibPrimesInterfaceJournalEntry::addHandleParameter(const std::string & sNa addParameter(sName, "handle", LibPrimesHandleToHex(pHandle)); } -void CLibPrimesInterfaceJournalEntry::addEnumParameter(const std::string & sName, const std::string & sEnumType, const LibPrimes_uint32 nValue) +void CLibPrimesInterfaceJournalEntry::addEnumParameter(const std::string & sName, const std::string & sEnumType, const LibPrimes_int32 nValue) { addParameter(sName, "enum" + sEnumType, std::to_string(nValue)); } @@ -230,6 +234,11 @@ void CLibPrimesInterfaceJournalEntry::addDoubleResult(const std::string & sName, addResult(sName, "double", std::to_string(dValue)); } +void CLibPrimesInterfaceJournalEntry::addPointerResult(const std::string & sName, const LibPrimes_pvoid pValue) +{ + addResult(sName, "pointer", std::to_string(reinterpret_cast<const LibPrimes_uint64>(pValue))); +} + void CLibPrimesInterfaceJournalEntry::addStringResult(const std::string & sName, const char * pValue) { if (pValue != nullptr) { @@ -245,7 +254,7 @@ void CLibPrimesInterfaceJournalEntry::addHandleResult(const std::string & sName, addResult(sName, "handle", LibPrimesHandleToHex(pHandle)); } -void CLibPrimesInterfaceJournalEntry::addEnumResult(const std::string & sName, const std::string & sEnumType, const LibPrimes_uint32 nValue) +void CLibPrimesInterfaceJournalEntry::addEnumResult(const std::string & sName, const std::string & sEnumType, const LibPrimes_int32 nValue) { addResult(sName, "enum" + sEnumType, std::to_string(nValue)); } diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.hpp index 65d8e2f0..0ccfa0ba 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacejournal.hpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ header file in order to allow easy development of Prime Numbers Library. It provides an automatic Journaling mechanism for the library implementation. @@ -23,7 +23,7 @@ Interface version: 1.2.0 #include <list> #include <mutex> #include <chrono> -#include "libprimes_types.h" +#include "libprimes_types.hpp" /************************************************************************************************************************* Class CLibPrimesInterfaceJournal @@ -67,9 +67,10 @@ class CLibPrimesInterfaceJournalEntry { void addInt64Parameter(const std::string & sName, const LibPrimes_int64 nValue); void addSingleParameter(const std::string & sName, const LibPrimes_single fValue); void addDoubleParameter(const std::string & sName, const LibPrimes_double dValue); + void addPointerParameter(const std::string & sName, const LibPrimes_pvoid pValue); void addStringParameter(const std::string & sName, const char * pValue); void addHandleParameter(const std::string & sName, const LibPrimesHandle pHandle); - void addEnumParameter(const std::string & sName, const std::string & sEnumType, const LibPrimes_uint32 nValue); + void addEnumParameter(const std::string & sName, const std::string & sEnumType, const LibPrimes_int32 nValue); void addBooleanResult(const std::string & sName, const bool bValue); void addUInt8Result(const std::string & sName, const LibPrimes_uint8 nValue); @@ -82,9 +83,10 @@ class CLibPrimesInterfaceJournalEntry { void addInt64Result(const std::string & sName, const LibPrimes_int64 nValue); void addSingleResult(const std::string & sName, const LibPrimes_single fValue); void addDoubleResult(const std::string & sName, const LibPrimes_double dValue); + void addPointerResult(const std::string & sName, const LibPrimes_pvoid pValue); void addStringResult(const std::string & sName, const char * pValue); void addHandleResult(const std::string & sName, const LibPrimesHandle pHandle); - void addEnumResult(const std::string & sName, const std::string & sEnumType, const LibPrimes_uint32 nValue); + void addEnumResult(const std::string & sName, const std::string & sEnumType, const LibPrimes_int32 nValue); friend class CLibPrimesInterfaceJournal; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaces.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaces.hpp index 71b5002f..ef761a54 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaces.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfaces.hpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ header file in order to allow easy development of Prime Numbers Library. The implementer of Prime Numbers Library needs to @@ -20,7 +20,7 @@ Interface version: 1.2.0 #include <string> -#include "libprimes_types.h" +#include "libprimes_types.hpp" namespace LibPrimes { namespace Impl { @@ -28,58 +28,80 @@ namespace Impl { /** Forward declarations of class interfaces */ -class ILibPrimesCalculator; -class ILibPrimesFactorizationCalculator; -class ILibPrimesSieveCalculator; +class IBase; +class ICalculator; +class IFactorizationCalculator; +class ISieveCalculator; /************************************************************************************************************************* - Class ILibPrimesBaseClass + Class interface for Base **************************************************************************************************************************/ -class ILibPrimesBaseClass { +class IBase { public: - virtual ~ILibPrimesBaseClass () {} + /** + * IBase::~IBase - virtual destructor of IBase + */ + virtual ~IBase() {}; + + /** + * IBase::GetLastErrorMessage - Returns the last error registered of this class instance + * @param[out] sErrorMessage - Message of the last error registered + * @return Has an error been registered already + */ + virtual bool GetLastErrorMessage(std::string & sErrorMessage) = 0; + + /** + * IBase::ClearErrorMessages - Clears all registered messages of this class instance + */ + virtual void ClearErrorMessages() = 0; + + /** + * IBase::RegisterErrorMessage - Registers an error message with this class instance + * @param[in] sErrorMessage - Error message to register + */ + virtual void RegisterErrorMessage(const std::string & sErrorMessage) = 0; }; /************************************************************************************************************************* - Class interface for LibPrimesCalculator + Class interface for Calculator **************************************************************************************************************************/ -class ILibPrimesCalculator : public virtual ILibPrimesBaseClass { +class ICalculator : public virtual IBase{ public: /** * ICalculator::GetValue - Returns the current value of this Calculator * @return The current value of this Calculator */ - virtual LibPrimes_uint64 GetValue () = 0; + virtual LibPrimes_uint64 GetValue() = 0; /** * ICalculator::SetValue - Sets the value to be factorized * @param[in] nValue - The value to be factorized */ - virtual void SetValue (const LibPrimes_uint64 nValue) = 0; + virtual void SetValue(const LibPrimes_uint64 nValue) = 0; /** * ICalculator::Calculate - Performs the specific calculation of this Calculator */ - virtual void Calculate () = 0; + virtual void Calculate() = 0; /** * ICalculator::SetProgressCallback - Sets the progress callback function * @param[in] pProgressCallback - callback function */ - virtual void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) = 0; + virtual void SetProgressCallback(const LibPrimes::ProgressCallback pProgressCallback) = 0; }; /************************************************************************************************************************* - Class interface for LibPrimesFactorizationCalculator + Class interface for FactorizationCalculator **************************************************************************************************************************/ -class ILibPrimesFactorizationCalculator : public virtual ILibPrimesBaseClass, public virtual ILibPrimesCalculator { +class IFactorizationCalculator : public virtual IBase, public virtual ICalculator{ public: /** * IFactorizationCalculator::GetPrimeFactors - Returns the prime factors of this number (without multiplicity) @@ -87,16 +109,16 @@ class ILibPrimesFactorizationCalculator : public virtual ILibPrimesBaseClass, pu * @param[out] pPrimeFactorsNeededCount - will be filled with the count of the written structs, or needed buffer size. * @param[out] pPrimeFactorsBuffer - PrimeFactor buffer of The prime factors of this number */ - virtual void GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) = 0; + virtual void GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer) = 0; }; /************************************************************************************************************************* - Class interface for LibPrimesSieveCalculator + Class interface for SieveCalculator **************************************************************************************************************************/ -class ILibPrimesSieveCalculator : public virtual ILibPrimesBaseClass, public virtual ILibPrimesCalculator { +class ISieveCalculator : public virtual IBase, public virtual ICalculator{ public: /** * ISieveCalculator::GetPrimes - Returns all prime numbers lower or equal to the sieve's value @@ -104,7 +126,7 @@ class ILibPrimesSieveCalculator : public virtual ILibPrimesBaseClass, public vir * @param[out] pPrimesNeededCount - will be filled with the count of the written structs, or needed buffer size. * @param[out] pPrimesBuffer - uint64 buffer of The primes lower or equal to the sieve's value */ - virtual void GetPrimes (LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) = 0; + virtual void GetPrimes(LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) = 0; }; @@ -112,39 +134,41 @@ class ILibPrimesSieveCalculator : public virtual ILibPrimesBaseClass, public vir /************************************************************************************************************************* Global functions declarations **************************************************************************************************************************/ -class CLibPrimesWrapper { +class CWrapper { public: /** - * Ilibprimes::ReleaseInstance - Releases the memory of an Instance + * Ilibprimes::GetVersion - retrieves the binary version of this library. + * @param[out] nMajor - returns the major version of this library + * @param[out] nMinor - returns the minor version of this library + * @param[out] nMicro - returns the micro version of this library + */ + static void GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); + + /** + * Ilibprimes::GetLastError - Returns the last error recorded on this object * @param[in] pInstance - Instance Handle + * @param[out] sErrorMessage - Message of the last error + * @return Is there a last error to query */ - static void ReleaseInstance (ILibPrimesBaseClass* pInstance); + static bool GetLastError(IBase* pInstance, std::string & sErrorMessage); /** - * Ilibprimes::GetLibraryVersion - retrieves the current version of the library. - * @param[out] nMajor - returns the major version of the library - * @param[out] nMinor - returns the minor version of the library - * @param[out] nMicro - returns the micro version of the library + * Ilibprimes::ReleaseInstance - Releases the memory of an Instance + * @param[in] pInstance - Instance Handle */ - static void GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro); + static void ReleaseInstance(IBase* pInstance); /** * Ilibprimes::CreateFactorizationCalculator - Creates a new FactorizationCalculator instance * @return New FactorizationCalculator instance */ - static ILibPrimesFactorizationCalculator * CreateFactorizationCalculator (); + static IFactorizationCalculator * CreateFactorizationCalculator(); /** * Ilibprimes::CreateSieveCalculator - Creates a new SieveCalculator instance * @return New SieveCalculator instance */ - static ILibPrimesSieveCalculator * CreateSieveCalculator (); - - /** - * Ilibprimes::SetJournal - Handles Library Journaling - * @param[in] sFileName - Journal FileName - */ - static void SetJournal (const std::string & sFileName); + static ISieveCalculator * CreateSieveCalculator(); }; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacewrapper.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacewrapper.cpp index 884063fd..2d89e77b 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacewrapper.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_interfacewrapper.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of Prime Numbers Library. The functions in this file need to be implemented. It needs to be generated only once. @@ -13,7 +13,7 @@ Interface version: 1.2.0 */ -#include "libprimes.h" +#include "libprimes_abi.hpp" #include "libprimes_interfaces.hpp" #include "libprimes_interfaceexception.hpp" #include "libprimes_interfacejournal.hpp" @@ -22,14 +22,58 @@ using namespace LibPrimes::Impl; PLibPrimesInterfaceJournal m_GlobalJournal; -extern "C" { +LibPrimesResult handleLibPrimesException(IBase * pIBaseClass, ELibPrimesInterfaceException & Exception, CLibPrimesInterfaceJournalEntry * pJournalEntry = nullptr) +{ + LibPrimesResult errorCode = Exception.getErrorCode(); + + if (pJournalEntry != nullptr) + pJournalEntry->writeError(errorCode); + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage(Exception.what()); + + return errorCode; +} + +LibPrimesResult handleStdException(IBase * pIBaseClass, std::exception & Exception, CLibPrimesInterfaceJournalEntry * pJournalEntry = nullptr) +{ + LibPrimesResult errorCode = LIBPRIMES_ERROR_GENERICEXCEPTION; + + if (pJournalEntry != nullptr) + pJournalEntry->writeError(errorCode); + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage(Exception.what()); + + return errorCode; +} + +LibPrimesResult handleUnhandledException(IBase * pIBaseClass, CLibPrimesInterfaceJournalEntry * pJournalEntry = nullptr) +{ + LibPrimesResult errorCode = LIBPRIMES_ERROR_GENERICEXCEPTION; + + if (pJournalEntry != nullptr) + pJournalEntry->writeError(errorCode); + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage("Unhandled Exception"); + + return errorCode; +} + +/************************************************************************************************************************* + Class implementation for Base +**************************************************************************************************************************/ + /************************************************************************************************************************* Class implementation for Calculator **************************************************************************************************************************/ -LibPrimesResult libprimes_calculator_getvalue (LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) +LibPrimesResult libprimes_calculator_getvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) { + IBase* pIBaseClass = (IBase *)pCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -39,8 +83,7 @@ LibPrimesResult libprimes_calculator_getvalue (LibPrimes_Calculator pCalculator, if (pValue == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -49,36 +92,36 @@ LibPrimesResult libprimes_calculator_getvalue (LibPrimes_Calculator pCalculator, if (pJournalEntry.get() != nullptr) { - pJournalEntry->addUInt64Result ("Value", *pValue); + pJournalEntry->addUInt64Result("Value", *pValue); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_calculator_setvalue (LibPrimes_Calculator pCalculator, LibPrimes_uint64 nValue) +LibPrimesResult libprimes_calculator_setvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 nValue) { + IBase* pIBaseClass = (IBase *)pCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { pJournalEntry = m_GlobalJournal->beginClassMethod(pCalculator, "Calculator", "SetValue"); - pJournalEntry->addUInt64Parameter ("Value", nValue); + pJournalEntry->addUInt64Parameter("Value", nValue); } - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -92,20 +135,21 @@ LibPrimesResult libprimes_calculator_setvalue (LibPrimes_Calculator pCalculator, return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_calculator_calculate (LibPrimes_Calculator pCalculator) +LibPrimesResult libprimes_calculator_calculate(LibPrimes_Calculator pCalculator) { + IBase* pIBaseClass = (IBase *)pCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -113,8 +157,7 @@ LibPrimesResult libprimes_calculator_calculate (LibPrimes_Calculator pCalculator } - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -128,20 +171,21 @@ LibPrimesResult libprimes_calculator_calculate (LibPrimes_Calculator pCalculator return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_calculator_setprogresscallback (LibPrimes_Calculator pCalculator, LibPrimesProgressCallback pProgressCallback) +LibPrimesResult libprimes_calculator_setprogresscallback(LibPrimes_Calculator pCalculator, LibPrimesProgressCallback pProgressCallback) { + IBase* pIBaseClass = (IBase *)pCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -149,8 +193,7 @@ LibPrimesResult libprimes_calculator_setprogresscallback (LibPrimes_Calculator p } - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -164,15 +207,14 @@ LibPrimesResult libprimes_calculator_setprogresscallback (LibPrimes_Calculator p return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } @@ -180,8 +222,10 @@ LibPrimesResult libprimes_calculator_setprogresscallback (LibPrimes_Calculator p /************************************************************************************************************************* Class implementation for FactorizationCalculator **************************************************************************************************************************/ -LibPrimesResult libprimes_factorizationcalculator_getprimefactors (LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) +LibPrimesResult libprimes_factorizationcalculator_getprimefactors(LibPrimes_FactorizationCalculator pFactorizationCalculator, const LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) { + IBase* pIBaseClass = (IBase *)pFactorizationCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -191,8 +235,7 @@ LibPrimesResult libprimes_factorizationcalculator_getprimefactors (LibPrimes_Fac if ((!pPrimeFactorsBuffer) && !(pPrimeFactorsNeededCount)) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pFactorizationCalculator; - ILibPrimesFactorizationCalculator* pIFactorizationCalculator = dynamic_cast<ILibPrimesFactorizationCalculator*>(pIBaseClass); + IFactorizationCalculator* pIFactorizationCalculator = dynamic_cast<IFactorizationCalculator*>(pIBaseClass); if (!pIFactorizationCalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -206,15 +249,14 @@ LibPrimesResult libprimes_factorizationcalculator_getprimefactors (LibPrimes_Fac return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } @@ -222,8 +264,10 @@ LibPrimesResult libprimes_factorizationcalculator_getprimefactors (LibPrimes_Fac /************************************************************************************************************************* Class implementation for SieveCalculator **************************************************************************************************************************/ -LibPrimesResult libprimes_sievecalculator_getprimes (LibPrimes_SieveCalculator pSieveCalculator, const LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) +LibPrimesResult libprimes_sievecalculator_getprimes(LibPrimes_SieveCalculator pSieveCalculator, const LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) { + IBase* pIBaseClass = (IBase *)pSieveCalculator; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -233,8 +277,7 @@ LibPrimesResult libprimes_sievecalculator_getprimes (LibPrimes_SieveCalculator p if ((!pPrimesBuffer) && !(pPrimesNeededCount)) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pSieveCalculator; - ILibPrimesSieveCalculator* pISieveCalculator = dynamic_cast<ILibPrimesSieveCalculator*>(pIBaseClass); + ISieveCalculator* pISieveCalculator = dynamic_cast<ISieveCalculator*>(pIBaseClass); if (!pISieveCalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); @@ -248,15 +291,14 @@ LibPrimesResult libprimes_sievecalculator_getprimes (LibPrimes_SieveCalculator p return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } @@ -264,91 +306,142 @@ LibPrimesResult libprimes_sievecalculator_getprimes (LibPrimes_SieveCalculator p /************************************************************************************************************************* Global functions implementation **************************************************************************************************************************/ -LibPrimesResult libprimes_releaseinstance (LibPrimes_BaseClass pInstance) +LibPrimesResult libprimes_getversion(LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro) { + IBase* pIBaseClass = nullptr; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { - pJournalEntry = m_GlobalJournal->beginStaticFunction("ReleaseInstance"); - pJournalEntry->addHandleParameter ("Instance", pInstance); + pJournalEntry = m_GlobalJournal->beginStaticFunction("GetVersion"); } + if (!pMajor) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); + if (!pMinor) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); + if (!pMicro) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); + + + CWrapper::GetVersion(*pMajor, *pMinor, *pMicro); + - ILibPrimesBaseClass* pIBaseClassInstance = (ILibPrimesBaseClass *)pInstance; - ILibPrimesBaseClass* pIInstance = dynamic_cast<ILibPrimesBaseClass*>(pIBaseClassInstance); + if (pJournalEntry.get() != nullptr) { + pJournalEntry->addUInt32Result("Major", *pMajor); + pJournalEntry->addUInt32Result("Minor", *pMinor); + pJournalEntry->addUInt32Result("Micro", *pMicro); + pJournalEntry->writeSuccess(); + } + + return LIBPRIMES_SUCCESS; + } + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); + } + catch (...) { + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); + } +} + +LibPrimesResult libprimes_getlasterror(LibPrimes_Base pInstance, const LibPrimes_uint32 nErrorMessageBufferSize, LibPrimes_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError) +{ + IBase* pIBaseClass = nullptr; + + PLibPrimesInterfaceJournalEntry pJournalEntry; + try { + if (m_GlobalJournal.get() != nullptr) { + pJournalEntry = m_GlobalJournal->beginStaticFunction("GetLastError"); + pJournalEntry->addHandleParameter("Instance", pInstance); + } + + if ( (!pErrorMessageBuffer) && !(pErrorMessageNeededChars) ) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); + if (pHasError == nullptr) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); + + IBase* pIBaseClassInstance = (IBase *)pInstance; + IBase* pIInstance = dynamic_cast<IBase*>(pIBaseClassInstance); if (!pIInstance) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDCAST); + std::string sErrorMessage(""); - CLibPrimesWrapper::ReleaseInstance(pIInstance); + *pHasError = CWrapper::GetLastError(pIInstance, sErrorMessage); + if (pErrorMessageNeededChars) + *pErrorMessageNeededChars = (LibPrimes_uint32) sErrorMessage.size(); + if (pErrorMessageBuffer) { + if (sErrorMessage.size() >= nErrorMessageBufferSize) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_BUFFERTOOSMALL); + for (int iErrorMessage = 0; iErrorMessage < sErrorMessage.size(); iErrorMessage++) + pErrorMessageBuffer[iErrorMessage] = sErrorMessage[iErrorMessage]; + } if (pJournalEntry.get() != nullptr) { + pJournalEntry->addStringResult("ErrorMessage", sErrorMessage.c_str()); + pJournalEntry->addBooleanResult("HasError", *pHasError); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_getlibraryversion (LibPrimes_uint32 * pMajor, LibPrimes_uint32 * pMinor, LibPrimes_uint32 * pMicro) +LibPrimesResult libprimes_releaseinstance(LibPrimes_Base pInstance) { + IBase* pIBaseClass = nullptr; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { - pJournalEntry = m_GlobalJournal->beginStaticFunction("GetLibraryVersion"); + pJournalEntry = m_GlobalJournal->beginStaticFunction("ReleaseInstance"); + pJournalEntry->addHandleParameter("Instance", pInstance); } - if (!pMajor) - throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - if (!pMinor) - throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - if (!pMicro) - throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - LibPrimes_uint32 nMajor; - LibPrimes_uint32 nMinor; - LibPrimes_uint32 nMicro; + IBase* pIBaseClassInstance = (IBase *)pInstance; + IBase* pIInstance = dynamic_cast<IBase*>(pIBaseClassInstance); + if (!pIInstance) + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDCAST); + - CLibPrimesWrapper::GetLibraryVersion(nMajor, nMinor, nMicro); + CWrapper::ReleaseInstance(pIInstance); - *pMajor = nMajor; - *pMinor = nMinor; - *pMicro = nMicro; if (pJournalEntry.get() != nullptr) { - pJournalEntry->addUInt32Result ("Major", *pMajor); - pJournalEntry->addUInt32Result ("Minor", *pMinor); - pJournalEntry->addUInt32Result ("Micro", *pMicro); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_createfactorizationcalculator (LibPrimes_FactorizationCalculator * pInstance) +LibPrimesResult libprimes_createfactorizationcalculator(LibPrimes_FactorizationCalculator * pInstance) { + IBase* pIBaseClass = nullptr; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -358,33 +451,34 @@ LibPrimesResult libprimes_createfactorizationcalculator (LibPrimes_Factorization if (pInstance == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pBaseInstance(nullptr); + IBase* pBaseInstance(nullptr); - pBaseInstance = CLibPrimesWrapper::CreateFactorizationCalculator(); + pBaseInstance = CWrapper::CreateFactorizationCalculator(); - *pInstance = (ILibPrimesBaseClass*)(pBaseInstance); + *pInstance = (IBase*)(pBaseInstance); if (pJournalEntry.get() != nullptr) { - pJournalEntry->addHandleResult ("Instance", *pInstance); + pJournalEntry->addHandleResult("Instance", *pInstance); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_createsievecalculator (LibPrimes_SieveCalculator * pInstance) +LibPrimesResult libprimes_createsievecalculator(LibPrimes_SieveCalculator * pInstance) { + IBase* pIBaseClass = nullptr; + PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { @@ -394,33 +488,34 @@ LibPrimesResult libprimes_createsievecalculator (LibPrimes_SieveCalculator * pIn if (pInstance == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pBaseInstance(nullptr); + IBase* pBaseInstance(nullptr); - pBaseInstance = CLibPrimesWrapper::CreateSieveCalculator(); + pBaseInstance = CWrapper::CreateSieveCalculator(); - *pInstance = (ILibPrimesBaseClass*)(pBaseInstance); + *pInstance = (IBase*)(pBaseInstance); if (pJournalEntry.get() != nullptr) { - pJournalEntry->addHandleResult ("Instance", *pInstance); + pJournalEntry->addHandleResult("Instance", *pInstance); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } -LibPrimesResult libprimes_setjournal (const char * pFileName) +LibPrimesResult libprimes_setjournal(const char * pFileName) { + IBase* pIBaseClass = nullptr; + try { if (pFileName == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); @@ -435,13 +530,15 @@ LibPrimesResult libprimes_setjournal (const char * pFileName) return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); } catch (...) { - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass); } } -} diff --git a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.h b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.hpp similarity index 65% rename from Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.h rename to Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.hpp index 2b14eea7..e502bbe6 100644 --- a/Examples/Primes/LibPrimes_component/Bindings/Cpp/libprimes_types.h +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Interfaces/libprimes_types.hpp @@ -1,20 +1,20 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. -Abstract: This is an autogenerated plain C Header file with basic types in +Abstract: This is an autogenerated C++-Header file with basic types in order to allow an easy use of Prime Numbers Library Interface version: 1.2.0 */ -#ifndef __LIBPRIMES_TYPES_HEADER -#define __LIBPRIMES_TYPES_HEADER +#ifndef __LIBPRIMES_TYPES_HEADER_CPP +#define __LIBPRIMES_TYPES_HEADER_CPP /************************************************************************************************************************* Scalar types definition @@ -55,6 +55,7 @@ typedef double LibPrimes_double; typedef LibPrimes_int32 LibPrimesResult; typedef void * LibPrimesHandle; +typedef void * LibPrimes_pvoid; /************************************************************************************************************************* Version for LibPrimes @@ -63,6 +64,8 @@ typedef void * LibPrimesHandle; #define LIBPRIMES_VERSION_MAJOR 1 #define LIBPRIMES_VERSION_MINOR 2 #define LIBPRIMES_VERSION_MICRO 0 +#define LIBPRIMES_VERSION_PRERELEASEINFO "" +#define LIBPRIMES_VERSION_BUILDINFO "" /************************************************************************************************************************* Error constants for LibPrimes @@ -84,34 +87,42 @@ typedef void * LibPrimesHandle; Declaration of handle classes **************************************************************************************************************************/ -typedef LibPrimesHandle LibPrimes_BaseClass; +typedef LibPrimesHandle LibPrimes_Base; typedef LibPrimesHandle LibPrimes_Calculator; typedef LibPrimesHandle LibPrimes_FactorizationCalculator; typedef LibPrimesHandle LibPrimes_SieveCalculator; -/************************************************************************************************************************* - Declaration of structs -**************************************************************************************************************************/ - -#pragma pack (1) - -typedef struct { - LibPrimes_uint64 m_Prime; - LibPrimes_uint32 m_Multiplicity; -} sLibPrimesPrimeFactor; - -#pragma pack () - -/************************************************************************************************************************* - Declaration of function pointers -**************************************************************************************************************************/ - -/** -* LibPrimesProgressCallback - Callback to report calculation progress and query whether it should be aborted -* -* @param[in] fProgressPercentage - How far has the calculation progressed? -* @param[out] pShouldAbort - Should the calculation be aborted? -*/ -typedef void(*LibPrimesProgressCallback)(LibPrimes_single, bool*); - -#endif // __LIBPRIMES_TYPES_HEADER +namespace LibPrimes { + + /************************************************************************************************************************* + Declaration of structs + **************************************************************************************************************************/ + + #pragma pack (1) + + typedef struct { + LibPrimes_uint64 m_Prime; + LibPrimes_uint32 m_Multiplicity; + } sPrimeFactor; + + #pragma pack () + + /************************************************************************************************************************* + Declaration of function pointers + **************************************************************************************************************************/ + + /** + * ProgressCallback - Callback to report calculation progress and query whether it should be aborted + * + * @param[in] fProgressPercentage - How far has the calculation progressed? + * @param[out] pShouldAbort - Should the calculation be aborted? + */ + typedef void(*ProgressCallback)(LibPrimes_single, bool*); + +} // namespace LibPrimes; + +// define legacy C-names for enums, structs and function types +typedef LibPrimes::sPrimeFactor sLibPrimesPrimeFactor; +typedef LibPrimes::ProgressCallback LibPrimesProgressCallback; + +#endif // __LIBPRIMES_TYPES_HEADER_CPP diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes.cpp index 5d0b0757..1ea5f4ac 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes.cpp @@ -1,52 +1,53 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated C++ implementation file in order to allow easy development of Prime Numbers Library. It needs to be generated only once. -Interface version: 1.2.0 +Interface version: 1.0.0 */ -#include "libprimes.h" +#include "libprimes_abi.hpp" #include "libprimes_interfaces.hpp" #include "libprimes_interfaceexception.hpp" #include "libprimes_factorizationcalculator.hpp" #include "libprimes_sievecalculator.hpp" +using namespace LibPrimes; using namespace LibPrimes::Impl; -ILibPrimesFactorizationCalculator * CLibPrimesWrapper::CreateFactorizationCalculator () +bool CWrapper::GetLastError(IBase* pInstance, std::string & sErrorMessage) { - return new CLibPrimesFactorizationCalculator(); + return pInstance->GetLastErrorMessage(sErrorMessage); } -ILibPrimesSieveCalculator * CLibPrimesWrapper::CreateSieveCalculator() -{ - return new CLibPrimesSieveCalculator(); -} - -void CLibPrimesWrapper::ReleaseInstance (ILibPrimesBaseClass* pInstance) +void CWrapper::ReleaseInstance(IBase* pInstance) { delete pInstance; } -void CLibPrimesWrapper::GetLibraryVersion (unsigned int & nMajor, unsigned int & nMinor, unsigned int & nMicro) +void CWrapper::GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) { nMajor = LIBPRIMES_VERSION_MAJOR; nMinor = LIBPRIMES_VERSION_MINOR; nMicro = LIBPRIMES_VERSION_MICRO; } -void CLibPrimesWrapper::SetJournal (const std::string & sFileName) +IFactorizationCalculator * CWrapper::CreateFactorizationCalculator() +{ + return new CFactorizationCalculator(); +} + +ISieveCalculator * CWrapper::CreateSieveCalculator() { - throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_NOTIMPLEMENTED); + return new CSieveCalculator(); } diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.cpp new file mode 100644 index 00000000..4c61efd8 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.cpp @@ -0,0 +1,44 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +Abstract: This is a stub class definition of CBase + +*/ + +#include "libprimes_base.hpp" +#include "libprimes_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibPrimes::Impl; + +/************************************************************************************************************************* + Class definition of CBase +**************************************************************************************************************************/ + +bool CBase::GetLastErrorMessage(std::string & sErrorMessage) +{ + auto iIterator = m_errors.rbegin(); + if (iIterator != m_errors.rend()) { + sErrorMessage = *iIterator; + return true; + }else { + sErrorMessage = ""; + return false; + } +} + +void CBase::ClearErrorMessages() +{ + m_errors.clear(); +} + +void CBase::RegisterErrorMessage(const std::string & sErrorMessage) +{ + m_errors.push_back(sErrorMessage); +} + diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.hpp new file mode 100644 index 00000000..e1363832 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_base.hpp @@ -0,0 +1,67 @@ +/*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +Abstract: This is the class declaration of CBase + +*/ + + +#ifndef __LIBPRIMES_BASE +#define __LIBPRIMES_BASE + +#include "libprimes_interfaces.hpp" +#include <vector> + + +// Include custom headers here. + + +namespace LibPrimes { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CBase +**************************************************************************************************************************/ + +class CBase : public virtual IBase { +private: + + std::vector<std::string> m_errors; + + /** + * Put private members here. + */ + +protected: + + /** + * Put protected members here. + */ + +public: + + /** + * Put additional public members here. They will not be visible in the external API. + */ + + bool GetLastErrorMessage(std::string & sErrorMessage); + + void ClearErrorMessages(); + + void RegisterErrorMessage(const std::string & sErrorMessage); + + + /** + * Public member functions to implement. + */ + +}; + +} // namespace Impl +} // namespace LibPrimes + +#endif // __LIBPRIMES_BASE diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.cpp index 94b6d391..f3bb370c 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is a stub class definition of CLibPrimesCalculator +Abstract: This is a stub class definition of CCalculator */ @@ -17,28 +17,26 @@ Abstract: This is a stub class definition of CLibPrimesCalculator using namespace LibPrimes::Impl; /************************************************************************************************************************* - Class definition of CLibPrimesCalculator + Class definition of CCalculator **************************************************************************************************************************/ -CLibPrimesCalculator::CLibPrimesCalculator() - :m_value(0) , m_Callback(nullptr) +void CCalculator::SetProgressCallback(const LibPrimes::ProgressCallback pProgressCallback) { - + m_Callback = pProgressCallback; } - -LibPrimes_uint64 CLibPrimesCalculator::GetValue() +LibPrimes_uint64 CCalculator::GetValue() { return m_value; } -void CLibPrimesCalculator::SetValue(const LibPrimes_uint64 nValue) +void CCalculator::SetValue(const LibPrimes_uint64 nValue) { m_value = nValue; } -void CLibPrimesCalculator::SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) +void CCalculator::Calculate() { - m_Callback = pProgressCallback; + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_NOTIMPLEMENTED); } diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.hpp index 121b1789..a36336d5 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_calculator.hpp @@ -1,19 +1,23 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is the class declaration of CLibPrimesCalculator +Abstract: This is the class declaration of CCalculator */ -#ifndef __LIBPRIMES_LIBPRIMESCALCULATOR -#define __LIBPRIMES_LIBPRIMESCALCULATOR +#ifndef __LIBPRIMES_CALCULATOR +#define __LIBPRIMES_CALCULATOR #include "libprimes_interfaces.hpp" +// Parent classes +#include "libprimes_base.hpp" +#pragma warning( push) +#pragma warning( disable : 4250) // Include custom headers here. @@ -23,37 +27,47 @@ namespace Impl { /************************************************************************************************************************* - Class declaration of CLibPrimesCalculator + Class declaration of CCalculator **************************************************************************************************************************/ -class CLibPrimesCalculator : public virtual ILibPrimesCalculator { +class CCalculator : public virtual ICalculator, public virtual CBase { private: + /** + * Put private members here. + */ + protected: - LibPrimes_uint64 m_value; - LibPrimesProgressCallback m_Callback; + /** + * Put protected members here. + */ + LibPrimes_uint64 m_value; + ProgressCallback m_Callback; public: /** * Put additional public members here. They will not be visible in the external API. */ - CLibPrimesCalculator(); + /** * Public member functions to implement. */ + + void SetProgressCallback(const LibPrimes::ProgressCallback pProgressCallback); + LibPrimes_uint64 GetValue(); void SetValue(const LibPrimes_uint64 nValue); - void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback); + void Calculate(); - virtual void Calculate () = 0; }; } // namespace Impl } // namespace LibPrimes -#endif // __LIBPRIMES_LIBPRIMESCALCULATOR +#pragma warning( pop ) +#endif // __LIBPRIMES_CALCULATOR diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.cpp index 6f9d1a49..05801970 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is a stub class definition of CLibPrimesFactorizationCalculator +Abstract: This is a stub class definition of CFactorizationCalculator */ @@ -17,10 +17,10 @@ Abstract: This is a stub class definition of CLibPrimesFactorizationCalculator using namespace LibPrimes::Impl; /************************************************************************************************************************* - Class definition of CLibPrimesFactorizationCalculator + Class definition of CFactorizationCalculator **************************************************************************************************************************/ -void CLibPrimesFactorizationCalculator::Calculate() +void CFactorizationCalculator::Calculate() { primeFactors.clear(); @@ -35,7 +35,7 @@ void CLibPrimesFactorizationCalculator::Calculate() } } - sLibPrimesPrimeFactor primeFactor; + sPrimeFactor primeFactor; primeFactor.m_Prime = i; primeFactor.m_Multiplicity = 0; while (nValue % i == 0) { @@ -48,18 +48,17 @@ void CLibPrimesFactorizationCalculator::Calculate() } } - -void CLibPrimesFactorizationCalculator::GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64 * pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) +void CFactorizationCalculator::GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer) { if (primeFactors.size() == 0) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_NORESULTAVAILABLE); if (pPrimeFactorsNeededCount) - *pPrimeFactorsNeededCount = (unsigned int)primeFactors.size(); + *pPrimeFactorsNeededCount = (LibPrimes_uint64)primeFactors.size(); if (nPrimeFactorsBufferSize >= primeFactors.size() && pPrimeFactorsBuffer) { - for (size_t i = 0; i < primeFactors.size(); i++) + for (int i = 0; i < primeFactors.size(); i++) { pPrimeFactorsBuffer[i] = primeFactors[i]; } diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.hpp index c1f61b12..d80fc5fd 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_factorizationcalculator.hpp @@ -1,16 +1,16 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is the class declaration of CLibPrimesFactorizationCalculator +Abstract: This is the class declaration of CFactorizationCalculator */ -#ifndef __LIBPRIMES_LIBPRIMESFACTORIZATIONCALCULATOR -#define __LIBPRIMES_LIBPRIMESFACTORIZATIONCALCULATOR +#ifndef __LIBPRIMES_FACTORIZATIONCALCULATOR +#define __LIBPRIMES_FACTORIZATIONCALCULATOR #include "libprimes_interfaces.hpp" @@ -20,20 +20,20 @@ Abstract: This is the class declaration of CLibPrimesFactorizationCalculator #pragma warning( disable : 4250) // Include custom headers here. -#include <vector> + namespace LibPrimes { namespace Impl { /************************************************************************************************************************* - Class declaration of CLibPrimesFactorizationCalculator + Class declaration of CFactorizationCalculator **************************************************************************************************************************/ -class CLibPrimesFactorizationCalculator : public virtual ILibPrimesFactorizationCalculator, public virtual CLibPrimesCalculator { +class CFactorizationCalculator : public virtual IFactorizationCalculator, public virtual CCalculator { private: - std::vector<sLibPrimesPrimeFactor> primeFactors; + std::vector<sPrimeFactor> primeFactors; protected: @@ -53,7 +53,7 @@ class CLibPrimesFactorizationCalculator : public virtual ILibPrimesFactorization * Public member functions to implement. */ - void GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, sLibPrimesPrimeFactor* pPrimeFactorsBuffer); + void GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); }; @@ -61,4 +61,4 @@ class CLibPrimesFactorizationCalculator : public virtual ILibPrimesFactorization } // namespace LibPrimes #pragma warning( pop ) -#endif // __LIBPRIMES_LIBPRIMESFACTORIZATIONCALCULATOR +#endif // __LIBPRIMES_FACTORIZATIONCALCULATOR diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.cpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.cpp index 6f17111c..06076ca7 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.cpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.cpp @@ -1,10 +1,10 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is a stub class definition of CLibPrimesSieveCalculator +Abstract: This is a stub class definition of CSieveCalculator */ @@ -14,14 +14,13 @@ Abstract: This is a stub class definition of CLibPrimesSieveCalculator // Include custom headers here. #include <cmath> - using namespace LibPrimes::Impl; /************************************************************************************************************************* - Class definition of CLibPrimesSieveCalculator + Class definition of CSieveCalculator **************************************************************************************************************************/ -void CLibPrimesSieveCalculator::Calculate() +void CSieveCalculator::Calculate() { primes.clear(); @@ -29,23 +28,8 @@ void CLibPrimesSieveCalculator::Calculate() for (LibPrimes_uint64 i = 0; i <= m_value; i++) { strikenOut[i] = i < 2; } - LibPrimes_uint64 sqrtValue = (LibPrimes_uint64)(std::sqrt(m_value)); - - int progressStep = (int)std::ceil(sqrtValue / 20.0f); - for (LibPrimes_uint64 i = 2; i <= sqrtValue; i++) { - - if (m_Callback) { - if (i % progressStep == 0) { - bool shouldAbort = false; - (*m_Callback)(float(i) / sqrtValue, &shouldAbort); - if (shouldAbort) { - throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_CALCULATIONABORTED); - } - } - } - if (!strikenOut[i]) { primes.push_back(i); for (LibPrimes_uint64 j = i * i; j < m_value; j += i) { @@ -53,7 +37,6 @@ void CLibPrimesSieveCalculator::Calculate() } } } - for (LibPrimes_uint64 i = sqrtValue; i <= m_value; i++) { if (!strikenOut[i]) { primes.push_back(i); @@ -61,21 +44,18 @@ void CLibPrimesSieveCalculator::Calculate() } } -void CLibPrimesSieveCalculator::GetPrimes (LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64 * pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) +void CSieveCalculator::GetPrimes(LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) { if (primes.size() == 0) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_NORESULTAVAILABLE); - if (pPrimesNeededCount) - *pPrimesNeededCount = (unsigned int)primes.size(); - + *pPrimesNeededCount = (LibPrimes_uint64)primes.size(); if (nPrimesBufferSize >= primes.size() && pPrimesBuffer) { - for (size_t i = 0; i < primes.size(); i++) + for (int i = 0; i < primes.size(); i++) { pPrimesBuffer[i] = primes[i]; } } - } diff --git a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.hpp b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.hpp index c75920e4..1359b5a3 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.hpp +++ b/Examples/Primes/LibPrimes_component/Implementations/Cpp/Stub/libprimes_sievecalculator.hpp @@ -1,16 +1,16 @@ /*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -Abstract: This is the class declaration of CLibPrimesSieveCalculator +Abstract: This is the class declaration of CSieveCalculator */ -#ifndef __LIBPRIMES_LIBPRIMESSIEVECALCULATOR -#define __LIBPRIMES_LIBPRIMESSIEVECALCULATOR +#ifndef __LIBPRIMES_SIEVECALCULATOR +#define __LIBPRIMES_SIEVECALCULATOR #include "libprimes_interfaces.hpp" @@ -21,18 +21,22 @@ Abstract: This is the class declaration of CLibPrimesSieveCalculator // Include custom headers here. -#include <vector> namespace LibPrimes { namespace Impl { + /************************************************************************************************************************* - Class declaration of CLibPrimesSieveCalculator + Class declaration of CSieveCalculator **************************************************************************************************************************/ -class CLibPrimesSieveCalculator : public virtual ILibPrimesSieveCalculator, public virtual CLibPrimesCalculator { +class CSieveCalculator : public virtual ISieveCalculator, public virtual CCalculator { private: + /** + * Put private members here. + */ + std::vector<LibPrimes_uint64> primes; protected: @@ -43,13 +47,18 @@ class CLibPrimesSieveCalculator : public virtual ILibPrimesSieveCalculator, publ public: - void Calculate(); + /** + * Put additional public members here. They will not be visible in the external API. + */ + /** * Public member functions to implement. */ - void GetPrimes (LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer); + void Calculate(); + + void GetPrimes(LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer); }; @@ -57,4 +66,4 @@ class CLibPrimesSieveCalculator : public virtual ILibPrimesSieveCalculator, publ } // namespace LibPrimes #pragma warning( pop ) -#endif // __LIBPRIMES_LIBPRIMESSIEVECALCULATOR +#endif // __LIBPRIMES_SIEVECALCULATOR diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/.gitignore b/Examples/Primes/LibPrimes_component/Implementations/Pascal/.gitignore deleted file mode 100644 index c6415d19..00000000 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -bin -lib - diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes.lpr b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes.lpr index 41b81dd2..e651a08e 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes.lpr +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes.lpr @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal project file in order to allow easy development of Prime Numbers Library. @@ -33,8 +33,9 @@ libprimes_calculator_setprogresscallback, libprimes_factorizationcalculator_getprimefactors, libprimes_sievecalculator_getprimes, + libprimes_getversion, + libprimes_getlasterror, libprimes_releaseinstance, - libprimes_getlibraryversion, libprimes_createfactorizationcalculator, libprimes_createsievecalculator, libprimes_setjournal; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exception.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exception.pas index 0195a43e..1ff46e4e 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exception.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exception.pas @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal exception class definition file in order to allow easy development of Prime Numbers Library. The functions in this file need to be implemented. It needs to be generated only once. @@ -20,6 +20,7 @@ interface uses libprimes_types, + libprimes_interfaces, Classes, sysutils; @@ -36,6 +37,15 @@ ELibPrimesException = class (Exception) end; +(************************************************************************************************************************* + Definition of exception handling functionality for LibPrimes +**************************************************************************************************************************) + +function HandleLibPrimesException(ALibPrimesObject: TObject; E: ELibPrimesException): TLibPrimesResult; +function HandleStdException(ALibPrimesObject: TObject; E: Exception): TLibPrimesResult; +function HandleUnhandledException(ALibPrimesObject: TObject): TLibPrimesResult; + + implementation constructor ELibPrimesException.Create (AErrorCode: TLibPrimesResult); @@ -68,4 +78,29 @@ implementation inherited Create (Format ('%s (%d)', [FCustomMessage, AErrorCode])); end; +(************************************************************************************************************************* + Implementation of exception handling functionality for LibPrimes +**************************************************************************************************************************) + +function HandleLibPrimesException(ALibPrimesObject: TObject; E: ELibPrimesException): TLibPrimesResult; +begin + result := E.ErrorCode; + if Supports (ALibPrimesObject, ILibPrimesBase) then begin + (ALibPrimesObject as ILibPrimesBase).RegisterErrorMessage(E.CustomMessage) + end; +end; +function HandleStdException(ALibPrimesObject: TObject; E: Exception): TLibPrimesResult; +begin + Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + if Supports (ALibPrimesObject, ILibPrimesBase) then begin + (ALibPrimesObject as ILibPrimesBase).RegisterErrorMessage(E.Message) + end; +end; +function HandleUnhandledException(ALibPrimesObject: TObject): TLibPrimesResult; +begin + Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + if Supports (ALibPrimesObject, ILibPrimesBase) then begin + (ALibPrimesObject as ILibPrimesBase).RegisterErrorMessage('Unhandled Exception') + end; +end; end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exports.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exports.pas index 8fbb0a30..b0c0918a 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exports.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_exports.pas @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal export implementation file in order to allow easy development of Prime Numbers Library. The functions in this file need to be implemented. It needs to be generated only once. @@ -26,6 +26,10 @@ interface Classes, sysutils; +(************************************************************************************************************************* + Class export definition of Base +**************************************************************************************************************************) + (************************************************************************************************************************* Class export definition of Calculator **************************************************************************************************************************) @@ -100,22 +104,34 @@ function libprimes_sievecalculator_getprimes (pSieveCalculator: TLibPrimesHandle **************************************************************************************************************************) (** -* Releases the memory of an Instance +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*) +function libprimes_getversion (pMajor: PCardinal; pMinor: PCardinal; pMicro: PCardinal): TLibPrimesResult; cdecl; + +(** +* Returns the last error recorded on this object * * @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query * @return error code or 0 (success) *) -function libprimes_releaseinstance (pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; +function libprimes_getlasterror (pInstance: TLibPrimesHandle; nErrorMessageBufferSize: Cardinal; pErrorMessageNeededChars: PCardinal; pErrorMessageBuffer: PAnsiChar; pHasError: PByte): TLibPrimesResult; cdecl; (** -* retrieves the current version of the library. +* Releases the memory of an Instance * -* @param[out] pMajor - returns the major version of the library -* @param[out] pMinor - returns the minor version of the library -* @param[out] pMicro - returns the micro version of the library +* @param[in] pInstance - Instance Handle * @return error code or 0 (success) *) -function libprimes_getlibraryversion (pMajor: PCardinal; pMinor: PCardinal; pMicro: PCardinal): TLibPrimesResult; cdecl; +function libprimes_releaseinstance (pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; (** * Creates a new FactorizationCalculator instance @@ -167,10 +183,13 @@ function libprimes_calculator_getvalue (pCalculator: TLibPrimesHandle; pValue: P Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectCalculator); end; end; end; @@ -195,10 +214,13 @@ function libprimes_calculator_setvalue (pCalculator: TLibPrimesHandle; nValue: Q Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectCalculator); end; end; end; @@ -223,10 +245,13 @@ function libprimes_calculator_calculate (pCalculator: TLibPrimesHandle): TLibPri Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectCalculator); end; end; end; @@ -251,10 +276,13 @@ function libprimes_calculator_setprogresscallback (pCalculator: TLibPrimesHandle Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectCalculator); end; end; end; @@ -281,10 +309,13 @@ function libprimes_factorizationcalculator_getprimefactors (pFactorizationCalcul Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectFactorizationCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectFactorizationCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectFactorizationCalculator); end; end; end; @@ -311,60 +342,102 @@ function libprimes_sievecalculator_getprimes (pSieveCalculator: TLibPrimesHandle Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin - Result := E.ErrorCode; + Result := HandleLibPrimesException(ObjectSieveCalculator , E); end; On E: Exception do begin - Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + Result := HandleStdException(ObjectSieveCalculator , E); + end + else begin + Result := HandleUnhandledException(ObjectSieveCalculator); end; end; end; -function libprimes_releaseinstance (pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; +function libprimes_getversion (pMajor: PCardinal; pMinor: PCardinal; pMicro: PCardinal): TLibPrimesResult; cdecl; +begin + try + if (not Assigned (pMajor)) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); + + if (not Assigned (pMinor)) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); + + if (not Assigned (pMicro)) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); + + + TLibPrimesWrapper.GetVersion(pMajor^, pMinor^, pMicro^); + + Result := LIBPRIMES_SUCCESS; + except + On E: ELibPrimesException do begin + Result := E.ErrorCode; + end + else begin + Result := LIBPRIMES_ERROR_GENERICEXCEPTION; + end + end; +end; + +function libprimes_getlasterror (pInstance: TLibPrimesHandle; nErrorMessageBufferSize: Cardinal; pErrorMessageNeededChars: PCardinal; pErrorMessageBuffer: PAnsiChar; pHasError: PByte): TLibPrimesResult; cdecl; var ObjectInstance: TObject; + ResultErrorMessage: String; + LenErrorMessage: Cardinal; + ResultHasError: Boolean; begin try ObjectInstance := TObject (pInstance); - if (not Supports (ObjectInstance, ILibPrimesBaseClass)) then + if (not Supports (ObjectInstance, ILibPrimesBase)) then raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDCAST); + if ((not Assigned (pErrorMessageBuffer)) and (not Assigned(pErrorMessageNeededChars))) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); + if not Assigned (pHasError) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); - TLibPrimesWrapper.ReleaseInstance(ObjectInstance); + ResultHasError := TLibPrimesWrapper.GetLastError(ObjectInstance, ResultErrorMessage); + LenErrorMessage := Length (ResultErrorMessage); + if Assigned(pErrorMessageNeededChars) then + pErrorMessageNeededChars^ := LenErrorMessage; + if Assigned(pErrorMessageBuffer) then begin + if (LenErrorMessage >= nErrorMessageBufferSize) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_BUFFERTOOSMALL); + Move (PAnsiChar (ResultErrorMessage)^, pErrorMessageBuffer^, LenErrorMessage + 1); + end; + pHasError^ := Ord (ResultHasError); Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin Result := E.ErrorCode; - end; - On E: Exception do begin + end + else begin Result := LIBPRIMES_ERROR_GENERICEXCEPTION; - end; + end end; end; -function libprimes_getlibraryversion (pMajor: PCardinal; pMinor: PCardinal; pMicro: PCardinal): TLibPrimesResult; cdecl; +function libprimes_releaseinstance (pInstance: TLibPrimesHandle): TLibPrimesResult; cdecl; +var + ObjectInstance: TObject; begin try - if (not Assigned (pMajor)) then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); - - if (not Assigned (pMinor)) then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); - - if (not Assigned (pMicro)) then - raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDPARAM); - + ObjectInstance := TObject (pInstance); + if (not Supports (ObjectInstance, ILibPrimesBase)) then + raise ELibPrimesException.Create (LIBPRIMES_ERROR_INVALIDCAST); + - TLibPrimesWrapper.GetLibraryVersion(pMajor^, pMinor^, pMicro^); + TLibPrimesWrapper.ReleaseInstance(ObjectInstance); Result := LIBPRIMES_SUCCESS; except On E: ELibPrimesException do begin Result := E.ErrorCode; - end; - On E: Exception do begin + end + else begin Result := LIBPRIMES_ERROR_GENERICEXCEPTION; - end; + end end; end; @@ -383,10 +456,10 @@ function libprimes_createfactorizationcalculator (pInstance: PLibPrimesHandle): except On E: ELibPrimesException do begin Result := E.ErrorCode; - end; - On E: Exception do begin + end + else begin Result := LIBPRIMES_ERROR_GENERICEXCEPTION; - end; + end end; end; @@ -405,10 +478,10 @@ function libprimes_createsievecalculator (pInstance: PLibPrimesHandle): TLibPrim except On E: ELibPrimesException do begin Result := E.ErrorCode; - end; - On E: Exception do begin + end + else begin Result := LIBPRIMES_ERROR_GENERICEXCEPTION; - end; + end end; end; @@ -424,10 +497,10 @@ function libprimes_setjournal (pFileName: PAnsiChar): TLibPrimesResult; cdecl; except On E: ELibPrimesException do begin Result := E.ErrorCode; - end; - On E: Exception do begin + end + else begin Result := LIBPRIMES_ERROR_GENERICEXCEPTION; - end; + end end; end; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_interfaces.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_interfaces.pas index 09728ad5..143161cf 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_interfaces.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_interfaces.pas @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal interface definition file in order to allow easy development of Prime Numbers Library. The functions in this file need to be implemented. It needs to be generated only once. @@ -25,13 +25,18 @@ interface sysutils; +type + (************************************************************************************************************************* - Interface definition for BaseClass + Interface definition for Base **************************************************************************************************************************) -type - ILibPrimesBaseClass = interface + ILibPrimesBase = interface ['{52FDFC07-2182-454F-963F-5F0F9A621D72}'] + + function GetLastErrorMessage(out AErrorMessage: String): Boolean; + procedure ClearErrorMessages(); + procedure RegisterErrorMessage(const AErrorMessage: String); end; @@ -39,7 +44,7 @@ interface Interface definition for Calculator **************************************************************************************************************************) - ILibPrimesCalculator = interface (ILibPrimesBaseClass) + ILibPrimesCalculator = interface (ILibPrimesBase) ['{9566C74D-1003-4C4D-BBBB-0407D1E2C649}'] function GetValue(): QWord; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_types.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_types.pas index f9829351..9b0e28d5 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_types.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Interfaces/libprimes_types.pas @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal type definition file in order to allow easy development of Prime Numbers Library. The functions in this file need to be implemented. It needs to be generated only once. @@ -30,6 +30,8 @@ interface LIBPRIMES_VERSION_MAJOR = 1; LIBPRIMES_VERSION_MINOR = 2; LIBPRIMES_VERSION_MICRO = 0; + LIBPRIMES_VERSION_PRERELEASEINFO = ''; + LIBPRIMES_VERSION_BUILDINFO = ''; (************************************************************************************************************************* diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl.pas index 5a929efa..c48b064b 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl.pas @@ -1,10 +1,10 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. -This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0. +This file has been generated by the Automatic Component Toolkit (ACT) version 1.5.0. Abstract: This is an autogenerated Pascal implementation file in order to allow easy development of Prime Numbers Library. It needs to be generated only once. @@ -21,49 +21,52 @@ interface uses libprimes_types, libprimes_exception, - libprimes_impl_factorizationcalculator, - libprimes_impl_sievecalculator, + libprimes_interfaces, Classes, sysutils; type TLibPrimesWrapper = class (TObject) public + class procedure GetVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); + class function GetLastError(AInstance: TObject; out AErrorMessage: String): Boolean; + class procedure ReleaseInstance(AInstance: TObject); class function CreateFactorizationCalculator(): TObject; class function CreateSieveCalculator(): TObject; - class procedure ReleaseInstance(AInstance: TObject); - class procedure GetLibraryVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); class procedure SetJournal(const AFileName: String); end; implementation -class function TLibPrimesWrapper.CreateFactorizationCalculator(): TObject; +class procedure TLibPrimesWrapper.GetVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); begin - result := TLibPrimesFactorizationCalculator.Create(); + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; -class function TLibPrimesWrapper.CreateSieveCalculator(): TObject; +class function TLibPrimesWrapper.GetLastError(AInstance: TObject; out AErrorMessage: String): Boolean; begin - result := TLibPrimesSieveCalculator.Create(); + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; class procedure TLibPrimesWrapper.ReleaseInstance(AInstance: TObject); begin - FreeAndNil(AInstance); + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; -class procedure TLibPrimesWrapper.GetLibraryVersion(out AMajor: Cardinal; out AMinor: Cardinal; out AMicro: Cardinal); +class function TLibPrimesWrapper.CreateFactorizationCalculator(): TObject; +begin + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); +end; + +class function TLibPrimesWrapper.CreateSieveCalculator(): TObject; begin - AMajor := LIBPRIMES_VERSION_MAJOR; - AMinor := LIBPRIMES_VERSION_MINOR; - AMicro := LIBPRIMES_VERSION_MICRO; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; class procedure TLibPrimesWrapper.SetJournal(const AFileName: String); begin - raise ELibPrimesException (LIBPRIMES_ERROR_NOTIMPLEMENTED); + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_base.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_base.pas new file mode 100644 index 00000000..a2c7c198 --- /dev/null +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_base.pas @@ -0,0 +1,69 @@ +(*++ + +Copyright (C) 2019 PrimeDevelopers + +All rights reserved. + +Abstract: This is the class declaration of TLibPrimesBase + +*) + +{$MODE DELPHI} +unit libprimes_impl_base; + +interface + +uses + libprimes_types, + libprimes_interfaces, + libprimes_exception, + Classes, + sysutils; + +type + TLibPrimesBase = class(TObject, ILibPrimesBase) + private + FMessages: TStringList; + + protected + + public + constructor Create(); + destructor Destroy(); override; + function GetLastErrorMessage(out AErrorMessage: String): Boolean; + procedure ClearErrorMessages(); + procedure RegisterErrorMessage(const AErrorMessage: String); + end; + +implementation + +constructor TLibPrimesBase.Create(); +begin + inherited Create(); + FMessages := TStringList.Create(); +end; + +destructor TLibPrimesBase.Destroy(); +begin + FreeAndNil(FMessages); + inherited Destroy(); +end; + +function TLibPrimesBase.GetLastErrorMessage(out AErrorMessage: String): Boolean; +begin + result := (FMessages.Count>0); + if (result) then + AErrorMessage := FMessages[FMessages.Count-1]; +end; + +procedure TLibPrimesBase.ClearErrorMessages(); +begin + FMessages.Clear(); +end; + +procedure TLibPrimesBase.RegisterErrorMessage(const AErrorMessage: String); +begin + FMessages.Add(AErrorMessage); +end; + +end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_baseclass.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_baseclass.pas deleted file mode 100644 index e7733694..00000000 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_baseclass.pas +++ /dev/null @@ -1,27 +0,0 @@ -(*++ - -Copyright (C) 2018 PrimeDevelopers - -All rights reserved. - -Abstract: This is the class declaration of TLibPrimesBaseClass - -*) - -{$MODE DELPHI} -unit libprimes_impl_baseclass; - -interface - -uses - libprimes_interfaces, - Classes, - sysutils; - -type - TLibPrimesBaseClass = class (TObject, ILibPrimesBaseClass) - end; - -implementation - -end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_calculator.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_calculator.pas index 9264f107..d9e92c5e 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_calculator.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_calculator.pas @@ -1,6 +1,6 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. @@ -17,44 +17,43 @@ interface libprimes_types, libprimes_interfaces, libprimes_exception, - libprimes_impl_baseclass, + libprimes_impl_base, Classes, sysutils; type - TLibPrimesCalculator = class (TLibPrimesBaseClass, ILibPrimesCalculator) + TLibPrimesCalculator = class(TLibPrimesBase, ILibPrimesCalculator) private protected - FValue : QWord; - FProgressCallback: PLibPrimes_ProgressCallback; + public function GetValue(): QWord; procedure SetValue(const AValue: QWord); + procedure Calculate(); procedure SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); - procedure Calculate(); virtual; end; implementation function TLibPrimesCalculator.GetValue(): QWord; begin - result := FValue; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; procedure TLibPrimesCalculator.SetValue(const AValue: QWord); begin - FValue := AValue; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; -procedure TLibPrimesCalculator.SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); +procedure TLibPrimesCalculator.Calculate(); begin - FProgressCallback:=AProgressCallback; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; -procedure TLibPrimesCalculator.Calculate(); +procedure TLibPrimesCalculator.SetProgressCallback(const AProgressCallback: PLibPrimes_ProgressCallback); begin - raise ELibPrimesException (LIBPRIMES_ERROR_NOTIMPLEMENTED); + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_factorizationcalculator.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_factorizationcalculator.pas index d84acbac..586eb0e7 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_factorizationcalculator.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_factorizationcalculator.pas @@ -1,6 +1,6 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. @@ -22,81 +22,20 @@ interface sysutils; type - TLibPrimesFactorizationCalculator = class (TLibPrimesCalculator, ILibPrimesFactorizationCalculator) + TLibPrimesFactorizationCalculator = class(TLibPrimesCalculator, ILibPrimesFactorizationCalculator) private - FPrimeFactors : Array Of TLibPrimesPrimeFactor; + protected public procedure GetPrimeFactors(const APrimeFactorsCount: QWord; PPrimeFactorsNeededCount: PQWord; APrimeFactors: PLibPrimesPrimeFactor); - procedure Calculate(); override; - destructor Destroy(); override; end; implementation -destructor TLibPrimesFactorizationCalculator.Destroy(); -begin - SetLength(FPrimeFactors, 0); -end; - procedure TLibPrimesFactorizationCalculator.GetPrimeFactors(const APrimeFactorsCount: QWord; PPrimeFactorsNeededCount: PQWord; APrimeFactors: PLibPrimesPrimeFactor); -var - i : QWord; -begin - if (Length(FPrimeFactors) = 0) then - raise ELibPrimesException.Create(LIBPRIMES_ERROR_NORESULTAVAILABLE); - - if (assigned(PPrimeFactorsNeededCount)) then - PPrimeFactorsNeededCount^ := Length(FPrimeFactors); - - if (APrimeFactorsCount >= Length(FPrimeFactors)) then - begin - for i:=0 to Length(FPrimeFactors) -1 do begin - APrimeFactors^ := FPrimeFactors[i]; - inc(APrimeFactors); - end; - end; -end; - -procedure TLibPrimesFactorizationCalculator.Calculate(); -var - AValue: QWord; - I: QWord; - APFCount: QWord; - APrimeFactor: TLibPrimesPrimeFactor; - AShouldAbort: Cardinal; begin - SetLength(FPrimeFactors, 0); - - APFCount := 0; - AValue := FValue; - I := 2; - while I < AValue - do begin - - - if (assigned(FProgressCallback)) then begin - AShouldAbort := 0; - FProgressCallback(1 - 1.0*AValue / FValue, AShouldAbort); - if (AShouldAbort <> 0) then - raise ELibPrimesException.Create(LIBPRIMES_ERROR_CALCULATIONABORTED); - end; - - - APrimeFactor.FMultiplicity:=0; - APrimeFactor.FPrime:=I; - while (AValue mod i = 0) do begin - inc(APrimeFactor.FMultiplicity); - AValue := AValue div I; - end; - if (APrimeFactor.FMultiplicity > 0) then begin - inc(APFCount); - SetLength(FPrimeFactors, APFCount); - FPrimeFactors[APFCount-1] := APrimeFactor; - end; - inc(I); - end; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_sievecalculator.pas b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_sievecalculator.pas index 24e480fa..28ee5265 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_sievecalculator.pas +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/Stub/libprimes_impl_sievecalculator.pas @@ -1,6 +1,6 @@ (*++ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. @@ -22,77 +22,20 @@ interface sysutils; type - TLibPrimesSieveCalculator = class (TLibPrimesCalculator, ILibPrimesSieveCalculator) + TLibPrimesSieveCalculator = class(TLibPrimesCalculator, ILibPrimesSieveCalculator) private - FPrimes: array of QWord; + protected public procedure GetPrimes(const APrimesCount: QWord; PPrimesNeededCount: PQWord; APrimes: PQWord); - procedure Calculate(); override; end; implementation -procedure TLibPrimesSieveCalculator.Calculate(); -var - AStrikenOut : array of Boolean; - I, J : QWord; - ASqrtValue : QWord; - ANumPrimes: QWord; -begin - SetLength(FPrimes, 0); - ANumPrimes := 0; - - SetLength(AStrikenOut, FValue + 1); - for I := 0 to FValue do begin - AStrikenOut[I] := I < 2; - end; - - ASqrtValue := round(sqrt(FValue)); - - for I := 2 to ASqrtValue do begin - if not AStrikenOut[I] then begin - inc(ANumPrimes); - SetLength(FPrimes, ANumPrimes); - FPrimes[ANumPrimes - 1] := I; - J := I*I; - while (J <= FValue) do begin - AStrikenOut[j] := true; - inc(J, I); - end; - - end; - - end; - - for I:= ASqrtValue to FValue do begin - if not AStrikenOut[i] then begin - inc(ANumPrimes); - SetLength(FPrimes, ANumPrimes); - FPrimes[ANumPrimes - 1] := I; - end; - end; - -end; - procedure TLibPrimesSieveCalculator.GetPrimes(const APrimesCount: QWord; PPrimesNeededCount: PQWord; APrimes: PQWord); -var - i : QWord; begin - if (Length(FPrimes) = 0) then - raise ELibPrimesException.Create(LIBPRIMES_ERROR_NORESULTAVAILABLE); - - if (assigned(PPrimesNeededCount)) then - PPrimesNeededCount^ := Length(FPrimes); - - if (APrimesCount >= Length(FPrimes)) then - begin - for i:=0 to Length(FPrimes) -1 do begin - APrimes^ := FPrimes[i]; - inc(APrimes); - end; - end; + raise ELibPrimesException.Create (LIBPRIMES_ERROR_NOTIMPLEMENTED); end; end. diff --git a/Examples/Primes/LibPrimes_component/Implementations/Pascal/libprimes.def b/Examples/Primes/LibPrimes_component/Implementations/Pascal/libprimes.def index babde722..b41507d0 100644 --- a/Examples/Primes/LibPrimes_component/Implementations/Pascal/libprimes.def +++ b/Examples/Primes/LibPrimes_component/Implementations/Pascal/libprimes.def @@ -1,6 +1,7 @@ EXPORTS +libprimes_getversion +libprimes_getlasterror libprimes_releaseinstance -libprimes_getlibraryversion libprimes_createfactorizationcalculator libprimes_createsievecalculator libprimes_setjournal diff --git a/Examples/Primes/LibPrimes_component/license.txt b/Examples/Primes/LibPrimes_component/license.txt index f0a7288b..3025d2e0 100644 --- a/Examples/Primes/LibPrimes_component/license.txt +++ b/Examples/Primes/LibPrimes_component/license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2018 PrimeDevelopers +Copyright (C) 2019 PrimeDevelopers All rights reserved. diff --git a/Examples/Primes/Tutorial.md b/Examples/Primes/Tutorial.md index d141b217..f8ae730f 100644 --- a/Examples/Primes/Tutorial.md +++ b/Examples/Primes/Tutorial.md @@ -38,7 +38,7 @@ _There are much more efficient algorithms and more suitable software packages to # 2. Requirements - CMake - A C++ compiler / development environment. This tutorial was tested with Visual Studio 2017, but should also work with `GCC` and `make` or other development tools. - - ACT: This tutorial is tested to work with release 1.4.0 of ACT. You can get it from [the releases page](https://github.com/Autodesk/AutomaticComponentToolkit/releases). + - ACT: This tutorial is tested to work with release 1.5.0 of ACT. You can get it from [the releases page](https://github.com/Autodesk/AutomaticComponentToolkit/releases). Decide on a location for your tutorial's component to live in, and download the binary for your platform into this folder. Alternatively, stick it somwhere in your `$PATH`. @@ -51,16 +51,16 @@ First, copy the snippet, a bare-bone IDL-file, and save it into libPrimes.xml in ```xml <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.0.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> </bindings> <implementations> @@ -79,15 +79,22 @@ First, copy the snippet, a bare-bone IDL-file, and save it into libPrimes.xml in <error name="INCOMPATIBLEBINARYVERSION" code="8" description="the version of the binary interface does not match the bindings interface" /> </errors> - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion"> + <class name="Base"> + </class> + + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError"> + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> </method> - - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> + <method name="GetLibraryVersion" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> </method> </global> </component> @@ -97,10 +104,11 @@ It's elements define the following: - The attributes of `\<component>` define essential properties and naming conventions of the component, and contains all other info about the component. - `\<error>` define the error codes to be used in the library that will be exposed for it's consumers. The errors listed in this snippet are required. --`\<global>` defines the global functions that can be used as entry points into the component. -It must contain a `versionmethod` and a `releasemethod` with the signatures in this snippet. +- `\<global>` defines the global functions that can be used as entry points into the component. +It must contain a `versionmethod`, a `releasemethod` and a `errormethod` with the signatures in this snippet. They will be explained in [this section](#331-required-steps-for-every-act-component). The syntax for methods will be explained when we add new classes and functions to the IDL-file now. +- The `baseclassname`-attribute of the `\<global>`-section points to the `\<class>` "Base", which will be the baseclass for all other classes defined in this component. ### 3.1.1 A struct for prime factors @@ -112,10 +120,10 @@ In the `\<component>` element, add a struct `PrimeFactor` that encodes a prime n </struct> ``` ### 3.1.1 Calculator -In the `\<component>` element, add a class `Calculator` which implements the base class for +After the `Base`-class in the `\<component>`-element add a class `Calculator` which implements the base class for the different calculators we will expose in our API. ```xml -<class name="Calculator"> +<class name="Calculator" parent="Base"> <method name="GetValue" description="Returns the current value of this Calculator"> <param name="Value" type="uint64" pass="return" description="The current value of this Calculator" /> </method> @@ -167,14 +175,14 @@ results from a calculator without having performed a calculation before. Thus ad The global section requires two more methods, that are used as entry points to the component's functionality: ```xml <method name="CreateFactorizationCalculator" description="Creates a new FactorizationCalculator instance"> - <param name="Instance" type="handle" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> + <param name="Instance" type="class" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> </method> ``` `CreateFactorizationCalculator` specifies a global function that will create a new instance of the `FactorizationCalculator`. ```xml <method name="CreateSieveCalculator" description="Creates a new SieveCalculator instance"> - <param name="Instance" type="handle" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> + <param name="Instance" type="class" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> </method> ``` `CreateSieveCalculator` specifies a global function that will create a new instance of the `SieveCalculator`. @@ -191,27 +199,30 @@ act.exe libPrimes.xml ``` This generates a folder `LibPrimes_component` with two subfolders, `Bindings` and `Implementation`. -Let's focus on `Implementation/CPP` for now, which contains a folder `Interfaces` and `Stubs` +Let's focus on `Implementation/CPP` for now, which contains a folder `Interfaces` and `Stubs`. + ### 3.2.1 Interfaces Consider all files in the `Interfaces` folder read only for your development. -They will be regenerated/overwritten if you run ACT again, and you should never have to modify them. +They will be regenerated/overwritten if you run ACT again, and you should never have to modify them manually. Usually, you will not include them in the source code control system of your component. -The `libprimes_interfaces.hpp` file contains all classes from the IDL as pure abstract C++ classes. E.g. have a look at -the interfaces `ILibPrimesCalculator` and `ILibPrimesFactorizationCalculator`: +The `libprimes_interfaces.hpp`-file contains all classes from the IDL as pure abstract C++ classes. E.g. have a look at +the interfaces `LibPrimes::ICalculator` and `LibPrimes::IFactorizationCalculator`: ```cpp /*...*/ -class ILibPrimesCalculator : public virtual ILibPrimesBaseClass { +class ICalculator : public virtual IBase{ public: - virtual LibPrimes_uint64 long GetValue () = 0; - virtual void SetValue (const LibPrimes_uint64 nValue) = 0; - virtual void Calculate () = 0; + ICalculator::GetValue - Returns the current value of this + virtual LibPrimes_uint64 GetValue() = 0; + virtual void SetValue(const LibPrimes_uint64 nValue) = 0; + virtual void Calculate() = 0; }; -class ILibPrimesFactorizationCalculator : public virtual ILibPrimesBaseClass, public virtual ILibPrimesCalculator { +class IFactorizationCalculator : public virtual IBase, public virtual ICalculator{ public: - virtual void GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64 * pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) = 0; + virtual void GetPrimeFactors(LibPrimes_uint64 + nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer) = 0; }; /*...*/ ``` @@ -221,26 +232,26 @@ The `libprimes_interfaceexception.hpp` and `libprimes_interfaceexception.cpp` fi The `libprimes_interfacewrapper.cpp` file implements the forwarding of the C89-interface functions to the classes you will implement. It also translates all exceptions into error codes. ```cpp -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_getvalue (LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) +LibPrimesResult libprimes_calculator_getvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) { + IBase* pIBaseClass = (IBase *)pCalculator; try { if (pValue == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); - *pValue = pICalculator->GetValue(); - return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); } catch (...) { - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass); } } ``` @@ -252,19 +263,17 @@ For each class in the IDL, a pair of header and source files has been generated. They contain a concrete class definition derived from the corresponding interface in interfaces.hpp. ```cpp -class CLibPrimesFactorizationCalculator : public virtual ILibPrimesFactorizationCalculator, public virtual CLibPrimesCalculator { +class CFactorizationCalculator : public virtual IFactorizationCalculator, public virtual CCalculator { public: - void Calculate(); - void GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64 * pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer); + void GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer); }; ``` The autogenerated implementation of each of a class's methods throws a `NOTIMPLEMENTED` exception: ```cpp -void CLibPrimesFactorizationCalculator::GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, - LibPrimes_uint64 * pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) +void CFactorizationCalculator::GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer) { - throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_NOTIMPLEMENTED); + throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_NOTIMPLEMENTED); } ``` @@ -286,28 +295,32 @@ Now we can start actually implementing the library. ### 3.3.1. Required steps for every ACT component #### GetVersion function ```cpp -void CLibPrimesWrapper::GetLibraryVersion (LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) +void CWrapper::GetVersion(LibPrimes_uint32 & nMajor, LibPrimes_uint32 & nMinor, LibPrimes_uint32 & nMicro) { nMajor = LIBPRIMES_VERSION_MAJOR; nMinor = LIBPRIMES_VERSION_MINOR; nMicro = LIBPRIMES_VERSION_MICRO; } ``` +ACT advocates the [semantic versioning scheme](https://semver.org/) and all components defined by ACT provide a function that returns +the major-, minor- and micro-version. `LIBPRIMES_VERSION_*` are defined automatically from the `version` attribute of the `\<component>` in libPrimes.xml. + +In addition an ACT component CAN provide prerelease- and build-information by defining a `prereleasemethod` and `buildinfomethod`, see the [documentation](../../Documentation/IDL.md). #### CreateFunctions For all methods in the IDL that are used to return a new instance of a class, code similar to this needs to be implemented. ```cpp #include "libprimes_factorizationcalculator.hpp" /*...*/ -ILibPrimesFactorizationCalculator * CLibPrimesWrapper::CreateFactorizationCalculator () +IFactorizationCalculator * CWrapper::CreateFactorizationCalculator() { - return new CLibPrimesFactorizationCalculator(); + return new CFactorizationCalculator(); } ``` #### Release Function ```cpp -void CLibPrimesWrapper::ReleaseInstance (ILibPrimesBaseClass* pInstance) +void CWrapper::ReleaseInstance(IBase* pInstance) { delete pInstance; } @@ -318,7 +331,19 @@ _Obvioulsy, you can do something more clever/robust, than simply handing out "ne and deleting them if asked for it via `ReleaseInstance`" (e.g. store them in a set-datastructure, so that you can "free" them if the consumer does not do so). However, this is solution is fine in the context of ACT, as all automatically generated bindings -(except `C`) handle the lifetime of all generated ILibPrimesBaseClass instances._ +(except `C`) handle the lifetime of all generated IBase instances._ + +#### Error Function +```cpp +bool CWrapper::GetLastError(IBase* pInstance, std::string & sErrorMessage) +{ + return pInstance->GetLastErrorMessage(sErrorMessage); +} +``` + +This method queries the last error that occurred during a method of an instance. +See [4.1.1 Exception/Error handling](#411-exceptionerror-handling) for more details. + ### 3.3.2. Domain code implementation: Steps for LibPrimes #### CreateFunctions @@ -326,16 +351,16 @@ Implement the missing `CreateSieveCalculator` ```cpp #include "libprimes_sievecalculator.hpp" /*...*/ -ILibPrimesSieveCalculator * CLibPrimesWrapper::CreateSieveCalculator () +ISieveCalculator * CWrapper::CreateSieveCalculator() { - return new CLibPrimesSieveCalculator(); + return new CSieveCalculator(); } ``` #### Calculator -Add a protected member `m_value` to the `CLibPrimesCalculator` +Add a protected member `m_value` to the `CCalculator` ```cpp -class CLibPrimesCalculator : public virtual ILibPrimesCalculator { +class CCalculator : public virtual ICalculator { protected: LibPrimes_uint64 m_value; /*...*/ @@ -343,12 +368,12 @@ protected: ``` The `GetValue`/`SetValue` methods of the `Calculator` are straight-forward: ```cpp -LibPrimes_uint64 CLibPrimesCalculator::GetValue() +LibPrimes_uint64 CCalculator::GetValue() { return m_value; } -void CLibPrimesCalculator::SetValue(const LibPrimes_uint64 nValue) +void CCalculator::SetValue(const LibPrimes_uint64 nValue) { m_value = nValue; } @@ -358,13 +383,13 @@ We can safely leave the `Calculate`-method untouched, or alternatively, declare and remove its implementation. #### FactorizationCalculator -Add an array that holds the calculated prime factors as private member in `CLibPrimesFactorizationCalculator` +Add an array that holds the calculated prime factors as private member in `CFactorizationCalculator` and a public `Calculate` method: ```cpp -class CLibPrimesFactorizationCalculator : public virtual ILibPrimesFactorizationCalculator, public virtual CLibPrimesCalculator +class CFactorizationCalculator : public virtual IFactorizationCalculator, public virtual CCalculator { private: - std::vector<sLibPrimesPrimeFactor> primeFactors; + std::vector<sPrimeFactor> primeFactors; public: void Calculate(); /*...*/ @@ -373,14 +398,13 @@ public: A valid implementation of `GetPrimes` is the following ```cpp -void CLibPrimesFactorizationCalculator::GetPrimeFactors (LibPrimes_uint64 nPrimeFactorsBufferSize, - LibPrimes_uint64 * pPrimeFactorsNeededCount, sLibPrimesPrimeFactor * pPrimeFactorsBuffer) +void CFactorizationCalculator::GetPrimeFactors(LibPrimes_uint64 nPrimeFactorsBufferSize, LibPrimes_uint64* pPrimeFactorsNeededCount, LibPrimes::sPrimeFactor * pPrimeFactorsBuffer) { if (primeFactors.size() == 0) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_NORESULTAVAILABLE); if (pPrimeFactorsNeededCount) - *pPrimeFactorsNeededCount = (unsigned int)primeFactors.size(); + *pPrimeFactorsNeededCount = (LibPrimes_uint64)primeFactors.size(); if (nPrimeFactorsBufferSize >= primeFactors.size() && pPrimeFactorsBuffer) { @@ -394,13 +418,13 @@ void CLibPrimesFactorizationCalculator::GetPrimeFactors (LibPrimes_uint64 nPrime The following snippet calculates the prime factor decomposition of the calculator's member `m_value`. ```cpp -void CLibPrimesFactorizationCalculator::Calculate() +void CFactorizationCalculator::Calculate() { primeFactors.clear(); LibPrimes_uint64 nValue = m_value; for (LibPrimes_uint64 i = 2; i <= nValue; i++) { - sLibPrimesPrimeFactor primeFactor; + sPrimeFactor primeFactor; primeFactor.m_Prime = i; primeFactor.m_Multiplicity = 0; while (nValue % i == 0) { @@ -415,10 +439,10 @@ void CLibPrimesFactorizationCalculator::Calculate() ``` #### SieveCalculator -Add an array that holds the calculated prime numbers as private member in `CLibPrimesSieveCalculator` +Add an array that holds the calculated prime numbers as private member in `CSieveCalculator` and a public `Calculate` method: ```cpp -class CLibPrimesSieveCalculator : public virtual ILibPrimesSieveCalculator, public virtual CLibPrimesCalculator { +class CSieveCalculator : public virtual ISieveCalculator, public virtual CCalculator { private: std::vector<LibPrimes_uint64> primes; public: @@ -429,8 +453,7 @@ public: The `GetPrimes` method is analogous to the above `GetPrimeFactors` ```cpp -void CLibPrimesSieveCalculator::GetPrimes (unsigned int nPrimesBufferSize, - LibPrimes_uint64 * pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) +void CSieveCalculator::GetPrimes(LibPrimes_uint64 nPrimesBufferSize, LibPrimes_uint64* pPrimesNeededCount, LibPrimes_uint64 * pPrimesBuffer) { if (primes.size() == 0) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_NORESULTAVAILABLE); @@ -448,7 +471,9 @@ void CLibPrimesSieveCalculator::GetPrimes (unsigned int nPrimesBufferSize, Finally, the following calculate method implements the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) ```cpp -void CLibPrimesSieveCalculator::Calculate() +#include <cmath> +/* ... */ +void CSieveCalculator::Calculate() { primes.clear(); @@ -456,7 +481,7 @@ void CLibPrimesSieveCalculator::Calculate() for (LibPrimes_uint64 i = 0; i <= m_value; i++) { strikenOut[i] = i < 2; } - LibPrimes_uint64 sqrtValue = (LibPrimes_uint64)(sqrt(m_value)); + LibPrimes_uint64 sqrtValue = (LibPrimes_uint64)(std::sqrt(m_value)); for (LibPrimes_uint64 i = 2; i <= sqrtValue; i++) { if (!strikenOut[i]) { primes.push_back(i); @@ -473,7 +498,7 @@ void CLibPrimesSieveCalculator::Calculate() } ``` -This concludes the implementation of the library. +This concludes the implementation of version `1.0.0` of the library. # 4. The Consumers This section will demonstrate how easy it is to consume "LibPrimes". The autogenerated `Bindings` folder contains multiple language bindings, @@ -501,11 +526,12 @@ int main() { try { - std::string libpath = (""); // TODO: put the location of the LibPrimes-library file here. - auto wrapper = LibPrimes::CLibPrimesWrapper::loadLibrary(libpath + "/libprimes."); // TODO: add correct suffix of the library - unsigned int nMajor, nMinor, nMicro; - wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); - std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro << std::endl; + std::string libpath = ""; // TODO: put the location of the LibPrimes-library file here. + auto wrapper = LibPrimes::CWrapper::loadLibrary(libpath + "/libprimes."); // TODO: add correct suffix of the library + LibPrimes_uint32 nMajor, nMinor, nMicro; + wrapper->GetVersion(nMajor, nMinor, nMicro); + std::cout << "LibPrimes.Version = " << nMajor << "." << nMinor << "." << nMicro; + std::cout << std::endl; } catch (std::exception &e) { @@ -530,7 +556,7 @@ add the following at the end of the try block: auto factorization = wrapper->CreateFactorizationCalculator(); factorization->SetValue(735); factorization->Calculate(); -std::vector<sLibPrimesPrimeFactor> primeFactors; +std::vector<LibPrimes::sPrimeFactor> primeFactors; factorization->GetPrimeFactors(primeFactors); std::cout << factorization->GetValue() << " = "; @@ -547,27 +573,43 @@ LibPrimes.Version = 1.0.0 ``` Have a look at the implementation of the dynamic Cpp bindings in the single header file `libprimes_dynamic.hpp`, -e.g. a C++ function call is forwarded to the C-interface as follows +e.g. a C++ function call is forwarded to the thin C-interface as follows ```cpp -void GetPrimeFactors (std::vector<sLibPrimesPrimeFactor> & PrimeFactorsBuffer) -{ - LibPrimes_uint64 elementsNeededPrimeFactors = 0; - LibPrimes_uint64 elementsWrittenPrimeFactors = 0; - CheckError ( m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors (m_pHandle, 0, &elementsNeededPrimeFactors, nullptr) ); - PrimeFactorsBuffer.resize(elementsNeededPrimeFactors); - CheckError ( m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors (m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data()) ); -} + void CFactorizationCalculator::GetPrimeFactors(std::vector<sPrimeFactor> & PrimeFactorsBuffer) + { + LibPrimes_uint64 elementsNeededPrimeFactors = 0; + LibPrimes_uint64 elementsWrittenPrimeFactors = 0; + CheckError(m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors(m_pHandle, 0, &elementsNeededPrimeFactors, nullptr)); + PrimeFactorsBuffer.resize((size_t) elementsNeededPrimeFactors); + CheckError(m_pWrapper->m_WrapperTable.m_FactorizationCalculator_GetPrimeFactors(m_pHandle, elementsNeededPrimeFactors, &elementsWrittenPrimeFactors, PrimeFactorsBuffer.data())); + } ``` __Note__ _For the out-array, `m_FactorizationCalculator_GetPrimeFactors` is called twice. First, to obtain the size of the array, secondly to actually fill the array with content. Thus, it would be very inefficient to perform the calculation during the `GetPrimeFactors`-method_ -All return values of functions are translated to C++ exceptions via the `CheckError`-method: +# 4.1.1 Exception/Error handling +All return values of functions are translated to C++ exceptions via the `CheckError`-methods of the base-class and the wrapper object: ```cpp -void CheckError(LibPrimesHandle handle, LibPrimesResult nResult) +class CBase { +/* ... */ + void CheckError(LibPrimesResult nResult) + { + if (m_pWrapper != nullptr) + m_pWrapper->CheckError(this, nResult); + } +/* ... */ +} +/* ... */ +inline void CWrapper::CheckError(CBase * pBaseClass, LibPrimesResult nResult) { - if (nResult != 0) - throw ELibPrimesException (nResult); + if (nResult != 0) { + std::string sErrorMessage; + if (pBaseClass != nullptr) { + GetLastError(pBaseClass, sErrorMessage); + } + throw ELibPrimesException(nResult, sErrorMessage); + } } ``` @@ -584,9 +626,9 @@ import LibPrimes def main(): libpath = '' # TODO add the location of the shared library binary here - wrapper = LibPrimes.LibPrimesWrapper(os.path.join(libpath, "LibPrimes")) + wrapper = LibPrimes.Wrapper(os.path.join(libpath, "LibPrimes")) - major, minor, micro = wrapper.GetLibraryVersion() + major, minor, micro = wrapper.GetVersion() print("LibPrimes version: {:d}.{:d}.{:d}".format(major, minor, micro)) if __name__ == "__main__": @@ -618,8 +660,7 @@ LibPrimes version: 1.0.0 ``` # 4.2.1. Debug the C++-DLL from a Python Host Application -This section explains a neat trick to debug a library that is used in a unrelated project, -even in a different, interpreted language: +This section explains a neat trick to debug a library that is used in a unrelated project, even in a different, interpreted language: In our specific setup, open the Visual Studio solution from [3. The Library's Implementation](#3-the-librarys-implementation), @@ -631,30 +672,32 @@ to the location of the `LibPrimes_Example.py` ![VSProperties](ressources/VSProperties.png) Set a breakpoint somewhere in your C++-library code -(e.g. in "void CLibPrimesFactorizationCalculator::Calculate()") and start debugging. +(e.g. in `void CFactorizationCalculator::Calculate()`) and start debugging. # 4.3. Pascal -The folder `Examples\Pascal` contains a project for the Free Pascal IDE [Lazarus](https://www.lazarus-ide.org/). +The folder `Examples/Pascal` contains a project for the Free Pascal IDE [Lazarus](https://www.lazarus-ide.org/). Open the project `LibPrimes_Example.lpi` in the IDE, adjust the library path in the `TestLibPrimes` procedure and build the application. ```pascal procedure TLibPrimes_Example.TestLibPrimes (); var - ALibPrimesWrapper: TLibPrimesWrapper; - AMajor, AMinor, AMicro: Cardinal; - ALibPath: string; + ALibPrimesWrapper: TLibPrimesWrapper; + AMajor, AMinor, AMicro: Cardinal; + AVersionString: string; + ALibPath: string; begin - writeln ('loading DLL'); - ALibPath := ''; // TODO add the location of the shared library binary here - ALibPrimesWrapper := TLibPrimesWrapper.Create (ALibPath + '/' + 'libprimes.dll'); - try - writeln ('loading DLL Done'); - ALibPrimesWrapper.GetLibraryVersion(AMajor, AMinor, AMicro); - writeln (Format('LibPrimes.version = %d.%d.%d', [AMajor, AMinor, AMicro])); - finally - FreeAndNil(ALibPrimesWrapper); - end; + writeln ('loading DLL'); + ALibPath := ''; // TODO add the location of the shared library binary here + ALibPrimesWrapper := TLibPrimesWrapper.Create (ALibPath + '/' + 'libprimes.'); // TODO add the + try + writeln ('loading DLL Done'); + ALibPrimesWrapper.GetVersion(AMajor, AMinor, AMicro); + AVersionString := Format('LibPrimes.version = %d.%d.%d', [AMajor, AMinor, AMicro]); + writeln(AVersionString); + finally + FreeAndNil(ALibPrimesWrapper); + end; end; ``` @@ -672,11 +715,10 @@ We found that a simple task using dynamic language bindings. In reality, it is more important to integrate a components functionality into _existing_, potentially large and complex code bases. -However, the integration of an ACT component into other code bases is _as simple_ as integrating it into -a new application. +However, the integration of an ACT component into other code bases is _as simple_ as integrating it into a new application. The only requirement is to include the specific language binding file -(`libprimes_dyanmic.hpp`, `LibPrimes.py`,`Unit_LibPrimes.pas`) into a project -and specifying the location of the components binary. +(`libprimes_dyanmic.hpp`, `LibPrimes.py`, `Unit_LibPrimes.pas`) into a project +and specifying the location of the component's binary. This concludes the section on using an ACT component via the autogenerated language bindings. @@ -684,7 +726,7 @@ This concludes the section on using an ACT component via the autogenerated langu # 5. Extending the Library with a Callback This section goes through the process of adding new functionality to an ACT component. We will first modify the IDL-file, secondly regenerate the interfaces and language bindings -and finally adapt one of the example applications use the new feature of the library. +and finally adapt one of the example applications to use the new feature of the library. The new functionality will be a callback that reports the progress during the (potentially) time consuming calculation method of the calculators. @@ -715,11 +757,11 @@ Thus, add a new `\<error>`: <error name="CALCULATIONABORTED" code="10" description="a calculation has been aborted" /> ``` -In the [semantic versioning scheme](https://semver.org/), which is advocated by ACT, adding a new function to a components class +In the [semantic versioning scheme](https://semver.org/) adding a new function to a components class requires a minor version update. Thus update the version in the IDL, too: ```xml <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime Numbers Interface" namespace="LibPrimes" copyright="Automatic Component Toolkit Developers" year="2018" basename="libprimes" + libraryname="Prime Numbers Interface" namespace="LibPrimes" copyright="Automatic Component Toolkit Developers" year="2019" basename="libprimes" version="1.1.0"> ``` @@ -731,23 +773,26 @@ Finally, recrate interfaces, wrapper and bindings code: act.exe libPrimes.xml ``` -A quick look at the `libprimes_types.h` and `libprimes_interfaces.hpp` reveals how the `ProgressCallback` +A quick look at the `libprimes_types.hpp` and `libprimes_interfaces.hpp` reveals how the `ProgressCallback` function type and their usage is declared: ```cpp -/************************************************************************************************************************* - Declaration of function pointers -**************************************************************************************************************************/ -typedef void(*LibPrimesProgressCallback)(LibPrimes_single, bool*); +/* + * ProgressCallback - Callback to report calculation progress and query whether it should be aborted + * + * @param[in] fProgressPercentage - How far has the calculation progressed? + * @param[out] pShouldAbort - Should the calculation be aborted? + */ + typedef void(*ProgressCallback)(LibPrimes_single, bool*); ``` ```cpp -class ILibPrimesCalculator : public virtual ILibPrimesBaseClass { +class ICalculator : public virtual IBase { public: /*...*/ /** * ICalculator::SetProgressCallback - Sets the progress callback function * @param[in] pProgressCallback - callback function */ -virtual void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) = 0; +virtual void SetProgressCallback(const LibPrimes::ProgressCallback pProgressCallback) = 0; /*...*/ } ``` @@ -755,25 +800,25 @@ virtual void SetProgressCallback (const LibPrimesProgressCallback pProgressCallb # 5.2 Library Reopen the Visual Studio solution from [3. The Library's Implementation](#3-the-librarys-implementation). You will not be able to successfully rebuild the solution, -since `CLibPrimesCalculator` does not define the `SetProgressCallback`-function. -To resolve this, add a protected member to `CLibPrimesCalculator` and define the public -`SetProgressCallbackFunction` +since `CCalculator` does not define the `SetProgressCallback`-function. +To resolve this, add a protected member to `CCalculator` and define the public +`SetProgressCallback`-function. #### libprimes_calculator.hpp ```cpp -class CLibPrimesCalculator : public virtual ILibPrimesCalculator { +class CCalculator : public virtual ICalculator { protected: /*...*/ - LibPrimesProgressCallback m_Callback; + ProgressCallback m_Callback; /*...*/ public: /*...*/ - void SetProgressCallback (const LibPrimesProgressCallback pProgressCallback); + void SetProgressCallback(const ProgressCallback pProgressCallback); /*...*/ } ``` #### libprimes_calculator.cpp ```cpp -void CLibPrimesCalculator::SetProgressCallback (const LibPrimesProgressCallback pProgressCallback) +void CCalculator::SetProgressCallback (const LibPrimes::ProgressCallback pProgressCallback) { m_Callback = pProgressCallback; } @@ -781,7 +826,7 @@ void CLibPrimesCalculator::SetProgressCallback (const LibPrimesProgressCallback We can use the callback in the calculation function for example like this: ```cpp -void CLibPrimesFactorizationCalculator::Calculate() +void CFactorizationCalculator::Calculate() { primeFactors.clear(); @@ -796,7 +841,7 @@ void CLibPrimesFactorizationCalculator::Calculate() } } - sLibPrimesPrimeFactor primeFactor; + sPrimeFactor primeFactor; primeFactor.m_Prime = i; primeFactor.m_Multiplicity = 0; while (nValue % i == 0) { @@ -819,15 +864,17 @@ Now, recompile the solution. # 5.3 Consumer The usage of the callback functionality from the client applications is straightforward, -as their respective language bindings have already been updated at the end of step. +as their respective language bindings have already been updated at the end of the previous step. ## 5.3.1 Cpp Dynamic Application with Callback Open the solution from [Section 4.1](#41-cpp-dynamic), and add a concrete implementation of the -"LibPrimesProgressCallback" function-type: +"ProgressCallback" function-type: ```cpp +#include <cmath> +/* ... */ void progressCallback(LibPrimes_single progress, bool* shouldAbort) { - std::cout << "Progress = " << round(progress * 100) << "%" << std::endl; + std::cout << "Progress = " << std::round(progress * 100) << "%" << std::endl; if (shouldAbort) { *shouldAbort = progress > 0.5; } @@ -852,7 +899,7 @@ LibPrimes.Version = 1.1.0 Progress = 0% Progress = 0% Progress = 67% -LibPrimes Error 10 +LibPrimes Error 10 (LibPrimes Error 10) ``` Error 10 (`CALCULATIONABORTED`) notifies us that a calculation has been aborted, as we expected. @@ -872,7 +919,7 @@ when it will called by the library, e.g. like this: ```python # ... factorization.SetValue(735) -cTypesCallback = LibPrimes.LibPrimesProgressCallback(progressCallback) +cTypesCallback = LibPrimes.ProgressCallback(progressCallback) factorization.SetProgressCallback(cTypesCallback) factorization.Calculate() # ... @@ -884,7 +931,7 @@ LibPrimes version: 1.1.0 Progress = 0% Progress = 0% Progress = 67% -LibPrimesException 10 +LibPrimesException 10: LibPrimes Error 10 ``` # 6. Enable journaling @@ -895,7 +942,8 @@ and enabled/disabled dynamically during the usage of the component. ## 6.1 Update the IDL file To add the journaling, simply add a `journalmethod` to the IDL file `libPrimes.xml`: ```xml -<global releasemethod="ReleaseInstance" journalmethod="SetJournal" versionmethod="GetLibraryVersion"> +<global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError" + journalmethod="SetJournal" > <!--...--> <method name="SetJournal" description="Handles Library Journaling"> <param name="FileName" type="string" pass="in" description="Journal FileName" /> @@ -905,7 +953,7 @@ To add the journaling, simply add a `journalmethod` to the IDL file `libPrimes.x Since a new function has been added, another minor version update is required. ```xml <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime Numbers Interface" namespace="LibPrimes" copyright="Automatic Component Toolkit Developers" year="2018" basename="libprimes" + libraryname="Prime Numbers Interface" namespace="LibPrimes" copyright="Automatic Component Toolkit Developers" year="2019" basename="libprimes" version="1.2.0"> ``` @@ -920,8 +968,9 @@ act.exe libPrimes.xml Check the updated `libprimes_interfacewrapper.cpp` and its autogenerated SetJournal method ```cpp -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_setjournal (const char * pFileName) +LibPrimesResult libprimes_setjournal(const char * pFileName) { + IBase* pIBaseClass = nullptr; try { if (pFileName == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); @@ -932,11 +981,14 @@ LIBPRIMES_DECLSPEC LibPrimesResult libprimes_setjournal (const char * pFileName) } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); } catch (...) { - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass); } } ``` @@ -945,38 +997,34 @@ in the wrapper itself._ This is how the journal is filled by other methods: ```cpp -LIBPRIMES_DECLSPEC LibPrimesResult libprimes_calculator_getvalue (LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) +LibPrimesResult libprimes_calculator_getvalue(LibPrimes_Calculator pCalculator, LibPrimes_uint64 * pValue) { + IBase* pIBaseClass = (IBase *)pCalculator; PLibPrimesInterfaceJournalEntry pJournalEntry; try { if (m_GlobalJournal.get() != nullptr) { pJournalEntry = m_GlobalJournal->beginClassMethod(pCalculator, "Calculator", "GetValue"); } - if (pValue == nullptr) throw ELibPrimesInterfaceException (LIBPRIMES_ERROR_INVALIDPARAM); - ILibPrimesBaseClass* pIBaseClass = (ILibPrimesBaseClass *)pCalculator; - ILibPrimesCalculator* pICalculator = dynamic_cast<ILibPrimesCalculator*>(pIBaseClass); + ICalculator* pICalculator = dynamic_cast<ICalculator*>(pIBaseClass); if (!pICalculator) throw ELibPrimesInterfaceException(LIBPRIMES_ERROR_INVALIDCAST); - *pValue = pICalculator->GetValue(); - if (pJournalEntry.get() != nullptr) { - pJournalEntry->addUInt64Result ("Value", *pValue); + pJournalEntry->addUInt64Result("Value", *pValue); pJournalEntry->writeSuccess(); } return LIBPRIMES_SUCCESS; } - catch (ELibPrimesInterfaceException & E) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(E.getErrorCode()); - return E.getErrorCode(); + catch (ELibPrimesInterfaceException & Exception) { + return handleLibPrimesException(pIBaseClass, Exception, pJournalEntry.get()); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException, pJournalEntry.get()); } catch (...) { - if (pJournalEntry.get() != nullptr) - pJournalEntry->writeError(LIBPRIMES_ERROR_GENERICEXCEPTION); - return LIBPRIMES_ERROR_GENERICEXCEPTION; + return handleUnhandledException(pIBaseClass, pJournalEntry.get()); } } ``` @@ -1003,12 +1051,12 @@ int main() { try { - std::string libpath = ""; // TODO: put the location of the LibPrimes-library file here. - auto wrapper = LibPrimes::CLibPrimesWrapper::loadLibrary(libpath + "/libprimes"); + std::string libpath = (""); // TODO: put the location of the LibPrimes-library file here. + auto wrapper = LibPrimes::CWrapper::loadLibrary(libpath + "/libprimes."); // TODO: add correct suffix of the library wrapper->SetJournal("journal_cppdynamic.xml"); - - unsigned int nMajor, nMinor, nMicro; - wrapper->GetLibraryVersion(nMajor, nMinor, nMicro); + LibPrimes_uint32 nMajor, nMinor, nMicro; + std::string sPreReleaseInfo, sBuildInfo; + wrapper->GetLibraryVersion(nMajor, nMinor, nMicro, sPreReleaseInfo, sBuildInfo); /*..*/ } /*..*/ @@ -1020,32 +1068,37 @@ that go through the interface: ```xml <?xml version="1.0" encoding="UTF-8" ?> <journal library="LibPrimes" version="1.2.0" xmlns="http://schemas.autodesk.com/components/LibPrimes/1.2.0"> - <entry method="GetLibraryVersion" timestamp="1" duration="0"> - <result name="Major" type="uint32" value="1" /> - <result name="Minor" type="uint32" value="2" /> - <result name="Micro" type="uint32" value="0" /> - </entry> - - <entry method="CreateFactorizationCalculator" timestamp="1" duration="0"> - <result name="Instance" type="handle" value="0000000003d821b8" /> - </entry> - - <entry class="Calculator" method="SetValue" timestamp="1" duration="0"> - <instance handle="0000000003d821b8" /> - <parameter name="Value" type="uint64" value="735" /> - </entry> - - <entry class="Calculator" method="SetProgressCallback" timestamp="1" duration="0"> - <instance handle="0000000003d821b8" /> - </entry> - - <entry class="Calculator" method="Calculate" errorcode="9" timestamp="1" duration="0"> - <instance handle="0000000003d821b8" /> - </entry> - - <entry method="ReleaseInstance" timestamp="2" duration="0"> - <parameter name="Instance" type="handle" value="0000000003d821b8" /> - </entry> + <entry method="GetVersion" timestamp="0" duration="0"> + <result name="Major" type="uint32" value="1" /> + <result name="Minor" type="uint32" value="2" /> + <result name="Micro" type="uint32" value="0" /> + </entry> + <entry method="CreateFactorizationCalculator" timestamp="1" duration="0"> + <result name="Instance" type="class" value="000001d259663858" /> + </entry> + <entry class="Calculator" method="SetValue" timestamp="1" duration="0"> + <instance handle="000001d259663858" /> + <parameter name="Value" type="uint64" value="735" /> + </entry> + <entry class="Calculator" method="SetProgressCallback" timestamp="1" duration="0"> + <instance handle="000001d259663858" /> + </entry> + <entry class="Calculator" method="Calculate" errorcode="10" timestamp="1" duration="2"> + <instance handle="000001d259663858" /> + </entry> + <entry method="GetLastError" timestamp="1115" duration="0"> + <parameter name="Instance" type="class" value="000001d259663858" /> + <result name="ErrorMessage" type="string" value="LibPrimes Error 10" /> + <result name="HasError" type="bool" value="1" /> + </entry> + <entry method="GetLastError" timestamp="1115" duration="0"> + <parameter name="Instance" type="class" value="000001d259663858" /> + <result name="ErrorMessage" type="string" value="LibPrimes Error 10" /> + <result name="HasError" type="bool" value="1" /> + </entry> + <entry method="ReleaseInstance" timestamp="1116" duration="0"> + <parameter name="Instance" type="class" value="000001d259663858" /> + </entry> </journal> ``` @@ -1056,16 +1109,15 @@ def main(): libpath = '' # TODO add the location of the shared library binary here wrapper = LibPrimes.LibPrimesWrapper(os.path.join(libpath, "libprimes")) wrapper.SetJournal('journal_python.xml') - - major, minor, micro = wrapper.GetLibraryVersion() - print("LibPrimes version: {:d}.{:d}.{:d}".format(major, minor, micro)) + major, minor, micro = wrapper.GetVersion() + print("LibPrimes version: {:d}.{:d}.{:d}".format(major, minor, micro), end="") # ... ``` The generated xml-journal is similar to the one shown above. # 7. Conclusion -This tutorial has walked through a basic development cycle using ACT -and conveyed the power of ACT to simplify and automate the development of components. +This tutorial has walked you through a basic development cycle using ACT +and conveyed the power of ACT to simplify and automate the development of software components. Moreover, it has shown how easy ACT components can be integrated in standalone or existing code bases with ease. @@ -1073,4 +1125,4 @@ Other important aspects of software componentization, like packaging and distrib source code control, stable interfaces, versioning, releases, ... can also be supported and simplified by ACT. -Tutorials or articles about these topics will follow. \ No newline at end of file +Tutorials or articles about these topics will follow. diff --git a/Examples/Primes/libPrimes.xml b/Examples/Primes/libPrimes.xml index 373ecc42..e334856b 100644 --- a/Examples/Primes/libPrimes.xml +++ b/Examples/Primes/libPrimes.xml @@ -1,16 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.2.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> + <binding language="CSharp" indentation="tabs" /> </bindings> <implementations> <implementation language="Cpp" indentation="tabs"/> @@ -34,24 +35,24 @@ <member name="Prime" type="uint64" /> <member name="Multiplicity" type="uint32" /> </struct> - + <functiontype name="ProgressCallback" description="Callback to report calculation progress and query whether it should be aborted"> <param name="ProgressPercentage" type="single" pass="in" description="How far has the calculation progressed?"/> <param name="ShouldAbort" type="bool" pass="out" description="Should the calculation be aborted?"/> </functiontype> + + <class name="Base"> + </class> - <class name="Calculator"> + <class name="Calculator" parent="Base"> <method name="GetValue" description="Returns the current value of this Calculator"> <param name="Value" type="uint64" pass="return" description="The current value of this Calculator" /> </method> - <method name="SetValue" description="Sets the value to be factorized"> <param name="Value" type="uint64" pass="in" description="The value to be factorized" /> </method> - <method name="Calculate" description="Performs the specific calculation of this Calculator"> </method> - <method name="SetProgressCallback" description="Sets the progress callback function"> <param name="ProgressCallback" type="functiontype" class="ProgressCallback" pass="in" description="The progress callback" /> </method> @@ -68,28 +69,31 @@ <param name="Primes" type="basicarray" class="uint64" pass="out" description="The primes lower or equal to the sieve's value" /> </method> </class> - - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion" journalmethod="SetJournal"> - <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> - </method> - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> - </method> + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError" + journalmethod="SetJournal" > + <method name="GetVersion" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> + </method> + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> + <method name="ReleaseInstance" description="Releases the memory of an Instance"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + </method> <method name="CreateFactorizationCalculator" description="Creates a new FactorizationCalculator instance"> - <param name="Instance" type="handle" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> + <param name="Instance" type="class" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> </method> - <method name="CreateSieveCalculator" description="Creates a new SieveCalculator instance"> - <param name="Instance" type="handle" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> + <param name="Instance" type="class" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> </method> - <method name="SetJournal" description="Handles Library Journaling"> <param name="FileName" type="string" pass="in" description="Journal FileName" /> </method> </global> -</component> \ No newline at end of file +</component> diff --git a/Examples/Primes/ressources/310/libPrimes.xml b/Examples/Primes/ressources/310/libPrimes.xml index c0d12208..259876c8 100644 --- a/Examples/Primes/ressources/310/libPrimes.xml +++ b/Examples/Primes/ressources/310/libPrimes.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.0.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> </bindings> <implementations> @@ -28,15 +28,22 @@ <error name="INCOMPATIBLEBINARYVERSION" code="8" description="the version of the binary interface does not match the bindings interface" /> </errors> - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion"> + <class name="Base"> + </class> + + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError"> + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> </method> - - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> + <method name="GetVersion" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> </method> </global> -</component> \ No newline at end of file +</component> diff --git a/Examples/Primes/ressources/315/libPrimes.xml b/Examples/Primes/ressources/315/libPrimes.xml index c9fde167..d93262ea 100644 --- a/Examples/Primes/ressources/315/libPrimes.xml +++ b/Examples/Primes/ressources/315/libPrimes.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.0.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> </bindings> <implementations> @@ -33,16 +33,17 @@ <member name="Prime" type="uint64" /> <member name="Multiplicity" type="uint32" /> </struct> + + <class name="Base"> + </class> - <class name="Calculator"> + <class name="Calculator" parent="Base"> <method name="GetValue" description="Returns the current value of this Calculator"> <param name="Value" type="uint64" pass="return" description="The current value of this Calculator" /> </method> - <method name="SetValue" description="Sets the value to be factorized"> <param name="Value" type="uint64" pass="in" description="The value to be factorized" /> </method> - <method name="Calculate" description="Performs the specific calculation of this Calculator"> </method> </class> @@ -58,24 +59,26 @@ <param name="Primes" type="basicarray" class="uint64" pass="out" description="The primes lower or equal to the sieve's value" /> </method> </class> - - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion"> + + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError"> + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> </method> - - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> + <method name="GetVersion" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> </method> - <method name="CreateFactorizationCalculator" description="Creates a new FactorizationCalculator instance"> - <param name="Instance" type="handle" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> + <param name="Instance" type="class" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> </method> - <method name="CreateSieveCalculator" description="Creates a new SieveCalculator instance"> - <param name="Instance" type="handle" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> + <param name="Instance" type="class" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> </method> </global> -</component> \ No newline at end of file +</component> diff --git a/Examples/Primes/ressources/510/libPrimes.xml b/Examples/Primes/ressources/510/libPrimes.xml index 4a0b6699..0a22d39f 100644 --- a/Examples/Primes/ressources/510/libPrimes.xml +++ b/Examples/Primes/ressources/510/libPrimes.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.1.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> </bindings> <implementations> @@ -34,24 +34,24 @@ <member name="Prime" type="uint64" /> <member name="Multiplicity" type="uint32" /> </struct> - + <functiontype name="ProgressCallback" description="Callback to report calculation progress and query whether it should be aborted"> <param name="ProgressPercentage" type="single" pass="in" description="How far has the calculation progressed?"/> <param name="ShouldAbort" type="bool" pass="out" description="Should the calculation be aborted?"/> </functiontype> + + <class name="Base"> + </class> - <class name="Calculator"> + <class name="Calculator" parent="Base"> <method name="GetValue" description="Returns the current value of this Calculator"> <param name="Value" type="uint64" pass="return" description="The current value of this Calculator" /> </method> - <method name="SetValue" description="Sets the value to be factorized"> <param name="Value" type="uint64" pass="in" description="The value to be factorized" /> </method> - <method name="Calculate" description="Performs the specific calculation of this Calculator"> </method> - <method name="SetProgressCallback" description="Sets the progress callback function"> <param name="ProgressCallback" type="functiontype" class="ProgressCallback" pass="in" description="The progress callback" /> </method> @@ -68,24 +68,26 @@ <param name="Primes" type="basicarray" class="uint64" pass="out" description="The primes lower or equal to the sieve's value" /> </method> </class> - - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion"> + + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError"> + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> </method> - - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> + <method name="GetVersion" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> </method> - <method name="CreateFactorizationCalculator" description="Creates a new FactorizationCalculator instance"> - <param name="Instance" type="handle" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> + <param name="Instance" type="class" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> </method> - <method name="CreateSieveCalculator" description="Creates a new SieveCalculator instance"> - <param name="Instance" type="handle" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> + <param name="Instance" type="class" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> </method> </global> -</component> \ No newline at end of file +</component> diff --git a/Examples/Primes/ressources/610/libPrimes.xml b/Examples/Primes/ressources/610/libPrimes.xml index 373ecc42..7c7e899e 100644 --- a/Examples/Primes/ressources/610/libPrimes.xml +++ b/Examples/Primes/ressources/610/libPrimes.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <component xmlns="http://schemas.autodesk.com/netfabb/automaticcomponenttoolkit/2018" - libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2018" basename="libprimes" + libraryname="Prime Numbers Library" namespace="LibPrimes" copyright="PrimeDevelopers" year="2019" basename="libprimes" version="1.2.0"> <license> <line value="All rights reserved." /> </license> <bindings> - <binding language="Cpp" indentation="tabs" /> <binding language="CppDynamic" indentation="tabs" /> - <binding language="Pascal" indentation="4spaces" /> + <binding language="Cpp" indentation="tabs" /> + <binding language="Pascal" indentation="2spaces" /> <binding language="Python" indentation="tabs" /> </bindings> <implementations> @@ -34,24 +34,24 @@ <member name="Prime" type="uint64" /> <member name="Multiplicity" type="uint32" /> </struct> - + <functiontype name="ProgressCallback" description="Callback to report calculation progress and query whether it should be aborted"> <param name="ProgressPercentage" type="single" pass="in" description="How far has the calculation progressed?"/> <param name="ShouldAbort" type="bool" pass="out" description="Should the calculation be aborted?"/> </functiontype> + + <class name="Base"> + </class> - <class name="Calculator"> + <class name="Calculator" parent="Base"> <method name="GetValue" description="Returns the current value of this Calculator"> <param name="Value" type="uint64" pass="return" description="The current value of this Calculator" /> </method> - <method name="SetValue" description="Sets the value to be factorized"> <param name="Value" type="uint64" pass="in" description="The value to be factorized" /> </method> - <method name="Calculate" description="Performs the specific calculation of this Calculator"> </method> - <method name="SetProgressCallback" description="Sets the progress callback function"> <param name="ProgressCallback" type="functiontype" class="ProgressCallback" pass="in" description="The progress callback" /> </method> @@ -68,28 +68,30 @@ <param name="Primes" type="basicarray" class="uint64" pass="out" description="The primes lower or equal to the sieve's value" /> </method> </class> - - <global releasemethod="ReleaseInstance" versionmethod="GetLibraryVersion" journalmethod="SetJournal"> + + <global baseclassname="Base" releasemethod="ReleaseInstance" versionmethod="GetVersion" errormethod="GetLastError" + journalmethod="SetJournal" > + <method name="GetLastError" description="Returns the last error recorded on this object"> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error" /> + <param name="HasError" type="bool" pass="return" description="Is there a last error to query" /> + </method> <method name="ReleaseInstance" description="Releases the memory of an Instance"> - <param name="Instance" type="handle" class="BaseClass" pass="in" description="Instance Handle" /> + <param name="Instance" type="class" class="Base" pass="in" description="Instance Handle" /> </method> - - <method name="GetLibraryVersion" description = "retrieves the current version of the library."> - <param name="Major" type="uint32" pass="out" description="returns the major version of the library" /> - <param name="Minor" type="uint32" pass="out" description="returns the minor version of the library" /> - <param name="Micro" type="uint32" pass="out" description="returns the micro version of the library" /> + <method name="GetLibrary" description = "retrieves the binary version of this library."> + <param name="Major" type="uint32" pass="out" description="returns the major version of this library" /> + <param name="Minor" type="uint32" pass="out" description="returns the minor version of this library" /> + <param name="Micro" type="uint32" pass="out" description="returns the micro version of this library" /> </method> - <method name="CreateFactorizationCalculator" description="Creates a new FactorizationCalculator instance"> - <param name="Instance" type="handle" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> + <param name="Instance" type="class" class="FactorizationCalculator" pass="return" description="New FactorizationCalculator instance" /> </method> - <method name="CreateSieveCalculator" description="Creates a new SieveCalculator instance"> - <param name="Instance" type="handle" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> + <param name="Instance" type="class" class="SieveCalculator" pass="return" description="New SieveCalculator instance" /> </method> - <method name="SetJournal" description="Handles Library Journaling"> <param name="FileName" type="string" pass="in" description="Journal FileName" /> </method> </global> -</component> \ No newline at end of file +</component> diff --git a/README.md b/README.md index c0f883b3..df0e10c6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Automatic Component Toolkit -[![Build Status](https://travis-ci.org/Autodesk/AutomaticComponentToolkit.svg?branch=develop)](https://travis-ci.org/Autodesk/AutomaticComponentToolkit) +[![Build Status](https://travis-ci.org/Autodesk/AutomaticComponentToolkit.svg?branch=master)](https://travis-ci.org/Autodesk/AutomaticComponentToolkit) The Automatic Component Toolkit (ACT) is a code generator that takes an instance of an [Interface Description Language](#interface-description-language-idl) file and generates a [thin C89-API](#thin-c89-api), [implementation stubs](#implementation-stubs) and [language bindings](#language-bindings) of your desired software component. @@ -46,22 +46,24 @@ Contributions are welcome and we are looking for people that can improve existin ACT supports generation of bindings or implementation stubs for C++, C, Pascal, Golang, NodeJS and Python3. However, not all features of the IDL are yet supported by the individual binding or implementation language: #### Feature Matrix: Bindings -| Binding | Status | Operating Systems | class | scalar type | struct | enumeration | string | basicarray | structarray | Callbacks | -|:-----------:|:----------------------------------------------------------:|:-----------------:|:---------:|:-------------:|:-------------:|:-------------:|:-------------:|:----------:|:-----------:|:---------:| -| C++ | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| C++ Dynamic | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| C | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| C Dynamic | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| Pascal | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| Python3 | ![](Documentation/images/Tick.png) complete (but unstable) | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | -| Golang | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | ? | ? | ? | ? | ? | - | -| NodeJS | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | ? | ? | ? | ? | ? | - | +| Binding | Status | Operating Systems | class | scalar type | struct | enumeration | string | basicarray | structarray | Callbacks | Error Message Propagation | +|:---------------:|:----------------------------------------------------------:|:-----------------:|:---------:|:-------------:|:-------------:|:-------------:|:-------------:|:----------:|:-----------:|:---------:|:---------:| +| C++ | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| C++ Dynamic | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| C | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| C Dynamic | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| Pascal | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| Python3 | ![](Documentation/images/Tick.png) complete (but not very pythonic) | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | +| Golang | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | ? | ? | ? | ? | ? | - | - | +| NodeJS | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | ? | ? | - | + | +| C# | ![](Documentation/images/O.png) experimental | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | - | - | - | + | +| PHP | ![](Documentation/images/X.png) not implemented | Win, Linux, MacOS | - | - | - | - | - | - | - | - | - | #### Feature Matrix: Implementation Stubs -| Implementation | Status | Operating Systems | class | scalar type | struct | enumeration | string | basicarray | structarray | Callbacks | Journaling | -|:--------------:|:-----------------------------------------------------:|:-----------------:|:---------:|:-------------:|:-------------:|:-------------:|:-------------:|:----------:|:-----------:|:---------:|:----------:| -| C++ | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | -| Pascal | ![](Documentation/images/O.png) complete (but unstable) | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | | +| Implementation | Status | Operating Systems | class | scalar type | struct | enumeration | string | basicarray | structarray | Callbacks | Journaling | Error Message Propagation | +|:--------------:|:-----------------------------------------------------:|:-----------------:|:---------:|:-------------:|:-------------:|:-------------:|:-------------:|:----------:|:-----------:|:---------:|:----------:|:---------:| +| C++ | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | + | +| Pascal | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | - | + | ## Example diff --git a/Source/ACT.xsd b/Source/ACT.xsd index 5e18ae9b..f718cb8d 100644 --- a/Source/ACT.xsd +++ b/Source/ACT.xsd @@ -153,6 +153,15 @@ <xs:attribute name="versionmethod" type="ST_Name" use="required"> <xs:annotation><xs:documentation xml:lang="en">The <versionmethod> must match a method with the same name and the correct signature.</xs:documentation></xs:annotation> </xs:attribute> + <xs:attribute name="errormethod" type="ST_Name" use="required"> + <xs:annotation><xs:documentation xml:lang="en">The <errormethod> must match a method with the same name and the correct signature.</xs:documentation></xs:annotation> + </xs:attribute> + <xs:attribute name="prereleasemethod" type="ST_Name" use="optional"> + <xs:annotation><xs:documentation xml:lang="en">The <prereleasemethod> must match a method with the same name and the correct signature.</xs:documentation></xs:annotation> + </xs:attribute> + <xs:attribute name="buildinfomethod" type="ST_Name" use="optional"> + <xs:annotation><xs:documentation xml:lang="en">The <buildinfomethod> must match a method with the same name and the correct signature.</xs:documentation></xs:annotation> + </xs:attribute> <xs:attribute name="journalmethod" type="ST_Name" use="optional"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> @@ -195,6 +204,7 @@ <xs:enumeration value="Fortran"/> <xs:enumeration value="Node"/> <xs:enumeration value="Go"/> + <xs:enumeration value="CSharp"/> </xs:restriction> </xs:simpleType> @@ -239,7 +249,7 @@ <xs:simpleType name="ST_Version"> <xs:restriction base="xs:string"> - <xs:pattern value="[0-9]*\.[0-9]*\.[0-9]*"/> + <xs:pattern value="([0-9]+\.[0-9]+\.[0-9])(\-[a-zA-Z0-9.\-]+)?(\+[a-zA-Z0-9.\-]+)?"/> </xs:restriction> </xs:simpleType> @@ -256,6 +266,7 @@ <xs:enumeration value="int64"/> <xs:enumeration value="single"/> <xs:enumeration value="double"/> + <xs:enumeration value="pointer"/> <xs:enumeration value="struct"/> <xs:enumeration value="enum"/> <xs:enumeration value="basicarray"/> @@ -263,6 +274,7 @@ <xs:enumeration value="structarray"/> <xs:enumeration value="string"/> <xs:enumeration value="handle"/> + <xs:enumeration value="class"/> <xs:enumeration value="functiontype"/> </xs:restriction> </xs:simpleType> @@ -280,6 +292,7 @@ <xs:enumeration value="int64"/> <xs:enumeration value="single"/> <xs:enumeration value="double"/> + <xs:enumeration value="pointer"/> </xs:restriction> </xs:simpleType> @@ -326,7 +339,6 @@ </xs:restriction> </xs:simpleType> - <!-- Elements --> <xs:element name="component" type="CT_Component"/> <xs:element name="license" type="CT_License"/> diff --git a/Source/automaticcomponenttoolkit.go b/Source/automaticcomponenttoolkit.go index db2e394e..fdb9e428 100644 --- a/Source/automaticcomponenttoolkit.go +++ b/Source/automaticcomponenttoolkit.go @@ -34,53 +34,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package main import ( + "encoding/xml" "fmt" - "path" - "log" "io/ioutil" + "log" "os" - "encoding/xml" + "path" ) const ( eACTModeGenerate = 0 - eACTModeDiff = 1 + eACTModeDiff = 1 ) func readComponentDefinition(FileName string, ACTVersion string) (ComponentDefinition, error) { var component ComponentDefinition - file, err := os.Open(FileName); - if (err != nil) { + file, err := os.Open(FileName) + if err != nil { return component, err } - bytes, err := ioutil.ReadAll (file); - if (err != nil) { + bytes, err := ioutil.ReadAll(file) + if err != nil { return component, err } - + component.ACTVersion = ACTVersion err = xml.Unmarshal(bytes, &component) - if (err != nil) { + if err != nil { return component, err } + + component.Normalize() + return component, nil } -func main () { - ACTVersion := "1.4.0" - fmt.Fprintln(os.Stdout, "Automatic Component Toolkit v" + ACTVersion) - if (len (os.Args) < 2) { - log.Fatal ("Please run with the Interface Description XML as command line parameter."); - log.Fatal ("To specify a path for the generated source code use the optional flag \"-o ABSOLUTE_PATH_TO_OUTPUT_FOLDER\""); - log.Fatal ("To create a diff between two versions of an Interface Description XML use the optional flag \"-d OTHER_IDL_FILE\""); +func main() { + ACTVersion := "1.5.0" + fmt.Fprintln(os.Stdout, "Automatic Component Toolkit v"+ACTVersion) + if len(os.Args) < 2 { + log.Fatal("Please run with the Interface Description XML as command line parameter.") + log.Fatal("To specify a path for the generated source code use the optional flag \"-o ABSOLUTE_PATH_TO_OUTPUT_FOLDER\"") + log.Fatal("To create a diff between two versions of an Interface Description XML use the optional flag \"-d OTHER_IDL_FILE\"") } if os.Args[1] == "-v" { fmt.Fprintln(os.Stdout, "Version: "+ACTVersion) return } - log.Printf ("---------------------------------------\n"); + log.Printf("---------------------------------------\n") mode := eACTModeGenerate outfolderBase, err := os.Getwd() @@ -88,7 +91,7 @@ func main () { log.Fatal(err) } diffFile := "" - if (len (os.Args) >= 4) { + if len(os.Args) >= 4 { if os.Args[2] == "-o" { outfolderBase = os.Args[3] } @@ -98,333 +101,382 @@ func main () { mode = eACTModeDiff } } - if (mode == eACTModeGenerate) { + if mode == eACTModeGenerate { log.Printf("Output directory: " + outfolderBase) } - - log.Printf ("Loading Component Description File" ); + + log.Printf("Loading Component Description File") component, err := readComponentDefinition(os.Args[1], ACTVersion) - if (err != nil) { - log.Fatal (err); + if err != nil { + log.Fatal(err) } - - log.Printf ("Checking Component Description", ); - err = CheckComponentDefinition (component); - if (err != nil) { - log.Fatal (err); + + log.Printf("Checking Component Description") + err = CheckComponentDefinition(component) + if err != nil { + log.Fatal(err) } - if (mode == eACTModeDiff) { - log.Printf ("Loading Component Description File to compare to" ); + if mode == eACTModeDiff { + log.Printf("Loading Component Description File to compare to") componentB, err := readComponentDefinition(diffFile, ACTVersion) - if (err != nil) { - log.Fatal (err); + if err != nil { + log.Fatal(err) } - log.Printf ("Checking Component Description B", ); - err = CheckComponentDefinition (componentB); - if (err != nil) { - log.Fatal (err); + log.Printf("Checking Component Description B") + err = CheckComponentDefinition(componentB) + if err != nil { + log.Fatal(err) } diff, err := DiffComponentDefinitions(component, componentB) - if (err != nil) { - log.Fatal (err); + if err != nil { + log.Fatal(err) } output, err := xml.MarshalIndent(diff, "", "\t") - if (err != nil) { - log.Fatal (err); + if err != nil { + log.Fatal(err) } writer, err := os.Create("diff.xml") if err != nil { - log.Fatal (err); + log.Fatal(err) } os.Stdout.Write(output) writer.Write(output) - + return } - - - outputFolder := path.Join(outfolderBase, component.NameSpace + "_component"); + // This needs to go into a "preparation function" + // baseClass, err := setupBaseClassDefinition(true) + // if (err != nil) { + // log.Fatal (err); + // } + // component.Classes = append([]ComponentDefinitionClass{baseClass}, component.Classes...) + // for i := 0; i < len(component.Classes); i++ { + // if (!component.Classes[i].isBaseClass()) { + // if (component.Classes[i].ParentClass == "") { + // component.Classes[i].ParentClass = "BaseClass"; + // } + // } + // } + + outputFolder := path.Join(outfolderBase, component.NameSpace+"_component") outputFolderBindings := path.Join(outputFolder, "Bindings") outputFolderExamples := path.Join(outputFolder, "Examples") outputFolderImplementations := path.Join(outputFolder, "Implementations") - - err = os.MkdirAll(outputFolder, os.ModePerm); - if (err != nil) { - log.Fatal (err); - } + err = os.MkdirAll(outputFolder, os.ModePerm) + if err != nil { + log.Fatal(err) + } - licenseFileName := path.Join(outputFolder, "license.txt"); + licenseFileName := path.Join(outputFolder, "license.txt") log.Printf("Creating \"%s\"", licenseFileName) - licenseFile, err := CreateLanguageFile (licenseFileName, "") + licenseFile, err := CreateLanguageFile(licenseFileName, "") if err != nil { - log.Fatal (err); + log.Fatal(err) } - licenseFile.WritePlainLicenseHeader(component, "", false); + licenseFile.WritePlainLicenseHeader(component, "", false) - if (len(component.BindingList.Bindings) > 0) { - err = os.MkdirAll(outputFolderBindings, os.ModePerm); - if (err != nil) { - log.Fatal (err); + if len(component.BindingList.Bindings) > 0 { + err = os.MkdirAll(outputFolderBindings, os.ModePerm) + if err != nil { + log.Fatal(err) } } for bindingindex := 0; bindingindex < len(component.BindingList.Bindings); bindingindex++ { - binding := component.BindingList.Bindings[bindingindex]; + binding := component.BindingList.Bindings[bindingindex] indentString := getIndentationString(binding.Indentation) - log.Printf ("Exporting Interface Binding for Languge \"%s\"", binding.Language); - - switch (binding.Language) { - case "C": { - outputFolderBindingC := outputFolderBindings + "/C"; + log.Printf("Exporting Interface Binding for Languge \"%s\"", binding.Language) - err = os.MkdirAll(outputFolderBindingC, os.ModePerm); - if (err != nil) { - log.Fatal (err); + switch binding.Language { + case "C": + { + outputFolderBindingC := outputFolderBindings + "/C" + + err = os.MkdirAll(outputFolderBindingC, os.ModePerm) + if err != nil { + log.Fatal(err) } - + err = BuildBindingC(component, outputFolderBindingC) - if (err != nil) { - log.Fatal (err); + if err != nil { + log.Fatal(err) } } - case "CDynamic": { - outputFolderBindingCDynamic := outputFolderBindings + "/CDynamic"; + case "CDynamic": + { + outputFolderBindingCDynamic := outputFolderBindings + "/CDynamic" - err = os.MkdirAll(outputFolderBindingCDynamic, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderBindingCDynamic, os.ModePerm) + if err != nil { + log.Fatal(err) } - - CTypesHeaderName := path.Join(outputFolderBindingCDynamic, component.BaseName + "_types.h"); - err = CreateCTypesHeader (component, CTypesHeaderName); - if (err != nil) { - log.Fatal (err); + + CTypesHeaderName := path.Join(outputFolderBindingCDynamic, component.BaseName+"_types.h") + err = CreateCTypesHeader(component, CTypesHeaderName) + if err != nil { + log.Fatal(err) } - - err = BuildBindingCDynamic(component, outputFolderBindingCDynamic, indentString); - if (err != nil) { - log.Fatal (err); + + err = BuildBindingCExplicit(component, outputFolderBindingCDynamic, indentString) + if err != nil { + log.Fatal(err) } } - case "CppDynamic": { - outputFolderBindingCppDynamic := outputFolderBindings + "/CppDynamic"; - err = os.MkdirAll(outputFolderBindingCppDynamic, os.ModePerm); - if (err != nil) { - log.Fatal (err); + case "CppDynamic": + { + outputFolderBindingCppDynamic := outputFolderBindings + "/CppDynamic" + err = os.MkdirAll(outputFolderBindingCppDynamic, os.ModePerm) + if err != nil { + log.Fatal(err) } - outputFolderExampleCppDynamic := outputFolderExamples + "/CppDynamic"; - err = os.MkdirAll(outputFolderExampleCppDynamic, os.ModePerm); - if (err != nil) { - log.Fatal (err); + outputFolderExampleCppDynamic := outputFolderExamples + "/CppDynamic" + err = os.MkdirAll(outputFolderExampleCppDynamic, os.ModePerm) + if err != nil { + log.Fatal(err) } - CTypesHeaderName := path.Join(outputFolderBindingCppDynamic, component.BaseName + "_types.h"); - err = CreateCTypesHeader (component, CTypesHeaderName); - if (err != nil) { - log.Fatal (err); + CPPTypesHeaderName := path.Join(outputFolderBindingCppDynamic, component.BaseName+"_types.hpp") + err = CreateCPPTypesHeader(component, CPPTypesHeaderName) + if err != nil { + log.Fatal(err) } - - err = BuildBindingCppDynamic(component, outputFolderBindingCppDynamic, outputFolderExampleCppDynamic, indentString); - if (err != nil) { - log.Fatal (err); + + CPPABIHeaderName := path.Join(outputFolderBindingCppDynamic, component.BaseName+"_abi.hpp") + err = CreateCPPAbiHeader(component, CPPABIHeaderName) + if err != nil { + log.Fatal(err) } - } - case "Cpp": { - outputFolderBindingCpp := outputFolderBindings + "/Cpp"; - err = os.MkdirAll(outputFolderBindingCpp, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = BuildBindingCppExplicit(component, outputFolderBindingCppDynamic, outputFolderExampleCppDynamic, + indentString, binding.ClassIdentifier) + if err != nil { + log.Fatal(err) } + } - outputFolderExampleCPP := outputFolderExamples + "/CPP"; - err = os.MkdirAll(outputFolderExampleCPP, os.ModePerm); - if (err != nil) { - log.Fatal (err); + case "Cpp": + { + outputFolderBindingCppImplicit := outputFolderBindings + "/Cpp" + err = os.MkdirAll(outputFolderBindingCppImplicit, os.ModePerm) + if err != nil { + log.Fatal(err) + } + outputFolderExampleCppImplicit := outputFolderExamples + "/Cpp" + err = os.MkdirAll(outputFolderExampleCppImplicit, os.ModePerm) + if err != nil { + log.Fatal(err) } - CTypesHeaderName := path.Join(outputFolderBindingCpp, component.BaseName + "_types.h"); - err = CreateCTypesHeader (component, CTypesHeaderName); - if (err != nil) { - log.Fatal (err); + CPPTypesHeaderName := path.Join(outputFolderBindingCppImplicit, component.BaseName+"_types.hpp") + err = CreateCPPTypesHeader(component, CPPTypesHeaderName) + if err != nil { + log.Fatal(err) } - - CHeaderName := path.Join(outputFolderBindingCpp, component.BaseName + ".h"); - err = CreateCHeader (component, CHeaderName); - if (err != nil) { - log.Fatal (err); + + CPPABIHeaderName := path.Join(outputFolderBindingCppImplicit, component.BaseName+"_abi.hpp") + err = CreateCPPAbiHeader(component, CPPABIHeaderName) + if err != nil { + log.Fatal(err) } - - err = BuildBindingCPP(component, outputFolderBindingCpp, outputFolderExampleCPP, indentString); - if (err != nil) { - log.Fatal (err); + + err = BuildBindingCppImplicit(component, outputFolderBindingCppImplicit, outputFolderExampleCppImplicit, + indentString, binding.ClassIdentifier) + if err != nil { + log.Fatal(err) } } - case "Go": { - outputFolderBindingGo := outputFolderBindings + "/Go"; + case "Go": + { + outputFolderBindingGo := outputFolderBindings + "/Go" - err = os.MkdirAll(outputFolderBindingGo, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderBindingGo, os.ModePerm) + if err != nil { + log.Fatal(err) } - err := BuildBindingGo(component, outputFolderBindingGo); - if (err != nil) { - log.Fatal (err); + err := BuildBindingGo(component, outputFolderBindingGo) + if err != nil { + log.Fatal(err) } } - case "Node": { - outputFolderBindingNode := outputFolderBindings + "/NodeJS"; + case "Node": + { + outputFolderBindingNode := outputFolderBindings + "/NodeJS" - err = os.MkdirAll(outputFolderBindingNode, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderBindingNode, os.ModePerm) + if err != nil { + log.Fatal(err) } - - CTypesHeaderName := path.Join(outputFolderBindingNode, component.BaseName + "_types.h"); - err = CreateCTypesHeader (component, CTypesHeaderName); - if (err != nil) { - log.Fatal (err); + + CTypesHeaderName := path.Join(outputFolderBindingNode, component.BaseName+"_types.h") + err = CreateCTypesHeader(component, CTypesHeaderName) + if err != nil { + log.Fatal(err) } - - err = BuildBindingCDynamic(component, outputFolderBindingNode, indentString); - if (err != nil) { - log.Fatal (err); + + err = BuildBindingCExplicit(component, outputFolderBindingNode, indentString) + if err != nil { + log.Fatal(err) } - - err := BuildBindingNode(component, outputFolderBindingNode, indentString); - if (err != nil) { - log.Fatal (err); + + err := BuildBindingNode(component, outputFolderBindingNode, indentString) + if err != nil { + log.Fatal(err) } } - - case "Pascal": { - outputFolderBindingPascal := outputFolderBindings + "/Pascal"; - err = os.MkdirAll(outputFolderBindingPascal, os.ModePerm); - if (err != nil) { - log.Fatal (err); + + case "Pascal": + { + outputFolderBindingPascal := outputFolderBindings + "/Pascal" + err = os.MkdirAll(outputFolderBindingPascal, os.ModePerm) + if err != nil { + log.Fatal(err) } - outputFolderExamplePascal := outputFolderExamples + "/Pascal"; - err = os.MkdirAll(outputFolderExamplePascal, os.ModePerm); - if (err != nil) { - log.Fatal (err); + outputFolderExamplePascal := outputFolderExamples + "/Pascal" + err = os.MkdirAll(outputFolderExamplePascal, os.ModePerm) + if err != nil { + log.Fatal(err) } - - err = BuildBindingPascalDynamic(component, outputFolderBindingPascal, outputFolderExamplePascal, indentString); - if (err != nil) { - log.Fatal (err); + + err = BuildBindingPascalDynamic(component, outputFolderBindingPascal, outputFolderExamplePascal, indentString) + if err != nil { + log.Fatal(err) } } - case "Python": { - outputFolderBindingPython := outputFolderBindings + "/Python"; - err = os.MkdirAll(outputFolderBindingPython, os.ModePerm); + case "CSharp": + { + outputFolderBindingCSharp := outputFolderBindings + "/CSharp"; + err = os.MkdirAll(outputFolderBindingCSharp, os.ModePerm); if (err != nil) { log.Fatal (err); } - outputFolderExamplePython := outputFolderExamples + "/Python"; - err = os.MkdirAll(outputFolderExamplePython, os.ModePerm); + outputFolderExampleCSharp := outputFolderExamples + "/CSharp"; + err = os.MkdirAll(outputFolderExampleCSharp, os.ModePerm); if (err != nil) { log.Fatal (err); } - err = BuildBindingPythonDynamic(component, outputFolderBindingPython, outputFolderExamplePython, indentString); + err = BuildBindingCSharp(component, outputFolderBindingCSharp, outputFolderExampleCSharp, indentString); if (err != nil) { log.Fatal (err); } } - - case"Fortran": { - log.Printf ("Interface binding for language \"%s\" is not yet supported.", binding.Language); + case "Python": + { + outputFolderBindingPython := outputFolderBindings + "/Python" + err = os.MkdirAll(outputFolderBindingPython, os.ModePerm) + if err != nil { + log.Fatal(err) + } + + outputFolderExamplePython := outputFolderExamples + "/Python" + err = os.MkdirAll(outputFolderExamplePython, os.ModePerm) + if err != nil { + log.Fatal(err) + } + + err = BuildBindingPythonDynamic(component, outputFolderBindingPython, outputFolderExamplePython, indentString) + if err != nil { + log.Fatal(err) + } } - default: - log.Fatal ("Unknown binding export"); + case "Fortran": + { + log.Printf("Interface binding for language \"%s\" is not yet supported.", binding.Language) + } + + default: + log.Fatal("Unknown binding export") } } - if (len(component.ImplementationList.Implementations) > 0) { - err = os.MkdirAll(outputFolderImplementations, os.ModePerm); - if (err != nil) { - log.Fatal (err); + if len(component.ImplementationList.Implementations) > 0 { + err = os.MkdirAll(outputFolderImplementations, os.ModePerm) + if err != nil { + log.Fatal(err) } } for implementationindex := 0; implementationindex < len(component.ImplementationList.Implementations); implementationindex++ { - implementation := component.ImplementationList.Implementations[implementationindex]; - log.Printf ("Exporting Implementation Interface for Language \"%s\"", implementation.Language); - - switch (implementation.Language) { - case "Cpp": { - outputFolderImplementationProject := outputFolderImplementations + "/Cpp"; - outputFolderImplementationCpp := outputFolderImplementations + "/Cpp/Interfaces"; - outputFolderImplementationCppStub := outputFolderImplementations + "/Cpp/Stub"; - - err = os.MkdirAll(outputFolderImplementationCpp, os.ModePerm); - if (err != nil) { - log.Fatal (err); + implementation := component.ImplementationList.Implementations[implementationindex] + log.Printf("Exporting Implementation Interface for Language \"%s\"", implementation.Language) + + switch implementation.Language { + case "Cpp": + { + outputFolderImplementationProject := outputFolderImplementations + "/Cpp" + outputFolderImplementationCpp := outputFolderImplementations + "/Cpp/Interfaces" + outputFolderImplementationCppStub := outputFolderImplementations + "/Cpp/Stub" + + err = os.MkdirAll(outputFolderImplementationCpp, os.ModePerm) + if err != nil { + log.Fatal(err) } - err = os.MkdirAll(outputFolderImplementationCppStub, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderImplementationCppStub, os.ModePerm) + if err != nil { + log.Fatal(err) } - CTypesHeaderName := path.Join(outputFolderImplementationCpp, component.BaseName + "_types.h"); - err = CreateCTypesHeader (component, CTypesHeaderName); - if (err != nil) { - log.Fatal (err); + CTypesHeaderName := path.Join(outputFolderImplementationCpp, component.BaseName+"_types.hpp") + err = CreateCPPTypesHeader(component, CTypesHeaderName) + if err != nil { + log.Fatal(err) } - - CHeaderName := path.Join(outputFolderImplementationCpp, component.BaseName + ".h"); - err = CreateCHeader (component, CHeaderName); - if (err != nil) { - log.Fatal (err); + + CHeaderName := path.Join(outputFolderImplementationCpp, component.BaseName+"_abi.hpp") + err = CreateCPPAbiHeader(component, CHeaderName) + if err != nil { + log.Fatal(err) } - + err = BuildImplementationCPP(component, outputFolderImplementationCpp, outputFolderImplementationCppStub, - outputFolderImplementationProject, implementation); - if (err != nil) { - log.Fatal (err); + outputFolderImplementationProject, implementation) + if err != nil { + log.Fatal(err) } } - case "Pascal": { - outputFolderImplementationProject := outputFolderImplementations + "/Pascal"; - outputFolderImplementationPascal := outputFolderImplementations + "/Pascal/Interfaces"; - outputFolderImplementationPascalStub := outputFolderImplementations + "/Pascal/Stub"; + case "Pascal": + { + outputFolderImplementationProject := outputFolderImplementations + "/Pascal" + outputFolderImplementationPascal := outputFolderImplementations + "/Pascal/Interfaces" + outputFolderImplementationPascalStub := outputFolderImplementations + "/Pascal/Stub" - err = os.MkdirAll(outputFolderImplementationPascal, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderImplementationPascal, os.ModePerm) + if err != nil { + log.Fatal(err) } - err = os.MkdirAll(outputFolderImplementationPascalStub, os.ModePerm); - if (err != nil) { - log.Fatal (err); + err = os.MkdirAll(outputFolderImplementationPascalStub, os.ModePerm) + if err != nil { + log.Fatal(err) } - + err = BuildImplementationPascal(component, outputFolderImplementationPascal, outputFolderImplementationPascalStub, - outputFolderImplementationProject, implementation); - if (err != nil) { - log.Fatal (err); + outputFolderImplementationProject, implementation) + if err != nil { + log.Fatal(err) } } - - case "Fortran": { - log.Printf ("Implementation in language \"%s\" is not yet supported.", implementation.Language); + + case "Fortran": + { + log.Printf("Implementation in language \"%s\" is not yet supported.", implementation.Language) } - default: - log.Fatal ("Unknown export"); + default: + log.Fatal("Unknown export") } } diff --git a/Source/buildbindingccpp.go b/Source/buildbindingccpp.go new file mode 100644 index 00000000..f1b8cfc4 --- /dev/null +++ b/Source/buildbindingccpp.go @@ -0,0 +1,1378 @@ +/*++ + +Copyright (C) 2018 Autodesk Inc. (Original Author) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--*/ + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// buildbindingccppdynamic.go +// functions to generate C and C++-bindings of a library's API in form of dynamically loaded functions +// handles. It provides bindings that link explicitly (also known as run-time dynamic library loading) +// and implicitly (load-time dynamic library loading). +////////////////////////////////////////////////////////////////////////////////////////////////////// + +package main + +import ( + "fmt" + "log" + "path" + "path/filepath" + "strings" +) + +// BuildBindingCExplicit builds dyanmic C-bindings of a library's API in form of explicitly loaded function handles. +func BuildBindingCExplicit(component ComponentDefinition, outputFolder string, indentString string) error { + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h") + log.Printf("Creating \"%s\"", DynamicCHeader) + dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) + if err != nil { + return err + } + dynhfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, false, false) + if err != nil { + return err + } + + DynamicCImpl := path.Join(outputFolder, baseName+"_dynamic.cc") + log.Printf("Creating \"%s\"", DynamicCImpl) + dyncppfile, err := CreateLanguageFile(DynamicCImpl, indentString) + if err != nil { + return err + } + dyncppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), + true) + + err = buildDynamicCImplementation(component, dyncppfile, namespace, baseName) + if err != nil { + return err + } + + return nil +} + +// BuildBindingCppImplicit builds dynamic C++-bindings of a library's API in form of implicitly linked functions handles. +func BuildBindingCppImplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string, ClassIdentifier string) error { + forceRecreation := false + ExplicitLinking := false + + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + CppHeader := path.Join(outputFolder, baseName+"_implicit.hpp") + log.Printf("Creating \"%s\"", CppHeader) + hppfile, err := CreateLanguageFile(CppHeader, indentString) + if err != nil { + return err + } + hppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildCppHeader(component, hppfile, namespace, baseName, ClassIdentifier, ExplicitLinking) + if err != nil { + return err + } + + if len(outputFolderExample) > 0 { + CPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp") + if forceRecreation || !FileExists(CPPExample) { + log.Printf("Creating \"%s\"", CPPExample) + cppexamplefile, err := CreateLanguageFile(CPPExample, " ") + if err != nil { + return err + } + cppexamplefile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the C++ bindings of %s", libraryname), + true) + buildDynamicCppExample(component, cppexamplefile, outputFolder, ClassIdentifier, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++-example file \"%s\"", CPPExample) + } + + CPPCMake := path.Join(outputFolderExample, "CMakeLists.txt") + if forceRecreation || !FileExists(CPPCMake) { + log.Printf("Creating \"%s\"", CPPCMake) + cppcmake, err := CreateLanguageFile(CPPCMake, " ") + if err != nil { + return err + } + cppcmake.WriteCMakeLicenseHeader(component, + fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the C++ bindings of %s", libraryname), + true) + buildCppDynamicExampleCMake(component, cppcmake, outputFolder, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++-example CMakeLists-file \"%s\"", CPPCMake) + } + } + return nil +} + +func buildDynamicCCPPHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, + headerOnly bool, useCPPTypes bool) error { + + sIncludeGuard := "__" + strings.ToUpper(NameSpace) + "_DYNAMICHEADER" + if useCPPTypes { + sIncludeGuard += "_CPPTYPES" + } + w.Writeln("#ifndef %s", sIncludeGuard) + w.Writeln("#define %s", sIncludeGuard) + w.Writeln("") + + if useCPPTypes { + w.Writeln("#include \"%s_types.hpp\"", BaseName) + } else { + w.Writeln("#include \"%s_types.h\"", BaseName) + } + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class definition for %s", class.ClassName) + w.Writeln("**************************************************************************************************************************/") + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + WriteCCPPAbiMethod(method, w, NameSpace, class.ClassName, false, true, useCPPTypes) + } + } + + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Global functions") + w.Writeln("**************************************************************************************************************************/") + + global := component.Global + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + err := WriteCCPPAbiMethod(method, w, NameSpace, "Wrapper", true, true, useCPPTypes) + if err != nil { + return err + } + } + + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Function Table Structure") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("") + w.Writeln("typedef struct {") + w.Writeln(" void * m_LibraryHandle;") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + w.Writeln(" P%s%s_%sPtr m_%s_%s;", NameSpace, class.ClassName, method.MethodName, class.ClassName, method.MethodName) + } + } + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + w.Writeln(" P%s%sPtr m_%s;", NameSpace, method.MethodName, method.MethodName) + } + + w.Writeln("} s%sDynamicWrapperTable;", NameSpace) + w.Writeln("") + + if !headerOnly { + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Load DLL dynamically") + w.Writeln("**************************************************************************************************************************/") + + w.Writeln("%sResult Init%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace, NameSpace) + w.Writeln("%sResult Release%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace, NameSpace) + w.Writeln("%sResult Load%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace, NameSpace) + + w.Writeln("") + } + + w.Writeln("#endif // %s", sIncludeGuard) + w.Writeln("") + + return nil +} + +func buildDynamicCInitTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { + global := component.Global + + w.Writeln("if (pWrapperTable == nullptr)") + w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) + w.Writeln("") + w.Writeln("pWrapperTable->m_LibraryHandle = nullptr;") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + w.Writeln("pWrapperTable->m_%s_%s = nullptr;", class.ClassName, method.MethodName) + } + } + + global = component.Global + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + w.Writeln("pWrapperTable->m_%s = nullptr;", method.MethodName) + } + + w.Writeln("") + w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) + + return nil +} + +func buildDynamicCReleaseTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, initWrapperFunctionName string) error { + + w.Writeln("if (pWrapperTable == nullptr)") + w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) + w.Writeln("") + w.Writeln("if (pWrapperTable->m_LibraryHandle != nullptr) {") + w.Writeln("#ifdef _WIN32") + w.Writeln(" HMODULE hModule = (HMODULE) pWrapperTable->m_LibraryHandle;") + w.Writeln(" FreeLibrary(hModule);") + w.Writeln("#else // _WIN32") + w.Writeln(" dlclose(pWrapperTable->m_LibraryHandle);") + w.Writeln("#endif // _WIN32") + w.Writeln(" return %s(pWrapperTable);", initWrapperFunctionName) + w.Writeln("}") + w.Writeln("") + w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) + + return nil +} + +// WriteLoadingOfMethod the loading of a method from a library into a LanguagWriter +func WriteLoadingOfMethod(class ComponentDefinitionClass, method ComponentDefinitionMethod, w LanguageWriter, NameSpace string) { + w.Writeln("#ifdef _WIN32") + w.Writeln("pWrapperTable->m_%s_%s = (P%s%s_%sPtr) GetProcAddress(hLibrary, \"%s_%s_%s\");", class.ClassName, method.MethodName, NameSpace, class.ClassName, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) + w.Writeln("#else // _WIN32") + w.Writeln("pWrapperTable->m_%s_%s = (P%s%s_%sPtr) dlsym(hLibrary, \"%s_%s_%s\");", class.ClassName, method.MethodName, NameSpace, class.ClassName, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) + w.Writeln("dlerror();") + w.Writeln("#endif // _WIN32") + w.Writeln("if (pWrapperTable->m_%s_%s == nullptr)", class.ClassName, method.MethodName) + w.Writeln(" return %s_ERROR_COULDNOTFINDLIBRARYEXPORT;", strings.ToUpper(NameSpace)) + w.Writeln("") +} + +func buildDynamicCLoadTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { + global := component.Global + + w.Writeln("if (pWrapperTable == nullptr)") + w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) + w.Writeln("if (pLibraryFileName == nullptr)") + w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) + + w.Writeln("") + + w.Writeln("#ifdef _WIN32") + w.Writeln("// Convert filename to UTF16-string") + w.Writeln("int nLength = (int)strlen(pLibraryFileName);") + w.Writeln("int nBufferSize = nLength * 2 + 2;") + w.Writeln("std::vector<wchar_t> wsLibraryFileName(nBufferSize);") + w.Writeln("int nResult = MultiByteToWideChar(CP_UTF8, 0, pLibraryFileName, nLength, &wsLibraryFileName[0], nBufferSize);") + w.Writeln("if (nResult == 0)") + w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) + w.Writeln("") + w.Writeln("HMODULE hLibrary = LoadLibraryW(wsLibraryFileName.data());") + + w.Writeln("if (hLibrary == 0) ") + w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) + w.Writeln("#else // _WIN32") + w.Writeln("void* hLibrary = dlopen(pLibraryFileName, RTLD_LAZY);") + w.Writeln("if (hLibrary == 0) ") + w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) + w.Writeln("dlerror();") + w.Writeln("#endif // _WIN32") + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + WriteLoadingOfMethod(class, method, w, NameSpace) + } + } + + global = component.Global + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + w.Writeln("#ifdef _WIN32") + w.Writeln("pWrapperTable->m_%s = (P%s%sPtr) GetProcAddress(hLibrary, \"%s_%s\");", method.MethodName, NameSpace, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + w.Writeln("#else // _WIN32") + w.Writeln("pWrapperTable->m_%s = (P%s%sPtr) dlsym(hLibrary, \"%s_%s\");", method.MethodName, NameSpace, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + w.Writeln("dlerror();") + w.Writeln("#endif // _WIN32") + + w.Writeln("if (pWrapperTable->m_%s == nullptr)", method.MethodName) + w.Writeln(" return %s_ERROR_COULDNOTFINDLIBRARYEXPORT;", strings.ToUpper(NameSpace)) + w.Writeln("") + } + + w.Writeln("pWrapperTable->m_LibraryHandle = hLibrary;") + w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) + + return nil +} + +func buildDynamicCImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { + w.Writeln("#include \"%s_types.h\"", BaseName) + w.Writeln("#include \"%s_dynamic.h\"", BaseName) + + w.Writeln("#ifdef _WIN32") + w.Writeln("#include <Windows.h>") + w.Writeln("#include <vector>") + w.Writeln("#else // _WIN32") + w.Writeln("#include <dlfcn.h>") + w.Writeln("#endif // _WIN32") + + w.Writeln("") + w.Writeln("%sResult Init%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, NameSpace, NameSpace) + w.Writeln("{") + + w.AddIndentationLevel(1) + buildDynamicCInitTableCode(component, w, NameSpace, BaseName) + w.AddIndentationLevel(-1) + + w.Writeln("}") + + w.Writeln("") + w.Writeln("%sResult Release%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, NameSpace, NameSpace) + w.Writeln("{") + + w.AddIndentationLevel(1) + buildDynamicCReleaseTableCode(component, w, NameSpace, BaseName, "Init"+NameSpace+"WrapperTable") + w.AddIndentationLevel(-1) + + w.Writeln("}") + + w.Writeln("") + w.Writeln("%sResult Load%sWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, NameSpace, NameSpace) + w.Writeln("{") + + w.AddIndentationLevel(1) + buildDynamicCLoadTableCode(component, w, NameSpace, BaseName) + w.AddIndentationLevel(-1) + + w.Writeln("}") + w.Writeln("") + + return nil +} + +func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string) error { + parameters := "" + returntype := "void" + + for k := 0; k < len(method.Params); k++ { + + param := method.Params[k] + variableName := getBindingCppVariableName(param) + + switch param.ParamPass { + case "in": + if parameters != "" { + parameters = parameters + ", " + } + cppParamType := getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, true) + + switch param.ParamType { + case "string": + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "struct": + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "structarray", "basicarray": + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "class": + parameters = parameters + fmt.Sprintf("%s %s", cppParamType, variableName) + default: + parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, variableName) + } + case "out": + cppParamType := getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, false) + if parameters != "" { + parameters = parameters + ", " + } + parameters = parameters + fmt.Sprintf("%s & %s", cppParamType, variableName) + case "return": + returntype = getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, false) + default: + return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + } + } + + w.Writeln(" inline %s %s(%s);", returntype, method.MethodName, parameters) + + return nil +} + +func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string, + isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool) error { + + CMethodName := "" + requiresInitCall := false + initCallParameters := "" // usually used to check sizes of buffers + callParameters := "" + checkErrorCodeBegin := "" + checkErrorCodeEnd := ")" + makeSharedParameter := "" + + if isGlobal { + if ExplicitLinking { + CMethodName = fmt.Sprintf("m_WrapperTable.m_%s", method.MethodName) + } else { + CMethodName = fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + } + checkErrorCodeBegin = "CheckError(nullptr," + makeSharedParameter = "this, " + } else { + if ExplicitLinking { + CMethodName = fmt.Sprintf("m_pWrapper->m_WrapperTable.m_%s_%s", ClassName, method.MethodName) + } else { + CMethodName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) + } + callParameters = "m_pHandle" + initCallParameters = "m_pHandle" + checkErrorCodeBegin = "CheckError(" + makeSharedParameter = "m_pWrapper, " + } + if doNotThrow { + checkErrorCodeBegin = "" + checkErrorCodeEnd = "" + } + + parameters := "" + returntype := "void" + + definitionCodeLines := []string{} + functionCodeLines := []string{} + returnCodeLines := []string{} + commentcodeLines := []string{} + postCallCodeLines := []string{} + + cppClassPrefix := "C" + if !useCPPTypes { + cppClassPrefix += NameSpace + } + cppClassName := cppClassPrefix + ClassIdentifier + ClassName + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k] + variableName := getBindingCppVariableName(param) + + callParameter := "" + initCallParameter := "" + + switch param.ParamPass { + case "in": + if parameters != "" { + parameters = parameters + ", " + } + cppParamType := getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, true) + commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[in] %s - %s", variableName, param.ParamDescription)) + + switch param.ParamType { + case "string": + callParameter = variableName + ".c_str()" + initCallParameter = callParameter + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "struct": + callParameter = "&" + variableName + initCallParameter = callParameter + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "structarray", "basicarray": + callParameter = fmt.Sprintf("(%s_uint64)%s.size(), %s.data()", NameSpace, variableName, variableName) + initCallParameter = callParameter + parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName) + case "class": + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("if (%s != nullptr) {", variableName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf(" h%s = %s->GetHandle();", param.ParamName, variableName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("};")) + callParameter = "h" + param.ParamName + initCallParameter = callParameter + parameters = parameters + fmt.Sprintf("%s %s", cppParamType, variableName) + + default: + callParameter = variableName + initCallParameter = callParameter + parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, variableName) + } + + case "out": + cppParamType := getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, false) + commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[out] %s - %s", variableName, param.ParamDescription)) + + if parameters != "" { + parameters = parameters + ", " + } + parameters = parameters + fmt.Sprintf("%s & %s", cppParamType, variableName) + + switch param.ParamType { + + case "string": + requiresInitCall = true + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) + initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + + functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) + functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) + + callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) + + postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName)) + postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("s%s = std::string(&buffer%s[0]);", param.ParamName, param.ParamName)) + + case "class": + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) + callParameter = fmt.Sprintf("&h%s", param.ParamName) + initCallParameter = callParameter + postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("p%s = std::make_shared<%s%s%s>(h%s);", param.ParamName, cppClassPrefix, ClassIdentifier, param.ParamClass, param.ParamName)) + + case "structarray", "basicarray": + requiresInitCall = true + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsNeeded%s = 0;", NameSpace, param.ParamName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsWritten%s = 0;", NameSpace, param.ParamName)) + initCallParameter = fmt.Sprintf("0, &elementsNeeded%s, nullptr", param.ParamName) + + functionCodeLines = append(functionCodeLines, fmt.Sprintf("%s.resize((size_t) elementsNeeded%s);", variableName, param.ParamName)) + callParameter = fmt.Sprintf("elementsNeeded%s, &elementsWritten%s, %s.data()", param.ParamName, param.ParamName, variableName) + + default: + callParameter = "&" + variableName + initCallParameter = callParameter + } + + case "return": + commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @return %s", param.ParamDescription)) + returntype = getBindingCppParamType(param.ParamType, param.ParamClass, NameSpace, ClassIdentifier, false) + + switch param.ParamType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer": + callParameter = fmt.Sprintf("&result%s", param.ParamName) + initCallParameter = callParameter + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s result%s = 0;", returntype, param.ParamName)) + returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) + + case "string": + requiresInitCall = true + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) + initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName) + + functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) + functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) + + callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) + + postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName)) + returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::string(&buffer%s[0]);", param.ParamName)) + + case "enum": + callParameter = fmt.Sprintf("&result%s", param.ParamName) + initCallParameter = callParameter + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("e%s%s result%s = (e%s%s) 0;", NameSpace, param.ParamClass, param.ParamName, NameSpace, param.ParamClass)) + returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) + + case "struct": + callParameter = fmt.Sprintf("&result%s", param.ParamName) + initCallParameter = callParameter + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("s%s%s result%s;", NameSpace, param.ParamClass, param.ParamName)) + returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) + + case "class": + definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) + callParameter = fmt.Sprintf("&h%s", param.ParamName) + initCallParameter = callParameter + returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::make_shared<%s%s%s>(%sh%s);", cppClassPrefix, ClassIdentifier, param.ParamClass, makeSharedParameter, param.ParamName)) + + case "basicarray": + return fmt.Errorf("can not return basicarray \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + + case "structarray": + return fmt.Errorf("can not return structarray \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + + default: + return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + } + + default: + return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + } + + if callParameters != "" { + callParameters = callParameters + ", " + } + callParameters = callParameters + callParameter + if initCallParameters != "" { + initCallParameters = initCallParameters + ", " + } + initCallParameters = initCallParameters + initCallParameter + } + + w.Writeln(" ") + if includeComments { + w.Writeln(" /**") + w.Writeln(" * %s::%s - %s", cppClassName, method.MethodName, method.MethodDescription) + w.Writelns(" ", commentcodeLines) + w.Writeln(" */") + } + + nameSpaceQualifier := cppClassName + "::" + + if isGlobal { + w.Writeln(" inline %s %s%s(%s)", returntype, nameSpaceQualifier, method.MethodName, parameters) + } else { + w.Writeln(" %s %s%s(%s)", returntype, nameSpaceQualifier, method.MethodName, parameters) + } + + w.Writeln(" {") + w.Writelns(" ", definitionCodeLines) + if requiresInitCall { + w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, initCallParameters, checkErrorCodeEnd) + } + w.Writelns(" ", functionCodeLines) + w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, callParameters, checkErrorCodeEnd) + w.Writelns(" ", postCallCodeLines) + w.Writelns(" ", returnCodeLines) + w.Writeln(" }") + + return nil +} + +func writeDynamicCppBaseClassMethods(component ComponentDefinition, baseClass ComponentDefinitionClass, w LanguageWriter, NameSpace string, BaseName string, cppClassPrefix string, ClassIdentifier string) error { + cppBaseClassName := cppClassPrefix + ClassIdentifier + baseClass.ClassName + w.Writeln("protected:") + w.Writeln(" /* Wrapper Object that created the class. */") + w.Writeln(" %s%sWrapper * m_pWrapper;", cppClassPrefix, ClassIdentifier) + w.Writeln(" /* Handle to Instance in library*/") + w.Writeln(" %sHandle m_pHandle;", NameSpace) + w.Writeln("") + w.Writeln(" /* Checks for an Error code and raises Exceptions */") + w.Writeln(" void CheckError(%sResult nResult)", NameSpace) + w.Writeln(" {") + w.Writeln(" if (m_pWrapper != nullptr)") + w.Writeln(" m_pWrapper->CheckError(this, nResult);") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * %s::%s - Constructor for Base class.", cppBaseClassName, cppBaseClassName) + w.Writeln(" */") + w.Writeln(" %s(%s%sWrapper * pWrapper, %sHandle pHandle)", cppBaseClassName, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" : m_pWrapper(pWrapper), m_pHandle(pHandle)") + w.Writeln(" {") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * %s::~%s - Destructor for Base class.", cppBaseClassName, cppBaseClassName) + w.Writeln(" */") + + w.Writeln(" virtual ~%s()", cppBaseClassName) + w.Writeln(" {") + w.Writeln(" if (m_pWrapper != nullptr)") + w.Writeln(" m_pWrapper->%s(this);", component.Global.ReleaseMethod) + w.Writeln(" m_pWrapper = nullptr;") + w.Writeln(" }") + w.Writeln("") + w.Writeln("public:") + w.Writeln(" /**") + w.Writeln(" * %s::GetHandle - Returns handle to instance.", cppBaseClassName) + w.Writeln(" */") + w.Writeln(" %sHandle GetHandle()", NameSpace) + w.Writeln(" {") + w.Writeln(" return m_pHandle;") + w.Writeln(" }") + + w.Writeln(" ") + w.Writeln(" friend class CWrapper;") + return nil +} + + +func buildBindingCPPAllForwardDeclarations(component ComponentDefinition, w LanguageWriter, NameSpace string, cppClassPrefix string, ClassIdentifier string) { + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Forward Declaration of all classes") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("class %s%sWrapper;", cppClassPrefix, ClassIdentifier) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + className := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln("class %s;", className) + } + if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Declaration of deprecated class types") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("typedef %s%sWrapper %s%sWrapper;", cppClassPrefix, ClassIdentifier, cppClassPrefix, NameSpace) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + className := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln("typedef %s %s%s%s;", className, cppClassPrefix, NameSpace, class.ClassName) + } + w.Writeln("") + } + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Declaration of shared pointer types") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("typedef std::shared_ptr<%s%sWrapper> P%sWrapper;", cppClassPrefix, ClassIdentifier, ClassIdentifier) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + className := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln("typedef std::shared_ptr<%s> P%s%s;", className, ClassIdentifier, class.ClassName) + } + + if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Declaration of deprecated shared pointer types") + w.Writeln("**************************************************************************************************************************/") + w.Writeln("typedef P%sWrapper P%sWrapper;", ClassIdentifier, NameSpace) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + w.Writeln("typedef P%s%s P%s%s;", ClassIdentifier, class.ClassName, NameSpace, class.ClassName) + } + w.Writeln("") + } +} + +func writeCPPInputVector(w LanguageWriter, NameSpace string, ClassIdentifier string) error { + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class C%sInputVector", ClassIdentifier) + w.Writeln("**************************************************************************************************************************/") + w.Writeln("template <typename T>") + w.Writeln("class C%sInputVector {", ClassIdentifier) + w.Writeln("private:") + w.Writeln(" ") + w.Writeln(" const T* m_data;") + w.Writeln(" size_t m_size;") + w.Writeln(" ") + w.Writeln("public:") + w.Writeln(" ") + w.Writeln(" C%sInputVector( const std::vector<T>& vec)", ClassIdentifier) + w.Writeln(" : m_data( vec.data() ), m_size( vec.size() )") + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + w.Writeln(" C%sInputVector( const T* in_data, size_t in_size)", ClassIdentifier) + w.Writeln(" : m_data( in_data ), m_size(in_size )") + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + w.Writeln(" const T* data() const") + w.Writeln(" {") + w.Writeln(" return m_data;") + w.Writeln(" }") + w.Writeln(" ") + w.Writeln(" size_t size() const") + w.Writeln(" {") + w.Writeln(" return m_size;") + w.Writeln(" }") + w.Writeln(" ") + w.Writeln("};") + w.Writeln("") + if (strings.Compare(ClassIdentifier, NameSpace) != 0) { + w.Writeln("// declare deprecated class name") + w.Writeln("template<typename T>") + w.Writeln("using C%sInputVector = C%sInputVector<T>;", NameSpace, ClassIdentifier) + } + return nil +} + + +func getBindingCppParamType(paramType string, paramClass string, NameSpace string, ClassIdentifier string, isInput bool) string { + cppClassPrefix := "C" + switch paramType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + return fmt.Sprintf("%s_%s", NameSpace, paramType) + case "string": + return fmt.Sprintf("std::string") + case "bool": + return fmt.Sprintf("bool") + case "pointer": + return fmt.Sprintf("%s_pvoid", NameSpace) + case "basicarray": + cppBasicType := "" + switch paramClass { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", + "bool", "pointer": + cppBasicType = getBindingCppParamType(paramClass, "", NameSpace, ClassIdentifier, isInput) + default: + log.Fatal("Invalid parameter type: ", paramClass) + } + if isInput { + return fmt.Sprintf("C%sInputVector<%s>", ClassIdentifier, cppBasicType) + } + return fmt.Sprintf("std::vector<%s>", cppBasicType) + case "structarray": + if isInput { + return fmt.Sprintf("C%sInputVector<s%s>", ClassIdentifier, paramClass) + } + return fmt.Sprintf("std::vector<s%s>", paramClass) + case "enum": + return fmt.Sprintf("e%s", paramClass) + case "struct": + return fmt.Sprintf("s%s", paramClass) + case "class": + if isInput { + return fmt.Sprintf("%s%s%s *", cppClassPrefix, ClassIdentifier, paramClass) + } + return fmt.Sprintf("P%s%s", ClassIdentifier, paramClass) + case "functiontype": + return fmt.Sprintf("%s", paramClass) + } + log.Fatal("Invalid parameter type: ", paramType) + return "" +} + +func getBindingCppVariableName(param ComponentDefinitionParam) string { + switch param.ParamType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": + return "n" + param.ParamName + case "string": + return "s" + param.ParamName + case "bool": + return "b" + param.ParamName + case "single": + return "f" + param.ParamName + case "basicarray", "structarray": + return param.ParamName + "Buffer" + case "double": + return "d" + param.ParamName + case "pointer": + return "p" + param.ParamName + case "enum": + return "e" + param.ParamName + case "struct": + return param.ParamName + case "class": + return "p" + param.ParamName + case "functiontype": + return fmt.Sprintf("p%s", param.ParamName) + } + + log.Fatal("Invalid parameter type: ", param.ParamType) + + return "" +} + + +func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, ClassIdentifier string, ExplicitLinking bool) error { + useCPPTypes := true + + global := component.Global + + cppClassPrefix := "C" + baseClass := component.baseClass() + cppBaseClassName := cppClassPrefix + ClassIdentifier + baseClass.ClassName + + sIncludeGuard := ""; + + if ExplicitLinking { + sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_DYNAMIC" + } else { + sIncludeGuard = "__" + strings.ToUpper(NameSpace) + "_CPPHEADER_IMPLICIT" + } + + if useCPPTypes { + sIncludeGuard += "_CPP" + } + w.Writeln("#ifndef %s", sIncludeGuard) + w.Writeln("#define %s", sIncludeGuard) + w.Writeln("") + + w.Writeln("#include \"%s_types.hpp\"", BaseName) + + if ExplicitLinking { + w.Writeln("#include \"%s_dynamic.h\"", BaseName) + } else { + w.Writeln("#include \"%s_abi.hpp\"", BaseName) + } + + w.Writeln("") + + w.Writeln("#ifdef _WIN32") + w.Writeln("#include <Windows.h>") + w.Writeln("#else // _WIN32") + w.Writeln("#include <dlfcn.h>") + w.Writeln("#endif // _WIN32") + w.Writeln("#include <string>") + w.Writeln("#include <memory>") + w.Writeln("#include <vector>") + w.Writeln("#include <exception>") + w.Writeln("") + + w.Writeln("namespace %s {", NameSpace) + w.Writeln("") + + buildBindingCPPAllForwardDeclarations(component, w, NameSpace, cppClassPrefix, ClassIdentifier) + + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class E%sException ", NameSpace) + w.Writeln("**************************************************************************************************************************/") + w.Writeln("class E%sException : public std::exception {", NameSpace) + w.Writeln("protected:") + w.Writeln(" /**") + w.Writeln(" * Error code for the Exception.") + w.Writeln(" */") + w.Writeln(" %sResult m_errorCode;", NameSpace) + w.Writeln(" /**") + w.Writeln(" * Error message for the Exception.") + w.Writeln(" */") + w.Writeln(" std::string m_errorMessage;") + w.Writeln("") + w.Writeln("public:") + w.Writeln(" /**") + w.Writeln(" * Exception Constructor.") + w.Writeln(" */") + w.Writeln(" E%sException(%sResult errorCode, const std::string & sErrorMessage)", NameSpace, NameSpace) + w.Writeln(" : m_errorMessage(\"%s Error \" + std::to_string(errorCode) + \" (\" + sErrorMessage + \")\")", NameSpace) + w.Writeln(" {") + w.Writeln(" m_errorCode = errorCode;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * Returns error code") + w.Writeln(" */") + w.Writeln(" %sResult getErrorCode() const noexcept", NameSpace) + w.Writeln(" {") + w.Writeln(" return m_errorCode;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * Returns error message") + w.Writeln(" */") + w.Writeln(" const char* what() const noexcept") + w.Writeln(" {") + w.Writeln(" return m_errorMessage.c_str();") + w.Writeln(" }") + w.Writeln("") + + w.Writeln("};") + + w.Writeln("") + + err := writeCPPInputVector(w, NameSpace, ClassIdentifier) + if err != nil { + return err + } + w.Writeln("") + + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s%sWrapper ", cppClassPrefix, ClassIdentifier) + w.Writeln("**************************************************************************************************************************/") + + w.Writeln("class %s%sWrapper {", cppClassPrefix, ClassIdentifier) + w.Writeln("public:") + w.Writeln(" ") + + if ExplicitLinking { + w.Writeln(" %s%sWrapper(const std::string &sFileName)", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" CheckError(nullptr, initWrapperTable(&m_WrapperTable));") + w.Writeln(" CheckError(nullptr, loadWrapperTable(&m_WrapperTable, sFileName.c_str()));") + w.Writeln(" ") + w.Writeln(" CheckError(nullptr, checkBinaryVersion());") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" static P%sWrapper loadLibrary(const std::string &sFileName)", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>(sFileName);", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" releaseWrapperTable(&m_WrapperTable);") + w.Writeln(" }") + } else { + w.Writeln(" %s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln(" ~%s%sWrapper()", cppClassPrefix, ClassIdentifier) + w.Writeln(" {") + w.Writeln(" }") + + w.Writeln(" static inline P%sWrapper loadLibrary()", ClassIdentifier) + w.Writeln(" {") + w.Writeln(" return std::make_shared<%s%sWrapper>();", cppClassPrefix, ClassIdentifier) + w.Writeln(" }") + } + + w.Writeln(" ") + w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) + w.Writeln("") + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, "Wrapper") + if err != nil { + return err + } + } + + w.Writeln("") + w.Writeln("private:") + if ExplicitLinking { + w.Writeln(" s%sDynamicWrapperTable m_WrapperTable;", NameSpace) + } + + w.Writeln(" ") + w.Writeln(" %sResult checkBinaryVersion()", NameSpace) + w.Writeln(" {") + w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) + w.Writeln(" %s(nMajor, nMinor, nMicro);", global.VersionMethod) + w.Writeln(" if ( (nMajor != %s_VERSION_MAJOR) || (nMinor < %s_VERSION_MINOR) ) {", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace)) + w.Writeln(" return %s_ERROR_INCOMPATIBLEBINARYVERSION;", strings.ToUpper(NameSpace)) + w.Writeln(" }") + w.Writeln(" return %s_SUCCESS;", strings.ToUpper(NameSpace)) + w.Writeln(" }") + + if ExplicitLinking { + w.Writeln(" %sResult initWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) + w.Writeln(" %sResult loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace) + } + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + w.Writeln(" friend class %s;", cppClassName) + } + + w.Writeln("") + w.Writeln("};") + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + ClassIdentifier + class.ClassName + + cppParentClassName := "" + inheritanceSpecifier := "" + if !component.isBaseClass(class) { + if class.ParentClass == "" { + cppParentClassName = cppClassPrefix + ClassIdentifier + component.Global.BaseClassName + } else { + cppParentClassName = cppClassPrefix + ClassIdentifier+ class.ParentClass + } + inheritanceSpecifier = fmt.Sprintf(": public %s ", cppParentClassName) + } + + w.Writeln(" ") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class %s ", cppClassName) + w.Writeln("**************************************************************************************************************************/") + w.Writeln("class %s %s{", cppClassName, inheritanceSpecifier) + w.Writeln("public:") + w.Writeln(" ") + if !component.isBaseClass(class) { + w.Writeln(" /**") + w.Writeln(" * %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) + w.Writeln(" */") + w.Writeln(" %s(%s%sWrapper* pWrapper, %sHandle pHandle)", cppClassName, cppClassPrefix, ClassIdentifier, NameSpace) + if cppParentClassName != "" { + w.Writeln(" : %s(pWrapper, pHandle)", cppParentClassName) + } + w.Writeln(" {") + w.Writeln(" }") + w.Writeln(" ") + } else { + err = writeDynamicCppBaseClassMethods(component, baseClass, w, NameSpace, BaseName, cppClassPrefix, ClassIdentifier) + if err != nil { + return err + } + } + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + err = writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + if err != nil { + return err + } + } + w.Writeln("};") + } + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", true, true, false, useCPPTypes, ExplicitLinking) + if err != nil { + return err + } + } + + w.Writeln(" ") + w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) + w.Writeln(" {") + w.Writeln(" if (nResult != 0) {") + w.Writeln(" std::string sErrorMessage;") + w.Writeln(" if (pBaseClass != nullptr) {") + w.Writeln(" %s(pBaseClass, sErrorMessage);", component.Global.ErrorMethod) + w.Writeln(" }") + w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" ") + + w.Writeln("") + + if ExplicitLinking { + w.Writeln(" inline %sResult %s%sWrapper::initWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCInitTableCode(component, w, NameSpace, BaseName) + w.AddIndentationLevel(-2) + + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" inline %sResult %s%sWrapper::releaseWrapperTable(s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCReleaseTableCode(component, w, NameSpace, BaseName, "initWrapperTable") + w.AddIndentationLevel(-2) + + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" inline %sResult %s%sWrapper::loadWrapperTable(s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, cppClassPrefix, ClassIdentifier, NameSpace) + w.Writeln(" {") + + w.AddIndentationLevel(2) + buildDynamicCLoadTableCode(component, w, NameSpace, BaseName) + w.AddIndentationLevel(-2) + + w.Writeln(" }") + + w.Writeln(" ") + } + + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + cppClassName := cppClassPrefix + class.ClassName + w.Writeln(" ") + w.Writeln(" /**") + w.Writeln(" * Method definitions for class %s", cppClassName) + w.Writeln(" */") + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, false, false, false, useCPPTypes, ExplicitLinking) + if err != nil { + return err + } + } + } + + w.Writeln("") + + w.Writeln("} // namespace %s", NameSpace) + w.Writeln("") + + w.Writeln("#endif // %s", sIncludeGuard) + w.Writeln("") + + return nil +} + +// BuildBindingCppExplicit builds headeronly C++-bindings of a library's API in form of expliclty loaded function handles. +func BuildBindingCppExplicit(component ComponentDefinition, outputFolder string, outputFolderExample string, + indentString string, ClassIdentifier string) error { + forceRecreation := false + ExplicitLinking := true + namespace := component.NameSpace + libraryname := component.LibraryName + baseName := component.BaseName + + DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h") + log.Printf("Creating \"%s\"", DynamicCHeader) + dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) + if err != nil { + return err + } + dynhfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildDynamicCCPPHeader(component, dynhfile, namespace, baseName, true, true) + if err != nil { + return err + } + + DynamicCppHeader := path.Join(outputFolder, baseName+"_dynamic.hpp") + log.Printf("Creating \"%s\"", DynamicCppHeader) + dynhppfile, err := CreateLanguageFile(DynamicCppHeader, indentString) + if err != nil { + return err + } + dynhppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", libraryname), + true) + err = buildCppHeader(component, dynhppfile, namespace, baseName, ClassIdentifier, ExplicitLinking) + if err != nil { + return err + } + + if len(outputFolderExample) > 0 { + DynamicCPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp") + if forceRecreation || !FileExists(DynamicCPPExample) { + log.Printf("Creating \"%s\"", DynamicCPPExample) + dyncppexamplefile, err := CreateLanguageFile(DynamicCPPExample, " ") + if err != nil { + return err + } + dyncppexamplefile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), + true) + buildDynamicCppExample(component, dyncppexamplefile, outputFolder, ClassIdentifier, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPExample) + } + + DynamicCPPCMake := path.Join(outputFolderExample, "CMakeLists.txt") + if forceRecreation || !FileExists(DynamicCPPCMake) { + log.Printf("Creating \"%s\"", DynamicCPPCMake) + dyncppcmake, err := CreateLanguageFile(DynamicCPPCMake, " ") + if err != nil { + return err + } + dyncppcmake.WriteCMakeLicenseHeader(component, + fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), + true) + buildCppDynamicExampleCMake(component, dyncppcmake, outputFolder, ExplicitLinking) + } else { + log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPCMake) + } + } + + return nil +} + + +func buildDynamicCppExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string, ClassIdentifier string, ExplicitLinking bool) error { + NameSpace := componentdefinition.NameSpace + BaseName := componentdefinition.BaseName + + w.Writeln("#include <iostream>") + if (ExplicitLinking) { + w.Writeln("#include \"%s_dynamic.hpp\"", strings.ToLower(BaseName)) + } else { + w.Writeln("#include \"%s_implicit.hpp\"", strings.ToLower(BaseName)) + } + + w.Writeln("") + w.Writeln("") + + w.Writeln("int main()") + w.Writeln("{") + w.Writeln(" try") + w.Writeln(" {") + if (ExplicitLinking) { + w.Writeln(" std::string libpath = (\"\"); // TODO: put the location of the %s-library file here.", NameSpace) + w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary(libpath + \"/%s.\"); // TODO: add correct suffix of the library", NameSpace, ClassIdentifier, BaseName,) + } else { + w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary();", NameSpace, ClassIdentifier) + } + w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) + w.Writeln(" wrapper->%s(nMajor, nMinor, nMicro);", componentdefinition.Global.VersionMethod) + w.Writeln(" std::cout << \"%s.Version = \" << nMajor << \".\" << nMinor << \".\" << nMicro;", NameSpace) + if len(componentdefinition.Global.PrereleaseMethod)>0 { + w.Writeln(" std::string sPreReleaseInfo;") + w.Writeln(" if (wrapper->%s(sPreReleaseInfo)) {", componentdefinition.Global.PrereleaseMethod) + w.Writeln(" std::cout << \"-\" << sPreReleaseInfo;") + w.Writeln(" }") + } + if len(componentdefinition.Global.BuildinfoMethod)>0 { + w.Writeln(" std::string sBuildInfo;") + w.Writeln(" if (wrapper->%s(sBuildInfo)) {", componentdefinition.Global.BuildinfoMethod) + w.Writeln(" std::cout << \"+\" << sBuildInfo;") + w.Writeln(" }") + } + w.Writeln(" std::cout << std::endl;") + w.Writeln(" }") + w.Writeln(" catch (std::exception &e)") + w.Writeln(" {") + w.Writeln(" std::cout << e.what() << std::endl;") + w.Writeln(" return 1;") + w.Writeln(" }") + w.Writeln(" return 0;") + w.Writeln("}") + w.Writeln("") + + return nil +} + +func buildCppDynamicExampleCMake(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string, ExplicitLinking bool) error { + NameSpace := componentdefinition.NameSpace + BaseName := componentdefinition.BaseName + + w.Writeln("cmake_minimum_required(VERSION 3.5)") + + w.Writeln("") + projectName := fmt.Sprintf("%sExample_CPP", NameSpace) + if ExplicitLinking { + projectName += "Dynamic" + } else { + projectName += "Implicit" + } + + w.Writeln("project(%s)", projectName) + w.Writeln("set(CMAKE_CXX_STANDARD 11)") + w.Writeln("add_executable(%s \"${CMAKE_CURRENT_SOURCE_DIR}/%s_example.cpp\")", projectName, NameSpace) + if (ExplicitLinking) { + w.Writeln("if (UNIX)") + w.Writeln(" target_link_libraries(%s ${CMAKE_DL_LIBS})", projectName) + w.Writeln("endif (UNIX)") + } else { + linkFolder := strings.Replace(outputFolder, string(filepath.Separator), "/", -2) + "/../../Implementations/*/*/*" + w.Writeln("find_library(%sLOCATION %s \"%s\")", strings.ToUpper(BaseName), BaseName, linkFolder) + w.Writeln("target_link_libraries(%s ${%sLOCATION})", projectName, strings.ToUpper(BaseName)) + } + // TODO: calculate relative path from ExampleOutputFolder to OUTPUTFOLDER based on CURRENT_SOURCE_DIR + outputFolder = strings.Replace(outputFolder, string(filepath.Separator), "/", -1) + w.Writeln("target_include_directories(%s PRIVATE \"%s\")", projectName, outputFolder) + return nil +} diff --git a/Source/buildbindingcdynamic.go b/Source/buildbindingcdynamic.go deleted file mode 100644 index 4b2d3ee0..00000000 --- a/Source/buildbindingcdynamic.go +++ /dev/null @@ -1,1070 +0,0 @@ -/*++ - -Copyright (C) 2018 Autodesk Inc. (Original Author) - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---*/ - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// buildbindingcdynamic.go -// functions to generate dynamic C-bindings of a library's API in form of dynamically loaded functions -// handles. -////////////////////////////////////////////////////////////////////////////////////////////////////// - -package main - -import ( - "fmt" - "log" - "path" - "strings" - "path/filepath" -) - -// BuildBindingCDynamic builds dyanmic C-bindings of a library's API in form of dynamically loaded functions -// handles. -func BuildBindingCDynamic(component ComponentDefinition, outputFolder string, indentString string) error { - - namespace := component.NameSpace; - libraryname := component.LibraryName; - baseName := component.BaseName; - - DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h"); - log.Printf("Creating \"%s\"", DynamicCHeader) - dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) - if err != nil { - return err; - } - dynhfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), - true) - err = buildDynamicCHeader(component, dynhfile, namespace, baseName, false) - if err != nil { - return err; - } - - DynamicCImpl := path.Join(outputFolder, baseName+"_dynamic.cpp"); - log.Printf("Creating \"%s\"", DynamicCImpl) - dyncppfile, err := CreateLanguageFile(DynamicCImpl, indentString) - if err != nil { - return err; - } - dyncppfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), - true) - - err = buildDynamicCppImplementation(component, dyncppfile, namespace, baseName) - if err != nil { - return err; - } - - return nil; -} - -func buildDynamicCHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, headerOnly bool) error { - w.Writeln("#ifndef __%s_DYNAMICHEADER", strings.ToUpper(NameSpace)) - w.Writeln("#define __%s_DYNAMICHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - w.Writeln("#include \"%s_types.h\"", BaseName) - w.Writeln("") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class definition for %s", class.ClassName) - w.Writeln("**************************************************************************************************************************/") - - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - WriteCMethod(method, w, NameSpace, class.ClassName, false, true) - } - - } - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Global functions") - w.Writeln("**************************************************************************************************************************/") - - global := component.Global; - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - err := WriteCMethod(method, w, NameSpace, "Wrapper", true, true) - if err != nil { - return err - } - - } - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Function Table Structure") - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - w.Writeln("typedef struct {") - w.Writeln(" void * m_LibraryHandle;") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - w.Writeln(" P%s%s_%sPtr m_%s_%s;", NameSpace, class.ClassName, method.MethodName, class.ClassName, method.MethodName) - } - } - - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - w.Writeln(" P%s%sPtr m_%s;", NameSpace, method.MethodName, method.MethodName) - } - - w.Writeln("} s%sDynamicWrapperTable;", NameSpace) - w.Writeln("") - - if (!headerOnly) { - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Load DLL dynamically") - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("%sResult Init%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace, NameSpace) - w.Writeln("%sResult Release%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace, NameSpace) - w.Writeln("%sResult Load%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace, NameSpace) - - w.Writeln("") - } - - w.Writeln("#endif // __%s_DYNAMICHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - return nil -} - - -func buildDynamicCInitTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { - global := component.Global; - - w.Writeln("if (pWrapperTable == nullptr)") - w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) - w.Writeln("") - w.Writeln("pWrapperTable->m_LibraryHandle = nullptr;") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - w.Writeln("pWrapperTable->m_%s_%s = nullptr;", class.ClassName, method.MethodName) - } - } - - global = component.Global - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - w.Writeln("pWrapperTable->m_%s = nullptr;", method.MethodName) - } - - w.Writeln("") - w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) - - return nil; -} - - -func buildDynamicCReleaseTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, initWrapperFunctionName string) error { - - w.Writeln("if (pWrapperTable == nullptr)") - w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) - w.Writeln("") - w.Writeln("if (pWrapperTable->m_LibraryHandle != nullptr) {") - w.Writeln("#ifdef WIN32") - w.Writeln(" HMODULE hModule = (HMODULE) pWrapperTable->m_LibraryHandle;") - w.Writeln(" FreeLibrary (hModule);") - w.Writeln("#else // WIN32") - w.Writeln(" dlclose (pWrapperTable->m_LibraryHandle);") - w.Writeln("#endif // WIN32") - w.Writeln(" return %s (pWrapperTable);", initWrapperFunctionName) - w.Writeln("}") - w.Writeln("") - w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) - - return nil; -} - - -func buildDynamicCLoadTableCode(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { - - global := component.Global; - - w.Writeln("if (pWrapperTable == nullptr)") - w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) - w.Writeln("if (pLibraryFileName == nullptr)") - w.Writeln(" return %s_ERROR_INVALIDPARAM;", strings.ToUpper(NameSpace)) - - w.Writeln("") - - - w.Writeln("#ifdef WIN32") - // TODO: Unicode - w.Writeln("HMODULE hLibrary = LoadLibraryA (pLibraryFileName);") - w.Writeln("if (hLibrary == 0) ") - w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) - w.Writeln("#else // WIN32") - w.Writeln("void* hLibrary = dlopen (pLibraryFileName, RTLD_LAZY);") - w.Writeln("if (hLibrary == 0) ") - w.Writeln(" return %s_ERROR_COULDNOTLOADLIBRARY;", strings.ToUpper(NameSpace)) - w.Writeln("dlerror();"); - w.Writeln("#endif // WIN32") - w.Writeln("") - - for i := 0; i < len(component.Classes); i++ { - - class := component.Classes[i] - for j := 0; j < len(class.Methods); j++ { - - method := class.Methods[j] - w.Writeln("#ifdef WIN32") - w.Writeln("pWrapperTable->m_%s_%s = (P%s%s_%sPtr) GetProcAddress (hLibrary, \"%s_%s_%s%s\");", class.ClassName, method.MethodName, NameSpace, class.ClassName, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName), method.DLLSuffix) - w.Writeln("#else // WIN32") - w.Writeln("pWrapperTable->m_%s_%s = (P%s%s_%sPtr) dlsym (hLibrary, \"%s_%s_%s%s\");", class.ClassName, method.MethodName, NameSpace, class.ClassName, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName), method.DLLSuffix) - w.Writeln("dlerror();") - w.Writeln("#endif // WIN32") - w.Writeln("if (pWrapperTable->m_%s_%s == nullptr)", class.ClassName, method.MethodName) - w.Writeln(" return %s_ERROR_COULDNOTFINDLIBRARYEXPORT;", strings.ToUpper(NameSpace)) - w.Writeln("") - } - } - - global = component.Global - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - w.Writeln("#ifdef WIN32") - w.Writeln("pWrapperTable->m_%s = (P%s%sPtr) GetProcAddress (hLibrary, \"%s_%s%s\");", method.MethodName, NameSpace, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(method.MethodName), method.DLLSuffix) - w.Writeln("#else // WIN32") - w.Writeln("pWrapperTable->m_%s = (P%s%sPtr) dlsym (hLibrary, \"%s_%s%s\");", method.MethodName, NameSpace, method.MethodName, strings.ToLower(NameSpace), strings.ToLower(method.MethodName), method.DLLSuffix) - w.Writeln("dlerror();") - w.Writeln("#endif // WIN32") - - w.Writeln("if (pWrapperTable->m_%s == nullptr)", method.MethodName) - w.Writeln(" return %s_ERROR_COULDNOTFINDLIBRARYEXPORT;", strings.ToUpper(NameSpace)) - w.Writeln("") - } - - w.Writeln("pWrapperTable->m_LibraryHandle = hLibrary;") - w.Writeln("return %s_SUCCESS;", strings.ToUpper(NameSpace)) - - return nil; -} - -func buildDynamicCppImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { - - w.Writeln("#include \"%s_types.h\"", BaseName) - w.Writeln("#include \"%s_dynamic.h\"", BaseName) - - w.Writeln("#ifdef WIN32") - w.Writeln("#include <Windows.h>") - w.Writeln("#else // WIN32") - w.Writeln("#include <dlfcn.h>") - w.Writeln("#endif // WIN32") - - w.Writeln("") - w.Writeln("%sResult Init%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable)", NameSpace, NameSpace, NameSpace) - w.Writeln("{") - - w.AddIndentationLevel(1) - buildDynamicCInitTableCode(component, w, NameSpace, BaseName); - w.AddIndentationLevel(-1) - - w.Writeln("}") - - w.Writeln("") - w.Writeln("%sResult Release%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable)", NameSpace, NameSpace, NameSpace) - w.Writeln("{") - - w.AddIndentationLevel(1) - buildDynamicCReleaseTableCode (component, w, NameSpace, BaseName, "Init" + NameSpace + "WrapperTable"); - w.AddIndentationLevel(-1) - - w.Writeln("}") - - w.Writeln("") - w.Writeln("%sResult Load%sWrapperTable (s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, NameSpace, NameSpace) - w.Writeln("{") - - w.AddIndentationLevel(1) - buildDynamicCLoadTableCode (component, w, NameSpace, BaseName); - w.AddIndentationLevel(-1) - - w.Writeln("}") - w.Writeln("") - - return nil -} - - -func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string) error { - parameters := "" - returntype := "void" - - for k := 0; k < len(method.Params); k++ { - - param := method.Params[k] - variableName := getBindingCppVariableName(param) - - switch param.ParamPass { - case "in": - - if parameters != "" { - parameters = parameters + ", " - } - - cppParamType := getBindingCppParamType(param, NameSpace, true) - - switch param.ParamType { - case "string": - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "struct": - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "structarray", "basicarray": - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "handle": - parameters = parameters + fmt.Sprintf("%s %s", cppParamType, variableName) - - default: - parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, variableName) - } - - case "out": - cppParamType := getBindingCppParamType(param, NameSpace, false) - - if parameters != "" { - parameters = parameters + ", " - } - parameters = parameters + fmt.Sprintf("%s & %s", cppParamType, variableName) - - - case "return": - returntype = getBindingCppParamType(param, NameSpace, false) - - default: - return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - } - - } - - w.Writeln(" inline %s %s (%s);", returntype, method.MethodName, parameters); - - return nil -} - - - -func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool, includeComments bool) error { - - CMethodName := "" - requiresInitCall := false; - initCallParameters := "" // usually used to check sizes of buffers - callParameters := "" - checkErrorCode := "" - makeSharedParameter := ""; - - if isGlobal { - CMethodName = fmt.Sprintf("m_WrapperTable.m_%s", method.MethodName) - checkErrorCode = "CheckError (nullptr," - makeSharedParameter = "this, " - } else { - CMethodName = fmt.Sprintf("m_pWrapper->m_WrapperTable.m_%s_%s", ClassName, method.MethodName) - callParameters = "m_pHandle" - initCallParameters = "m_pHandle" - checkErrorCode = "CheckError (" - makeSharedParameter = "m_pWrapper, " - } - - parameters := "" - returntype := "void" - - definitionCodeLines := []string{} - functionCodeLines := []string{} - returnCodeLines := []string{} - commentcodeLines := []string{} - postCallCodeLines := []string{} - - cppClassPrefix := "C" + NameSpace - cppClassName := cppClassPrefix + ClassName - - for k := 0; k < len(method.Params); k++ { - - param := method.Params[k] - variableName := getBindingCppVariableName(param) - - callParameter := ""; - initCallParameter := ""; - - switch param.ParamPass { - case "in": - - if parameters != "" { - parameters = parameters + ", " - } - - cppParamType := getBindingCppParamType(param, NameSpace, true) - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[in] %s - %s", variableName, param.ParamDescription) ) - - switch param.ParamType { - case "string": - callParameter = variableName + ".c_str()" - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "struct": - callParameter = "&" + variableName - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "structarray", "basicarray": - callParameter = fmt.Sprintf("(%s_uint64)%s.size(), %s.data()", NameSpace, variableName, variableName); - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "handle": - functionCodeLines = append(functionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("if (%s != nullptr) {", variableName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf(" h%s = %s->GetHandle ();", param.ParamName, variableName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("};")) - callParameter = "h" + param.ParamName; - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("%s %s", cppParamType, variableName) - - default: - callParameter = variableName; - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, variableName) - } - - case "out": - cppParamType := getBindingCppParamType(param, NameSpace, false) - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[out] %s - %s", variableName, param.ParamDescription)) - - if parameters != "" { - parameters = parameters + ", " - } - parameters = parameters + fmt.Sprintf("%s & %s", cppParamType, variableName) - - switch param.ParamType { - - case "string": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) - - callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) - - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName) ) - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("s%s = std::string(&buffer%s[0]);", param.ParamName, param.ParamName) ) - - case "handle": - // NOTTESTED - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName) ) - callParameter = fmt.Sprintf("&h%s", param.ParamName) - initCallParameter = callParameter; - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("p%s = std::make_shared<%s%s> (h%s);", param.ParamName, cppClassPrefix, param.ParamClass, param.ParamName) ) - - case "structarray", "basicarray": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsNeeded%s = 0;", NameSpace, param.ParamName) ) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsWritten%s = 0;", NameSpace, param.ParamName) ) - initCallParameter = fmt.Sprintf("0, &elementsNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("%s.resize(elementsNeeded%s);", variableName, param.ParamName)); - callParameter = fmt.Sprintf("elementsNeeded%s, &elementsWritten%s, %s.data()", param.ParamName, param.ParamName, variableName) - - default: - callParameter = "&" + variableName - initCallParameter = callParameter - } - - case "return": - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @return %s", param.ParamDescription) ) - returntype = getBindingCppParamType(param, NameSpace, false) - - switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s result%s = 0;", returntype, param.ParamName) ) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "string": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) - - callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) - - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::string(&buffer%s[0]);", param.ParamName)) - - case "enum": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("e%s%s result%s = (e%s%s) 0;", NameSpace, param.ParamClass, param.ParamName, NameSpace, param.ParamClass)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "struct": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("s%s%s result%s;", NameSpace, param.ParamClass, param.ParamName)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "handle": - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - callParameter = fmt.Sprintf("&h%s", param.ParamName) - initCallParameter = callParameter; - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::make_shared<%s%s> (%sh%s);", cppClassPrefix, param.ParamClass, makeSharedParameter, param.ParamName)) - - case "basicarray": - return fmt.Errorf("can not return basicarray \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - - case "structarray": - return fmt.Errorf("can not return structarray \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - - default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - } - - default: - return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - } - - if callParameters != "" { - callParameters = callParameters + ", " - } - callParameters = callParameters + callParameter; - if (initCallParameters != "") { - initCallParameters = initCallParameters + ", "; - } - initCallParameters = initCallParameters + initCallParameter; - } - - w.Writeln(" ") - if (includeComments) { - w.Writeln(" /**") - w.Writeln(" * %s::%s - %s", cppClassName, method.MethodName, method.MethodDescription) - w.Writelns(" ", commentcodeLines) - w.Writeln(" */") - } - - if (isGlobal) { - w.Writeln(" inline %s %s::%s (%s)", returntype, cppClassName, method.MethodName, parameters) - } else { - w.Writeln(" %s %s::%s (%s)", returntype, cppClassName, method.MethodName, parameters) - } - - w.Writeln(" {") - w.Writelns(" ", definitionCodeLines) - if (requiresInitCall) { - w.Writeln(" %s %s (%s) );", checkErrorCode, CMethodName, initCallParameters) - } - w.Writelns(" ", functionCodeLines) - w.Writeln(" %s %s (%s) );", checkErrorCode, CMethodName, callParameters) - w.Writelns(" ", postCallCodeLines) - w.Writelns(" ", returnCodeLines) - w.Writeln(" }") - - return nil -} - - -func buildDynamicCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { - - global := component.Global - - cppClassPrefix := "C" + NameSpace - - w.Writeln("#ifndef __%s_DYNAMICCPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("#define __%s_DYNAMICCPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - w.Writeln("#include \"%s_types.h\"", BaseName) - w.Writeln("#include \"%s_dynamic.h\"", BaseName) - w.Writeln("") - - w.Writeln("#ifdef WIN32") - w.Writeln("#include <Windows.h>") - w.Writeln("#else // WIN32") - w.Writeln("#include <dlfcn.h>") - w.Writeln("#endif // WIN32") - w.Writeln("#include <string>") - w.Writeln("#include <memory>") - w.Writeln("#include <vector>") - w.Writeln("#include <exception>") - w.Writeln("") - - w.Writeln("namespace %s {", NameSpace) - w.Writeln("") - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Forward Declaration of all classes ") - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - - w.Writeln("class %sBaseClass;", cppClassPrefix) - w.Writeln("class %sWrapper;", cppClassPrefix) - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - w.Writeln("class %s%s;", cppClassPrefix, class.ClassName) - } - - w.Writeln("") - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Declaration of shared pointer types ") - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("") - - w.Writeln("typedef std::shared_ptr<%sBaseClass> P%sBaseClass;", cppClassPrefix, NameSpace) - w.Writeln("typedef std::shared_ptr<%sWrapper> P%sWrapper;", cppClassPrefix, NameSpace) - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - w.Writeln("typedef std::shared_ptr<%s%s> P%s%s;", cppClassPrefix, class.ClassName, NameSpace, class.ClassName) - } - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class E%sException ", NameSpace) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("class E%sException : public std::exception {", NameSpace) - w.Writeln("protected:") - w.Writeln(" /**") - w.Writeln(" * Error code for the Exception.") - w.Writeln(" */") - w.Writeln(" %sResult m_errorCode;", NameSpace) - w.Writeln(" /**") - w.Writeln(" * Error message for the Exception.") - w.Writeln(" */") - w.Writeln(" std::string m_errorMessage;") - w.Writeln("") - w.Writeln("public:") - w.Writeln(" /**") - w.Writeln(" * Exception Constructor.") - w.Writeln(" */") - w.Writeln(" E%sException (%sResult errorCode)", NameSpace, NameSpace) - w.Writeln(" : m_errorMessage(\"%s Error \" + std::to_string (errorCode))", NameSpace) - w.Writeln(" {") - w.Writeln(" m_errorCode = errorCode;") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * Returns error code") - w.Writeln(" */") - w.Writeln(" %sResult getErrorCode ()", NameSpace) - w.Writeln(" {") - w.Writeln(" return m_errorCode;") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * Returns error message") - w.Writeln(" */") - w.Writeln(" const char* what () const noexcept") - w.Writeln(" {") - w.Writeln(" return m_errorMessage.c_str();") - w.Writeln(" }") - w.Writeln("") - - w.Writeln("};") - - w.Writeln("") - - err := writeCPPInputVector(w, NameSpace) - if err != nil { - return err - } - w.Writeln("") - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %sWrapper ", cppClassPrefix) - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("class %sWrapper {", cppClassPrefix) - w.Writeln("public:") - - w.Writeln(" ") - w.Writeln(" %sWrapper (const std::string &sFileName)", cppClassPrefix) - w.Writeln(" {") - w.Writeln(" CheckError (nullptr, initWrapperTable (&m_WrapperTable));") - w.Writeln(" CheckError (nullptr, loadWrapperTable (&m_WrapperTable, sFileName.c_str ()));") - w.Writeln(" ") - w.Writeln(" CheckError(nullptr, checkBinaryVersion());") - w.Writeln(" }") - w.Writeln(" ") - - w.Writeln(" static P%sWrapper loadLibrary (const std::string &sFileName)", NameSpace) - w.Writeln(" {"); - w.Writeln(" return std::make_shared<%sWrapper> (sFileName);", cppClassPrefix); - w.Writeln(" }") - w.Writeln(" ") - - - w.Writeln(" ~%sWrapper ()", cppClassPrefix) - w.Writeln(" {") - w.Writeln(" releaseWrapperTable (&m_WrapperTable);") - w.Writeln(" }") - w.Writeln(" ") - - w.Writeln(" void CheckError(%sHandle handle, %sResult nResult)", NameSpace, NameSpace) - w.Writeln(" {") - w.Writeln(" if (nResult != 0) ") - w.Writeln(" throw E%sException (nResult);", NameSpace) - w.Writeln(" }") - w.Writeln(" ") - - w.Writeln("") - - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - - err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, "Wrapper") - if err != nil { - return err - } - } - - w.Writeln("") - w.Writeln("private:") - w.Writeln(" s%sDynamicWrapperTable m_WrapperTable;", NameSpace) - w.Writeln("") - - w.Writeln(" %sResult checkBinaryVersion()", NameSpace) - w.Writeln(" {") - w.Writeln(" %s_uint32 nMajor, nMinor, nMicro;", NameSpace) - w.Writeln(" %s(nMajor, nMinor, nMicro);", global.VersionMethod) - w.Writeln(" if ( (nMajor != %s_VERSION_MAJOR) || (nMinor < %s_VERSION_MINOR) ) {", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace) ) - w.Writeln(" return %s_ERROR_INCOMPATIBLEBINARYVERSION;", strings.ToUpper(NameSpace)) - w.Writeln(" }") - w.Writeln(" return %s_SUCCESS;", strings.ToUpper(NameSpace)) - w.Writeln(" }") - - w.Writeln(" %sResult initWrapperTable (s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) - w.Writeln(" %sResult releaseWrapperTable (s%sDynamicWrapperTable * pWrapperTable);", NameSpace, NameSpace) - w.Writeln(" %sResult loadWrapperTable (s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName);", NameSpace, NameSpace) - w.Writeln("") - for i := 0; i < len(component.Classes); i++ { - - class := component.Classes[i] - cppClassName := cppClassPrefix + class.ClassName - w.Writeln(" friend class %s;", cppClassName) - - } - w.Writeln("") - w.Writeln("};") - w.Writeln("") - - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %sBaseClass ", cppClassPrefix) - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("class %sBaseClass {", cppClassPrefix) - w.Writeln("protected:") - w.Writeln(" /* Wrapper Object that created the class..*/") - w.Writeln(" %sWrapper * m_pWrapper;", cppClassPrefix) - w.Writeln(" /* Handle to Instance in library*/") - w.Writeln(" %sHandle m_pHandle;", NameSpace) - w.Writeln("") - w.Writeln(" /* Checks for an Error code and raises Exceptions */") - w.Writeln(" void CheckError(%sResult nResult)", NameSpace) - w.Writeln(" {") - w.Writeln(" if (m_pWrapper != nullptr)") - w.Writeln(" m_pWrapper->CheckError (m_pHandle, nResult);") - w.Writeln(" }") - w.Writeln("") - w.Writeln("public:") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::%sBaseClass - Constructor for Base class.", cppClassPrefix, cppClassPrefix) - w.Writeln(" */") - w.Writeln(" %sBaseClass(%sWrapper * pWrapper, %sHandle pHandle)", cppClassPrefix, cppClassPrefix, NameSpace) - w.Writeln(" : m_pWrapper (pWrapper), m_pHandle (pHandle)") - w.Writeln(" {") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::~%sBaseClass - Destructor for Base class.", cppClassPrefix, cppClassPrefix) - w.Writeln(" */") - - w.Writeln(" virtual ~%sBaseClass()", cppClassPrefix) - w.Writeln(" {") - w.Writeln(" if (m_pWrapper != nullptr)") - w.Writeln(" m_pWrapper->%s (this);", component.Global.ReleaseMethod) - w.Writeln(" m_pWrapper = nullptr;") - w.Writeln(" }") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::GetHandle - Returns handle to instance.", cppClassPrefix) - w.Writeln(" */") - w.Writeln(" %sHandle GetHandle()", NameSpace) - w.Writeln(" {") - w.Writeln(" return m_pHandle;") - w.Writeln(" }") - w.Writeln("};") - - w.Writeln(" ") - - for i := 0; i < len(component.Classes); i++ { - - class := component.Classes[i] - cppClassName := cppClassPrefix + class.ClassName - - parentClassName := class.ParentClass - if parentClassName == "" { - parentClassName = "BaseClass" - } - cppParentClassName := cppClassPrefix + parentClassName - - w.Writeln(" ") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %s ", cppClassName) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("class %s : public %s {", cppClassName, cppParentClassName) - w.Writeln("public:") - w.Writeln(" ") - w.Writeln(" /**") - w.Writeln(" * %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) - w.Writeln(" */") - w.Writeln(" %s (%sWrapper * pWrapper, %sHandle pHandle)", cppClassName, cppClassPrefix, NameSpace) - w.Writeln(" : %s (pWrapper, pHandle)", cppParentClassName); - w.Writeln(" {") - w.Writeln(" }") - w.Writeln(" ") - - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - - err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, cppClassName) - if err != nil { - return err - } - } - w.Writeln("};") - } - - - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - - err := writeDynamicCPPMethod(method, w, NameSpace, "Wrapper", true, true) - if err != nil { - return err - } - } - - w.Writeln("") - w.Writeln(" inline %sResult %sWrapper::initWrapperTable (s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCInitTableCode (component, w, NameSpace, BaseName); - w.AddIndentationLevel(-2) - - w.Writeln(" }") - w.Writeln("") - - w.Writeln(" inline %sResult %sWrapper::releaseWrapperTable (s%sDynamicWrapperTable * pWrapperTable)", NameSpace, cppClassPrefix, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCReleaseTableCode (component, w, NameSpace, BaseName, "initWrapperTable"); - w.AddIndentationLevel(-2) - - w.Writeln(" }") - w.Writeln("") - - w.Writeln(" inline %sResult %sWrapper::loadWrapperTable (s%sDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName)", NameSpace, cppClassPrefix, NameSpace) - w.Writeln(" {") - - w.AddIndentationLevel(2) - buildDynamicCLoadTableCode (component, w, NameSpace, BaseName); - w.AddIndentationLevel(-2) - - w.Writeln(" }") - - w.Writeln(" ") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - cppClassName := cppClassPrefix + class.ClassName - w.Writeln(" ") - w.Writeln(" /**") - w.Writeln(" * Method definitions for class %s", cppClassName ) - w.Writeln(" */") - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, class.ClassName, false, false) - if err != nil { - return err - } - } - } - - w.Writeln("") - - w.Writeln("} // namespace %s", NameSpace) - w.Writeln("") - - w.Writeln("#endif // __%s_DYNAMICCPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - return nil -} - - - -// BuildBindingCppDynamic builds dynamic headeronly C++-bindings of a library's API in form of dynamically loaded functions -// handles. -func BuildBindingCppDynamic(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { - forceRecreation := false - - namespace := component.NameSpace; - libraryname := component.LibraryName; - baseName := component.BaseName; - - DynamicCHeader := path.Join(outputFolder, baseName+"_dynamic.h"); - log.Printf("Creating \"%s\"", DynamicCHeader) - dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) - if err != nil { - return err; - } - dynhfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", libraryname), - true) - err = buildDynamicCHeader(component, dynhfile, namespace, baseName, true) - if err != nil { - return err; - } - - DynamicCppHeader := path.Join(outputFolder, baseName+"_dynamic.hpp"); - log.Printf("Creating \"%s\"", DynamicCppHeader) - dynhppfile, err := CreateLanguageFile(DynamicCppHeader, indentString) - if err != nil { - return err; - } - dynhppfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++ Header file in order to allow an easy\n use of %s", libraryname), - true) - err = buildDynamicCppHeader(component, dynhppfile, namespace, baseName) - if err != nil { - return err; - } - - if (len(outputFolderExample) > 0) { - DynamicCPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp"); - if (forceRecreation || !FileExists(DynamicCPPExample)) { - log.Printf("Creating \"%s\"", DynamicCPPExample) - dyncppexamplefile, err := CreateLanguageFile (DynamicCPPExample, " ") - if err != nil { - return err; - } - dyncppexamplefile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), - true) - buildDynamicCppExample(component, dyncppexamplefile, outputFolder) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPExample) - } - - DynamicCPPCMake := path.Join(outputFolderExample, "CMakeLists.txt"); - if (forceRecreation || !FileExists(DynamicCPPCMake)) { - log.Printf("Creating \"%s\"", DynamicCPPCMake) - dyncppcmake, err := CreateLanguageFile (DynamicCPPCMake, " ") - if err != nil { - return err; - } - dyncppcmake.WriteCMakeLicenseHeader(component, - fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the Dynamic C++ bindings of %s", libraryname), - true) - buildDynamicCppExampleCMake(component, dyncppcmake, outputFolder) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", DynamicCPPCMake) - } - } - - return nil; -} - - -func buildDynamicCppExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { - NameSpace := componentdefinition.NameSpace - BaseName := componentdefinition.BaseName - - w.Writeln("#include <iostream>") - w.Writeln("#include \"%s_dynamic.hpp\"", strings.ToLower(BaseName) ) - w.Writeln("") - w.Writeln("") - - w.Writeln("int main()") - w.Writeln("{") - w.Writeln(" try") - w.Writeln(" {") - w.Writeln(" std::string libpath = (\"\"); // TODO: put the location of the %s-library file here.", NameSpace) - w.Writeln(" auto wrapper = %s::C%sWrapper::loadLibrary(libpath + \"/%s.\"); // TODO: add correct suffix of the library", NameSpace, NameSpace, BaseName) - w.Writeln(" unsigned int nMajor, nMinor, nMicro;") - w.Writeln(" wrapper->%s(nMajor, nMinor, nMicro);", componentdefinition.Global.VersionMethod) - w.Writeln(" std::cout << \"%s.Version = \" << nMajor << \".\" << nMinor << \".\" << nMicro << std::endl;", NameSpace); - w.Writeln(" }") - w.Writeln(" catch (std::exception &e)") - w.Writeln(" {") - w.Writeln(" std::cout << e.what() << std::endl;") - w.Writeln(" return 1;") - w.Writeln(" }") - w.Writeln(" return 0;") - w.Writeln("}") - w.Writeln("") - - return nil -} - -func buildDynamicCppExampleCMake(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { - NameSpace := componentdefinition.NameSpace - - w.Writeln("cmake_minimum_required(VERSION 3.5)") - - w.Writeln("") - w.Writeln("project(%sExample_CPPDynamic)", NameSpace) - w.Writeln("set (CMAKE_CXX_STANDARD 11)") - w.Writeln("add_executable(%sExample_CPPDynamic \"${CMAKE_CURRENT_SOURCE_DIR}/%s_example.cpp\")", NameSpace, NameSpace) - w.Writeln("if (UNIX)") - w.Writeln(" target_link_libraries(%sExample_CPPDynamic ${CMAKE_DL_LIBS})", NameSpace) - w.Writeln("endif (UNIX)") - // TODO: calculate relative path from ExampleOutputFolder to OUTPUTFOLDER based on CURRENT_SOURCE_DIR - outputFolder = strings.Replace(outputFolder, string(filepath.Separator), "/", -1) - w.Writeln("target_include_directories(%sExample_CPPDynamic PRIVATE \"%s\")", NameSpace, outputFolder) - return nil -} diff --git a/Source/buildbindingcpp.go b/Source/buildbindingcpp.go deleted file mode 100644 index 7e807999..00000000 --- a/Source/buildbindingcpp.go +++ /dev/null @@ -1,795 +0,0 @@ -/*++ - -Copyright (C) 2018 Autodesk Inc. (Original Author) - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---*/ - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// buildbindingcpp.go -// functions to generate C++-bindings of a library's API in form of automatically implemented C++- -// wrapper classes. -////////////////////////////////////////////////////////////////////////////////////////////////////// - -package main - -import ( - "fmt" - "log" - "path" - "strings" - "path/filepath" -) - -// BuildBindingCPP builds C++-bindings of a library's API in form of automatically implemented C++- -// wrapper classes. -func BuildBindingCPP(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { - namespace := component.NameSpace; - libraryname := component.LibraryName; - baseName := component.BaseName; - forceRecreation := true - - CppHeaderName := path.Join(outputFolder, baseName+".hpp"); - log.Printf("Creating \"%s\"", CppHeaderName) - hppfile, err :=CreateLanguageFile(CppHeaderName, indentString) - if err != nil { - return err - } - - CppImplName := path.Join(outputFolder, baseName+".cpp"); - log.Printf("Creating \"%s\"", CppImplName) - cppfile, err :=CreateLanguageFile(CppImplName, indentString) - if err != nil { - return err - } - - WriteLicenseHeader(hppfile.Writer, component, - fmt.Sprintf("This is an autogenerated C++ Header file in order to allow an easy use\n of %s", libraryname), - true) - WriteLicenseHeader(cppfile.Writer, component, - fmt.Sprintf("This is an autogenerated C++ Wrapper Implementation file in order to allow \nan easy use of %s", libraryname), - true) - - err = buildCPPHeaderAndImplementation(component, hppfile, cppfile, namespace, baseName) - if err != nil { - return err - } - - if (len(outputFolderExample) > 0) { - CPPExample := path.Join(outputFolderExample, namespace+"_example"+".cpp"); - if (forceRecreation || !FileExists(CPPExample)) { - log.Printf("Creating \"%s\"", CPPExample) - cppexamplefile, err := CreateLanguageFile (CPPExample, " ") - if err != nil { - return err; - } - cppexamplefile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated C++ application that demonstrates the\n usage of the C++ bindings of %s", libraryname), - true) - buildCppExample(component, cppexamplefile, outputFolder) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", CPPExample) - } - - CPPCMake := path.Join(outputFolderExample, "CMakeLists.txt"); - if (forceRecreation || !FileExists(CPPCMake)) { - log.Printf("Creating \"%s\"", CPPCMake) - cppcmake, err := CreateLanguageFile (CPPCMake, " ") - if err != nil { - return err; - } - cppcmake.WriteCMakeLicenseHeader(component, - fmt.Sprintf("This is an autogenerated CMake Project that demonstrates the\n usage of the C++ bindings of %s", libraryname), - true) - buildCppExampleCMake(component, cppcmake, outputFolder) - } else { - log.Printf("Omitting recreation of C++Dynamic example file \"%s\"", CPPCMake) - } - } - return nil -} - -func buildCPPHeaderAndImplementation(component ComponentDefinition, w LanguageWriter, cppimplw LanguageWriter, NameSpace string, BaseName string) error { - // Header start code - w.Writeln("") - w.Writeln("#ifndef __%s_CPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("#define __%s_CPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - w.Writeln("#include \"%s.h\"", BaseName) - - w.Writeln("#include <string>") - w.Writeln("#include <memory>") - w.Writeln("#include <vector>") - w.Writeln("#include <exception>") - w.Writeln("") - - w.Writeln("namespace %s {", NameSpace) - w.Writeln("") - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Forward Declaration of all classes ") - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - - cppClassPrefix := "C" + NameSpace - - w.Writeln("class %sBaseClass;", cppClassPrefix) - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - w.Writeln("class %s%s;", cppClassPrefix, class.ClassName) - } - - w.Writeln("") - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Declaration of shared pointer types ") - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("") - - w.Writeln("typedef std::shared_ptr<%sBaseClass> P%sBaseClass;", cppClassPrefix, NameSpace) - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - w.Writeln("typedef std::shared_ptr<%s%s> P%s%s;", cppClassPrefix, class.ClassName, NameSpace, class.ClassName) - } - - w.Writeln(" ") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class E%sException ", NameSpace) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("class E%sException : public std::exception {", NameSpace) - w.Writeln(" protected:") - w.Writeln(" /**") - w.Writeln(" * Error code for the Exception.") - w.Writeln(" */") - w.Writeln(" %sResult m_errorCode;", NameSpace) - w.Writeln(" /**") - w.Writeln(" * Error message for the Exception.") - w.Writeln(" */") - w.Writeln(" std::string m_errorMessage;") - w.Writeln("") - w.Writeln(" public:") - w.Writeln(" /**") - w.Writeln(" * Exception Constructor.") - w.Writeln(" */") - w.Writeln(" E%sException (%sResult errorCode);", NameSpace, NameSpace) - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * Returns error code") - w.Writeln(" */") - w.Writeln(" %sResult getErrorCode ();", NameSpace) - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * Returns error message") - w.Writeln(" */") - w.Writeln(" const char* what () const noexcept;") - w.Writeln("") - - w.Writeln("};") - - w.Writeln("") - err := writeCPPInputVector(w, NameSpace) - if err != nil { - return err - } - w.Writeln("") - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %sBaseClass ", cppClassPrefix) - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("class %sBaseClass {", cppClassPrefix) - w.Writeln("protected:") - - w.Writeln(" /* Handle to Instance in library*/") - w.Writeln(" %sHandle m_pHandle;", NameSpace) - w.Writeln("") - w.Writeln(" /* Checks for an Error code and raises Exceptions */") - w.Writeln(" void CheckError(%sResult nResult);", NameSpace) - w.Writeln("public:") - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::%sBaseClass - Constructor for Base class.", cppClassPrefix, cppClassPrefix) - w.Writeln(" */") - w.Writeln(" %sBaseClass(%sHandle pHandle);", cppClassPrefix, NameSpace) - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::~%sBaseClass - Destructor for Base class.", cppClassPrefix, cppClassPrefix) - w.Writeln(" */") - - w.Writeln(" virtual ~%sBaseClass();", cppClassPrefix) - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %sBaseClass::GetHandle - Returns handle to instance.", cppClassPrefix) - w.Writeln(" */") - w.Writeln(" %sHandle GetHandle();", NameSpace) - w.Writeln("};") - - // Implementation start code - cppimplw.Writeln("#include \"%s.hpp\"", BaseName) - cppimplw.Writeln("") - cppimplw.Writeln("#include <vector>") - cppimplw.Writeln("") - cppimplw.Writeln("namespace %s {", NameSpace) - cppimplw.Writeln("") - cppimplw.Writeln("/*************************************************************************************************************************") - cppimplw.Writeln(" Class E%sException ", NameSpace) - cppimplw.Writeln("**************************************************************************************************************************/") - cppimplw.Writeln(" E%sException::E%sException(%sResult errorCode)", NameSpace, NameSpace, NameSpace) - cppimplw.Writeln(" : m_errorMessage(\"%s Error \" + std::to_string (errorCode))", NameSpace) - cppimplw.Writeln(" {") - cppimplw.Writeln(" m_errorCode = errorCode;") - cppimplw.Writeln(" }") - cppimplw.Writeln("") - cppimplw.Writeln(" %sResult E%sException::getErrorCode ()", NameSpace, NameSpace) - cppimplw.Writeln(" {") - cppimplw.Writeln(" return m_errorCode;") - cppimplw.Writeln(" }") - - cppimplw.Writeln("") - cppimplw.Writeln(" const char* E%sException::what () const noexcept", NameSpace) - cppimplw.Writeln(" {") - cppimplw.Writeln(" return m_errorMessage.c_str();") - cppimplw.Writeln(" }") - - cppimplw.Writeln("") - cppimplw.Writeln("/*************************************************************************************************************************") - cppimplw.Writeln(" Class %sBaseClass ", cppClassPrefix) - cppimplw.Writeln("**************************************************************************************************************************/") - cppimplw.Writeln("") - cppimplw.Writeln("%sBaseClass::%sBaseClass(%sHandle pHandle)", cppClassPrefix, cppClassPrefix, NameSpace) - cppimplw.Writeln("{") - cppimplw.Writeln(" m_pHandle = pHandle;") - cppimplw.Writeln("}") - cppimplw.Writeln("") - cppimplw.Writeln("%sBaseClass::~%sBaseClass()", cppClassPrefix, cppClassPrefix) - cppimplw.Writeln("{") - cppimplw.Writeln(" %sWrapper::%s(this);", cppClassPrefix, component.Global.ReleaseMethod) - cppimplw.Writeln("}") - cppimplw.Writeln("") - cppimplw.Writeln("void %sBaseClass::CheckError(%sResult nResult)", cppClassPrefix, NameSpace) - cppimplw.Writeln("{") - cppimplw.Writeln(" %sWrapper::CheckError(m_pHandle, nResult);", cppClassPrefix) - cppimplw.Writeln("}") - cppimplw.Writeln("") - cppimplw.Writeln("%sHandle %sBaseClass::GetHandle()", NameSpace, cppClassPrefix) - cppimplw.Writeln("{") - cppimplw.Writeln(" return m_pHandle;") - cppimplw.Writeln("}") - cppimplw.Writeln("") - - for i := 0; i < len(component.Classes); i++ { - - class := component.Classes[i] - cppClassName := cppClassPrefix + class.ClassName - - parentClassName := class.ParentClass - if parentClassName == "" { - parentClassName = "BaseClass" - } - cppParentClassName := cppClassPrefix + parentClassName - - w.Writeln(" ") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %s ", cppClassName) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("class %s : public %s {", cppClassName, cppParentClassName) - w.Writeln("public:") - w.Writeln(" ") - w.Writeln(" /**") - w.Writeln(" * %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) - w.Writeln(" */") - w.Writeln(" %s (%sHandle pHandle);", cppClassName, NameSpace) - - cppimplw.Writeln(" ") - cppimplw.Writeln("/*************************************************************************************************************************") - cppimplw.Writeln(" Class %s ", cppClassName) - cppimplw.Writeln("**************************************************************************************************************************/") - cppimplw.Writeln("/**") - cppimplw.Writeln("* %s::%s - Constructor for %s class.", cppClassName, cppClassName, class.ClassName) - cppimplw.Writeln("*/") - cppimplw.Writeln("%s::%s (%sHandle pHandle)", cppClassName, cppClassName, NameSpace) - cppimplw.Writeln(" : %s (pHandle)", cppParentClassName) - cppimplw.Writeln("{ }") - - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - - err := writeCPPMethod(method, w, cppimplw, NameSpace, class.ClassName, false) - if err != nil { - return err - } - - } - - w.Writeln("};") - - } - - // Global functions - w.Writeln(" ") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class %sWrapper ", cppClassPrefix) - w.Writeln("**************************************************************************************************************************/") - - w.Writeln("class %sWrapper {", cppClassPrefix) - w.Writeln("public:") - - w.Writeln(" static void CheckError(%sHandle handle, %sResult nResult);", NameSpace, NameSpace) - - global := component.Global; - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - - err := writeCPPMethod(method, w, cppimplw, NameSpace, "Wrapper", true) - if err != nil { - return err - } - } - - w.Writeln("};") - - w.Writeln("") - w.Writeln("};") - w.Writeln("") - w.Writeln("#endif // __%s_CPPHEADER", strings.ToUpper(NameSpace)) - w.Writeln("") - - cppimplw.Writeln("") - cppimplw.Writeln("void %sWrapper::CheckError(%sHandle handle, %sResult nResult)", cppClassPrefix, NameSpace, NameSpace) - cppimplw.Writeln("{") - cppimplw.Writeln(" if (nResult != 0) ") - cppimplw.Writeln(" throw E%sException (nResult);", NameSpace) - cppimplw.Writeln("}") - cppimplw.Writeln("") - - cppimplw.Writeln("") - cppimplw.Writeln("}; // end namespace %s", NameSpace) - cppimplw.Writeln("") - - return nil -} - -func writeCPPInputVector(w LanguageWriter, NameSpace string) (error) { - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class C%sInputVector", NameSpace) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("template <typename T>") - w.Writeln("class C%sInputVector {", NameSpace) - w.Writeln("private:") - w.Writeln(" ") - w.Writeln(" const T* m_data;") - w.Writeln(" size_t m_size;") - w.Writeln(" ") - w.Writeln("public:") - w.Writeln(" ") - w.Writeln(" C%sInputVector( const std::vector<T>& vec)", NameSpace) - w.Writeln(" : m_data( vec.data() ), m_size( vec.size() )"); - w.Writeln(" {") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln(" C%sInputVector( const T* in_data, size_t in_size)", NameSpace) - w.Writeln(" : m_data( in_data ), m_size(in_size )"); - w.Writeln(" {") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln(" const T* data() const") - w.Writeln(" {") - w.Writeln(" return m_data;") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln(" size_t size() const") - w.Writeln(" {") - w.Writeln(" return m_size;") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln("};") - return nil -} - -func getBindingCppParamType (param ComponentDefinitionParam, NameSpace string, isInput bool) (string) { - cppClassPrefix := "C" + NameSpace; - switch (param.ParamType) { - case "uint8": - return fmt.Sprintf ("%s_uint8", NameSpace); - case "uint16": - return fmt.Sprintf ("%s_uint16", NameSpace); - case "uint32": - return fmt.Sprintf ("%s_uint32", NameSpace); - case "uint64": - return fmt.Sprintf ("%s_uint64", NameSpace); - case "int8": - return fmt.Sprintf ("%s_int8", NameSpace); - case "int16": - return fmt.Sprintf ("%s_int16", NameSpace); - case "int32": - return fmt.Sprintf ("%s_int32", NameSpace); - case "int64": - return fmt.Sprintf ("%s_int64", NameSpace); - case "string": - return fmt.Sprintf ("std::string"); - case "bool": - return fmt.Sprintf ("bool"); - case "single": - return fmt.Sprintf ("float"); - case "basicarray": - cppBasicType := ""; - switch (param.ParamClass) { - case "uint8": - cppBasicType = fmt.Sprintf ("%s_uint8", NameSpace); - case "uint16": - cppBasicType = fmt.Sprintf ("%s_uint16", NameSpace); - case "uint32": - cppBasicType = fmt.Sprintf ("%s_uint32", NameSpace); - case "uint64": - cppBasicType = fmt.Sprintf ("%s_uint64", NameSpace); - case "int8": - cppBasicType = fmt.Sprintf ("%s_int8", NameSpace); - case "int16": - cppBasicType = fmt.Sprintf ("%s_int16", NameSpace); - case "int32": - cppBasicType = fmt.Sprintf ("%s_int32", NameSpace); - case "int64": - cppBasicType = fmt.Sprintf ("%s_int64", NameSpace); - case "bool": - cppBasicType = "bool"; - case "single": - cppBasicType =fmt.Sprintf ("%s_single", NameSpace); - case "double": - cppBasicType = fmt.Sprintf ("%s_double", NameSpace); - default: - log.Fatal ("Invalid parameter type: ", param.ParamClass); - } - if (isInput) { - return fmt.Sprintf ("C%sInputVector<%s>", NameSpace, cppBasicType); - } - return fmt.Sprintf ("std::vector<%s>", cppBasicType); - case "structarray": - if (isInput) { - return fmt.Sprintf ("C%sInputVector<s%s%s>", NameSpace, NameSpace, param.ParamClass); - } - return fmt.Sprintf ("std::vector<s%s%s>", NameSpace, param.ParamClass); - case "double": - return fmt.Sprintf ("%s_double", NameSpace); - case "enum": - return fmt.Sprintf ("e%s%s", NameSpace, param.ParamClass); - case "struct": - return fmt.Sprintf ("s%s%s", NameSpace, param.ParamClass); - case "handle": - if (isInput) { - return fmt.Sprintf ("%s%s *", cppClassPrefix, param.ParamClass); - } - return fmt.Sprintf ("P%s%s", NameSpace, param.ParamClass); - case "functiontype": - return fmt.Sprintf ("%s%s", NameSpace, param.ParamClass); - } - - log.Fatal ("Invalid parameter type: ", param.ParamType); - return ""; -} - -func getBindingCppVariableName (param ComponentDefinitionParam) (string) { - switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": - return "n" + param.ParamName; - case "string": - return "s" + param.ParamName; - case "bool": - return "b" + param.ParamName; - case "single": - return "f" + param.ParamName; - case "basicarray", "structarray": - return param.ParamName + "Buffer"; - case "double": - return "d" + param.ParamName; - case "enum": - return "e" + param.ParamName; - case "struct": - return param.ParamName; - case "handle": - return "p" + param.ParamName; - case "functiontype": - return fmt.Sprintf ("p%s", param.ParamName); - } - - log.Fatal ("Invalid parameter type: ", param.ParamType); - - return ""; -} - -func writeCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, cppimplw LanguageWriter, NameSpace string, ClassName string, isGlobal bool) error { - - CMethodName := "" - requiresInitCall := false; - initCallParameters := "" // usually used to check sizes of buffers - callParameters := "" - staticPrefix := "" - checkErrorCode := "" - - if isGlobal { - CMethodName = fmt.Sprintf("%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName), method.DLLSuffix) - staticPrefix = "static " - checkErrorCode = "CheckError (nullptr," - } else { - CMethodName = fmt.Sprintf("%s_%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName), method.DLLSuffix) - callParameters = "m_pHandle" - initCallParameters = "m_pHandle" - checkErrorCode = "CheckError (" - } - - parameters := "" - returntype := "void" - - definitionCodeLines := []string{} - functionCodeLines := []string{} - returnCodeLines := []string{} - commentcodeLines := []string{} - postCallCodeLines := []string{} - - cppClassPrefix := "C" + NameSpace - cppClassName := cppClassPrefix + ClassName - - for k := 0; k < len(method.Params); k++ { - - param := method.Params[k] - variableName := getBindingCppVariableName(param) - - callParameter := ""; - initCallParameter := ""; - - switch param.ParamPass { - case "in": - - if parameters != "" { - parameters = parameters + ", " - } - - cppParamType := getBindingCppParamType(param, NameSpace, true) - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[in] %s - %s", variableName, param.ParamDescription)) - - switch param.ParamType { - case "string": - callParameter = variableName + ".c_str()" - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "struct": - callParameter = "&" + variableName - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "structarray", "basicarray": - callParameter = fmt.Sprintf("(%s_uint64)%s.size(), %s.data()", NameSpace, variableName, variableName); - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s & %s", cppParamType, variableName); - case "handle": - functionCodeLines = append(functionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("if (%s != nullptr) {", variableName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf(" h%s = %s->GetHandle ();", param.ParamName, variableName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("};")) - callParameter = "h" + param.ParamName; - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("%s %s", cppParamType, variableName) - - default: - callParameter = variableName; - initCallParameter = callParameter; - parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, variableName) - } - - case "out": - cppParamType := getBindingCppParamType(param, NameSpace, false) - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @param[out] %s - %s", variableName, param.ParamDescription)) - - if parameters != "" { - parameters = parameters + ", " - } - parameters = parameters + fmt.Sprintf("%s & %s", cppParamType, variableName) - - switch param.ParamType { - - case "string": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) - - callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) - - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName)) - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("s%s = std::string(&buffer%s[0]);", param.ParamName, param.ParamName)) - - case "handle": - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - callParameter = fmt.Sprintf("&h%s", param.ParamName) - initCallParameter = callParameter; - postCallCodeLines = append(postCallCodeLines, fmt.Sprintf("p%s = std::make_shared<%s%s> (h%s);", param.ParamName, cppClassPrefix, param.ParamClass, param.ParamName)) - - case "structarray", "basicarray": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsNeeded%s = 0;", NameSpace, param.ParamName)) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint64 elementsWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &elementsNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("%s.resize(elementsNeeded%s);", variableName, param.ParamName)) - callParameter = fmt.Sprintf("elementsNeeded%s, &elementsWritten%s, %s.data()", param.ParamName, param.ParamName, variableName) - - default: - callParameter = "&" + variableName - initCallParameter = callParameter - } - - case "return": - - commentcodeLines = append(commentcodeLines, fmt.Sprintf("* @return %s", param.ParamDescription)) - returntype = getBindingCppParamType(param, NameSpace, false) - - switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s result%s = 0;", returntype, param.ParamName)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "string": - requiresInitCall = true; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesNeeded%s = 0;", NameSpace, param.ParamName)) - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%s_uint32 bytesWritten%s = 0;", NameSpace, param.ParamName)) - initCallParameter = fmt.Sprintf("0, &bytesNeeded%s, nullptr", param.ParamName); - - functionCodeLines = append(functionCodeLines, fmt.Sprintf("std::vector<char> buffer%s;", param.ParamName)) - functionCodeLines = append(functionCodeLines, fmt.Sprintf("buffer%s.resize(bytesNeeded%s + 2);", param.ParamName, param.ParamName)) - - callParameter = fmt.Sprintf("bytesNeeded%s + 2, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) - - returnCodeLines = append(returnCodeLines, fmt.Sprintf("buffer%s[bytesNeeded%s + 1] = 0;", param.ParamName, param.ParamName)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::string(&buffer%s[0]);", param.ParamName)) - - case "enum": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("e%s%s result%s = (e%s%s) 0;", NameSpace, param.ParamClass, param.ParamName, NameSpace, param.ParamClass)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "struct": - callParameter = fmt.Sprintf("&result%s", param.ParamName) - initCallParameter = callParameter; - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("s%s%s result%s;", NameSpace, param.ParamClass, param.ParamName)) - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return result%s;", param.ParamName)) - - case "handle": - definitionCodeLines = append(definitionCodeLines, fmt.Sprintf("%sHandle h%s = nullptr;", NameSpace, param.ParamName)) - callParameter = fmt.Sprintf("&h%s", param.ParamName) - initCallParameter = callParameter; - returnCodeLines = append(returnCodeLines, fmt.Sprintf("return std::make_shared<%s%s> (h%s);", cppClassPrefix, param.ParamClass, param.ParamName)) - - case "basicarray": - return fmt.Errorf("can not return basicarray \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - - case "structarray": - return fmt.Errorf("can not return structarray \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - - default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - } - - default: - return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) - } - - if callParameters != "" { - callParameters = callParameters + ", " - } - callParameters = callParameters + callParameter; - if (initCallParameters != "") { - initCallParameters = initCallParameters + ", "; - } - initCallParameters = initCallParameters + initCallParameter; - - } - - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %s::%s - %s", cppClassName, method.MethodName, method.MethodDescription) - w.Writelns(" ", commentcodeLines) - w.Writeln(" */") - w.Writeln(" %s%s %s (%s);", staticPrefix, returntype, method.MethodName, parameters) - - cppimplw.Writeln("") - cppimplw.Writeln("/**") - cppimplw.Writeln("* %s::%s - %s", cppClassName, method.MethodName, method.MethodDescription) - cppimplw.Writelns("", commentcodeLines) - cppimplw.Writeln("*/") - cppimplw.Writeln("%s %s::%s (%s)", returntype, cppClassName, method.MethodName, parameters) - cppimplw.Writeln("{") - cppimplw.Writelns(" ", definitionCodeLines) - if (requiresInitCall) { - cppimplw.Writeln(" %s %s (%s) );", checkErrorCode, CMethodName, initCallParameters) - } - cppimplw.Writelns(" ", functionCodeLines) - cppimplw.Writeln(" %s %s (%s) );", checkErrorCode, CMethodName, callParameters) - cppimplw.Writelns(" ", postCallCodeLines) - cppimplw.Writelns(" ", returnCodeLines) - cppimplw.Writeln("}") - - - return nil -} - - -func buildCppExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { - NameSpace := componentdefinition.NameSpace - BaseName := componentdefinition.BaseName - - w.Writeln("#include <iostream>") - w.Writeln("#include \"%s.hpp\"", strings.ToLower(BaseName) ) - w.Writeln("") - w.Writeln("") - - w.Writeln("int main()") - w.Writeln("{") - w.Writeln(" try") - w.Writeln(" {") - w.Writeln(" unsigned int nMajor, nMinor, nMicro;") - w.Writeln(" %s::C%sWrapper::%s(nMajor, nMinor, nMicro);", NameSpace, NameSpace, componentdefinition.Global.VersionMethod) - w.Writeln(" std::cout << \"%s.Version = \" << nMajor << \".\" << nMinor << \".\" << nMicro << std::endl;", NameSpace); - w.Writeln(" }") - w.Writeln(" catch (std::exception &e)") - w.Writeln(" {") - w.Writeln(" std::cout << e.what() << std::endl;") - w.Writeln(" return 1;") - w.Writeln(" }") - w.Writeln(" return 0;") - w.Writeln("}") - w.Writeln("") - - return nil -} - -func buildCppExampleCMake(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { - NameSpace := componentdefinition.NameSpace - BaseName := componentdefinition.BaseName - - w.Writeln("cmake_minimum_required(VERSION 3.5)") - - w.Writeln("") - w.Writeln("project(%sExample_CPP)", NameSpace) - w.Writeln("set (CMAKE_CXX_STANDARD 11)") - // TODO: calculate relative path from ExampleOutputFolder to OUTPUTFOLDER based on CURRENT_SOURCE_DIR - linkfolder := strings.Replace(outputFolder, string(filepath.Separator), "/", -2) - w.Writeln("link_directories(\"%s\") # TODO: put the correct path of the import library here", linkfolder) - - outputFolder = strings.Replace(outputFolder, string(filepath.Separator), "/", -1) - w.Writeln("add_executable(%sExample_CPP \"${CMAKE_CURRENT_SOURCE_DIR}/%s_example.cpp\"", NameSpace, NameSpace) - w.Writeln(" \"%s/%s.cpp\")", outputFolder, BaseName) - w.Writeln("target_link_libraries(%sExample_CPP %s)", NameSpace, BaseName) - - // TODO: calculate relative path from ExampleOutputFolder to OUTPUTFOLDER based on CURRENT_SOURCE_DIR - w.Writeln("target_include_directories(%sExample_CPP PRIVATE \"%s\")", NameSpace, outputFolder) - - return nil -} diff --git a/Source/buildbindingcsharp.go b/Source/buildbindingcsharp.go new file mode 100644 index 00000000..c80f4442 --- /dev/null +++ b/Source/buildbindingcsharp.go @@ -0,0 +1,1186 @@ +/*++ + +Copyright (C) 2018 Autodesk Inc. (Original Author) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--*/ + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// buildbindingcsharp.go +// functions to generate C#-bindings of a library's API in form of dynamically loaded function +// handles. +////////////////////////////////////////////////////////////////////////////////////////////////////// + +package main + +import ( + "crypto/rand" + "fmt" + "io" + "log" + "path" + "strings" +) + +// BuildBindingCSharp builds CSharp bindings of a library's API in form of dynamically loaded function +// handles. +func BuildBindingCSharp(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { + forceRecreation := false + + namespace := component.NameSpace + baseName := component.BaseName + libraryName := component.LibraryName + + CSharpImpl := path.Join(outputFolder, namespace+".cs") + log.Printf("Creating \"%s\"", CSharpImpl) + CSharpImplFile, err := CreateLanguageFile(CSharpImpl, indentString) + if err != nil { + return err + } + + err = buildBindingCSharpImplementation(component, CSharpImplFile, namespace, baseName) + + if len(outputFolderExample) > 0 { + csharpExample := path.Join(outputFolderExample, namespace+"_Example"+".cs") + if forceRecreation || !FileExists(csharpExample) { + log.Printf("Creating \"%s\"", csharpExample) + csharpExampleFile, err := CreateLanguageFile(csharpExample, indentString) + if err != nil { + return err + } + csharpExampleFile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated CSharp application that demonstrates the\n usage of the CSharp bindings of %s", libraryName), + true) + buildCSharpExample(component, csharpExampleFile, outputFolder) + } else { + log.Printf("Omitting recreation of CSharp example \"%s\"", csharpExample) + } + + csharpExampleSolution := path.Join(outputFolderExample, namespace+"_Example"+".sln") + if forceRecreation || !FileExists(csharpExampleSolution) { + log.Printf("Creating \"%s\"", csharpExampleSolution) + csharpExampleSolutionFile, err := CreateLanguageFile(csharpExampleSolution, indentString) + if err != nil { + return err + } + err = buildCSharpExampleSolution(component, csharpExampleSolutionFile, outputFolder) + if err != nil { + return err + } + } else { + log.Printf("Omitting recreation of CSharp example \"%s\"", csharpExample) + } + + csharpExampleProject := path.Join(outputFolderExample, namespace+"_Example"+".csproj") + if forceRecreation || !FileExists(csharpExampleProject) { + log.Printf("Creating \"%s\"", csharpExampleProject) + csharpExampleProjectFile, err := CreateLanguageFile(csharpExampleProject, indentString) + if err != nil { + return err + } + buildCSharpExampleProject(component, csharpExampleProjectFile, outputFolder) + } else { + log.Printf("Omitting recreation of CSharp example \"%s\"", csharpExample) + } + } + + return err +} + +func getCSharpParameterType(ParamTypeName string, NameSpace string, ParamClass string, isPlain bool) (string, error) { + CSharpParamTypeName := "" + switch ParamTypeName { + case "uint8": + CSharpParamTypeName = "Byte" + + case "uint16": + CSharpParamTypeName = "UInt16" + + case "uint32": + CSharpParamTypeName = "UInt32" + + case "uint64": + CSharpParamTypeName = "UInt64" + + case "int8": + CSharpParamTypeName = "Int8" + + case "int16": + CSharpParamTypeName = "Int16" + + case "int32": + CSharpParamTypeName = "Int32" + + case "int64": + CSharpParamTypeName = "Int64" + + case "bool": + if isPlain { + CSharpParamTypeName = "Byte" + } else { + CSharpParamTypeName = "bool" + } + + case "single": + CSharpParamTypeName = "Single" + + case "double": + CSharpParamTypeName = "Double" + + case "pointer": + CSharpParamTypeName = "UInt64" + + case "string": + if isPlain { + CSharpParamTypeName = "byte[]" + } else { + CSharpParamTypeName = "String" + } + + case "enum": + if isPlain { + CSharpParamTypeName = "Int32" + } else { + CSharpParamTypeName = "e" + ParamClass + } + + case "functiontype": + CSharpParamTypeName = fmt.Sprintf("IntPtr") + + case "struct": + if isPlain { + CSharpParamTypeName = "Internal" + ParamClass + } else { + CSharpParamTypeName = "s" + ParamClass + } + + case "basicarray": + if isPlain { + CSharpParamTypeName = fmt.Sprintf("IntPtr") + } else { + + basicTypeName, err := getCSharpParameterType(ParamClass, NameSpace, "", isPlain) + if err != nil { + return "", err + } + + CSharpParamTypeName = basicTypeName + "[]" + + } + + case "structarray": + if isPlain { + CSharpParamTypeName = fmt.Sprintf("IntPtr") + } else { + + CSharpParamTypeName = "s" + ParamClass + "[]" + + } + + case "class": + if isPlain { + CSharpParamTypeName = "IntPtr" + } else { + CSharpParamTypeName = "C" + ParamClass + } + + default: + } + + return CSharpParamTypeName, nil +} + +func getCSharpPlainParameters(method ComponentDefinitionMethod, NameSpace string, ClassName string, isGlobal bool) (string, error) { + parameters := "" + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k] + ParamTypeName, err := getCSharpParameterType(param.ParamType, NameSpace, param.ParamClass, true) + if err != nil { + return "", err + } + + switch param.ParamPass { + case "in": + if parameters != "" { + parameters = parameters + ", " + } + + switch param.ParamType { + case "basicarray": + parameters = parameters + fmt.Sprintf("UInt64 size%s, IntPtr data%s", param.ParamName, param.ParamName) + case "structarray": + parameters = parameters + fmt.Sprintf("UInt64 size%s, IntPtr data%s", param.ParamName, param.ParamName) + + default: + + parameters = parameters + ParamTypeName + " A" + param.ParamName + } + + case "out", "return": + if parameters != "" { + parameters = parameters + ", " + } + + switch param.ParamType { + case "string": + parameters = parameters + fmt.Sprintf("UInt32 size%s, out UInt32 needed%s, IntPtr data%s", param.ParamName, param.ParamName, param.ParamName) + case "basicarray": + parameters = parameters + fmt.Sprintf("UInt64 size%s, out UInt64 needed%s, IntPtr data%s", param.ParamName, param.ParamName, param.ParamName) + case "structarray": + parameters = parameters + fmt.Sprintf("UInt64 size%s, out UInt64 needed%s, IntPtr data%s", param.ParamName, param.ParamName, param.ParamName) + + default: + parameters = parameters + "out " + ParamTypeName + " A" + param.ParamName + } + + } + } + + return parameters, nil +} + +func getCSharpClassParameters(method ComponentDefinitionMethod, NameSpace string, ClassName string, isGlobal bool) (string, string, error) { + parameters := "" + returnType := "" + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k] + ParamTypeName, err := getCSharpParameterType(param.ParamType, NameSpace, param.ParamClass, false) + if err != nil { + return "", "", err + } + + switch param.ParamPass { + case "in": + if parameters != "" { + parameters = parameters + ", " + } + parameters = parameters + ParamTypeName + " A" + param.ParamName + + case "out": + if parameters != "" { + parameters = parameters + ", " + } + parameters = parameters + "out " + ParamTypeName + " A" + param.ParamName + + case "return": + if returnType != "" { + return "", "", fmt.Errorf("duplicate return value \"%s\" for Pascal method \"%s\"", param.ParamName, method.MethodName) + } + returnType = ParamTypeName + } + } + + if returnType == "" { + returnType = "void" + } + + return parameters, returnType, nil +} + +func writeCSharpClassMethodImplementation(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool, spacing string) error { + + defineCommands := make([]string, 0) + initCommands := make([]string, 0) + resultCommands := make([]string, 0) + postInitCommands := make([]string, 0) + + doInitCall := false + + callFunctionName := "" + callFunctionParameters := "" + initCallParameters := "" + + if isGlobal { + callFunctionName = fmt.Sprintf("%s", method.MethodName) + } else { + callFunctionName = fmt.Sprintf("%s_%s", ClassName, method.MethodName) + callFunctionParameters = "Handle" + } + + initCallParameters = callFunctionParameters + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k] + ParamTypeName, err := getCSharpParameterType(param.ParamType, NameSpace, param.ParamClass, false) + if err != nil { + return err + } + + callFunctionParameter := "" + initCallParameter := "" + + switch param.ParamPass { + case "in": + + switch param.ParamType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": + callFunctionParameter = "A" + param.ParamName + initCallParameter = callFunctionParameter + + case "single": + callFunctionParameter = "A" + param.ParamName + initCallParameter = callFunctionParameter + + case "double": + callFunctionParameter = "A" + param.ParamName + initCallParameter = callFunctionParameter + + case "pointer": + callFunctionParameter = "A" + param.ParamName + initCallParameter = callFunctionParameter + + case "string": + defineCommands = append(defineCommands, fmt.Sprintf(" byte[] byte%s = Encoding.UTF8.GetBytes(A%s + char.MinValue);", param.ParamName, param.ParamName)) + callFunctionParameter = "byte" + param.ParamName + initCallParameter = callFunctionParameter + + case "enum": + defineCommands = append(defineCommands, fmt.Sprintf(" Int32 enum%s = (Int32) A%s;", param.ParamName, param.ParamName)) + callFunctionParameter = "enum" + param.ParamName + initCallParameter = callFunctionParameter + + case "bool": + callFunctionParameter = "(Byte)( A" + param.ParamName + " ? 1 : 0 )" + initCallParameter = callFunctionParameter + + case "struct": + defineCommands = append(defineCommands, fmt.Sprintf(" Internal.Internal%s int%s = Internal.%sWrapper.convertStructToInternal_%s (A%s);", param.ParamClass, param.ParamName, NameSpace, param.ParamClass, param.ParamName)) + callFunctionParameter = "int" + param.ParamName + initCallParameter = callFunctionParameter + + case "basicarray": + + defineCommands = append(defineCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(A%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("(UInt64) A%s.Length, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName) + initCallParameter = callFunctionParameter + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free ();", param.ParamName)) + + case "structarray": + + defineCommands = append(defineCommands, fmt.Sprintf(" Internal.Internal%s[] intdata%s = new Internal.Internal%s[A%s.Length];", param.ParamClass, param.ParamName, param.ParamClass, param.ParamName)) + defineCommands = append(defineCommands, fmt.Sprintf(" for (int index = 0; index < A%s.Length; index++)", param.ParamName)) + defineCommands = append(defineCommands, fmt.Sprintf(" intdata%s[index] = Internal.%sWrapper.convertStructToInternal_%s(A%s[index]);", param.ParamName, NameSpace, param.ParamClass, param.ParamName)) + + defineCommands = append(defineCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(intdata%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("(UInt64) A%s.Length, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName) + initCallParameter = callFunctionParameter + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free ();", param.ParamName)) + + case "functiontype": + callFunctionParameter = "IntPtr.Zero" + initCallParameter = callFunctionParameter + + case "class": + callFunctionParameter = "A" + param.ParamName + ".GetHandle()" + initCallParameter = callFunctionParameter + + default: + return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + } + + case "out": + + switch param.ParamType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": + + callFunctionParameter = "out A" + param.ParamName + initCallParameter = callFunctionParameter + + case "single": + callFunctionParameter = "out A" + param.ParamName + initCallParameter = callFunctionParameter + + case "double": + callFunctionParameter = "out A" + param.ParamName + initCallParameter = callFunctionParameter + + case "pointer": + defineCommands = append(defineCommands, fmt.Sprintf(" %s result%s = 0;", ParamTypeName, param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = result%s;", param.ParamName, param.ParamName)) + initCallParameter = callFunctionParameter + + case "string": + + initCommands = append(initCommands, fmt.Sprintf(" UInt32 size%s = 0;", param.ParamName)) + initCommands = append(initCommands, fmt.Sprintf(" UInt32 needed%s = 0;", param.ParamName)) + + initCallParameter = fmt.Sprintf("size%s, out needed%s, IntPtr.Zero", param.ParamName, param.ParamName) + + postInitCommands = append(postInitCommands, fmt.Sprintf(" size%s = needed%s + 1;", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" byte[] bytes%s = new byte[size%s];", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(bytes%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("size%s, out needed%s, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName, param.ParamName) + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free();", param.ParamName)) + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = Encoding.UTF8.GetString(bytes%s).TrimEnd(char.MinValue);", param.ParamName, param.ParamName)) + + doInitCall = true + + case "enum": + defineCommands = append(defineCommands, fmt.Sprintf(" Int32 result%s = 0;", param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = (e%s) (result%s);", param.ParamName, param.ParamClass, param.ParamName)) + + case "bool": + defineCommands = append(defineCommands, fmt.Sprintf(" Byte result%s = 0;", param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = (result%s != 0);", param.ParamName, param.ParamName)) + + case "struct": + defineCommands = append(defineCommands, fmt.Sprintf(" Internal.Internal%s intresult%s;", param.ParamClass, param.ParamName)) + callFunctionParameter = "out intresult" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = Internal.%sWrapper.convertInternalToStruct_%s (intresult%s);", param.ParamName, NameSpace, param.ParamClass, param.ParamName)) + + case "basicarray": + + ParamTypeArrayName, err := getCSharpParameterType(param.ParamClass, NameSpace, param.ParamClass, false) + if err != nil { + return err + } + + initCommands = append(initCommands, fmt.Sprintf(" UInt64 size%s = 0;", param.ParamName)) + initCommands = append(initCommands, fmt.Sprintf(" UInt64 needed%s = 0;", param.ParamName)) + + initCallParameter = fmt.Sprintf("size%s, out needed%s, IntPtr.Zero", param.ParamName, param.ParamName) + + postInitCommands = append(postInitCommands, fmt.Sprintf(" size%s = needed%s;", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" A%s = new %s[size%s];", param.ParamName, ParamTypeArrayName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(A%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("size%s, out needed%s, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName, param.ParamName) + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free();", param.ParamName)) + + doInitCall = true + + case "structarray": + + initCommands = append(initCommands, fmt.Sprintf(" UInt64 size%s = 0;", param.ParamName)) + initCommands = append(initCommands, fmt.Sprintf(" UInt64 needed%s = 0;", param.ParamName)) + + initCallParameter = fmt.Sprintf("size%s, out needed%s, IntPtr.Zero", param.ParamName, param.ParamName) + + postInitCommands = append(postInitCommands, fmt.Sprintf(" size%s = needed%s;", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" var array%s = new Internal.Internal%s[size%s];", param.ParamName, param.ParamClass, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(array%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("size%s, out needed%s, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName, param.ParamName) + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free();", param.ParamName)) + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = new s%s[size%s];", param.ParamName, param.ParamClass, param.ParamName)) + + resultCommands = append(resultCommands, fmt.Sprintf(" for (int index = 0; index < A%s.Length; index++)", param.ParamName)) + resultCommands = append(resultCommands, fmt.Sprintf(" A%s[index] = Internal.%sWrapper.convertInternalToStruct_%s(array%s[index]);", param.ParamName, NameSpace, param.ParamClass, param.ParamName)) + + doInitCall = true + + case "class": + defineCommands = append(defineCommands, fmt.Sprintf(" IntPtr new%s = IntPtr.Zero;", param.ParamName)) + callFunctionParameter = "out new" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" A%s = new C%s (new%s );", param.ParamName, param.ParamClass, param.ParamName)) + + default: + return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + } + + case "return": + + switch param.ParamType { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": + + defineCommands = append(defineCommands, fmt.Sprintf(" %s result%s = 0;", ParamTypeName, param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" return result%s;", param.ParamName)) + + case "string": + + initCommands = append(initCommands, fmt.Sprintf(" UInt32 size%s = 0;", param.ParamName)) + initCommands = append(initCommands, fmt.Sprintf(" UInt32 needed%s = 0;", param.ParamName)) + + initCallParameter = fmt.Sprintf("size%s, out needed%s, IntPtr.Zero", param.ParamName, param.ParamName) + + postInitCommands = append(postInitCommands, fmt.Sprintf(" size%s = needed%s + 1;", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" byte[] bytes%s = new byte[size%s];", param.ParamName, param.ParamName)) + postInitCommands = append(postInitCommands, fmt.Sprintf(" GCHandle data%s = GCHandle.Alloc(bytes%s, GCHandleType.Pinned);", param.ParamName, param.ParamName)) + + callFunctionParameter = fmt.Sprintf("size%s, out needed%s, data%s.AddrOfPinnedObject()", param.ParamName, param.ParamName, param.ParamName) + + resultCommands = append(resultCommands, fmt.Sprintf(" data%s.Free();", param.ParamName)) + resultCommands = append(resultCommands, fmt.Sprintf(" return Encoding.UTF8.GetString(bytes%s).TrimEnd(char.MinValue);", param.ParamName)) + + doInitCall = true + + case "enum": + defineCommands = append(defineCommands, fmt.Sprintf(" Int32 result%s = 0;", param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" return (e%s) (result%s);", param.ParamClass, param.ParamName)) + + case "bool": + defineCommands = append(defineCommands, fmt.Sprintf(" Byte result%s = 0;", param.ParamName)) + callFunctionParameter = "out result" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" return (result%s != 0);", param.ParamName)) + + case "struct": + defineCommands = append(defineCommands, fmt.Sprintf(" Internal.Internal%s intresult%s;", param.ParamClass, param.ParamName)) + callFunctionParameter = "out intresult" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" return Internal.%sWrapper.convertInternalToStruct_%s (intresult%s);", NameSpace, param.ParamClass, param.ParamName)) + + case "class": + + defineCommands = append(defineCommands, fmt.Sprintf(" IntPtr new%s = IntPtr.Zero;", param.ParamName)) + callFunctionParameter = "out new" + param.ParamName + initCallParameter = callFunctionParameter + resultCommands = append(resultCommands, fmt.Sprintf(" return new C%s (new%s );", param.ParamClass, param.ParamName)) + + default: + return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + } + + } + + if callFunctionParameters != "" { + callFunctionParameters = callFunctionParameters + ", " + } + + if initCallParameters != "" { + initCallParameters = initCallParameters + ", " + } + + callFunctionParameters = callFunctionParameters + callFunctionParameter + initCallParameters = initCallParameters + initCallParameter + + } + + if len(defineCommands) > 0 { + w.Writelns(spacing, defineCommands) + } + + if len(initCommands) > 0 { + w.Writelns(spacing, initCommands) + } + + if doInitCall { + w.Writeln(spacing+" CheckError (Internal.%sWrapper.%s (%s));", NameSpace, callFunctionName, initCallParameters) + } + + w.Writelns(spacing, postInitCommands) + + w.Writeln("") + + w.Writeln(spacing+" CheckError (Internal.%sWrapper.%s (%s));", NameSpace, callFunctionName, callFunctionParameters) + + w.Writelns(spacing, resultCommands) + + return nil +} + +func buildBindingCSharpImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { + + baseName := component.BaseName + global := component.Global + + CSharpBaseClassName := "C" + component.Global.BaseClassName + w.Writeln("using System;") + w.Writeln("using System.Text;") + w.Writeln("using System.Runtime.InteropServices;") + w.Writeln("") + + w.Writeln("namespace %s {", NameSpace) + w.Writeln("") + + for i := 0; i < len(component.Enums); i++ { + enum := component.Enums[i] + w.Writeln(" public enum e%s {", enum.Name) + + for j := 0; j < len(enum.Options); j++ { + option := enum.Options[j] + commavalue := "" + if j < (len(enum.Options) - 1) { + commavalue = "," + } + + w.Writeln(" %s = %d%s", option.Name, option.Value, commavalue) + } + + w.Writeln(" };") + w.Writeln("") + + } + + for i := 0; i < len(component.Structs); i++ { + structinfo := component.Structs[i] + + w.Writeln(" public struct s%s", structinfo.Name) + w.Writeln(" {") + + for j := 0; j < len(structinfo.Members); j++ { + element := structinfo.Members[j] + + arraysuffix := "" + if element.Rows > 0 { + if element.Columns > 0 { + arraysuffix = fmt.Sprintf("[][]") + } else { + arraysuffix = fmt.Sprintf("[]") + } + } + + switch element.Type { + case "uint8": + w.Writeln(" public Byte%s %s;", arraysuffix, element.Name) + case "uint16": + w.Writeln(" public UInt16%s %s;", arraysuffix, element.Name) + case "uint32": + w.Writeln(" public UInt32%s %s;", arraysuffix, element.Name) + case "uint64": + w.Writeln(" public UInt64%s %s;", arraysuffix, element.Name) + case "int8": + w.Writeln(" public Int8%s %s;", arraysuffix, element.Name) + case "int16": + w.Writeln(" public Int16%s %s;", arraysuffix, element.Name) + case "int32": + w.Writeln(" public Int32%s %s;", arraysuffix, element.Name) + case "int64": + w.Writeln(" public Int64%s %s;", arraysuffix, element.Name) + case "bool": + w.Writeln(" public bool%s %s;", arraysuffix, element.Name) + case "single": + w.Writeln(" public Single%s %s;", arraysuffix, element.Name) + case "double": + w.Writeln(" public Double%s %s;", arraysuffix, element.Name) + case "pointer": + w.Writeln(" public UInt64%s %s;", arraysuffix, element.Name) + case "string": + return fmt.Errorf("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name) + case "class": + return fmt.Errorf("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name) + case "enum": + w.Writeln(" public e%s%s %s;", element.Class, arraysuffix, element.Name) + } + } + + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln("") + + w.Writeln(" namespace Internal {") + w.Writeln("") + + for i := 0; i < len(component.Structs); i++ { + structinfo := component.Structs[i] + + fieldOffset := 0 + memberLines := make([]string, 0) + for j := 0; j < len(structinfo.Members); j++ { + element := structinfo.Members[j] + + arraysuffix := "" + fixedtag := "" + multiplier := 1 + if element.Rows > 0 { + if element.Columns > 0 { + multiplier = element.Rows * element.Columns + arraysuffix = fmt.Sprintf("[%d]", multiplier) + } else { + multiplier = element.Rows + arraysuffix = fmt.Sprintf("[%d]", multiplier) + } + fixedtag = "fixed " + } + + switch element.Type { + case "uint8": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sByte %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 1*multiplier + case "uint16": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sUInt16 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 2*multiplier + case "uint32": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sUInt32 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 4*multiplier + case "uint64": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sUInt64 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 8*multiplier + case "int8": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sInt8 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 1*multiplier + case "int16": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sInt16 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 2*multiplier + case "int32": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sInt32 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 4*multiplier + case "int64": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sInt64 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 8*multiplier + case "bool": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sByte %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 1*multiplier + case "single": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sSingle %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 4*multiplier + case "double": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sDouble %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 8*multiplier + case "pointer": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sUint64 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 8*multiplier + case "string": + return fmt.Errorf("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name) + case "class": + return fmt.Errorf("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name) + case "enum": + memberLines = append(memberLines, fmt.Sprintf("[FieldOffset(%d)] public %sInt32 %s%s;", fieldOffset, fixedtag, element.Name, arraysuffix)) + fieldOffset = fieldOffset + 4*multiplier + } + } + + w.Writeln(" [StructLayout(LayoutKind.Explicit, Size=%d)]", fieldOffset) + w.Writeln(" public unsafe struct Internal%s", structinfo.Name) + w.Writeln(" {") + w.Writelns(" ", memberLines) + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln("") + + w.Writeln(" public class %sWrapper", NameSpace) + w.Writeln(" {") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + + parameters, err := getCSharpPlainParameters(method, NameSpace, class.ClassName, false) + if err != nil { + return err + } + + w.Writeln(" [DllImport(\"%s.dll\", EntryPoint = \"%s_%s_%s\", CallingConvention=CallingConvention.Cdecl)]", baseName, strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) + + if parameters == "" { + parameters = "IntPtr Handle" + } else { + parameters = "IntPtr Handle, " + parameters + } + + w.Writeln(" public unsafe extern static Int32 %s_%s (%s);", class.ClassName, method.MethodName, parameters) + w.Writeln("") + + } + + } + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + + parameters, err := getCSharpPlainParameters(method, NameSpace, "", true) + if err != nil { + return err + } + + w.Writeln(" [DllImport(\"%s.dll\", EntryPoint = \"%s_%s\", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]", baseName, strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) + w.Writeln(" public extern static Int32 %s (%s);", method.MethodName, parameters) + w.Writeln("") + } + + for i := 0; i < len(component.Structs); i++ { + structinfo := component.Structs[i] + + w.Writeln(" public unsafe static s%s convertInternalToStruct_%s (Internal%s int%s)", structinfo.Name, structinfo.Name, structinfo.Name, structinfo.Name) + w.Writeln(" {") + w.Writeln(" s%s %s;", structinfo.Name, structinfo.Name) + + for j := 0; j < len(structinfo.Members); j++ { + element := structinfo.Members[j] + + paramType, err := getCSharpParameterType(element.Type, NameSpace, element.Class, false) + if err != nil { + return err + } + + castPrefix := "" + castSuffix := "" + switch element.Type { + case "bool": + castSuffix = " != 0" + case "enum": + castPrefix = fmt.Sprintf("(e%s) ", element.Class) + } + + if element.Rows > 0 { + if element.Columns > 0 { + w.Writeln(" %s.%s = new %s[%d][];", structinfo.Name, element.Name, paramType, element.Columns) + w.Writeln(" for (int colIndex = 0; colIndex < %d; colIndex++) {", element.Columns) + w.Writeln(" %s.%s[colIndex] = new %s[%d];", structinfo.Name, element.Name, paramType, element.Rows) + w.Writeln(" for (int rowIndex = 0; rowIndex < %d; rowIndex++) {", element.Rows) + w.Writeln(" %s.%s[colIndex][rowIndex] = %sint%s.%s%s[colIndex * %d + rowIndex];", structinfo.Name, element.Name, castPrefix, structinfo.Name, element.Name, castSuffix, element.Rows) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + } else { + w.Writeln(" %s.%s = new %s[%d];", structinfo.Name, element.Name, paramType, element.Rows) + w.Writeln(" for (int rowIndex = 0; rowIndex < %d; rowIndex++) {", element.Rows) + w.Writeln(" %s.%s[rowIndex] = %sint%s.%s%s[rowIndex];", structinfo.Name, element.Name, castPrefix, structinfo.Name, element.Name, castSuffix) + w.Writeln(" }") + w.Writeln("") + } + } else { + w.Writeln(" %s.%s = %sint%s.%s%s;", structinfo.Name, element.Name, castPrefix, structinfo.Name, element.Name, castSuffix) + } + } + + w.Writeln(" return %s;", structinfo.Name) + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" public unsafe static Internal%s convertStructToInternal_%s (s%s %s)", structinfo.Name, structinfo.Name, structinfo.Name, structinfo.Name) + w.Writeln(" {") + w.Writeln(" Internal%s int%s;", structinfo.Name, structinfo.Name) + + for j := 0; j < len(structinfo.Members); j++ { + element := structinfo.Members[j] + + castPrefix := "" + castSuffix := "" + switch element.Type { + case "bool": + castSuffix = " (byte)" + case "enum": + castPrefix = fmt.Sprintf("(Int32) ") + } + + if element.Rows > 0 { + if element.Columns > 0 { + w.Writeln(" for (int colIndex = 0; colIndex < %d; colIndex++) {", element.Columns) + w.Writeln(" for (int rowIndex = 0; rowIndex < %d; rowIndex++) {", element.Rows) + w.Writeln(" int%s.%s[colIndex * %d + rowIndex] = %s%s.%s[colIndex][rowIndex]%s;", structinfo.Name, element.Name, element.Rows, castPrefix, structinfo.Name, element.Name, castSuffix) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + } else { + w.Writeln(" for (int rowIndex = 0; rowIndex < %d; rowIndex++) {", element.Rows) + w.Writeln(" int%s.%s[rowIndex] = %s%s.%s%s[rowIndex];", structinfo.Name, element.Name, castPrefix, structinfo.Name, element.Name, castSuffix) + w.Writeln(" }") + w.Writeln("") + } + } else { + w.Writeln(" int%s.%s = %s%s.%s%s;", structinfo.Name, element.Name, castPrefix, structinfo.Name, element.Name, castSuffix) + } + + } + + w.Writeln(" return int%s;", structinfo.Name) + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln(" public static void ThrowError(IntPtr Handle, Int32 errorCode)") + w.Writeln(" {") + w.Writeln(" String sMessage = \"%s Error\";", NameSpace) + + if len(component.Global.ErrorMethod) > 0 { + w.Writeln(" if (Handle != IntPtr.Zero) {") + w.Writeln(" UInt32 sizeMessage = 0;") + w.Writeln(" UInt32 neededMessage = 0;") + w.Writeln(" Byte hasLastError = 0;") + w.Writeln(" Int32 resultCode1 = %s (Handle, sizeMessage, out neededMessage, IntPtr.Zero, out hasLastError);", component.Global.ErrorMethod) + w.Writeln(" if ((resultCode1 == 0) && (hasLastError != 0)) {") + w.Writeln(" sizeMessage = neededMessage + 1;") + w.Writeln(" byte[] bytesMessage = new byte[sizeMessage];") + w.Writeln("") + w.Writeln(" GCHandle dataMessage = GCHandle.Alloc(bytesMessage, GCHandleType.Pinned);") + w.Writeln(" Int32 resultCode2 = %s(Handle, sizeMessage, out neededMessage, dataMessage.AddrOfPinnedObject(), out hasLastError);", component.Global.ErrorMethod) + w.Writeln(" dataMessage.Free();") + w.Writeln("") + w.Writeln(" if ((resultCode2 == 0) && (hasLastError != 0)) {") + w.Writeln(" sMessage = sMessage + \": \" + Encoding.UTF8.GetString(bytesMessage).TrimEnd(char.MinValue);") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + } + w.Writeln(" throw new Exception(sMessage + \"(# \" + errorCode + \")\");") + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" }") + w.Writeln(" }") + + w.Writeln("") + w.Writeln("") + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + + CSharpParentClassName := "" + if !component.isBaseClass(class) { + if class.ParentClass == "" { + CSharpParentClassName = ": " + CSharpBaseClassName + } else { + CSharpParentClassName = ": C" + class.ParentClass + } + } + + w.Writeln(" class C%s %s", class.ClassName, CSharpParentClassName) + w.Writeln(" {") + + if component.isBaseClass(class) { + w.Writeln(" protected IntPtr Handle;") + w.Writeln("") + w.Writeln(" public C%s (IntPtr NewHandle)", class.ClassName) + w.Writeln(" {") + w.Writeln(" Handle = NewHandle;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" ~C%s ()", class.ClassName) + w.Writeln(" {") + w.Writeln(" if (Handle != IntPtr.Zero) {") + w.Writeln(" Internal.%sWrapper.%s (Handle);", NameSpace, component.Global.ReleaseMethod) + w.Writeln(" Handle = IntPtr.Zero;") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" protected void CheckError (Int32 errorCode)") + w.Writeln(" {") + w.Writeln(" if (errorCode != 0) {") + w.Writeln(" Internal.%sWrapper.ThrowError (Handle, errorCode);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + + w.Writeln(" public IntPtr GetHandle ()") + w.Writeln(" {") + w.Writeln(" return Handle;") + w.Writeln(" }") + w.Writeln("") + + } else { + w.Writeln(" public C%s (IntPtr NewHandle) : base (NewHandle)", class.ClassName) + w.Writeln(" {") + w.Writeln(" }") + w.Writeln("") + } + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + + parameters, returnType, err := getCSharpClassParameters(method, NameSpace, class.ClassName, false) + if err != nil { + return err + } + + w.Writeln(" public %s %s (%s)", returnType, method.MethodName, parameters) + w.Writeln(" {") + + writeCSharpClassMethodImplementation(method, w, NameSpace, class.ClassName, false, " ") + + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln(" class Wrapper") + w.Writeln(" {") + + w.Writeln(" private static void CheckError (Int32 errorCode)") + w.Writeln(" {") + w.Writeln(" if (errorCode != 0) {") + w.Writeln(" Internal.%sWrapper.ThrowError (IntPtr.Zero, errorCode);", NameSpace) + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + + for j := 0; j < len(global.Methods); j++ { + method := global.Methods[j] + + parameters, returnType, err := getCSharpClassParameters(method, NameSpace, "", true) + if err != nil { + return err + } + + w.Writeln(" public static %s %s (%s)", returnType, method.MethodName, parameters) + w.Writeln(" {") + + writeCSharpClassMethodImplementation(method, w, NameSpace, "Wrapper", true, " ") + + w.Writeln(" }") + w.Writeln("") + } + + w.Writeln(" }") + w.Writeln("") + + w.Writeln("}") + + return nil +} + +func buildCSharpExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) { + NameSpace := componentdefinition.NameSpace + global := componentdefinition.Global + + w.Writeln("") + w.Writeln("using System;") + w.Writeln("namespace %s_Example", NameSpace) + w.Writeln("{") + w.Writeln(" class %s_Example", NameSpace) + w.Writeln(" {") + w.Writeln(" static void Main()") + w.Writeln(" {") + w.Writeln(" UInt32 nMajor, nMinor, nMicro;") + //w.Writeln(" SetDllDirectory(\"\"); // TODO add the location of the shared library binary here") + w.Writeln(" %s.Wrapper.%s(out nMajor, out nMinor, out nMicro);", NameSpace, componentdefinition.Global.VersionMethod) + //w.Writeln(" SetDllDirectory(null);") + w.Writeln(" string versionString = string.Format(\"%s.version = {0}.{1}.{2}\", nMajor, nMinor, nMicro);", NameSpace) + if len(global.PrereleaseMethod) > 0 { + w.Writeln(" string sPreReleaseInfo;") + w.Writeln(" if (%s.Wrapper.%s(out sPreReleaseInfo))", NameSpace, global.PrereleaseMethod) + w.Writeln(" versionString = versionString + '-' + sPreReleaseInfo;") + } + if len(global.BuildinfoMethod) > 0 { + w.Writeln(" string sBuildInfo;") + w.Writeln(" if (%s.Wrapper.%s(out sBuildInfo))", NameSpace, global.BuildinfoMethod) + w.Writeln(" versionString = versionString + '-' + sBuildInfo;") + } + w.Writeln(" Console.WriteLine(versionString);") + w.Writeln(" ") + w.Writeln(" Console.WriteLine(\"Press any key to exit.\");") + w.Writeln(" Console.ReadKey();") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") +} + +// newUUID generates a random UUID according to RFC 4122 +// taken from https://play.golang.org/p/4FkNSiUDMg to not rely on external dependencies +func newUUID() (string, error) { + uuid := make([]byte, 16) + n, err := io.ReadFull(rand.Reader, uuid) + if n != len(uuid) || err != nil { + return "", err + } + // variant bits; see section 4.1.1 + uuid[8] = uuid[8]&^0xc0 | 0x80 + // version 4 (pseudo-random); see section 4.1.3 + uuid[6] = uuid[6]&^0xf0 | 0x40 + return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil +} + +func buildCSharpExampleSolution(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { + NameSpace := componentdefinition.NameSpace + + exampleName := NameSpace + "_Example" + + uuid1, err := newUUID() + if err != nil { + return err + } + uuid2, err := newUUID() + if err != nil { + return err + } + solutionGUID, err := newUUID() + if err != nil { + return err + } + w.Writeln("") + w.Writeln("Microsoft Visual Studio Solution File, Format Version 12.00") + w.Writeln("# Visual Studio 15") + w.Writeln("VisualStudioVersion = 15.0.28307.539") + w.Writeln("MinimumVisualStudioVersion = 10.0.40219.1") + w.Writeln("Project(\"%s\") = \"%s\", \"%s.csproj\", \"%s\"", uuid1, exampleName, exampleName, uuid2) + w.Writeln("EndProject") + w.Writeln("Global") + w.Writeln(" GlobalSection(SolutionConfigurationPlatforms) = preSolution") + w.Writeln(" Debug|x64 = Debug|x64") + w.Writeln(" Release|x64 = Release|x64") + w.Writeln(" EndGlobalSection") + w.Writeln(" GlobalSection(ProjectConfigurationPlatforms) = postSolution") + w.Writeln(" %s.Debug|x64.ActiveCfg = Debug|x64", uuid2) + w.Writeln(" %s.Debug|x64.Build.0 = Debug|x64", uuid2) + w.Writeln(" %s.Release|x64.ActiveCfg = Release|x64", uuid2) + w.Writeln(" %s.Release|x64.Build.0 = Release|x64", uuid2) + w.Writeln(" EndGlobalSection") + w.Writeln(" GlobalSection(SolutionProperties) = preSolution") + w.Writeln(" HideSolutionNode = FALSE") + w.Writeln(" EndGlobalSection") + w.Writeln(" GlobalSection(ExtensibilityGlobals) = postSolution") + w.Writeln(" SolutionGuid = %s", solutionGUID) + w.Writeln(" EndGlobalSection") + w.Writeln("EndGlobal") + + return nil +} + +func buildCSharpExampleProject(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) { + NameSpace := componentdefinition.NameSpace + exampleName := NameSpace + "_Example" + + w.Writeln("") + w.Writeln("<Project Sdk=\"Microsoft.NET.Sdk\">") + w.Writeln(" <PropertyGroup>") + w.Writeln(" <OutputType>Exe</OutputType>") + w.Writeln(" <TargetFramework>netcoreapp2.0</TargetFramework>") + w.Writeln(" <StartupObject>%s.%s</StartupObject>", exampleName, exampleName) + w.Writeln(" <ApplicationIcon />") + w.Writeln(" <Platforms>x64</Platforms>") + w.Writeln(" </PropertyGroup>") + w.Writeln(" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">") + w.Writeln(" <AllowUnsafeBlocks>true</AllowUnsafeBlocks>") + w.Writeln(" </PropertyGroup>") + w.Writeln(" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">") + w.Writeln(" <AllowUnsafeBlocks>true</AllowUnsafeBlocks>") + w.Writeln(" </PropertyGroup>") + w.Writeln(" <ItemGroup>") + w.Writeln(" <Compile Include=\"..\\..\\Bindings\\CSharp\\%s.cs\" Link=\"%s.cs\" />", NameSpace, NameSpace) + w.Writeln(" </ItemGroup>") + w.Writeln("</Project>") +} diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 19c3d1ca..44b76782 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -136,7 +136,7 @@ func buildGoWrapper (component ComponentDefinition, w io.Writer, implw io.Writer fmt.Fprintf (w, " %s%s uint16;\n", member.Name, arraysuffix); case "uint32": fmt.Fprintf (w, " %s%s uint32;\n", member.Name, arraysuffix); - case "uint64": + case "uint64": fmt.Fprintf (w, " %s%s uint64;\n", member.Name, arraysuffix); case "int8": fmt.Fprintf (w, " %s%s int8;\n", member.Name, arraysuffix); @@ -152,9 +152,11 @@ func buildGoWrapper (component ComponentDefinition, w io.Writer, implw io.Writer fmt.Fprintf (w, " %s%s float32;\n", member.Name, arraysuffix); case "double": fmt.Fprintf (w, " %s%s float64;\n", member.Name, arraysuffix); + case "pointer": + fmt.Fprintf (w, " %s%s uint64;\n", member.Name, arraysuffix); case "string": return fmt.Errorf ("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name); - case "handle": + case "class": return fmt.Errorf ("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name); case "enum": fmt.Fprintf (w, " %s%s E%s%s;\n", member.Name, arraysuffix, NameSpace, member.Class); @@ -204,14 +206,14 @@ func buildGoWrapper (component ComponentDefinition, w io.Writer, implw io.Writer class := component.Classes[i]; for j := 0; j < len(class.Methods); j++ { method := class.Methods[j]; - fmt.Fprintf (implw, " %s_%s_%s%s uintptr\n", NameSpace, strings.ToLower (class.ClassName), strings.ToLower (method.MethodName), method.DLLSuffix); + fmt.Fprintf (implw, " %s_%s_%s uintptr\n", NameSpace, strings.ToLower (class.ClassName), strings.ToLower (method.MethodName)); } } for j := 0; j < len(global.Methods); j++ { method := global.Methods[j]; - fmt.Fprintf (implw, " %s_%s%s uintptr\n", NameSpace, strings.ToLower (method.MethodName), method.DLLSuffix); + fmt.Fprintf (implw, " %s_%s uintptr\n", NameSpace, strings.ToLower (method.MethodName)); } fmt.Fprintf (implw, "}\n"); @@ -359,8 +361,8 @@ func buildGoWrapper (component ComponentDefinition, w io.Writer, implw io.Writer class := component.Classes[i]; for j := 0; j < len(class.Methods); j++ { method := class.Methods[j]; - functionName := fmt.Sprintf ("%s_%s_%s%s", strings.ToLower (NameSpace), strings.ToLower (class.ClassName), strings.ToLower (method.MethodName), method.DLLSuffix); - fmt.Fprintf (implw, " implementation.%s_%s_%s%s, err = syscall.GetProcAddress (dllHandle, \"%s\");\n", NameSpace, strings.ToLower (class.ClassName), strings.ToLower (method.MethodName), method.DLLSuffix, functionName); + functionName := fmt.Sprintf ("%s_%s_%s", strings.ToLower (NameSpace), strings.ToLower (class.ClassName), strings.ToLower (method.MethodName)); + fmt.Fprintf (implw, " implementation.%s_%s_%s, err = syscall.GetProcAddress (dllHandle, \"%s\");\n", NameSpace, strings.ToLower (class.ClassName), strings.ToLower (method.MethodName), functionName); fmt.Fprintf (implw, " if (err != nil) {\n"); fmt.Fprintf (implw, " return errors.New (\"Could not get function %s: \" + err.Error());\n", functionName); fmt.Fprintf (implw, " }\n"); @@ -371,8 +373,8 @@ func buildGoWrapper (component ComponentDefinition, w io.Writer, implw io.Writer for j := 0; j < len(global.Methods); j++ { method := global.Methods[j]; - functionName := fmt.Sprintf ("%s_%s%s", strings.ToLower (NameSpace), strings.ToLower (method.MethodName), method.DLLSuffix); - fmt.Fprintf (implw, " implementation.%s_%s%s, err = syscall.GetProcAddress (dllHandle, \"%s\");\n", NameSpace, strings.ToLower (method.MethodName), method.DLLSuffix, functionName); + functionName := fmt.Sprintf ("%s_%s", strings.ToLower (NameSpace), strings.ToLower (method.MethodName)); + fmt.Fprintf (implw, " implementation.%s_%s, err = syscall.GetProcAddress (dllHandle, \"%s\");\n", NameSpace, strings.ToLower (method.MethodName), functionName); fmt.Fprintf (implw, " if (err != nil) {\n"); fmt.Fprintf (implw, " return errors.New (\"Could not get function %s: \" + err.Error());\n", functionName); fmt.Fprintf (implw, " }\n"); @@ -535,15 +537,16 @@ func getGoBasicType (paramType string) (string, error) { switch (paramType) { case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool": - return paramType, nil; + return paramType, nil case "single": - return "float32", nil; + return "float32", nil case "double": - return "float64", nil; + return "float64", nil - + case "pointer": + return "uint64", nil } return "", errors.New ("Invalid basic type: " + paramType); @@ -574,6 +577,8 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ switch (param.ParamType) { case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": errorreturn = errorreturn + fmt.Sprintf ("0, ") + case "pointer": + errorreturn = errorreturn + fmt.Sprintf ("0, ") case "enum": errorreturn = errorreturn + fmt.Sprintf ("0, ") case "bool": @@ -582,7 +587,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ errorreturn = errorreturn + fmt.Sprintf ("\"\", ") case "struct": errorreturn = errorreturn + fmt.Sprintf ("s%s, ", param.ParamName) - case "handle": + case "class": errorreturn = errorreturn + fmt.Sprintf ("h%s, ", param.ParamName) case "functiontype": errorreturn = errorreturn + fmt.Sprintf ("0, ") @@ -695,18 +700,24 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ implcommandparameters = implcommandparameters + fmt.Sprintf (", UInt32InValue (n%s)", param.ParamName); callparameters = callparameters + "b" + param.ParamName; - case "single": + case "single": comments = comments + fmt.Sprintf(" * @param[in] f%s - %s\n", param.ParamName, param.ParamDescription); parameters = parameters + fmt.Sprintf ("f%s float32", param.ParamName) implcommandparameters = implcommandparameters + fmt.Sprintf (", Float32InValue (f%s)", param.ParamName); callparameters = callparameters + "f" + param.ParamName; - case "double": + case "double": comments = comments + fmt.Sprintf(" * @param[in] d%s - %s\n", param.ParamName, param.ParamDescription); parameters = parameters + fmt.Sprintf ("d%s float64", param.ParamName) implcommandparameters = implcommandparameters + fmt.Sprintf (", Float64InValue (d%s)", param.ParamName); callparameters = callparameters + "d" + param.ParamName; - + + case "pointer": + comments = comments + fmt.Sprintf(" * @param[in] n%s - %s\n", param.ParamName, param.ParamDescription); + parameters = parameters + fmt.Sprintf ("n%s uint64", param.ParamName) + implcommandparameters = implcommandparameters + fmt.Sprintf (", UInt64InValue (n%s)", param.ParamName); + callparameters = callparameters + "n" + param.ParamName; + case "string": comments = comments + fmt.Sprintf(" * @param[in] s%s - %s\n", param.ParamName, param.ParamDescription); parameters = parameters + fmt.Sprintf ("s%s string", param.ParamName) @@ -749,7 +760,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ implcommandparameters = implcommandparameters + fmt.Sprintf (", 0"); callparameters = callparameters + "p" + param.ParamName; - case "handle": + case "class": comments = comments + fmt.Sprintf(" * @param[in] %s - %s\n", param.ParamName, param.ParamDescription); parameters = parameters + fmt.Sprintf ("%s %sHandle", param.ParamName, NameSpace) @@ -808,6 +819,16 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ classreturnvariables = classreturnvariables + "n" + param.ParamName + ", "; classreturnstring = classreturnstring + "n" + param.ParamName + ", "; classreturntypes = classreturntypes + fmt.Sprintf ("uint64, "); + + case "pointer": + comments = comments + fmt.Sprintf (" * @return %s\n", param.ParamDescription); + returnvalues = returnvalues + fmt.Sprintf ("uint64, ") + impldeclarations = impldeclarations + fmt.Sprintf ("%svar n%s uint64 = 0;\n", spacing, param.ParamName); + implreturnvalues = implreturnvalues + fmt.Sprintf ("n%s, ", param.ParamName); + implcommandparameters = implcommandparameters + fmt.Sprintf (", UInt64OutValue (&n%s)", param.ParamName); + classreturnvariables = classreturnvariables + "n" + param.ParamName + ", "; + classreturnstring = classreturnstring + "n" + param.ParamName + ", "; + classreturntypes = classreturntypes + fmt.Sprintf ("uint64, "); case "int8": comments = comments + fmt.Sprintf (" * @return %s\n", param.ParamDescription); @@ -884,7 +905,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%svar neededfor%s int64 = 0;\n", spacing, param.ParamName); implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%svar filledin%s int64 = 0;\n", spacing, param.ParamName); - implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%serr = implementation.CallFunction (implementation.%s_%s_%s%s, implementation_%s.GetDLLInHandle()%s, Int64InValue (0), Int64InValue (0), Int64OutValue (&neededfor%s));\n", spacing, NameSpace, strings.ToLower(ClassName), strings.ToLower(method.MethodName), method.DLLSuffix, strings.ToLower(ClassName), implcommandparameters, param.ParamName); + implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%serr = implementation.CallFunction (implementation.%s_%s_%s, implementation_%s.GetDLLInHandle()%s, Int64InValue (0), Int64InValue (0), Int64OutValue (&neededfor%s));\n", spacing, NameSpace, strings.ToLower(ClassName), strings.ToLower(method.MethodName), strings.ToLower(ClassName), implcommandparameters, param.ParamName); implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%sif (err != nil) {\n", spacing); implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%s return %s;\n", spacing, errorreturn); implcommandpreparation = implcommandpreparation + fmt.Sprintf ("%s}\n", spacing); @@ -967,7 +988,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ classreturnstring = classreturnstring + "s" + param.ParamName + ", "; classreturntypes = classreturntypes + fmt.Sprintf ("s%s%s, ", NameSpace, param.ParamClass); - case "handle": + case "class": comments = comments + fmt.Sprintf(" * @return %s\n", param.ParamDescription); returnvalues = returnvalues + fmt.Sprintf ("%sHandle, ", NameSpace) impldeclarations = impldeclarations + fmt.Sprintf ("%sh%s := implementation.NewHandle();\n", spacing, param.ParamName); @@ -1027,7 +1048,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ fmt.Fprintf (implw, "\n"); fmt.Fprintf (implw, implcommandpreparation); - fmt.Fprintf (implw, " err = implementation.CallFunction (implementation.%s_%s%s%s);\n", NameSpace, strings.ToLower (method.MethodName), method.DLLSuffix, implcommandparameters); + fmt.Fprintf (implw, " err = implementation.CallFunction (implementation.%s_%s%s);\n", NameSpace, strings.ToLower (method.MethodName), implcommandparameters); } else { @@ -1038,7 +1059,7 @@ func writeGoMethod (method ComponentDefinitionMethod, w io.Writer, implw io.Writ fmt.Fprintf (implw, "\n"); fmt.Fprintf (implw, implcommandpreparation); - fmt.Fprintf (implw, " err = implementation.CallFunction (implementation.%s_%s_%s%s, implementation_%s.GetDLLInHandle()%s);\n", NameSpace, strings.ToLower (ClassName), strings.ToLower (method.MethodName), method.DLLSuffix, strings.ToLower (ClassName), implcommandparameters); + fmt.Fprintf (implw, " err = implementation.CallFunction(implementation.%s_%s_%s, implementation_%s.GetDLLInHandle()%s);\n", NameSpace, strings.ToLower(ClassName), strings.ToLower(method.MethodName), strings.ToLower(ClassName), implcommandparameters); } diff --git a/Source/buildbindingnode.go b/Source/buildbindingnode.go index 0b3bcfa6..35ffc389 100644 --- a/Source/buildbindingnode.go +++ b/Source/buildbindingnode.go @@ -104,7 +104,7 @@ func buildNodeAddOnImplementation(component ComponentDefinition, w io.Writer, Na fmt.Fprintf(w, "\n") fmt.Fprintf(w, "void Load%s (const FunctionCallbackInfo<Value>& args)\n", NameSpace) fmt.Fprintf(w, "{\n") - fmt.Fprintf(w, " Isolate* isolate = Isolate::GetCurrent();\n") + fmt.Fprintf(w, " Isolate* isolate = args.GetIsolate();\n") fmt.Fprintf(w, " HandleScope scope(isolate);\n") fmt.Fprintf(w, " args.GetReturnValue().Set (C%sWrapper::NewInstance());\n", NameSpace) fmt.Fprintf(w, "}\n") @@ -128,7 +128,6 @@ func buildNodeAddOnImplementation(component ComponentDefinition, w io.Writer, Na func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Writer, NameSpace string, ClassName string, isGlobal bool) error { - returnvariablecount := 0 returndeclaration := "" inputdeclaration := "" inputcheck := "" @@ -141,6 +140,21 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr callParameters := "" initCallParameters := "" + + returnParamCount := 0; + + for k := 0; k < len(method.Params); k++ { + param := method.Params[k]; + if ((param.ParamPass == "out") || (param.ParamPass == "return")) { + returnParamCount = returnParamCount + 1; + } + } + + if (returnParamCount > 1) { + inputdeclaration = inputdeclaration + fmt.Sprintf ("%sLocal<Object> outObject = Object::New(isolate);\n", spacing); + } + + for k := 0; k < len(method.Params); k++ { initCallParameter := ""; @@ -172,10 +186,22 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr initCallParameter = callParameter; case "uint64": - inputcheckfunction = "IsNumber" - inputdeclaration = inputdeclaration + fmt.Sprintf("%sunsigned long long n%s = (unsigned long long) args[%d]->IntegerValue ();\n", spacing, param.ParamName, k) + inputcheckfunction = "IsString" + + inputdeclaration = inputdeclaration + fmt.Sprintf("%sv8::String::Utf8Value sutf8%s (args[%d]->ToString());\n", spacing, param.ParamName, k) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sstd::string s%s = *sutf8%s;\n", spacing, param.ParamName, param.ParamName) + inputdeclaration = inputdeclaration + fmt.Sprintf("%suint64_t n%s = stoull (s%s);\n", spacing, param.ParamName, param.ParamName) callParameter = "n" + param.ParamName initCallParameter = callParameter; + + case "pointer": + inputcheckfunction = "IsString" + + inputdeclaration = inputdeclaration + fmt.Sprintf("%sv8::String::Utf8Value sutf8%s (args[%d]->ToString());\n", spacing, param.ParamName, k) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sstd::string s%s = *sutf8%s;\n", spacing, param.ParamName, param.ParamName) + inputdeclaration = inputdeclaration + fmt.Sprintf("%suint64_t n%s = stoull (s%s);\n", spacing, param.ParamName, param.ParamName) + callParameter = "(void*) n" + param.ParamName + initCallParameter = callParameter; case "int8": inputcheckfunction = "IsInt32" @@ -196,25 +222,28 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr initCallParameter = callParameter; case "int64": - inputcheckfunction = "IsNumber" - inputdeclaration = inputdeclaration + fmt.Sprintf("%slong long n%s = (long long) args[%d]->IntegerValue ();\n", spacing, param.ParamName, k) + inputcheckfunction = "IsString" + + inputdeclaration = inputdeclaration + fmt.Sprintf("%sv8::String::Utf8Value sutf8%s (args[%d]->ToString());\n", spacing, param.ParamName, k) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sstd::string s%s = *sutf8%s;\n", spacing, param.ParamName, param.ParamName) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sint64_t n%s = stoll (s%s);\n", spacing, param.ParamName, param.ParamName) callParameter = "n" + param.ParamName initCallParameter = callParameter; case "string": inputcheckfunction = "IsString" - inputdeclaration = inputdeclaration + fmt.Sprintf("%sv8::String::Utf8Value s%sUTF8 (args[%d]->ToString());\n", spacing, param.ParamName, k) - inputdeclaration = inputdeclaration + fmt.Sprintf("%sstd::string s%s = *s%sUTF8;\n", spacing, param.ParamName, param.ParamName) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sv8::String::Utf8Value sutf8%s (args[%d]->ToString());\n", spacing, param.ParamName, k) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sstd::string s%s = *sutf8%s;\n", spacing, param.ParamName, param.ParamName) callParameter = "s" + param.ParamName + ".c_str()" initCallParameter = callParameter; case "basicarray": - callParameter = "nullptr, 0"; + callParameter = "0, nullptr"; initCallParameter = callParameter; case "structarray": - callParameter = "nullptr, 0"; + callParameter = "0, nullptr"; initCallParameter = callParameter; case "functiontype": @@ -246,18 +275,21 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr initCallParameter = callParameter; case "struct": - callParameter = "nullptr"; + inputcheckfunction = "IsObject" + + inputdeclaration = inputdeclaration + fmt.Sprintf("%ss%s%s s%s = convertObjectTo%s%s(isolate, args[%d]);\n", spacing, NameSpace, param.ParamClass, param.ParamName, NameSpace, param.ParamClass, k) + + callParameter = fmt.Sprintf ("&s%s", param.ParamName); initCallParameter = callParameter; - //return fmt.Errorf("parameter type \"%s\" not yet supported for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - case "handle": + case "class": inputcheckfunction = "IsObject" - inputdeclaration = inputdeclaration + fmt.Sprintf("%sLocal<Object> obj%s = args[%d]->ToObject();\n", spacing, param.ParamName, k) + inputdeclaration = inputdeclaration + fmt.Sprintf("%sLocal<Object> obj%s = args[%d]->ToObject(isolate->GetCurrentContext()).ToLocalChecked ();\n", spacing, param.ParamName, k) inputdeclaration = inputdeclaration + fmt.Sprintf("%sC%s%s * instance%s = ObjectWrap::Unwrap<C%s%s>(obj%s);\n", spacing, NameSpace, param.ParamClass, param.ParamName, NameSpace, param.ParamClass, param.ParamName) inputdeclaration = inputdeclaration + fmt.Sprintf("%sif (instance%s == nullptr)\n", spacing, param.ParamName) inputdeclaration = inputdeclaration + fmt.Sprintf("%s throw std::runtime_error(\"Invalid Object parameter %d (%s)\");\n", spacing, k, param.ParamName) - inputdeclaration = inputdeclaration + fmt.Sprintf("%s%sHandle h%s = instance%s->getHandle (args.Holder ());\n", spacing, NameSpace, param.ParamName, param.ParamName) + inputdeclaration = inputdeclaration + fmt.Sprintf("%s%sHandle h%s = instance%s->getHandle ( obj%s );\n", spacing, NameSpace, param.ParamName, param.ParamName, param.ParamName) callParameter = "h" + param.ParamName initCallParameter = callParameter; @@ -274,8 +306,15 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr } case "out", "return": - - returnvariablecount = returnvariablecount + 1 + + var argsvalue string; + if (returnParamCount > 1) { + argsvalue = fmt.Sprintf ("outObject->Set (String::NewFromUtf8 (isolate, \"%s\"), ", param.ParamName); + + } else { + argsvalue = "args.GetReturnValue().Set ("; + } + switch param.ParamType { case "uint8": @@ -283,56 +322,63 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::NewFromUnsigned (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "uint16": returndeclaration = returndeclaration + fmt.Sprintf("%sunsigned short nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::NewFromUnsigned (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "uint32": returndeclaration = returndeclaration + fmt.Sprintf("%sunsigned int nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::NewFromUnsigned (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "uint64": - returndeclaration = returndeclaration + fmt.Sprintf("%sunsigned long long nReturn%s = 0;\n", spacing, param.ParamName) + returndeclaration = returndeclaration + fmt.Sprintf("%suint64_t nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sString::NewFromUtf8 (isolate, std::to_string (nReturn%s).c_str()));\n", spacing, argsvalue, param.ParamName) + + case "pointer": + returndeclaration = returndeclaration + fmt.Sprintf("%suint64_t nReturn%s = 0;\n", spacing, param.ParamName) + callParameter = "&nReturn" + param.ParamName + initCallParameter = callParameter; + + returncode = returncode + fmt.Sprintf("%s%sString::NewFromUtf8 (isolate, std::to_string (nReturn%s).c_str()));\n", spacing, argsvalue, param.ParamName) case "int8": returndeclaration = returndeclaration + fmt.Sprintf("%schar nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::New (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "int16": returndeclaration = returndeclaration + fmt.Sprintf("%s short nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::New (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "int32": returndeclaration = returndeclaration + fmt.Sprintf("%s int nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::New (isolate, nReturn%s));\n", spacing, argsvalue, param.ParamName) case "int64": - returndeclaration = returndeclaration + fmt.Sprintf("%s long long nReturn%s = 0;\n", spacing, param.ParamName) + returndeclaration = returndeclaration + fmt.Sprintf("%s int64_t nReturn%s = 0;\n", spacing, param.ParamName) callParameter = "&nReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, nReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sString::NewFromUtf8 (isolate, std::to_string (nReturn%s).c_str() ));\n", spacing, argsvalue, param.ParamName) case "string": requiresInitCall = true; @@ -347,62 +393,62 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr callParameter = fmt.Sprintf("bytesNeeded%s, &bytesWritten%s, &buffer%s[0]", param.ParamName, param.ParamName, param.ParamName) returncode = returncode + fmt.Sprintf("%sbuffer%s[bytesNeeded%s + 1] = 0;\n", spacing, param.ParamName, param.ParamName); - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(String::NewFromUtf8 (isolate, &buffer%s[0]));\n", spacing, param.ParamName); + returncode = returncode + fmt.Sprintf("%s%sString::NewFromUtf8 (isolate, &buffer%s[0]));\n", spacing, argsvalue, param.ParamName); case "bool": returndeclaration = returndeclaration + fmt.Sprintf("%sbool bReturn%s = false;\n", spacing, param.ParamName) callParameter = "&bReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Boolean::New (isolate, bReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sBoolean::New (isolate, bReturn%s));\n", spacing, argsvalue, param.ParamName) case "single": returndeclaration = returndeclaration + fmt.Sprintf("%sfloat fReturn%s = 0.0f;\n", spacing, param.ParamName) callParameter = "&fReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Number::New (isolate, fReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sNumber::New (isolate, (double) fReturn%s));\n", spacing, argsvalue, param.ParamName) case "double": returndeclaration = returndeclaration + fmt.Sprintf("%sdouble dReturn%s = 0.0;\n", spacing, param.ParamName) callParameter = "&dReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Number::New (isolate, dReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sNumber::New (isolate, dReturn%s));\n", spacing, argsvalue, param.ParamName) case "enum": returndeclaration = returndeclaration + fmt.Sprintf("%se%s%s eReturn%s;\n", spacing, NameSpace, param.ParamClass, param.ParamName) callParameter = "&eReturn" + param.ParamName initCallParameter = callParameter; - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(Integer::New (isolate, (int) eReturn%s));\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sInteger::New (isolate, (int) eReturn%s));\n", spacing, argsvalue, param.ParamName) case "struct": returndeclaration = returndeclaration + fmt.Sprintf("%ss%s%s sReturn%s;\n", spacing, NameSpace, param.ParamClass, param.ParamName) callParameter = "&sReturn" + param.ParamName initCallParameter = callParameter; - - //return fmt.Errorf("can not return struct \"%s\" for %s.%s (%s) yet in nodejs", param.ParamType, ClassName, method.MethodName, param.ParamName) + + returncode = returncode + fmt.Sprintf("%s%sconvert%s%sToObject (isolate, sReturn%s));\n", spacing, argsvalue, NameSpace, param.ParamClass, param.ParamName) case "basicarray": - callParameter = "nullptr, 0, nullptr"; + callParameter = "0, nullptr, nullptr"; initCallParameter = callParameter; case "structarray": - callParameter = "nullptr, 0, nullptr"; + callParameter = "0, nullptr, nullptr"; initCallParameter = callParameter; case "functiontype": callParameter = "nullptr"; initCallParameter = callParameter; - case "handle": + case "class": returndeclaration = returndeclaration + fmt.Sprintf("%s%sHandle hReturn%s = nullptr;\n", spacing, NameSpace, param.ParamName) callParameter = "&hReturn" + param.ParamName initCallParameter = callParameter; returncode = returncode + fmt.Sprintf("%sLocal<Object> instanceObj%s = C%s%s::NewInstance (args.Holder(), hReturn%s);\n", spacing, param.ParamName, NameSpace, param.ParamClass, param.ParamName) - returncode = returncode + fmt.Sprintf("%sargs.GetReturnValue().Set(instanceObj%s);\n", spacing, param.ParamName) + returncode = returncode + fmt.Sprintf("%s%sinstanceObj%s);\n", spacing, argsvalue, param.ParamName) default: return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) @@ -424,11 +470,16 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr } + if (returnParamCount > 1) { + returncode = returncode + fmt.Sprintf ("%sargs.GetReturnValue().Set (outObject);\n", spacing); + } + + fmt.Fprintf(implw, "\n") fmt.Fprintf(implw, "void C%s%s::%s (const FunctionCallbackInfo<Value>& args) \n", NameSpace, ClassName, method.MethodName) fmt.Fprintf(implw, "{\n") - fmt.Fprintf(implw, " Isolate* isolate = Isolate::GetCurrent();\n") + fmt.Fprintf(implw, " Isolate* isolate = args.GetIsolate();\n") fmt.Fprintf(implw, " HandleScope scope(isolate);\n") fmt.Fprintf(implw, " try {\n") @@ -448,7 +499,11 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr fmt.Fprintf(implw, "%sif (wrapperTable->m_%s_%s == nullptr)\n", spacing, ClassName, method.MethodName) fmt.Fprintf(implw, "%s throw std::runtime_error (\"Could not call %s method %s::%s.\");\n", spacing, NameSpace, ClassName, method.MethodName) } - + + + if (!isGlobal) { + fmt.Fprintf(implw, "%s%sHandle instanceHandle = C%sBaseClass::getHandle (args.Holder());\n", spacing, NameSpace, NameSpace); + } if (requiresInitCall) { @@ -459,11 +514,15 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr if initCallParameters != "" { initCallParameters = ", " + initCallParameters } - fmt.Fprintf(implw, "%s%sResult initErrorCode = wrapperTable->m_%s_%s (C%sBaseClass::getHandle (args.Holder())%s);\n", spacing, NameSpace, ClassName, method.MethodName, NameSpace, initCallParameters) + fmt.Fprintf(implw, "%s%sResult initErrorCode = wrapperTable->m_%s_%s (instanceHandle%s);\n", spacing, NameSpace, ClassName, method.MethodName, initCallParameters) } - fmt.Fprintf(implw, "%sCheckError (initErrorCode);\n", spacing) + if (isGlobal) { + fmt.Fprintf(implw, "%sCheckError (isolate, wrapperTable, nullptr, initErrorCode);\n", spacing) + } else { + fmt.Fprintf(implw, "%sCheckError (isolate, wrapperTable, instanceHandle, initErrorCode);\n", spacing) + } } fmt.Fprintf(implw, functioncode) @@ -475,11 +534,15 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr if callParameters != "" { callParameters = ", " + callParameters } - fmt.Fprintf(implw, "%s%sResult errorCode = wrapperTable->m_%s_%s (C%sBaseClass::getHandle (args.Holder())%s);\n", spacing, NameSpace, ClassName, method.MethodName, NameSpace, callParameters) + fmt.Fprintf(implw, "%s%sResult errorCode = wrapperTable->m_%s_%s (instanceHandle%s);\n", spacing, NameSpace, ClassName, method.MethodName, callParameters) } - fmt.Fprintf(implw, "%sCheckError (errorCode);\n", spacing) + if (isGlobal) { + fmt.Fprintf(implw, "%sCheckError (isolate, wrapperTable, nullptr, errorCode);\n", spacing) + } else { + fmt.Fprintf(implw, "%sCheckError (isolate, wrapperTable, instanceHandle, errorCode);\n", spacing) + } fmt.Fprintf(implw, returncode) @@ -493,6 +556,293 @@ func writeNodeMethodImplementation(method ComponentDefinitionMethod, implw io.Wr return nil } +func buildNodeStructConversion(structdefinition ComponentDefinitionStruct, implw io.Writer, NameSpace string) error { + + hasRowVariable := false; + hasColumnVariable := false; + + for i := 0; i < len(structdefinition.Members); i++ { + + member := structdefinition.Members[i]; + if (member.Rows > 0) { + hasRowVariable = true; + + if (member.Columns > 0) { + hasColumnVariable = true; + } + } + + } + + + fmt.Fprintf(implw, "/*************************************************************************************************************************\n") + fmt.Fprintf(implw, " Class s%s%s Conversion\n", NameSpace, structdefinition.Name) + fmt.Fprintf(implw, "**************************************************************************************************************************/\n") + + fmt.Fprintf(implw, ""); + fmt.Fprintf(implw, "s%s%s convertObjectTo%s%s (Isolate* isolate, const Local<Value> & pParamValue)\n", NameSpace, structdefinition.Name, NameSpace, structdefinition.Name); + fmt.Fprintf(implw, "{\n"); + fmt.Fprintf(implw, " s%s%s s%s;\n", NameSpace, structdefinition.Name, structdefinition.Name); + fmt.Fprintf(implw, " Local<Context> context = isolate->GetCurrentContext();\n"); + + if (hasRowVariable) { + fmt.Fprintf(implw, " int rowIndex;\n"); + } + if (hasColumnVariable) { + fmt.Fprintf(implw, " int columnIndex;\n"); + } + + fmt.Fprintf(implw, "\n"); + + for i := 0; i < len(structdefinition.Members); i++ { + + member := structdefinition.Members[i]; + defaultValue, err := GetCMemberDefaultValue (member.Type, member.Class, NameSpace); + if err != nil { + return err; + } + + defaultValueAssignment := " = " + defaultValue; + if (member.Type == "enum") { + defaultValueAssignment = ".m_code = " + defaultValue; + } + + if (member.Rows > 0) { + if (member.Columns > 0) { + fmt.Fprintf(implw, " for (columnIndex = 0; columnIndex < %d; columnIndex++)\n", member.Columns); + fmt.Fprintf(implw, " for (rowIndex = 0; rowIndex < %d; rowIndex++)\n", member.Rows); + fmt.Fprintf(implw, " s%s.m_%s[columnIndex][rowIndex]%s;\n", structdefinition.Name, member.Name, defaultValueAssignment); + } else { + fmt.Fprintf(implw, " for (rowIndex = 0; rowIndex < %d; rowIndex++)\n", member.Rows); + fmt.Fprintf(implw, " s%s.m_%s[rowIndex]%s;\n", structdefinition.Name, member.Name, defaultValueAssignment); + } + } else { + + fmt.Fprintf(implw, " s%s.m_%s%s;\n", structdefinition.Name, member.Name, defaultValueAssignment); + } + + + } + + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, " if (pParamValue->IsObject ()) {\n"); + fmt.Fprintf(implw, " MaybeLocal<Object> maybeObject = pParamValue->ToObject(context);\n"); + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, " if (!maybeObject.IsEmpty ()) {\n"); + fmt.Fprintf(implw, " Local<Object> obj = maybeObject.ToLocalChecked();\n"); + fmt.Fprintf(implw, "\n"); + + for i := 0; i < len(structdefinition.Members); i++ { + + member := structdefinition.Members[i]; + fmt.Fprintf(implw, " // %s Member\n", member.Name); + + fmt.Fprintf(implw, " MaybeLocal<Value> maybeVal%s = obj->Get(context, String::NewFromUtf8(isolate, \"%s\"));\n", member.Name, member.Name); + fmt.Fprintf(implw, " if (!maybeVal%s.IsEmpty ()) {\n", member.Name); + fmt.Fprintf(implw, " Local<Value> val%s = maybeVal%s.ToLocalChecked ();\n", member.Name, member.Name); + + valueTypeCall := ""; + assignmentOperator := " = "; + switch (member.Type) { + case "uint8", "uint16", "uint32": + valueTypeCall = "Uint32Value"; + case "int8", "int16", "int32": + valueTypeCall = "Int32Value"; + case "enum": + valueTypeCall = "Int32Value"; + assignmentOperator = ".m_code = "; + + case "uint64", "int64": + valueTypeCall = "IntegerValue"; + case "pointer": + valueTypeCall = "IntegerValue"; + assignmentOperator = " = (void *)"; + case "bool": + valueTypeCall = "BooleanValue"; + case "single": + assignmentOperator = " = (float)"; + valueTypeCall = "NumberValue"; + case "double": + valueTypeCall = "NumberValue"; + } + + + if (member.Rows > 0) { + + fmt.Fprintf(implw, " if (val%s->IsArray ()) {\n", member.Name); + fmt.Fprintf(implw, " Local<Array> array%s = Local<Array>::Cast(val%s);\n", member.Name, member.Name); + + if (member.Columns > 0) { + + fmt.Fprintf(implw, " for (int colIndex = 0; colIndex < %d; colIndex++) {\n", member.Columns); + fmt.Fprintf(implw, " MaybeLocal<Value> mlocalCol = array%s->Get(context, colIndex);\n", member.Name); + fmt.Fprintf(implw, " Local<Value> localCol;\n"); + fmt.Fprintf(implw, " if (mlocalCol.ToLocal (&localCol)) {\n"); + fmt.Fprintf(implw, " if (localCol->IsArray ()) {\n"); + fmt.Fprintf(implw, " Local<Array> localColArray = Local<Array>::Cast(localCol);\n"); + fmt.Fprintf(implw, " for (int rowIndex = 0; rowIndex < %d; rowIndex++) {\n", member.Rows); + fmt.Fprintf(implw, " MaybeLocal<Value> mlocalValue = localColArray->Get(context, rowIndex);\n"); + fmt.Fprintf(implw, " Local<Value> localValue;\n"); + fmt.Fprintf(implw, " if (mlocalValue.ToLocal (&localValue)) {\n"); + fmt.Fprintf(implw, " if (localValue->IsNumber ()) {\n"); + fmt.Fprintf(implw, " MaybeLocal<Number> localNumber = localValue->ToNumber(context);\n"); + fmt.Fprintf(implw, " s%s.m_%s[colIndex][rowIndex]%slocalNumber.ToLocalChecked()->%s ();\n", structdefinition.Name, member.Name, assignmentOperator, valueTypeCall); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is not a number\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is invalid\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is not an array\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is invalid\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " }\n"); + + + + } else { + + fmt.Fprintf(implw, " for (int rowIndex = 0; rowIndex < %d; rowIndex++) {\n", member.Rows); + fmt.Fprintf(implw, " MaybeLocal<Value> mlocalValue = array%s->Get(context, rowIndex);\n", member.Name); + fmt.Fprintf(implw, " Local<Value> localValue;\n"); + fmt.Fprintf(implw, " if (mlocalValue.ToLocal (&localValue)) {\n"); + fmt.Fprintf(implw, " if (localValue->IsNumber ()) {\n"); + fmt.Fprintf(implw, " MaybeLocal<Number> localNumber = localValue->ToNumber(context);\n"); + fmt.Fprintf(implw, " s%s.m_%s[rowIndex]%slocalNumber.ToLocalChecked()->%s ();\n", structdefinition.Name, member.Name, assignmentOperator, valueTypeCall); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is not a number\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s array entry is invalid\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " }\n"); + + } + + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s member is not an array\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + + + } else { + fmt.Fprintf(implw, " if (val%s->IsNumber ()) {\n", member.Name); + fmt.Fprintf(implw, " MaybeLocal<Number> localVal%s = val%s->ToNumber(context);\n", member.Name, member.Name); + fmt.Fprintf(implw, " s%s.m_%s%slocalVal%s.ToLocalChecked()->%s ();\n", structdefinition.Name, member.Name, assignmentOperator, member.Name, valueTypeCall); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s member is not a number\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + } + + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"%s member not found in object\" )));\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, "\n"); + + } + + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"invalid object passed.\" )));\n"); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " } else {\n"); + fmt.Fprintf(implw, " isolate->ThrowException(Exception::TypeError (String::NewFromUtf8(isolate, \"expected object parameter.\" )));\n"); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, " return s%s;\n", structdefinition.Name); + fmt.Fprintf(implw, "}\n"); + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, "\n"); + + + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, "Local<Object> convert%s%sToObject (Isolate* isolate, s%s%s s%s)\n", NameSpace, structdefinition.Name, NameSpace, structdefinition.Name, structdefinition.Name); + fmt.Fprintf(implw, "{\n"); + fmt.Fprintf(implw, " Local<Object> returnInstance = Object::New(isolate);\n"); + + for i := 0; i < len(structdefinition.Members); i++ { + + member := structdefinition.Members[i]; + + conversionCall := ""; + conversionValue := fmt.Sprintf ("s%s.m_%s", structdefinition.Name, member.Name); + conversionPostfix := ""; + switch (member.Type) { + case "uint8", "uint16", "uint32": + conversionCall = "Integer::NewFromUnsigned"; + case "int8", "int16", "int32": + conversionCall = "Integer::New"; + case "enum": + conversionCall = "Integer::New"; + conversionPostfix = ".m_code"; + case "uint64", "int64": + conversionCall = "String::NewFromUtf8"; + conversionValue = "std::to_string (" + conversionValue; + conversionPostfix = ").c_str()"; + case "pointer": + conversionCall = "String::NewFromUtf8"; + conversionValue = "std::to_string ((uint_ptr) " + conversionValue; + conversionPostfix = ").c_str()"; + case "bool": + conversionCall = "Boolean::New"; + case "single": + conversionCall = "Number::New"; + conversionValue = "(double) " + conversionValue; + case "double": + conversionCall = "Number::New"; + + } + + if (member.Rows > 0) { + + if (member.Columns > 0) { + + + fmt.Fprintf(implw, " Local<Array> new%s = Array::New (isolate, %d);\n", member.Name, member.Columns); + fmt.Fprintf(implw, " for (int colIndex = 0; colIndex < %d; colIndex++) {\n", member.Columns); + fmt.Fprintf(implw, " Local<Array> colArray = Array::New (isolate, %d);\n", member.Rows); + fmt.Fprintf(implw, " for (int rowIndex = 0; rowIndex < %d; rowIndex++) {\n", member.Rows); + fmt.Fprintf(implw, " colArray->Set (rowIndex, %s (isolate, %s[colIndex][rowIndex]%s));\n", conversionCall, conversionValue, conversionPostfix); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " new%s->Set (colIndex, colArray);\n", member.Name); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " returnInstance->Set (String::NewFromUtf8 (isolate, \"%s\"), new%s);\n", member.Name, member.Name); + fmt.Fprintf(implw, "\n"); + + } else { + + fmt.Fprintf(implw, " Local<Array> new%s = Array::New (isolate, %d);\n", member.Name, member.Rows); + fmt.Fprintf(implw, " for (int rowIndex = 0; rowIndex < %d; rowIndex++) {\n", member.Rows); + fmt.Fprintf(implw, " new%s->Set (rowIndex, %s (isolate, %s[rowIndex]%s));\n", member.Name, conversionCall, conversionValue, conversionPostfix); + fmt.Fprintf(implw, " }\n"); + fmt.Fprintf(implw, " returnInstance->Set (String::NewFromUtf8 (isolate, \"%s\"), new%s);\n", member.Name, member.Name); + fmt.Fprintf(implw, "\n"); + + } + + } else { + fmt.Fprintf(implw, " returnInstance->Set (String::NewFromUtf8 (isolate, \"%s\"), %s (isolate, %s%s));\n", member.Name, conversionCall, conversionValue, conversionPostfix); + } + + } + + fmt.Fprintf(implw, "\n"); + fmt.Fprintf(implw, " return returnInstance;\n"); + fmt.Fprintf(implw, "}\n"); + fmt.Fprintf(implw, "\n"); + + + + return nil; + +} + + + + func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io.Writer, NameSpace string, BaseName string) error { fmt.Fprintf(w, "\n") @@ -528,7 +878,7 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(w, "public:\n") fmt.Fprintf(w, " C%sBaseClass ();\n", NameSpace) fmt.Fprintf(w, " static void RaiseError (v8::Isolate * isolate, std::string Message);\n") - fmt.Fprintf(w, " static void CheckError (%sResult errorCode);\n", NameSpace) + fmt.Fprintf(w, " static void CheckError (v8::Isolate * isolate, s%sDynamicWrapperTable * sWrapperTable, %sHandle pInstance, %sResult errorCode);\n", NameSpace, NameSpace, NameSpace) fmt.Fprintf(w, " static void setHandle (%sHandle pHandle);\n", NameSpace) fmt.Fprintf(w, " static %sHandle getHandle (v8::Handle<v8::Object> objecthandle);\n", NameSpace) fmt.Fprintf(w, " static s%sDynamicWrapperTable * getDynamicWrapperTable (v8::Handle<v8::Object> objecthandle);\n", NameSpace) @@ -597,7 +947,6 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "#include <node.h>\n") fmt.Fprintf(implw, "#include \"%s_nodewrapper.h\"\n", BaseName) fmt.Fprintf(implw, "\n") - fmt.Fprintf(implw, "#include <Windows.h>\n") fmt.Fprintf(implw, "\n") fmt.Fprintf(implw, "using namespace v8;\n") fmt.Fprintf(implw, "\n") @@ -607,6 +956,18 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "Persistent<Function> C%s%s::constructor;\n", NameSpace, class.ClassName) } fmt.Fprintf(implw, "\n") + + + + for i := 0; i < len(component.Structs); i++ { + structdefinition := component.Structs[i]; + err := buildNodeStructConversion (structdefinition, implw, NameSpace); + if (err != nil) { + return err; + } + } + + fmt.Fprintf(implw, "/*************************************************************************************************************************\n") fmt.Fprintf(implw, " Class C%sBaseClass Implementation\n", NameSpace) @@ -626,10 +987,31 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, " }\n") fmt.Fprintf(implw, "}\n") - fmt.Fprintf(implw, "void C%sBaseClass::CheckError (%sResult errorCode)\n", NameSpace, NameSpace) + fmt.Fprintf(implw, "void C%sBaseClass::CheckError (v8::Isolate * isolate, s%sDynamicWrapperTable * sWrapperTable, %sHandle pInstance, %sResult errorCode)\n", NameSpace, NameSpace, NameSpace, NameSpace) fmt.Fprintf(implw, "{\n") fmt.Fprintf(implw, " if (errorCode != 0) { \n") - fmt.Fprintf(implw, " throw std::runtime_error (\"%s Error \" + std::to_string (errorCode));\n", NameSpace) + fmt.Fprintf(implw, " std::string sMessage;\n") + + if len (component.Global.ErrorMethod) > 0 { + + fmt.Fprintf(implw, " if ((sWrapperTable != nullptr) && (pInstance != nullptr)) {\n") + fmt.Fprintf(implw, " if (sWrapperTable->m_%s != nullptr) {\n", component.Global.ErrorMethod) + fmt.Fprintf(implw, " uint32_t neededChars = 0;\n") + fmt.Fprintf(implw, " bool hasLastError = 0;\n") + fmt.Fprintf(implw, " if (sWrapperTable->m_%s (pInstance, 0, &neededChars, nullptr, &hasLastError) == 0) {\n", component.Global.ErrorMethod) + fmt.Fprintf(implw, " uint32_t dummyChars = 0;\n") + fmt.Fprintf(implw, " std::vector<char> Buffer;\n") + fmt.Fprintf(implw, " Buffer.resize (neededChars + 2);\n") + fmt.Fprintf(implw, " if (sWrapperTable->m_%s (pInstance, neededChars + 1, &dummyChars, Buffer.data(), &hasLastError) == 0) {\n", component.Global.ErrorMethod) + fmt.Fprintf(implw, " Buffer[neededChars + 1] = 0;\n") + fmt.Fprintf(implw, " sMessage = std::string (\": \") + std::string (&Buffer[0]);\n") + fmt.Fprintf(implw, " }\n") + fmt.Fprintf(implw, " }\n") + fmt.Fprintf(implw, " }\n") + fmt.Fprintf(implw, " }\n") + + } + fmt.Fprintf(implw, " throw std::runtime_error (\"%s Error\" + sMessage + \" (\" + std::to_string (errorCode) + \")\");\n", NameSpace) fmt.Fprintf(implw, " }\n") fmt.Fprintf(implw, "}\n") @@ -696,7 +1078,7 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "void C%s%s::New(const FunctionCallbackInfo<Value>& args)\n", NameSpace, class.ClassName) fmt.Fprintf(implw, "{\n") - fmt.Fprintf(implw, " Isolate* isolate = Isolate::GetCurrent();\n") + fmt.Fprintf(implw, " Isolate* isolate = args.GetIsolate();\n") fmt.Fprintf(implw, " HandleScope scope(isolate);\n") fmt.Fprintf(implw, "\n") fmt.Fprintf(implw, " if (args.IsConstructCall()) {\n") @@ -718,12 +1100,12 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "{\n") fmt.Fprintf(implw, " Isolate* isolate = Isolate::GetCurrent();\n") fmt.Fprintf(implw, " HandleScope scope(isolate);\n") - fmt.Fprintf(implw, " const unsigned argc = 1; // TODO: Find out how to not pass dummy parameters..\n") - fmt.Fprintf(implw, " Handle<Value> argv[argc] = { Number::New (isolate, 0.0) };\n") fmt.Fprintf(implw, " Local<Function> cons = Local<Function>::New(isolate, constructor);\n") - fmt.Fprintf(implw, " Local<Object> instance = cons->NewInstance(argc, argv);\n") - fmt.Fprintf(implw, " instance->SetInternalField (NODEWRAPPER_TABLEINDEX, External::New (isolate, C%sBaseClass::getDynamicWrapperTable (pParent)));\n", NameSpace) - fmt.Fprintf(implw, " instance->SetInternalField (NODEWRAPPER_HANDLEINDEX, External::New (isolate, pHandle));\n") + fmt.Fprintf(implw, " Local<Object> instance;\n"); + fmt.Fprintf(implw, " if (cons->NewInstance(isolate->GetCurrentContext()).ToLocal (&instance)) {\n") + fmt.Fprintf(implw, " instance->SetInternalField (NODEWRAPPER_TABLEINDEX, External::New (isolate, C%sBaseClass::getDynamicWrapperTable (pParent)));\n", NameSpace) + fmt.Fprintf(implw, " instance->SetInternalField (NODEWRAPPER_HANDLEINDEX, External::New (isolate, pHandle));\n") + fmt.Fprintf(implw, " }\n"); fmt.Fprintf(implw, " return instance;\n") fmt.Fprintf(implw, "}\n") fmt.Fprintf(implw, "\n") @@ -773,7 +1155,7 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "\n") fmt.Fprintf(implw, "void C%sWrapper::New(const FunctionCallbackInfo<Value>& args)\n", NameSpace) fmt.Fprintf(implw, "{\n") - fmt.Fprintf(implw, " Isolate* isolate = Isolate::GetCurrent();\n") + fmt.Fprintf(implw, " Isolate* isolate = args.GetIsolate();\n") fmt.Fprintf(implw, " HandleScope scope(isolate);\n") fmt.Fprintf(implw, "\n") fmt.Fprintf(implw, " try {\n") @@ -791,7 +1173,7 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, " Local<Object> newObject = args.This();\n") fmt.Fprintf(implw, " std::auto_ptr<s%sDynamicWrapperTable> wrapperTable ( new s%sDynamicWrapperTable );\n", NameSpace, NameSpace) - fmt.Fprintf(implw, " CheckError (Load%sWrapperTable (wrapperTable.get(), sLibraryName.c_str()));\n", NameSpace) + fmt.Fprintf(implw, " CheckError (isolate, nullptr, nullptr, Load%sWrapperTable (wrapperTable.get(), sLibraryName.c_str()));\n", NameSpace) fmt.Fprintf(implw, " newObject->SetInternalField (NODEWRAPPER_TABLEINDEX, External::New (isolate, wrapperTable.release ()));\n") // write out enums @@ -810,7 +1192,7 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, " const int argc = 1;\n") fmt.Fprintf(implw, " Local<Value> argv[argc] = { args[0] };\n") fmt.Fprintf(implw, " Local<Function> cons = Local<Function>::New(isolate, constructor);\n") - fmt.Fprintf(implw, " args.GetReturnValue().Set(cons->NewInstance(argc, argv));\n") + fmt.Fprintf(implw, " args.GetReturnValue().Set(cons->NewInstance(isolate->GetCurrentContext(), argc, argv).ToLocalChecked());\n") fmt.Fprintf(implw, " }\n") fmt.Fprintf(implw, " } catch (std::exception & E) {\n") fmt.Fprintf(implw, " RaiseError (isolate, E.what());\n") @@ -821,10 +1203,9 @@ func buildNodeWrapperClass(component ComponentDefinition, w io.Writer, implw io. fmt.Fprintf(implw, "{\n") fmt.Fprintf(implw, " Isolate* isolate = Isolate::GetCurrent();\n") fmt.Fprintf(implw, " HandleScope scope(isolate);\n") - fmt.Fprintf(implw, " const unsigned argc = 1; // TODO: Find out how to not pass dummy parameters..\n") - fmt.Fprintf(implw, " Handle<Value> argv[argc] = { Number::New (isolate, 0.0) };\n") fmt.Fprintf(implw, " Local<Function> cons = Local<Function>::New(isolate, constructor);\n") - fmt.Fprintf(implw, " Local<Object> instance = cons->NewInstance(argc, argv);\n") + fmt.Fprintf(implw, " Local<Object> instance;\n"); + fmt.Fprintf(implw, " cons->NewInstance(isolate->GetCurrentContext()).ToLocal(&instance);\n") fmt.Fprintf(implw, " return instance;\n") fmt.Fprintf(implw, "}\n") @@ -854,7 +1235,16 @@ func buildNodeBindingGyp(component ComponentDefinition, w io.Writer, indentStrin fmt.Fprintf(w, "%s\"targets\": [\n", indentString) fmt.Fprintf(w, "%s%s{\n", indentString, indentString) fmt.Fprintf(w, "%s%s%s\"target_name\": \"%s_nodeaddon\",\n", indentString, indentString, indentString, BaseName) - fmt.Fprintf(w, "%s%s%s\"sources\": [ \"%s_nodeaddon.cc\", \"%s_nodewrapper.cc\", \"%s_dynamic.cpp\" ]\n", indentString, indentString, indentString, BaseName, BaseName, BaseName) + fmt.Fprintf(w, "%s%s%s\"sources\": [ \"%s_nodeaddon.cc\", \"%s_nodewrapper.cc\", \"%s_dynamic.cc\" ],\n", indentString, indentString, indentString, BaseName, BaseName, BaseName) + fmt.Fprintf(w, "%s%s%s\"cflags\": [ \"-fexceptions \" ],\n", indentString, indentString, indentString ) + fmt.Fprintf(w, "%s%s%s\"cflags_cc\": [ \"-fexceptions \" ],\n", indentString, indentString, indentString ) + fmt.Fprintf(w, "%s%s%s\"msvs_settings\": {\n", indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s%s%s\"VCCLCompilerTool\": { \"ExceptionHandling\": 1 }\n", indentString, indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s%s},\n", indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s%s\"conditions\": [\n", indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s%s%s[\"OS=='win'\", { \"defines\": [ \"_HAS_EXCEPTIONS=1\" ] }]\n", indentString, indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s%s]\n", indentString, indentString, indentString) + fmt.Fprintf(w, "%s%s}\n", indentString, indentString) fmt.Fprintf(w, "%s]\n", indentString) fmt.Fprintf(w, "}\n") diff --git a/Source/buildbindingpascal.go b/Source/buildbindingpascal.go index c7446806..ab644dff 100644 --- a/Source/buildbindingpascal.go +++ b/Source/buildbindingpascal.go @@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ////////////////////////////////////////////////////////////////////////////////////////////////////// // buildbindingpascal.go -// functions to generate dynamic Pascal-bindings of a library's API in form of dynamically loaded functions -// handles. +// functions to generate dynamic Pascal-bindings of a library's API in form of explicitly loaded +// function handles. ////////////////////////////////////////////////////////////////////////////////////////////////////// package main @@ -41,14 +41,14 @@ import ( "strings" ) -// BuildBindingPascalDynamic builds dynamic Pascal bindings of a library's API in form of dynamically loaded functions -// handles. -func BuildBindingPascalDynamic(componentdefinition ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { +// BuildBindingPascalDynamic builds dynamic Pascal bindings of a library's API in form of explicitly loaded +// function handles. +func BuildBindingPascalDynamic(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { forceRecreation := false - namespace := componentdefinition.NameSpace; - libraryname := componentdefinition.LibraryName; - baseName := componentdefinition.BaseName; + namespace := component.NameSpace; + libraryname := component.LibraryName; + baseName := component.BaseName; DynamicPascalImpl := path.Join(outputFolder, "Unit_" + namespace+".pas"); log.Printf("Creating \"%s\"", DynamicPascalImpl) @@ -58,11 +58,11 @@ func BuildBindingPascalDynamic(componentdefinition ComponentDefinition, outputFo } dynpascalfile.Writeln("{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}") - dynpascalfile.WritePascalLicenseHeader(componentdefinition, + dynpascalfile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal Header file in order to allow an easy\n use of %s", libraryname), true) - err = buildDynamicPascalImplementation(componentdefinition, dynpascalfile, namespace, baseName) + err = buildDynamicPascalImplementation(component, dynpascalfile, namespace, baseName) if err != nil { return err; } @@ -72,10 +72,10 @@ func BuildBindingPascalDynamic(componentdefinition ComponentDefinition, outputFo if (forceRecreation || !FileExists(DynamicPascalExample)) { log.Printf("Creating \"%s\"", DynamicPascalExample) dynpascalexamplefile, err := CreateLanguageFile (DynamicPascalExample, indentString) - dynpascalexamplefile.WritePascalLicenseHeader(componentdefinition, + dynpascalexamplefile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal application that demonstrates the\n usage of the Pascal bindings of %s", libraryname), true) - err = buildDynamicPascalExample(dynpascalexamplefile, componentdefinition.Global, namespace, baseName, outputFolder) + err = buildDynamicPascalExample(dynpascalexamplefile, component.Global, namespace, baseName, outputFolder) if err != nil { return err; } @@ -102,16 +102,16 @@ func BuildBindingPascalDynamic(componentdefinition ComponentDefinition, outputFo } -func writeEnumConversionInterface(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string) error { +func writeEnumConversionInterface(component ComponentDefinition, w LanguageWriter, NameSpace string) error { - if (len(componentdefinition.Enums) > 0) { + if (len(component.Enums) > 0) { w.Writeln ("(*************************************************************************************************************************"); w.Writeln (" Enum conversion"); w.Writeln ("**************************************************************************************************************************)"); w.Writeln (""); - for i := 0; i < len(componentdefinition.Enums); i++ { - enum := componentdefinition.Enums[i]; + for i := 0; i < len(component.Enums); i++ { + enum := component.Enums[i]; w.Writeln (" function convert%sToConst (const AValue: T%s%s): Integer;", enum.Name, NameSpace, enum.Name); w.Writeln (" function convertConstTo%s (const AValue: Integer): T%s%s;", enum.Name, NameSpace, enum.Name); } @@ -123,17 +123,17 @@ func writeEnumConversionInterface(componentdefinition ComponentDefinition, w Lan } -func writeEnumConversionImplementation(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string) error { +func writeEnumConversionImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string) error { - if (len(componentdefinition.Enums) > 0) { + if (len(component.Enums) > 0) { w.Writeln ("(*************************************************************************************************************************"); w.Writeln (" Enum conversion"); w.Writeln ("**************************************************************************************************************************)"); w.Writeln (""); - for i := 0; i < len(componentdefinition.Enums); i++ { - enum := componentdefinition.Enums[i]; + for i := 0; i < len(component.Enums); i++ { + enum := component.Enums[i]; w.Writeln (" function convert%sToConst (const AValue: T%s%s): Integer;", enum.Name, NameSpace, enum.Name); w.Writeln (" begin"); w.Writeln (" case AValue of"); @@ -172,7 +172,7 @@ func writeEnumConversionImplementation(componentdefinition ComponentDefinition, } -func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildDynamicPascalImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { w.Writeln ("unit Unit_%s;", NameSpace) w.Writeln ("") @@ -190,7 +190,7 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln ("") - err := writePascalBaseTypeDefinitions (componentdefinition, w, NameSpace, BaseName); + err := writePascalBaseTypeDefinitions (component, w, NameSpace, BaseName); if (err != nil) { return err; } @@ -199,19 +199,18 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" Declaration of handle classes "); w.Writeln ("**************************************************************************************************************************)"); w.Writeln (""); - w.Writeln ("type"); - w.Writeln (" T%sBaseClass = class;", NameSpace); - w.Writeln (" T%sWrapper = class;", NameSpace); + w.Writeln ("type"); + w.Writeln (" T%sWrapper = class;", NameSpace); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i]; - w.Writeln (" T%s%s = class;", NameSpace, class.ClassName); + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i]; + w.Writeln (" T%s%s = class;", NameSpace, class.ClassName); } w.Writeln (""); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] w.Writeln ("") w.Writeln ("(*************************************************************************************************************************") @@ -234,7 +233,7 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln ("**************************************************************************************************************************)") w.Writeln (""); - global := componentdefinition.Global; + global := component.Global; for j := 0; j < len(global.Methods); j++ { method := global.Methods[j] @@ -256,29 +255,29 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" public"); w.Writeln (" property ErrorCode: T%sResult read FErrorCode;", NameSpace); w.Writeln (" property CustomMessage: String read FCustomMessage;"); - w.Writeln (" constructor Create (AErrorCode: T%sResult);", NameSpace); + w.Writeln (" constructor Create (AErrorCode: T%sResult; AMessage: String);", NameSpace); w.Writeln (" constructor CreateCustomMessage (AErrorCode: T%sResult; AMessage: String);", NameSpace); w.Writeln (" end;"); w.Writeln ("") - w.Writeln ("(*************************************************************************************************************************"); - w.Writeln (" Base class definition"); - w.Writeln ("**************************************************************************************************************************)"); - w.Writeln ("") - w.Writeln (" T%sBaseClass = class (TObject)", NameSpace); - w.Writeln (" private"); - w.Writeln (" FWrapper: T%sWrapper;", NameSpace); - w.Writeln (" FHandle: T%sHandle;", NameSpace); - w.Writeln (" public"); - w.Writeln (" constructor Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, NameSpace); - w.Writeln (" destructor Destroy; override;"); - w.Writeln (" end;"); - w.Writeln ("") - - - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + // w.Writeln ("(*************************************************************************************************************************"); + // w.Writeln (" Base class definition"); + // w.Writeln ("**************************************************************************************************************************)"); + // w.Writeln ("") + // w.Writeln (" T%sBaseClass = class (TObject)", NameSpace); + // w.Writeln (" private"); + // w.Writeln (" FWrapper: T%sWrapper;", NameSpace); + // w.Writeln (" FHandle: T%sHandle;", NameSpace); + // w.Writeln (" public"); + // w.Writeln (" constructor Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, NameSpace); + // w.Writeln (" destructor Destroy; override;"); + // w.Writeln (" end;"); + // w.Writeln ("") + + pascalBaseClassName := "T"+NameSpace + component.Global.BaseClassName + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] w.Writeln ("") w.Writeln ("(*************************************************************************************************************************") @@ -286,18 +285,32 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln ("**************************************************************************************************************************)") w.Writeln (""); + pascalParentClassName := "" + if (!component.isBaseClass(class)) { + if class.ParentClass == "" { + pascalParentClassName = pascalBaseClassName + } else { + pascalParentClassName = "T" + NameSpace + class.ParentClass + } + } + parentClassName := class.ParentClass if parentClassName == "" { parentClassName = "BaseClass" } - - w.Writeln (" T%s%s = class (T%s%s)", NameSpace, class.ClassName, NameSpace, parentClassName); - w.Writeln (" private"); + if (component.isBaseClass(class)) { + w.Writeln (" %s = class (TObject)", pascalBaseClassName); + w.Writeln(" private") + w.Writeln(" FWrapper: TLibPrimesWrapper;") + w.Writeln(" FHandle: TLibPrimesHandle;") + } else { + w.Writeln (" T%s%s = class (%s)", NameSpace, class.ClassName, pascalParentClassName); + } w.Writeln (" public"); w.Writeln (" constructor Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, NameSpace); w.Writeln (" destructor Destroy; override;"); - + for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] err := writePascalClassMethodDefinition(method, w, NameSpace, class.ClassName, false, " ", false) @@ -306,7 +319,7 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w } } - w.Writeln (" end;"); + w.Writeln (" end;"); w.Writeln ("") } @@ -319,8 +332,8 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" private"); w.Writeln (" FModule: HMODULE;"); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] @@ -347,8 +360,8 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" protected"); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] @@ -360,66 +373,59 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w for j := 0; j < len(global.Methods); j++ { method := global.Methods[j] - w.Writeln (" property %s%sFunc: T%s%sFunc read F%s%sFunc;", NameSpace, method.MethodName, NameSpace, method.MethodName, NameSpace, method.MethodName); - } + w.Writeln (" procedure CheckError (AInstance: %s; AErrorCode: T%sResult);", pascalBaseClassName, NameSpace); - w.Writeln (" procedure CheckError (AInstance: T%sBaseClass; AErrorCode: T%sResult);", NameSpace, NameSpace); + w.Writeln (" public"); - w.Writeln (" public"); - - w.Writeln (" constructor Create (ADLLName: String);"); - w.Writeln (" destructor Destroy; override;"); + w.Writeln (" constructor Create (ADLLName: String);"); + w.Writeln (" destructor Destroy; override;"); for j := 0; j < len(global.Methods); j++ { method := global.Methods[j] - + err := writePascalClassMethodDefinition(method, w, NameSpace, "Wrapper", true, " ", false) if err != nil { return err; } } - - - w.Writeln (" end;"); + w.Writeln (" end;"); w.Writeln ("") - - writeEnumConversionInterface (componentdefinition, w, NameSpace); - + writeEnumConversionInterface (component, w, NameSpace); w.Writeln ("") w.Writeln ("implementation") w.Writeln ("") - writeEnumConversionImplementation (componentdefinition, w, NameSpace); + writeEnumConversionImplementation (component, w, NameSpace); w.Writeln ("") w.Writeln ("(*************************************************************************************************************************"); w.Writeln (" Exception implementation"); w.Writeln ("**************************************************************************************************************************)"); w.Writeln ("") - w.Writeln (" constructor E%sException.Create (AErrorCode: T%sResult);", NameSpace, NameSpace); + w.Writeln (" constructor E%sException.Create (AErrorCode: T%sResult; AMessage: String);", NameSpace, NameSpace); w.Writeln (" var"); w.Writeln (" ADescription: String;"); w.Writeln (" begin"); w.Writeln (" FErrorCode := AErrorCode;"); w.Writeln (" case FErrorCode of"); - for _, error := range componentdefinition.Errors.Errors { + for _, error := range component.Errors.Errors { w.Writeln (" %s_ERROR_%s: ADescription := '%s';", strings.ToUpper (NameSpace), error.Name, error.Description); } - w.Writeln (" else"); - w.Writeln (" ADescription := 'unknown';"); - w.Writeln (" end;"); + w.Writeln (" else"); + w.Writeln (" ADescription := 'unknown';"); + w.Writeln (" end;"); w.Writeln ("") - w.Writeln (" inherited Create (Format ('%s Error - %%s (#%%d)', [ ADescription, AErrorCode ]));", componentdefinition.LibraryName); - w.Writeln (" end;"); + w.Writeln (" inherited Create (Format ('%s Error - %%s (#%%d, %%s)', [ ADescription, AErrorCode, AMessage ]));", component.LibraryName); + w.Writeln (" end;"); w.Writeln ("") w.Writeln (" constructor E%sException.CreateCustomMessage (AErrorCode: T%sResult; AMessage: String);", NameSpace, NameSpace); w.Writeln (" begin"); @@ -429,46 +435,41 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" end;"); w.Writeln ("") - w.Writeln ("(*************************************************************************************************************************"); - w.Writeln (" Base class implementation"); - w.Writeln ("**************************************************************************************************************************)"); - w.Writeln ("") - w.Writeln (" constructor T%sBaseClass.Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, NameSpace, NameSpace); - w.Writeln (" begin"); - w.Writeln (" if not Assigned (AWrapper) then"); - w.Writeln (" raise E%sException.Create (%s_ERROR_INVALIDPARAM);", NameSpace, strings.ToUpper (NameSpace)); - w.Writeln (" if not Assigned (AHandle) then"); - w.Writeln (" raise E%sException.Create (%s_ERROR_INVALIDPARAM);", NameSpace, strings.ToUpper (NameSpace)); - w.Writeln ("") - w.Writeln (" inherited Create ();"); - w.Writeln (" FWrapper := AWrapper;"); - w.Writeln (" FHandle := AHandle;"); - w.Writeln (" end;"); - w.Writeln ("") - w.Writeln (" destructor T%sBaseClass.Destroy;", NameSpace); - w.Writeln (" begin"); - w.Writeln (" FWrapper.ReleaseInstance(self);"); - w.Writeln (" inherited;"); - w.Writeln (" end;"); - w.Writeln ("") - - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] w.Writeln ("(*************************************************************************************************************************") w.Writeln (" Class implementation for %s", class.ClassName) w.Writeln ("**************************************************************************************************************************)") w.Writeln (""); - - w.Writeln (" constructor T%s%s.Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, class.ClassName, NameSpace, NameSpace); - w.Writeln (" begin"); - w.Writeln (" inherited Create (AWrapper, AHandle);"); - w.Writeln (" end;"); + + if (component.isBaseClass(class)) { + w.Writeln (" constructor %s.Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", pascalBaseClassName, NameSpace, NameSpace); + w.Writeln (" begin"); + w.Writeln (" if not Assigned (AWrapper) then"); + w.Writeln (" raise E%sException.Create (%s_ERROR_INVALIDPARAM, '');", NameSpace, strings.ToUpper (NameSpace)); + w.Writeln (" if not Assigned (AHandle) then"); + w.Writeln (" raise E%sException.Create (%s_ERROR_INVALIDPARAM, '');", NameSpace, strings.ToUpper (NameSpace)); + w.Writeln ("") + w.Writeln (" inherited Create ();"); + w.Writeln (" FWrapper := AWrapper;"); + w.Writeln (" FHandle := AHandle;"); + w.Writeln (" end;"); + } else { + w.Writeln (" constructor T%s%s.Create (AWrapper: T%sWrapper; AHandle: T%sHandle);", NameSpace, class.ClassName, NameSpace, NameSpace); + w.Writeln (" begin"); + w.Writeln (" inherited Create (AWrapper, AHandle);"); + w.Writeln (" end;"); + } + w.Writeln ("") - w.Writeln (" destructor T%s%s.Destroy;", NameSpace, class.ClassName); - w.Writeln (" begin"); - w.Writeln (" inherited;"); - w.Writeln (" end;"); + w.Writeln (" destructor T%s%s.Destroy;", NameSpace, class.ClassName); + w.Writeln (" begin"); + if (component.isBaseClass(class)) { + w.Writeln (" FWrapper.%s(self);", component.Global.ReleaseMethod); + } + w.Writeln (" inherited;"); + w.Writeln (" end;"); w.Writeln ("") @@ -502,11 +503,11 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" FModule := dynlibs.LoadLibrary (ADLLName);"); w.Writeln (" {$ENDIF MSWINDOWS}"); w.Writeln (" if FModule = 0 then"); - w.Writeln (" raise E%sException.Create (%s_ERROR_COULDNOTLOADLIBRARY);", NameSpace, strings.ToUpper (NameSpace)); + w.Writeln (" raise E%sException.Create (%s_ERROR_COULDNOTLOADLIBRARY, '');", NameSpace, strings.ToUpper (NameSpace)); w.Writeln ("") - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] @@ -537,14 +538,23 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" inherited;"); w.Writeln (" end;"); w.Writeln ("") - w.Writeln (" procedure T%sWrapper.CheckError (AInstance: T%sBaseClass; AErrorCode: T%sResult);", NameSpace, NameSpace, NameSpace); + w.Writeln (" procedure T%sWrapper.CheckError (AInstance: %s; AErrorCode: T%sResult);", NameSpace, pascalBaseClassName, NameSpace); + w.Writeln (" var") + w.Writeln (" AErrorMessage: String;") w.Writeln (" begin") w.Writeln (" if AInstance <> nil then begin"); w.Writeln (" if AInstance.FWrapper <> Self then"); w.Writeln (" raise E%sException.CreateCustomMessage (%s_ERROR_INVALIDCAST, 'invalid wrapper call');", NameSpace, strings.ToUpper (NameSpace)); w.Writeln (" end;"); - w.Writeln (" if AErrorCode <> %s_SUCCESS then", strings.ToUpper (NameSpace)); - w.Writeln (" raise E%sException.Create (AErrorCode);", NameSpace); + + w.Writeln (" if AErrorCode <> %s_SUCCESS then begin", strings.ToUpper (NameSpace)); + w.Writeln (" AErrorMessage := '';"); + + w.Writeln (" if Assigned (AInstance) then"); + w.Writeln (" %s(AInstance, AErrorMessage);", component.Global.ErrorMethod); + + w.Writeln (" raise E%sException.Create (AErrorCode, AErrorMessage);", NameSpace); + w.Writeln (" end;") w.Writeln (" end;") w.Writeln ("") @@ -572,7 +582,7 @@ func buildDynamicPascalImplementation(componentdefinition ComponentDefinition, w w.Writeln (" begin") w.Writeln (" %s(AMajor, AMinor, AMicro);", global.VersionMethod) w.Writeln (" if (AMajor <> %s_VERSION_MAJOR) or (AMinor < %s_VERSION_MINOR) then", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace)) - w.Writeln (" raise E%sException.Create(%s_ERROR_INCOMPATIBLEBINARYVERSION);", NameSpace, strings.ToUpper(NameSpace)) + w.Writeln (" raise E%sException.Create(%s_ERROR_INCOMPATIBLEBINARYVERSION, '');", NameSpace, strings.ToUpper(NameSpace)) w.Writeln (" end;") w.Writeln (" ") @@ -707,7 +717,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L case "in": switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": callFunctionParameters = callFunctionParameters + "A" + param.ParamName; initCallParameters = initCallParameters + "A" + param.ParamName; @@ -769,7 +779,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L callFunctionParameters = callFunctionParameters + "A" + param.ParamName; initCallParameters = initCallParameters + "A" + param.ParamName; - case "handle": + case "class": initCommands = append (initCommands, fmt.Sprintf (" if not Assigned (A%s) then", param.ParamName)); initCommands = append (initCommands, fmt.Sprintf (" raise E%sException.CreateCustomMessage (%s_ERROR_INVALIDPARAM, 'A%s is a nil value.');", NameSpace, strings.ToUpper (NameSpace), param.ParamName)); callFunctionParameters = callFunctionParameters + "A" + param.ParamName + ".FHandle"; @@ -784,7 +794,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L case "out": switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": callFunctionParameters = callFunctionParameters + "A" + param.ParamName; initCallParameters = initCallParameters + "A" + param.ParamName; @@ -811,13 +821,15 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L initCommands = append (initCommands, " Result" + param.ParamName + " := 0;"); callFunctionParameters = callFunctionParameters + "Result" + param.ParamName; + initCallParameters = initCallParameters + "Result" + param.ParamName; resultCommands = append (resultCommands, fmt.Sprintf (" A%s := convertConstTo%s (Result%s);", param.ParamName, param.ParamClass, param.ParamName)); case "bool": - defineCommands = append (defineCommands, " Result" + param.ParamName + ": Cardinal;"); + defineCommands = append (defineCommands, " Result" + param.ParamName + ": Byte;"); initCommands = append (initCommands, " Result" + param.ParamName + " := 0;"); - callFunctionParameters = callFunctionParameters + "Result" + param.ParamName; + callFunctionParameters = callFunctionParameters + "Result" + param.ParamName + initCallParameters = initCallParameters + "Result" + param.ParamName resultCommands = append (resultCommands, fmt.Sprintf (" A%s := Result%s <> 0;", param.ParamName, param.ParamName)); case "struct": @@ -839,7 +851,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L doInitCall = true; - case "handle": + case "class": defineCommands = append (defineCommands, " H" + param.ParamName + ": " + PlainParamTypeName + ";"); initCommands = append (initCommands, " Result := nil;"); initCommands = append (initCommands, " A%s := nil;", param.ParamName); @@ -858,7 +870,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L case "return": switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": callFunctionParameters = callFunctionParameters + "Result"; case "string": @@ -885,13 +897,15 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L initCommands = append (initCommands, " Result" + param.ParamName + " := 0;"); callFunctionParameters = callFunctionParameters + "Result" + param.ParamName; + initCallParameters = initCallParameters + "Result" + param.ParamName; resultCommands = append (resultCommands, fmt.Sprintf (" Result := convertConstTo%s (Result%s);", param.ParamClass, param.ParamName)); case "bool": - defineCommands = append (defineCommands, " Result" + param.ParamName + ": Cardinal;"); + defineCommands = append (defineCommands, " Result" + param.ParamName + ": Byte;"); initCommands = append (initCommands, " Result" + param.ParamName + " := 0;"); callFunctionParameters = callFunctionParameters + "Result" + param.ParamName; + initCallParameters = initCallParameters + "Result" + param.ParamName; resultCommands = append (resultCommands, fmt.Sprintf (" Result := (Result%s <> 0);", param.ParamName)); case "struct": @@ -911,7 +925,7 @@ func writePascalClassMethodImplementation (method ComponentDefinitionMethod, w L doInitCall = true; - case "handle": + case "class": defineCommands = append (defineCommands, " H" + param.ParamName + ": " + PlainParamTypeName + ";"); initCommands = append (initCommands, " Result := nil;"); initCommands = append (initCommands, " H" + param.ParamName + " := nil;"); @@ -1054,15 +1068,28 @@ func buildDynamicPascalExample(w LanguageWriter, global ComponentDefinitionGloba w.Writeln("var") w.Writeln(" A%sWrapper: T%sWrapper;", NameSpace, NameSpace) w.Writeln(" AMajor, AMinor, AMicro: Cardinal;") + if len(global.PrereleaseMethod)>0 { + w.Writeln(" APreReleaseInfo, ABuildInfo: string;") + } + w.Writeln(" AVersionString: string;") w.Writeln(" ALibPath: string;") w.Writeln("begin") w.Writeln(" writeln ('loading DLL');") w.Writeln(" ALibPath := ''; // TODO add the location of the shared library binary here") - w.Writeln(" A%sWrapper := T%sWrapper.Create (ALibPath + '/' + '%s.dll');", NameSpace, NameSpace, BaseName) + w.Writeln(" A%sWrapper := T%sWrapper.Create (ALibPath + '/' + '%s.'); // TODO add the extension of the shared library file here", NameSpace, NameSpace, BaseName) w.Writeln(" try") w.Writeln(" writeln ('loading DLL Done');") w.Writeln(" A%sWrapper.%s(AMajor, AMinor, AMicro);", NameSpace, global.VersionMethod) - w.Writeln(" writeln (Format('%s.version = %s', [AMajor, AMinor, AMicro]));",NameSpace, "%d.%d.%d") + w.Writeln(" AVersionString := Format('%s.version = %s', [AMajor, AMinor, AMicro]);", NameSpace, "%d.%d.%d") + if len(global.PrereleaseMethod)>0 { + w.Writeln(" if (A%sWrapper.%s(APreReleaseInfo) then", NameSpace, global.PrereleaseMethod) + w.Writeln(" AVersionString := AVersionString + '-' + APreReleaseInfo;") + } + if len(global.BuildinfoMethod)>0 { + w.Writeln(" if (A%sWrapper.%s(ABuildInfo) then", NameSpace, global.BuildinfoMethod) + w.Writeln(" AVersionString := AVersionString + '-' + ABuildInfo;") + } + w.Writeln(" writeln(AVersionString);") w.Writeln(" finally") w.Writeln(" FreeAndNil(A%sWrapper);", NameSpace) w.Writeln(" end;") @@ -1116,21 +1143,21 @@ func buildDynamicPascalExampleLPI(w LanguageWriter, NameSpace string, BaseName s w.Writeln (" <PathDelim Value=\"\\\"/>"); w.Writeln (" <General>"); w.Writeln (" <Flags>"); - w.Writeln (" <MainUnitHasCreateFormStatements Value=\"False\" />"); - w.Writeln (" <MainUnitHasTitleStatement Value=\"False\" />"); - w.Writeln (" <MainUnitHasScaledStatement Value=\"False\" />"); + w.Writeln (" <MainUnitHasCreateFormStatements Value=\"False\"/>"); + w.Writeln (" <MainUnitHasTitleStatement Value=\"False\"/>"); + w.Writeln (" <MainUnitHasScaledStatement Value=\"False\"/>"); w.Writeln (" </Flags>"); - w.Writeln (" <SessionStorage Value=\"InProjectDir\" />"); + w.Writeln (" <SessionStorage Value=\"InProjectDir\"/>"); w.Writeln (" <MainUnit Value=\"%d\"/>", 0); - w.Writeln (" <Title Value=\"%s_Example\" />", NameSpace); - w.Writeln (" <UseAppBundle Value=\"False\" />"); - w.Writeln (" <ResourceType Value=\"res\" />"); + w.Writeln (" <Title Value=\"%s_Example\"/>", NameSpace); + w.Writeln (" <UseAppBundle Value=\"False\"/>"); + w.Writeln (" <ResourceType Value=\"res\"/>"); w.Writeln (" </General>"); w.Writeln (" <BuildModes Count=\"%d\">", 2); w.Writeln (" <Item1 Name=\"Release\" Default=\"True\"/>"); w.Writeln (" <Item2 Name=\"Debug\">"); w.Writeln (" <CompilerOptions>"); - w.Writeln (" <Version Value=\"11\" />"); + w.Writeln (" <Version Value=\"11\"/>"); w.Writeln (" <PathDelim Value=\"\\\"/>"); w.Writeln (" <Target>"); w.Writeln (" <Filename Value=\"bin\\$(TargetCPU)-$(TargetOS)\\Release\\%s_Example\"/>", NameSpace); @@ -1146,7 +1173,7 @@ func buildDynamicPascalExampleLPI(w LanguageWriter, NameSpace string, BaseName s w.Writeln (" </SyntaxOptions>"); w.Writeln (" </Parsing>"); w.Writeln (" <CodeGeneration>"); - w.Writeln (" <RelocatableUnit Value=\"True\" />"); + w.Writeln (" <RelocatableUnit Value=\"True\"/>"); w.Writeln (" </CodeGeneration>"); w.Writeln (" <Linking>"); w.Writeln (" <Debugging>"); diff --git a/Source/buildbindingpython.go b/Source/buildbindingpython.go index bf0a3cf7..c12e6c98 100644 --- a/Source/buildbindingpython.go +++ b/Source/buildbindingpython.go @@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ////////////////////////////////////////////////////////////////////////////////////////////////////// // buildbindingpython.go -// functions to generate dynamic Python3-bindings of a library's API in form of dynamically loaded functions -// handles. +// functions to generate dynamic Python3-bindings of a library's API in form of explicitly loaded +// function handles. ////////////////////////////////////////////////////////////////////////////////////////////////////// package main @@ -40,8 +40,8 @@ import ( "path" ) -// BuildBindingPythonDynamic builds dynamic Python bindings of a library's API in form of dynamically loaded functions -// handles. +// BuildBindingPythonDynamic builds dynamic Python bindings of a library's API in form of explicitly loaded +// functions handles. func BuildBindingPythonDynamic(componentdefinition ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { forceRecreation := false @@ -72,7 +72,7 @@ func BuildBindingPythonDynamic(componentdefinition ComponentDefinition, outputFo dynpythonexamplefile.WritePythonLicenseHeader(componentdefinition, fmt.Sprintf("This is an autogenerated Python application that demonstrates the\n usage of the Python bindings of %s", libraryname), true) - err = buildDynamiCPythonExample(componentdefinition, dynpythonexamplefile, outputFolder) + err = buildDynamicPythonExample(componentdefinition, dynpythonexamplefile, outputFolder) if err != nil { return err; } @@ -88,7 +88,7 @@ func BuildBindingPythonDynamic(componentdefinition ComponentDefinition, outputFo func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w LanguageWriter) error { NameSpace := componentdefinition.NameSpace - // BaseName := componentdefinition.BaseName + BaseName := componentdefinition.BaseName w.Writeln("") w.Writeln("import ctypes") @@ -96,6 +96,9 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("import enum") w.Writeln("") + w.Writeln("name = \"%s\"", BaseName) + w.Writeln("") + w.Writeln("'''Definition of domain specific exception") w.Writeln("'''") w.Writeln("class E%sException(Exception):", NameSpace) @@ -112,7 +115,7 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("'''Definition of binding API version") w.Writeln("'''") - w.Writeln("class %sBindingVersion(enum.IntEnum):", NameSpace) + w.Writeln("class BindingVersion(enum.IntEnum):") w.Writeln(" MAJOR = %d", majorVersion(componentdefinition.Version)) w.Writeln(" MINOR = %d", minorVersion(componentdefinition.Version)) w.Writeln(" MICRO = %d", microVersion(componentdefinition.Version)) @@ -120,7 +123,7 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("'''Definition Error Codes") w.Writeln("'''") - w.Writeln("class %sErrorCodes(enum.IntEnum):", NameSpace) + w.Writeln("class ErrorCodes(enum.IntEnum):") w.Writeln(" SUCCESS = 0") for i := 0; i<len(componentdefinition.Errors.Errors); i++ { merror := componentdefinition.Errors.Errors[i] @@ -141,9 +144,9 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w for i := 0; i<len(componentdefinition.Enums); i++ { enum := componentdefinition.Enums[i] - w.Writeln("'''Definition of %s%s", NameSpace, enum.Name) + w.Writeln("'''Definition of %s", enum.Name) w.Writeln("'''") - w.Writeln("class %s%s(CTypesEnum):", NameSpace, enum.Name) + w.Writeln("class %s(CTypesEnum):", enum.Name) for j:= 0; j<len(enum.Options); j++ { option := enum.Options[j] w.Writeln(" %s = %d", option.Name, option.Value) @@ -157,9 +160,9 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("'''") for i := 0; i<len(componentdefinition.Structs); i++ { _struct := componentdefinition.Structs[i] - w.Writeln("'''Definition of %s%s", NameSpace, _struct.Name) + w.Writeln("'''Definition of %s", _struct.Name) w.Writeln("'''") - w.Writeln("class %s%s(ctypes.Structure):", NameSpace, _struct.Name) + w.Writeln("class %s(ctypes.Structure):", _struct.Name) if (len(_struct.Members) > 0) { w.Writeln(" _pack_ = 1") w.Writeln(" _fields_ = [") @@ -198,7 +201,7 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("'''") for i := 0; i<len(componentdefinition.Functions); i++ { _func := componentdefinition.Functions[i] - w.Writeln("'''Definition of %s%s", NameSpace, _func.FunctionName) + w.Writeln("'''Definition of %s", _func.FunctionName) w.Writeln(" %s", _func.FunctionDescription) w.Writeln("'''") arguments := "ctypes.c_void_p" @@ -213,7 +216,7 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w } arguments = arguments + cParams[0].ParamType } - w.Writeln("%s%s = ctypes.CFUNCTYPE(%s)", NameSpace, _func.FunctionName, arguments) + w.Writeln("%s = ctypes.CFUNCTYPE(%s)", _func.FunctionName, arguments) } w.Writeln("") } @@ -221,10 +224,10 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln("") w.Writeln("'''Wrapper Class Implementation") w.Writeln("'''") - w.Writeln("class %sWrapper:", NameSpace) + w.Writeln("class Wrapper:") w.Writeln("") - w.Writeln(" def __init__(self, libraryName):") + w.Writeln(" def __init__(self, libraryName = None):") w.Writeln(" ending = ''") w.Writeln(" if platform.system() == 'Windows':") w.Writeln(" ending = 'dll'") @@ -233,14 +236,16 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w w.Writeln(" elif platform.system() == 'Darwin':") w.Writeln(" ending = 'dylib'") w.Writeln(" else:") - w.Writeln(" raise E%sException(%sErrorCodes.COULDNOTLOADLIBRARY)", NameSpace, NameSpace) + w.Writeln(" raise E%sException(ErrorCodes.COULDNOTLOADLIBRARY)", NameSpace) w.Writeln(" ") + w.Writeln(" if (not libraryName):") + w.Writeln(" libraryName = os.path.join(os.path.dirname(os.path.realpath(__file__)),'%s')", BaseName) w.Writeln(" path = libraryName + '.' + ending") w.Writeln(" ") w.Writeln(" try:") w.Writeln(" self.lib = ctypes.CDLL(path)") w.Writeln(" except Exception as e:") - w.Writeln(" raise E%sException(%sErrorCodes.COULDNOTLOADLIBRARY, str(e) + '| \"'+path + '\"' )", NameSpace, NameSpace ) + w.Writeln(" raise E%sException(ErrorCodes.COULDNOTLOADLIBRARY, str(e) + '| \"'+path + '\"' )", NameSpace ) w.Writeln(" ") w.Writeln(" self._loadFunctionTable()") w.Writeln(" ") @@ -254,21 +259,23 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w return err } w.Writeln(" except AttributeError as ae:") - w.Writeln(" raise E%sException(%sErrorCodes.COULDNOTFINDLIBRARYEXPORT, ae.args[0])", NameSpace, NameSpace) + w.Writeln(" raise E%sException(ErrorCodes.COULDNOTFINDLIBRARYEXPORT, ae.args[0])", NameSpace) w.Writeln(" ") w.Writeln(" def _checkBinaryVersion(self):") w.Writeln(" nMajor, nMinor, _ = self.%s()", componentdefinition.Global.VersionMethod) - w.Writeln(" if (nMajor != %sBindingVersion.MAJOR) or (nMinor < %sBindingVersion.MINOR):", NameSpace, NameSpace) - w.Writeln(" raise E%sException(%sErrorCodes.INCOMPATIBLEBINARYVERSION)", NameSpace, NameSpace) + w.Writeln(" if (nMajor != BindingVersion.MAJOR) or (nMinor < BindingVersion.MINOR):") + w.Writeln(" raise E%sException(ErrorCodes.INCOMPATIBLEBINARYVERSION)", NameSpace) w.Writeln(" ") + w.Writeln(" def checkError(self, instance, errorCode):") - w.Writeln(" if instance:") - w.Writeln(" if instance._wrapper != self:") - w.Writeln(" raise E%sException(%sErrorCodes.INVALIDCAST, 'invalid wrapper call')", NameSpace, NameSpace) - w.Writeln(" if errorCode != %sErrorCodes.SUCCESS.value:", NameSpace) - w.Writeln(" raise E%sException(errorCode)", NameSpace) + w.Writeln(" if errorCode != ErrorCodes.SUCCESS.value:") + w.Writeln(" if instance:") + w.Writeln(" if instance._wrapper != self:") + w.Writeln(" raise E%sException(ErrorCodes.INVALIDCAST, 'invalid wrapper call')", NameSpace) + w.Writeln(" message,_ = self.%s(instance)", componentdefinition.Global.ErrorMethod) + w.Writeln(" raise E%sException(errorCode, message)", NameSpace) w.Writeln(" ") for j:=0; j<len(componentdefinition.Global.Methods); j++ { @@ -279,22 +286,10 @@ func buildDynamicPythonImplementation(componentdefinition ComponentDefinition, w } } - w.Writeln("'''Base Class Implementation") - w.Writeln("'''") - w.Writeln("class %sBaseClass():", NameSpace) - w.Writeln(" def __init__(self, handle, wrapper):") - w.Writeln(" if not handle or not wrapper:") - w.Writeln(" raise E%sException()", NameSpace) - w.Writeln(" self._handle = handle") - w.Writeln(" self._wrapper = wrapper") - w.Writeln(" ") - w.Writeln(" def __del__(self):") - w.Writeln(" self._wrapper.%s(self)", componentdefinition.Global.ReleaseMethod) - for i:=0; i<len(componentdefinition.Classes); i++ { w.Writeln("") w.Writeln("") - err = writeClass(componentdefinition.Classes[i], w, NameSpace) + err = writePythonClass(componentdefinition, componentdefinition.Classes[i], w, NameSpace) if (err!=nil) { return err } @@ -395,6 +390,8 @@ func getCTypesParameterTypeName(ParamTypeName string, NameSpace string, ParamCla CTypesParamTypeName = "ctypes.c_float"; case "double": CTypesParamTypeName = "ctypes.c_double"; + case "pointer": + CTypesParamTypeName = "ctypes.c_void_p"; case "string": CTypesParamTypeName = "ctypes.c_char_p"; case "basicarray": @@ -404,14 +401,14 @@ func getCTypesParameterTypeName(ParamTypeName string, NameSpace string, ParamCla } CTypesParamTypeName = dummy case "enum": - return fmt.Sprintf("%s%s", NameSpace, ParamClass), nil + return fmt.Sprintf("%s", ParamClass), nil case "struct": - return fmt.Sprintf("%s%s", NameSpace, ParamClass), nil + return fmt.Sprintf("%s", ParamClass), nil case "structarray": - return fmt.Sprintf("%s%s", NameSpace, ParamClass), nil + return fmt.Sprintf("%s", ParamClass), nil case "functiontype": - return fmt.Sprintf("%s%s", NameSpace, ParamClass), nil - case "handle": + return fmt.Sprintf("%s", ParamClass), nil + case "class": CTypesParamTypeName = "ctypes.c_void_p"; default: return "", fmt.Errorf ("invalid parameter type \"%s\" for Python parameter", ParamTypeName); @@ -460,6 +457,12 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m cParams[0].ParamCallType = cParamTypeName; cParams[0].ParamName = "d" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); + + case "pointer": + cParams[0].ParamType = cParamTypeName; + cParams[0].ParamCallType = cParamTypeName; + cParams[0].ParamName = "p" + param.ParamName; + cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); case "string": cParams[0].ParamType = cParamTypeName; @@ -474,7 +477,7 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); case "struct": - cParams[0].ParamType = cParamTypeName; + cParams[0].ParamType = "ctypes.POINTER("+cParamTypeName+")"; cParams[0].ParamCallType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -491,7 +494,7 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m cParams[1].ParamName = "p" + param.ParamName + "Buffer"; cParams[1].ParamComment = fmt.Sprintf("* @param[in] %s - %s buffer of %s", cParams[1].ParamName, param.ParamClass, param.ParamDescription); - case "handle": + case "class": cParams[0].ParamType = cParamTypeName; cParams[0].ParamCallType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; @@ -510,7 +513,7 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer": cParams[0].ParamType = "ctypes.POINTER("+cParamTypeName+")"; cParams[0].ParamCallType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; @@ -562,7 +565,7 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m cParams[2].ParamName = "p" + param.ParamName + "Buffer"; cParams[2].ParamComment = fmt.Sprintf("* @param[out] %s - %s buffer of %s, may be NULL", cParams[2].ParamName, param.ParamClass, param.ParamDescription); - case "handle": + case "class": cParams[0].ParamType = "ctypes.POINTER("+cParamTypeName +")"; cParams[0].ParamCallType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; @@ -580,20 +583,35 @@ func generateCTypesParameter(param ComponentDefinitionParam, className string, m } -func writeClass(class ComponentDefinitionClass, w LanguageWriter, NameSpace string) error { - w.Writeln("'''%s Class Implementation", class.ClassName) +func writePythonClass(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string) error { + pythonBaseClassName := fmt.Sprintf("%s", component.Global.BaseClassName) + + w.Writeln("''' Class Implementation for %s", class.ClassName) w.Writeln("'''") - parentClass := fmt.Sprintf("%sBaseClass", NameSpace) - if (class.ParentClass != "") { - parentClass = fmt.Sprintf("%s%s", NameSpace, class.ParentClass) + parentClass := "" + if (!component.isBaseClass(class)) { + if (class.ParentClass != "") { + parentClass = fmt.Sprintf("%s", class.ParentClass) + } else { + parentClass = pythonBaseClassName + } + w.Writeln("class %s(%s):", class.ClassName, parentClass) + w.Writeln(" def __init__(self, handle, wrapper):") + w.Writeln(" %s.__init__(self, handle, wrapper)", parentClass) + + } else { + w.Writeln("class %s:", class.ClassName) + w.Writeln(" def __init__(self, handle, wrapper):") + w.Writeln(" if not handle or not wrapper:") + w.Writeln(" raise E%sException(ErrorCodes.INVALIDPARAM)", NameSpace) + w.Writeln(" self._handle = handle") + w.Writeln(" self._wrapper = wrapper") + w.Writeln(" ") + w.Writeln(" def __del__(self):") + w.Writeln(" self._wrapper.%s(self)", component.Global.ReleaseMethod) } - w.Writeln("class %s%s(%s):", NameSpace, class.ClassName, parentClass) - w.Writeln(" def __init__(self, handle, wrapper):") - w.Writeln(" %sBaseClass.__init__(self, handle, wrapper)", NameSpace) - w.Writeln(" ") - for i:=0; i<len(class.Methods); i++ { err := writeMethod(class.Methods[i], w, NameSpace, class.ClassName, false) if (err != nil) { @@ -643,7 +661,7 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s cCheckArguments = cCheckArguments + ", " } switch param.ParamType { - case "handle": { + case "class": { if (retVals != "") { retVals = retVals + ", "; } @@ -652,8 +670,8 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s cArguments = cArguments + newArgument cCheckArguments = cCheckArguments + newArgument postCallLines = append(postCallLines, - fmt.Sprintf("%sObject = %s%s(%sHandle, %s)", - param.ParamName, NameSpace, param.ParamClass, param.ParamName, wrapperReference)) + fmt.Sprintf("%sObject = %s(%sHandle, %s)", + param.ParamName, param.ParamClass, param.ParamName, wrapperReference)) retVals = retVals + fmt.Sprintf("%sObject", param.ParamName) } case "string": { @@ -712,7 +730,7 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s cCheckArguments = cCheckArguments + cParams[0].ParamName retVals = retVals + fmt.Sprintf("%s(%s.value)", cParams[0].ParamCallType, cParams[0].ParamName) } - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool", "pointer": if (retVals != "") { retVals = retVals + ", "; } @@ -742,7 +760,7 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s pythonInParams = pythonInParams + ", "; switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool", "pointer": preCallLines = append(preCallLines, fmt.Sprintf("%s = %s(%s)", cParams[0].ParamName, cParams[0].ParamCallType, param.ParamName)) pythonInParams = pythonInParams + param.ParamName cArguments = cArguments + cParams[0].ParamName @@ -777,7 +795,7 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s cArguments = cArguments + param.ParamName cCheckArguments = cCheckArguments + param.ParamName } - case "handle": { + case "class": { pythonInParams = pythonInParams + param.ParamName + "Object" cArguments = cArguments + param.ParamName + "Object._handle" cCheckArguments = cCheckArguments + param.ParamName + "Object._handle" @@ -812,7 +830,7 @@ func writeMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace s return nil } -func buildDynamiCPythonExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { +func buildDynamicPythonExample(componentdefinition ComponentDefinition, w LanguageWriter, outputFolder string) error { NameSpace := componentdefinition.NameSpace BaseName := componentdefinition.BaseName @@ -826,10 +844,21 @@ func buildDynamiCPythonExample(componentdefinition ComponentDefinition, w Langua w.Writeln("def main():") w.Writeln(" libpath = '' # TODO add the location of the shared library binary here") - w.Writeln(" wrapper = %s.%sWrapper(os.path.join(libpath, \"%s\"))", NameSpace, NameSpace, BaseName) + w.Writeln(" wrapper = %s.Wrapper(os.path.join(libpath, \"%s\"))", NameSpace, BaseName) w.Writeln(" ") - w.Writeln(" major, minor, micro = wrapper.GetLibraryVersion()") - w.Writeln(" print(\"%s version: {:d}.{:d}.{:d}\".format(major, minor, micro))", NameSpace) + w.Writeln(" major, minor, micro = wrapper.%s()", componentdefinition.Global.VersionMethod) + w.Writeln(" print(\"%s version: {:d}.{:d}.{:d}\".format(major, minor, micro), end=\"\")", NameSpace) + if len(componentdefinition.Global.PrereleaseMethod)>0 { + w.Writeln(" hasInfo, prereleaseinfo = wrapper.%s()", componentdefinition.Global.PrereleaseMethod) + w.Writeln(" if hasInfo:") + w.Writeln(" print(\"-\"+prereleaseinfo, end=\"\")") + } + if len(componentdefinition.Global.BuildinfoMethod)>0 { + w.Writeln(" hasInfo, buildinfo = wrapper.%s()", componentdefinition.Global.BuildinfoMethod) + w.Writeln(" if hasInfo:") + w.Writeln(" print(\"+\"+buildinfo, end=\"\")") + } + w.Writeln(" print(\"\")") w.Writeln("") w.Writeln("") diff --git a/Source/buildimplementationcpp.go b/Source/buildimplementationcpp.go index 6aa1121a..a4d7a289 100644 --- a/Source/buildimplementationcpp.go +++ b/Source/buildimplementationcpp.go @@ -190,7 +190,7 @@ func buildCPPInternalException (wHeader LanguageWriter, wImpl LanguageWriter, Na wHeader.Writeln("#include <exception>"); wHeader.Writeln("#include <stdexcept>"); - wHeader.Writeln("#include \"%s_types.h\"", BaseName); + wHeader.Writeln("#include \"%s_types.hpp\"", BaseName); wHeader.Writeln(""); wHeader.Writeln("/*************************************************************************************************************************"); @@ -258,6 +258,59 @@ func buildCPPInternalException (wHeader LanguageWriter, wImpl LanguageWriter, Na return nil; } +func writeCPPClassInterface(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string) (error) { + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class interface for %s ", class.ClassName) + w.Writeln("**************************************************************************************************************************/") + w.Writeln("") + parentClassName := " " + if (!component.isBaseClass(class)) { + parentClassName = fmt.Sprintf(" : public virtual I%s%s", ClassIdentifier, component.Global.BaseClassName) + if (class.ParentClass != "") && (component.Global.BaseClassName != class.ParentClass) { + parentClassName = parentClassName + ", " + fmt.Sprintf("public virtual I%s%s", ClassIdentifier, class.ParentClass) + } + } + + classInterfaceName := fmt.Sprintf("I%s%s", ClassIdentifier, class.ClassName) + w.Writeln("class %s%s{", classInterfaceName, parentClassName) + w.Writeln("public:") + + if (component.isBaseClass(class)) { + w.Writeln(" /**") + w.Writeln(" * %s::~%s - virtual destructor of %s", classInterfaceName, classInterfaceName, classInterfaceName) + w.Writeln(" */") + w.Writeln(" virtual ~%s() {};", classInterfaceName) + var methods [3]ComponentDefinitionMethod + methods[0] = GetLastErrorMessageMethod() + methods[1] = ClearErrorMessageMethod() + methods[2] = RegisterErrorMessageMethod() + for j := 0; j < len(methods); j++ { + methodstring, _, err := buildCPPInterfaceMethodDeclaration(methods[j], class.ClassName, NameSpace, ClassIdentifier, BaseName, w.IndentString, false, true, true) + if err != nil { + return err + } + w.Writeln("") + w.Writeln("%s", methodstring) + } + + + } + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + methodstring, _, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, w.IndentString, false, true, true) + if err != nil { + return err + } + w.Writeln("%s", methodstring) + w.Writeln("") + } + + w.Writeln("};") + w.Writeln("") + return nil +} func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string) error { w.Writeln("") @@ -267,7 +320,7 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln("#include <string>") w.Writeln("") - w.Writeln("#include \"%s_types.h\"", BaseName) + w.Writeln("#include \"%s_types.hpp\"", BaseName) w.Writeln("") w.Writeln("namespace %s {", NameSpace) @@ -279,50 +332,14 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln("*/") for i := 0; i < len(component.Classes); i++ { class := component.Classes[i] - w.Writeln("class I%s%s%s;", ClassIdentifier, NameSpace, class.ClassName); + w.Writeln("class I%s%s;", ClassIdentifier, class.ClassName); } w.Writeln("") - - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class I%s%sBaseClass ", ClassIdentifier, NameSpace) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - w.Writeln("class I%s%sBaseClass {", ClassIdentifier, NameSpace) - w.Writeln("public:") - w.Writeln(" virtual ~I%s%sBaseClass () {}", ClassIdentifier, NameSpace) - w.Writeln("};") - w.Writeln("") - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class interface for %s%s ", NameSpace, class.ClassName) - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - parentClassName := fmt.Sprintf("I%s%sBaseClass", ClassIdentifier, NameSpace) - if "" != class.ParentClass { - parentClassName = parentClassName + ", " + fmt.Sprintf("public virtual I%s%s%s", NameSpace, ClassIdentifier, class.ParentClass) - } - w.Writeln("class I%s%s%s : public virtual %s {", ClassIdentifier, NameSpace, class.ClassName, parentClassName) - w.Writeln("public:") - - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - methodstring, _, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, w.IndentString, false, true, true) - if err != nil { - return err - } - w.Writeln("%s", methodstring) - w.Writeln("") - } - - w.Writeln("};") - w.Writeln("") + writeCPPClassInterface(component, class, w, NameSpace, NameSpaceImplementation, ClassIdentifier, BaseName) } w.Writeln("") @@ -330,12 +347,21 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln(" Global functions declarations") w.Writeln("**************************************************************************************************************************/") - w.Writeln("class C%s%sWrapper {", ClassIdentifier, NameSpace) + w.Writeln("class C%sWrapper {", ClassIdentifier) w.Writeln("public:") global := component.Global; for j := 0; j < len(global.Methods); j++ { method := global.Methods[j] + // Omit Journal Method + isSpecialFunction, err := CheckHeaderSpecialFunction(method, global); + if err != nil { + return err + } + if (isSpecialFunction == eSpecialMethodJournal) { + continue + } + methodstring, _, err := buildCPPInterfaceMethodDeclaration(method, BaseName, NameSpace, ClassIdentifier, "Wrapper", w.IndentString, true, false, true) if err != nil { return err @@ -355,16 +381,25 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa } func buildCPPGlobalStubFile(component ComponentDefinition, stubfile LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string) error { - stubfile.Writeln("#include \"%s.h\"", BaseName) + stubfile.Writeln("#include \"%s_abi.hpp\"", BaseName) stubfile.Writeln("#include \"%s_interfaces.hpp\"", BaseName) stubfile.Writeln("#include \"%s_interfaceexception.hpp\"", BaseName) stubfile.Writeln("") + stubfile.Writeln("using namespace %s;", NameSpace) stubfile.Writeln("using namespace %s::%s;", NameSpace, NameSpaceImplementation) stubfile.Writeln("") for j := 0; j < len(component.Global.Methods); j++ { method := component.Global.Methods[j] + // Omit Journal Method + isSpecialFunction, err := CheckHeaderSpecialFunction(method, component.Global); + if err != nil { + return err + } + if (isSpecialFunction == eSpecialMethodJournal) { + continue + } _, implementationdeclaration, err := buildCPPInterfaceMethodDeclaration(method, "Wrapper", NameSpace, ClassIdentifier, BaseName, stubfile.IndentString, true, false, false) if err != nil { return err @@ -372,7 +407,7 @@ func buildCPPGlobalStubFile(component ComponentDefinition, stubfile LanguageWrit stubfile.Writeln("%s", implementationdeclaration) stubfile.Writeln("{") - stubfile.Writeln(" throw E%sInterfaceException (%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper(NameSpace)) + stubfile.Writeln(" throw E%sInterfaceException(%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper(NameSpace)) stubfile.Writeln("}") stubfile.Writeln("") } @@ -382,8 +417,24 @@ func buildCPPGlobalStubFile(component ComponentDefinition, stubfile LanguageWrit return nil } +func buildCPPInterfaceWrapperMethods(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string, doJournal bool) error { + w.Writeln("") + w.Writeln("/*************************************************************************************************************************") + w.Writeln(" Class implementation for %s", class.ClassName) + w.Writeln("**************************************************************************************************************************/") + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j] + err := writeCImplementationMethod(method, w, BaseName, NameSpace, ClassIdentifier, class.ClassName, component.Global.BaseClassName, false, doJournal, eSpecialMethodNone) + if err != nil { + return err + } + } + return nil +} + func buildCPPInterfaceWrapper(component ComponentDefinition, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string, doJournal bool) error { - w.Writeln("#include \"%s.h\"", BaseName) + w.Writeln("#include \"%s_abi.hpp\"", BaseName) w.Writeln("#include \"%s_interfaces.hpp\"", BaseName) w.Writeln("#include \"%s_interfaceexception.hpp\"", BaseName) if (doJournal) { @@ -397,24 +448,77 @@ func buildCPPInterfaceWrapper(component ComponentDefinition, w LanguageWriter, N w.Writeln("P%sInterfaceJournal m_GlobalJournal;", NameSpace) w.Writeln("") } + - w.Writeln("extern \"C\" {") + journalParameter := ""; + if (doJournal) { + journalParameter = fmt.Sprintf (", C%sInterfaceJournalEntry * pJournalEntry = nullptr", NameSpace); + } + + IBaseClassName := "I" + ClassIdentifier + component.Global.BaseClassName + registerErrorMethod := RegisterErrorMessageMethod() + w.Writeln("%sResult handle%sException(%s * pIBaseClass, E%sInterfaceException & Exception%s)", NameSpace, NameSpace, IBaseClassName, NameSpace, journalParameter) + w.Writeln("{") + w.Writeln(" %sResult errorCode = Exception.getErrorCode();", NameSpace) w.Writeln("") + if (doJournal) { + w.Writeln(" if (pJournalEntry != nullptr)") + w.Writeln(" pJournalEntry->writeError(errorCode);") + w.Writeln("") + } - for i := 0; i < len(component.Classes); i++ { + w.Writeln(" if (pIBaseClass != nullptr)") + + w.Writeln(" pIBaseClass->%s(Exception.what());", registerErrorMethod.MethodName) - class := component.Classes[i] + w.Writeln("") + w.Writeln(" return errorCode;") + w.Writeln("}") + w.Writeln("") + + w.Writeln("%sResult handleStdException(%s * pIBaseClass, std::exception & Exception%s)", NameSpace, IBaseClassName, journalParameter) + w.Writeln("{") + w.Writeln(" %sResult errorCode = %s_ERROR_GENERICEXCEPTION;", NameSpace, strings.ToUpper(NameSpace)) + w.Writeln("") + if (doJournal) { + w.Writeln(" if (pJournalEntry != nullptr)") + w.Writeln(" pJournalEntry->writeError(errorCode);") w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Class implementation for %s", class.ClassName) - w.Writeln("**************************************************************************************************************************/") + } - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - err := writeCImplementationMethod(method, w, BaseName, NameSpace, ClassIdentifier, class.ClassName, false, doJournal, eSpecialMethodNone) - if err != nil { - return err - } + w.Writeln(" if (pIBaseClass != nullptr)") + w.Writeln(" pIBaseClass->%s(Exception.what());", registerErrorMethod.MethodName) + + w.Writeln("") + w.Writeln(" return errorCode;") + w.Writeln("}") + w.Writeln("") + + w.Writeln("%sResult handleUnhandledException(%s * pIBaseClass%s)", NameSpace, IBaseClassName, journalParameter) + w.Writeln("{") + w.Writeln(" %sResult errorCode = %s_ERROR_GENERICEXCEPTION;", NameSpace, strings.ToUpper(NameSpace)) + w.Writeln("") + if (doJournal) { + w.Writeln(" if (pJournalEntry != nullptr)") + w.Writeln(" pJournalEntry->writeError(errorCode);") + w.Writeln("") + } + + w.Writeln(" if (pIBaseClass != nullptr)") + w.Writeln(" pIBaseClass->%s(\"Unhandled Exception\");", registerErrorMethod.MethodName) + + w.Writeln("") + w.Writeln(" return errorCode;") + w.Writeln("}") + w.Writeln("") + + + w.Writeln("") + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + err := buildCPPInterfaceWrapperMethods(component, class, w, NameSpace, NameSpaceImplementation, ClassIdentifier, BaseName, doJournal) + if (err != nil) { + return err } } @@ -439,19 +543,18 @@ func buildCPPInterfaceWrapper(component ComponentDefinition, w LanguageWriter, N } // Write Static function implementation - err = writeCImplementationMethod(method, w, BaseName, NameSpace, ClassIdentifier, "Wrapper", true, doMethodJournal, isSpecialFunction) + err = writeCImplementationMethod(method, w, BaseName, NameSpace, ClassIdentifier, "Wrapper", component.Global.BaseClassName, true, doMethodJournal, isSpecialFunction) if err != nil { return err } } - w.Writeln("}") w.Writeln("") return nil } -func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWriter, BaseName string, NameSpace string, ClassIdentifier string, ClassName string, isGlobal bool, doJournal bool, isSpecialFunction int) error { +func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWriter, BaseName string, NameSpace string, ClassIdentifier string, ClassName string, BaseClassName string, isGlobal bool, doJournal bool, isSpecialFunction int) error { indentString := w.IndentString CMethodName := "" cParams, err := GenerateCParameters(method, ClassName, NameSpace) @@ -468,9 +571,9 @@ func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWrit } if isGlobal { - CMethodName = fmt.Sprintf("%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName), method.DLLSuffix) + CMethodName = fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) } else { - CMethodName = fmt.Sprintf("%s_%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName), method.DLLSuffix) + CMethodName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) if cparameters != "" { cparameters = ", " + cparameters } @@ -479,24 +582,21 @@ func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWrit callCPPFunctionCode := ""; - checkInputCPPFunctionCode, preCallCPPFunctionCode, postCallCPPFunctionCode, returnVariable, callParameters, err := generatePrePostCallCPPFunctionCode(method, NameSpace, ClassIdentifier, ClassName, w.IndentString) + checkInputCPPFunctionCode, preCallCPPFunctionCode, postCallCPPFunctionCode, returnVariable, callParameters, err := generatePrePostCallCPPFunctionCode(method, NameSpace, ClassIdentifier, ClassName, BaseClassName, w.IndentString) if err != nil { return err } - - if (isSpecialFunction == eSpecialMethodNone || isSpecialFunction == eSpecialMethodRelease || isSpecialFunction == eSpecialMethodVersion) { - callCPPFunctionCode, err = generateCallCPPFunctionCode(method, NameSpace, ClassIdentifier, ClassName, returnVariable, callParameters, isGlobal, w.IndentString) - if err != nil { - return err - } - } - if (isSpecialFunction == eSpecialMethodJournal) { callCPPFunctionCode = fmt.Sprintf(indentString + indentString + "m_GlobalJournal = nullptr;\n") + fmt.Sprintf(indentString + indentString + "if (s%s != \"\") {\n", method.Params[0].ParamName) + fmt.Sprintf(indentString + indentString + indentString + "m_GlobalJournal = std::make_shared<C%sInterfaceJournal> (s%s);\n", NameSpace, method.Params[0].ParamName) + fmt.Sprintf(indentString + indentString + "}\n"); + } else { + callCPPFunctionCode, err = generateCallCPPFunctionCode(method, NameSpace, ClassIdentifier, ClassName, returnVariable, callParameters, isGlobal, w.IndentString) + if err != nil { + return err + } } journalInitFunctionCode := ""; @@ -510,16 +610,23 @@ func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWrit if !isGlobal { - preCallCPPFunctionCode = fmt.Sprintf(indentString + indentString + "I%s%sBaseClass* pIBaseClass = (I%s%sBaseClass *)p%s;\n", ClassIdentifier, NameSpace, ClassIdentifier, NameSpace, ClassName) + - fmt.Sprintf(indentString + indentString + "I%s%s%s* pI%s = dynamic_cast<I%s%s%s*>(pIBaseClass);\n", ClassIdentifier, NameSpace, ClassName, ClassName, ClassIdentifier, NameSpace, ClassName) + + preCallCPPFunctionCode = fmt.Sprintf(indentString + indentString + "I%s%s* pI%s = dynamic_cast<I%s%s*>(pIBaseClass);\n", ClassIdentifier, ClassName, ClassName, ClassIdentifier, ClassName) + fmt.Sprintf(indentString + indentString + "if (!pI%s)\n", ClassName) + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException(%s_ERROR_INVALIDCAST);\n\n", NameSpace, strings.ToUpper(NameSpace)) + preCallCPPFunctionCode } - w.Writeln("%sResult %s (%s)", NameSpace, CMethodName, cparameters) + w.Writeln("%sResult %s(%s)", NameSpace, CMethodName, cparameters) w.Writeln("{") + IBaseClassName := fmt.Sprintf("I%s%s", ClassIdentifier, BaseClassName) + if !isGlobal { + w.Writeln (" %s* pIBaseClass = (%s *)p%s;\n", IBaseClassName, IBaseClassName, ClassName); + } else { + w.Writeln (" %s* pIBaseClass = nullptr;\n", IBaseClassName); + } + + if (doJournal) { w.Writeln(" P%sInterfaceJournalEntry pJournalEntry;", NameSpace); } @@ -535,27 +642,23 @@ func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWrit w.Writeln("%s", callCPPFunctionCode) w.Writeln("%s", postCallCPPFunctionCode) + journalHandleParam := ""; + if (doJournal) { w.Writeln("%s", journalSuccessFunctionCode) + journalHandleParam = ", pJournalEntry.get()"; } w.Writeln(" return %s_SUCCESS;", strings.ToUpper(NameSpace)) w.Writeln(" }") - w.Writeln(" catch (E%sInterfaceException & E) {", NameSpace) - - if (doJournal) { - w.Writeln(" if (pJournalEntry.get() != nullptr)"); - w.Writeln(" pJournalEntry->writeError(E.getErrorCode());"); - } - w.Writeln(" return E.getErrorCode();") + w.Writeln(" catch (E%sInterfaceException & Exception) {", NameSpace) + w.Writeln(" return handle%sException(pIBaseClass, Exception%s);", NameSpace, journalHandleParam) + w.Writeln(" }") + w.Writeln(" catch (std::exception & StdException) {") + w.Writeln(" return handleStdException(pIBaseClass, StdException%s);", journalHandleParam) w.Writeln(" }") w.Writeln(" catch (...) {") - if (doJournal) { - w.Writeln(" if (pJournalEntry.get() != nullptr)"); - w.Writeln(" pJournalEntry->writeError(%s_ERROR_GENERICEXCEPTION);", strings.ToUpper(NameSpace)); - } - - w.Writeln(" return %s_ERROR_GENERICEXCEPTION;", strings.ToUpper(NameSpace)) + w.Writeln(" return handleUnhandledException(pIBaseClass%s);", journalHandleParam) w.Writeln(" }") w.Writeln("}") @@ -563,18 +666,15 @@ func writeCImplementationMethod(method ComponentDefinitionMethod, w LanguageWrit return nil } -func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string, outputFolder string, indentString string, stubIdentifier string, forceRecreation bool) error { - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - outClassName := "C" + ClassIdentifier + NameSpace + class.ClassName +func buildCPPStubClass(component ComponentDefinition, class ComponentDefinitionClass, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string, outputFolder string, indentString string, stubIdentifier string, forceRecreation bool) error { + outClassName := "C" + ClassIdentifier + class.ClassName StubHeaderFileName := path.Join(outputFolder, BaseName + stubIdentifier + "_" +strings.ToLower(class.ClassName)+".hpp"); StubImplFileName := path.Join(outputFolder, BaseName + stubIdentifier + "_" + strings.ToLower(class.ClassName)+".cpp"); if !forceRecreation && ( FileExists(StubHeaderFileName) || FileExists(StubImplFileName) ) { log.Printf("Omitting recreation of Stub implementation for \"%s\"", outClassName) - continue; + return nil } log.Printf("Creating \"%s\"", StubHeaderFileName) @@ -596,13 +696,22 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl false) stubheaderw.Writeln("") - stubheaderw.Writeln("#ifndef __%s_%s%s", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) - stubheaderw.Writeln("#define __%s_%s%s", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) + stubheaderw.Writeln("#ifndef __%s_%s", strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) + stubheaderw.Writeln("#define __%s_%s", strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) stubheaderw.Writeln("") stubheaderw.Writeln("#include \"%s_interfaces.hpp\"", BaseName) + if (component.isBaseClass(class)) { + stubheaderw.Writeln("#include <vector>") + } stubheaderw.Writeln("") + if (!component.isBaseClass(class)) { + if (class.ParentClass == "") { + class.ParentClass = component.Global.BaseClassName + } + } + if class.ParentClass != "" { stubheaderw.Writeln("// Parent classes") stubheaderw.Writeln("#include \"%s%s_%s.hpp\"", BaseName, stubIdentifier, strings.ToLower(class.ParentClass)) @@ -624,13 +733,18 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl stubheaderw.Writeln(" Class declaration of %s ", outClassName) stubheaderw.Writeln("**************************************************************************************************************************/") stubheaderw.Writeln("") - parentClassName := fmt.Sprintf("I%s%s%s", ClassIdentifier, NameSpace, class.ClassName) + parentClassName := fmt.Sprintf("I%s%s", ClassIdentifier, class.ClassName) if "" != class.ParentClass { - parentClassName = parentClassName + ", " + fmt.Sprintf("public virtual C%s%s%s", ClassIdentifier, NameSpace, class.ParentClass) + parentClassName = parentClassName + ", " + fmt.Sprintf("public virtual C%s%s", ClassIdentifier, class.ParentClass) } stubheaderw.Writeln("class %s : public virtual %s {", outClassName, parentClassName) stubheaderw.Writeln("private:") stubheaderw.Writeln("") + + if (component.isBaseClass(class)) { + stubheaderw.Writeln(" std::vector<std::string> m_errors;") + stubheaderw.Writeln("") + } stubheaderw.Writeln(" /**") stubheaderw.Writeln(" * Put private members here.") stubheaderw.Writeln(" */") @@ -649,11 +763,6 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl stubheaderw.Writeln(" */") stubheaderw.Writeln("") - stubheaderw.Writeln("") - stubheaderw.Writeln(" /**") - stubheaderw.Writeln(" * Public member functions to implement.") - stubheaderw.Writeln(" */") - stubheaderw.Writeln("") stubimplw.Writeln("#include \"%s%s_%s.hpp\"", BaseName, stubIdentifier, strings.ToLower(class.ClassName)) stubimplw.Writeln("#include \"%s_interfaceexception.hpp\"", BaseName) @@ -671,6 +780,45 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl stubimplw.Writeln("**************************************************************************************************************************/") stubimplw.Writeln("") + if (component.isBaseClass(class)) { + var methods [3]ComponentDefinitionMethod + methods[0] = GetLastErrorMessageMethod() + methods[1] = ClearErrorMessageMethod() + methods[2] = RegisterErrorMessageMethod() + + var implementations [3][]string + implementations[0] = append(implementations[0], "auto iIterator = m_errors.rbegin();") + implementations[0] = append(implementations[0], "if (iIterator != m_errors.rend()) {") + implementations[0] = append(implementations[0], " sErrorMessage = *iIterator;") + implementations[0] = append(implementations[0], " return true;") + implementations[0] = append(implementations[0], "}else {") + implementations[0] = append(implementations[0], " sErrorMessage = \"\";") + implementations[0] = append(implementations[0], " return false;") + implementations[0] = append(implementations[0], "}") + implementations[1] = append(implementations[1], "m_errors.clear();") + implementations[2] = append(implementations[2], "m_errors.push_back(sErrorMessage);") + for i := 0; i < len(methods); i++ { + methodstring, implementationdeclaration, err := buildCPPInterfaceMethodDeclaration(methods[i], class.ClassName, NameSpace, ClassIdentifier, BaseName, stubimplw.IndentString, false, false, false) + if (err!=nil) { + return err + } + stubheaderw.Writeln("%s", methodstring) + stubheaderw.Writeln("") + + stubimplw.Writeln("%s", implementationdeclaration) + stubimplw.Writeln("{") + stubimplw.Writelns(" ", implementations[i]) + stubimplw.Writeln("}") + stubimplw.Writeln("") + } + } + + stubheaderw.Writeln("") + stubheaderw.Writeln(" /**") + stubheaderw.Writeln(" * Public member functions to implement.") + stubheaderw.Writeln(" */") + stubheaderw.Writeln("") + for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] methodstring, implementationdeclaration, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, stubimplw.IndentString, false, false, false) @@ -682,7 +830,7 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl stubimplw.Writeln("%s", implementationdeclaration) stubimplw.Writeln("{") - stubimplw.Writeln(" throw E%sInterfaceException (%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper(NameSpace)) + stubimplw.Writeln(" throw E%sInterfaceException(%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper(NameSpace)) stubimplw.Writeln("}") stubimplw.Writeln("") } @@ -697,8 +845,18 @@ func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImpl if class.ParentClass != "" { stubheaderw.Writeln("#pragma warning( pop )") } - stubheaderw.Writeln("#endif // __%s_%s%s", strings.ToUpper(NameSpace), strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) + stubheaderw.Writeln("#endif // __%s_%s", strings.ToUpper(NameSpace), strings.ToUpper(class.ClassName)) + return nil +} + +func buildCPPStub(component ComponentDefinition, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string, outputFolder string, indentString string, stubIdentifier string, forceRecreation bool) error { + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + err := buildCPPStubClass(component, class, NameSpace, NameSpaceImplementation, ClassIdentifier, BaseName, outputFolder, indentString, stubIdentifier, forceRecreation) + if err != nil { + return err + } } return nil @@ -718,11 +876,13 @@ func getCppVariableName (param ComponentDefinitionParam) (string) { return "p" + param.ParamName + "Buffer"; case "double": return "d" + param.ParamName; + case "pointer": + return "p" + param.ParamName; case "enum": return "e" + param.ParamName; case "struct": return param.ParamName; - case "handle": + case "class": return "p" + param.ParamName; case "functiontype": return "p" + param.ParamName; @@ -773,6 +933,10 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] d%s - %s\n", param.ParamName, param.ParamDescription) parameters = parameters + fmt.Sprintf("const %s d%s", cppParamType, param.ParamName) + case "pointer": + commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] n%s - %s\n", param.ParamName, param.ParamDescription) + parameters = parameters + fmt.Sprintf("const %s p%s", cppParamType, param.ParamName) + case "enum": commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] e%s - %s\n", param.ParamName, param.ParamDescription) parameters = parameters + fmt.Sprintf("const %s e%s", cppParamType, param.ParamName) @@ -781,9 +945,9 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] %s - %s\n", param.ParamName, param.ParamDescription) parameters = parameters + fmt.Sprintf("const %s %s", cppParamType, param.ParamName) - case "handle": + case "class": commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] p%s - %s\n", param.ParamName, param.ParamDescription) - parameters = parameters + fmt.Sprintf("I%s%s%s* p%s", ClassIdentifier, NameSpace, param.ParamClass, param.ParamName) + parameters = parameters + fmt.Sprintf("I%s%s* p%s", ClassIdentifier, param.ParamClass, param.ParamName) case "basicarray": commentcode = commentcode + fmt.Sprintf(indentString + "* @param[in] n%sBufferSize - Number of elements in buffer\n", param.ParamName) @@ -800,7 +964,7 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN parameters = parameters + fmt.Sprintf("const %s p%s", cppParamType, param.ParamName) default: - return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, className, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, className, method.MethodName, param.ParamName) } case "out": @@ -828,6 +992,10 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN commentcode = commentcode + fmt.Sprintf(indentString + "* @param[out] d%s - %s\n", param.ParamName, param.ParamDescription) parameters = parameters + fmt.Sprintf("%s & d%s", cppParamType, param.ParamName) + case "pointer": + commentcode = commentcode + fmt.Sprintf(indentString + "* @param[out] d%s - %s\n", param.ParamName, param.ParamDescription) + parameters = parameters + fmt.Sprintf("%s & p%s", cppParamType, param.ParamName) + case "string": commentcode = commentcode + fmt.Sprintf(indentString + "* @param[out] s%s - %s\n", param.ParamName, param.ParamDescription) parameters = parameters + fmt.Sprintf("std::string & s%s", param.ParamName) @@ -852,31 +1020,31 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN commentcode = commentcode + fmt.Sprintf(indentString + "* @param[out] p%sBuffer - %s buffer of %s\n", param.ParamName, param.ParamClass, param.ParamDescription) parameters = parameters + fmt.Sprintf("%s_uint64 n%sBufferSize, %s_uint64* p%sNeededCount, %s p%sBuffer", NameSpace, param.ParamName, NameSpace, param.ParamName, cppParamType, param.ParamName) - case "handle": - parameters = parameters + fmt.Sprintf("I%s%s%s * p%s", ClassIdentifier, NameSpace, param.ParamClass, param.ParamName) + case "class": + parameters = parameters + fmt.Sprintf("I%s%s * p%s", ClassIdentifier, param.ParamClass, param.ParamName) commentcode = commentcode + fmt.Sprintf(indentString + "* @return %s\n", param.ParamDescription) default: - return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, className, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, className, method.MethodName, param.ParamName) } case "return": currentReturnType := getCppParamType(param, NameSpace, false) switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "string", "enum", "struct": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer", "string", "enum", "struct": returntype = currentReturnType commentcode = commentcode + fmt.Sprintf(indentString + "* @return %s\n", param.ParamDescription) - case "handle": - returntype = fmt.Sprintf("I%s%s%s *", ClassIdentifier, NameSpace, param.ParamClass) + case "class": + returntype = fmt.Sprintf("I%s%s *", ClassIdentifier, param.ParamClass) commentcode = commentcode + fmt.Sprintf(indentString + "* @return %s\n", param.ParamDescription) default: - return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, className, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, className, method.MethodName, param.ParamName) } default: - return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, className, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, className, method.MethodName, param.ParamName) } } outstring := ""; @@ -889,22 +1057,22 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN if isGlobal { if isVirtual { - outstring = outstring + fmt.Sprintf(indentString + "virtual static %s %s (%s) = 0;", returntype, method.MethodName, parameters) + outstring = outstring + fmt.Sprintf(indentString + "virtual static %s %s(%s) = 0;", returntype, method.MethodName, parameters) } else { - outstring = outstring + fmt.Sprintf(indentString + "static %s %s (%s);", returntype, method.MethodName, parameters) + outstring = outstring + fmt.Sprintf(indentString + "static %s %s(%s);", returntype, method.MethodName, parameters) } } else { if isVirtual { - outstring = outstring + fmt.Sprintf(indentString + "virtual %s %s (%s) = 0;", returntype, method.MethodName, parameters) + outstring = outstring + fmt.Sprintf(indentString + "virtual %s %s(%s) = 0;", returntype, method.MethodName, parameters) } else { - outstring = outstring + fmt.Sprintf(indentString + "%s %s (%s);", returntype, method.MethodName, parameters) + outstring = outstring + fmt.Sprintf(indentString + "%s %s(%s);", returntype, method.MethodName, parameters) } } if isGlobal { - templateimplementation = fmt.Sprintf("%s C%s%s%s::%s (%s)", returntype, ClassIdentifier, NameSpace, className, method.MethodName, parameters) + templateimplementation = fmt.Sprintf("%s C%s%s::%s(%s)", returntype, ClassIdentifier, className, method.MethodName, parameters) } else { - templateimplementation = fmt.Sprintf("%s C%s%s%s::%s (%s)", returntype, ClassIdentifier, NameSpace, className, method.MethodName, parameters) + templateimplementation = fmt.Sprintf("%s C%s%s::%s(%s)", returntype, ClassIdentifier, className, method.MethodName, parameters) } return outstring, templateimplementation, nil @@ -913,86 +1081,54 @@ func buildCPPInterfaceMethodDeclaration(method ComponentDefinitionMethod, classN func getCppParamType (param ComponentDefinitionParam, NameSpace string, isInput bool) (string) { cppClassPrefix := "C" + NameSpace; switch (param.ParamType) { - case "uint8": - return fmt.Sprintf ("%s_uint8", NameSpace); - case "uint16": - return fmt.Sprintf ("%s_uint16", NameSpace); - case "uint32": - return fmt.Sprintf ("%s_uint32", NameSpace); - case "uint64": - return fmt.Sprintf ("%s_uint64", NameSpace); - case "int8": - return fmt.Sprintf ("%s_int8", NameSpace); - case "int16": - return fmt.Sprintf ("%s_int16", NameSpace); - case "int32": - return fmt.Sprintf ("%s_int32", NameSpace); - case "int64": - return fmt.Sprintf ("%s_int64", NameSpace); + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + return fmt.Sprintf ("%s_%s", NameSpace, param.ParamType); case "string": return fmt.Sprintf ("std::string"); case "bool": return fmt.Sprintf ("bool"); - case "single": - return fmt.Sprintf ("float"); + case "pointer": + return fmt.Sprintf ("%s_pvoid", NameSpace); + case "basicarray": cppBasicType := ""; switch (param.ParamClass) { - case "uint8": - cppBasicType = fmt.Sprintf ("%s_uint8", NameSpace); - case "uint16": - cppBasicType = fmt.Sprintf ("%s_uint16", NameSpace); - case "uint32": - cppBasicType = fmt.Sprintf ("%s_uint32", NameSpace); - case "uint64": - cppBasicType = fmt.Sprintf ("%s_uint64", NameSpace); - case "int8": - cppBasicType = fmt.Sprintf ("%s_int8", NameSpace); - case "int16": - cppBasicType = fmt.Sprintf ("%s_int16", NameSpace); - case "int32": - cppBasicType = fmt.Sprintf ("%s_int32", NameSpace); - case "int64": - cppBasicType = fmt.Sprintf ("%s_int64", NameSpace); + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + cppBasicType = fmt.Sprintf ("%s_%s", NameSpace, param.ParamClass); case "bool": cppBasicType = "bool"; - case "single": - cppBasicType = fmt.Sprintf ("%s_single", NameSpace); - case "double": - cppBasicType = fmt.Sprintf ("%s_double", NameSpace); + case "pointer": + cppBasicType = fmt.Sprintf ("%s_pvoid", NameSpace); default: log.Fatal ("Invalid parameter type: ", param.ParamClass); } return fmt.Sprintf ("%s *", cppBasicType); case "structarray": - return fmt.Sprintf ("s%s%s *", NameSpace, param.ParamClass); - case "float": - return fmt.Sprintf ("%s_single", NameSpace); - case "double": - return fmt.Sprintf ("%s_double", NameSpace); + return fmt.Sprintf ("%s::s%s *", NameSpace, param.ParamClass); case "enum": - return fmt.Sprintf ("e%s%s", NameSpace, param.ParamClass); + return fmt.Sprintf ("%s::e%s", NameSpace, param.ParamClass); case "struct": - return fmt.Sprintf ("s%s%s", NameSpace, param.ParamClass); - case "handle": + return fmt.Sprintf ("%s::s%s", NameSpace, param.ParamClass); + case "class": if (isInput) { return fmt.Sprintf ("%s%s *", cppClassPrefix, param.ParamClass); } - return fmt.Sprintf ("P%s%s", NameSpace, param.ParamClass); + return fmt.Sprintf ("P%s", param.ParamClass); case "functiontype": - return fmt.Sprintf ("%s%s", NameSpace, param.ParamClass); + return fmt.Sprintf ("%s::%s", NameSpace, param.ParamClass); } log.Fatal ("Invalid parameter type: ", param.ParamType); return ""; } -func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSpace string, ClassIdentifier string, ClassName string, indentString string) (string, string, string, string, string, error) { +func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSpace string, ClassIdentifier string, ClassName string, BaseClassName string, indentString string) (string, string, string, string, string, error) { preCallCode := "" postCallCode := "" callParameters := "" returnVariable := "" checkInputCode := "" + IBaseClassName := fmt.Sprintf("I%s%s", ClassIdentifier, BaseClassName) for k := 0; k < len(method.Params); k++ { param := method.Params[k] variableName := getCppVariableName(param) @@ -1005,7 +1141,7 @@ func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSp } switch param.ParamType { - case "bool", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "bool", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": callParameters = callParameters + variableName case "enum": callParameters = callParameters + "e" + param.ParamName @@ -1020,9 +1156,9 @@ func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSp checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException (%s_ERROR_INVALIDPARAM);\n", NameSpace, strings.ToUpper(NameSpace)) callParameters = callParameters + fmt.Sprintf("n%sBufferSize, ", param.ParamName) + variableName - case "handle": - preCallCode = fmt.Sprintf(indentString + indentString + "I%s%sBaseClass* pIBaseClass%s = (I%s%sBaseClass *)p%s;\n", ClassIdentifier, NameSpace, param.ParamName, ClassIdentifier, NameSpace, param.ParamName) + - fmt.Sprintf(indentString + indentString + "I%s%s%s* pI%s = dynamic_cast<I%s%s%s*>(pIBaseClass%s);\n", ClassIdentifier, NameSpace, param.ParamClass, param.ParamName, ClassIdentifier, NameSpace, param.ParamClass, param.ParamName) + + case "class": + preCallCode = fmt.Sprintf(indentString + indentString + "%s* pIBaseClass%s = (%s *)p%s;\n", IBaseClassName, param.ParamName, IBaseClassName, param.ParamName) + + fmt.Sprintf(indentString + indentString + "I%s%s* pI%s = dynamic_cast<I%s%s*>(pIBaseClass%s);\n", ClassIdentifier, param.ParamClass, param.ParamName, ClassIdentifier, param.ParamClass, param.ParamName) + fmt.Sprintf(indentString + indentString + "if (!pI%s)\n", param.ParamName) + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException (%s_ERROR_INVALIDCAST);\n\n", NameSpace, strings.ToUpper(NameSpace)) + preCallCode @@ -1047,13 +1183,10 @@ func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSp switch param.ParamType { - case "bool", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "enum", "struct": + case "bool", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "enum", "struct", "pointer": checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + "if (!p%s)\n", param.ParamName) checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException (%s_ERROR_INVALIDPARAM);\n", NameSpace, strings.ToUpper(NameSpace)) - - preCallCode = preCallCode + fmt.Sprintf(indentString + indentString + "%s %s;\n", getCppParamType(param, NameSpace, false), variableName) - callParameters = callParameters + variableName - postCallCode = postCallCode + fmt.Sprintf(indentString + indentString + "*p%s = %s;\n", param.ParamName, variableName) + callParameters = callParameters + "*p" + param.ParamName case "basicarray", "structarray": checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + "if ((!p%sBuffer) && !(p%sNeededCount))\n", param.ParamName, param.ParamName) @@ -1084,7 +1217,7 @@ func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSp switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "enum": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "enum", "pointer": checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + "if (p%s == nullptr)\n", param.ParamName) checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException (%s_ERROR_INVALIDPARAM);\n", NameSpace, strings.ToUpper(NameSpace)) @@ -1112,20 +1245,20 @@ func generatePrePostCallCPPFunctionCode(method ComponentDefinitionMethod, NameSp postCallCode = postCallCode + fmt.Sprintf(indentString + indentString + indentString + indentString + "p%sBuffer[i%s] = %s[i%s];\n", param.ParamName, param.ParamName, variableName, param.ParamName) postCallCode = postCallCode + fmt.Sprintf(indentString + indentString + "}\n") - case "handle": + case "class": checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + "if (p%s == nullptr)\n", param.ParamName) checkInputCode = checkInputCode + fmt.Sprintf(indentString + indentString + indentString + "throw E%sInterfaceException (%s_ERROR_INVALIDPARAM);\n", NameSpace, strings.ToUpper(NameSpace)) - preCallCode = preCallCode + fmt.Sprintf(indentString + indentString + "I%s%sBaseClass* pBase%s(nullptr);\n", ClassIdentifier, NameSpace, param.ParamName) + preCallCode = preCallCode + fmt.Sprintf(indentString + indentString + "%s* pBase%s(nullptr);\n", IBaseClassName, param.ParamName) returnVariable = fmt.Sprintf("pBase%s", param.ParamName) - postCallCode = postCallCode + fmt.Sprintf(indentString + indentString + "*%s = (I%s%sBaseClass*)(pBase%s);\n", variableName, ClassIdentifier, NameSpace, param.ParamName); + postCallCode = postCallCode + fmt.Sprintf(indentString + indentString + "*%s = (%s*)(pBase%s);\n", variableName, IBaseClassName, param.ParamName); default: - return "", "", "", "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + return "", "", "", "", "", fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) } default: - return "", "", "", "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + return "", "", "", "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) } } @@ -1139,7 +1272,7 @@ func generateCallCPPFunctionCode(method ComponentDefinitionMethod, NameSpace str } callFunctionCode := "" if isGlobal { - callFunctionCode = fmt.Sprintf(indentString + indentString + "%sC%s%s%s::%s(%s);\n", returnValueCode, ClassIdentifier, NameSpace, ClassName, method.MethodName, callParameters) + callFunctionCode = fmt.Sprintf(indentString + indentString + "%sC%s%s::%s(%s);\n", returnValueCode, ClassIdentifier, ClassName, method.MethodName, callParameters) } else { callFunctionCode = fmt.Sprintf(indentString + indentString + "%spI%s->%s(%s);\n", returnValueCode, ClassName, method.MethodName, callParameters) } @@ -1169,46 +1302,49 @@ func generateJournalFunctionCode (method ComponentDefinitionMethod, NameSpace st switch (param.ParamType) { case "bool": - journalCall = "addBooleanParameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addBooleanParameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "uint8": - journalCall = "addUInt8Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addUInt8Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "uint16": - journalCall = "addUInt16Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addUInt16Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "uint32": - journalCall = "addUInt32Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addUInt32Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "uint64": - journalCall = "addUInt64Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addUInt64Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "int8": - journalCall = "addInt8Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addInt8Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "int16": - journalCall = "addInt16Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addInt16Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "int32": - journalCall = "addInt32Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addInt32Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "int64": - journalCall = "addInt64Parameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addInt64Parameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "single": - journalCall = "addSingleParameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addSingleParameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "double": - journalCall = "addDoubleParameter (\"" + param.ParamName+ "\", " + variableName + ")"; + journalCall = "addDoubleParameter(\"" + param.ParamName+ "\", " + variableName + ")"; + + case "pointer": + journalCall = "addPointerParameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "string": - journalCall = "addStringParameter (\"" + param.ParamName+ "\", p" + param.ParamName + ")"; + journalCall = "addStringParameter(\"" + param.ParamName+ "\", p" + param.ParamName + ")"; case "enum": - journalCall = "addEnumParameter (\"" + param.ParamName+ "\", \"" + param.ParamClass + "\", " + variableName + ")"; + journalCall = "addEnumParameter(\"" + param.ParamName+ "\", \"" + param.ParamClass + "\", (" + NameSpace + "_int32)(" + variableName + "))"; - case "handle": - journalCall = "addHandleParameter (\"" + param.ParamName+ "\", " + variableName + ")"; + case "class": + journalCall = "addHandleParameter(\"" + param.ParamName+ "\", " + variableName + ")"; case "struct": case "basicarray": @@ -1216,7 +1352,7 @@ func generateJournalFunctionCode (method ComponentDefinitionMethod, NameSpace st case "functiontype": default: - return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) } if journalCall != "" { @@ -1236,59 +1372,61 @@ func generateJournalFunctionCode (method ComponentDefinitionMethod, NameSpace st switch (param.ParamType) { case "bool": - journalCall = "addBooleanResult (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addBooleanResult(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "uint8": - journalCall = "addUInt8Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addUInt8Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "uint16": - journalCall = "addUInt16Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addUInt16Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "uint32": - journalCall = "addUInt32Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addUInt32Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "uint64": - journalCall = "addUInt64Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addUInt64Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "int8": - journalCall = "addInt8Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addInt8Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "int16": - journalCall = "addInt16Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addInt16Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "int32": - journalCall = "addInt32Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addInt32Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "int64": - journalCall = "addInt64Result (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addInt64Result(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "single": - journalCall = "addSingleResult (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addSingleResult(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "double": - journalCall = "addDoubleResult (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + journalCall = "addDoubleResult(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + + case "pointer": + journalCall = "addPointerResult(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "string": - journalCall = "addStringResult (\"" + param.ParamName+ "\", s" + param.ParamName + ".c_str())"; + journalCall = "addStringResult(\"" + param.ParamName+ "\", s" + param.ParamName + ".c_str())"; case "enum": - journalCall = "addEnumResult (\"" + param.ParamName+ "\", \"" + param.ParamClass + "\", *p" + param.ParamName + ")"; + journalCall = "addEnumResult(\"" + param.ParamName+ "\", \"" + param.ParamClass + "\", (" + NameSpace + "_int32)(*p" + param.ParamName + "))"; - case "handle": - journalCall = "addHandleResult (\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; + case "class": + journalCall = "addHandleResult(\"" + param.ParamName+ "\", *p" + param.ParamName + ")"; case "struct": case "basicarray": case "structarray": default: - return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + return "", "", fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s(%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) } if journalCall != "" { journalSuccessFunctionCode = journalSuccessFunctionCode + fmt.Sprintf(indentString + indentString + indentString + "pJournalEntry->%s;\n", journalCall); } - } } @@ -1333,6 +1471,8 @@ func buildCMakeForCPPImplementation(component ComponentDefinition, w LanguageWri targetName := strings.ToLower(NameSpace) w.Writeln("add_library(%s SHARED ${%s_SRC})", targetName, strings.ToUpper(NameSpace)) + w.Writeln("# Do not prefix the binary's name with \"lib\" on Unix systems:") + w.Writeln("set_target_properties(%s PROPERTIES PREFIX \"\" IMPORT_PREFIX \"\" )", targetName) w.Writeln("# The following two properties are crucial to reduce the number of undesirably exported symbols") w.Writeln("set_target_properties(%s PROPERTIES CXX_VISIBILITY_PRESET hidden)", targetName) w.Writeln("set_target_properties(%s PROPERTIES VISIBILITY_INLINES_HIDDEN ON)", targetName) @@ -1357,7 +1497,7 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i headerw.Writeln("#include <list>"); headerw.Writeln("#include <mutex>"); headerw.Writeln("#include <chrono>"); - headerw.Writeln("#include \"%s_types.h\"", BaseName); + headerw.Writeln("#include \"%s_types.hpp\"", BaseName); headerw.Writeln(""); headerw.Writeln("/*************************************************************************************************************************"); headerw.Writeln(" Class C%sInterfaceJournal ", NameSpace); @@ -1402,9 +1542,10 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i headerw.Writeln(" void addInt64Parameter(const std::string & sName, const %s_int64 nValue);", NameSpace); headerw.Writeln(" void addSingleParameter(const std::string & sName, const %s_single fValue);", NameSpace); headerw.Writeln(" void addDoubleParameter(const std::string & sName, const %s_double dValue);", NameSpace); + headerw.Writeln(" void addPointerParameter(const std::string & sName, const %s_pvoid pValue);", NameSpace); headerw.Writeln(" void addStringParameter(const std::string & sName, const char * pValue);"); headerw.Writeln(" void addHandleParameter(const std::string & sName, const %sHandle pHandle);", NameSpace); - headerw.Writeln(" void addEnumParameter(const std::string & sName, const std::string & sEnumType, const %s_uint32 nValue);", NameSpace); + headerw.Writeln(" void addEnumParameter(const std::string & sName, const std::string & sEnumType, const %s_int32 nValue);", NameSpace); headerw.Writeln(""); headerw.Writeln(" void addBooleanResult(const std::string & sName, const bool bValue);"); headerw.Writeln(" void addUInt8Result(const std::string & sName, const %s_uint8 nValue);", NameSpace); @@ -1417,9 +1558,10 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i headerw.Writeln(" void addInt64Result(const std::string & sName, const %s_int64 nValue);", NameSpace); headerw.Writeln(" void addSingleResult(const std::string & sName, const %s_single fValue);", NameSpace); headerw.Writeln(" void addDoubleResult(const std::string & sName, const %s_double dValue);", NameSpace); + headerw.Writeln(" void addPointerResult(const std::string & sName, const %s_pvoid pValue);", NameSpace); headerw.Writeln(" void addStringResult(const std::string & sName, const char * pValue);"); headerw.Writeln(" void addHandleResult(const std::string & sName, const %sHandle pHandle);", NameSpace); - headerw.Writeln(" void addEnumResult(const std::string & sName, const std::string & sEnumType, const %s_uint32 nValue);", NameSpace); + headerw.Writeln(" void addEnumResult(const std::string & sName, const std::string & sEnumType, const %s_int32 nValue);", NameSpace); headerw.Writeln(""); headerw.Writeln("friend class C%sInterfaceJournal;", NameSpace); headerw.Writeln(""); @@ -1600,6 +1742,10 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i implw.Writeln("{"); implw.Writeln(" addParameter(sName, \"double\", std::to_string(dValue));"); implw.Writeln("}"); + implw.Writeln("void C%sInterfaceJournalEntry::addPointerParameter(const std::string & sName, const %s_pvoid pValue)", NameSpace, NameSpace); + implw.Writeln("{"); + implw.Writeln(" addParameter(sName, \"pointer\", std::to_string(reinterpret_cast<const %s_uint64>(pValue)));", NameSpace); + implw.Writeln("}"); implw.Writeln(""); implw.Writeln("void C%sInterfaceJournalEntry::addStringParameter(const std::string & sName, const char * pValue)", NameSpace); implw.Writeln("{"); @@ -1616,7 +1762,7 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i implw.Writeln(" addParameter(sName, \"handle\", %sHandleToHex(pHandle));", NameSpace); implw.Writeln("}"); implw.Writeln(""); - implw.Writeln("void C%sInterfaceJournalEntry::addEnumParameter(const std::string & sName, const std::string & sEnumType, const %s_uint32 nValue)", NameSpace, NameSpace); + implw.Writeln("void C%sInterfaceJournalEntry::addEnumParameter(const std::string & sName, const std::string & sEnumType, const %s_int32 nValue)", NameSpace, NameSpace); implw.Writeln("{"); implw.Writeln(" addParameter(sName, \"enum\" + sEnumType, std::to_string(nValue));"); implw.Writeln("}"); @@ -1676,6 +1822,11 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i implw.Writeln(" addResult(sName, \"double\", std::to_string(dValue));"); implw.Writeln("}"); implw.Writeln(""); + implw.Writeln("void C%sInterfaceJournalEntry::addPointerResult(const std::string & sName, const %s_pvoid pValue)", NameSpace, NameSpace); + implw.Writeln("{"); + implw.Writeln(" addResult(sName, \"pointer\", std::to_string(reinterpret_cast<const %s_uint64>(pValue)));", NameSpace); + implw.Writeln("}"); + implw.Writeln(""); implw.Writeln("void C%sInterfaceJournalEntry::addStringResult(const std::string & sName, const char * pValue)", NameSpace); implw.Writeln("{"); implw.Writeln(" if (pValue != nullptr) {"); @@ -1691,7 +1842,7 @@ func buildJournalingCPP(component ComponentDefinition, headerw LanguageWriter, i implw.Writeln(" addResult(sName, \"handle\", %sHandleToHex(pHandle));", NameSpace); implw.Writeln("}"); implw.Writeln(""); - implw.Writeln("void C%sInterfaceJournalEntry::addEnumResult(const std::string & sName, const std::string & sEnumType, const %s_uint32 nValue)", NameSpace, NameSpace); + implw.Writeln("void C%sInterfaceJournalEntry::addEnumResult(const std::string & sName, const std::string & sEnumType, const %s_int32 nValue)", NameSpace, NameSpace); implw.Writeln("{"); implw.Writeln(" addResult(sName, \"enum\" + sEnumType, std::to_string(nValue));"); implw.Writeln("}"); diff --git a/Source/buildimplementationpascal.go b/Source/buildimplementationpascal.go index d7e61d6c..b89fabe0 100644 --- a/Source/buildimplementationpascal.go +++ b/Source/buildimplementationpascal.go @@ -49,7 +49,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin //doJournal := len (component.Global.JournalMethod) > 0; forceRecreation := false - namespace := component.NameSpace; + NameSpace := component.NameSpace; libraryname := component.LibraryName; baseName := component.BaseName; @@ -73,7 +73,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin typesWrapperfile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal type definition file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", libraryname), true) - buildPascalTypeDefinition (component, typesWrapperfile, namespace, baseName); + buildPascalTypeDefinition (component, typesWrapperfile, NameSpace, baseName); IntfWrapperExceptionName := path.Join(outputFolder, baseName+"_exception.pas"); @@ -85,7 +85,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin exceptionWrapperfile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal exception class definition file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", libraryname), true) - buildPascalExceptionDefinition (component, exceptionWrapperfile, namespace, baseName); + buildPascalExceptionDefinition (component, exceptionWrapperfile, NameSpace, baseName); IntfWrapperInterfaceName := path.Join(outputFolder, baseName+"_interfaces.pas"); @@ -97,7 +97,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin interfaceWrapperfile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal interface definition file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", libraryname), true) - buildPascalInterfaceDefinition (component, interfaceWrapperfile, namespace, baseName); + buildPascalInterfaceDefinition (component, interfaceWrapperfile, NameSpace, baseName); IntfWrapperExportName := path.Join(outputFolder, baseName+"_exports.pas"); @@ -110,8 +110,11 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin fmt.Sprintf("This is an autogenerated Pascal export implementation file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", libraryname), true) - buildPascalExportsDefinition (component, exportWrapperfile, namespace, baseName, stubIdentifier, implementation.ClassIdentifier); + buildPascalExportsDefinition (component, exportWrapperfile, NameSpace, baseName, stubIdentifier, implementation.ClassIdentifier); + var defaultImplementation []string + defaultImplementation = append(defaultImplementation, fmt.Sprintf("raise E%sException.Create (%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper (NameSpace))); + IntfWrapperStubName := path.Join(stubOutputFolder, baseName + stubIdentifier + ".pas") if forceRecreation || (!FileExists(IntfWrapperStubName) ) { log.Printf("Creating \"%s\"", IntfWrapperStubName) @@ -123,7 +126,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin fmt.Sprintf("This is an autogenerated Pascal implementation file in order to allow easy\ndevelopment of %s. It needs to be generated only once.", libraryname), true) - err = buildStubImplementation (component, templatefile, namespace, baseName, stubIdentifier); + err = buildStubImplementation (component, templatefile, NameSpace, baseName, stubIdentifier, defaultImplementation); if err != nil { return err } @@ -138,7 +141,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin if err != nil { return err } - err = buildLPIImplementation (component, lpifile, namespace, baseName); + err = buildLPIImplementation (component, lpifile, NameSpace, baseName); if err != nil { return err } @@ -153,7 +156,7 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin lprfile.WritePascalLicenseHeader(component, fmt.Sprintf("This is an autogenerated Pascal project file in order to allow easy\ndevelopment of %s.", libraryname), true); - err = buildLPRImplementation (component, lprfile, namespace, baseName); + err = buildLPRImplementation (component, lprfile, NameSpace, baseName); if err != nil { return err } @@ -164,12 +167,12 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin if err != nil { return err } - err = buildDefFile(component, defFile, namespace) + err = buildDefFile(component, defFile, NameSpace) if err != nil { return err } - err = buildPascalStub(component, namespace, implementation.ClassIdentifier, baseName, stubOutputFolder, indentString, stubIdentifier, forceRecreation) + err = buildPascalStub(component, NameSpace, implementation.ClassIdentifier, baseName, stubOutputFolder, indentString, stubIdentifier, forceRecreation, defaultImplementation) if err != nil { return err } @@ -178,13 +181,13 @@ func BuildImplementationPascal(component ComponentDefinition, outputFolder strin } // buildDefFile writes a module definition file with all exported functions -func buildDefFile(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string) error { +func buildDefFile(component ComponentDefinition, w LanguageWriter, NameSpace string) error { w.Writeln("EXPORTS") - global := componentdefinition.Global; + global := component.Global; for _, method := range global.Methods { w.Writeln("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) } - for _, class := range componentdefinition.Classes { + for _, class := range component.Classes { for _, method := range class.Methods { w.Writeln("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) } @@ -193,7 +196,7 @@ func buildDefFile(componentdefinition ComponentDefinition, w LanguageWriter, Nam } -func buildPascalTypeDefinition(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildPascalTypeDefinition(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { w.Writeln ("{$MODE DELPHI}"); w.Writeln ("unit %s_types;", BaseName); @@ -206,7 +209,7 @@ func buildPascalTypeDefinition(componentdefinition ComponentDefinition, w Langua w.Writeln (" sysutils;"); w.Writeln (""); - err := writePascalBaseTypeDefinitions (componentdefinition, w, NameSpace, BaseName); + err := writePascalBaseTypeDefinitions (component, w, NameSpace, BaseName); if (err != nil) { return err; } @@ -222,7 +225,7 @@ func buildPascalTypeDefinition(componentdefinition ComponentDefinition, w Langua -func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildPascalExceptionDefinition(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { w.Writeln ("{$MODE DELPHI}"); w.Writeln ("unit %s_exception;", BaseName); @@ -232,6 +235,7 @@ func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w L w.Writeln ("uses"); w.Writeln (" %s_types,", BaseName); + w.Writeln (" %s_interfaces,", BaseName); w.Writeln (" Classes,"); w.Writeln (" sysutils;"); w.Writeln (""); @@ -248,7 +252,17 @@ func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w L w.Writeln (" end;"); w.Writeln ("") w.Writeln ("") - + + w.Writeln ("(*************************************************************************************************************************") + w.Writeln (" Definition of exception handling functionality for %s", NameSpace) + w.Writeln ("**************************************************************************************************************************)") + w.Writeln (""); + w.Writeln ("function Handle%sException(A%sObject: TObject; E: E%sException): T%sResult;", NameSpace, NameSpace, NameSpace, NameSpace); + w.Writeln ("function HandleStdException(A%sObject: TObject; E: Exception): T%sResult;", NameSpace, NameSpace); + w.Writeln ("function HandleUnhandledException(A%sObject: TObject): T%sResult;", NameSpace, NameSpace); + w.Writeln (""); + w.Writeln (""); + w.Writeln ("implementation"); w.Writeln (""); w.Writeln (" constructor E%sException.Create (AErrorCode: T%sResult);", NameSpace, NameSpace); @@ -258,7 +272,7 @@ func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w L w.Writeln (" FErrorCode := AErrorCode;"); w.Writeln (" case FErrorCode of"); - for _, error := range componentdefinition.Errors.Errors { + for _, error := range component.Errors.Errors { w.Writeln (" %s_ERROR_%s: ADescription := '%s';", strings.ToUpper (NameSpace), error.Name, error.Description); } @@ -266,7 +280,7 @@ func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w L w.Writeln (" ADescription := 'unknown';"); w.Writeln (" end;"); w.Writeln ("") - w.Writeln (" inherited Create (Format ('%s Error - %%s (#%%d)', [ ADescription, AErrorCode ]));", componentdefinition.LibraryName); + w.Writeln (" inherited Create (Format ('%s Error - %%s (#%%d)', [ ADescription, AErrorCode ]));", component.LibraryName); w.Writeln (" end;"); w.Writeln ("") w.Writeln (" constructor E%sException.CreateCustomMessage (AErrorCode: T%sResult; AMessage: String);", NameSpace, NameSpace); @@ -277,6 +291,35 @@ func buildPascalExceptionDefinition(componentdefinition ComponentDefinition, w L w.Writeln (" end;"); w.Writeln ("") + registerErrorMethod := RegisterErrorMessageMethod() + pascalBaseInterfaceName := "I" + NameSpace + component.baseClass().ClassName + w.Writeln ("(*************************************************************************************************************************") + w.Writeln (" Implementation of exception handling functionality for %s", NameSpace) + w.Writeln ("**************************************************************************************************************************)") + w.Writeln (""); + w.Writeln ("function Handle%sException(A%sObject: TObject; E: E%sException): T%sResult;", NameSpace, NameSpace, NameSpace, NameSpace); + w.Writeln("begin") + w.Writeln(" result := E.ErrorCode;") + w.Writeln(" if Supports (A%sObject, %s) then begin", NameSpace, pascalBaseInterfaceName) + w.Writeln(" (A%sObject as %s).%s(E.CustomMessage)", NameSpace, pascalBaseInterfaceName, registerErrorMethod.MethodName) + w.Writeln(" end;") + w.Writeln("end;") + w.Writeln ("function HandleStdException(A%sObject: TObject; E: Exception): T%sResult;", NameSpace, NameSpace); + w.Writeln("begin") + w.Writeln(" Result := %s_ERROR_GENERICEXCEPTION;", strings.ToUpper(NameSpace)); + w.Writeln(" if Supports (A%sObject, %s) then begin", NameSpace, pascalBaseInterfaceName) + w.Writeln(" (A%sObject as %s).%s(E.Message)", NameSpace, pascalBaseInterfaceName, registerErrorMethod.MethodName) + w.Writeln(" end;") + w.Writeln("end;") + + w.Writeln ("function HandleUnhandledException(A%sObject: TObject): T%sResult;", NameSpace, NameSpace); + w.Writeln("begin") + w.Writeln(" Result := %s_ERROR_GENERICEXCEPTION;", strings.ToUpper(NameSpace)); + w.Writeln(" if Supports (A%sObject, %s) then begin", NameSpace, pascalBaseInterfaceName) + w.Writeln(" (A%sObject as %s).%s('Unhandled Exception')", NameSpace, pascalBaseInterfaceName, registerErrorMethod.MethodName) + w.Writeln(" end;") + w.Writeln("end;") + w.Writeln ("end."); return nil; @@ -302,7 +345,7 @@ func createRandomUUID () (string, error) { } -func buildPascalInterfaceDefinition(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildPascalInterfaceDefinition(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { w.Writeln ("{$MODE DELPHI}"); w.Writeln ("{$INTERFACES CORBA}"); @@ -312,38 +355,19 @@ func buildPascalInterfaceDefinition(componentdefinition ComponentDefinition, w L w.Writeln ("interface"); w.Writeln (""); w.Writeln ("uses"); - w.Writeln (" %s_types,", BaseName); - if (len(componentdefinition.Enums) > 0) { - // Unit contains enums conversion that may raise exceptions - w.Writeln (" %s_exception,", BaseName); - } w.Writeln (" Classes,"); w.Writeln (" sysutils;"); w.Writeln (""); - writeEnumConversionInterface (componentdefinition, w, NameSpace); + writeEnumConversionInterface (component, w, NameSpace); w.Writeln ("") - w.Writeln ("(*************************************************************************************************************************") - w.Writeln (" Interface definition for BaseClass") - w.Writeln ("**************************************************************************************************************************)") - w.Writeln (""); - w.Writeln ("type"); - w.Writeln (" I%sBaseClass = interface", NameSpace); - - uuid, err := createRandomUUID (); - if err != nil { - return err - } - w.Writeln (" ['{%s}']", uuid); - - w.Writeln (" end;"); - w.Writeln ("") + w.Writeln ("type") - - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + pascalBaseInterfaceName := "I" + NameSpace + component.baseClass().ClassName + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] w.Writeln ("") w.Writeln ("(*************************************************************************************************************************") @@ -353,11 +377,17 @@ func buildPascalInterfaceDefinition(componentdefinition ComponentDefinition, w L parentClassName := class.ParentClass if parentClassName == "" { - parentClassName = "BaseClass" + parentClassName = pascalBaseInterfaceName + } else { + parentClassName = "I" + NameSpace + parentClassName + } + + if (component.isBaseClass(class)) { + w.Writeln (" I%s%s = interface", NameSpace, class.ClassName); + } else { + w.Writeln (" I%s%s = interface (%s)", NameSpace, class.ClassName, parentClassName); } - - w.Writeln (" I%s%s = interface (I%s%s)", NameSpace, class.ClassName, NameSpace, parentClassName); uuid, err := createRandomUUID (); if err != nil { return err @@ -365,15 +395,29 @@ func buildPascalInterfaceDefinition(componentdefinition ComponentDefinition, w L w.Writeln (" ['{%s}']", uuid); w.Writeln (""); + w.AddIndentationLevel(2) + if (component.isBaseClass(class)) { + var methods [3]ComponentDefinitionMethod + methods[0] = GetLastErrorMessageMethod() + methods[1] = ClearErrorMessageMethod() + methods[2] = RegisterErrorMessageMethod() + + for _, method := range methods { + err := writePascalImplClassMethodDefinition(method, w, NameSpace, class.ClassName, false) + if err != nil { + return err; + } + } + } + for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - w.AddIndentationLevel(2) err := writePascalImplClassMethodDefinition(method, w, NameSpace, class.ClassName, false) - w.AddIndentationLevel(-2) if err != nil { return err; } } + w.AddIndentationLevel(-2) w.Writeln (" end;"); w.Writeln ("") @@ -383,7 +427,14 @@ func buildPascalInterfaceDefinition(componentdefinition ComponentDefinition, w L w.Writeln ("implementation"); w.Writeln (""); - writeEnumConversionImplementation (componentdefinition, w, NameSpace); + if (len(component.Enums) > 0) { + // Unit contains enums conversion that may raise exceptions + w.Writeln ("uses"); + w.Writeln (" %s_exception;", BaseName); + w.Writeln (""); + } + + writeEnumConversionImplementation (component, w, NameSpace); w.Writeln ("end."); @@ -465,7 +516,7 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam callParameters = callParameters + ", " } switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": callParameters = callParameters + pascalParams[0].ParamName case "bool": callParameters = callParameters + pascalParams[0].ParamName + " <> 0" @@ -483,19 +534,19 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam callParameters = callParameters + fmt.Sprintf("%s, %s", pascalParams[0].ParamName, pascalParams[1].ParamName) - case "handle": + case "class": variableDefinitions = append (variableDefinitions, fmt.Sprintf (" Object%s: TObject;", param.ParamName)); checkInputCode = append (checkInputCode, fmt.Sprintf("Object%s := TObject (%s);", param.ParamName, pascalParams[0].ParamName)) checkInputCode = append (checkInputCode, fmt.Sprintf("if (not Supports (Object%s, I%s%s)) then", param.ParamName, NameSpace, param.ParamClass)) checkInputCode = append (checkInputCode, fmt.Sprintf(" raise E%sException.Create (%s_ERROR_INVALIDCAST);", NameSpace, strings.ToUpper(NameSpace))) checkInputCode = append (checkInputCode, ""); - + callParameters = callParameters + fmt.Sprintf("Object%s", param.ParamName) case "string": checkInputCode = append (checkInputCode, fmt.Sprintf("if (not Assigned (%s)) then", pascalParams[0].ParamName)); checkInputCode = append (checkInputCode, fmt.Sprintf(" raise E%sException.Create (%s_ERROR_INVALIDPARAM);", NameSpace, strings.ToUpper(NameSpace))); - + callParameters = callParameters + "StrPas (" + pascalParams[0].ParamName + ")"; case "functiontype": @@ -512,7 +563,7 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "struct": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer", "struct": checkInputCode = append (checkInputCode, fmt.Sprintf("if (not Assigned (%s)) then", pascalParams[0].ParamName)) checkInputCode = append (checkInputCode, fmt.Sprintf(" raise E%sException.Create (%s_ERROR_INVALIDPARAM);\n", NameSpace, strings.ToUpper(NameSpace))) @@ -571,7 +622,7 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "pointer": checkInputCode = append (checkInputCode, fmt.Sprintf("if not Assigned (%s) then", pascalParams[0].ParamName)) checkInputCode = append (checkInputCode, fmt.Sprintf(" raise E%sException.Create (%s_ERROR_INVALIDPARAM);", NameSpace, strings.ToUpper(NameSpace))) @@ -630,7 +681,7 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam postCallCode = append (postCallCode, fmt.Sprintf(" Move (PAnsiChar (Result%s)^, %s^, Len%s + 1);", param.ParamName, pascalParams[2].ParamName, param.ParamName)); postCallCode = append (postCallCode, fmt.Sprintf("end;")); - case "handle": + case "class": checkInputCode = append (checkInputCode, fmt.Sprintf("if not Assigned(p%s) then", param.ParamName)) checkInputCode = append (checkInputCode, fmt.Sprintf(" raise E%sException.Create (%s_ERROR_INVALIDPARAM);", NameSpace, strings.ToUpper(NameSpace))) @@ -655,39 +706,6 @@ func generatePrePostCallPascalFunctionCode(method ComponentDefinitionMethod, Nam func writePascalClassExportImplementation (method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool, ClassIdentifier string) (error) { - -/*var - ANumberObject: TObject; - AInterface: ILibNumbersNumber; - AReturnValue: Double; -begin - try - if not Assigned (pNumber) then - raise ELibNumbersException.Create (LIBNUMBERS_ERROR_INVALIDPARAM); - if not Assigned (pValue) then - raise ELibNumbersException.Create (LIBNUMBERS_ERROR_INVALIDPARAM); - - ANumberObject := TObject (pNumber); - if Supports (ANumberObject, ILibNumbersNumber) then begin - AInterface := ANumberObject as ILibNumbersNumber; - AReturnValue := AInterface.Value (); - - PValue^ := AReturnValue; - end; - - Result := LIBNUMBERS_SUCCESS; - - except - On E: ELibNumbersException do begin - Result := E.getErrorCode (); - end; - On E: Exception do begin - Result := LIBNUMBERS_ERROR_GENERICEXCEPTION; - end; - end; -end; */ - - variableDefinitions, parameterChecks, preCallCode, postCallCode, callParameters, resultVariable, err := generatePrePostCallPascalFunctionCode (method, NameSpace, ClassIdentifier, ClassName) if (err != nil) { return err; @@ -748,12 +766,24 @@ end; */ w.Writeln (" Result := %s_SUCCESS;", strings.ToUpper (NameSpace)); w.Writeln (" except"); - w.Writeln (" On E: E%sException do begin", NameSpace); - w.Writeln (" Result := E.ErrorCode;"); - w.Writeln (" end;"); - w.Writeln (" On E: Exception do begin"); - w.Writeln (" Result := %s_ERROR_GENERICEXCEPTION;", strings.ToUpper (NameSpace)); - w.Writeln (" end;"); + if (!isGlobal) { + w.Writeln (" On E: E%sException do begin", NameSpace); + w.Writeln (" Result := Handle%sException(Object%s , E);", NameSpace, ClassName); + w.Writeln (" end;"); + w.Writeln (" On E: Exception do begin"); + w.Writeln (" Result := HandleStdException(Object%s , E);", ClassName); + w.Writeln (" end"); + w.Writeln (" else begin"); + w.Writeln (" Result := HandleUnhandledException(Object%s);", ClassName); + w.Writeln (" end;"); + } else { + w.Writeln (" On E: E%sException do begin", NameSpace); + w.Writeln (" Result := E.ErrorCode;"); + w.Writeln (" end"); + w.Writeln (" else begin"); + w.Writeln (" Result := %s_ERROR_GENERICEXCEPTION;", strings.ToUpper(NameSpace)); + w.Writeln (" end"); + } w.Writeln (" end;"); w.Writeln ("end;"); w.Writeln (""); @@ -763,9 +793,9 @@ end; */ -func buildPascalExportsDefinition(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, stubIdentifier string, ClassIdentifier string) error { +func buildPascalExportsDefinition(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, stubIdentifier string, ClassIdentifier string) error { - global := componentdefinition.Global; + global := component.Global; w.Writeln ("{$MODE DELPHI}"); w.Writeln ("unit %s_exports;", BaseName); @@ -780,9 +810,9 @@ func buildPascalExportsDefinition(componentdefinition ComponentDefinition, w Lan w.Writeln (" Classes,"); w.Writeln (" sysutils;"); w.Writeln (""); - - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] w.Writeln("(*************************************************************************************************************************") w.Writeln(" Class export definition of %s ", class.ClassName) @@ -822,8 +852,8 @@ func buildPascalExportsDefinition(componentdefinition ComponentDefinition, w Lan w.Writeln ("implementation"); w.Writeln (""); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { @@ -868,9 +898,9 @@ func buildPascalExportsDefinition(componentdefinition ComponentDefinition, w Lan -func buildLPRImplementation(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildLPRImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { - global := componentdefinition.Global; + global := component.Global; w.Writeln ("{$MODE DELPHI}"); w.Writeln ("library %s;", BaseName); @@ -887,8 +917,8 @@ func buildLPRImplementation(componentdefinition ComponentDefinition, w LanguageW w.Writeln (""); w.Writeln ("exports"); - for i := 0; i < len(componentdefinition.Classes); i++ { - class := componentdefinition.Classes[i] + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] for j := 0; j < len(class.Methods); j++ { @@ -920,13 +950,12 @@ func buildLPRImplementation(componentdefinition ComponentDefinition, w LanguageW w.Writeln ("end."); return nil; - } -func buildLPIImplementation(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { +func buildLPIImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error { w.Writeln ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); w.Writeln ("<CONFIG>"); @@ -1069,7 +1098,7 @@ func getPascalImplClassParameters(method ComponentDefinitionMethod, NameSpace st } parameters = parameters + "const A" + param.ParamName + "Count: QWord" parameters = parameters + "; const A" + param.ParamName + ": " + ParamTypeName - case "handle": + case "class": if (parameters != "") { parameters = parameters + "; "; } @@ -1112,7 +1141,7 @@ func getPascalImplClassParameters(method ComponentDefinitionMethod, NameSpace st return parameters, returnType, nil; } -func writePascalClassMethodDummyStub (method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, outClassName string, isGlobal bool) (error) { +func writePascalClassMethodDummyStub(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, outClassName string, isGlobal bool, customImplementation []string) (error) { parameters, returnType, err := getPascalImplClassParameters (method, NameSpace, ClassName, isGlobal, true); if (err != nil) { return err; @@ -1130,7 +1159,7 @@ func writePascalClassMethodDummyStub (method ComponentDefinitionMethod, w Langua } w.Writeln("begin"); - w.Writeln(" raise E%sException.Create (%s_ERROR_NOTIMPLEMENTED);", NameSpace, strings.ToUpper (NameSpace)); + w.Writelns(" ", customImplementation); w.Writeln("end;"); w.Writeln(""); @@ -1140,43 +1169,21 @@ func writePascalClassMethodDummyStub (method ComponentDefinitionMethod, w Langua -func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdentifier string, BaseName string, outputFolder string, indentString string, stubIdentifier string, forceRecreation bool) error { +func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdentifier string, BaseName string, outputFolder string, indentString string, stubIdentifier string, forceRecreation bool, defaultImplementation []string) error { - baseClassName := "T" + ClassIdentifier + NameSpace + "BaseClass" - StubFileName := path.Join(outputFolder, BaseName + stubIdentifier + "_" +"baseclass.pas"); - if forceRecreation || !FileExists(StubFileName) { - log.Printf("Creating \"%s\"", StubFileName) - w, err := CreateLanguageFile(StubFileName, indentString) - if err != nil { - return err - } - w.WritePascalLicenseHeader(component, - fmt.Sprintf("This is the class declaration of %s", baseClassName), - false) - - w.Writeln ("{$MODE DELPHI}"); - w.Writeln ("unit %s%s_%s;", BaseName, stubIdentifier, strings.ToLower("BaseClass")); - w.Writeln (""); - w.Writeln ("interface"); - w.Writeln (""); - w.Writeln ("uses"); - w.Writeln (" %s_interfaces,", BaseName); - w.Writeln (" Classes,"); - w.Writeln (" sysutils;"); - w.Writeln (""); + pascalBaseClassName := "T" + ClassIdentifier + NameSpace + component.baseClass().ClassName - w.Writeln ("type"); - w.Writeln (" %s = class (TObject, I%sBaseClass)", baseClassName, NameSpace); - w.Writeln (" end;"); - w.Writeln ("") + var baseClassMethods [3]ComponentDefinitionMethod + baseClassMethods[0] = GetLastErrorMessageMethod() + baseClassMethods[1] = ClearErrorMessageMethod() + baseClassMethods[2] = RegisterErrorMessageMethod() - w.Writeln ("implementation"); - w.Writeln (""); - w.Writeln ("end."); - } else { - log.Printf("Omitting recreation of Stub implementation for \"%s\"", baseClassName) - } - + var baseClassMethodImplementation [3][]string + baseClassMethodImplementation[0] = append(baseClassMethodImplementation[0], "result := (FMessages.Count>0);") + baseClassMethodImplementation[0] = append(baseClassMethodImplementation[0], "if (result) then") + baseClassMethodImplementation[0] = append(baseClassMethodImplementation[0], " AErrorMessage := FMessages[FMessages.Count-1];") + baseClassMethodImplementation[1] = append(baseClassMethodImplementation[1], "FMessages.Clear();") + baseClassMethodImplementation[2] = append(baseClassMethodImplementation[2], "FMessages.Add(AErrorMessage);") for i := 0; i < len(component.Classes); i++ { class := component.Classes[i] @@ -1187,7 +1194,7 @@ func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdent if class.ParentClass != "" { outparentClassName = "T" + ClassIdentifier + NameSpace + class.ParentClass; } else { - outparentClassName = baseClassName; + outparentClassName = pascalBaseClassName; } StubFileName := path.Join(outputFolder, BaseName + stubIdentifier + "_" +strings.ToLower(class.ClassName)+".pas"); @@ -1215,10 +1222,8 @@ func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdent w.Writeln (" %s_interfaces,", BaseName); w.Writeln (" %s_exception,", BaseName); - if (class.ParentClass != "") { + if ((class.ParentClass != "") ) { w.Writeln (" %s%s_%s,", BaseName, stubIdentifier, strings.ToLower(class.ParentClass)); - } else { - w.Writeln (" %s%s_%s,", BaseName, stubIdentifier, strings.ToLower("BaseClass")); } w.Writeln (" Classes,"); @@ -1227,22 +1232,44 @@ func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdent w.Writeln ("type"); - w.Writeln (" %s = class (%s, I%s%s)", outClassName, outparentClassName, NameSpace, class.ClassName); + if (component.isBaseClass(class)) { + w.Writeln (" %s = class(TObject, I%s%s)", outClassName, NameSpace, class.ClassName); + } else { + w.Writeln (" %s = class(%s, I%s%s)", outClassName, outparentClassName, NameSpace, class.ClassName); + } + w.Writeln (" private"); + if (component.isBaseClass(class)) { + w.Writeln (" FMessages: TStringList;"); + } w.Writeln (""); w.Writeln (" protected"); w.Writeln (""); w.Writeln (" public"); + if (component.isBaseClass(class)) { + w.Writeln (" constructor Create();"); + w.Writeln (" destructor Destroy(); override;"); + } + + w.AddIndentationLevel(3) + if (component.isBaseClass(class)) { + for _,method := range baseClassMethods { + err := writePascalImplClassMethodDefinition(method, w, NameSpace, class.ClassName, false) + if err != nil { + return err; + } + } + } + for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - w.AddIndentationLevel(3) err := writePascalImplClassMethodDefinition(method, w, NameSpace, class.ClassName, false) - w.AddIndentationLevel(-3) if err != nil { return err; } } + w.AddIndentationLevel(-3) w.Writeln (" end;"); w.Writeln ("") @@ -1250,10 +1277,34 @@ func buildPascalStub(component ComponentDefinition, NameSpace string, ClassIdent w.Writeln ("implementation"); w.Writeln (""); - + + if (component.isBaseClass(class)) { + w.Writeln ("constructor %s.Create();", pascalBaseClassName); + w.Writeln ("begin"); + w.Writeln (" inherited Create();"); + w.Writeln (" FMessages := TStringList.Create();"); + w.Writeln ("end;"); + w.Writeln (""); + w.Writeln ("destructor %s.Destroy();", pascalBaseClassName); + w.Writeln ("begin"); + w.Writeln (" FreeAndNil(FMessages);"); + w.Writeln (" inherited Destroy();"); + w.Writeln ("end;"); + w.Writeln (""); + } + + if (component.isBaseClass(class)) { + for i,method := range baseClassMethods { + err := writePascalClassMethodDummyStub(method, w, NameSpace, class.ClassName, outClassName, false, baseClassMethodImplementation[i]) + if err != nil { + return err; + } + } + } + for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writePascalClassMethodDummyStub(method, w, NameSpace, class.ClassName, outClassName, false); + err := writePascalClassMethodDummyStub(method, w, NameSpace, class.ClassName, outClassName, false, defaultImplementation); if err != nil { return err; } @@ -1288,9 +1339,9 @@ func writePascalImplClassMethodDefinition (method ComponentDefinitionMethod, w L } -func buildStubImplementation(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, stubIdentifier string) error { +func buildStubImplementation(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, stubIdentifier string, defaultImplementation []string) error { - global := componentdefinition.Global; + global := component.Global; w.Writeln ("{$MODE DELPHI}"); w.Writeln ("Unit %s%s;", BaseName, stubIdentifier); @@ -1300,6 +1351,7 @@ func buildStubImplementation(componentdefinition ComponentDefinition, w Language w.Writeln ("uses"); w.Writeln (" %s_types,", BaseName); w.Writeln (" %s_exception,", BaseName); + w.Writeln (" %s_interfaces,", BaseName); w.Writeln (" Classes,"); w.Writeln (" sysutils;"); w.Writeln (""); @@ -1325,7 +1377,7 @@ func buildStubImplementation(componentdefinition ComponentDefinition, w Language for j := 0; j < len(global.Methods); j++ { method := global.Methods[j] - err := writePascalClassMethodDummyStub(method, w, NameSpace, "Wrapper", "T" + NameSpace + "Wrapper", true) + err := writePascalClassMethodDummyStub(method, w, NameSpace, "Wrapper", "T" + NameSpace + "Wrapper", true, defaultImplementation) if err != nil { return err; } diff --git a/Source/componentdefinition.go b/Source/componentdefinition.go index ee1332dd..bcb590d8 100644 --- a/Source/componentdefinition.go +++ b/Source/componentdefinition.go @@ -49,6 +49,9 @@ const ( eSpecialMethodRelease = 1 eSpecialMethodVersion = 2 eSpecialMethodJournal = 3 + eSpecialMethodError = 4 + eSpecialMethodPrerelease = 5 + eSpecialMethodBuildinfo = 6 ) // ComponentDefinitionParam definition of a method parameter used in the component's API @@ -68,7 +71,6 @@ type ComponentDefinitionMethod struct { XMLName xml.Name `xml:"method"` MethodName string `xml:"name,attr"` MethodDescription string `xml:"description,attr"` - DLLSuffix string `xml:"dllsuffix,attr"` Params []ComponentDefinitionParam `xml:"param"` } @@ -107,9 +109,13 @@ type ComponentDefinitionImplementationList struct { type ComponentDefinitionGlobal struct { ComponentDiffableElement XMLName xml.Name `xml:"global"` + BaseClassName string `xml:"baseclassname,attr"` + ErrorMethod string `xml:"errormethod,attr"` ReleaseMethod string `xml:"releasemethod,attr"` JournalMethod string `xml:"journalmethod,attr"` VersionMethod string `xml:"versionmethod,attr"` + PrereleaseMethod string `xml:"prereleasemethod,attr"` + BuildinfoMethod string `xml:"buildinfomethod,attr"` Methods []ComponentDefinitionMethod `xml:"method"` } @@ -119,6 +125,7 @@ type ComponentDefinitionBinding struct { XMLName xml.Name `xml:"binding"` Language string `xml:"language,attr"` Indentation string `xml:"indentation,attr"` + ClassIdentifier string `xml:"classidentifier,attr"` } // ComponentDefinitionImplementation definition of a specific languages for which bindings to the component's API will be generated @@ -217,6 +224,42 @@ type ComponentDefinition struct { Errors ComponentDefinitionErrors `xml:"errors"` } +// Normalize adds default values, changes deprecated constants to their later versions +func (component *ComponentDefinition) Normalize() { + for i := 0; i < len(component.Classes); i++ { + component.Classes[i].Normalize() + } + component.Global.Normalize() +} + +// Normalize adds default values, changes deprecated constants to their later versions +func (global *ComponentDefinitionGlobal) Normalize() { + for i := 0; i < len(global.Methods); i++ { + global.Methods[i].Normalize() + } +} + +// Normalize adds default values, changes deprecated constants to their later versions +func (class *ComponentDefinitionClass) Normalize() { + for i := 0; i < len(class.Methods); i++ { + class.Methods[i].Normalize() + } +} + +// Normalize adds default values, changes deprecated constants to their later versions +func (method *ComponentDefinitionMethod) Normalize() { + for i := 0; i < len(method.Params); i++ { + method.Params[i].Normalize() + } +} + +// Normalize adds default values, changes deprecated constants to their later versions +func (param *ComponentDefinitionParam) Normalize() { + if param.ParamType == "handle" { + param.ParamType = "class" + } +} + func getIndentationString (str string) string { if str == "tabs" { return "\t"; @@ -261,6 +304,7 @@ func checkImplementations(implementations[] ComponentDefinitionImplementation) e func checkErrors(errors ComponentDefinitionErrors) error { errorNameList := make(map[string]bool, 0); errorCodeList := make(map[int]bool, 0); + for i := 0; i < len(errors.Errors); i++ { merror := errors.Errors[i]; if !nameIsValidIdentifier(merror.Name) { @@ -280,6 +324,15 @@ func checkErrors(errors ComponentDefinitionErrors) error { return fmt.Errorf( "invalid error description \"%s\" for error \"%s\"", merror.Description, merror.Name); } } + + requiredErrors := []string{"NOTIMPLEMENTED", "INVALIDPARAM", + "INVALIDCAST", "BUFFERTOOSMALL", "GENERICEXCEPTION", "COULDNOTLOADLIBRARY", "COULDNOTFINDLIBRARYEXPORT", "INCOMPATIBLEBINARYVERSION"} + for _, req := range requiredErrors { + if (!errorNameList[strings.ToLower(req)]) { + return fmt.Errorf( "component is missing the required error \"%s\"", req); + } + } + return nil } @@ -355,16 +408,23 @@ func checkStructs(structs[] ComponentDefinitionStruct) (map[string]bool, error) if structLowerNameList[mstruct.Name] == true { return nil, fmt.Errorf ("duplicate struct name \"%s\"", mstruct.Name) } - structNameList[mstruct.Name] = true structLowerNameList[strings.ToLower(mstruct.Name)] = true + + for j := 0; j < len(mstruct.Members); j++ { + member := mstruct.Members[j] + if !nameIsValidIdentifier(member.Name) { + return nil, fmt.Errorf ("invalid member name \"%s\"", member.Name); + } + } } return structNameList, nil } -func checkClasses(classes[] ComponentDefinitionClass) (map[string]bool, error) { +func checkClasses(classes[] ComponentDefinitionClass, baseClassName string) (map[string]bool, error) { classLowerNameList := make(map[string]bool, 0) classNameList := make(map[string]bool, 0) + classNameIndex := make(map[string]int, 0) for i := 0; i < len(classes); i++ { class := classes[i]; if !nameIsValidIdentifier(class.ClassName) { @@ -379,22 +439,29 @@ func checkClasses(classes[] ComponentDefinitionClass) (map[string]bool, error) { classLowerNameList[strings.ToLower(class.ClassName)] = true classNameList[class.ClassName] = true + classNameIndex[class.ClassName] = i } + // Check parent class definitions for i := 0; i < len(classes); i++ { class := classes[i]; parentClass := class.ParentClass; + if ((baseClassName != class.ClassName) && (len(parentClass) == 0) ) { + parentClass = baseClassName + } if (len(parentClass) > 0) { if !nameIsValidIdentifier(parentClass) { - return nil, fmt.Errorf ("invalid class parent name \"%s\"", parentClass); + return nil, fmt.Errorf ("invalid parent class name \"%s\"", parentClass); } if (classNameList[parentClass] == false) { return nil, fmt.Errorf ("unknown parent class \"%s\" for class \"%s\"", parentClass, class.ClassName); } + if (classNameIndex[parentClass] >= i) { + return nil, fmt.Errorf ("parent class \"%s\" for class \"%s\" is defined after its child class", parentClass, class.ClassName); + } if (strings.ToLower(class.ClassName) == strings.ToLower(parentClass)) { return nil, fmt.Errorf ("class \"%s\" cannot be its own parent class \"%s\"", class.ClassName, parentClass); } - } } @@ -424,7 +491,7 @@ func checkFunctionTypes(functions[] ComponentDefinitionFunctionType) (map[string func checkDuplicateNames(enumList map[string]bool, structList map[string]bool, classList map[string]bool) (error) { allLowerList := make(map[string]string, 0) - for k := range structList { + for k := range structList { if allLowerList[strings.ToLower(k)] == "struct" { return fmt.Errorf ("duplicate struct name \"%s\"", k) } @@ -490,7 +557,7 @@ func checkClassMethods(classes[] ComponentDefinitionClass, enumList map[string]b if (isScalarType(param.ParamType) || param.ParamType == "string") { // okay - } else if (param.ParamType == "handle") { + } else if (param.ParamType == "class") { if (classList[param.ParamClass] != true) { return fmt.Errorf ("parameter \"%s\" of method \"%s.%s\" is of unknown class \"%s\"", param.ParamName, class.ClassName, method.MethodName, param.ParamClass); } @@ -538,50 +605,75 @@ func descriptionIsValid (description string) bool { func isScalarType(typeStr string) bool { switch (typeStr) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer": return true } return false } -func majorVersion (version string) int { - return versionTriple(version)[0] +func majorVersion(version string) int { + isValid, versions, _ := decomposeVersionString(version) + if (!isValid) { + log.Fatal("invalid version") + } + return versions[0] } -func minorVersion (version string) int { - return versionTriple(version)[1] +func minorVersion(version string) int { + isValid, versions, _ := decomposeVersionString(version) + if (!isValid) { + log.Fatal("invalid version") + } + return versions[1] } -func microVersion (version string) int { - return versionTriple(version)[2] +func microVersion(version string) int { + isValid, versions, _ := decomposeVersionString(version) + if (!isValid) { + log.Fatal("invalid version") + } + return versions[2] } - -func versionTriple (version string) [3]int { - if !versionIsValidVersion(version) { +func preReleaseInfo(version string) string { + isValid, _, additionalData := decomposeVersionString(version) + if (!isValid) { log.Fatal("invalid version") } - - versionTripleR, _ := regexp.Compile("([0-9]*)") - trip := versionTripleR.FindAllString(version, -1) - if len(trip) != 3 { + return additionalData[0] +} +func buildInfo(version string) string { + isValid, _, additionalData := decomposeVersionString(version) + if (!isValid) { log.Fatal("invalid version") } + return additionalData[1] +} + +func decomposeVersionString(version string) (bool, [3]int, [2]string) { + var IsValidVersion = regexp.MustCompile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\-[a-zA-Z0-9.\\-]+)?(\\+[a-zA-Z0-9.\\-]+)?$") var vers [3]int; + var data [2]string; + + if !(IsValidVersion.MatchString(version)) { + return false, vers, data; + } + slices := IsValidVersion.FindStringSubmatch(version) + if (len(slices) != 6) { + return false, vers, data; + } for i := 0; i < 3; i++ { - ver, err := strconv.Atoi(trip[i]) + ver, err := strconv.Atoi(slices[i+1]) if err != nil { - log.Fatal("invalid version") + return false, vers, data; } vers[i] = ver } - return vers -} - -func versionIsValidVersion (version string) bool { - var IsValidVersion = regexp.MustCompile("^([0-9]*)\\.([0-9]*)\\.([0-9]*)$").MatchString - if (version != "") { - return IsValidVersion (version); + for i := 0; i < 2; i++ { + slice := slices[i+4] + if (len(slice)>0) { + data[i] = slice[1:] + } } - return false; + return true, vers, data; } func nameSpaceIsValid (namespace string) bool { @@ -617,7 +709,8 @@ func baseNameIsValid (baseName string) bool { } func checkComponentHeader(component ComponentDefinition) (error) { - if !versionIsValidVersion(component.Version) { + versionIsValid, _, _ := decomposeVersionString(component.Version) + if !versionIsValid { return fmt.Errorf("Version \"%s\" is invalid", component.Version) } if component.Copyright == "" { @@ -647,7 +740,7 @@ func CheckComponentDefinition (component ComponentDefinition) (error) { if err != nil { return err } - + err = checkErrors(component.Errors) if err != nil { return err @@ -671,7 +764,7 @@ func CheckComponentDefinition (component ComponentDefinition) (error) { } var classList = make(map[string]bool, 0) - classList, err = checkClasses(component.Classes) + classList, err = checkClasses(component.Classes, component.Global.BaseClassName) if err != nil { return err } @@ -692,6 +785,21 @@ func CheckComponentDefinition (component ComponentDefinition) (error) { return err } + + if (component.Global.BaseClassName == "") { + return errors.New ("No base class name specified"); + } + found := 0 + for i := 0; i < len(component.Classes); i++ { + if (component.Classes[i].ClassName == component.Global.BaseClassName) { + found++ + } + } + if (found==0) { + return errors.New ("Specified base class not found"); + } else if (found>1) { + return errors.New ("Base clase defined more than once"); + } return nil } @@ -707,6 +815,10 @@ func CheckHeaderSpecialFunction (method ComponentDefinitionMethod, global Compon return eSpecialMethodNone, errors.New ("No version method specified"); } + if (global.ErrorMethod == "") { + return eSpecialMethodNone, errors.New ("No error method specified"); + } + if (global.ReleaseMethod == global.JournalMethod) { return eSpecialMethodNone, errors.New ("Release method can not be the same as the Journal method"); } @@ -718,13 +830,13 @@ func CheckHeaderSpecialFunction (method ComponentDefinitionMethod, global Compon if (global.JournalMethod == global.VersionMethod) { return eSpecialMethodNone, errors.New ("Journal method can not be the same as the Version method"); } - + if (method.MethodName == global.ReleaseMethod) { if (len (method.Params) != 1) { return eSpecialMethodNone, errors.New ("Release method does not match the expected function template"); } - if (method.Params[0].ParamType != "handle") || (method.Params[0].ParamClass != "BaseClass") || (method.Params[0].ParamPass != "in") { + if (method.Params[0].ParamType != "class") || (method.Params[0].ParamClass != global.BaseClassName) || (method.Params[0].ParamPass != "in") { return eSpecialMethodNone, errors.New ("Release method does not match the expected function template"); } @@ -750,14 +862,103 @@ func CheckHeaderSpecialFunction (method ComponentDefinitionMethod, global Compon if (method.Params[0].ParamType != "uint32") || (method.Params[0].ParamPass != "out") || (method.Params[1].ParamType != "uint32") || (method.Params[1].ParamPass != "out") || - (method.Params[2].ParamType != "uint32") || (method.Params[2].ParamPass != "out") { + (method.Params[2].ParamType != "uint32") || (method.Params[2].ParamPass != "out") { return eSpecialMethodNone, errors.New ("Version method does not match the expected function template"); } return eSpecialMethodVersion, nil; } + if (method.MethodName == global.ErrorMethod) { + if (len (method.Params) != 3) { + return eSpecialMethodNone, errors.New ("Error method does not match the expected function template"); + } + + if (method.Params[0].ParamType != "class") || (method.Params[0].ParamPass != "in") || + (method.Params[1].ParamType != "string") || (method.Params[1].ParamPass != "out") || + (method.Params[2].ParamType != "bool") || (method.Params[2].ParamPass != "return") || + (method.Params[0].ParamClass != global.BaseClassName) { + return eSpecialMethodNone, errors.New ("Error method does not match the expected function template"); + } + + return eSpecialMethodError, nil; + } + + if len(global.PrereleaseMethod)>0 && (global.PrereleaseMethod == global.BuildinfoMethod) { + return eSpecialMethodNone, errors.New ("Prerelease method can not be the same as the buildinfo method"); + } + + if (method.MethodName == global.PrereleaseMethod) { + if (len (method.Params) != 2) { + return eSpecialMethodNone, errors.New ("Prerelease method does not match the expected function template"); + } + + if (method.Params[0].ParamType != "bool") || (method.Params[0].ParamPass != "return") || + (method.Params[1].ParamType != "string") || (method.Params[1].ParamPass != "out") { + return eSpecialMethodNone, errors.New ("Prerelease method does not match the expected function template"); + } + + return eSpecialMethodPrerelease, nil; + } + + if (method.MethodName == global.BuildinfoMethod) { + if (len (method.Params) != 2) { + return eSpecialMethodNone, errors.New ("Buildinfo method does not match the expected function template"); + } + + if (method.Params[0].ParamType != "bool") || (method.Params[0].ParamPass != "return") || + (method.Params[1].ParamType != "string") || (method.Params[1].ParamPass != "out") { + return eSpecialMethodNone, errors.New ("Buildinfo method does not match the expected function template"); + } + + return eSpecialMethodBuildinfo, nil; + } + return eSpecialMethodNone, nil; } +// GetLastErrorMessageMethod returns the xml definition of the GetLastErrorMessage-method +func GetLastErrorMessageMethod() (ComponentDefinitionMethod) { + var method ComponentDefinitionMethod + source := `<method name="GetLastErrorMessage" description = "Returns the last error registered of this class instance"> + <param name="ErrorMessage" type="string" pass="out" description="Message of the last error registered" /> + <param name="HasLastError" type="bool" pass="return" description="Has an error been registered already" /> + </method>` + xml.Unmarshal([]byte(source), &method) + return method +} + +// RegisterErrorMessageMethod returns the xml definition of the RegisterErrorMessage-method +func RegisterErrorMessageMethod() (ComponentDefinitionMethod) { + var method ComponentDefinitionMethod + source := `<method name="RegisterErrorMessage" description = "Registers an error message with this class instance"> + <param name="ErrorMessage" type="string" pass="in" description="Error message to register" /> + </method>` + xml.Unmarshal([]byte(source), &method) + return method +} + +// ClearErrorMessageMethod returns the xml definition of the ClearErrorMessage-method +func ClearErrorMessageMethod() (ComponentDefinitionMethod) { + var method ComponentDefinitionMethod + source := ` <method name="ClearErrorMessages" description = "Clears all registered messages of this class instance"> + </method>` + xml.Unmarshal([]byte(source), &method) + return method +} + +func (component *ComponentDefinition) isBaseClass(class ComponentDefinitionClass) (bool) { + return class.ClassName == component.Global.BaseClassName +} + +func (component *ComponentDefinition) baseClass() (ComponentDefinitionClass) { + for i := 0; i < len(component.Classes); i++ { + if (component.isBaseClass(component.Classes[i])) { + return component.Classes[i] + } + } + var out ComponentDefinitionClass + log.Fatal("No base class available") + return out +} diff --git a/Source/componentdiff.go b/Source/componentdiff.go index 74eb1382..df3c5675 100644 --- a/Source/componentdiff.go +++ b/Source/componentdiff.go @@ -489,7 +489,7 @@ func diffGlobal(path string, globalA ComponentDefinitionGlobal, globalB Componen } if (globalA.VersionMethod != globalB.VersionMethod) { var change ComponentDiffAttributeChange - change.Path = pathA + "/resrionmethod" + change.Path = pathA + "/versionmethod" change.OldValue = globalA.VersionMethod change.NewValue = globalB.VersionMethod changes = append(changes, change) diff --git a/Source/languagec.go b/Source/languagec.go index 536decd1..a810061a 100644 --- a/Source/languagec.go +++ b/Source/languagec.go @@ -51,7 +51,7 @@ func BuildBindingC(component ComponentDefinition, outputFolderBindingC string) e CHeaderName := path.Join(outputFolderBindingC, component.BaseName + ".h"); log.Printf("Creating \"%s\"", CTypesHeaderName) - err = CreateCHeader (component, CHeaderName); + err = CreateCAbiHeader(component, CHeaderName); if (err != nil) { return err; } @@ -69,16 +69,13 @@ func CreateCTypesHeader (component ComponentDefinition, CTypesHeaderName string) fmt.Sprintf ("This is an autogenerated plain C Header file with basic types in\norder to allow an easy use of %s", component.LibraryName), true); - err = buildCTypesHeader(component, hTypesFile, component.NameSpace); + err = buildCCPPTypesHeader(component, hTypesFile, component.NameSpace, false); return err; } -func buildCTypesHeader (component ComponentDefinition, w LanguageWriter, NameSpace string) (error) { - w.Writeln("#ifndef __%s_TYPES_HEADER", strings.ToUpper (NameSpace)); - w.Writeln("#define __%s_TYPES_HEADER", strings.ToUpper (NameSpace)); - w.Writeln(""); +func buildSharedCCPPTypesHeader(component ComponentDefinition, w LanguageWriter, NameSpace string) (error) { w.Writeln("/*************************************************************************************************************************"); w.Writeln(" Scalar types definition"); w.Writeln("**************************************************************************************************************************/") @@ -121,15 +118,18 @@ func buildCTypesHeader (component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln(""); w.Writeln("typedef %s_int32 %sResult;", NameSpace, NameSpace); w.Writeln("typedef void * %sHandle;", NameSpace); + w.Writeln("typedef void * %s_pvoid;", NameSpace); w.Writeln(""); w.Writeln("/*************************************************************************************************************************"); w.Writeln(" Version for %s", NameSpace); w.Writeln("**************************************************************************************************************************/"); w.Writeln(""); - w.Writeln("#define %s_VERSION_MAJOR %d", strings.ToUpper (NameSpace), majorVersion(component.Version)); - w.Writeln("#define %s_VERSION_MINOR %d", strings.ToUpper (NameSpace), minorVersion(component.Version)); - w.Writeln("#define %s_VERSION_MICRO %d", strings.ToUpper (NameSpace), microVersion(component.Version)); + w.Writeln("#define %s_VERSION_MAJOR %d", strings.ToUpper(NameSpace), majorVersion(component.Version)); + w.Writeln("#define %s_VERSION_MINOR %d", strings.ToUpper(NameSpace), minorVersion(component.Version)); + w.Writeln("#define %s_VERSION_MICRO %d", strings.ToUpper(NameSpace), microVersion(component.Version)); + w.Writeln("#define %s_VERSION_PRERELEASEINFO \"%s\"", strings.ToUpper(NameSpace), preReleaseInfo(component.Version)); + w.Writeln("#define %s_VERSION_BUILDINFO \"%s\"", strings.ToUpper(NameSpace), buildInfo(component.Version)); w.Writeln(""); @@ -138,8 +138,6 @@ func buildCTypesHeader (component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln("**************************************************************************************************************************/"); w.Writeln(""); w.Writeln("#define %s_SUCCESS 0", strings.ToUpper (NameSpace)); - - for i := 0; i < len(component.Errors.Errors); i++ { errorcode := component.Errors.Errors[i]; w.Writeln("#define %s_ERROR_%s %d", strings.ToUpper (NameSpace), errorcode.Name, errorcode.Code); @@ -152,175 +150,117 @@ func buildCTypesHeader (component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln("**************************************************************************************************************************/"); w.Writeln(""); - w.Writeln("typedef %sHandle %s_BaseClass;", NameSpace, NameSpace); - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i]; - w.Writeln("typedef %sHandle %s_%s;", NameSpace, NameSpace, class.ClassName); + class := component.Classes[i]; + w.Writeln("typedef %sHandle %s_%s;", NameSpace, NameSpace, class.ClassName); } w.Writeln(""); - if (len(component.Enums) > 0) { - w.Writeln("/*************************************************************************************************************************"); - w.Writeln(" Declaration of enums"); - w.Writeln("**************************************************************************************************************************/"); - w.Writeln(""); + return nil +} - for i := 0; i < len(component.Enums); i++ { - enum := component.Enums[i]; - w.Writeln("enum e%s%s {", NameSpace, enum.Name); - - for j := 0; j < len(enum.Options); j++ { - - comma := ""; - if (j < len(enum.Options) - 1) { - comma = ","; - } - - option := enum.Options[j]; - w.Writeln(" e%s%s = %d%s", enum.Name, option.Name, option.Value, comma); +func getCMemberLine(member ComponentDefinitionMember, NameSpace string, arraysuffix string, structName string) (string, error) { + switch (member.Type) { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool", "pointer": + typeName, err := getCParameterTypeName(member.Type, NameSpace, "") + if (err != nil) { + return "", err } - - w.Writeln("};"); - w.Writeln(""); - } - + return fmt.Sprintf("%s m_%s%s;", typeName, member.Name, arraysuffix), nil + case "enum": + return fmt.Sprintf("structEnum%s%s m_%s%s;", NameSpace, member.Class, member.Name, arraysuffix), nil + default: + return "", fmt.Errorf ("it is not possible for struct %s to contain a %s member", structName, member.Type); + } +} - w.Writeln("/*************************************************************************************************************************"); - w.Writeln(" Declaration of enum members for 4 byte struct alignment"); - w.Writeln("**************************************************************************************************************************/"); +func buildCCPPTypesHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, useCPPTypes bool) (error) { + sIncludeGuard := "__"+strings.ToUpper(NameSpace)+"_TYPES_HEADER" + if useCPPTypes { + sIncludeGuard += "_CPP" + } + + w.Writeln("#ifndef %s", sIncludeGuard); + w.Writeln("#define %s", sIncludeGuard); + w.Writeln(""); + + err := buildSharedCCPPTypesHeader(component, w, NameSpace) + if (err != nil) { + return err + } + + if useCPPTypes { + w.Writeln("namespace %s {", NameSpace); w.Writeln(""); + w.AddIndentationLevel(1); + } + err = buildCCPPEnums(component, w, NameSpace, useCPPTypes) + if (err!=nil) { + return err + } + err = buildCCPPStructs(component, w, NameSpace, useCPPTypes) + if (err!=nil) { + return err + } + err = buildCCPPFunctionPointers(component, w, NameSpace, useCPPTypes) + if (err != nil) { + return err + } + + if (useCPPTypes) { + w.AddIndentationLevel(-1); + w.Writeln("} // namespace %s;", NameSpace); + w.Writeln("") + w.Writeln("// define legacy C-names for enums, structs and function types") for i := 0; i < len(component.Enums); i++ { enum := component.Enums[i]; - w.Writeln("typedef union {"); - w.Writeln(" e%s%s m_enum;", NameSpace, enum.Name); - w.Writeln(" int m_code;"); - w.Writeln("} structEnum%s%s;", NameSpace, enum.Name); - w.Writeln(""); + w.Writeln("typedef %s::e%s e%s%s;", NameSpace, enum.Name, NameSpace, enum.Name); } - } - - if len(component.Structs) > 0 { - - w.Writeln("/*************************************************************************************************************************"); - w.Writeln(" Declaration of structs"); - w.Writeln("**************************************************************************************************************************/"); - w.Writeln(""); - - w.Writeln("#pragma pack (1)"); - w.Writeln(""); - for i := 0; i < len(component.Structs); i++ { structinfo := component.Structs[i]; - w.Writeln("typedef struct {"); - - for j := 0; j < len(structinfo.Members); j++ { - - member := structinfo.Members[j]; - - arraysuffix := ""; - if (member.Rows > 0) { - if (member.Columns > 0) { - arraysuffix = fmt.Sprintf ("[%d][%d]", member.Columns, member.Rows) - } else { - arraysuffix = fmt.Sprintf ("[%d]",member.Rows) - } - } - - switch (member.Type) { - case "uint8": - w.Writeln(" %s_uint8 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "uint16": - w.Writeln(" %s_uint16 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "uint32": - w.Writeln(" %s_uint32 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "uint64": - w.Writeln(" %s_uint64 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "int8": - w.Writeln(" %s_int8 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "int16": - w.Writeln(" %s_int16 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "int32": - w.Writeln(" %s_int32 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "int64": - w.Writeln(" %s_int64 m_%s%s;", NameSpace, member.Name, arraysuffix); - case "bool": - w.Writeln(" bool m_%s%s;", member.Name, arraysuffix); - case "single": - w.Writeln(" %s_single m_%s%s;", NameSpace, member.Name, arraysuffix); - case "double": - w.Writeln(" %s_double m_%s%s;", NameSpace, member.Name, arraysuffix); - case "string": - return fmt.Errorf ("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name); - case "handle": - return fmt.Errorf ("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name); - case "enum": - w.Writeln(" structEnum%s%s m_%s%s;", NameSpace, member.Class, member.Name, arraysuffix); - } - - - } - - w.Writeln("} s%s%s;", NameSpace, structinfo.Name); - w.Writeln(""); + w.Writeln("typedef %s::s%s s%s%s;", NameSpace, structinfo.Name, NameSpace, structinfo.Name); } - - w.Writeln("#pragma pack ()"); - w.Writeln(""); - - } - - if len(component.Functions) > 0 { - w.Writeln("/*************************************************************************************************************************"); - w.Writeln(" Declaration of function pointers "); - w.Writeln("**************************************************************************************************************************/"); for i := 0; i < len(component.Functions); i++ { functiontype := component.Functions[i] - returnType := "void" - parameters := "" + w.Writeln("typedef %s::%s %s%s;", NameSpace, functiontype.FunctionName, NameSpace, functiontype.FunctionName); + } + } - w.Writeln(""); - w.Writeln("/**"); - w.Writeln("* %s%s - %s", NameSpace, functiontype.FunctionName, functiontype.FunctionDescription ) - w.Writeln("*") - for j := 0; j < len(functiontype.Params); j++ { - param := functiontype.Params[j] + w.Writeln(""); + w.Writeln("#endif // %s", sIncludeGuard); - cParams, err := generateCParameter(param, "", functiontype.FunctionName, NameSpace) - if (err != nil) { - return err; - } - for _, cParam := range cParams { - w.Writeln(cParam.ParamComment); - } + return nil; +} - cParamTypeName, err := getCParameterTypeName(param.ParamType, NameSpace, param.ParamClass); - if (err != nil) { - return err; - } - if (parameters != "") { - parameters = parameters + ", " - } - if (param.ParamPass == "in") { - parameters = parameters + cParamTypeName - } else { - parameters = parameters + cParamTypeName + "*" - } - } - w.Writeln("*/"); - w.Writeln("typedef %s(*%s%s)(%s);", returnType, NameSpace, functiontype.FunctionName, parameters); - } - w.Writeln(""); +// GetCMemberDefaultValue returns the defailt value of a member in C-based-languages +func GetCMemberDefaultValue(memberType string, memberClass string, NameSpace string) (string, error) { + switch (memberType) { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": + return "0", nil; + case "bool": + return "false", nil; + case "single": + return "0.0f", nil; + case "double": + return "0.0", nil; + case "pointer": + return "nullptr", nil; + case "enum": + return "0", nil; + case "string": + return "", fmt.Errorf ("it is not possible for a struct to contain a string value"); + case "class": + return "", fmt.Errorf ("it is not possible for a struct to contain a handle value"); + default: + return "", fmt.Errorf ("unknown member type %s", memberType); } - - w.Writeln("#endif // __%s_TYPES_HEADER", strings.ToUpper (NameSpace)); - return nil; } -// CreateCHeader creates a C header file for the component's API -func CreateCHeader (component ComponentDefinition, CHeaderName string) (error) { + +// CreateCAbiHeader creates a C header file for the component's API +func CreateCAbiHeader(component ComponentDefinition, CHeaderName string) (error) { hfile, err := CreateLanguageFile(CHeaderName, " "); if (err != nil) { return err; @@ -328,47 +268,65 @@ func CreateCHeader (component ComponentDefinition, CHeaderName string) (error) { hfile.WriteCLicenseHeader (component, fmt.Sprintf ("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", component.LibraryName), true); - err = buildCHeader (component, hfile, component.NameSpace, component.BaseName); + err = buildCAbiHeader(component, hfile, component.NameSpace, component.BaseName, false); return err; } -func buildCHeader (component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) (error) { - w.Writeln("#ifndef __%s_HEADER", strings.ToUpper (NameSpace)); - w.Writeln("#define __%s_HEADER", strings.ToUpper (NameSpace)); +func writeClassMethodsIntoCCPPHeader(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, useCPPTypes bool) (error) { + w.Writeln(""); + w.Writeln("/*************************************************************************************************************************"); + w.Writeln(" Class definition for %s", class.ClassName); + w.Writeln("**************************************************************************************************************************/"); + + for j := 0; j < len(class.Methods); j++ { + method := class.Methods[j]; + err := WriteCCPPAbiMethod (method, w, NameSpace, class.ClassName, false, false, useCPPTypes); + if (err != nil) { + return err; + } + } + return nil +} + +func buildCAbiHeader(component ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string, useCPPTypes bool) (error) { + sIncludeGuard := "__"+strings.ToUpper(NameSpace)+"_HEADER" + if (useCPPTypes) { + sIncludeGuard += "_CPP" + } + + w.Writeln("#ifndef %s", sIncludeGuard); + w.Writeln("#define %s", sIncludeGuard); w.Writeln(""); + w.Writeln("#ifdef __%s_EXPORTS", strings.ToUpper (NameSpace)); - - w.Writeln("#ifdef WIN32"); + w.Writeln("#ifdef _WIN32"); w.Writeln("#define %s_DECLSPEC __declspec (dllexport)", strings.ToUpper (NameSpace)); - w.Writeln("#else // WIN32"); + w.Writeln("#else // _WIN32"); w.Writeln("#define %s_DECLSPEC __attribute__((visibility(\"default\")))", strings.ToUpper (NameSpace)); - w.Writeln("#endif // WIN32"); + w.Writeln("#endif // _WIN32"); w.Writeln("#else // __%s_EXPORTS", strings.ToUpper (NameSpace)); w.Writeln("#define %s_DECLSPEC", strings.ToUpper (NameSpace)); w.Writeln("#endif // __%s_EXPORTS", strings.ToUpper (NameSpace)); w.Writeln(""); - w.Writeln("#include \"%s_types.h\"", BaseName); + if (useCPPTypes) { + w.Writeln("#include \"%s_types.hpp\"", BaseName); + } else { + w.Writeln("#include \"%s_types.h\"", BaseName); + } w.Writeln(""); w.Writeln("extern \"C\" {"); for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i]; - - w.Writeln(""); - w.Writeln("/*************************************************************************************************************************"); - w.Writeln(" Class definition for %s", class.ClassName); - w.Writeln("**************************************************************************************************************************/"); - - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j]; - WriteCMethod (method, w, NameSpace, class.ClassName, false, false); + class := component.Classes[i]; + err := writeClassMethodsIntoCCPPHeader(component, class, w, NameSpace, useCPPTypes) + if (err != nil) { + return err; } } - w.Writeln(""); w.Writeln("/*************************************************************************************************************************"); w.Writeln(" Global functions"); @@ -377,7 +335,7 @@ func buildCHeader (component ComponentDefinition, w LanguageWriter, NameSpace st global := component.Global; for j := 0; j < len(global.Methods); j++ { method := global.Methods[j]; - err := WriteCMethod (method, w, NameSpace, "Wrapper", true, false); + err := WriteCCPPAbiMethod(method, w, NameSpace, "Wrapper", true, false, useCPPTypes); if (err != nil) { return err; } @@ -386,7 +344,7 @@ func buildCHeader (component ComponentDefinition, w LanguageWriter, NameSpace st w.Writeln(""); w.Writeln("}"); w.Writeln(""); - w.Writeln("#endif // __%s_HEADER", strings.ToUpper (NameSpace)); + w.Writeln("#endif // %s", sIncludeGuard); w.Writeln(""); return nil; @@ -397,26 +355,25 @@ func buildCHeader (component ComponentDefinition, w LanguageWriter, NameSpace st func GetCExportName (NameSpace string, ClassName string, method ComponentDefinitionMethod, isGlobal bool) (string) { CMethodName := ""; if isGlobal { - CMethodName = fmt.Sprintf("%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName), method.DLLSuffix) + CMethodName = fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) } else { - CMethodName = fmt.Sprintf("%s_%s_%s%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName), method.DLLSuffix) + CMethodName = fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(ClassName), strings.ToLower(method.MethodName)) } return CMethodName; } -// WriteCMethod writes a method as a C funtion -func WriteCMethod (method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool, writeCallbacks bool) (error) { - +// WriteCCPPAbiMethod writes an ABI method as a C-function +func WriteCCPPAbiMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool, writeCallbacks bool, useCPPTypes bool) (error) { CMethodName := ""; CCallbackName := ""; parameters := ""; if (isGlobal) { - CMethodName = fmt.Sprintf ("%s_%s%s", strings.ToLower (NameSpace), strings.ToLower (method.MethodName), method.DLLSuffix); + CMethodName = fmt.Sprintf ("%s_%s", strings.ToLower (NameSpace), strings.ToLower (method.MethodName)); CCallbackName = fmt.Sprintf ("P%s%sPtr", NameSpace, method.MethodName); } else { - CMethodName = fmt.Sprintf ("%s_%s_%s%s", strings.ToLower (NameSpace), strings.ToLower (ClassName), strings.ToLower (method.MethodName), method.DLLSuffix); + CMethodName = fmt.Sprintf ("%s_%s_%s", strings.ToLower (NameSpace), strings.ToLower (ClassName), strings.ToLower (method.MethodName)); CCallbackName = fmt.Sprintf ("P%s%s_%sPtr", NameSpace, ClassName, method.MethodName); parameters = fmt.Sprintf ("%s_%s p%s", NameSpace, ClassName, ClassName); } @@ -432,12 +389,10 @@ func WriteCMethod (method ComponentDefinitionMethod, w LanguageWriter, NameSpace for k := 0; k < len(method.Params); k++ { param := method.Params [k]; - - cParams, err := generateCParameter(param, ClassName, method.MethodName, NameSpace); + cParams, err := generateCCPPParameter(param, ClassName, method.MethodName, NameSpace, useCPPTypes); if (err != nil) { return err; } - for _, cParam := range cParams { w.Writeln(cParam.ParamComment); if (parameters != "") { @@ -445,12 +400,11 @@ func WriteCMethod (method ComponentDefinitionMethod, w LanguageWriter, NameSpace } parameters = parameters + cParam.ParamType + " " + cParam.ParamName; } - } w.Writeln("* @return error code or 0 (success)"); w.Writeln("*/"); - + if (writeCallbacks) { w.Writeln("typedef %sResult (*%s) (%s);", NameSpace, CCallbackName, parameters); } else { @@ -460,72 +414,205 @@ func WriteCMethod (method ComponentDefinitionMethod, w LanguageWriter, NameSpace return nil; } +func buildCCPPStructs(component ComponentDefinition, w LanguageWriter, NameSpace string, useCPPTypes bool) (error) { + if (len(component.Structs) == 0) { + return nil + } -func getCParameterTypeName(ParamTypeName string, NameSpace string, ParamClass string)(string, error) { - cParamTypeName := ""; - switch (ParamTypeName) { - case "uint8": - cParamTypeName = fmt.Sprintf ("%s_uint8", NameSpace); - - case "uint16": - cParamTypeName = fmt.Sprintf ("%s_uint16", NameSpace); + var err error + + w.Writeln("/*************************************************************************************************************************"); + w.Writeln(" Declaration of structs"); + w.Writeln("**************************************************************************************************************************/"); + w.Writeln(""); + + w.Writeln("#pragma pack (1)"); + w.Writeln(""); - case "uint32": - cParamTypeName = fmt.Sprintf ("%s_uint32", NameSpace); + for i := 0; i < len(component.Structs); i++ { + structinfo := component.Structs[i]; + w.Writeln("typedef struct {"); - case "uint64": - cParamTypeName = fmt.Sprintf ("%s_uint64", NameSpace); + for j := 0; j < len(structinfo.Members); j++ { + member := structinfo.Members[j]; + arraysuffix := ""; + if (member.Rows > 0) { + if (member.Columns > 0) { + arraysuffix = fmt.Sprintf ("[%d][%d]", member.Columns, member.Rows) + } else { + arraysuffix = fmt.Sprintf ("[%d]",member.Rows) + } + } + var memberLine string + if (useCPPTypes) { + memberLine, err= getCPPMemberLine(member, NameSpace, arraysuffix, structinfo.Name) + } else { + memberLine, err= getCMemberLine(member, NameSpace, arraysuffix, structinfo.Name) + } + if (err!=nil) { + return err + } + w.Writeln(" %s", memberLine) + } + if (useCPPTypes) { + w.Writeln("} s%s;", structinfo.Name); + } else { + w.Writeln("} s%s%s;", NameSpace, structinfo.Name); + } + w.Writeln(""); + } + + w.Writeln("#pragma pack ()"); + w.Writeln(""); + + return nil +} + +func buildCCPPEnums(component ComponentDefinition, w LanguageWriter, NameSpace string, useCPPTypes bool) (error) { + if (len(component.Enums) == 0) { + return nil + } + + w.Writeln("/*************************************************************************************************************************"); + w.Writeln(" Declaration of enums"); + w.Writeln("**************************************************************************************************************************/"); + w.Writeln(""); + + for i := 0; i < len(component.Enums); i++ { + enum := component.Enums[i]; + if (useCPPTypes) { + w.Writeln("enum class e%s : %s_int32 {", enum.Name, NameSpace); + } else { + w.Writeln("enum e%s%s {", NameSpace, enum.Name); + } - case "int8": - cParamTypeName = fmt.Sprintf ("%s_int8", NameSpace); + for j := 0; j < len(enum.Options); j++ { + comma := ""; + if (j < len(enum.Options) - 1) { + comma = ","; + } + option := enum.Options[j]; + if (useCPPTypes) { + w.Writeln(" %s = %d%s", option.Name, option.Value, comma); + } else { + w.Writeln(" e%s%s = %d%s", enum.Name, option.Name, option.Value, comma); + } + } + w.Writeln("};"); + w.Writeln(""); + } + + if (!useCPPTypes) { + w.Writeln("/*************************************************************************************************************************"); + w.Writeln(" Declaration of enum members for 4 byte struct alignment"); + w.Writeln("**************************************************************************************************************************/"); + w.Writeln(""); + + for i := 0; i < len(component.Enums); i++ { + enum := component.Enums[i]; + w.Writeln("typedef union {"); + w.Writeln(" e%s%s m_enum;", NameSpace, enum.Name); + w.Writeln(" int m_code;"); + w.Writeln("} structEnum%s%s;", NameSpace, enum.Name); + w.Writeln(""); + } + } + return nil +} + - case "int16": - cParamTypeName = fmt.Sprintf ("%s_int16", NameSpace); +func buildCCPPFunctionPointers(component ComponentDefinition, w LanguageWriter, NameSpace string, useCPPTypes bool) (error) { + if len(component.Functions) == 0 { + return nil + } + + w.Writeln("/*************************************************************************************************************************"); + w.Writeln(" Declaration of function pointers "); + w.Writeln("**************************************************************************************************************************/"); + for i := 0; i < len(component.Functions); i++ { + functiontype := component.Functions[i] + returnType := "void" + parameters := "" - case "int32": - cParamTypeName = fmt.Sprintf ("%s_int32", NameSpace); + w.Writeln(""); + w.Writeln("/**"); + if (useCPPTypes) { + w.Writeln("* %s - %s", functiontype.FunctionName, functiontype.FunctionDescription ) + } else { + w.Writeln("* %s%s - %s", NameSpace, functiontype.FunctionName, functiontype.FunctionDescription ) + } - case "int64": - cParamTypeName = fmt.Sprintf ("%s_int64", NameSpace); + w.Writeln("*") + for j := 0; j < len(functiontype.Params); j++ { + param := functiontype.Params[j] + + cParams, err := generateCCPPParameter(param, "", functiontype.FunctionName, NameSpace, useCPPTypes) + if (err != nil) { + return err; + } + for _, cParam := range cParams { + w.Writeln(cParam.ParamComment); + } + var cParamTypeName string + if (useCPPTypes) { + cParamTypeName, err = getCPPParameterTypeName(param.ParamType, NameSpace, param.ParamClass); + } else { + cParamTypeName, err = getCParameterTypeName(param.ParamType, NameSpace, param.ParamClass); + } + + if (err != nil) { + return err; + } + if (parameters != "") { + parameters = parameters + ", " + } + if (param.ParamPass == "in") { + parameters = parameters + cParamTypeName + } else { + parameters = parameters + cParamTypeName + "*" + } + } + w.Writeln("*/"); + if (useCPPTypes) { + w.Writeln("typedef %s(*%s)(%s);", returnType, functiontype.FunctionName, parameters); + } else { + w.Writeln("typedef %s(*%s%s)(%s);", returnType, NameSpace, functiontype.FunctionName, parameters); + } + } + w.Writeln(""); + return nil +} +func getCParameterTypeName(ParamTypeName string, NameSpace string, ParamClass string)(string, error) { + cParamTypeName := ""; + switch (ParamTypeName) { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": + cParamTypeName = fmt.Sprintf ("%s_%s", NameSpace, ParamTypeName); case "bool": cParamTypeName = "bool"; - - case "single": - cParamTypeName = fmt.Sprintf ("%s_single", NameSpace); - - case "double": - cParamTypeName = fmt.Sprintf ("%s_double", NameSpace); - + case "pointer": + cParamTypeName = fmt.Sprintf ("%s_pvoid", NameSpace); case "string": cParamTypeName = "char *"; - case "enum": cParamTypeName = fmt.Sprintf ("e%s%s", NameSpace, ParamClass); - case "struct": cParamTypeName = fmt.Sprintf ("s%s%s *", NameSpace, ParamClass); - case "basicarray": basicTypeName, err := getCParameterTypeName(ParamClass, NameSpace, ""); if (err != nil) { return "", err; } cParamTypeName = fmt.Sprintf ("%s *", basicTypeName); - case "structarray": cParamTypeName = fmt.Sprintf ("s%s%s *", NameSpace, ParamClass) - - case "handle": + case "class": cParamTypeName = fmt.Sprintf ("%s_%s", NameSpace, ParamClass) - case "functiontype": cParamTypeName = fmt.Sprintf ("%s%s", NameSpace, ParamClass) - default: return "", fmt.Errorf ("invalid parameter type \"%s\" for C-parameter", ParamTypeName); } - return cParamTypeName, nil; } @@ -537,9 +624,15 @@ type CParameter struct { } -func generateCParameter(param ComponentDefinitionParam, className string, methodName string, NameSpace string) ([]CParameter, error) { +func generateCCPPParameter(param ComponentDefinitionParam, className string, methodName string, NameSpace string, useCPPTypes bool) ([]CParameter, error) { cParams := make([]CParameter,1) - cParamTypeName, err := getCParameterTypeName(param.ParamType, NameSpace, param.ParamClass); + var cParamTypeName string + var err error + if (useCPPTypes) { + cParamTypeName, err = getCPPParameterTypeName(param.ParamType, NameSpace, param.ParamClass); + } else { + cParamTypeName, err = getCParameterTypeName(param.ParamType, NameSpace, param.ParamClass); + } if (err != nil) { return nil, err; } @@ -566,6 +659,11 @@ func generateCParameter(param ComponentDefinitionParam, className string, method cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "d" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); + + case "pointer": + cParams[0].ParamType = cParamTypeName; + cParams[0].ParamName = "p" + param.ParamName; + cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); case "string": cParams[0].ParamType = "const " + cParamTypeName; @@ -592,7 +690,7 @@ func generateCParameter(param ComponentDefinitionParam, className string, method cParams[1].ParamName = "p" + param.ParamName + "Buffer"; cParams[1].ParamComment = fmt.Sprintf("* @param[in] %s - %s buffer of %s", cParams[1].ParamName, param.ParamClass, param.ParamDescription); - case "handle": + case "class": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -610,7 +708,7 @@ func generateCParameter(param ComponentDefinitionParam, className string, method switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "enum": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer", "enum": cParams[0].ParamType = cParamTypeName + " *"; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -648,7 +746,7 @@ func generateCParameter(param ComponentDefinitionParam, className string, method cParams[2].ParamName = "p" + param.ParamName + "Buffer"; cParams[2].ParamComment = fmt.Sprintf("* @param[out] %s - %s buffer of %s, may be NULL", cParams[2].ParamName, param.ParamClass, param.ParamDescription); - case "handle": + case "class": cParams[0].ParamType = cParamTypeName + " *"; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -670,7 +768,7 @@ func GenerateCParameters(method ComponentDefinitionMethod, className string, Nam for k := 0; k < len(method.Params); k++ { param := method.Params [k]; - cParam, err := generateCParameter(param, className, method.MethodName, NameSpace); + cParam, err := generateCCPPParameter(param, className, method.MethodName, NameSpace, false); if err != nil { return nil, err; } diff --git a/Source/languagecpp.go b/Source/languagecpp.go new file mode 100644 index 00000000..637bf168 --- /dev/null +++ b/Source/languagecpp.go @@ -0,0 +1,104 @@ +/*++ + +Copyright (C) 2018 Autodesk Inc. (Original Author) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--*/ + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// languagecpp.go +// functions to generate a CPP-layer of a library's API (can be used in bindings or implementation) +////////////////////////////////////////////////////////////////////////////////////////////////////// + +package main + +import ( + "fmt" +) + +// CreateCPPTypesHeader creates a CPP header file for the types in component's API +func CreateCPPTypesHeader(component ComponentDefinition, CTypesHeaderName string) (error) { + hTypesFile, err := CreateLanguageFile(CTypesHeaderName, " "); + if (err != nil) { + return err; + } + hTypesFile.WriteCLicenseHeader (component, + fmt.Sprintf ("This is an autogenerated C++-Header file with basic types in\norder to allow an easy use of %s", component.LibraryName), + true); + + err = buildCCPPTypesHeader(component, hTypesFile, component.NameSpace, true); + return err; +} + +func getCPPMemberLine(member ComponentDefinitionMember, NameSpace string, arraysuffix string, structName string) (string, error) { + switch (member.Type) { + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double", "bool", "pointer": + typeName, err := getCPPParameterTypeName(member.Type, NameSpace, "") + if (err != nil) { + return "", err + } + return fmt.Sprintf("%s m_%s%s;", typeName, member.Name, arraysuffix), nil + case "enum": + return fmt.Sprintf("e%s m_%s%s;", member.Class, member.Name, arraysuffix), nil + default: + return "", fmt.Errorf ("it is not possible for struct %s to contain a %s member", structName, member.Type); + + } +} + +// CreateCPPAbiHeader creates a CPP header file for the component's API +func CreateCPPAbiHeader(component ComponentDefinition, CHeaderName string) (error) { + hfile, err := CreateLanguageFile(CHeaderName, " "); + if (err != nil) { + return err; + } + hfile.WriteCLicenseHeader (component, + fmt.Sprintf ("This is an autogenerated C++-Header file in order to allow an easy\n use of %s", component.LibraryName), + true); + err = buildCAbiHeader(component, hfile, component.NameSpace, component.BaseName, true); + return err; +} + +func getCPPParameterTypeName(ParamTypeName string, NameSpace string, ParamClass string)(string, error) { + cppParamTypeName := ""; + switch (ParamTypeName) { + case "enum": + cppParamTypeName = fmt.Sprintf ("%s::e%s", NameSpace, ParamClass); + case "struct": + cppParamTypeName = fmt.Sprintf ("%s::s%s *", NameSpace, ParamClass); + case "structarray": + cppParamTypeName = fmt.Sprintf ("%s::s%s *", NameSpace, ParamClass) + case "class": + cppParamTypeName = fmt.Sprintf ("%s_%s", NameSpace, ParamClass) + case "functiontype": + cppParamTypeName = fmt.Sprintf ("%s::%s", NameSpace, ParamClass) + default: + cParamTypeName, err := getCParameterTypeName(ParamTypeName, NameSpace, ParamClass) + if (err != nil) { + return "", err + } + cppParamTypeName = cParamTypeName + } + return cppParamTypeName, nil; +} diff --git a/Source/languagepascal.go b/Source/languagepascal.go index 4571b50b..b031e710 100644 --- a/Source/languagepascal.go +++ b/Source/languagepascal.go @@ -47,9 +47,12 @@ func writePascalBaseTypeDefinitions(componentdefinition ComponentDefinition, w L w.Writeln ("**************************************************************************************************************************)"); w.Writeln (""); w.Writeln ("const"); - w.Writeln (" %s_VERSION_MAJOR = %d;", strings.ToUpper (NameSpace), majorVersion(componentdefinition.Version)); - w.Writeln (" %s_VERSION_MINOR = %d;", strings.ToUpper (NameSpace), minorVersion(componentdefinition.Version)); - w.Writeln (" %s_VERSION_MICRO = %d;", strings.ToUpper (NameSpace), microVersion(componentdefinition.Version)); + w.Writeln (" %s_VERSION_MAJOR = %d;", strings.ToUpper(NameSpace), majorVersion(componentdefinition.Version)); + w.Writeln (" %s_VERSION_MINOR = %d;", strings.ToUpper(NameSpace), minorVersion(componentdefinition.Version)); + w.Writeln (" %s_VERSION_MICRO = %d;", strings.ToUpper(NameSpace), microVersion(componentdefinition.Version)); + w.Writeln (" %s_VERSION_PRERELEASEINFO = '%s';", strings.ToUpper(NameSpace), preReleaseInfo(componentdefinition.Version)); + w.Writeln (" %s_VERSION_BUILDINFO = '%s';", strings.ToUpper(NameSpace), buildInfo(componentdefinition.Version)); + w.Writeln (""); w.Writeln (""); @@ -153,9 +156,11 @@ func writePascalBaseTypeDefinitions(componentdefinition ComponentDefinition, w L w.Writeln ( " F%s: %sSingle;", element.Name, arrayprefix); case "double": w.Writeln ( " F%s: %sDouble;", element.Name, arrayprefix); + case "pointer": + w.Writeln ( " F%s: %sPointer;", element.Name, arrayprefix); case "string": return fmt.Errorf ("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name); - case "handle": + case "class": return fmt.Errorf ("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name); case "enum": w.Writeln ( " F%s: %sInteger;", element.Name, arrayprefix); @@ -251,6 +256,9 @@ func getPascalParameterType(ParamTypeName string, NameSpace string, ParamClass s case "double": PascalParamTypeName = "Double"; + + case "pointer": + PascalParamTypeName = "Pointer"; case "string": if isPlain { @@ -307,7 +315,7 @@ func getPascalParameterType(ParamTypeName string, NameSpace string, ParamClass s } } - case "handle": + case "class": if isPlain { PascalParamTypeName = fmt.Sprintf ("T%sHandle", NameSpace) } else { @@ -371,7 +379,14 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); cParams[0].ParamConvention = "const "; cParams[0].ParamTypeNoConvention = cParams[0].ParamType; - + + case "pointer": + cParams[0].ParamType = cParamTypeName; + cParams[0].ParamName = "p" + param.ParamName; + cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); + cParams[0].ParamConvention = "const "; + cParams[0].ParamTypeNoConvention = cParams[0].ParamType; + case "string": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; @@ -414,7 +429,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri cParams[0].ParamConvention = "const "; cParams[0].ParamTypeNoConvention = cParams[0].ParamType; - case "handle": + case "class": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[in] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -429,7 +444,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "enum": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer", "enum": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -440,7 +455,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); - cParams[0].ParamConvention = "out "; + cParams[0].ParamConvention = ""; cParams[0].ParamTypeNoConvention = "P" + cParamTypeName[1:]; case "basicarray": @@ -503,7 +518,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri cParams[2].ParamConvention = ""; cParams[2].ParamTypeNoConvention = cParams[2].ParamType; - case "handle": + case "class": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -518,7 +533,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri switch (param.ParamType) { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "enum": + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer", "enum": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription); @@ -592,7 +607,7 @@ func generatePlainPascalParameter(param ComponentDefinitionParam, className stri cParams[2].ParamConvention = ""; cParams[2].ParamTypeNoConvention = cParams[2].ParamType; - case "handle": + case "class": cParams[0].ParamType = cParamTypeName; cParams[0].ParamName = "p" + param.ParamName; cParams[0].ParamComment = fmt.Sprintf("* @param[out] %s - %s", cParams[0].ParamName, param.ParamDescription);