Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Regexdispatcher #1944

Merged
merged 40 commits into from
Jun 8, 2018
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
aae608b
haskell-cmake-improvements: add release note
e1528532 May 18, 2018
78fe8ba
haskell-cmake-improvements: adjust the release notes to expected format
e1528532 May 23, 2018
91c2807
typechecker-regex-prototype: improve/finish cmake packaging process, …
e1528532 Apr 19, 2018
0546bd0
typechecker-regex-prototype: improve build process; avoid artifacts i…
e1528532 Apr 23, 2018
2ef3869
typechecker-regex-prototype: require hint 0.7.0 or it fails on stretch
e1528532 Apr 23, 2018
d1c8684
typechecker-regex-prototype: fix/unify sandbox handling
e1528532 Apr 23, 2018
1657d17
regexdispatcher: add first draft of the plugin
e1528532 Apr 26, 2018
3c4f964
regexdispatcher: finish range dispatcher
e1528532 Apr 27, 2018
61e7d66
regexdispatcher: adjust typechecker to dispatched regexes
e1528532 Apr 27, 2018
26aa49a
regexdispatcher: add dispatcher for enum checks
e1528532 Apr 27, 2018
4fb298b
regexdispatcher: add travis test
e1528532 Apr 27, 2018
9c1e001
regexdispatcher: fix compilation on linux
e1528532 Apr 27, 2018
9e72ede
regexdispatcher: reformat cmake
e1528532 May 24, 2018
4bf7de5
regexdispatcher: mount along typechecker
e1528532 May 24, 2018
0583114
regexdispatcher: fix adjusted typechecker example
e1528532 May 24, 2018
58d972a
regexdispatcher: rebase fixies
e1528532 May 25, 2018
fccad52
regexdispatcher: adjust cabal file
e1528532 May 25, 2018
3b241c9
regexdispatcher: prepare for new prelude loading implementation
e1528532 May 25, 2018
3b48a98
regexdispatcher: add invoke bindings for alternative prelude handling
e1528532 May 28, 2018
c33660b
regexdispatcher: prepare typechecker for alternate prelude handling
e1528532 May 28, 2018
1ff9e34
regexdispatcher: use invoke now for prelude loading to avoid kdbOpen …
e1528532 May 28, 2018
6130545
regexdispatcher: bindings are implicitly included with new cmake system
e1528532 May 28, 2018
53e1f4a
regexdispatcher: greatly improve plugin data plumbing to avoid messin…
e1528532 May 29, 2018
0cb37dd
regexdispatcher: invoke in open/close, store plugin data
e1528532 May 29, 2018
2eac7e4
regexdispatcher: fix type signature in prelude
e1528532 May 29, 2018
00c6af9
regexdispatcher: update release notes
e1528532 May 29, 2018
66c6de3
regexdispatcher: adjust ifKey and whenKey syntax to how its normally …
e1528532 May 29, 2018
4d93782
regexdispatcher: add validation support
e1528532 May 29, 2018
5e39fda
regexdispatcher: correct order & minimize inversion results
e1528532 May 29, 2018
2bbf2c2
regexdispatcher: small simplification
e1528532 May 29, 2018
f9ce3e0
regexdispatcher: adjust rebase issue
e1528532 May 29, 2018
98b38fd
regexdispatcher: add validation example to typechecker
e1528532 May 29, 2018
efa7502
regexdispatcher: remove ununsed function
e1528532 May 30, 2018
0dd7dca
regexdispatcher: use raw pointers directly, figure out segfaults
e1528532 May 30, 2018
96be930
regexdispatcher: fix plugin data handling in combination with pluginp…
e1528532 Jun 4, 2018
176a63a
regexdispatcher: correct case of file
e1528532 Jun 4, 2018
9bee5b1
regexdispatcher: fix case #2
e1528532 Jun 5, 2018
8c05f4a
regexdispatcher: resolve the review comments
e1528532 Jun 5, 2018
0f75668
regexdispatcher: use check/validation metakey for generated regexes
e1528532 Jun 6, 2018
e589848
regexdispatcher: add usedby to check/validation metadata
e1528532 Jun 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ before_script:
- |
if [[ $HASKELL == ON ]]; then
bindings="haskell"
plugins="resolver_fm_hpu_b;dump;dini;list;spec;haskell;typechecker;ini;sync;error;base64"
plugins="resolver_fm_hpu_b;dump;dini;list;spec;haskell;typechecker;ini;sync;error;base64;regexdispatcher"
tools="kdb"
fi
- |
Expand Down
24 changes: 17 additions & 7 deletions cmake/Modules/LibAddHaskellPlugin.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ macro (add_haskell_plugin target)

