blob: 7eed0d6dc046bcd71fcddaeff6b102754b1b129c [file] [log] [blame]
/*
*******************************************************************************
*
* Copyright (C) 1998-1999, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
*
* File uprntf_p.c
*
* Modification History:
*
* Date Name Description
* 11/23/98 stephen Creation.
* 03/12/99 stephen Modified for new C API.
*******************************************************************************
*/
#include "uprntf_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_printf_parse_spec (const UChar *fmt,
u_printf_spec *spec)
{
const UChar *s = fmt;
const UChar *backup;
/* initialize spec to default values */
spec->fWidthPos = -1;
spec->fPrecisionPos = -1;
spec->fArgPos = -1;
spec->fInfo.fPrecision = -1;
spec->fInfo.fWidth = -1;
spec->fInfo.fSpec = 0x0000;
spec->fInfo.fPadChar = 0x0020;
spec->fInfo.fAlt = FALSE;
spec->fInfo.fSpace = FALSE;
spec->fInfo.fLeft = FALSE;
spec->fInfo.fShowSign = FALSE;
spec->fInfo.fZero = FALSE;
spec->fInfo.fIsLongDouble = FALSE;
spec->fInfo.fIsShort = FALSE;
spec->fInfo.fIsLong = FALSE;
spec->fInfo.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:
spec->fInfo.fLeft = TRUE;
break;
/* always show sign */
case FLAG_PLUS:
spec->fInfo.fShowSign = TRUE;
break;
/* use space if no sign present */
case FLAG_SPACE:
spec->fInfo.fSpace = TRUE;
break;
/* use alternate form */
case FLAG_POUND:
spec->fInfo.fAlt = TRUE;
break;
/* pad with leading zeroes */
case FLAG_ZERO:
spec->fInfo.fZero = TRUE;
spec->fInfo.fPadChar = 0x0030;
break;
/* pad character specified */
case FLAG_PAREN:
/* first four characters are hex values for pad char */
spec->fInfo.fPadChar = ufmt_digitvalue(*s++);
spec->fInfo.fPadChar *= 16;
spec->fInfo.fPadChar += ufmt_digitvalue(*s++);
spec->fInfo.fPadChar *= 16;
spec->fInfo.fPadChar += ufmt_digitvalue(*s++);
spec->fInfo.fPadChar *= 16;
spec->fInfo.fPadChar += ufmt_digitvalue(*s++);
/* final character is ignored */
*s++;
break;
}
}
/* Get the width */
/* width is specified out of line */
if(*s == SPEC_ASTERISK) {
spec->fInfo.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)){
spec->fInfo.fWidth = (int) (*s++ - DIGIT_ZERO);
while(ISDIGIT(*s)) {
spec->fInfo.fWidth *= 10;
spec->fInfo.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) {
spec->fInfo.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)){
spec->fInfo.fPrecision = (int) (*s++ - DIGIT_ZERO);
while(ISDIGIT(*s)) {
spec->fInfo.fPrecision *= 10;
spec->fInfo.fPrecision += (int) (*s++ - DIGIT_ZERO);
}
}
}
/* Get any modifiers */
if(ISMOD(*s)) {
switch(*s++) {
/* short */
case MOD_H:
spec->fInfo.fIsShort = TRUE;
break;
/* long or long long */
case MOD_LOWERL:
if(*s == MOD_LOWERL) {
spec->fInfo.fIsLongLong = TRUE;
/* skip over the next 'l' */
*s++;
}
else
spec->fInfo.fIsLong = TRUE;
break;
/* long double */
case MOD_L:
spec->fInfo.fIsLongDouble = TRUE;
break;
}
}
/* finally, get the specifier letter */
spec->fInfo.fSpec = *s++;
/* return # of characters in this specifier */
return (s - fmt);
}