Accelerator Independent Data Access / PVAccess 2.0
AIDA-PVA is the latest version of the AIDA framework. Built on top of EPICS 7 it enables client applications to programmatically access and manage any device or database on the SLAC Network using simple channel names.
Loading...
Searching...
No Matches
aida_pva_types_helper.c
Go to the documentation of this file.
1/** @file
2 * @brief This file contain functions that should be
3 * used directly by Native Channel Providers.
4 * These functions provide all of the features related to processing of Arguments and Table
5 * that allow the Channel Provider to implement its service.
6 *
7 * **MEMBER**=SLCLIBS:AIDA_PVALIB
8 * **ATTRIBUTES**=JNI
9 *
10 * - ascanf() and avscanf() to scan arguments into provided variables.
11 * - Table creation and building functions: tableAddColumn(),
12 * tableAddSingleRowFloatColumn(),
13 * tableAddSingleRowLongColumn(),
14 * tableAddSingleRowBooleanColumn(),
15 * tableAddSingleRowByteColumn(),
16 * tableAddSingleRowShortColumn(),
17 * tableAddSingleRowIntegerColumn(),
18 * tableAddSingleRowDoubleColumn(),
19 * tableAddSingleRowStringColumn(),
20 * tableAddFixedWidthStringColumn(),
21 * tableAddStringColumn()
22 */
23#include <jni.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <ctype.h>
28#include <stdbool.h>
29
30#include "slc_macros.h" /* vmsstat_t, int2u, int4u, etc. */
31#include "sysutil_proto.h" /* for cvt_vms_to_ieee_flt */
32
33#include "aida_pva_jni_helper.h"
36
37static void allocateTableColumn(JNIEnv* env, Table* table, Type aidaType, size_t elementSize);
38static Type tableArrayTypeOf(Type type);
39static size_t tableElementSizeOfOf(Type type);
40static int vavscanf(JNIEnv* env, Arguments* arguments, Value* value, const char* formatString, va_list argp);
41static Type getAidaType(JNIEnv* env, char format, short isArray, short isLong, short isShort);
42static void getJsonPathElements(char* fullJsonPath, char* variableName, char** path);
43static void parseFormatString(char* formatString, short formatCharsToProcess, char* format,
44 short* isRequired, short* isLong, short* isShort, short* isArray);
45static void expectingJsonOrValue(const char* argumentName, short isArray, short* isValue,
46 short* valueShouldBeJson);
47static int getFloatArgument(Arguments* arguments, char* path, float* target);
48static int getDoubleArgument(Arguments* arguments, char* path, double* target);
49static int getFloatArrayArgument(Arguments* arguments, char* path, float** target, unsigned int* elementCount);
50static int getDoubleArrayArgument(Arguments* arguments, char* path, double** target, unsigned int* elementCount);
51static FloatingPointValue* getFloatingPointValue(Arguments* arguments, char* path);
52static void* _getFloatArray(Arguments* arguments, char* path, bool forFloat, unsigned int* elementCount);
53static float* getFloatArray(Arguments* arguments, char* path, unsigned int* elementCount);
54static double* getDoubleArray(Arguments* arguments, char* path, unsigned int* elementCount);
55static int getBooleanValue(char* stringValue);
56static Value asArrayValue(char* stringValue);
57
58/**
59 * ascanf(), avscanf()
60 *
61 * @paragraph Synopsis
62 * @code
63 * int ascanf(Arguments *arguments, const char *format, ...);
64 * int avscanf(Arguments *arguments, Value *value, const char *format, ...);
65 * @endcode
66 *
67 * @paragraph Details
68 * Reads data from the given @p arguments and stores them according
69 * to parameter format into the locations given by the additional arguments,
70 * as if scanf() was used, but reading from arguments instead of the standard input (stdin).
71 *
72 * @see avscanf() for full details.
73 *
74 * @param env The JNI environment. Used in all functions involving JNI
75 * @param arguments Arguments that the function processes as its source to retrieve the data.
76 * @param formatString C string that contains a format string as described above
77 * @param ... Depending on the format string, the function may expect a sequence of additional arguments,
78 * containing pairs of names and pointers to allocated storage (except as indicated above),
79 * where the interpretation of the extracted data is stored with the appropriate type.
80 * There should be at least as many pairs of these arguments as the number of values stored
81 * by the format specifiers.
82 * Additional arguments are ignored by the function
83 * @return `EXIT_SUCCESS` if all required arguments were read and no errors occurred, otherwise `EXIT_FAILURE`
84 * @throw MissingRequiredArgumentException if one of the required arguments are missing
85*/
86int ascanf(JNIEnv* env, Arguments* arguments, const char* formatString, ...)
87{
88 va_list argp;
89 va_start(argp, formatString);
90 int status = vavscanf(env, arguments, NULL, formatString, argp);
91 va_end (argp);
92 return status;
93}
94
95/**
96 * ascanf(), avscanf()
97 *
98 * @paragraph Synopsis
99 * @code
100 * int ascanf(Arguments *arguments, const char *format, ...);
101 * int avscanf(Arguments *arguments, Value *value, const char *format, ...);
102 * @endcode
103 *
104 * @paragraph Details
105 * Reads data from the given @p arguments and stores them according
106 * to parameter format into the locations given by the additional arguments,
107 * as if scanf() was used, but reading from arguments instead of the standard input (stdin).
108 *
109 * The additional arguments should point to already allocated objects of
110 * the type specified by their corresponding format specifier.
111 * For strings and arrays only the pointer needs to be pre-allocated.
112 *
113 * The only space allocated by this function is for the strings or arrays. So callers
114 * should only free strings and arrays. Even if you provide a default value for a string
115 * the pointer will be allocated memory on exit from the function, so even then you need to free it.
116 *
117 * @note
118 * Only the provided pointer needs to be freed as only one allocation is made e.g.
119 * @code
120 * Arguments arguments;
121 * int *intArray;
122 * ascanf(arguments "%da, "fooArray", &intArray);
123 * // Do stuff
124 * free(intArray);
125 * @endcode
126 *
127 * String space is allocated as follows:
128 * @code
129 * +------------------------+----------+----------+----------+---------+
130 * | pointers to strings | string 1 | string 2 | string 3 | ... |
131 * +------------------------+----------+----------+----------+---------+
132 * @endcode
133 *
134 * @paragraph dts Differences to scanf()
135 * ___
136 * There are a number of differences from scanf() which are best described by example:
137 *
138 * @paragraph gd General differences
139 * -# Scan into simple variable/
140 * @code
141 * int n;
142 * ascanf("%d", "NPOS", &n);
143 * @endcode
144 * You must always provide the name of the variable and the pointer to the place to put the value in pairs
145 * -# Optional arguments.
146 * Optional arguments are specified with the **o** character before the format character.
147 * @code
148 * short flag = 10; // 10 is the default value
149 * ascanf("%ohd", "flag", &flag);
150 * @endcode
151 *
152 * By default all arguments referenced by format specifications are considered required
153 * unless the format specification character is preceded by **o**.
154 * For optional arguments the pointer provided must point to the default value.
155 * In the case of arrays and strings this will be copied into allocated storage that
156 * will need to be freed as normal.
157 *
158 * @paragraph an Argument names
159 * -# You can specify simple argument names to search for. These will simply find the named argument and extract its value.
160 * @code
161 * int simpleInt;
162 * ascanf(&arguments "%d, "simple", &simpleInt);
163 * @endcode
164 * -# You can also use dot and square brace notation to refer to complex arguments that are either arrays or complex objects.
165 * Values that are buried deep inside the json structures can be referenced in this way. e.g., given a
166 * variable named `json` and presented as:
167 * @code
168 * json='{"foo": {"bar": 0}}}'
169 * @endcode
170 * You can specify the @p name as "json.foo.bar" to retrieve the `0` value.
171 * -# Also given a variable named `jsonArray` and presented as
172 * @code
173 * jsonArray='[{"foo": 10}, {"bar": 20}]'
174 * @endcode
175 * You can specify the #p name as "jsonArray[1].bar" to retrieve the `20` value.
176 * -# Finally if you use the @p name "value", then the avscanf() function
177 * will use the supplied @p value parameter to get the data for that parameter
178 * @code
179 * Arguments arguments;
180 * Value value;
181 * int *intArray;
182 * avscanf(&arguments &value, "%da, "fooArray", &intArray);
183 * // Do stuff
184 * free(intArray);
185 * @endcode
186 *
187 * @paragraph fs Format Specifiers
188 * ___
189 * @paragraph sfs Type specifiers
190 * - **b** : `unsigned char *` - interpret the input as a boolean, then extract a single byte into the corresponding variable.
191 * - The following translate to `true`
192 * - not `0` - integer, short, long,
193 * - not `0.0` - float, double
194 * - `“true”` - char string
195 * - `“t”` - char string
196 * - `“yes”` - char string
197 * - `“y”` - char string
198 * - `!0` - short, int, long, float, or double
199 * - The following translate to `false`
200 * - `0` - integer, short, long,
201 * - `0.0` - float, double
202 * - `“false”` - char string
203 * - `“f”`- char string
204 * - `“no”`- char string
205 * - `“n”`- char string
206 * - `0` - short, int, long, float, or double
207 * - **c** : `char *` - extract a single character into the corresponding variable.
208 * - **d** : `int *` - extract an integer into the corresponding variable (see **l** & **h** below).
209 * - **f** : `float *` - extract a floating point number (see **l** below).
210 * - **s** : `char *` - extract a string of characters into allocated space and point the corresponding variable to it.
211 * - **u** : `unsigned int *` - extract an unsigned integer into the corresponding variable (see **l** & **h** below).
212 *
213 * @paragraph rf Required flag
214 * - **o** - optional precede the format with this to indicate that the argument is optional.
215 *
216 * @paragraph Prefixes
217 * - **h** - `short *` - preceding **d** will retrieve a short e.g. "%hd".
218 * - **l** - `long *`, double * - preceding **d** will retrieve a long eg. "%ld"; preceding **f** will retrieve a double eg. "%lf".
219 *
220 * @paragraph Suffixes
221 * - **a** - extract an array of the preceding type into a block of allocated space and point the corresponding variable to it.
222 * The variable will have an extra level of indirection than the non-array version.
223 * e.g.,
224 * @code
225 * int i;
226 * ascanf(..., "%d", &i);
227 * @endcode
228 * becomes
229 * @code
230 * int *ia, n;
231 * ascanf(..., "%da", &ia, &n);
232 * @endcode
233 * Also, you need to provide an extra parameter for each format containing an **a** suffix to hold the count of array
234 * elements found. The pointer will point to an `int`.
235 *
236 *
237 * @param env The JNI environment. Used in all functions involving JNI
238 * @param arguments Arguments that the function processes as its source to retrieve the data.
239 * @param value For the avscanf() form this parameter holds the parsed Value given to the Channel Provider endpoint.
240 * @param formatString C string that contains a format string as described above
241 * @param ... Depending on the format string, the function may expect a sequence of additional arguments,
242 * containing pairs of names and pointers to allocated storage (except as indicated above),
243 * where the interpretation of the extracted data is stored with the appropriate type.
244 * There should be at least as many pairs of these arguments as the number of references
245 * in the format specifiers.
246 * Additional arguments are ignored by the function
247 * @return `EXIT_SUCCESS` if all required arguments were read and no errors occurred, otherwise `EXIT_FAILURE`
248 * @throw MissingRequiredArgumentException if one of the required arguments are missing
249*/
250int avscanf(JNIEnv* env, Arguments* arguments, Value* value, const char* formatString, ...)
251{
252 va_list argp;
253 va_start(argp, formatString);
254 int status = vavscanf(env, arguments, value, formatString, argp);
255 va_end (argp);
256 return status;
257}
258
259static int vavscanf(JNIEnv* env, Arguments* arguments, Value* value, const char* formatString, va_list argp)
260{
261 // Keep track of stuff to free
263
264 if (!formatString) {
266 aidaThrowNonOsException(env, AIDA_INTERNAL_EXCEPTION, "No format specifiers provided to ascanf");
267 return EXIT_FAILURE;
268 }
269
270 // Remove white space and empty format strings, also strtok variable must not be const!
271 char _formatString[strlen(formatString) + 1];
272 sprintf(_formatString, "- %s", formatString);
273 char* formatSpecifier = strtok(_formatString, "% ");
274 int numberOfFormatStrings = 0;
275 char formatSpecifiers[MAX_FORMAT_SPECIFIERS][MAX_FORMAT];
276 for (int i = 0; formatSpecifier; ++i) {
277 numberOfFormatStrings++;
278 strcpy(formatSpecifiers[i], formatSpecifier);
279 formatSpecifier = strtok(NULL, "% ");
280 }
281
282 if (!numberOfFormatStrings) {
284 aidaThrowNonOsException(env, AIDA_INTERNAL_EXCEPTION, "No format specifiers provided to ascanf");
285 return EXIT_FAILURE;
286 }
287
288 // nextStringPosition: Used to store strings in space at end of pointers to strings
289 // String space is allocated as follows:
290 // +------------------------+----------+----------+----------+---------+
291 // | pointers to strings | string 1 | string 2 | string 3 | ... |
292 // +------------------------+----------+----------+----------+---------+
293 // So only one block of memory needs to be freed.
294 // The nextStringPosition initially points to the first position after the list of pointers
295 // to strings and is incremented by the string length each time
296 char* nextStringPosition;
297
298 // loop over format specifiers
299 for (int formatNumber = 0; formatNumber < numberOfFormatStrings; formatNumber++) {
300 formatSpecifier = formatSpecifiers[formatNumber];
301
302 short formatSpecifierLength = (short)strlen(formatSpecifier);
303
304 // If format specifier is empty or our artificially added prefix then silently ignore
305 if (!formatSpecifierLength || *formatSpecifier == '-') {
306 continue;
307 }
308
309 // extract the format, isRequiredFlag, isLong, isShort, and isArray
310 char format = 0x0;
311 short isRequired = true, isLong = false, isShort = false, isArray = false;
312
313 parseFormatString(formatSpecifier, formatSpecifierLength, &format, &isRequired, &isLong, &isShort, &isArray);
314
315 // Invalid format - if no format was specified
316 if (!format) {
317 SPRINTF_ERROR_FREE_MEMORY_AND_RETURN_(AIDA_INTERNAL_EXCEPTION, "incorrect format string: %%%s", formatSpecifier,
318 EXIT_FAILURE)
319 }
320
321 // get argumentName
322 // This is the name of the argument that we will get the value from
323 char* argumentName = va_arg (argp, char *);
324 if (!argumentName) {
325 SPRINTF_ERROR_FREE_MEMORY_AND_RETURN_(AIDA_INTERNAL_EXCEPTION, "missing variable to correspond to format: %%%s",
326 formatSpecifier, EXIT_FAILURE)
327 }
328
329 // Set valueShouldBeJson (if argument name should reference json
330 // or if we are expecting an array or if the argument name has json path in it
331 // Set isValue (if we need to get the value from the "value" argument)
332 short valueShouldBeJson = false, isValue = false;
333 expectingJsonOrValue(argumentName, isArray, &isValue, &valueShouldBeJson);
334
335 // Get target variable pointer
336 void* target = va_arg (argp, void *);
337 void** arrayPtr = (void**)target;
338 unsigned int* elementCount;
339 if (isArray) {
340 elementCount = va_arg (argp, unsigned int *);
341 *elementCount = 0;
342 }
343
344 // Convert format, isArray, isLong, and isShort into an AIDA_TYPE
345 Type aidaType = getAidaType(env, format, isArray, isLong, isShort);
347
348 // If this is for a FLOAT or DOUBLE then try to get ieee version if available
349 float floatTarget;
350 float* floatArrayTarget;
351 double doubleTarget;
352 double* doubleArrayTarget;
353 if (aidaType == AIDA_FLOAT_TYPE || aidaType == AIDA_DOUBLE_TYPE) {
354 // Try getting double first
355 if (getDoubleArgument(arguments, argumentName, (double*)&doubleTarget) == EXIT_SUCCESS) {
356 if (aidaType == AIDA_FLOAT_TYPE) { // use for float if that's what you need
357 *((float*)target) = (float)doubleTarget;
358 } else {
359 *((double*)target) = doubleTarget;
360 };
361 continue;
362 }
363 // Try float
364 if (getFloatArgument(arguments, argumentName, (float*)&floatTarget) == EXIT_SUCCESS) {
365 if (aidaType == AIDA_DOUBLE_TYPE) { // use for double if that's what you need
366 *((double*)target) = (double)floatTarget;
367 } else {
368 *((float*)target) = floatTarget;
369 };
370 continue;
371 }
372 }
373
374 if (aidaType == AIDA_FLOAT_ARRAY_TYPE || aidaType == AIDA_DOUBLE_ARRAY_TYPE) {
375 // Try double array first
376 if (getDoubleArrayArgument(arguments, argumentName, (double**)&doubleArrayTarget, elementCount)
377 == EXIT_SUCCESS) {
378 TRACK_MEMORY(doubleArrayTarget)
379 if (aidaType == AIDA_FLOAT_ARRAY_TYPE) { // use for float if that's what you need
380 // Allocate a new array and copy values
381 floatArrayTarget = calloc(*elementCount, sizeof(float));
382 TRACK_MEMORY(floatArrayTarget)
383 if (!floatArrayTarget) {
385 "Could not allocate memory for float argument",
386 EXIT_FAILURE)
387 }
388 *((float**)target) = floatArrayTarget;
389 for (int i = 0; i < *elementCount; i++) {
390 floatArrayTarget[i] = (float)doubleArrayTarget[i];
391 }
392 FREE_TRACKED_MEMORY(doubleArrayTarget)
393 } else {
394 *((double**)target) = doubleArrayTarget;
395 };
396 continue;
397 }
398
399 // Then try float array
400 if (getFloatArrayArgument(arguments, argumentName, (float**)&floatArrayTarget, elementCount)
401 == EXIT_SUCCESS) {
402 TRACK_MEMORY(floatArrayTarget)
403 if (aidaType == AIDA_DOUBLE_ARRAY_TYPE) { // use for double if that's what you need
404 // Allocate a new array and copy values
405 doubleArrayTarget = calloc(*elementCount, sizeof(double));
406 TRACK_MEMORY(doubleArrayTarget)
407 if (!doubleArrayTarget) {
409 "Could not allocate memory for double argument",
410 EXIT_FAILURE)
411 }
412 *((double**)target) = doubleArrayTarget;
413 for (int i = 0; i < *elementCount; i++) {
414 doubleArrayTarget[i] = (double)floatArrayTarget[i];
415 }
416 FREE_TRACKED_MEMORY(floatArrayTarget)
417 } else {
418 *((float**)target) = floatArrayTarget;
419 };
420 continue;
421 }
422 }
423
424 // If this is for a FLOAT_ARRAY or DOUBLE_ARRAY then get the ieee version if available
425
426 // if the argument is json then the name may contain dots and square braces,
427 // so this variable contains just the argument name part at the beginning.
428 // e.g. if the argumentName="bpms[0].name" then jsonArgumentName="bpms"
429 char jsonArgumentName[strlen(argumentName) + 1];
430
431 // The json path used to identify the element in the given json that we should use.
432 // It is the remaining part of the argument name after the jsonArgumentName has been removed.
433 // e.g. if the argumentName="bpms[0].name" then jsonPath="[0].name"
434 char* jsonPath = "";
435
436 // This is the value extracted from the provided argument that has been parsed for json
437 Value elementValue;
438
439 // get the valueString and jsonRoot
440 // valueString is the string representation of the argument's value and
441 // jsonRoot is the root of the parsed json version of the argument, if the argument is json
442 char* stringValue = NULL;
443 json_value* jsonRoot = NULL;
444 json_type jsonType = json_none;
445
446 if (valueShouldBeJson) {
447 getJsonPathElements(argumentName, jsonArgumentName, &jsonPath);
448 }
449
450 // Is using value argument
451 if (isValue) {
452 // First check if we have had the value passed to us as an argument
453 // If not then go and get it
454 if (value) {
455 if (isArray && value->type == AIDA_STRING_TYPE) {
456
457 // ignore passed in value if we need an array but the user didn't give us an array
458 // Just take the string and wrap it as an array
459 elementValue = asArrayValue(value->value.stringValue);
460 if (elementValue.type != AIDA_JSON_TYPE) {
462 value->value.stringValue, EXIT_FAILURE)
463 }
464 value = &elementValue;
465 TRACK_JSON(elementValue.value.jsonValue)
466 }
467 } else {
468 if (isArray && !*jsonPath) {
469 elementValue = getArrayValue(env, *arguments);
470 } else {
471 elementValue = getValue(env, *arguments);
472 }
474 value = &elementValue;
475 if (elementValue.type == AIDA_JSON_TYPE) {
476 TRACK_JSON(elementValue.value.jsonValue)
477 valueShouldBeJson = true;
478 }
479 }
480
481 // Check if the value has been properly set
482 if (value->type == AIDA_NO_TYPE) {
483 if (isRequired) {
485 argumentName, EXIT_FAILURE)
486 } else {
487 // If this is a string and a default has been set but the optional string has not been provided
488 // then allocate space for it and set it
489 // so that callers can uniformly free all strings
490 char* defaultString = *(char**)target;
491 if (aidaType == AIDA_STRING_TYPE && defaultString) {
492 char* allocatedString;
494 env, allocatedString, defaultString, "default arguments", EXIT_FAILURE)
495 *(char**)target = allocatedString;
496 }
497 continue;
498 }
499 }
500
501 if (valueShouldBeJson) {
502 jsonRoot = getJsonValue(value, jsonPath);
503 jsonType = jsonRoot->type;
504 } else {
505 stringValue = value->value.stringValue;
506 }
507 } else {
508 // Is not using value argument
509 if (valueShouldBeJson) {
510 // Should be a normal json argument
511 if (isArray && !*jsonPath) {
512 elementValue = getNamedArrayValue(env, *arguments, jsonArgumentName);
513 } else {
514 elementValue = getNamedValue(env, *arguments, jsonArgumentName);
515 }
517 if (elementValue.type != AIDA_JSON_TYPE) {
518 if (isRequired) {
520 "Missing required argument: %s", argumentName, EXIT_FAILURE)
521 } else {
522 continue;
523 }
524 }
525 TRACK_JSON(elementValue.value.jsonValue)
526 jsonRoot = getJsonValue(&elementValue, jsonPath);
527 jsonType = jsonRoot->type;
528 } else {
529 // Normal string argument
530 Argument elementArgument = getArgument(*arguments, argumentName);
531 if (!elementArgument.name) {
532 if (isRequired) {
534 "Missing required argument: %s", argumentName, EXIT_FAILURE)
535 } else {
536 continue;
537 }
538 }
539 stringValue = elementArgument.value;
540 }
541 }
542
543 // Note that for strings we allocate enough memory for all the pointers and for the strings as well
544 // stored contiguously afterwards so that the caller simply frees the pointer-to-pointer to strings
545 // +------------------------+----------+----------+----------+---------+
546 // | pointers to strings | string 1 | string 2 | string 3 | ... |
547 // +------------------------+----------+----------+----------+---------+
548 // For all other arrays the allocated space is simply a contiguous set of elements of the base array type
549
550 // From this point forwards we can be sure that all arrays have a valid arrayRoot set.
551 json_value* arrayRoot = NULL;
552 unsigned int arrayCount;
553 if (isArray) {
554 if (jsonType != json_array) {
556 "Array expected but found scalar or string: %s", argumentName, EXIT_FAILURE)
557 }
558 arrayRoot = jsonRoot;
559 arrayCount = arrayRoot->u.array.length;
560 }
561
562 // Now we have a valueString or jsonRoot, a target to put the data and the type we want to extract!
563 // based on format process the argument and/or value
564 switch (aidaType) {
566 break;
568 break;
569 case AIDA_BYTE_TYPE: ASCANF_SET_BYTE(target)
570 break;
572 break;
573 case AIDA_SHORT_TYPE: ASCANF_SET_SCALAR("%hi", short, json_integer, "short", target)
574 break;
575 case AIDA_SHORT_ARRAY_TYPE: ASCANF_SET_ARRAY("%hi", short, json_integer, "short")
576 break;
577 case AIDA_UNSIGNED_SHORT_TYPE: ASCANF_SET_SCALAR("%hu", unsigned short, json_integer, "unsigned short", target)
578 break;
579 case AIDA_UNSIGNED_SHORT_ARRAY_TYPE: ASCANF_SET_ARRAY("%hu", unsigned short, json_integer, "unsigned short")
580 break;
581 case AIDA_INTEGER_TYPE: ASCANF_SET_SCALAR("%d", int, json_integer, "integer", target)
582 break;
583 case AIDA_INTEGER_ARRAY_TYPE: ASCANF_SET_ARRAY("%d", int, json_integer, "integer")
584 break;
585 case AIDA_UNSIGNED_INTEGER_TYPE: ASCANF_SET_SCALAR("%u", unsigned int, json_integer, "unsigned integer", target)
586 break;
587 case AIDA_UNSIGNED_INTEGER_ARRAY_TYPE: ASCANF_SET_ARRAY("%u", unsigned int, json_integer, "unsigned integer")
588 break;
589 case AIDA_LONG_TYPE: ASCANF_SET_SCALAR("%ld", long, json_integer, "long", target)
590 break;
591 case AIDA_LONG_ARRAY_TYPE: ASCANF_SET_ARRAY("%ld", long, json_integer, "long")
592 break;
593 case AIDA_UNSIGNED_LONG_TYPE: ASCANF_SET_SCALAR("%lu", unsigned long, json_integer, "unsigned long", target)
594 break;
595 case AIDA_UNSIGNED_LONG_ARRAY_TYPE: ASCANF_SET_ARRAY("%lu", unsigned long, json_integer, "unsigned long")
596 break;
597 case AIDA_FLOAT_TYPE: ASCANF_SET_SCALAR("%f", float, json_double, "float", target)
598 break;
599 case AIDA_FLOAT_ARRAY_TYPE: ASCANF_SET_ARRAY("%f", float, json_double, "float")
600 break;
601 case AIDA_DOUBLE_TYPE: ASCANF_SET_SCALAR("%lf", double, json_double, "double", target)
602 break;
603 case AIDA_DOUBLE_ARRAY_TYPE: ASCANF_SET_ARRAY("%lf", double, json_double, "double")
604 break;
606 break;
608 break;
609
610 // Will never happen so ignore
611 case AIDA_NO_TYPE:
612 case AIDA_VOID_TYPE:
613 case AIDA_TABLE_TYPE:
614 case AIDA_JSON_TYPE:
615 default:
616 break;
617 }
618
619 if (isArray) {
620 *elementCount = arrayCount;
621 }
622 }
623
625 return EXIT_SUCCESS;
626}
627
628/**
629 * Make a Table for return to client. This is the first call that needs to be made to return a Table.
630 * This will create a Table with the specified the number of rows and columns.
631 * You need to call tableAddColumn(), tableAddStringColumn(), or any of the
632 * other special `tableAdd` functions to add
633 * columns to the Table before returning it.
634 *
635 * @param env The JNI environment. Used in all functions involving JNI.
636 * @param rows the number of rows to create the Table with.
637 * @param columns the number of columns to create the Table with,
638 * @return the newly created Table
639 *
640 * @see
641 * tableAddColumn(),
642 * tableAddStringColumn()
643 * tableAddFixedWidthStringColumn(),
644 * tableAddSingleRowBooleanColumn(),
645 * tableAddSingleRowByteColumn(),
646 * tableAddSingleRowShortColumn(),
647 * tableAddSingleRowIntegerColumn(),
648 * tableAddSingleRowLongColumn(),
649 * tableAddSingleRowFloatColumn(),
650 * tableAddSingleRowDoubleColumn(),
651 * tableAddSingleRowStringColumn(),
652 *
653 * @paragraph Example
654 *
655 * Create a two column, two row Table, add data, and return.
656 * @code
657 * int rows = 2, columns = 2;
658 * float xData[rows] = { 1.0f, 2.0f }, yData[rows] = { 7.0f, 8.0f };
659 *
660 * Table table = tableCreate(env, rows, columns);
661 * ON_EXCEPTION_RETURN_(table)
662 * tableAddColumn(env, &table, AIDA_FLOAT_TYPE, xData, true);
663 * ON_EXCEPTION_RETURN_(table)
664 * tableAddColumn(env, &table, AIDA_FLOAT_TYPE, yData, true);
665 * ON_EXCEPTION_RETURN_(table)
666 * return table;
667 * @endcode
668 * @note
669 * You need to call ON_EXCEPTION_RETURN_(table) after each call to make
670 * sure that no exception was raised.
671 */
672Table tableCreate(JNIEnv* env, int rows, int columns)
673{
674 Table table;
675 memset(&table, 0, sizeof(table));
676 table._currentColumn = 0; // Reset current column so that any addColumn() calls are correct
677 table.columnCount = 0;
678
679 if (rows <= 0) {
680 aidaThrowNonOsException(env, AIDA_INTERNAL_EXCEPTION, "Attempt to allocate a zero length table");
681 return table;
682 }
683
684 // Allocate space for the table columns and column types
685 ALLOCATE_MEMORY_AND_ON_ERROR_RETURN_(env, table.ppData, columns * sizeof(void*), "table columns", table)
686 ALLOCATE_MEMORY_AND_ON_ERROR_RETURN_(env, table.types, columns * sizeof(Type*), "table column types", table)
687 table.rowCount = rows;
688 table.columnCount = columns;
689 return table;
690}
691
692Table tableCreateDynamic(JNIEnv* env, int rows, int columns) {
693 Table table = tableCreate(env, rows, columns);
695
696 table._currentField = 0; // Reset current field so that any addField() calls are correct
697 ALLOCATE_MEMORY_AND_ON_ERROR_RETURN_(env, table.ppFields, columns * sizeof(char*), "table fields", table)
698 table._currentLabel = 0; // Reset current label so that any addLabel() calls are correct
699 ALLOCATE_MEMORY_AND_ON_ERROR_RETURN_(env, table.ppLabels, columns * sizeof(char*), "table fields", table)
700 return table;
701}
702
703/**
704 * Add a column of arbitrary type to a Table. Add the given data to the
705 * column assuming that the data has a number of rows that corresponds to the
706 * Table's rowCount. Memory will be allocated for the data of the column so
707 * the @p data buffer presented can be freed up after calling this function.
708 *
709 * @note
710 * Don't call this to add strings to the Table. Use tableAddStringColumn() for that.
711 *
712 * The framework will release all memory associated with
713 * a Table when you return from your API implementation.
714 *
715 * @param env The JNI environment. Used in all functions involving JNI.
716 * @param table the Table to add the column to.
717 * @param type the type of this Table column.
718 * @param data the data to add to this column, a buffer of `sizeof(type) * table->rowCount` size.
719 * @param ieeeFormat true if the data provided is already in ieee format. If the data is not in ieee format,
720 * usually because it has been retrieved from some backend system, this function will convert it to ieee format
721 * unless this parameter is set to true.
722 *
723 * @see
724 * tableCreate(),
725 * tableAddStringColumn()
726 * tableAddFixedWidthStringColumn(),
727 * tableAddSingleRowBooleanColumn(),
728 * tableAddSingleRowByteColumn(),
729 * tableAddSingleRowShortColumn(),
730 * tableAddSingleRowIntegerColumn(),
731 * tableAddSingleRowLongColumn(),
732 * tableAddSingleRowFloatColumn(),
733 * tableAddSingleRowDoubleColumn(),
734 * tableAddSingleRowStringColumn(),
735 *
736 * @paragraph Example
737 *
738 * Create a two column, two row Table, add data, and return.
739 * @code
740 * int rows = 2, columns = 2;
741 * float xData[rows] = { 1.0f, 2.0f }, yData[rows] = { 7.0f, 8.0f };
742 *
743 * Table table = tableCreate(env, rows, columns);
744 * ON_EXCEPTION_RETURN_(table)
745 * tableAddColumn(env, &table, AIDA_FLOAT_TYPE, xData, true);
746 * ON_EXCEPTION_RETURN_(table)
747 * tableAddColumn(env, &table, AIDA_FLOAT_TYPE, yData, true);
748 * ON_EXCEPTION_RETURN_(table)
749 * return table;
750 * @endcode
751 * @note
752 * You need to call ON_EXCEPTION_RETURN_(table) after each call to make
753 * sure that no exception was raised.
754 */
755void tableAddColumn(JNIEnv* env, Table* table, Type type, void* data, bool ieeeFormat)
756{
757 // Table full?
758 if (table->_currentColumn >= table->columnCount) {
760 "Internal Error: more columns added than table size");
761 return;
762 }
763
764 // No Data supplied ?
765 if (!data) {
767 "Internal Error: Attempt to add column with no data");
768 return;
769 }
770
771 // Correct type for tables
772 type = tableArrayTypeOf(type);
773
774 // Set column type, and allocate space
775 allocateTableColumn(env, table, type, tableElementSizeOfOf(type));
777
778 // Rest of processing for strings is done in addStringColumn
779 if (type == AIDA_STRING_ARRAY_TYPE) {
780 return;
781 }
782
783 if (!ieeeFormat) {
784 // Convert float values if float array
785 if (type == AIDA_FLOAT_ARRAY_TYPE) {
786 CONVERT_FROM_VMS_FLOAT(((float*)data), (int2u)table->rowCount)
787 }
788
789 // Convert double values if double array
790 if (type == AIDA_DOUBLE_ARRAY_TYPE) {
791 CONVERT_FROM_VMS_DOUBLE((double*)data, (int2u)table->rowCount)
792 }
793 }
794
795 // Add data to column
796 for (int row = 0; row < table->rowCount; row++) {
797 // add data and increment pointer based on type
798 switch (type) {
801 ((unsigned char*)(table->ppData[table->_currentColumn]))[row] = ((unsigned char*)data)[row];
802 break;
804 ((short*)(table->ppData[table->_currentColumn]))[row] = ((short*)data)[row];
805 break;
807 ((int*)(table->ppData[table->_currentColumn]))[row] = ((int*)data)[row];
808 break;
810 ((long*)(table->ppData[table->_currentColumn]))[row] = ((long*)data)[row];
811 break;
813 ((float*)(table->ppData[table->_currentColumn]))[row] = ((float*)data)[row];
814 break;
816 ((double*)(table->ppData[table->_currentColumn]))[row] = ((double*)data)[row];
817 break;
818 default:
820 "Internal Error: Call to tableAddColumn() un-supported type");
821 return;
822 }
823 }
824
825 table->_currentColumn++;
826}
827
828void tableAddField(JNIEnv* env, Table* table, char* fieldName) {
829 // Table full?
830 if (table->_currentField >= table->columnCount) {
832 "Internal Error: more fields added than table size");
833 return;
834 }
835
836 // No Data supplied ?
837 if (!fieldName || !*fieldName) {
839 "Internal Error: Attempt to add empty field name");
840 return;
841 }
842
843 ALLOCATE_STRING_AND_ON_ERROR_RETURN_VOID(env, table->ppFields[table->_currentField], fieldName, "table field names")
844 table->_currentField++;
845}
846
847void tableAddLabel(JNIEnv* env, Table* table, char* labelName) {
848 // Table full?
849 if (table->_currentLabel >= table->columnCount) {
851 "Internal Error: more labels added than table size");
852 return;
853 }
854
855 // No Data supplied ?
856 if (!labelName || !*labelName) {
858 "Internal Error: Attempt to add empty label name");
859 return;
860 }
861
862 ALLOCATE_STRING_AND_ON_ERROR_RETURN_VOID(env, table->ppLabels[table->_currentLabel], labelName, "table label names")
863 table->_currentLabel++;
864}
865
866/**
867 * Add a String column to the given Table.
868 * This reads data from a buffer that is itself a list of pointers to strings.
869 * We allocate just enough space to store the strings in our Table. This is allocated
870 * in one buffer so there is only one pointer to release.
871 *
872 * @note
873 * The framework will release all memory associated with
874 * a Table when you return from your API implementation.
875 *
876 * @param env The JNI environment. Used in all functions involving JNI.
877 * @param table the Table to add the string column to.
878 * @param data the data to add to this column, a buffer of `sizeof(char *) * table->rowCount` size.
879 * This will contain the strings to be added to the Table.
880 *
881 * @see
882 * tableCreate(),
883 * tableAddColumn(),
884 * tableAddFixedWidthStringColumn(),
885 * tableAddSingleRowBooleanColumn(),
886 * tableAddSingleRowByteColumn(),
887 * tableAddSingleRowShortColumn(),
888 * tableAddSingleRowIntegerColumn(),
889 * tableAddSingleRowLongColumn(),
890 * tableAddSingleRowFloatColumn(),
891 * tableAddSingleRowDoubleColumn(),
892 * tableAddSingleRowStringColumn(),
893 *
894 * @paragraph Example
895 *
896 * Create a single column, one row Table, add data, and return.
897 * @code
898 * int rows = 1, columns = 1;
899 * char* namesData[rows];
900 * namesData[0] = "NAME";
901 *
902 * Table table = tableCreate(env, rows, columns);
903 * ON_EXCEPTION_RETURN_(table)
904 * tableAddStringColumn(env, &table, namesData);
905 * ON_EXCEPTION_RETURN_(table)
906 * return table;
907 * @endcode
908 * @note
909 * You need to call ON_EXCEPTION_RETURN_(table) after each call to make
910 * sure that no exception was raised.
911 */
912void tableAddStringColumn(JNIEnv* env, Table* table, char** data)
913{
914 tableAddColumn(env, table, AIDA_STRING_ARRAY_TYPE, data, false);
916
917 // allocate data for each string too
918 char** stringArray = table->ppData[table->_currentColumn];
919 for (int row = 0; row < table->rowCount; row++, data++) {
920 ALLOCATE_STRING_AND_ON_ERROR_RETURN_VOID(env, stringArray[row], *data, "table strings")
921 }
922
923 table->_currentColumn++;
924}
925
926/**
927 * This reads data from an allocated space that is rows * width with each string occupying width characters
928 * Though the strings are null terminated if there is space, there is no guarantee so an exact number of
929 * bytes is copied. Each string in the Table is allocated maximally.
930 *
931 * @note
932 * The framework will release all memory associated with
933 * a Table when you return from your API implementation.
934 *
935 * @param env The JNI environment. Used in all functions involving JNI.
936 * @param table The Table to add the column to.
937 * @param data The data to add to this column, a pointer to `char` buffer containing
938 * the fixed length strings. The strings are arranged in
939 * contiguous blocks @p width long.
940 * @param width the width of the strings
941 *
942 * @see
943 * tableCreate(),
944 * tableAddColumn(),
945 * tableAddStringColumn()
946 * tableAddSingleRowBooleanColumn(),
947 * tableAddSingleRowByteColumn(),
948 * tableAddSingleRowShortColumn(),
949 * tableAddSingleRowIntegerColumn(),
950 * tableAddSingleRowLongColumn(),
951 * tableAddSingleRowFloatColumn(),
952 * tableAddSingleRowDoubleColumn(),
953 * tableAddSingleRowStringColumn(),
954 */
955void tableAddFixedWidthStringColumn(JNIEnv* env, Table* table, char* data, int width)
956{
957 tableAddColumn(env, table, AIDA_STRING_ARRAY_TYPE, data, false);
959
960 // allocate data for each string too
961 char** stringArray = table->ppData[table->_currentColumn];
962 char* dataPointer = (char*)data;
963 for (int row = 0; row < table->rowCount; row++, dataPointer += width) {
964 ALLOCATE_FIXED_LENGTH_STRING_AND_ON_ERROR_RETURN_VOID(env, stringArray[row], dataPointer, width + 1, "table strings")
965 stringArray[row][width] = 0x0;
966 }
967
968 table->_currentColumn++;
969}
970
971/**
972 * Add a boolean column to a Table with only one row. This function will allocate
973 * the required memory for the single `unsigned char` that is required.
974 *
975 * @note
976 * The framework will release all memory associated with
977 * a Table when you return from your API implementation.
978 *
979 * @param env The JNI environment. Used in all functions involving JNI.
980 * @param table The Table to add the column to.
981 * @param data The data to add to this column, a pointer to an `unsigned char`.
982 *
983 * @see
984 * tableCreate(),
985 * tableAddColumn(),
986 * tableAddStringColumn()
987 * tableAddFixedWidthStringColumn(),
988 * tableAddSingleRowByteColumn(),
989 * tableAddSingleRowShortColumn(),
990 * tableAddSingleRowIntegerColumn(),
991 * tableAddSingleRowLongColumn(),
992 * tableAddSingleRowFloatColumn(),
993 * tableAddSingleRowDoubleColumn(),
994 * tableAddSingleRowStringColumn(),
995 */
996void tableAddSingleRowBooleanColumn(JNIEnv* env, Table* table, unsigned char data)
997{
998 tableAddColumn(env, table, AIDA_BOOLEAN_TYPE, &data, false);
999}
1000
1001/**
1002 * Add a byte column to a Table with only one row
1003 *
1004 * @note
1005 * The framework will release all memory associated with
1006 * a Table when you return from your API implementation.
1007 *
1008 * @param env The JNI environment. Used in all functions involving JNI.
1009 * @param table The Table to add the column to.
1010 * @param data The data to add to this column, an `unsigned char`.
1011 *
1012 * @see
1013 * tableCreate(),
1014 * tableAddColumn(),
1015 * tableAddStringColumn()
1016 * tableAddFixedWidthStringColumn(),
1017 * tableAddSingleRowBooleanColumn(),
1018 * tableAddSingleRowShortColumn(),
1019 * tableAddSingleRowIntegerColumn(),
1020 * tableAddSingleRowLongColumn(),
1021 * tableAddSingleRowFloatColumn(),
1022 * tableAddSingleRowDoubleColumn(),
1023 * tableAddSingleRowStringColumn(),
1024 */
1025void tableAddSingleRowByteColumn(JNIEnv* env, Table* table, unsigned char data)
1026{
1027 tableAddColumn(env, table, AIDA_BYTE_TYPE, &data, false);
1028}
1029
1030/**
1031 * Add a short column to a Table with only one row.
1032 *
1033 * @note
1034 * The framework will release all memory associated with
1035 * a Table when you return from your API implementation.
1036 *
1037 * @param env The JNI environment. Used in all functions involving JNI.
1038 * @param table The Table to add the column to.
1039 * @param data The data to add to this column, a `short`.
1040 *
1041 * @see
1042 * tableCreate(),
1043 * tableAddColumn(),
1044 * tableAddStringColumn()
1045 * tableAddFixedWidthStringColumn(),
1046 * tableAddSingleRowBooleanColumn(),
1047 * tableAddSingleRowByteColumn(),
1048 * tableAddSingleRowIntegerColumn(),
1049 * tableAddSingleRowLongColumn(),
1050 * tableAddSingleRowFloatColumn(),
1051 * tableAddSingleRowDoubleColumn(),
1052 * tableAddSingleRowStringColumn(),
1053 */
1054void tableAddSingleRowShortColumn(JNIEnv* env, Table* table, short data)
1055{
1056 tableAddColumn(env, table, AIDA_SHORT_TYPE, &data, false);
1057}
1058
1059/**
1060 * Add a integer column to a Table with only one row.
1061 *
1062 * @note
1063 * The framework will release all memory associated with
1064 * a Table when you return from your API implementation.
1065 *
1066 * @param env The JNI environment. Used in all functions involving JNI.
1067 * @param table the Table to add the column to.
1068 * @param data the data to add to this column, an `int`
1069 *
1070 * @see
1071 * tableCreate(),
1072 * tableAddColumn(),
1073 * tableAddStringColumn()
1074 * tableAddFixedWidthStringColumn(),
1075 * tableAddSingleRowBooleanColumn(),
1076 * tableAddSingleRowByteColumn(),
1077 * tableAddSingleRowShortColumn(),
1078 * tableAddSingleRowLongColumn(),
1079 * tableAddSingleRowFloatColumn(),
1080 * tableAddSingleRowDoubleColumn(),
1081 * tableAddSingleRowStringColumn(),
1082 */
1083void tableAddSingleRowIntegerColumn(JNIEnv* env, Table* table, int data)
1084{
1085 tableAddColumn(env, table, AIDA_INTEGER_TYPE, &data, false);
1086}
1087
1088/**
1089 * Add a long column to a Table with only one row
1090 *
1091 *
1092 * @note
1093 * The framework will release all memory associated with
1094 * a Table when you return from your API implementation.
1095 *
1096 * @param env The JNI environment. Used in all functions involving JNI.
1097 * @param table the Table to add the column to.
1098 * @param data the data to add to this column. A `long` value
1099 *
1100 * @see
1101 * tableCreate(),
1102 * tableAddColumn(),
1103 * tableAddStringColumn()
1104 * tableAddFixedWidthStringColumn(),
1105 * tableAddSingleRowBooleanColumn(),
1106 * tableAddSingleRowByteColumn(),
1107 * tableAddSingleRowShortColumn(),
1108 * tableAddSingleRowIntegerColumn(),
1109 * tableAddSingleRowFloatColumn(),
1110 * tableAddSingleRowDoubleColumn(),
1111 * tableAddSingleRowStringColumn(),
1112 */
1113void tableAddSingleRowLongColumn(JNIEnv* env, Table* table, long data)
1114{
1115 tableAddColumn(env, table, AIDA_LONG_TYPE, &data, false);
1116}
1117
1118/**
1119 * Add a float column to a Table with only one row
1120 *
1121 * @note
1122 * The framework will release all memory associated with
1123 * a Table when you return from your API implementation.
1124 *
1125 * @param env The JNI environment. Used in all functions involving JNI.
1126 * @param table The Table to add the column to.
1127 * @param data The data to add to this column, a `float`.
1128 * @param ieeeFloat True if the data is in ieee format, otherwise the given floating point
1129 * number is converted from VMS to ieee format.
1130 *
1131 * @see
1132 * tableCreate(),
1133 * tableAddColumn(),
1134 * tableAddStringColumn()
1135 * tableAddFixedWidthStringColumn(),
1136 * tableAddSingleRowBooleanColumn(),
1137 * tableAddSingleRowByteColumn(),
1138 * tableAddSingleRowShortColumn(),
1139 * tableAddSingleRowIntegerColumn(),
1140 * tableAddSingleRowLongColumn(),
1141 * tableAddSingleRowDoubleColumn(),
1142 * tableAddSingleRowStringColumn(),
1143 */
1144void tableAddSingleRowFloatColumn(JNIEnv* env, Table* table, float data, bool ieeeFloat)
1145{
1146 tableAddColumn(env, table, AIDA_FLOAT_TYPE, &data, ieeeFloat);
1147}
1148
1149/**
1150 * Add a double column to a Table with only one row.
1151 *
1152 * @note
1153 * The framework will release all memory associated with
1154 * a Table when you return from your API implementation.
1155 *
1156 * @param env The JNI environment. Used in all functions involving JNI.
1157 * @param table The Table to add the column to.
1158 * @param data The data to add to this column, a `double`.
1159 * @param ieeeDouble True if the data is in ieee format, otherwise the double precision floating point
1160 * number is converted from VMS to ieee format.
1161 *
1162 * @see
1163 * tableCreate(),
1164 * tableAddColumn(),
1165 * tableAddStringColumn()
1166 * tableAddFixedWidthStringColumn(),
1167 * tableAddSingleRowBooleanColumn(),
1168 * tableAddSingleRowByteColumn(),
1169 * tableAddSingleRowShortColumn(),
1170 * tableAddSingleRowIntegerColumn(),
1171 * tableAddSingleRowLongColumn(),
1172 * tableAddSingleRowFloatColumn(),
1173 * tableAddSingleRowStringColumn(),
1174 */
1175void tableAddSingleRowDoubleColumn(JNIEnv* env, Table* table, double data, bool ieeeDouble)
1176{
1177 tableAddColumn(env, table, AIDA_DOUBLE_TYPE, &data, ieeeDouble);
1178}
1179
1180/**
1181 * Add a string column to a Table with only one row. This is a shortcut
1182 * Table function that simplifies adding a string to a Table with only one row.
1183 *
1184 * @note
1185 * The framework will release all memory associated with
1186 * a Table when you return from your API implementation.
1187 *
1188 * @param env The JNI environment. Used in all functions involving JNI.
1189 * @param table the Table to add the column to.
1190 * @param data the data to add to this column. A single string.
1191 *
1192 * @see
1193 * tableCreate(),
1194 * tableAddColumn(),
1195 * tableAddStringColumn()
1196 * tableAddFixedWidthStringColumn(),
1197 * tableAddSingleRowBooleanColumn(),
1198 * tableAddSingleRowByteColumn(),
1199 * tableAddSingleRowShortColumn(),
1200 * tableAddSingleRowIntegerColumn(),
1201 * tableAddSingleRowLongColumn(),
1202 * tableAddSingleRowFloatColumn(),
1203 * tableAddSingleRowDoubleColumn(),
1204 */
1205void tableAddSingleRowStringColumn(JNIEnv* env, Table* table, char* data)
1206{
1207 tableAddStringColumn(env, table, &data);
1208}
1209
1210/**
1211 * See if there is a ieee float value stored in arguments. If so set target
1212 *
1213 * @param arguments the arguments to scan for the float.
1214 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1215 * But it can also use dot notation to reference the value deep inside json.
1216 * e.g. "json.foo.bar"
1217 * @param target the place to store the float if found.
1218 * @return `EXIT_SUCCESS` if found `EXIT_FAILURE` if not.
1219 */
1220static int getFloatArgument(Arguments* arguments, char* path, float* target)
1221{
1222 FloatingPointValue* floatingPointValue = getFloatingPointValue(arguments, path);
1223 if (floatingPointValue) {
1224 *target = floatingPointValue->value.floatValue;
1225 return EXIT_SUCCESS;
1226 }
1227 return EXIT_FAILURE;
1228}
1229
1230/**
1231 * See if there is a ieee double value stored in arguments. If so set target.
1232 *
1233 * @param arguments the arguments to scan for the double.
1234 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1235 * But it can also use dot notation to reference the value deep inside json.
1236 * e.g. "json.foo.bar"
1237 * @param target the place to store the double.
1238 * @return `EXIT_SUCCESS` if found `EXIT_FAILURE` if not.
1239 */
1240static int getDoubleArgument(Arguments* arguments, char* path, double* target)
1241{
1242 FloatingPointValue* floatingPointValue = getFloatingPointValue(arguments, path);
1243 if (floatingPointValue) {
1244 *target = floatingPointValue->value.doubleValue;
1245 return EXIT_SUCCESS;
1246 }
1247 return EXIT_FAILURE;
1248}
1249
1250/**
1251 * See if there is an ieee float array stored in arguments. If so allocate space and
1252 * and set target.
1253 *
1254 * @param arguments the arguments to scan for the float array.
1255 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1256 * But it can also use dot notation to reference the value deep inside json.
1257 * e.g. "jsonArray[1].bar"
1258 * @param target the place to store the float array.
1259 * @return `EXIT_SUCCESS` if found `EXIT_FAILURE` if not.
1260 */
1261static int getFloatArrayArgument(Arguments* arguments, char* path, float** target, unsigned int* elementCount)
1262{
1263 float* floatArray = getFloatArray(arguments, path, elementCount);
1264 if (floatArray) {
1265 *target = floatArray;
1266 return EXIT_SUCCESS;
1267 }
1268 return EXIT_FAILURE;
1269}
1270
1271/**
1272 * See if there is an ieee double array stored in arguments. If so allocate space and
1273 * and set target.
1274 *
1275 * @param arguments the arguments to scan for the double array.
1276 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1277 * But it can also use dot notation to reference the value deep inside json.
1278 * e.g. "jsonArray[1].bar"
1279 * @param target the place to store the double array.
1280 * @return `EXIT_SUCCESS` if found `EXIT_FAILURE` if not.
1281 */
1282static int getDoubleArrayArgument(Arguments* arguments, char* path, double** target, unsigned int* elementCount)
1283{
1284 double* doubleArray = getDoubleArray(arguments, path, elementCount);
1285 if (doubleArray) {
1286 *target = doubleArray;
1287 return EXIT_SUCCESS;
1288 }
1289 return EXIT_FAILURE;
1290}
1291
1292/**
1293 * Get a floating point value by path. This will look up the value in the arguments
1294 * by searching for one with the given path.
1295 *
1296 * @param arguments the arguments to scan for the floating point value.
1297 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1298 * But it can also use dot notation to reference the value deep inside json.
1299 * e.g. "jsonArray[1].bar"
1300 * @return NULL of not found.
1301 */
1302static FloatingPointValue* getFloatingPointValue(Arguments* arguments, char* path)
1303{
1304 for (int i = 0; i < arguments->floatingPointValuesCount; i++) {
1305 if (strcasecmp(path, arguments->floatingPointValues[i].path) == 0) {
1306 return &arguments->floatingPointValues[i];
1307 }
1308 }
1309 return NULL;
1310}
1311
1312/**
1313 * Get an array of floats by searching for an array rooted at path.
1314 * Space for the array will be allocated if any are found (must be freed by caller).
1315 *
1316 * @param arguments the arguments to scan for the floating point array.
1317 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1318 * But it can also use dot notation to reference the value deep inside json.
1319 * e.g. "jsonArray[1].bar"
1320 * @return NULL of not found.
1321 */
1322static float* getFloatArray(Arguments* arguments, char* path, unsigned int* elementCount)
1323{
1324 return (float*)_getFloatArray(arguments, path, true, elementCount);
1325}
1326
1327/**
1328 * Get an array of doubles by searching for an array rooted at path
1329 * Space for the array will be allocated if any are found (must be freed by caller)
1330 *
1331 * @param arguments the arguments to scan for the double precision floating point array.
1332 * @param path path to look for in arguments. The path can be a simple path that is just the argument name.
1333 * But it can also use dot notation to reference the value deep inside json.
1334 * e.g. "jsonArray[1].bar"
1335 * @return NULL of not found.
1336 */
1337static double* getDoubleArray(Arguments* arguments, char* path, unsigned int* elementCount)
1338{
1339 return (double*)_getFloatArray(arguments, path, false, elementCount);
1340}
1341
1342static void* _getFloatArray(Arguments* arguments, char* path, bool forFloat, unsigned int* elementCount)
1343{
1344 // To store the floats/doubles found and return to caller
1345 void* theArray = NULL;
1346
1347 // To store the calculated element path
1348 char elementPath[strlen(path) + 10];
1349
1350 int numberOfFloatAllocated = 0, numberOfFloatsFound = 0;
1351
1352 FloatingPointValue* floatingPointValue;
1353 sprintf(elementPath, "%s[%d]", path, numberOfFloatsFound);
1354
1355 while ((floatingPointValue = getFloatingPointValue(arguments, elementPath))) {
1356 // If the floating point found is the same we're looking for ...
1357 if (floatingPointValue->isFloat == forFloat) {
1358 if (numberOfFloatAllocated == 0) { // allocate space if none allocated
1359 numberOfFloatAllocated += MIN_FLOAT_ALLOCATIONS;
1360 theArray = calloc(numberOfFloatAllocated, forFloat ? sizeof(float) : sizeof(double));
1361 if (theArray == NULL) {
1362 return NULL;
1363 }
1364 } else if (numberOfFloatAllocated
1365 <= numberOfFloatsFound) { // reallocate space is allocated space is used up
1366 numberOfFloatAllocated += MIN_FLOAT_ALLOCATIONS;
1367 theArray = realloc(theArray, numberOfFloatAllocated * (forFloat ? sizeof(float) : sizeof(double)));
1368 }
1369
1370 // Get the floating point value and store it in the target array
1371 if (forFloat) {
1372 ((float*)theArray)[numberOfFloatsFound] = floatingPointValue->value.floatValue;
1373 } else {
1374 ((double*)theArray)[numberOfFloatsFound] = floatingPointValue->value.doubleValue;
1375 }
1376 }
1377
1378 // Next element path
1379 sprintf(elementPath, "%s[%d]", path, ++numberOfFloatsFound);
1380 }
1381 *elementCount = numberOfFloatsFound;
1382 return theArray;
1383}
1384
1385/**
1386 * Determine if we are expecting json and/or whether we are expecting a value argument to have been provided
1387 *
1388 * @param argumentName
1389 * @param isArray
1390 * @param isValue
1391 * @param valueShouldBeJson
1392 */
1393static void expectingJsonOrValue(const char* argumentName, short isArray, short* isValue,
1394 short* valueShouldBeJson)
1395{
1396 if (strcasecmp(argumentName, "value") == 0) {
1397 (*isValue) = true;
1398 }
1399
1400 if (isArray || strchr(argumentName, '.') != NULL || strchr(argumentName, '[') != NULL) {
1401 (*valueShouldBeJson) = true;
1402 }
1403}
1404
1405/**
1406 * Parse out the format from the format specifier
1407 *
1408 * @param formatString the pointer to the format string
1409 * @param formatCharsToProcess count of format characters to process
1410 * @param format will store the one character format code
1411 * @param isRequired will store if this argument is required
1412 * @param isLong will store if the argument type is a long type
1413 * @param isShort will store if the argument type is a short type
1414 * @param isArray will store if this argument expecting an array
1415 */
1416static void parseFormatString(char* formatString, short formatCharsToProcess, char* format,
1417 short* isRequired, short* isLong, short* isShort, short* isArray)
1418{
1419 if (formatCharsToProcess && *formatString == FORMAT_OPTIONAL_FLAG) {
1420 (*isRequired) = false;
1421 formatCharsToProcess--;
1422 formatString++;
1423 }
1424
1425 if (formatCharsToProcess) {
1426 if (*formatString == FORMAT_PREFIX_SHORT) {
1427 (*isShort) = true;
1428 formatCharsToProcess--;
1429 formatString++;
1430 } else if (*formatString == FORMAT_PREFIX_LONG) {
1431 (*isLong) = true;
1432 formatCharsToProcess--;
1433 formatString++;
1434 }
1435 }
1436
1437 if (formatCharsToProcess) {
1438 (*format) = *formatString++;
1439 formatCharsToProcess--;
1440 }
1441
1442 if (formatCharsToProcess && *formatString == FORMAT_SUFFIX_ARRAY) {
1443 (*isArray) = true;
1444 }
1445}
1446
1447/**
1448 * Break a json path into the initial variable name and the remaining path.
1449 * e.g.
1450 * value.names[1]
1451 * is broken into
1452 * variableName = value
1453 * path = names[1]
1454 *
1455 * @param fullJsonPath the full json path to break
1456 * @param variableName to store the variable name
1457 * @param path to store the extracted path
1458 */
1459static void getJsonPathElements(char* fullJsonPath, char* variableName, char** path)
1460{
1461 char* firstDot = strchr(fullJsonPath, '.');
1462 char* firstParen = strchr(fullJsonPath, '[');
1463
1464 // If there are no path elements then return whole thing as variable and an empty path
1465 if (firstDot == NULL && firstParen == NULL) {
1466 strcpy(variableName, fullJsonPath);
1467 *path = &fullJsonPath[strlen(fullJsonPath)]; // The empty string
1468 return;
1469 }
1470
1471 char* relativeJsonPath = (firstDot == NULL || firstParen == NULL) ?
1472 MAX(firstDot, firstParen) :
1473 MIN(firstParen, firstDot);
1474 int lenRootArgument = (int)(relativeJsonPath - fullJsonPath);
1475
1476 if (*relativeJsonPath == '.') {
1477 relativeJsonPath++; // skip opening dot
1478 }
1479 memcpy(variableName, fullJsonPath, lenRootArgument);
1480 variableName[lenRootArgument] = 0x0;
1481 *path = relativeJsonPath;
1482}
1483
1484/**
1485 * Depending on the combination of options specified in a format string determine the target aida type
1486 *
1487 * @param env The JNI environment. Used in all functions involving JNI
1488 * @param format the format character of the format string
1489 * @param isArray true if the array indicator is set
1490 * @param isLong true if the long indicator is set
1491 * @param isShort true if the short indicator is set
1492 * @return the target aida type
1493 */
1494static Type getAidaType(JNIEnv* env, char format, short isArray, short isLong, short isShort)
1495{
1496 if (isArray) {
1497 if (isLong) {
1498 switch (format) {
1499 case FORMAT_INTEGER:
1500 return AIDA_LONG_ARRAY_TYPE;
1503 case FORMAT_FLOAT:
1505 default:
1506 break;
1507 }
1508 } else if (isShort) {
1509 switch (format) {
1510 case FORMAT_INTEGER:
1511 return AIDA_SHORT_ARRAY_TYPE;
1514 default:
1515 break;
1516 }
1517 } else {
1518 switch (format) {
1519 case FORMAT_INTEGER:
1523 case FORMAT_FLOAT:
1524 return AIDA_FLOAT_ARRAY_TYPE;
1525 case FORMAT_STRING:
1527 case FORMAT_BYTE:
1528 return AIDA_BYTE_ARRAY_TYPE;
1529 case FORMAT_BOOLEAN:
1531 default:
1532 break;
1533 }
1534 }
1535 } else {
1536 if (isLong) {
1537 switch (format) {
1538 case FORMAT_INTEGER:
1539 return AIDA_LONG_TYPE;
1542 case FORMAT_FLOAT:
1543 return AIDA_DOUBLE_TYPE;
1544 default:
1545 break;
1546 }
1547 } else if (isShort) {
1548 switch (format) {
1549 case FORMAT_INTEGER:
1550 return AIDA_SHORT_TYPE;
1553 default:
1554 break;
1555 }
1556 } else {
1557 switch (format) {
1558 case FORMAT_INTEGER:
1559 return AIDA_INTEGER_TYPE;
1562 case FORMAT_FLOAT:
1563 return AIDA_FLOAT_TYPE;
1564 case FORMAT_STRING:
1565 return AIDA_STRING_TYPE;
1566 case FORMAT_BYTE:
1567 return AIDA_BYTE_TYPE;
1568 case FORMAT_BOOLEAN:
1569 return AIDA_BOOLEAN_TYPE;
1570 default:
1571 break;
1572 }
1573 }
1574 }
1575
1576 aidaThrowNonOsException(env, AIDA_INTERNAL_EXCEPTION, "incorrect format string passed to ascanf() or avscanf()");
1577 return AIDA_NO_TYPE;
1578}
1579
1580/**
1581 * Make a single entry json_value array from a string. Use getJsonRoot() to get a
1582 * pointer to the array element directly.
1583 *
1584 * @param stringValue the string to add as the single entry in the json_value array
1585 * @return the single entry json_value array
1586 */
1587Value asArrayValue(char* stringValue)
1588{
1589 char arrayValueToParse[
1590 strlen(stringValue) + 20]; // Length of string plus strlen => {"_array": ["_"]} <= plus a couple of bytes
1591 if (isdigit(*stringValue)) {
1592 sprintf(arrayValueToParse, "{\"_array\": [%s]}", stringValue);
1593 } else {
1594 sprintf(arrayValueToParse, "{\"_array\": [\"%s\"]}", stringValue);
1595 }
1596 Value value;
1597 value.type = AIDA_NO_TYPE;
1598 value.value.jsonValue = json_parse(arrayValueToParse, strlen(arrayValueToParse));
1599 if (value.value.jsonValue) {
1600 value.type = AIDA_JSON_TYPE;
1601 }
1602 return value;
1603}
1604
1605/**
1606 * Return the corresponding array type of the given type.
1607 *
1608 * @param type the given type
1609 * @return the corresponding array type
1610 */
1611static Type tableArrayTypeOf(Type type)
1612{
1613 switch (type) {
1614 case AIDA_BOOLEAN_TYPE:
1616 break;
1617 case AIDA_BYTE_TYPE:
1618 type = AIDA_BYTE_ARRAY_TYPE;
1619 break;
1620 case AIDA_SHORT_TYPE:
1621 type = AIDA_SHORT_ARRAY_TYPE;
1622 break;
1623 case AIDA_INTEGER_TYPE:
1625 break;
1626 case AIDA_LONG_TYPE:
1627 type = AIDA_LONG_ARRAY_TYPE;
1628 break;
1629 case AIDA_FLOAT_TYPE:
1630 type = AIDA_FLOAT_ARRAY_TYPE;
1631 break;
1632 case AIDA_DOUBLE_TYPE:
1634 break;
1635 case AIDA_STRING_TYPE:
1637 break;
1638 default:
1639 break;
1640 }
1641 return type;
1642}
1643
1644/**
1645 * Return the corresponding data element size for the given type
1646 *
1647 * @param type the given type
1648 * @return the corresponding data element size
1649 */
1650static size_t tableElementSizeOfOf(Type type)
1651{
1652 size_t size;
1653
1654 switch (type) {
1655 case AIDA_BOOLEAN_TYPE:
1657 case AIDA_BYTE_TYPE:
1659 size = sizeof(unsigned char);
1660 break;
1661 case AIDA_SHORT_TYPE:
1663 size = sizeof(short);
1664 break;
1665 case AIDA_INTEGER_TYPE:
1667 size = sizeof(int);
1668 break;
1669 case AIDA_LONG_TYPE:
1671 size = sizeof(long);
1672 break;
1673 case AIDA_FLOAT_TYPE:
1675 size = sizeof(float);
1676 break;
1677 case AIDA_DOUBLE_TYPE:
1679 size = sizeof(double);
1680 break;
1681 case AIDA_STRING_TYPE:
1683 size = sizeof(char*);
1684 break;
1685
1686 default:
1687 size = 0;
1688 }
1689 return size;
1690}
1691
1692/**
1693 * Add a column to a Table specifying the type and element size
1694 *
1695 * @param table the Table to add the column to
1696 * @param aidaType the type of the column to add
1697 * @param elementSize the size of each element
1698 */
1699static void allocateTableColumn(JNIEnv* env, Table* table, Type aidaType, size_t elementSize)
1700{
1701 table->types[table->_currentColumn] = aidaType;
1702 table->ppData[table->_currentColumn] = ALLOCATE_MEMORY(env, table->rowCount * elementSize, "table data");
1703}
1704
1705/**
1706 * Determine if the given string value is a boolean value
1707 * @param stringValue string value
1708 * @return boolean or -1 if it is not a boolean value
1709 */
1710static int getBooleanValue(char* stringValue)
1711{
1712 if (strcasecmp(stringValue, "y") == 0
1713 || strcasecmp(stringValue, "1") == 0
1714 || strcasecmp(stringValue, "yes") == 0
1715 || strcasecmp(stringValue, "true") == 0
1716 || strcasecmp(stringValue, "t") == 0) {
1717 return true;
1718 }
1719 if (strcasecmp(stringValue, "n") == 0
1720 || strcasecmp(stringValue, "0") == 0
1721 || strcasecmp(stringValue, "no") == 0
1722 || strcasecmp(stringValue, "false") == 0
1723 || strcasecmp(stringValue, "f") == 0) {
1724 return false;
1725 }
1726 return -1;
1727}
#define CONVERT_FROM_VMS_FLOAT(_float, _count)
Convert in-place, floating point numbers from VMS to ieee format.
#define CONVERT_FROM_VMS_DOUBLE(_double, _count)
Convert in-place, doubles from VMS to ieee format.
#define PRINT_ERROR_FREE_MEMORY_AND_RETURN_(_exception, _errorText, _r)
Throw error message in an exception, free any allocated memory and return the error code.
#define ON_EXCEPTION_RETURN_VOID
Check to see if an exception has been raised, and return void,.
#define MISSING_REQUIRED_ARGUMENT_EXCEPTION
Use this string to signal Missing Required Argument Exceptions in aidaThrow()
#define ON_EXCEPTION_RETURN_(_r)
Check to see if an exception has been raised, and return the given return value.
#define AIDA_INTERNAL_EXCEPTION
Use this string to signal Internal Exceptions in aidaThrow()
#define SPRINTF_ERROR_FREE_MEMORY_AND_RETURN_(_exception, _errorText, _ref, _r)
Format an error message, throw it in an exception, free any allocated memory and return the error cod...
#define ON_EXCEPTION_FREE_MEMORY_AND_RETURN_(_r)
Check to see if an exception has been raised, then free tracked memory, and return the given return v...
#define UNABLE_TO_GET_DATA_EXCEPTION
Use this string to signal Exceptions when trying to Get Data in aidaThrow()
Value getArrayValue(JNIEnv *env, Arguments arguments)
Get value from the VALUE argument, in the provided Arguments structure, when the value is a scalar ar...
Value getValue(JNIEnv *env, Arguments arguments)
Get value from the VALUE request argument, in the provided Arguments structure, when the value is a s...
The Header File for the JNI helper functions.
#define TRACK_JSON(_ptr)
Register this newly allocated json value so that it will be freed by FREE_JSON_MEMORY.
#define ALLOCATE_STRING_AND_ON_ERROR_RETURN_VOID(_env, _var, _string, _purpose)
Allocate memory for a string and copy the given string into this allocated space The specified variab...
#define ALLOCATE_COPY_AND_TRACK_STRING_AND_ON_ERROR_RETURN_(_env, _var, _string, _purpose, _r)
Allocate and track a string.
#define ALLOCATE_MEMORY(_env, _size, _purpose)
Allocate memory.
#define TRACK_ALLOCATED_MEMORY
Create tracking variables so that memory can be freed with FREE_MEMORY macro.
#define ALLOCATE_FIXED_LENGTH_STRING_AND_ON_ERROR_RETURN_VOID(_env, _var, _string, _size, _purpose)
Allocate space for a fixed length string and copy date from the given string into the newly allocated...
#define FREE_MEMORY
Free any allocated memory.
#define ALLOCATE_MEMORY_AND_ON_ERROR_RETURN_(_env, _var, _size, _purpose, _r)
Allocate memory and on error return the given value.
#define FREE_TRACKED_MEMORY(_ptr)
Free a single tracked memory allocation and remove from list.
#define TRACK_MEMORY(_ptr)
Register this newly allocated memory so that it will be freed by FREE_MEMORY.
#define FREE_JSON
Free any allocated json memory.
Value getNamedArrayValue(JNIEnv *env, Arguments arguments, char *name)
Get value from a named argument in the provided arguments structure.
json_value * getJsonValue(Value *value, char *passedInPath)
Get the json value from the given value identified by the path.
Argument getArgument(Arguments arguments, char *name)
Get a named argument.
Value getNamedValue(JNIEnv *env, Arguments arguments, char *name)
Get value from a named argument in the provided arguments structure.
void aidaThrowNonOsException(JNIEnv *env, char *exception, const char *message)
To log any non-OS exceptions and throw back to java.
The Header File for the Native Channel Provider Server Helper functions.
Type
The definition of Aida Types.
@ AIDA_BYTE_TYPE
Represents a byte.
@ AIDA_SHORT_ARRAY_TYPE
Represents a short array.
@ AIDA_VOID_TYPE
Used when no return value is to be returned from a channel.
@ AIDA_UNSIGNED_INTEGER_TYPE
Represents an internal type of unsigned integer.
@ AIDA_UNSIGNED_LONG_ARRAY_TYPE
Represents an internal type of unsigned long array.
@ AIDA_UNSIGNED_SHORT_ARRAY_TYPE
Represents an internal type of unsigned short array.
@ AIDA_FLOAT_ARRAY_TYPE
Represents a float array.
@ AIDA_UNSIGNED_LONG_TYPE
Represents an internal type of unsigned long.
@ AIDA_BOOLEAN_ARRAY_TYPE
Represents a boolean array.
@ AIDA_INTEGER_ARRAY_TYPE
Represents an integer array.
@ AIDA_JSON_TYPE
Argument was provided as JSON text.
@ AIDA_STRING_TYPE
Represents a string.
@ AIDA_BYTE_ARRAY_TYPE
Represents a byte array.
@ AIDA_FLOAT_TYPE
Represents a float.
@ AIDA_INTEGER_TYPE
Represents an integer.
@ AIDA_SHORT_TYPE
Represents a short.
@ AIDA_LONG_ARRAY_TYPE
Represents a long array.
@ AIDA_STRING_ARRAY_TYPE
Represents a string array.
@ AIDA_LONG_TYPE
Represents a long.
@ AIDA_BOOLEAN_TYPE
Represents a boolean.
@ AIDA_UNSIGNED_INTEGER_ARRAY_TYPE
Represents an internal type of unsigned integer array.
@ AIDA_UNSIGNED_SHORT_TYPE
Represents an internal type of unsigned short.
@ AIDA_NO_TYPE
Used to indicate that no type was provided as an argument.
@ AIDA_DOUBLE_TYPE
Represents a double.
@ AIDA_DOUBLE_ARRAY_TYPE
Represents a double array.
@ AIDA_TABLE_TYPE
Represents a table.
void tableAddField(JNIEnv *env, Table *table, char *fieldName)
Add a dynamic field to a table.
void tableAddStringColumn(JNIEnv *env, Table *table, char **data)
Add a String column to the given Table.
void tableAddFixedWidthStringColumn(JNIEnv *env, Table *table, char *data, int width)
This reads data from an allocated space that is rows * width with each string occupying width charact...
void tableAddSingleRowFloatColumn(JNIEnv *env, Table *table, float data, bool ieeeFloat)
Add a float column to a Table with only one row.
int ascanf(JNIEnv *env, Arguments *arguments, const char *formatString,...)
ascanf(), avscanf()
void tableAddSingleRowLongColumn(JNIEnv *env, Table *table, long data)
Add a long column to a Table with only one row.
Table tableCreate(JNIEnv *env, int rows, int columns)
Make a Table for return to client.
void tableAddLabel(JNIEnv *env, Table *table, char *labelName)
Add a dynamic column to a table.
void tableAddSingleRowIntegerColumn(JNIEnv *env, Table *table, int data)
Add a integer column to a Table with only one row.
void tableAddSingleRowShortColumn(JNIEnv *env, Table *table, short data)
Add a short column to a Table with only one row.
void tableAddSingleRowByteColumn(JNIEnv *env, Table *table, unsigned char data)
Add a byte column to a Table with only one row.
void tableAddSingleRowDoubleColumn(JNIEnv *env, Table *table, double data, bool ieeeDouble)
Add a double column to a Table with only one row.
void tableAddSingleRowBooleanColumn(JNIEnv *env, Table *table, unsigned char data)
Add a boolean column to a Table with only one row.
void tableAddColumn(JNIEnv *env, Table *table, Type type, void *data, bool ieeeFormat)
Add a column of arbitrary type to a Table.
int avscanf(JNIEnv *env, Arguments *arguments, Value *value, const char *formatString,...)
ascanf(), avscanf()
void tableAddSingleRowStringColumn(JNIEnv *env, Table *table, char *data)
Add a string column to a Table with only one row.
Table tableCreateDynamic(JNIEnv *env, int rows, int columns)
Make a Dynamic Table for return to client.
The Header File for the Native Channel Provider AIDA-PVA type related functions.
#define FORMAT_SUFFIX_ARRAY
array format definition character for ascanf() and avscanf().
#define ASCANF_SET_BOOLEAN(_targetBoolean)
Macro used internally to set a scalar boolean for ascanf() and avscanf().
#define FORMAT_PREFIX_SHORT
short format definition character for ascanf() and avscanf().
#define FORMAT_BYTE
byte format definition character for ascanf() and avscanf().
#define MAX_FORMAT
Maximum length of s single format specifier for ascanf() and avscanf().
#define FORMAT_STRING
string format definition character for ascanf() and avscanf().
#define ASCANF_SET_BYTE(_targetByte)
Macro used internally to set a scalar byte for ascanf() and avscanf().
#define ASCANF_SET_BYTE_ARRAY
Macro used internally for setting a byte array for ascanf() and avscanf().
#define FORMAT_OPTIONAL_FLAG
optional format definition character for ascanf() and avscanf().
#define ASCANF_SET_STRING_ARRAY
Macro used internally to set a string array for ascanf() and avscanf().
#define MAX_FORMAT_SPECIFIERS
Maximum number of permitted format specifiers for ascanf() and avscanf().
#define ASCANF_SET_ARRAY(_format, _cType, _jsonType, _typeName)
Macro used internally to set an array for ascanf() and avscanf().
#define ASCANF_SET_STRING(_targetString)
Macro used internally to set a string for ascanf() and avscanf().
#define ASCANF_SET_BOOLEAN_ARRAY
Macro used to internally for setting a boolean array for ascanf() and avscanf().
#define FORMAT_UNSIGNED_INTEGER
unsigned int format definition character for ascanf() and avscanf().
#define FORMAT_FLOAT
float format definition character for ascanf() and avscanf().
#define FORMAT_PREFIX_LONG
long format definition character for ascanf() and avscanf().
#define ASCANF_SET_SCALAR(_format, _cType, _jsonType, _typeName, _target)
Macro used internally to set a scalar value for ascanf() and avscanf().
#define MIN_FLOAT_ALLOCATIONS
Minimum number of floating point allocations.
#define FORMAT_BOOLEAN
boolean format definition character for ascanf() and avscanf().
#define FORMAT_INTEGER
int format definition character for ascanf() and avscanf().
A single request argument.
char * value
The string value of the argument.
char * name
The name of the argument.
An Arguments structure stores all of the arguments passed from the request to the Native Channel Prov...
int floatingPointValuesCount
The number of floating point numbers in the arguments of this request.
FloatingPointValue * floatingPointValues
The array of FloatingPointValue.
Represents a floating point number.
char * path
The string path from the root of the json structure in which this value is found.
bool isFloat
Determines whether the value is a single or double precision floating point value.
FloatOrDoubleValue value
The floating point value.
Table structure.
int columnCount
number of columns in table
char ** ppLabels
the overridden label names. if null, not overridden. If not null then array of pointers to allocated ...
int _currentLabel
For internal use by addLabel() etc.
char ** ppFields
the overridden field names. if null, not overridden. If not null then array of pointers to allocated ...
Type * types
the scalar type of each column, one of BOOLEAN, BYTE, SHORT, INTEGER, LONG, FLOAT,...
void ** ppData
the data. an array of [rows][columns]
int _currentField
For internal use by addField() etc.
int rowCount
number of rows in table
int _currentColumn
For internal use by addColumn() etc.
This special type represents a Value.
ValueContents value
The value's contents, either a string or parsed json.
Type type
AIDA_STRING_TYPE or AIDA_JSON_TYPE.
double doubleValue
The double precision floating point value.
float floatValue
The single precision floating point value.
json_value * jsonValue
The parsed json_value of this Value if the type is AIDA_JSON_TYPE.
char * stringValue
The string value of this Value if the type is AIDA_STRING_TYPE.