Получить структуру * из параметра out в привязках Fibi Scheme Fibre Chibi - PullRequest
0 голосов
/ 04 апреля 2019

Можете ли вы получить struct * из параметра out функции C в схеме Chibi?

Я пытаюсь получить struct archive_entry * из этой функции C:

int archive_read_next_header(
    struct archive *archive,
    struct archive_entry **out_entry);

В Си это можно сделать так:

struct archive_entry *entry;
archive_read_next_header(archive, &entry);

Мой код FFI Чиби:

(define-c-struct archive)

(define-c-struct archive_entry)

(define-c int
          archive-read-next-header
          (archive (result reference archive_entry)))

Но он не генерирует правильный код C, чтобы получить archive_entry. я думаю, что reference - это неправильная вещь Я тоже пробовал pointer но это тоже не сработало.

1 Ответ

0 голосов
/ 05 апреля 2019

Я до сих пор не знаю, можно ли это сделать напрямую.

Но я смог обойти эту проблему, написав пользовательскую функцию thunk на C:

(c-declare "
struct archive_entry *my_archive_read(struct archive *a, int *out_errcode) {
    struct archive_entry *entry;
    int errcode;

    *out_errcode = errcode = archive_read_next_header(a, &entry);
    return (errcode == ARCHIVE_OK) ? entry : NULL;
}")

(define-c archive_entry my-archive-read (archive (result int)))

Таким образом, ключ в том, что в этой версии Scheme не нужно иметь дело с двойным косвенным указанием (**). Код C преобразует двойное косвенное обращение в однонаправленное для Scheme, поэтому все получается.

Пример использования из программы Scheme:

(let ((archive (my-archive-open filename)))
  (disp "archive" archive)
  (let* ((return-values (my-archive-read archive))
         (entry (car return-values))
         (errcode (cadr return-values)))
    (display entry)
    (newline)))

Я скопировал технику из привязок chibi-sqlite3 , где они сталкиваются с аналогичной проблемой, связанной с получением sqlite3_stmt * из параметра out:

(c-declare
 "sqlite3_stmt* sqlite3_prepare_return(sqlite3* db, const char* sql, const int len) {
    sqlite3_stmt* stmt;
    char** err;
    return sqlite3_prepare_v2(db, sql, len, &stmt, NULL) != SQLITE_OK ? NULL : stmt;
  }
")

(define-c sqlite3_stmt (sqlite3-prepare "sqlite3_prepare_return") (sqlite3 string (value (string-length arg1) int)))
...