Как создать привязку Red/System к функции, которая принимает указатель на указатель?

Я смотрел, как Red/System подключается к библиотечным функциям C из Windows DLL, общих библиотек Linux/Android .so и OS/X .dylib с синтаксисом #import:

#import [
    "libc.so.6" cdecl [

        allocate: "malloc" [
            size [integer!]
            return: [byte-ptr!]
        ]

        free: "free" [
            block [byte-ptr!]
        ]

        /* ... */
]

Работает для всех основных типов, но что делать, когда функции нужен указатель на указатель? Например, что, если вы пытаетесь выполнить привязку к чему-то вроде getline(), у которого есть прототип:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

Один из способов вызвать это (как я хочу это назвать...) состоит в том, что входящий lineptr является не предварительно выделенным буфером, а скорее null. В этом случае getline выделяет для вас буфер и изменяет char*, чтобы он больше не был нулевым.

В качестве первой попытки я сделал:

getline: "getline" [
    lineptr [byte-ptr!]       ;-- char **
    n [pointer! [integer!]]   ;-- size_t *
    stream [byte-ptr!]        ;-- FILE *
    return: [integer!]        ;-- ssize_t
]

Но поскольку не существует такой вещи, как pointer! [c-string!] или что-то подобное, я не понимаю, как это назвать. Могу ли я получить адрес локальной переменной c-string! и как-то передать ее как byte-ptr!?


person HostileFork says dont trust SE    schedule 15.12.2013    source источник


Ответы (2)


Red/System [
    Title: "derp"
]

#import [
    LIBC-file cdecl [
        _fdopen: "fdopen" [
            fd   [integer!]
            type [c-string!]

            return: [pointer! [byte!]]
        ]

        _getline: "getline" [
            line   [pointer! [integer!]]
            n      [pointer! [integer!]]
            stream [pointer! [byte!]]

            return: [integer!]
        ]
    ]
]

getline: func [
    stream  [pointer! [byte!]]
    return: [c-string!]

    /local
        line [integer!]
        n    [integer!]
] [
    line: 0
    n:    0

    _getline :line :n stream
    as c-string! line
]

stream: _fdopen 0 "r"
line:  getline stream

print line

Это работает.

person meh.    schedule 15.12.2013
comment
Спасибо! Это работает, хотя возврат от getline LIBC представляет собой длину извлеченной строки (а не строки), поэтому это будет целое число... вы можете редактировать свои ответы (я тоже мог). Но я позволю тебе сделать это. :-) - person HostileFork says dont trust SE; 16.12.2013

В мире небольшой документации Red один фактический документ Red/System довольно полезен, и этот раздел косвенно содержит ответ в другом примере:

p: declare pointer! [byte!]            ;-- char *p;

что приведет к:

getline: "getline" [
    lineptr [pointer! [byte!]]  ;-- *char *
    n [pointer! [integer!]]     ;-- *size_t 
    stream [pointer! [byte!]]   ;-- *char
    return: [integer!]          ;-- ssize_t
]
person kealist    schedule 16.12.2013
comment
Хорошо бы упомянуть ссылку. Я думаю, главное, что я действительно не понял, это приложение Red/System GET-WORD! означать адрес-оф. - person HostileFork says dont trust SE; 16.12.2013