bool lay_init_su( const char *p, su *in_su ) { bool cvterr = true; const char *pa = NULL; // start of value text char *ps = NULL; // destination for value text char sign; size_t len; su *s; s = in_su; pa = p; ps = s->su_txt; *ps = '\0'; while( *p && (*p == ' ' ) ) { // just in case p++; } while( *p && (*p != ' ' ) ) { p++; } len = p - pa; if( (len + 1) > MAX_SU_CHAR ) { // won't fit xx_line_err( err_inv_att_val, val_start ); scan_start = scan_stop; return( cvterr ); } memcpy( ps, pa, len ); ps[len] = '\0'; s->su_u = SU_undefined; if( *ps == '+' ) { // not allowed with tags xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } else if( *ps == '-' ) { // not relative, just negative sign = *ps; if( *(ps + 1) == '+' || *(ps + 1) == '-' ) { // only one sign is allowed xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } } else { sign = '+'; } if( !*ps ) { // value end reached, not valid xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } s->su_relative = false; // no relative positioning with tags if( su_layout_special( in_su ) ) { cvterr = false; } else { cvterr = internal_to_su( in_su, true, pa ); } return( cvterr ); }
bool att_val_to_su( su * in_su, bool pos ) { bool cvterr = true; char * ps = NULL; // destination for value text char sign; su * s; s = in_su; ps = s->su_txt; *ps = '\0'; if( (val_len + 1) > MAX_SU_CHAR ) { // won't fit xx_line_err( err_inv_att_val, val_start ); scan_start = scan_stop; return( cvterr ); } memcpy( ps, val_start, val_len ); ps[val_len] = '\0'; s->su_u = SU_undefined; if( *ps == '+' ) { // not allowed with tags xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } else if( *ps == '-' ) { // not relative, just negative if( pos ) { // value must be positive xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } sign = *ps; if( *(ps + 1) == '+' || *(ps + 1) == '-' ) { // only one sign is allowed xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } } else { sign = '+'; } if( !*ps ) { // value end reached, not valid xx_line_err( err_inv_att_val, ps ); scan_start = scan_stop; return( cvterr ); } s->su_relative = false; // no relative positioning with tags if( su_layout_special( in_su ) ) { cvterr = false; } else { cvterr = internal_to_su( in_su, true, val_start ); } return( cvterr ); }
bool att_val_to_SU( su * converted, bool pos ) { bool converterror = true; bool is_cp = false; char * p = NULL; // source of value text char * pd = NULL; // ptr to decimal point char * pd1 = NULL; // ptr to 0.1 decimal char * pdn = NULL; // ptr to last digit +1 char * ps = NULL; // destination for value text char * pu = NULL; // ptr to trailing unit char sign; char unit[4]; int i; ldiv_t div; long k; long wh; long wd; su * s; if( (val_len + 1) > MAX_SU_CHAR ) { // won't fit xx_line_err( err_inv_att_val, val_start ); scan_start = scan_stop + 1; return( converterror ); } unit[3] = '\0'; unit[2] = '\0'; unit[1] = '\0'; unit[0] = '\0'; s = converted; p = val_start; ps = s->su_txt; *ps = '\0'; wd = 0; wh = 0; s->su_u = SU_undefined; if( *p == '+' ) { // not allowed with tags xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } else if( *p == '-' ) { // not relative, just negative if( pos ) { // value must be positive xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } sign = *p; *ps++ = *p++; if( *p == '+' || *p == '-' ) { // only one sign is allowed xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } } else { sign = '+'; } if( (p - val_start) >= val_len ) { // value end reached, not valid xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } s->su_relative = false; // no relative positioning with tags /***********************************************************************/ /* Special for layout :BANREGION */ /***********************************************************************/ if( isalpha( *p ) ) { converterror = su_layout_special( &p, converted ); if( !converterror ) { return( converterror ); // layout special ok } } for( i = 0; i < 4; i++ ) { // max four digits in whole part if( (*p >= '0') && (*p <= '9') ) { wh = (10 * wh) + (*p - '0'); *ps++ = *p++; } else { break; } if( (p - val_start) > val_len ) { // value end reached break; } } if( (*p >= '0') && (*p <= '9') ) { // too many digits in whole part xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } if( ((p - val_start) < val_len) && *p == '.' ) { // check for decimal point pd = p; *ps++ = *p++; pd1 = p; // remember start of decimals for( i = 0; i < 2; i++ ) { // max two digits in decimals if( (*p >= '0') && (*p <= '9') ) { wd = 10 * wd + *p - '0'; *ps++ = *p++; } else { break; } if( (p - val_start) > val_len ) { // value end reached break; } } pdn = p; if( pd1 == p ) { // no decimals pd1 = NULL; pdn = NULL; } if( (*p >= '0') && (*p <= '9') ) { // too many digits in decimals xx_line_err( err_inv_att_val, pdn ); scan_start = scan_stop + 1; return( converterror ); } } k = 0; pu = p; for( i = 0; i < 2; i++ ) { // max two characters in unit if( *p && isalpha( *p ) ) { unit[k++] = tolower( *p ); // save Unit *ps++ = *p++; } else { break; } if( (p - val_start) > val_len ) { // value end reached break; } } if( *p && isalpha( *p ) ) { // too many characters in unit xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; 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; if( pd != NULL ) { // no decimals with "M" xx_line_err( err_inv_att_val, pd ); scan_start = scan_stop + 1; return( converterror ); } break; case 'c' : s->su_u = SU_cicero; is_cp = true; break; case 'p' : s->su_u = SU_pica; is_cp = true; break; case '\0' : // no unit is characters or lines s->su_u = SU_chars_lines; break; default: xx_line_err( err_inv_att_val, pu ); scan_start = scan_stop + 1; 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 xx_line_err( err_inv_att_val, pu ); scan_start = scan_stop + 1; return( converterror ); } } else if( unit[0] == 'd' ) { // dv ? if( unit[1] == 'v' ) { s->su_u = SU_dv; } } else { // invalid unit xx_line_err( err_inv_att_val, pu ); scan_start = scan_stop + 1; return( converterror ); } } if( is_cp ) { // "C" and "P" can be followed by max four digits for( i = 0; i < 4; i++ ) { if( (*p >= '0') && (*p <= '9') ) { wd = (10 * wd) + (*p - '0'); *ps++ = *p++; } if( (p - val_start) > val_len ) { // value end reached break; } } } if( (*p >= '0') && (*p <= '9') ) { // too many digits after "C" or "P" xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } *ps = '\0'; if( (p - val_start) < val_len ) { // value continues on: it shouldn't xx_line_err( err_inv_att_val, p ); scan_start = scan_stop + 1; return( converterror ); } s->su_whole = wh; s->su_dec = wd; if( k == 0 ) { // no trailing unit pu = NULL; } if( pd != NULL ) { // dec point found if( pu == NULL ) { // need trailing unit xx_line_err( err_inv_att_val, pd ); scan_start = scan_stop + 1; 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 : case SU_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 ); }
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 ); }