/* Read a single item. Syntax is: * * element : * whitespace* item whitespace* [EOF|EOL|separator] * * item : * double | * "anything" | * empty * * the anything in quotes can contain " escaped with \ * * Return the char that caused failure on fail (EOF or \n). */ static int read_double( FILE *fp, const char whitemap[256], const char sepmap[256], int lineno, int colno, double *out ) { int ch; /* The fscanf() may change this ... but all other cases need a zero. */ *out = 0; ch = skip_white( fp, whitemap ); if( ch == EOF || ch == '\n' ) return( ch ); if( ch == '"' ) { (void) fgetc( fp ); (void) skip_to_quote( fp ); ch = fgetc( fp ); } else if( !sepmap[ch] && fscanf( fp, "%lf", out ) != 1 ) { /* Only a warning, since (for example) exported spreadsheets * will often have text or date fields. */ vips_warn( "csv2vips", _( "error parsing number, line %d, column %d" ), lineno, colno ); /* Step over the bad data to the next separator. */ ch = skip_to_sep( fp, sepmap ); } /* Don't need to check result, we have read a field successfully. */ ch = skip_white( fp, whitemap ); /* If it's a separator, we have to step over it. */ if( ch != EOF && sepmap[ch] ) (void) fgetc( fp ); return( 0 ); }
bool to_internal_SU( char * * scanp, su * converted ) { bool converterror = true; char * p; char * ps; ldiv_t div; su * s; long wh; long wd; char * pp; // ptr to decimal point or embedded unit char * pu; // ptr to trailing unit char * pd1; // ptr to 0.1 decimal char * pdn; // ptr to last digit +1 char unit[4]; char quote; long k; char sign; unit[3] = '\0'; unit[2] = '\0'; unit[1] = '\0'; unit[0] = '\0'; s = converted; p = *scanp; ps = s->su_txt; *ps = '\0'; wh = 0; wd = 0; pp = NULL; quote = '\0'; s->su_u = SU_undefined; if( *p == '\'' || *p == '"' ) { // ignore but remember quote quote = *p++; } if( *p == '+' || *p == '-' ) { sign = *p; *ps++ = *p++; s->su_relative = true; // value is added / subtracted from old value } else { sign = '+'; s->su_relative = false; // value replaces old value } /***********************************************************************/ /* Special for layout :BANREGION */ /***********************************************************************/ if( quote == '\0' && isalpha( *p ) ) { converterror = su_layout_special( scanp, converted ); if( !converterror ) { return( converterror ); // layout special ok } } while( *p >= '0' && *p <= '9' ) { // whole part wh = 10 * wh + *p - '0'; *ps++ = *p++; if( ps >= s->su_txt + sizeof( s->su_txt ) ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } } pp = p; k = 0; while( *p && isalpha( *p ) ) { unit[k++] = tolower( *p ); // save Unit *ps++ = *p++; if( ps >= s->su_txt + sizeof( s->su_txt ) || k > 2 ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } } if( p > pp + 2 ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); // no unit has more than 2 chars } pd1 = NULL; pdn = NULL; if( p == pp && *p == '.' ) { // no unit found, try dec point *ps++ = *p++; pd1 = p; // remember start of decimals if( ps >= s->su_txt + sizeof( s->su_txt ) ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } while( *p >= '0' && *p <= '9' ) { // try decimal part wd = 10 * wd + *p - '0'; *ps++ = *p++; if( ps >= s->su_txt + sizeof( s->su_txt ) ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } if( p > pd1 + 2 ) { // more than two digits if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } } pdn = p; } else { if( k ) { // unit found pd1 = p; if( ps >= s->su_txt + sizeof( s->su_txt ) ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } while( *p >= '0' && *p <= '9' ) { // try decimal part wd = 10 * wd + *p - '0'; *ps++ = *p++; if( ps >= s->su_txt + sizeof( s->su_txt ) ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } if( p > pd1 + 2 ) { // more than two digits if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } } pdn = p; } } k = 0; pu = p; if( *p ) { // not yet at end while( *p && isalpha( *p ) ) { // try trailing unit unit[k++] = tolower( *p ); *ps++ = *p++; if( ps >= s->su_txt + sizeof( s->su_txt ) || k > 2 ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } } } *ps = '\0'; s->su_whole = wh; s->su_dec = wd; if( (quote && *p != quote ) || (!quote && *p == '\'') ) { if( quote ) { p = skip_to_quote( p, quote ); } *scanp = p; return( converterror ); } if( quote ) { p++; // over quote } *scanp = p; // report back scan position if( k == 0 ) { // no trailing unit pu = NULL; } else { if( pu == pp ) { // no decimals, no unit pu = NULL; } } if( *pp == '.' ) { // dec point found if( pu == NULL ) { // need trailing unit return( converterror ); } } else { // no decimals if( pu != NULL ) { // but unit specified twice? return( converterror ); } } /***********************************************************************/ /* check for valid unit */ /***********************************************************************/ if( unit[1] == '\0' ) { // single letter unit switch( unit[0] ) { case 'i' : s->su_u = SU_inch; break; case 'm' : s->su_u = SU_ems; break; case 'c' : s->su_u = SU_cicero; break; case 'p' : s->su_u = SU_pica; break; case '\0' : // no unit is characters or lines s->su_u = SU_chars_lines; break; default: return( converterror ); break; } } else { // two letter unit if( unit[1] == 'm' ) { // cm, mm ? if( unit[0] == 'c' ) { s->su_u = SU_cm; } else if( unit[0] == 'm' ) { s->su_u = SU_mm; } else { // invalid unit return( converterror ); } } else if( unit[0] == 'd' ) { // dv ? if( unit[1] == 'v' ) { s->su_u = SU_dv; } } else { // invalid unit return( converterror ); } } s->su_inch = 0; s->su_mm = 0; k = 1; if( pd1 != NULL ) { if( pdn - pd1 == 1 ) { k = 10; // only 0.1 digit } } switch( s->su_u ) { // the relative units are only stored, not converted case SU_chars_lines : case SU_ems : if( wd != 0 ) { // no decimals allowed return( converterror ); } break; case SU_dv : // decimals are allowed for dv break; case SU_inch : // inch, cm, mm valid with decimals s->su_mm = (wh * 100L + wd * k) * 2540L; s->su_inch = (wh * 100L + wd * k) * 100L; break; case SU_cm : s->su_mm = (wh * 100L + wd * k) * 1000L; s->su_inch = s->su_mm * 10L / 254L; break; case SU_mm : s->su_mm = (wh * 100L + wd * k) * 100L; s->su_inch = s->su_mm * 10L / 254L; break; case SU_cicero : // cicero if( wd > 11 ) { div = ldiv( wd, 12L); wh += div.quot; wd = div.rem; } s->su_inch = wh * 10000L / 6L + wd * 10000L / 72L; s->su_inch = (int64_t)s->su_inch * 10656L / 10000L; s->su_mm = s->su_inch * 254L / 10L; break; case SU_pica : // pica if( wd > 11 ) { div = ldiv( wd, 12L); wh += div.quot; wd = div.rem; } s->su_inch = wh * 10000L / 6L + wd * 10000L / 72L; s->su_inch = (int64_t)s->su_inch * 9978L / 10000L; s->su_mm = s->su_inch * 254L / 10L; break; default: break; } if( sign == '-' ) { s->su_inch = -s->su_inch; s->su_mm = -s->su_mm; s->su_whole = -s->su_whole; } converterror = false; return( converterror ); }