set (PLUGIN_NAME ${target})
set (PLUGIN_NAME_CAPITALIZED ${target})
string (SUBSTRING ${PLUGIN_NAME} 0 1 FIRST_LETTER)
string (TOUPPER ${FIRST_LETTER} FIRST_LETTER)
string (REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1" PLUGIN_NAME_CAPITALIZED "${PLUGIN_NAME}")
string (TOUPPER ${PLUGIN_NAME} PLUGIN_NAME_UPPERCASE)
if (ARG_MODULE)
set (PLUGIN_NAME_CAPITALIZED ${ARG_MODULE})
else (ARG_MODULE)
string (SUBSTRING ${PLUGIN_NAME} 0 1 FIRST_LETTER)
string (TOUPPER ${FIRST_LETTER} FIRST_LETTER)
string (REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1" PLUGIN_NAME_CAPITALIZED "${PLUGIN_NAME}")
endif (ARG_MODULE)

if (DEPENDENCY_PHASE)
find_package (Haskell)
Expand Down Expand Up @@ -180,9 +183,16 @@ macro (add_haskell_plugin target)
# our custom libs are all to be processed by cmake before we
# can add them, so enforce that, the build is more stable
# this way
add_subdirectory (
"${CMAKE_SOURCE_DIR}/${SANDBOX_ADD_SOURCE}"
"${CMAKE_BINARY_DIR}/${SANDBOX_ADD_SOURCE}")
if (NOT
IS_DIRECTORY
"${CMAKE_BINARY_DIR}/${SANDBOX_ADD_SOURCE}")
add_subdirectory (
"${CMAKE_SOURCE_DIR}/${SANDBOX_ADD_SOURCE}"
"${CMAKE_BINARY_DIR}/${SANDBOX_ADD_SOURCE}"
)
endif (NOT
IS_DIRECTORY
"${CMAKE_BINARY_DIR}/${SANDBOX_ADD_SOURCE}")
execute_process (
COMMAND
${CABAL_EXECUTABLE} sandbox
Expand Down
18 changes: 14 additions & 4 deletions doc/METADATA.ini
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ description= defines the max value type of the integer value

[check/range]
status= implemented
usedby/plugin= range
usedby/plugin= range regexdispatcher
usedby/tool = web
description= range checks, from-to, multiple ranges are separated by a comma
example= 1-10 or -1-4,6-10
Expand Down Expand Up @@ -596,21 +596,21 @@ description= type of match, to toggle REG_EXTENDED

[check/enum]
status=deprecated
usedby/plugin=enum
usedby/plugin= enum
description= List of apostrophe enclosed values separated by
commas to check against.
Please use check/enum/# instead.

[check/enum/#]
status= implemented
usedby/plugin=enum
usedby/plugin= enum regexdispatcher
usedby/tool = web
description= An array with different enum values to be used
instead of check/enum

[check/enum/multi]
status= implemented
usedby/plugin=enum
usedby/plugin= enum regexdispatcher
type= char
description= Specifies if multiple, but different, strings are allowed
within an value. The character given within this metavalue
Expand Down Expand Up @@ -905,3 +905,13 @@ default = dec
usedby/plugins = hexnumber
description = used to specify the base of an integer value. Currently only the hexnumber plugin supports this metadata. It converts any value marked as "hex" from
hexadecimal into decimal when the configuration is read, and back when it is written. The hexnumber plugin also ensures that a value marked as "hex" starts with "0x" or "0X".

[elektra/spec/regex/check/enum]
type = string
usedby/plugins = regexdispatcher
description = the generated regex representing the type of check/enum/# and check/enum/multi metakeys

[elektra/spec/regex/check/range]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts about the metadata name:

  • the elektra prefix does not give information, all meta data is for and from Elektra.
  • it should also not start with spec (do not be confused with the namespace).

And wouldn't it be better that we only have a single metadata and the regex is always merged together? Do you need the information of where the regex comes from?

What was the idea of giving this name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right. as the regexdispatcher does all the preprocessing this essentially yields a check/validation keyword in the end all the time, so in that case i don't need further information where it came from i think. i will try that idea out.

type = string
usedby/plugins = regexdispatcher
description = the generated regex representing the type of check/range metakeys
11 changes: 6 additions & 5 deletions doc/news/_preparation_next_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ set of type definitions for commonly used metakeys such as `check/range`,
`check/long`, `fallback` or `override`.

For more details see the
[typechecker readme](https://github.com/ElektraInitiative/libelektra/tree/master/src/plugins/typechecker/README.md)
[typechecker readme](https://www.libelektra.org/plugins/typechecker)

Thanks to Armin Wurzinger.

Expand Down Expand Up @@ -87,16 +87,17 @@ We added even more functionality, which could not make it to the highlights:
- The build system no longer installs haskell dependencies from hackage by itself, instead
this has to be done beforehand like it is the case with all other dependencies. The main
reason is that the build servers shouldn't compile the dependencies over and over again,
only if something changes. See the [readme](https://github.com/ElektraInitiative/libelektra/blob/master/src/bindings/haskell/README.md). *(Armin Wurzinger)*
- <<TODO>>
- <<TODO>>
only if something changes. See the [readme](https://www.libelektra.org/bindings/haskell). *(Armin Wurzinger)*
- The new tool `kdb find` lists keys of the database matching a certain regular expression. *(Markus Raab)*
- <<TODO>>

## New Plugins

- The plugin [hexnumber](https://www.libelektra.org/plugins/hexnumber) has been added. It can be used
to convert hexadecimal values into decimal when read, and back to hexadecimal when written. *(Klemens Böswirth)*
- <<TODO>>
- The plugin [regexdispatcher](https://www.libelektra.org/plugins/regexdispatcher) has been added. It calculates regex representations for commonly used specification
keywords to be used with the [typechecker](https://www.libelektra.org/plugins/typechecker). Currently the
keywords `check/range`, `check/enum` and `check/validation` are supported. *(Armin Wurzinger)*
- <<TODO>>


Expand Down
1 change: 1 addition & 0 deletions src/bindings/haskell/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ if (HASKELL_FOUND)
"${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Plugin.chs"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/KDB.chs"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Ease.chs"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Elektra/Invoke.chs"
"${CMAKE_CURRENT_SOURCE_DIR}/test/Elektra.hs"
"${CMAKE_CURRENT_SOURCE_DIR}/test/ElektraRealWorld.hs"
"${CMAKE_CURRENT_SOURCE_DIR}/src/c/hskdberrors.c"
Expand Down
4 changes: 4 additions & 0 deletions src/bindings/haskell/libelektra-haskell.cabal.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ library
, Elektra.Plugin
, Elektra.Ease
, Elektra.Errors
, Elektra.Invoke
, Elektra.PluginProcess
build-depends: base >= 4.9 && < 4.12
includes: kdb.h
, kdbplugin.h
, kdbease.h
, kdbinvoke.h
, kdberrors.h
, hskdberrors.h
, kdbpluginprocess.h
include-dirs: @CABAL_INCLUDE_DIRS@
, "@CMAKE_CURRENT_SOURCE_DIR@/src/include"
c-sources: "@CMAKE_CURRENT_BINARY_DIR@/src/c/hskdberrors.c"
Expand Down
62 changes: 62 additions & 0 deletions src/bindings/haskell/src/Elektra/Invoke.chs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--
-- @file
--
-- @brief Haskell bindings for libelektra-invoke
--
-- @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
--
module Elektra.Invoke (
InvokeFunction,
elektraInvokeOpen, elektraInvokeGetFunction,
elektraInvokeGetPluginConfig, elektraInvokeGetPluginName, elektraInvokeGetPluginData, elektraInvokeGetModules,
elektraInvokeGetExports, elektraInvoke2Args, elektraInvokeClose,
ifHandle
) where

{#import Elektra.Key #}
{#import Elektra.KeySet #}
{#import Elektra.Plugin #}

import Data.Maybe (maybe)
import Foreign.Ptr (Ptr, castPtr, nullPtr)
import Foreign.ForeignPtr (withForeignPtr, newForeignPtr_)

#include <kdbinvoke.h>

{#pointer *ElektraInvokeHandle newtype #}
type InvokeFunction = Ptr ()

-- Handles are already pointers, so just cast them from/to void pointers
instance PluginData ElektraInvokeHandle where
store a (ElektraInvokeHandle p) = a $ castPtr p
retrieve p = if p == nullPtr then Nothing else (Just . ElektraInvokeHandle $ castPtr p)

ifHandle :: IO a -> (ElektraInvokeHandle -> IO a) -> ElektraInvokeHandle -> IO a
ifHandle f t h@(ElektraInvokeHandle p) = if p == nullPtr then f else t h

-- ***
-- Invoke METHODS
-- ***

elektraInvokeOpen :: String -> Maybe KeySet -> Maybe Key -> IO ElektraInvokeHandle
elektraInvokeOpen elektraPluginName config errorKey = do
c <- maybe (ksNew 0) return config
e <- maybe (keyNew "") return errorKey
elektraInvokeOpenRaw elektraPluginName c e
{#fun unsafe elektraInvokeOpen as elektraInvokeOpenRaw {`String', `KeySet', `Key'} -> `ElektraInvokeHandle' #}

{#fun unsafe elektraInvokeGetFunction {`ElektraInvokeHandle', `String'} -> `InvokeFunction' return* #}
{#fun unsafe elektraInvokeGetPluginConfig {`ElektraInvokeHandle'} -> `KeySet' #}
{#fun unsafe elektraInvokeGetPluginName {`ElektraInvokeHandle'} -> `String' #}
elektraInvokeGetPluginData :: PluginData d => ElektraInvokeHandle -> IO (Maybe d)
elektraInvokeGetPluginData h = retrieve <$> elektraInvokeGetPluginDataRaw h
{#fun unsafe elektraInvokeGetPluginData as elektraInvokeGetPluginDataRaw {`ElektraInvokeHandle'} -> `Ptr ()' return* #}
{#fun unsafe elektraInvokeGetModules {`ElektraInvokeHandle'} -> `KeySet' #}
{#fun unsafe elektraInvokeGetExports {`ElektraInvokeHandle'} -> `KeySet' #}
{#fun unsafe elektraInvoke2Args {`ElektraInvokeHandle', `String', `KeySet', `Key'} -> `Int' #}

elektraInvokeClose :: ElektraInvokeHandle -> Maybe Key -> IO ()
elektraInvokeClose handle errorKey = do
e <- maybe (keyNew "") return errorKey
elektraInvokeCloseRaw handle e
{#fun unsafe elektraInvokeClose as elektraInvokeCloseRaw {`ElektraInvokeHandle',`Key'} -> `()' #}
14 changes: 7 additions & 7 deletions src/bindings/haskell/src/Elektra/Key.chs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module Elektra.Key (
keyCmp, keyNeedSync,
keyIsBelow, keyIsDirectBelow,
keyRel, keyIsInactive, keyIsBinary, keyIsString, keyPtrNull,
ifKey, withKey,
ifKey, withKey, whenKey,
tmpRef
) where

Expand All @@ -32,7 +32,7 @@ import Foreign.ForeignPtr (FinalizerPtr (..), withForeignPtr, addForeignPtrFinal
import System.IO.Unsafe (unsafePerformIO)
import Data.Maybe (isJust, fromJust)
import Control.Monad (liftM)
import Debug.Trace
import Data.Bool (bool)

{#context lib="libelektra" #}

Expand Down Expand Up @@ -190,14 +190,14 @@ instance Eq Key where
-- ADDITIONAL HELPERS USEFUL IN HASKELL
-- ***

--Key (C2HSImp.ForeignPtr (Key))
addFinalizer :: Key -> IO Key
addFinalizer (Key a) = addForeignPtrFinalizer keyDel a >> return (Key a)

ifKey :: IO Key -> (Key -> IO a) -> IO a -> IO a
ifKey k t f = do
null <- k >>= keyPtrNull
if null then f else k >>= t
ifKey :: IO a -> (Key -> IO a) -> Key -> IO a
ifKey f t k = keyPtrNull k >>= bool (t k) f

whenKey :: (Key -> IO ()) -> Key -> IO ()
whenKey w k = ifKey (return ()) w k

-- Temporarily increases the reference counter so e.g. a keyset will not take ownership so
-- Haskell's finalizer can run successfully afterwards
Expand Down
21 changes: 17 additions & 4 deletions src/bindings/haskell/src/Elektra/Plugin.chs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-- @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
--
module Elektra.Plugin (
Plugin, PluginStatus (..),
Plugin, withPlugin, PluginStatus (..), PluginData (..),
elektraPluginGetConfig,
elektraPluginSetData, elektraPluginGetData,
elektraPluginOpenWith, elektraPluginCloseWith,
Expand All @@ -16,6 +16,7 @@ module Elektra.Plugin (

{#import Elektra.Key#}
{#import Elektra.KeySet#}

import Foreign.Ptr (Ptr)
import Foreign.ForeignPtr (newForeignPtr_)
import Control.Monad (join, liftM, liftM2, liftM3)
Expand Down Expand Up @@ -44,9 +45,21 @@ instance Enum PluginStatus where
-- ***

{#fun unsafe elektraPluginGetConfig {`Plugin'} -> `KeySet' #}
-- You have to cast it using Foreign.Ptr.castPtr to the data structure you use manually
{#fun unsafe elektraPluginSetData {`Plugin', `Ptr ()'} -> `()' #}
{#fun unsafe elektraPluginGetData {`Plugin'} -> `Ptr ()' #}

-- This is already implemented for invoke handles
-- If you want to use other data structures you have to provide an instance of PluginData yourself
-- This way we can hide the ugly casting to c's void pointer
class PluginData d where
store :: (Ptr () -> IO ()) -> d -> IO ()
retrieve :: Ptr () -> Maybe d

elektraPluginSetData :: PluginData d => Plugin -> d -> IO ()
elektraPluginSetData p = store (elektraPluginSetDataRaw p)
{#fun unsafe elektraPluginSetData as elektraPluginSetDataRaw {`Plugin', `Ptr ()'} -> `()' #}

elektraPluginGetData :: PluginData d => Plugin -> IO (Maybe d)
elektraPluginGetData p = retrieve <$> elektraPluginGetDataRaw p
{#fun unsafe elektraPluginGetData as elektraPluginGetDataRaw {`Plugin'} -> `Ptr ()' #}

-- ***
-- PLUGIN STUB METHODS
Expand Down
30 changes: 30 additions & 0 deletions src/bindings/haskell/src/Elektra/PluginProcess.chs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--
-- @file
--
-- @brief PluginProcess Haskell bindings
--
-- @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
--
module Elektra.PluginProcess (
elektraPluginProcessGetData,
elektraPluginProcessSetData
) where

{#import Elektra.Plugin#}
{#import Elektra.Invoke#}

import Foreign.Ptr (Ptr)

#include <kdbpluginprocess.h>

-- ***
-- PLUGINPROCESS METHODS
-- ***

elektraPluginProcessSetData :: PluginData d => Plugin -> d -> IO ()
elektraPluginProcessSetData p = store (elektraPluginProcessSetDataRaw p)
{#fun unsafe elektraPluginProcessSetData as elektraPluginProcessSetDataRaw {`Plugin', `Ptr ()'} -> `()' #}

elektraPluginProcessGetData :: PluginData d => Plugin -> IO (Maybe d)
elektraPluginProcessGetData p = retrieve <$> elektraPluginProcessGetDataRaw p
{#fun unsafe elektraPluginProcessGetData as elektraPluginProcessGetDataRaw {`Plugin'} -> `Ptr ()' #}
3 changes: 3 additions & 0 deletions src/include/kdbpluginprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ int elektraPluginProcessSend (const ElektraPluginProcess *, pluginprocess_t, Key

int elektraPluginProcessClose (ElektraPluginProcess *, Key *);

void elektraPluginProcessSetData (Plugin * handle, void * data);
void * elektraPluginProcessGetData (Plugin * handle);

#ifdef __cplusplus
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/libs/pluginprocess/pluginprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct _ElektraPluginProcess
int pid;
int counter;
ElektraInvokeHandle * dump;
void * pluginData;
};

static void cleanupPluginData (ElektraPluginProcess * pp, Key * errorKey)
Expand Down Expand Up @@ -333,6 +334,7 @@ ElektraPluginProcess * elektraPluginProcessInit (Key * errorKey)
pp->resultPipe = getPipename (pp->pipeDirectory, "/result");
pp->dump = elektraInvokeOpen ("dump", 0, errorKey);
pp->counter = 0;
pp->pluginData = NULL;

if (pp->pipeDirectory && pp->commandPipe && pp->resultPipe && pp->dump)
{
Expand Down Expand Up @@ -401,3 +403,34 @@ int elektraPluginProcessClose (ElektraPluginProcess * pp, Key * errorKey)
if (done) cleanupPluginData (pp, errorKey);
return done;
}

/** Store a pointer to any plugin related data that is being executed inside an own process.
*
* @param plugin a pointer to the plugin
* @param data the pointer to the data
*/
void elektraPluginProcessSetData (Plugin * handle, void * data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this serialized and sent to the other process?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not, the proxied plugins just run in the child process and on linux it seems to share the memory between the parent and the child process. Thus if the child sets any plugin data directly, this would override the plugin data of the parent process, causing the pluginprocess library to fail.
Therefore i store it inside the pluginprocess data structure on the children's side to avoid this problem.

{
ElektraPluginProcess * pp = elektraPluginGetData (handle);
if (pp)
{
pp->pluginData = data;
}
}

/** Get a pointer to any plugin related data stored before.
*
* If elektraPluginProcessSetData was not called earlier, NULL will be returned.
*
* @param plugin a pointer to the plugin
* @retval a pointer to the data
*/
void * elektraPluginProcessGetData (Plugin * handle)
{
ElektraPluginProcess * pp = elektraPluginGetData (handle);
if (pp)
{
return pp->pluginData;
}
return NULL;
}
Loading