|  | /* | 
|  | ****************************************************************************** | 
|  | * | 
|  | *   Copyright (C) 2000-2001, International Business Machines | 
|  | *   Corporation and others.  All Rights Reserved. | 
|  | * | 
|  | ****************************************************************************** | 
|  | * | 
|  | * File sprntf_p.c | 
|  | * | 
|  | * Modification History: | 
|  | * | 
|  | *   Date        Name        Description | 
|  | *   02/08/00    george      Creation. Copied from uprntf_p.c | 
|  | ****************************************************************************** | 
|  | */ | 
|  |  | 
|  | #include "sprntf_p.h" | 
|  | #include "ufmt_cmn.h" | 
|  |  | 
|  | /* flag characters for uprintf */ | 
|  | #define FLAG_MINUS 0x002D | 
|  | #define FLAG_PLUS 0x002B | 
|  | #define FLAG_SPACE 0x0020 | 
|  | #define FLAG_POUND 0x0023 | 
|  | #define FLAG_ZERO  0x0030 | 
|  | #define FLAG_PAREN 0x0028 | 
|  |  | 
|  | #define ISFLAG(s)    (s) == FLAG_MINUS || \ | 
|  | (s) == FLAG_PLUS || \ | 
|  | (s) == FLAG_SPACE || \ | 
|  | (s) == FLAG_POUND || \ | 
|  | (s) == FLAG_ZERO || \ | 
|  | (s) == FLAG_PAREN | 
|  |  | 
|  | /* special characters for uprintf */ | 
|  | #define SPEC_ASTERISK 0x002A | 
|  | #define SPEC_DOLLARSIGN 0x0024 | 
|  | #define SPEC_PERIOD 0x002E | 
|  | #define SPEC_PERCENT 0x0025 | 
|  |  | 
|  | /* unicode digits */ | 
|  | #define DIGIT_ZERO 0x0030 | 
|  | #define DIGIT_ONE 0x0031 | 
|  | #define DIGIT_TWO 0x0032 | 
|  | #define DIGIT_THREE 0x0033 | 
|  | #define DIGIT_FOUR 0x0034 | 
|  | #define DIGIT_FIVE 0x0035 | 
|  | #define DIGIT_SIX 0x0036 | 
|  | #define DIGIT_SEVEN 0x0037 | 
|  | #define DIGIT_EIGHT 0x0038 | 
|  | #define DIGIT_NINE 0x0039 | 
|  |  | 
|  | #define ISDIGIT(s)    (s) == DIGIT_ZERO || \ | 
|  | (s) == DIGIT_ONE || \ | 
|  | (s) == DIGIT_TWO || \ | 
|  | (s) == DIGIT_THREE || \ | 
|  | (s) == DIGIT_FOUR || \ | 
|  | (s) == DIGIT_FIVE || \ | 
|  | (s) == DIGIT_SIX || \ | 
|  | (s) == DIGIT_SEVEN || \ | 
|  | (s) == DIGIT_EIGHT || \ | 
|  | (s) == DIGIT_NINE | 
|  |  | 
|  | /* u_printf modifiers */ | 
|  | #define MOD_H 0x0068 | 
|  | #define MOD_LOWERL 0x006C | 
|  | #define MOD_L 0x004C | 
|  |  | 
|  | #define ISMOD(s)    (s) == MOD_H || \ | 
|  | (s) == MOD_LOWERL || \ | 
|  | (s) == MOD_L | 
|  |  | 
|  | /* We parse the argument list in Unicode */ | 
|  | int32_t | 
|  | u_sprintf_parse_spec (const UChar     *fmt, | 
|  | u_sprintf_spec    *spec) | 
|  | { | 
|  | const UChar *s = fmt; | 
|  | const UChar *backup; | 
|  | u_sprintf_spec_info *info = &(spec->fInfo); | 
|  |  | 
|  | /* initialize spec to default values */ | 
|  | spec->fWidthPos     = -1; | 
|  | spec->fPrecisionPos = -1; | 
|  | spec->fArgPos       = -1; | 
|  |  | 
|  | info->fPrecision    = -1; | 
|  | info->fWidth        = -1; | 
|  | info->fSpec         = 0x0000; | 
|  | info->fPadChar      = 0x0020; | 
|  | info->fAlt          = FALSE; | 
|  | info->fSpace        = FALSE; | 
|  | info->fLeft         = FALSE; | 
|  | info->fShowSign     = FALSE; | 
|  | info->fZero         = FALSE; | 
|  | info->fIsLongDouble = FALSE; | 
|  | info->fIsShort      = FALSE; | 
|  | info->fIsLong       = FALSE; | 
|  | info->fIsLongLong   = FALSE; | 
|  |  | 
|  | /* skip over the initial '%' */ | 
|  | s++; | 
|  |  | 
|  | /* Check for positional argument */ | 
|  | if(ISDIGIT(*s)) { | 
|  |  | 
|  | /* Save the current position */ | 
|  | backup = s; | 
|  |  | 
|  | /* handle positional parameters */ | 
|  | if(ISDIGIT(*s)) { | 
|  | spec->fArgPos = (int) (*s++ - DIGIT_ZERO); | 
|  |  | 
|  | while(ISDIGIT(*s)) { | 
|  | spec->fArgPos *= 10; | 
|  | spec->fArgPos += (int) (*s++ - DIGIT_ZERO); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* if there is no '$', don't read anything */ | 
|  | if(*s != SPEC_DOLLARSIGN) { | 
|  | spec->fArgPos = -1; | 
|  | s = backup; | 
|  | } | 
|  | /* munge the '$' */ | 
|  | else | 
|  | s++; | 
|  | } | 
|  |  | 
|  | /* Get any format flags */ | 
|  | while(ISFLAG(*s)) { | 
|  | switch(*s++) { | 
|  |  | 
|  | /* left justify */ | 
|  | case FLAG_MINUS: | 
|  | info->fLeft = TRUE; | 
|  | break; | 
|  |  | 
|  | /* always show sign */ | 
|  | case FLAG_PLUS: | 
|  | info->fShowSign = TRUE; | 
|  | break; | 
|  |  | 
|  | /* use space if no sign present */ | 
|  | case FLAG_SPACE: | 
|  | info->fSpace = TRUE; | 
|  | break; | 
|  |  | 
|  | /* use alternate form */ | 
|  | case FLAG_POUND: | 
|  | info->fAlt = TRUE; | 
|  | break; | 
|  |  | 
|  | /* pad with leading zeroes */ | 
|  | case FLAG_ZERO: | 
|  | info->fZero = TRUE; | 
|  | info->fPadChar = 0x0030; | 
|  | break; | 
|  |  | 
|  | /* pad character specified */ | 
|  | case FLAG_PAREN: | 
|  |  | 
|  | /* first four characters are hex values for pad char */ | 
|  | info->fPadChar = (UChar)ufmt_digitvalue(*s++); | 
|  | info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); | 
|  | info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); | 
|  | info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++)); | 
|  |  | 
|  | /* final character is ignored */ | 
|  | s++; | 
|  |  | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the width */ | 
|  |  | 
|  | /* width is specified out of line */ | 
|  | if(*s == SPEC_ASTERISK) { | 
|  |  | 
|  | info->fWidth = -2; | 
|  |  | 
|  | /* Skip the '*' */ | 
|  | s++; | 
|  |  | 
|  | /* Save the current position */ | 
|  | backup = s; | 
|  |  | 
|  | /* handle positional parameters */ | 
|  | if(ISDIGIT(*s)) { | 
|  | spec->fWidthPos = (int) (*s++ - DIGIT_ZERO); | 
|  |  | 
|  | while(ISDIGIT(*s)) { | 
|  | spec->fWidthPos *= 10; | 
|  | spec->fWidthPos += (int) (*s++ - DIGIT_ZERO); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* if there is no '$', don't read anything */ | 
|  | if(*s != SPEC_DOLLARSIGN) { | 
|  | spec->fWidthPos = -1; | 
|  | s = backup; | 
|  | } | 
|  | /* munge the '$' */ | 
|  | else | 
|  | s++; | 
|  | } | 
|  | /* read the width, if present */ | 
|  | else if(ISDIGIT(*s)){ | 
|  | info->fWidth = (int) (*s++ - DIGIT_ZERO); | 
|  |  | 
|  | while(ISDIGIT(*s)) { | 
|  | info->fWidth *= 10; | 
|  | info->fWidth += (int) (*s++ - DIGIT_ZERO); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the precision */ | 
|  |  | 
|  | if(*s == SPEC_PERIOD) { | 
|  |  | 
|  | /* eat up the '.' */ | 
|  | s++; | 
|  |  | 
|  | /* precision is specified out of line */ | 
|  | if(*s == SPEC_ASTERISK) { | 
|  |  | 
|  | info->fPrecision = -2; | 
|  |  | 
|  | /* Skip the '*' */ | 
|  | s++; | 
|  |  | 
|  | /* save the current position */ | 
|  | backup = s; | 
|  |  | 
|  | /* handle positional parameters */ | 
|  | if(ISDIGIT(*s)) { | 
|  | spec->fPrecisionPos = (int) (*s++ - DIGIT_ZERO); | 
|  |  | 
|  | while(ISDIGIT(*s)) { | 
|  | spec->fPrecisionPos *= 10; | 
|  | spec->fPrecisionPos += (int) (*s++ - DIGIT_ZERO); | 
|  | } | 
|  |  | 
|  | /* if there is no '$', don't read anything */ | 
|  | if(*s != SPEC_DOLLARSIGN) { | 
|  | spec->fPrecisionPos = -1; | 
|  | s = backup; | 
|  | } | 
|  | else { | 
|  | /* munge the '$' */ | 
|  | s++; | 
|  | } | 
|  | } | 
|  | } | 
|  | /* read the precision */ | 
|  | else if(ISDIGIT(*s)){ | 
|  | info->fPrecision = (int) (*s++ - DIGIT_ZERO); | 
|  |  | 
|  | while(ISDIGIT(*s)) { | 
|  | info->fPrecision *= 10; | 
|  | info->fPrecision += (int) (*s++ - DIGIT_ZERO); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get any modifiers */ | 
|  | if(ISMOD(*s)) { | 
|  | switch(*s++) { | 
|  |  | 
|  | /* short */ | 
|  | case MOD_H: | 
|  | info->fIsShort = TRUE; | 
|  | break; | 
|  |  | 
|  | /* long or long long */ | 
|  | case MOD_LOWERL: | 
|  | if(*s == MOD_LOWERL) { | 
|  | info->fIsLongLong = TRUE; | 
|  | /* skip over the next 'l' */ | 
|  | s++; | 
|  | } | 
|  | else | 
|  | info->fIsLong = TRUE; | 
|  | break; | 
|  |  | 
|  | /* long double */ | 
|  | case MOD_L: | 
|  | info->fIsLongDouble = TRUE; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* finally, get the specifier letter */ | 
|  | info->fSpec = *s++; | 
|  |  | 
|  | /* return # of characters in this specifier */ | 
|  | return (s - fmt); | 
|  | } |