@@ -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