Affix

 view release on metacpan or  search on metacpan

lib/Affix.c  view on Meta::CPAN

        sv_setpv(sv, (const char *)c_ptr);
}

static void pull_pointer_as_struct(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    void * c_ptr = *(void **)ptr;
    if (c_ptr == nullptr)
        sv_setsv(sv, &PL_sv_undef);
    else {
        const infix_type * pointee_type = type->meta.pointer_info.pointee_type;
        pull_struct(aTHX_ affix, sv, pointee_type, c_ptr);
    }
}

static void pull_struct_as_live(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    void * c_ptr = *(void **)ptr;
    if (c_ptr == nullptr) {
        sv_setsv(sv, &PL_sv_undef);
        return;
    }
    const infix_type * pointee_type = type->meta.pointer_info.pointee_type;
    HV * hv = newHV();
    SV * rv = newRV_noinc(MUTABLE_SV(hv));
    sv_bless(rv, gv_stashpv("Affix::Live", GV_ADD));
    _populate_hv_from_c_struct(aTHX_ affix, hv, pointee_type, c_ptr, true, nullptr);
    sv_setsv(sv, rv);
    SvREFCNT_dec(rv);
}

static void pull_pointer_as_array(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    void * c_ptr = *(void **)ptr;
    if (c_ptr == nullptr)
        sv_setsv(sv, &PL_sv_undef);
    else {
        const infix_type * pointee_type = type->meta.pointer_info.pointee_type;
        pull_array(aTHX_ affix, sv, pointee_type, c_ptr);
    }
}

static void pull_pointer_as_pin(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    void * c_ptr = *(void **)ptr;

    if (c_ptr == nullptr) {
        sv_setsv(sv, &PL_sv_undef);
        return;
    }

    Affix_Pin * pin;
    Newxz(pin, 1, Affix_Pin);
    pin->pointer = c_ptr;

    // Ensure we point to the content type, not Pointer[Content]
    pin->type = _unwrap_pin_type(type);
    pin->managed = false;

    SV * obj_data = newSV(0);
    sv_setiv(obj_data, PTR2IV(pin));

    // Create the Reference
    SV * rv = sv_2mortal(newRV_noinc(obj_data));

    // Bless into Affix::Pointer BEFORE attaching magic to avoid triggering 'set' during blessing
    (void)sv_bless(rv, gv_stashpv("Affix::Pointer", GV_ADD));

    MAGIC * mg = sv_magicext(obj_data, nullptr, PERL_MAGIC_ext, &Affix_pin_vtbl, nullptr, 0);
    mg->mg_ptr = (char *)pin;

    // Update the target SV
    sv_setsv(sv, rv);
}

static void pull_sv(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    void * c_ptr = *(void **)ptr;
    if (c_ptr == nullptr)
        sv_setsv(sv, &PL_sv_undef);
    else
        sv_setsv(sv, (SV *)c_ptr);
}

static void pull_file(pTHX_ Affix * affix, SV * sv, const infix_type * type, void * ptr) {
    PERL_UNUSED_VAR(affix);
    PERL_UNUSED_VAR(type);
    FILE * fp = *(FILE **)ptr;
    if (!fp) {
        sv_setsv(sv, &PL_sv_undef);
        return;
    }

    // Duplicate FD to avoid double-close issues
    int fd =
#ifdef _WIN32
        _fileno
#else
        fileno
#endif
        (fp);
    if (fd < 0) {
        sv_setsv(sv, &PL_sv_undef);
        return;
    }

    int new_fd = PerlLIO_dup(fd);
    if (new_fd < 0) {
        sv_setsv(sv, &PL_sv_undef);
        return;
    }

    PerlIO * new_pio = PerlIO_fdopen(new_fd, "r+");  // Assuming R/W safe
    if (!new_pio) {
        PerlLIO_close(new_fd);
        sv_setsv(sv, &PL_sv_undef);
        return;
    }

    GV * gv = newGVgen("Affix::FileHandle");
    if (do_open(gv, "+<&", 3, FALSE, 0, 0, new_pio))
        sv_setsv(sv, sv_2mortal(newRV((SV *)gv)));
    else {
        PerlIO_close(new_pio);
        sv_setsv(sv, &PL_sv_undef);
    }
}

