1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <vdb/extern.h>
28
29 #include "linker-priv.h"
30 #include "schema-parse.h"
31 #include "xform-priv.h"
32
33 #include <kfs/dyload.h>
34 #include <klib/token.h>
35 #include <klib/symtab.h>
36 #include <klib/symbol.h>
37 #include <klib/out.h>
38 #include <klib/rc.h>
39 #include <sysalloc.h>
40
41 #include <kfg/config.h>
42
43 #include <stdlib.h>
44 #include <string.h>
45 #include <byteswap.h>
46 #include <assert.h>
47
48 #include "transform-functions.h"
49
50 /* these functions need something to fill in VFuncDesc */
51 static
fake_stub_func(void * self,const VXformInfo * info,int64_t row_id,VRowResult * rslt,uint32_t argc,const VRowData argv[])52 rc_t CC fake_stub_func ( void *self, const VXformInfo *info, int64_t row_id,
53 VRowResult *rslt, uint32_t argc, const VRowData argv [] )
54 {
55 assert(!"THIS FUNCTION IS NEVER TO BE CALLED");
56 abort();
57 return 0;
58 }
59
60 /* select is REALLY internal */
61 VTRANSFACT_BUILTIN_IMPL ( vdb_select, 1, 0, 0 ) ( const void *self,
62 const VXfactInfo *info, VFuncDesc *rslt, const VFactoryParams *cp, const VFunctionParams *dp )
63 {
64 /* set function pointer to non-NULL */
65 rslt -> u . rf = fake_stub_func;
66 rslt -> variant = vftSelect;
67 return 0;
68 }
69
70 #if THIS_IS_A_STUB_FOR_COPYPASTA
71 /*
72 function < type T >
73 T passthru #1.0 ( T target )
74 = vdb:stub:function;
75 */
76 /* all pass-through functions are REALLY internal */
77 VTRANSFACT_BUILTIN_IMPL ( vdb_stub_function, 1, 0, 0 ) ( const void *self,
78 const VXfactInfo *info, VFuncDesc *rslt, const VFactoryParams *cp, const VFunctionParams *dp )
79 {
80 bool shouldPassThru = false;
81
82 /* pass-through functions MUST have exactly one argument */
83 assert(dp->argc == 1);
84
85 /* This is where to implement logic to determine if pass-through is wanted
86 */
87
88 /* from here to the end of the function stays the same */
89 if (shouldPassThru) {
90 /* set function pointer to non-NULL */
91 rslt -> u . rf = fake_stub_func;
92
93 /* this is the magic that causes VFunctionProdRead to pass the Read
94 * message on to the first argument of this function */
95 rslt -> variant = vftPassThrough;
96 return 0;
97 }
98
99 /* some non-zero RC to signal that pass-through is NOT supposed to happen
100 * this will cause the schema to fall-through to the next rule or fail the
101 * production
102 */
103 return SILENT_RC(rcVDB, rcFunction, rcConstructing, rcFunction, rcIgnored);
104 }
105 #endif
106
107 /* Pass-through function constructors should use this to prepare the result */
maybePass(bool const shouldPass,VFuncDesc * const rslt)108 static rc_t maybePass(bool const shouldPass, VFuncDesc *const rslt)
109 {
110 if (shouldPass) {
111 rslt -> u . rf = fake_stub_func;
112 rslt -> variant = vftPassThrough;
113 return 0;
114 }
115 return SILENT_RC(rcVDB, rcFunction, rcConstructing, rcFunction, rcIgnored);
116 }
117
118 /* This function ALWAYS passes through
119 function < type T >
120 T passthru #1.0 ( T target )
121 = vdb:passthru;
122 */
123 /* all pass-through functions are REALLY internal */
124 VTRANSFACT_BUILTIN_IMPL ( vdb_passthru, 1, 0, 0 ) ( const void *self,
125 const VXfactInfo *info, VFuncDesc *rslt, const VFactoryParams *cp, const VFunctionParams *dp )
126 {
127 return maybePass(true, rslt);
128 }
129
compare_node_value(KConfigNode const * node,unsigned const len,char const * const value)130 static bool compare_node_value(KConfigNode const *node, unsigned const len, char const *const value)
131 {
132 char buffer[4096];
133 size_t num_read = 0, remaining = 0, offset = 0;
134
135 do {
136 KConfigNodeRead(node, offset, buffer, sizeof(buffer), &num_read, &remaining);
137 if (offset + num_read + remaining != len)
138 return false;
139 assert(offset + num_read <= len);
140 if (memcmp(buffer, value + offset, num_read) != 0)
141 return false;
142 offset += num_read;
143 } while (num_read > 0 && remaining > 0);
144 return offset == len;
145 }
146
check_config_node(VFactoryParams const * const name_value)147 static bool check_config_node(VFactoryParams const * const name_value)
148 {
149 rc_t rc = 0;
150 bool result = false;
151 assert(name_value->argc == 2);
152 {
153 KConfig *cfg;
154 rc = KConfigMake(&cfg, NULL);
155 if (rc == 0) {
156 KConfigNode const *node;
157 rc = KConfigOpenNodeRead(cfg, &node, "%.*s"
158 , (int)name_value->argv[0].count
159 , name_value->argv[0].data.ascii);
160 if (rc == 0) {
161 result = compare_node_value(node
162 , name_value->argv[1].count
163 , name_value->argv[1].data.ascii);
164 KConfigNodeRelease(node);
165 }
166 KConfigRelease(cfg);
167 }
168 }
169 return result;
170 }
171
172 /*
173 function < type T >
174 T is_configuration_set #1.0 < ascii node, ascii value > ( T target )
175 = vdb:is_configuration_set;
176 */
177 /* all pass-through functions are REALLY internal */
178 VTRANSFACT_BUILTIN_IMPL ( vdb_is_configuration_set, 1, 0, 0 ) ( const void *self,
179 const VXfactInfo *info, VFuncDesc *rslt, const VFactoryParams *cp, const VFunctionParams *dp )
180 {
181 return maybePass(check_config_node(cp), rslt);
182 }
183
184 /* temporary silly stuff
185 */
186
187 static
hello_func(void * self,const VXformInfo * info,int64_t row_id,VRowResult * rslt,uint32_t argc,const VRowData argv[])188 rc_t CC hello_func ( void *self, const VXformInfo *info, int64_t row_id,
189 VRowResult *rslt, uint32_t argc, const VRowData argv [] )
190 {
191 char *func_hello = self;
192 OUTMSG (( "%s - row id %ld\n", func_hello, row_id ));
193 return 0;
194 }
195
196 VTRANSFACT_BUILTIN_IMPL ( vdb_hello, 1, 0, 0 ) ( const void *self,
197 const VXfactInfo *info, VFuncDesc *rslt, const VFactoryParams *cp, const VFunctionParams *dp )
198 {
199 const char *fact_hello = "vdb:hello factory";
200 const char *func_hello = "vdb:hello function";
201
202 if ( cp -> argc > 0 )
203 {
204 fact_hello = cp -> argv [ 0 ] . data . ascii;
205 if ( cp -> argc > 1 )
206 func_hello = cp -> argv [ 1 ] . data . ascii;
207 }
208
209 rslt -> self = malloc ( strlen ( func_hello ) + 1 );
210 if ( rslt -> self == NULL )
211 return RC ( rcVDB, rcFunction, rcConstructing, rcMemory, rcExhausted );
212 strcpy ( rslt -> self, func_hello );
213 rslt -> whack = free;
214 rslt -> u . rf = hello_func;
215 rslt -> variant = vftRow;
216
217 OUTMSG (( "%s - %u factory params, %u function params\n", fact_hello, cp -> argc, dp -> argc ));
218 return 0;
219 }
220
221 /* InitFactories
222 */
223 static
VLinkerEnterFactory(KSymTable * tbl,const SchemaEnv * env,LFactory * lfact,const char * name)224 rc_t CC VLinkerEnterFactory ( KSymTable *tbl, const SchemaEnv *env,
225 LFactory *lfact, const char *name )
226 {
227 rc_t rc;
228
229 KTokenSource src;
230 KTokenText tt;
231 KToken t;
232
233 KTokenTextInitCString ( & tt, name, "VLinkerEnterFactory" );
234 KTokenSourceInit ( & src, & tt );
235 next_token ( tbl, & src, & t );
236
237 rc = create_fqn ( tbl, & src, & t, env, ltFactory, lfact );
238 if ( rc == 0 )
239 lfact -> name = t . sym;
240
241 return rc;
242 }
243
244
VLinkerAddFactories(VLinker * self,const VLinkerIntFactory * fact,uint32_t count,KSymTable * tbl,const SchemaEnv * env)245 rc_t VLinkerAddFactories ( VLinker *self,
246 const VLinkerIntFactory *fact, uint32_t count,
247 KSymTable *tbl, const SchemaEnv *env )
248 {
249 uint32_t i;
250 for ( i = 0; i < count; ++ i )
251 {
252 rc_t rc;
253 LFactory *lfact = malloc ( sizeof * lfact );
254 if ( lfact == NULL )
255 return RC ( rcVDB, rcFunction, rcRegistering, rcMemory, rcExhausted );
256
257 /* invoke factory to get description */
258 rc = ( * fact [ i ] . f ) ( & lfact -> desc );
259 if ( rc != 0 )
260 {
261 free ( lfact );
262 return rc;
263 }
264
265 /* I am intrinsic and have no dl symbol */
266 lfact -> addr = NULL;
267 lfact -> name = NULL;
268 lfact -> external = false;
269
270 /* add to linker */
271 rc = VectorAppend ( & self -> fact, & lfact -> id, lfact );
272 if ( rc != 0 )
273 {
274 LFactoryWhack ( lfact, NULL );
275 return rc;
276 }
277
278 /* create name */
279 rc = VLinkerEnterFactory ( tbl, env, lfact, fact [ i ] . name );
280 if ( rc != 0 )
281 {
282 void *ignore;
283 VectorSwap ( & self -> fact, lfact -> id, NULL, & ignore );
284 LFactoryWhack ( lfact, NULL );
285 return rc;
286 }
287 }
288
289 return 0;
290 }
291
292
293 static
VLinkerEnterSpecial(KSymTable * tbl,const SchemaEnv * env,LSpecial * lspec,const char * name)294 rc_t CC VLinkerEnterSpecial ( KSymTable *tbl, const SchemaEnv *env,
295 LSpecial *lspec, const char *name )
296 {
297 rc_t rc;
298
299 KTokenSource src;
300 KTokenText tt;
301 KToken t;
302
303 KTokenTextInitCString ( & tt, name, "VLinkerEnterSpecial" );
304 KTokenSourceInit ( & src, & tt );
305 next_token ( tbl, & src, & t );
306
307 rc = create_fqn ( tbl, & src, & t, env, ltUntyped, lspec );
308 if ( rc == 0 )
309 lspec -> name = t . sym;
310
311 return rc;
312 }
313
314 static
VLinkerAddUntyped(VLinker * self,const VLinkerIntSpecial * special,uint32_t count,KSymTable * tbl,const SchemaEnv * env)315 rc_t VLinkerAddUntyped ( VLinker *self,
316 const VLinkerIntSpecial *special, uint32_t count,
317 KSymTable *tbl, const SchemaEnv *env )
318 {
319 uint32_t i;
320 for ( i = 0; i < count; ++ i )
321 {
322 rc_t rc;
323 LSpecial *lspec = malloc ( sizeof * lspec );
324 if ( lspec == NULL )
325 return RC ( rcVDB, rcFunction, rcRegistering, rcMemory, rcExhausted );
326
327 /* I am intrinsic and have no dl symbol */
328 lspec -> addr = NULL;
329 lspec -> name = NULL;
330 lspec -> func = special [ i ] . f;
331
332 /* add to linker */
333 rc = VectorAppend ( & self -> special, & lspec -> id, lspec );
334 if ( rc != 0 )
335 {
336 LSpecialWhack ( lspec, NULL );
337 return rc;
338 }
339
340 /* create name */
341 rc = VLinkerEnterSpecial ( tbl, env, lspec, special [ i ] . name );
342 if ( rc != 0 )
343 {
344 void *ignore;
345 VectorSwap ( & self -> special, lspec -> id, NULL, & ignore );
346 LSpecialWhack ( lspec, NULL );
347 return rc;
348 }
349 }
350
351 return 0;
352 }
353
354 /* InitFactories
355 */
VLinkerInitFactoriesRead(VLinker * self,KSymTable * tbl,const SchemaEnv * env)356 rc_t VLinkerInitFactoriesRead ( VLinker *self, KSymTable *tbl, const SchemaEnv *env )
357 {
358 rc_t rc = VLinkerAddFactories ( self, fact, sizeof fact / sizeof fact [ 0 ], tbl, env );
359 if ( rc == 0 )
360 rc = VLinkerAddUntyped ( self, special, sizeof special / sizeof special [ 0 ], tbl, env );
361 return rc;
362 }
363
364
365 /* MakeIntrinsic
366 * creates an initial, intrinsic linker
367 * pre-loaded with intrinsic factories
368 */
VLinkerMakeIntrinsic(VLinker ** lp)369 rc_t VLinkerMakeIntrinsic ( VLinker **lp )
370 {
371 KDyld *dl;
372 rc_t rc = KDyldMake ( & dl );
373 if ( rc == 0 )
374 {
375 rc = VLinkerMake ( lp, NULL, dl );
376 KDyldRelease ( dl );
377
378 if ( rc == 0 )
379 {
380 KSymTable tbl;
381 VLinker *self = * lp;
382
383 /* create symbol table with no intrinsic scope */
384 rc = KSymTableInit ( & tbl, NULL );
385 if ( rc == 0 )
386 {
387 SchemaEnv env;
388 SchemaEnvInit ( & env, EXT_SCHEMA_LANG_VERSION );
389
390 /* make intrinsic scope modifiable */
391 KSymTablePushScope ( & tbl, & self -> scope );
392
393 /* add intrinsic functions */
394 rc = VLinkerInitFactories ( self, & tbl, & env );
395 if ( rc == 0 )
396 {
397 KSymTableWhack ( & tbl );
398 return 0;
399 }
400
401 KSymTableWhack ( & tbl );
402 }
403
404 VLinkerRelease ( self );
405 }
406 }
407
408 * lp = NULL;
409
410 return rc;
411 }
412