LabVIEW Call Library Function yielding array of strings - c

I need to interface C code to LabVIEW, and my C function needs to give back a two dimensional array of strings. I would rather not be forced to predetermine the size of the array in advance. So I want to know, what is the right data format to use (handle to array of C string pointers? Handle to array of string handles?), how to properly do the allocation, and whether it is better to use an array parameter or a return type. The dialog provided for Call Library Function Node only supports arrays of numeric types, so I'm a little bit lost on how to structure this.

You need the LabVIEW Code Interface Reference Manual to figure this stuff out.
You are writing a C function that will return a 2D array of strings to LabVIEW. That means you need to be returning LabVIEW's data structure and using LabVIEW's memory allocator. Include "extcode.h" in your C file (ships with LabVIEW). Then create the following C code:
#include "extcode.h"
struct String2DArrayBlock {
int32 dimensionSize1;
int32 dimensionSize2;
LStrHandle stringArray[1]; // Yes, this is intentional. Do not use LStrHandle* because that syntax changes the memory allocation. Old-school C code. LabVIEW's own C++ code has wrappers for managing this with more type safety.
};
typedef String2DArrayBlock** String2DArrayHandle;
MgErr GenerateMyStrings(String2DArrayHandle *ptrToHandle) {
if (!ptrToHandle)
return mgArgErr; // Gotta pass a location for us to allocate.
if (*ptrToHandle) {
// This handle is already allocated. I'm not going to walk you through all the code needed to deallocate.
return mgArgErr;
}
const int32 dimSize1 = ComputeHeight(); // This is your function... whereever your data is coming from.
const int32 dimSize2 = ComputeWidth(); // Same here.
const int32 numberOfElements = dimSize1 * dimSize2;
if (numberOfElements == 0) {
return mgNoErr; // Done. NULL means empty array, and the handle is already NULL.
}
// DSNewHClr allocates the block and flood fills it with all zeros.
*ptrToHandle = (String2DArrayHandle)DSNewHClr(sizeof(String2DArrayBlock) + ((numberOfElements - 1) * sizeof(LStrHandle))); // -1 because the sizeof block has 1 element.
if (!*ptrToHandle)
return mFullErr; // Out of memory
(**ptrToHandle)->dimensionSize1 = dimSize1;
(**ptrToHandle)->dimensionSize2 = dimSize2;
LStrHandle *current = (**ptrToHandle)->stringArray;
for (int32 i = 0; i < numberOfElements; ++i, ++current) {
std::string myCurrentString = GetMyCurrentString(i); // You write this however you look up the individual strings.
if (myCurrentString.empty())
continue; // NULL means empty string
*current = (LStrHandle)DSNewHClr(sizeof(LStr)); // Allocates a zero-length LStrHandle.
if (!*current)
return mFullErr; // The array will be partially filled, but it is in a safe state for early return.
MgErr err = LStrPrintf(*current, (CStr)"%s", myCurrentString.c_str());
if (err)
return err; // The array will be partially filled, but it is in a safe state for early return.
}
return mgNoErr;
}
Compile your code against the LabVIEW run-time engine (lvrt.dll).
In your G code, drop a Call Library Node, add a parameter that is "Adapt to type" and "Pointers to Handles", and wire it with an empty 2D array. And you're done.

Related

Best way to pass address of "char path[MAX]" to a param of "const char*" in Swift

