Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
semitrivial committed Jul 6, 2015
0 parents commit b5c9053
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
all:
gcc -g -Wall csv.c test.c -o test
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Just a simple C function for parsing CSV. License: MIT.

--------
Documentation
--------

char **parse_csv( const char *line );

Returns a NULL-terminated array of strings encoded in the indicated line of CSV.

Returns NULL if there was insufficient RAM or if the line is not property encoded CSV.
145 changes: 145 additions & 0 deletions csv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void free_csv_line( char **parsed )
{
for ( ; *parsed; parsed++ )
free( *parsed );

free( parsed );
}

int count_fields( const char *line )
{
const char *ptr;
int cnt, fQuote;

for ( cnt = 1, fQuote = 0, ptr = line; *ptr; ptr++ )
{
if ( fQuote )
{
if ( *ptr == '\"' )
{
if ( ptr[1] == '\"' )
{
ptr++;
continue;
}
fQuote = 0;
}
continue;
}

switch( *ptr )
{
case '\"':
fQuote = 1;
continue;
case ',':
cnt++;
continue;
default:
continue;
}
}

if ( fQuote )
return -1;

return cnt;
}

char **parse_csv( const char *line )
{
char **buf, **bptr, *tmp, *tptr;
const char *ptr;
int fieldcnt, fQuote, len, fEnd;

fieldcnt = count_fields( line );

if ( fieldcnt == -1 )
return NULL;

buf = malloc( sizeof(char*) * (fieldcnt+1) );

if ( !buf )
return NULL;

len = strlen(line);

tmp = malloc( len+1 );

if ( !tmp )
{
free( buf );
return NULL;
}

bptr = buf;

for ( ptr = line, fQuote = 0, *tmp = '\0', tptr = tmp, fEnd = 0; ; ptr++ )
{
if ( fQuote )
{
if ( !*ptr )
break;

if ( *ptr == '\"' )
{
if ( ptr[1] == '\"' )
{
*tptr++ = '\"';
ptr++;
continue;
}
fQuote = 0;
}
else
*tptr++ = *ptr;

continue;
}

switch( *ptr )
{
case '\"':
fQuote = 1;
continue;
case '\0':
fEnd = 1;
case ',':
*tptr = '\0';
*bptr = strdup( tmp );

if ( !*bptr )
{
for ( bptr--; bptr >= buf; bptr-- )
free( *bptr );

free( buf );
free( tmp );

return NULL;
}

bptr++;
tptr = tmp;

if ( fEnd )
break;
else
continue;

default:
*tptr++ = *ptr;
continue;
}

if ( fEnd )
break;
}

free( tmp );
return buf;
}
1 change: 1 addition & 0 deletions csv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
char **parse_csv( const char *line );
16 changes: 16 additions & 0 deletions test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <stdio.h>

void free_csv_line( char **parsed );
char **parse_csv( const char *line );

int main(void)
{
char *test = "a,b,\"c,d\",\"e,f,\"\",g\",h";
char **parsed = parse_csv( test );
char **ptr;

for ( ptr = parsed; *ptr; ptr++ )
printf( "%s\n", *ptr );

return 1;
}

0 comments on commit b5c9053

Please sign in to comment.