lib/Affix.c  view on Meta::CPAN

    }
    else {
        Newxz(pin, 1, Affix_Pin);
        mg = sv_magicext(sv, nullptr, PERL_MAGIC_ext, &Affix_pin_vtbl, nullptr, 0);
    }
    // Re-assign mg_ptr because sv_magicext(..., 0) likely corrupted it by treating pin as a string
    mg->mg_ptr = (char *)pin;

    pin->pointer = pointer;
    pin->managed = managed;
    pin->bit_offset = bit_offset;
    pin->bit_width = bit_width;

    if (owner_sv) {
        pin->owner_sv = owner_sv;
        SvREFCNT_inc(pin->owner_sv);
    }

    pin->type_arena = infix_arena_create(2048);
    if (!pin->type_arena) {
        safefree(pin);
        mg->mg_ptr = nullptr;
        croak("Failed to create memory arenas for pin's type information");
    }
    pin->type = _copy_type_graph_to_arena(pin->type_arena, type);
    if (!pin->type) {
        infix_arena_destroy(pin->type_arena);
        safefree(pin);
        mg->mg_ptr = nullptr;
        croak("Failed to copy type information into pin");
    }
}
XS_INTERNAL(Affix_find_symbol) {
    dXSARGS;
    dMY_CXT;  // Require the thread-local context
    if (items != 2 || !sv_isobject(ST(0)) || !sv_derived_from(ST(0), "Affix::Lib"))
        croak_xs_usage(cv, "Affix_Lib_object, symbol_name");
    IV tmp = SvIV((SV *)SvRV(ST(0)));
    infix_library_t * lib = INT2PTR(infix_library_t *, tmp);
    const char * name = SvPV_nolen(ST(1));
    void * symbol = infix_library_get_symbol(lib, name);
    if (symbol) {
        Affix_Pin * pin;
        Newxz(pin, 1, Affix_Pin);
        pin->pointer = symbol;
        pin->managed = false;
        pin->owner_sv = ST(0);
        SvREFCNT_inc(pin->owner_sv);
        pin->type_arena = infix_arena_create(256);
        infix_type * void_ptr_type = nullptr;
        if (infix_type_create_pointer_to(pin->type_arena, &void_ptr_type, infix_type_create_void()) != INFIX_SUCCESS) {
            safefree(pin);
            infix_arena_destroy(pin->type_arena);
            croak("Internal error: Failed to create pointer type for pin");
        }
        pin->type = void_ptr_type;
        SV * obj_data = newSV(0);
        sv_setiv(obj_data, PTR2IV(pin));
        SV * rv = newRV_inc(obj_data);

        // Bless into Affix::Pointer BEFORE attaching magic to avoid triggering 'set' during blessing
        (void)sv_bless(rv, gv_stashpv("Affix::Pointer", GV_ADD));

        MAGIC * mg = sv_magicext(obj_data, nullptr, PERL_MAGIC_ext, &Affix_pin_vtbl, nullptr, 0);
        mg->mg_ptr = (char *)pin;
        ST(0) = sv_2mortal(rv);
        XSRETURN(1);
    }
    XSRETURN_UNDEF;
}

