Skip to content

Commit 161076b

Browse files
committed
add full inline CSV parser
1 parent a704676 commit 161076b

File tree

1 file changed

+214
-25
lines changed

1 file changed

+214
-25
lines changed

src/AdafruitIO_Data.cpp

Lines changed: 214 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -434,40 +434,229 @@ char* AdafruitIO_Data::charFromDouble(double d, int precision)
434434
return _double_buffer;
435435
}
436436

437-
bool AdafruitIO_Data::_parseCSV()
437+
/*
438+
* From the csv_parser project by semitrivial
439+
* https://github.com/semitrivial/csv_parser/blob/93246cac509f85da12c6bb8c641fa75cd863c34f/csv.c - retrieved 2017-11-09
440+
*
441+
* MIT License
442+
*
443+
* Copyright 2016 Samuel Alexander
444+
*
445+
* Permission is hereby granted, free of charge, to any person obtaining a copy
446+
* of this software and associated documentation files (the "Software"), to
447+
* deal in the Software without restriction, including without limitation the
448+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
449+
* sell copies of the Software, and to permit persons to whom the Software is
450+
* furnished to do so, subject to the following conditions:
451+
*
452+
* The above copyright notice and this permission notice shall be included in
453+
* all copies or substantial portions of the Software.
454+
*
455+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
456+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
457+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
458+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
459+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
460+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
461+
* IN THE SOFTWARE.
462+
*
463+
*/
464+
465+
static int count_fields( const char *line )
466+
{
467+
const char *ptr;
468+
int cnt, fQuote;
469+
470+
for ( cnt = 1, fQuote = 0, ptr = line; *ptr; ptr++ )
471+
{
472+
if ( fQuote )
473+
{
474+
if ( *ptr == '\"' )
475+
{
476+
if ( ptr[1] == '\"' )
477+
{
478+
ptr++;
479+
continue;
480+
}
481+
fQuote = 0;
482+
}
483+
continue;
484+
}
485+
486+
switch( *ptr )
487+
{
488+
case '\"':
489+
fQuote = 1;
490+
continue;
491+
case ',':
492+
cnt++;
493+
continue;
494+
default:
495+
continue;
496+
}
497+
}
498+
499+
if ( fQuote )
500+
{
501+
return -1;
502+
}
503+
504+
return cnt;
505+
}
506+
507+
/*
508+
* Given a string containing no linebreaks, or containing line breaks
509+
* which are escaped by "double quotes", extract a NULL-terminated
510+
* array of strings, one for every cell in the row.
511+
*/
512+
char **parse_csv( const char *line )
438513
{
439-
char *csv = _csv;
440-
441-
if(csv[0] == '"') {
442-
// handle quoted values
443-
csv++;
444-
int end = strstr(csv, "\",") - csv;
445-
strncpy(_value, csv, end);
446-
csv += (end + 2);
447-
} else {
448-
// handle normal values
449-
strcpy(_value, strtok(csv, ","));
514+
char **buf, **bptr, *tmp, *tptr;
515+
const char *ptr;
516+
int fieldcnt, fQuote, fEnd;
517+
518+
fieldcnt = count_fields( line );
519+
520+
if ( fieldcnt == -1 )
521+
{
522+
return NULL;
523+
}
524+
525+
buf = (char **)malloc( sizeof(char*) * (fieldcnt+1) );
526+
527+
if ( !buf )
528+
{
529+
return NULL;
530+
}
531+
532+
tmp = (char *)malloc( strlen(line) + 1 );
533+
534+
if ( !tmp )
535+
{
536+
free( buf );
537+
return NULL;
538+
}
539+
540+
bptr = buf;
541+
542+
for ( ptr = line, fQuote = 0, *tmp = '\0', tptr = tmp, fEnd = 0; ; ptr++ )
543+
{
544+
if ( fQuote )
545+
{
546+
if ( !*ptr )
547+
{
548+
break;
549+
}
550+
551+
if ( *ptr == '\"' )
552+
{
553+
if ( ptr[1] == '\"' )
554+
{
555+
*tptr++ = '\"';
556+
ptr++;
557+
continue;
558+
}
559+
fQuote = 0;
560+
}
561+
else {
562+
*tptr++ = *ptr;
563+
}
564+
565+
continue;
566+
}
567+
568+
switch( *ptr )
569+
{
570+
case '\"':
571+
fQuote = 1;
572+
continue;
573+
case '\0':
574+
fEnd = 1;
575+
case ',':
576+
*tptr = '\0';
577+
*bptr = strdup( tmp );
578+
579+
if ( !*bptr )
580+
{
581+
for ( bptr--; bptr >= buf; bptr-- )
582+
{
583+
free( *bptr );
584+
}
585+
free( buf );
586+
free( tmp );
587+
588+
return NULL;
589+
}
590+
591+
bptr++;
592+
tptr = tmp;
593+
594+
if ( fEnd )
595+
{
596+
break;
597+
} else
598+
{
599+
continue;
600+
}
601+
602+
default:
603+
*tptr++ = *ptr;
604+
continue;
605+
}
606+
607+
if ( fEnd )
608+
{
609+
break;
610+
}
450611
}
451612

452-
if (! _value) return false;
613+
*bptr = NULL;
614+
free( tmp );
615+
return buf;
616+
}
617+
618+
//// END simple_csv SECTION
619+
620+
bool AdafruitIO_Data::_parseCSV()
621+
{
622+
623+
int field_count = count_fields(_csv);
453624

454-
// parse lat from csv and convert to float
455-
char *lat = strtok(NULL, ",");
456-
if (! lat) return false;
625+
if (field_count > 0)
626+
{
627+
// this is normal IO data in `value,lat,lon,ele` format
628+
char **fields = parse_csv(_csv);
457629

458-
_lat = atof(lat);
630+
// first field is handled as string
631+
strcpy(_value, fields[0]);
632+
field_count--;
459633

460-
// parse lon from csv and convert to float
461-
char *lon = strtok(NULL, ",");
462-
if (! lon) return false;
634+
// locations fields are handled with char * to float conversion
635+
if (field_count > 0)
636+
{
637+
_lat = atof(fields[1]);
638+
field_count--;
639+
}
463640

464-
_lon = atof(lon);
641+
if (field_count > 0)
642+
{
643+
_lon = atof(fields[1]);
644+
field_count--;
645+
}
465646

466-
// parse ele from csv and convert to float
467-
char *ele = strtok(NULL, ",");
468-
if (! ele) return false;
647+
if (field_count > 0)
648+
{
649+
_ele = atof(fields[1]);
650+
field_count--;
651+
}
469652

470-
_ele = atof(ele);
653+
return field_count == 0;
654+
}
655+
else
656+
{
657+
return false;
658+
}
471659

472660
return true;
473661
}
662+

0 commit comments

Comments
 (0)