I realize there are a million variations of the "how do I convert char[]/char* to a Swift Sting" question out there, and their inverse, all of which have been asked and answered.
I'm not asking that.
All I want to do, in Swift, is to simply pass the address of a C char array (obtained via a C function) to the C char* pointer argument of another C function.
Specifically, I'm trying to replicate the following C code, where the address of the char array contained in the stat.f_mntonname field gets passed as the first parameter of getattrlist(const char*, ...) call:
// Get volume stat
const char* path = ...;
struct statfs volStat;
if (statfs(path,&volStat)==-1) { error }
// statfs has the mount point of the volume; use that to get attributes
struct attrlist request;
// ... set up request here
struct volAttrs {
// ... response values
}
if (getattrlist(volStat.f_mntonname,&request,&volAttrs,sizeof(volAttrs),FSOPT_NOFOLLOW)==-1) { error }
The problem seems to be that Swift interprets the stat.f_mntonname field, not as an array, but as a tuple containing MAXPATHLEN number of Int8 values; in other words, (Int8,Int8,Int8,Int8,Int8,...,Int8).
After much poking around on the internet, I was ultimately able to find this workaround:
var volStat = statfs()
guard statfs(fileURL.path, &volStat) != -1 else {
ErrorExit(cause: "statfs")
}
var attrRequest = attrlist()
// set up getattrlist request ...
var attrs = XtraVolumeAttrs()
guard getattrlist(UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN)),
&attrRequest,
&attrs,
MemoryLayout<XtraVolumeAttrs>.size,
UInt32(FSOPT_NOFOLLOW)) != -1 else {
ErrorExit(cause: "getattrlist")
}
So the magic UnsafeRawPointer(&volStat.f_mntonname.0).bindMemory(to: CChar.self, capacity: Int(MAXPATHLEN) seems to accomplish the task of casting the char[MAXPATHLEN] array into a char*, but boy is it ugly, unintuitive, and—if I'm being completely honest—I'm not even sure this is correct (other than the fact that the code works).
I feel there's got to be a better way and I was hoping someone would post it.
It is ugly because Swift imports C arrays as tuples, and there is no automatic conversion to arrays or pointers.
As pointed out by Hamish, the use of UnsafeRawPointer(&volStat.f_mntonname.0) is incorrect, because the created pointer might be invalid on return from the initializer.
A safe version is
let retval = withUnsafeBytes(of: volStat.f_mntonname) {
getattrlist($0.bindMemory(to: Int8.self).baseAddress, /* other args */)
}
Here bindMemory() is called on the “buffer pointer” covering the raw bytes of the tuple, so that we don't have to specify the capacity explicitly.

How do i count the size of an str-type array?

I am currently creating a function that needs to append new str elements to an already existing array that I don't really know the size of since every str does not have the same size.
I tried using the sizeof() function but since I don't know the size of every str I don't see it working. I also tried to use a technique I found:
char* liste[]={"one","two","three","four","five"};
int size = *(&liste + 1) - liste;
printf(size);
Instead of a size I get a "Program Received signal SIGSEGV"
Remember that double-quoted string literals in C—and all arrays for that matter—generally act like pointers (for string literals, specifically, they act like char*s). In this case you've created an array of pointers to arrays of chars; the outermost array's size is the size of a pointer, times the number of elements. (All the strings themselves are stored somewhere else.)
If you want to get the number of elements, and that's known at compile-time, you can use sizeof(liste)/sizeof(liste[0]). If it's not known at compile-time, you'll have to add some other way of tracking it, such as a NULL at the end or a separate variable holding the size. (Double-quoted strings use this first option: "hello" is roughly equivalent to ['h', 'e', 'l', 'l', 'o', 0].)
As far as the SIGSEGV, though: printf takes a string—that is, a pointer—as its first argument. When you give it a number, it tries to use it as a pointer, runs head-first into some memory it's not supposed to access, and the operating system kills it with SIGSEGV. The proper way to print a number is something like printf("%d", my_int).
NOTE: sizeof(liste) will no longer return the full size of the array in Windows, but only the size of the pointer. The standard libraries in Windows have quietly changed this to allow for use of their additional libraries such as std:array and std::iterator. You will need to use the functions from these libraries or create your own methods to count the elements. This is a sample for those that cannot use std::array or std::iterator due to library conflicts or other reasons.
size_t SizeOfArray(std::string* inComing)
{
size_t outGoing = 0;
bool end = false;
// Validate Array
if (inComing != NULL)
{
// Appended arrays can be valid or not. Sometimes earlier cleanup
// will link to an empty array location, so check for empty and invalid.
while ((!end) && (inComing[outGoing].size() != 0))
{
__try
{
// if an appended memory location has value, but is not an array
// you look for the NULL character. For wstrings change '\0' to L'\0'.
// If the memory location is not valid, it will throw the exception.
if (inComing[outGoing].c_str()[inComing[outGoing].length()] != '\0')
{
// End of array - if nice empty value
end = true;
}
else
{
outGoing++; // Count each valid string in the array
}
}
// This is the blank exception catch to an extra element that is not
// valid.
__except (EXCEPTION_EXECUTE_HANDLER)
{
// End of array - if unknown value
end = true;
}
}
}
return outGoing; // Return the count
}

Using hashmap in C to store String - Integer mapping once and use for entire program run

I have my own implementation of C hash_map_t struct that I can use as below?
// string value allocator
allocator_t *str_value_allocator;
allocator_init(&str_value_allocator, string_allocate_handler, string_deallocate_handler);
str_hash_map_init(&str_hash_map, str_value_allocator, 5);
str_hash_map_put(str_hash_map, test_key, test_val, strlen(test_val));
str_hash_map_get(str_hash_map, test_key, NULL)
str_hash_map_remove(str_hash_map, test_key)
str_hash_map_free(str_hash_map);
I would like to use this hash map in function like below:
void handle_keyboard_input(char **tokens, size_t num_tokens) {
char *virtual_key_name = strtok(tokens[1], " ");
size_t num_flags = 0;
char **modifier_flags = str_split(tokens[2], ", ", &num_flags);
// map virtual_key_name (char *) to virtual_key code (int)
// foreach modifier flag (char *) map to modifier flag code (int)
}
I can create 2 hash_maps for key_name -> key_code mapping and flag_name -> flag_code mapping. The problem is that I don't want to create this flag each time the request handler function is called but have only one data structure instance from first call of the function and in successive function invocations I want to reuse this data structure (data store) already created.
My hash_map is created on the heap so there isn't possibility to allocate it like the array somewhere inside library source code file.
In Java or even C++ I could create some Singleton pattern or static member but such concept is not available in C language. Probably I could create this hash_map at program startup somewhere at the beginning of program but how could I pass reference to library used by the program.
My recent idea was to use static hash_map_t variable inside my handle_keyboard_input function and somehow initialised it only when it is NULL (the first function call), and if variable isn't NULL in successive calls just reuse previously initialised hash_map_t structure.
What will be the best approach to this problem?
UPDATE
Could I use such code?
static str_hash_map_t *virtual_keys_map = NULL;
static str_hash_map_t *modifier_flags_map = NULL;
if (virtual_keys_map == NULL) {
virtual_keys_map_init(&virtual_keys_map);
}
if (modifier_flags_map == NULL) {
modifier_flags_map_init(&modifier_flags_map);
}
Since this appears to be a library, you have several options:
You can make your library more "object oriented" and force the user to do the proper instantiation. For example, you would have your ADT struct defined as KeyboardHandler, and then your handle_keyboard_input would look something like this instead:
void KH_handle_input(KeyboardHandler self, char **tokens, size_t num_tokens);
Which means the caller is now responsible for doing the instantiation of that single part:
// caller must get the ADT instance at some point, and you don't care when
KeyboardHandler kh = KH_init();
KH_handle_input(kh, some_tokens, num_tokens);
// some other part can be initialized later
MouseHandler mh = MH_init();
MH_handle_input(mh, some_tokens, num_tokens);
It's possible to create a library initializer for both Windows and POSIX dlls. So you can let this be done automatically instead.
Otherwise, it seems like you will have to make this "check" anytime your functions want to use this potentially-uninitialized hash tables (perhaps it's a single function, but anyway). In which case, I would at least refactor it into a separate function:
void handle_keyboard_input(char **tokens, size_t num_tokens) {
initialize_hashes_if_needed();
// ...and then the rest of the function
}
The reasoning is that you don't want to have to modify several functions if you decide there is something else that needs to be malloced.
Yes, code above cause that pointers will be initialised just once (or if you set them to NULL, condition will be true and it will init again) and stay in memory even if you get outside of function.
The lifetime of function static variables begins the first time the program flow encounters the declaration and it ends at program termination - in other words they are global variables.
Also the name of this variable is only accessible within the function, and has no linkage.
Still need to take great care if you think you need a globally-accessible variable. Read here.
static str_hash_map_t *virtual_keys_map = NULL;
static str_hash_map_t *modifier_flags_map = NULL;
if(virtual_keys_map == NULL) {
virtual_keys_map_init(&virtual_keys_map);
}
if(modifier_flags_map == NULL) {
modifier_flags_map_init(&modifier_flags_map);
}

COpaquePointer to an arbitrary byte in a block of memory

I'm porting some code to Swift, but I'm confused about how to handle pointers.
In Swift, how do you create an empty block of memory, in such a manner that C functions can access it?
C source:
UInt8* bytes = malloc( qty_bytes_in_file );
..and, after so-doing, how would you create a pointer to an arbitrary offset of that memory? I'll need to repeatedly move the pointers to various addresses in this block of memory, to which a C function will then write data.
C source:
void* mData = &bytes[i];
Here's an abbreviated version of the C code with which I'm starting, so you can see both lines in context:
C source:
UInt8* bytes = malloc( qty_bytes_in_file ); // Swift equivalent?
while ( !err ) {
AudioBufferList buffer_list = new_buffer_list();
buffer_list.mBuffers[0].mData = &bytes[i]; // Swift equivalent?
// each iteration, ExtAudioFileRead fills
// in a portion of buffer_list's '.mData':
err = ExtAudioFileRead(
audio_file,
&qty_frames_requested,
&buffer_list
);
i += foo;
}
For the first question I would just make an array of byte values:
var bytes = Array<UInt8>(count: qty_bytes_in_file, repeatedValue: 0)
And I think you can provide a reference to that array as an in-out parameter. For example:
let stream = NSInputStream(data: someNSDataObject)
let numberOfBytesRead = stream.read(&bytes, maxLength:buffer.count)
There is also in Swift a wrapper available …
struct UnsafePointer<T>
… with a "memory" property to get to the raw underlying memory.

Using malloc with a structure and strcpy

I'm attempting to make an array of the structure I made called StatusItem, which looks like this:
typedef struct
{
char* name;
char* index;
int optional;
} StatusItem;
Also, as I want this array to be of any size, I am using malloc. So the array is defined as such:
StatusItem* statusItem = NULL;
(its then passed to function which retrieves all the values as follows.)
statusItem = (StatusItem*)malloc(cJSON_GetArraySize(items));
...
for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
strcpy(statusItem[i].name,name->valuestring);
strcpy(statusItem[i].index,index->valuestring);
if(!parseInt(optional->valuestring, &statusItem[i].optional));
{
goto cleanup;
}
}
There's come code that involves the cJSON library in getting the string values of name, index and optional into the variables referenced above, and they are stored in the valuestring field of those variables.
I have checked that everything involving the cJSON library works fine, and returns the correct values, but the program is unable to access or store values in the statusItems array.
Any ideas? I'm almost positive that it involves some misuse of malloc on my part.
1) cJSON_GetArraySize(items) returns an element count - you need the size of the object factored in: malloc(cJSON_GetArraySize(items) * sizeof(StatusItem))
2) a StatusItem structure doesn't have memory for the actual string - only a pointer to a string. You can use strdup() to allocate and copy a string.
You probably want your code to look more like:
statusItem = (StatusItem*)malloc(cJSON_GetArraySize(items) * sizeof(StatusItem));
...
for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
statusItem[i].name = strdup(name->valuestring);
statusItem[i].index = strdup(index->valuestring);
if(!parseInt(optional->valuestring, &statusItem[i].optional));
{
goto cleanup;
}
}
Of course this means that you also have to free the duplicated strings explicitly when you free the array of StatusItem objects:
// to free the statusItem array, and the various strings it refers to:
for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
free(statusItem[i].name);
free(statusItem[i].index);
}
free(statusItem);
Two misuses spotted:
Don't cast the return value of malloc(), it's dangerous and superfluous.
You don't allocate any memory for the members of the structure - you're strcpy()ing to uninitialized pointers, so your program invokes undefined behavior.
Edit: actually three:
malloc(cJSON_GetArraySize(items));
doesn't allocate enough memory since it's not magic and it doesn't know you're reserving sizeof(StatusItem) bytes of memory, thus you have to multiply the allocation size by sizeof(StatusItem), or even better, by sizeof(*statusItem) for safety.
In addition, malloc takes a number of bytes, not elements. The value passed to it must be multiplied by the size of each element.
To avoid having to use strdup() which is a little 'messier' because it leaves the freeing of the memory up to the caller instead of taking care of everything itself, I modified my existing structure as follows:
typedef struct
{
char name[32];
char index[32];
int optional;
} StatusItem;
This allows 32 bytes for the name and index, which should be more than enough. Before, the structures fields were pointing to nothing, which was causing the error when trying to copy to that location. now, there is empty (or junk) memory waiting for the string to be placed in.
This allows for strcpy() to still be used, and allows for an overall cleaner implementation.

Resources