XS_INTERNAL(Affix_pin) {
    dXSARGS;
    dMY_CXT;
    if (items != 4)
        croak_xs_usage(cv, "var, lib, symbol, type");
    SV * target_sv = ST(0);
    const char * lib_path_or_name = SvPV_nolen(ST(1));
    const char * symbol_name = SvPV_nolen(ST(2));
    const char * signature = SvPV_nolen(ST(3));
    infix_library_t * lib = infix_library_open(lib_path_or_name);
    if (lib == nullptr) {
        warn("Failed to load library from path '%s' for pinning: %s", lib_path_or_name, infix_get_last_error().message);
        XSRETURN_UNDEF;
    }
    void * ptr = infix_library_get_symbol(lib, symbol_name);
    infix_library_close(lib);
    if (ptr == nullptr) {
        warn("Failed to locate symbol '%s' in library '%s'", symbol_name, lib_path_or_name);
        XSRETURN_UNDEF;
    }
    infix_type * type = nullptr;
    infix_arena_t * arena = nullptr;
    const char * sig_to_parse = signature;
    char * clean_sig = nullptr;
    if (strstr(signature, "+")) {
        clean_sig = savepv(signature);
        const char * p = signature;
        char * d = clean_sig;
        while (*p) {
            // Strip '+' only if it precedes a signature character: * [ { ! < ( @
            if (*p == '+' &&
                (p[1] == '*' || p[1] == '[' || p[1] == '{' || p[1] == '!' || p[1] == '<' || p[1] == '(' || p[1] == '@'))
                p++;
            else
                *d++ = *p++;
        }
        *d = '\0';
        sig_to_parse = clean_sig;
    }

    if (infix_type_from_signature(&type, &arena, sig_to_parse, MY_CXT.registry) != INFIX_SUCCESS) {
        SV * err_sv = _format_parse_error(aTHX_ "for pin", sig_to_parse, infix_get_last_error());
        warn_sv(err_sv);
        if (arena)
            infix_arena_destroy(arena);
        if (clean_sig)
            safefree(clean_sig);
        XSRETURN_UNDEF;
    }
    _pin_sv(aTHX_ target_sv, type, ptr, false, nullptr, 0, 0);

lib/Affix.c  view on Meta::CPAN

             * Primitives expect a pointer to the value.
             * 'ptr_val' IS the address of the value. We pass 'ptr_val'.
             * The handler reads *(int*)ptr_val.
             */
            ptr2sv(aTHX_ nullptr, ptr_val, ret_val, new_type);
        }

        infix_arena_destroy(parse_arena);
        ST(0) = ret_val;
    }
    else {
        /* Return Alias Pin */
        Affix_Pin * new_pin;
        Newxz(new_pin, 1, Affix_Pin);
        new_pin->pointer = ptr_val;
        new_pin->managed = false;
        new_pin->type_arena = parse_arena;

        if (pin) {
            new_pin->owner_sv = pin->owner_sv ? pin->owner_sv : arg;
            SvREFCNT_inc(new_pin->owner_sv);
        }

        if (new_type->category == INFIX_TYPE_POINTER)
            new_pin->type = _unwrap_pin_type(new_type);
        else
            new_pin->type = new_type;

        // Create the object (SV wrapped in RV)
        SV * rv = _new_pointer_obj(aTHX_ new_pin);

        // Return the RV
        ST(0) = sv_2mortal(rv);
    }
    XSRETURN(1);
}

XS_INTERNAL(Affix_own) {
    dXSARGS;
    if (items < 1)
        croak_xs_usage(cv, "pin, [should_own]");

    Affix_Pin * pin = _get_pin_from_sv(aTHX_ ST(0));
    if (!pin) {
        warn("Argument is not a pinned pointer");
        XSRETURN_UNDEF;
    }

    if (items > 1) {
        // Don't dirty the memory if value hasn't changed
        bool new_val = SvTRUE(ST(1));
        if (pin->managed != new_val)
            pin->managed = new_val;
    }

    // Return current state as fast booleans (PL_sv_yes/no are essentially singletons)
    ST(0) = pin->managed ? &PL_sv_yes : &PL_sv_no;
    XSRETURN(1);
}

XS_INTERNAL(Affix_attach_destructor) {
    dXSARGS;
    if (items < 2)
        croak_xs_usage(cv, "pin, destructor_ptr, [lib_obj]");

    Affix_Pin * pin = _get_pin_from_sv(aTHX_ ST(0));
    if (!pin) {
        warn("First argument to attach_destructor must be a pinned pointer");
        XSRETURN_UNDEF;
    }

    void * destructor_ptr = nullptr;
    if (SvIOK(ST(1)))
        destructor_ptr = INT2PTR(void *, SvUV(ST(1)));
    else {
        Affix_Pin * dpin = _get_pin_from_sv(aTHX_ ST(1));
        if (dpin)
            destructor_ptr = dpin->pointer;
    }

    if (!destructor_ptr) {
        warn("Destructor pointer cannot be null");
        XSRETURN_UNDEF;
    }

    pin->destructor = (void (*)(void *))destructor_ptr;

    if (items > 2 && sv_isobject(ST(2)) && sv_derived_from(ST(2), "Affix::Lib"))
        pin->destructor_lib_sv = newSVsv(ST(2));

    XSRETURN_YES;
}

XS_INTERNAL(Affix_errno) {
    dXSARGS;
    PERL_UNUSED_VAR(items);

    SV * dual = newSV(1);

#ifdef _WIN32
    DWORD err_code = GetLastError();
    sv_setuv(dual, (UV)err_code);

    char * buf = nullptr;
    DWORD len =
        FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                       nullptr,
                       err_code,
                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                       (LPSTR)&buf,
                       0,
                       nullptr);

    if (buf) {
        while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
            buf[--len] = '\0';
        sv_setpvn(dual, buf, len);
        LocalFree(buf);
    }
    else
        sv_setpvn(dual, "Unknown system error", 20);

    SvIOK_on(dual);
    SvIsUV_on(dual);  // Mark as unsigned for DWORD
