簡體   English   中英

是否有 GNU getline 接口的替代實現?

[英]Are there alternate implementations of GNU getline interface?

我目前正在進行的實驗使用了一個具有復雜源歷史且沒有明確定義的許可證的軟件庫。 將事情合理化並在固定許可下發布將需要大量工作。

它還旨在運行一個隨機的 unixish 平台,只有我們支持的一些 libc 有 GNU getline,但現在代碼需要它。

有誰知道在限制較少的許可下可用的GNU getline語義的重新實現?

編輯::我問是因為谷歌沒有幫助,如果可能的話我想避免寫一個(這可能是一個有趣的練習,但它不是我時間的最佳利用方式。)

更具體地說,有問題的接口是:

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

我很困惑。

我查看了鏈接,閱讀了說明,這是一個很好的實用程序。

但是,您是說您根本無法將這個函數重寫為規范? 規格似乎很清楚,

這里:

/* 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 分鍾,我已經 10 年沒有寫過 C 了。 它稍微違反了 getline 約定,因為它只檢查 lineptr 是否為 NULL,而不是 NULL 和 n == 0。如果您願意,可以修復它。 (另一種情況對我來說沒有多大意義,我想在這種情況下您可以返回 -1。)

用變量替換 '\\n' 以實現“getdelim”。

人們仍然在編寫代碼嗎?

Will Hartung 的代碼有一個非常嚴重的問題。 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)了。

使用這些來自 NetBSD 的便攜版本: getdelim()getline()

這些來自 pkgsrc 中的 libnbcompat,並且在每個文件的頂部都有一個 BSD 許可證。 您需要兩者,因為 getline() 調用 getdelim()。 獲取兩個文件的最新版本。 請參閱每個文件頂部的 BSD 許可證。 修改文件以適合您的程序:您可能需要在其中一個頭文件中聲明 getline() 和 getdelim(),並修改這兩個文件以包含您的頭而不是 nbcompat 頭。

這個版本的 getdelim() 是可移植的,因為它調用了 fgetc()。 相比之下,來自 libc(如 BSD libc 或 musl libc)的 getdelim() 可能會使用該 libc 的私有特性,因此它無法跨平台工作。

POSIX 2008 指定 getline() 之后的幾年里,更多的 Unixish 平台添加了 getline() 函數。 getline() 很少丟失,但它仍然可以在舊平台上發生。 一些人嘗試在舊平台(如 PowerPC Mac OS X)上引導 NetBSD pkgsrc,因此他們希望 libnbcompat 提供缺少的 POSIX 函數,如 getline()。

如果您正在為 BSD 編譯,請改用fgetln

嘗試使用 fgets() 而不是 getline()。 我在 Linux 中使用 getline() 並且它運行良好,直到我遷移到 Windows。 Visual Studio 無法識別 getline()。 所以,我用字符替換字符指針,用 NULL 替換 EOF。 見下文:

前:

char *line = (char*) malloc(sizeof(char) * 1000);
size_t size = 1000 * sizeof(char);
FILE *fp = fopen(file, "r");
while(getline(&line, &size, fp) != EOF) {
   ...
}
free(line);

后:

char line[1000];
size_t size = 1000 * sizeof(char);
while(fgets(&line, &size, fp) != NULL) {
   ...
}

沒有錯誤的更好答案在這里:

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 = bufptr + (size - 128);
            }
            *p++ = c;
            if (c == '\n')
            {
                break;
            }
            c = fgetc(stream);
        }
    
        *p++ = '\0';
        *lineptr = bufptr;
        *n = size;
    
        return p - bufptr - 1;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM