Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for haskell plugin
5 : *
6 : * Gets configured by cmake as this is the base file for other haskell plugins.
7 : * See the cmake macro add_haskell_plugin for details.
8 : *
9 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
10 : */
11 :
12 : #include "Typechecker_stub.h"
13 : #include "haskell.h"
14 :
15 : #include <kdbhelper.h>
16 : #include <kdbpluginprocess.h>
17 : #include <stdio.h>
18 :
19 49 : int elektraHaskellOpen (Plugin * handle, Key * errorKey)
20 : {
21 49 : ElektraPluginProcess * pp = elektraPluginGetData (handle);
22 49 : if (pp == NULL)
23 : {
24 49 : if ((pp = elektraPluginProcessInit (errorKey)) == NULL) return ELEKTRA_PLUGIN_STATUS_ERROR;
25 49 : elektraPluginSetData (handle, pp);
26 49 : if (!elektraPluginProcessIsParent (pp)) elektraPluginProcessStart (handle, pp);
27 : }
28 49 : if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessOpen (pp, errorKey);
29 :
30 0 : char *argv[] = { "typechecker", 0 }, **argvPtr = argv;
31 0 : int argc = 1;
32 : // Startup the haskell runtime with some dummy args
33 : // Subsequent init calls are ignored by the runtime
34 0 : hs_init (&argc, &argvPtr);
35 0 : return hs_elektraHaskellOpen (handle, errorKey);
36 : }
37 :
38 49 : int elektraHaskellClose (Plugin * handle, Key * errorKey)
39 : {
40 49 : ElektraPluginProcess * pp = elektraPluginGetData (handle);
41 49 : if (elektraPluginProcessIsParent (pp))
42 : {
43 49 : ElektraPluginProcessCloseResult result = elektraPluginProcessClose (pp, errorKey);
44 49 : if (result.cleanedUp) elektraPluginSetData (handle, NULL);
45 49 : return result.result;
46 : }
47 :
48 0 : int ret = hs_elektraHaskellClose (handle, errorKey);
49 : // Shutdown the haskell runtime
50 : // Due to an unfortunate bug within GHC's ffi implementation we cannot
51 : // restart the runtime if it got closed once during elektra's runtime
52 : // in the same process.
53 : // Therefore we use the plugin process library to launch the runtime
54 : // in a separate process.
55 : // https://downloads.haskell.org/~ghc/8.2.2/docs/html/users_guide/bugs.html#infelicities-ffi
56 0 : hs_exit ();
57 0 : return ret;
58 : }
59 :
60 33 : int elektraHaskellGet (Plugin * handle, KeySet * returned, Key * parentKey)
61 : {
62 33 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/typechecker"))
63 : {
64 31 : KeySet * contract = ksNew (
65 : 30,
66 : keyNew ("system/elektra/modules/typechecker", KEY_VALUE, "typechecker plugin waits for your orders", KEY_END),
67 : keyNew ("system/elektra/modules/typechecker/exports", KEY_END),
68 : keyNew ("system/elektra/modules/typechecker/exports/open", KEY_FUNC, elektraHaskellOpen, KEY_END),
69 : keyNew ("system/elektra/modules/typechecker/exports/close", KEY_FUNC, elektraHaskellClose, KEY_END),
70 : keyNew ("system/elektra/modules/typechecker/exports/get", KEY_FUNC, elektraHaskellGet, KEY_END),
71 : keyNew ("system/elektra/modules/typechecker/exports/set", KEY_FUNC, elektraHaskellSet, KEY_END),
72 : keyNew ("system/elektra/modules/typechecker/exports/error", KEY_FUNC, elektraHaskellError, KEY_END),
73 : // clang-format off
74 : #include ELEKTRA_README
75 : // clang-format on
76 : keyNew ("system/elektra/modules/typechecker/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
77 31 : ksAppend (returned, contract);
78 31 : ksDel (contract);
79 :
80 31 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
81 : }
82 :
83 2 : ElektraPluginProcess * pp = elektraPluginGetData (handle);
84 2 : if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_GET, returned, parentKey);
85 :
86 0 : return hs_elektraHaskellGet (handle, returned, parentKey);
87 : }
88 :
89 4 : int elektraHaskellSet (Plugin * handle, KeySet * returned, Key * parentKey)
90 : {
91 4 : ElektraPluginProcess * pp = elektraPluginGetData (handle);
92 4 : if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_SET, returned, parentKey);
93 :
94 0 : return hs_elektraHaskellSet (handle, returned, parentKey);
95 : }
96 :
97 0 : int elektraHaskellError (Plugin * handle, KeySet * returned, Key * parentKey)
98 : {
99 0 : ElektraPluginProcess * pp = elektraPluginGetData (handle);
100 0 : if (elektraPluginProcessIsParent (pp)) return elektraPluginProcessSend (pp, ELEKTRA_PLUGINPROCESS_ERROR, returned, parentKey);
101 :
102 0 : return hs_elektraHaskellError (handle, returned, parentKey);
103 : }
104 :
105 : // clang-format off
106 49 : Plugin * ELEKTRA_PLUGIN_EXPORT
107 : {
108 49 : return elektraPluginExport ("typechecker",
109 : ELEKTRA_PLUGIN_OPEN, &elektraHaskellOpen,
110 : ELEKTRA_PLUGIN_CLOSE, &elektraHaskellClose,
111 : ELEKTRA_PLUGIN_GET, &elektraHaskellGet,
112 : ELEKTRA_PLUGIN_SET, &elektraHaskellSet,
113 : ELEKTRA_PLUGIN_ERROR, &elektraHaskellError,
114 : ELEKTRA_PLUGIN_END);
115 : }
|