Converting a C structure that contains a character array into an mJS string

I have a C structure which, amongst other things, contains an array of char, something like this:

typedef struct {
    char   name[32];
} my_struct;

So not a char * but an actual array of char in the struct.

I need to bring this into mJS, using s2o() and then convert it into an mJS string. Which of the MJS_STRUCT_FIELD_TYPE_* types should I declare this field as in my mjs_c_struct_member description and how should I go about converting it into an mJS string once it lands in mJS?

I’ve tried saying it’s MJS_STRUCT_FIELD_TYPE_DATA and then using the field that appears in mJS directly as a string but, when I attempt to print the string, mJS tells me unsupported object type so I guess that’s not the right approach.

1 Like

MJS_STRUCT_FIELD_TYPE_DATA and struct mjs_c_struct_member might help?

That’s what I’ve tried but it doesn’t seem to work for me. Here’s my C structure, where d_name is the field in question:

typedef struct {
    int32_t        d_ino;
    int32_t        d_off;
    uint16_t       d_reclen;
    uint16_t       d_type;
    char           d_name[NAME_MAX];
} cbFS_dirent_t;

I describe it for s2o as follows:

static const struct  mjs_c_struct_member fsDirEntryDescription[] = {
    { "d_ino", offsetof(cbFS_dirent_t, d_ino), MJS_STRUCT_FIELD_TYPE_INT, NULL },
    { "d_off", offsetof(cbFS_dirent_t, d_off), MJS_STRUCT_FIELD_TYPE_INT, NULL },
    { "d_reclen", offsetof(cbFS_dirent_t, d_reclen), MJS_STRUCT_FIELD_TYPE_UINT16, NULL },
    { "d_type", offsetof(cbFS_dirent_t, d_type), MJS_STRUCT_FIELD_TYPE_UINT16, NULL },
    { "d_name", offsetof(cbFS_dirent_t, d_name), MJS_STRUCT_FIELD_TYPE_DATA, NULL },
    { NULL, 0, MJS_STRUCT_FIELD_TYPE_INVALID, NULL }
};

static const struct mjs_c_struct_member *mjsApiFsDirEntryDescription()
{
    return fsDirEntryDescription;
}

static int mjsApiFsDirEntrySize()
{
    return sizeof(cbFS_dirent_t);
}

So in mJS the code is:

let DirRead = function(dir) {
    let result;
    let entryC = c.malloc(ffi('int mjsApiFsDirEntrySize()')());

    if (entryC !== 0) {
        let retValue = ffi('int mjsApiFsReadDirR(void *, void *)')(dir, entryC); // Call the C function that fills in entryC
        if (retValue === 0) {
            let entryDescription = ffi('void *mjsApiFsDirEntryDescription()')();
            let entryJs = s2o(entryC, entryDescription);
            print("d_ino: ", entryJs.d_ino, ".\n");
            print("d_off: ", entryJs.d_off, ".\n");
            print("d_reclen: ", entryJs.d_reclen, ".\n");
            print("d_type: ", entryJs.d_type, ".\n");
            print("d_name: \"", entryJs.d_name, "\".\n");
            result.type = entryJs.d_type;
            // Since  entryJs.d_name doesn't seem to be a string, I've tried doing this also but this gives me the "unsupported object type" error
            result.name =  mkstr(entryJs.d_name, 0, c.strlen(entryJs.d_name), true);
            print("result.name: \"", result.name, "\".\n");
        }
        c.free(entryC);
    }

When I run this, in the C function that fills in the struct I print out the values of the fields:

d_ino 65568, d_off 0, d_reclen 24, d_type 8, d_name "at_client.js"

…but in mJS what I get is:

d_ino:  65568 .
d_off:  0 .
d_reclen:  24 .
d_type:  8 .
d_name: "  ".
MJS Print: unsupported object type

As you can see, the numbers are correct but the string is nowhere to be seen. What am I doing wrong?

From the links above, I understand that the last argument of { "d_name", offsetof(cbFS_dirent_t, d_name), MJS_STRUCT_FIELD_TYPE_DATA, NULL }, should be NAME_MAX (from char d_name[NAME_MAX])

1 Like

Ooo, I thought the last argument of each structure description line was only relevant in nested or custom structure descriptions; at least, that’s the only place it’s non-NULL in the readme.md. Is it actually a size field as well?

Ah, yes, I see from mjs.h that it is. So the description line becomes:

{ "d_name", offsetof(cbFS_dirent_t, d_name), MJS_STRUCT_FIELD_TYPE_DATA, (void *) NAME_MAX }

…and in mJS I now get the correct(ish) contents in d_name (not sure why all the nulls are being printed if it has become a string):

d_ino:  65568 .
d_off:  0 .
d_reclen:  24 .
d_type:  8 .
d_name: "at_client.js\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00..."

…but when I assign the result to another mJS variable (in order to return it from the function) and print that variable:

            result.name =  entryJs.d_name;
            print("result.name: \"", result.name, "\".\n");

…mJS still gives me:

MJS Print: unsupported object type

What am I doing wrong? Is it somehow not a true mJS string and still needs to be converted into one?

mJS returns a string of length NAME_MAX. The useful part is from the beginning up to the terminating null character of the C string.
Try this:

let DirRead = function (dir) {
  let result = {}; /* fix unsupported object type */
  /* function body */
      let nullPosition = entryJs.d_name.indexOf('\x00');
      result.name = entryJs.d_name.slice(0, nullPosition);

I was thinking of doing that but I’ve just realised the problem is not quite what I thought it was.

The “unsupported object type” error is occurring not when assigning the string but on the line before, when assigning d_type to an mJS variable (see below). In the conversion from a C structure that field is a uint16_t: how do I get mJS to see it as an int?

let entryDescription = ffi('void *mjsApiFsDirEntryDescription()')();
let entryJs = s2o(entryC, entryDescription);
print("d_ino: ", entryJs.d_ino, ".\n");
print("d_off: ", entryJs.d_off, ".\n");
print("d_reclen: ", entryJs.d_reclen, ".\n");
print("d_type: ", entryJs.d_type, ".\n");
print("d_name: \"", entryJs.d_name, "\".\n");
print("Assigning entryJs.d_type to result.type...\n");
result.type = entryJs.d_type;
print("Converting to tidy string...\n");
let nullPosition = entryJs.d_name.indexOf('\x00');
result.name = entryJs.d_name.slice(0, nullPosition);
print("Printing result.name...\n");
print("result.name: \"", result.name, "\".\n");
d_ino:  65568 .
d_off:  0 .
d_reclen:  24 .
d_type:  8 .
d_name: "at_client.js\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00..."
Assigning entryJs.d_type to result.type...
MJS Print: unsupported object type

This line will solve that error:

  let result = {};
1 Like

Magic! One day I will understand JS, C is sooo much simpler ;-).

I agree :smile:
That’s why I don’t use mJS.

1 Like