#else
    int err_code = errno;
    sv_setiv(dual, err_code);

lib/Affix.c  view on Meta::CPAN

        sv_setsv(get_sv("Affix::()", TRUE), &PL_sv_yes);
        (void)newXSproto_portable("Affix::()", Affix_as_string, __FILE__, "$;@");

        sv_setsv(get_sv("Affix::Lib::()", TRUE), &PL_sv_yes);
        (void)newXSproto_portable("Affix::Lib::(0+", Affix_Lib_as_string, __FILE__, "$;@");
        (void)newXSproto_portable("Affix::Lib::()", Affix_as_string, __FILE__, "$;@");

        // Library & core utils
        XSUB_EXPORT(load_library, "$", "lib");
        XSUB_EXPORT(find_symbol, "$$", "lib");
        XSUB_EXPORT(get_last_error_message, "", "core");

        // Scalar pins
        XSUB_EXPORT(pin, "$$$$", "pin");
        XSUB_EXPORT(unpin, "$", "pin");

        // Introspection
        XSUB_EXPORT(sizeof, "$", "core");
        XSUB_EXPORT(alignof, "$", "core");
        XSUB_EXPORT(offsetof, "$$", "core");

        // Type registry
        (void)newXSproto_portable("Affix::_typedef", Affix_typedef, __FILE__, "$;$");
        (void)newXSproto_portable("Affix::_register_enum_values", Affix_register_enum_values, __FILE__, "$$$");
        (void)newXSproto_portable("Affix::types", Affix_defined_types, __FILE__, "");

        // Debugging
        (void)newXSproto_portable("Affix::sv_dump", Affix_sv_dump, __FILE__, "$");

        // Memory management & pointers
        XSUB_EXPORT(address, "$", "memory");
        XSUB_EXPORT(malloc, "$", "memory");
        XSUB_EXPORT(calloc, "$$", "memory");
        XSUB_EXPORT(realloc, "$$", "memory");
        XSUB_EXPORT(free, "$", "memory");
        XSUB_EXPORT(cast, "$$", "memory");
        XSUB_EXPORT(dump, "$$", "memory");
        XSUB_EXPORT(own, "$;$", "memory");

        // Raw memory operations
        XSUB_EXPORT(memcpy, "$$$", "memory");
        XSUB_EXPORT(memmove, "$$$", "memory");
        XSUB_EXPORT(memset, "$$$", "memory");
        XSUB_EXPORT(memcmp, "$$$", "memory");
        XSUB_EXPORT(memchr, "$$$", "memory");

        // Pointer utils
        XSUB_EXPORT(ptr_add, "$$", "memory");
        XSUB_EXPORT(ptr_diff, "$$", "memory");
        XSUB_EXPORT(strdup, "$", "memory");
        XSUB_EXPORT(strnlen, "$$", "memory");
        XSUB_EXPORT(is_null, "$", "memory");

        // Pin internals (for Affix::Pointer)
        (void)newXSproto_portable("Affix::_pin_type", Affix_pin_type, __FILE__, "$");
        (void)newXSproto_portable("Affix::_pin_element_type", Affix_pin_element_type, __FILE__, "$");
        (void)newXSproto_portable("Affix::_pin_count", Affix_pin_count, __FILE__, "$");
        (void)newXSproto_portable("Affix::_pin_size", Affix_pin_size, __FILE__, "$");
        (void)newXSproto_portable("Affix::_pin_get_at", Affix_pin_get_at, __FILE__, "$$");
        (void)newXSproto_portable("Affix::_pin_set_at", Affix_pin_set_at, __FILE__, "$$$");
        (void)newXSproto_portable("Affix::_attach_destructor", Affix_attach_destructor, __FILE__, "$$;$");
    }

    XSUB_EXPORT(coerce, "$$", "core");

    XSUB_EXPORT(errno, "", "core");
    (void)newXSproto_portable("Affix::set_destruct_level", Affix_set_destruct_level, __FILE__, "$");

#undef XSUB_EXPORT

    Perl_xs_boot_epilog(aTHX_ ax);
}



( run in 0.577 second using v1.01-cache-2.11-cpan-e1769b4cff6 )