_getdelim() for MS-Windows compilers

Ancient Dragon 2 Tallied Votes 314 Views Share

The idea for this came from another thread in the C++ forum that wanted to duplicate the _getdelim() function that is supported by GNU compilers g++. I made one major change in that this version does not allocate new memory every time it is called, which is grossly inefficient. Instead, this function only allocates new memory if the pointer to pointer passed to _getdelim() is NULL. If not NULL then it assumes the calling program has allocated the memory. The function might expand the size of the line buffer if the number of characters read exceeds the length of the line buffer.

I also removed the goto statements that are in the original GNU function and the ancient K&R style function parameter declarations.

This code snippet uses only standard C functions -- nothing compiler-specific, so it most likely will compile with any 32-bit or 64-bit compiler.

jonsca commented: Nice! +2
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#pragma warning(disable: 4996)

/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
  (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
   NULL), pointing to *N characters of space.  It is realloc'd as
   necessary.  Returns the number of characters read (not including the
   null terminator), or -1 on error or EOF.  */
static __inline void __set_errno(unsigned int no)
{
    errno = no;
}

size_t __getdelim (char** lineptr, size_t* n, int terminator,FILE* stream)
{
    const size_t BLOCKSIZE = 255;
    int c;
    size_t len = 0;
    size_t linesize = 0;
    int newalloc = 0;
    if( lineptr == NULL || stream == NULL || n == NULL)
    {
        _set_errno(EINVAL);
        return -1;
    }
    linesize = BLOCKSIZE;
    if( *lineptr == NULL)
    {
        // allocate new memory if required
        *lineptr = malloc(BLOCKSIZE);
        *n = BLOCKSIZE;
        newalloc = 1;
    }
    else
        linesize = *n;
    while( (c = fgetc(stream)) != EOF && c != terminator)
    {
        // make sure we have enough room for the new character
        // If not, then streatch it out a bit.
        if( (len+1) == linesize)
        {
            linesize += BLOCKSIZE;
            *n = linesize;
            *lineptr = realloc(*lineptr, linesize);
        }
        (*lineptr)[len++] = c;
    }
    if( len == 0 && c != terminator) // check for blank lines
    {
        _set_errno(EINVAL);
        if( newalloc )
        {
            free(*lineptr);
            *lineptr = NULL;
        }
        else
            (*lineptr)[0] = 0; // truncate the string
        return -1;
    }
    (*lineptr)[len] = 0; // null-terminate the string
       
    return len;
}

int main()
{
    unsigned int n = 255;
    char* lineptr = malloc(n);
    FILE* fp = fopen("test3.c", "r");
    if( fp != NULL)
    {
        while(__getdelim(&lineptr, &n, '\n', fp) != -1 )
        {
            printf("%s\n", lineptr);
        }
        free(lineptr);
        lineptr = NULL;
        fclose(fp);
    }

}
mitrmkar 1,056 Posting Virtuoso

:icon_eek: There are no checks against failed memory allocations.

Dave Sinkula 2,398 long time no c Team Colleague

I might suggest removing the leading underscores -- that's the implementor's namespace.

Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster

>>There are no checks against failed memory allocations.
Because its not really necessary on today's computers with lots and lots of memory, unless of course memory has been corrupt. I haven't seen malloc() return NULL since the days of 16-bit MS-DOS or Win95. If the computer doesn't have enough memory for malloc() then there are many many more problems to worry about.

>>I might suggest removing the leading underscores -- that's the implementor's namespace.

Agree -- its also a common way to indicate that a function is part of a library (*.lib or *.a)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.