English 中文(简体)
有GNU getline接口的替代实现吗?
原标题:
  • 时间:2009-04-09 17:18:29
  •  标签:

我目前正在进行的实验使用了一个软件库,该软件库具有复杂的源历史记录,并且没有明确定义的许可证。要使事情合理化并在固定许可证下发布,需要做大量的工作。

它还打算运行一个随机的unixish平台,并且只有我们支持的一些libc具有GNU getline,但现在代码期望它。

有人知道GNUgetline在限制较少的许可证下可用的语义?

编辑::我问是因为谷歌没有帮助,如果可能的话,我想避免写一个(这可能是一个有趣的练习,但不能最好地利用我的时间。)

更具体地说,有问题的接口是:

ssize_t getline (char **lineptr, size_t *n, FILE *stream);
问题回答

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 ==  
 ) {
            break;
        }
        c = getc(stream);
    }

    (*lineptr)[pos] =   ;
    return pos;
}

通过锁定流一次并使用getc_unlocked(3)-但这些在C中不是标准化的;如果您使用的是POSIX版本,那么您可能会有getline(3)已经。

我很困惑。

我查看了链接,阅读了描述,这是一个很好的实用程序。

但是,你是说你根本无法将这个函数重写为规范吗?规格似乎很清楚,

在这里:

/* 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 ==  
 ) {
            break;
        }
        c = fgetc(stream);
    }

    *p++ =   ;
    *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
", bufSize);
    int charsRead =  getline(&buf, &bufSize, stdin);

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

15分钟,我已经10年没有写过C了。它略微破坏了getline约定,因为它只检查lineptr是否为NULL,而不是NULL和n=0。如果你愿意,你可以解决这个问题。(另一种情况对我来说意义不大,我想在这种情况下你可以返回-1。)

Replace the with a variable to implement "getdelim".

人们还会写代码吗?

使用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(。

If you are compiling for BSD use fgetln instead

尝试使用fgets()而不是getline()。我在Linux中使用getline(),在迁移到Windows之前,它一直运行良好。Visual studio无法识别getline()。因此,我将字符指针替换为字符,将EOF替换为NULL。见下文:

#define CHARCOUNT 1000

之前:

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

之后:

char line[CHARCOUNT];
while(fgets(line, CHARCOUNT, 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 ==  
 )
            {
                break;
            }
            c = fgetc(stream);
        }
    
        *p++ =   ;
        *lineptr = bufptr;
        *n = size;
    
        return p - bufptr - 1;
    }




相关问题
热门标签