Exemplo n.º 1
0
/* 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 );
}
Exemplo n.º 2
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 );
}