Существуют ли альтернативные реализации интерфейса GNU getline?

В эксперименте, который я сейчас работаю, используется база программного обеспечения со сложной историей источника и без четко определенной лицензии. Было бы большой объем работы по рационализации вещей и выпуску по фиксированной лицензии.

Он также предназначен для запуска произвольной платформы unixish, и только некоторые из поддерживаемых libc имеют GNU getline, но сейчас код ожидает этого.

Кто-нибудь знает о повторной реализации семантики GNU getline, доступной по менее ограничительной лицензии?

Изменить:: Я прошу, потому что Google не помог, и я хотел бы избежать написания одного, если это возможно (это может быть забавное упражнение, но оно не может быть наилучшим образом моего времени.)

Чтобы быть более конкретным, рассматриваемый интерфейс:

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

Ответ 1

Взгляните на страницу Пола Се на Пользовательский ввод. Вы можете отправить письмо автору, если хотите узнать точные условия.

Ответ 2

Я озадачен.

Я просмотрел ссылку, прочитал описание, и это прекрасная утилита.

Но, вы говорите, что просто не можете переписать эту функцию в спецификацию? Спектр кажется вполне понятным,

Здесь:

/* This code is public domain -- Will Hartung 4/9/09 */
#include <stdio.h>
#include <stdlib.h>

size_t getline(char **lineptr, size_t *n, FILE *stream) {
    char *bufptr = NULL;
    char *p = bufptr;
    size_t size;
    int c;

    if (lineptr == NULL) {
        return -1;
    }
    if (stream == NULL) {
        return -1;
    }
    if (n == NULL) {
        return -1;
    }
    bufptr = *lineptr;
    size = *n;

    c = fgetc(stream);
    if (c == EOF) {
        return -1;
    }
    if (bufptr == NULL) {
        bufptr = malloc(128);
        if (bufptr == NULL) {
            return -1;
        }
        size = 128;
    }
    p = bufptr;
    while(c != EOF) {
        if ((p - bufptr) > (size - 1)) {
            size = size + 128;
            bufptr = realloc(bufptr, size);
            if (bufptr == NULL) {
                return -1;
            }
        }
        *p++ = c;
        if (c == '\n') {
            break;
        }
        c = fgetc(stream);
    }

    *p++ = '\0';
    *lineptr = bufptr;
    *n = size;

    return p - bufptr - 1;
}

int main(int argc, char** args) {
    char *buf = NULL; /*malloc(10);*/
    int bufSize = 0; /*10;*/

    printf("%d\n", bufSize);
    int charsRead =  getline(&buf, &bufSize, stdin);

    printf("'%s'", buf);
    printf("%d\n", bufSize);
    return 0;
}

15 минут, и я не написал C через 10 лет. Он незначительно нарушает контракт getline в том, что он проверяет, является ли lineptr NULL, а не NULL и n == 0. Вы можете это исправить, если хотите. (Другой случай не имел для меня большого смысла, я думаю, вы могли бы вернуть -1 в этом случае.)

Замените "\n" на переменную для реализации "getdelim".

Неужели люди все еще пишут код?

Ответ 3

Код Уилла Хартунга страдает от очень серьезной проблемы. Скорее всего, realloc освободит старый блок и выделит новый, но указатель p внутри кода будет продолжать указывать на оригинал. Этот пытается исправить это, используя вместо этого индексацию массива. Он также пытается более точно воспроизвести стандартную логику POSIX.

/* The original code is public domain -- Will Hartung 4/9/09 */
/* Modifications, public domain as well, by Antti Haapala, 11/10/17
   - Switched to getc on 5/23/19 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>

// if typedef doesn't exist (msvc, blah)
typedef intptr_t ssize_t;

ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
    size_t pos;
    int c;

    if (lineptr == NULL || stream == NULL || n == NULL) {
        errno = EINVAL;
        return -1;
    }

    c = getc(stream);
    if (c == EOF) {
        return -1;
    }

    if (*lineptr == NULL) {
        *lineptr = malloc(128);
        if (*lineptr == NULL) {
            return -1;
        }
        *n = 128;
    }

    pos = 0;
    while(c != EOF) {
        if (pos + 1 >= *n) {
            size_t new_size = *n + (*n >> 2);
            if (new_size < 128) {
                new_size = 128;
            }
            char *new_ptr = realloc(*lineptr, new_size);
            if (new_ptr == NULL) {
                return -1;
            }
            *n = new_size;
            *lineptr = new_ptr;
        }

        ((unsigned char *)(*lineptr))[pos ++] = c;
        if (c == '\n') {
            break;
        }
        c = getc(stream);
    }

    (*lineptr)[pos] = '\0';
    return pos;
}

Для платформы можно повысить производительность, заблокировав поток один раз и используя эквивалент getc_unlocked(3) но они не стандартизированы в C; и если вы используете версию POSIX, то, вероятно, у вас уже есть getline(3).

Ответ 4

Если вы компилируете для BSD, используйте fgetln вместо

Ответ 5

Используйте эти переносимые версии из NetBSD: getdelim() и getline()

Они поступают из libnbcompat в pkgsrc и имеют лицензию BSD в верхней части каждого файла. Вам нужны оба, потому что getline() вызывает getdelim(). Выполните последние версии обоих файлов. См. Лицензию BSD в верхней части каждого файла. Измените файлы, которые нужно поместить в вашу программу: вам может потребоваться объявить getline() и getdelim() в одном из ваших файлов заголовков и изменить оба файла, чтобы включить ваш заголовок вместо заголовков nbcompat.

Эта версия getdelim() переносима, поскольку вызывает fgetc(). Для сравнения, getdelim() из libc (например, BSD libc или musl libc), вероятно, будет использовать частные функции этого libc, поэтому он не будет работать на разных платформах.

В годы, прошедшие с POSIX 2008, указанная getline(), на платформах Unixish добавлена ​​функция getline(). Редко бывает, что getline() отсутствует, но это все равно может случиться на старых платформах. Несколько человек пытаются загружать NetBSD pkgsrc на старых платформах (например, PowerPC Mac OS X), поэтому они хотят, чтобы libnbcompat предоставлял отсутствующие функции POSIX, такие как getline().

Ответ 6

Если вы говорите о readline, проверьте: editline