pantoniou / libfyaml

Fully feature complete YAML parser and emitter, supporting the latest YAML spec and passing the full YAML testsuite.
MIT License
239 stars 73 forks source link

`fy_document_scanf' can not return the complete string including spaces. #95

Closed liyanrui closed 12 months ago

liyanrui commented 1 year ago

Here is a minimum example.

foo.yaml:

text: "hello yaml!"

foo.c:

#include <stdio.h>
#include <stdlib.h>
#include <libfyaml.h>

int main(void) {
        struct fy_document *fyd = fy_document_build_from_file(NULL, "foo.yaml");
        char text[256 + 1];
        int count = fy_document_scanf(fyd, "/text %256s", text);
        if (count != 1) {
                fprintf(stderr, "Failed to retreive the item!\n");
                exit(EXIT_FAILURE);
        }
        printf("text: %s\n", text);
        fy_document_destroy(fyd);
        return 0;
}

This program outputs

text: hello
q962 commented 1 year ago

https://github.com/pantoniou/libfyaml/blob/ce5149953e043541fb7ecca21691423aaad90513/src/lib/fy-doc.c#L6280

Unfortunately, no specific treatment is given. I am expecting two options

In fact, even if a width specifier is provided for %s, it is still impossible to include whitespace https://en.cppreference.com/w/c/io/fscanf

q962 commented 1 year ago

🤯

use %<number>c

The description of %c is very clear, but I didn't notice it


But it is a pity that the length variable is not supported.

I chose to directly write a function to implement it

char* _fy_node_get_string( struct fy_node* node, const char* name )
{
    struct fy_node* s = fy_node_by_path( node, name, -1, FYNWF_DONT_FOLLOW );
    if ( !fy_node_is_scalar( s ) )
        return NULL;

    size_t      len = 0;
    const char* str = fy_node_get_scalar( s, &len );
    return g_strndup( str, len );
}
liyanrui commented 12 months ago

@q962 Thanks your tips. I slightly modified your code and made a full minimum example.

#include <stdio.h>
#include <stdlib.h>
#include <libfyaml.h>

char* get_string_from_node(struct fy_node* node, const char* name) {
    struct fy_node* s = fy_node_by_path(node, name, -1, FYNWF_DONT_FOLLOW);
    if (!fy_node_is_scalar(s))
        return NULL;
    size_t      len = 0;
    const char* str = fy_node_get_scalar(s, &len);
        char *ret = malloc((len + 1) * sizeof(char));
        strncpy(ret, str, len);
        ret[len] = '\0';
    return ret;
}

int main(void) {
        struct fy_document *fyd = fy_document_build_from_file(NULL, "foo.yaml");
        struct fy_node *root = fy_document_root(fyd);
        char *s = get_string_from_node(root, "/text");
        printf("%s\n", s);
        free(s);
        fy_document_destroy(fyd);
        return 0;
}