1 /*
2 ************************************************************************
3 * Copyright (c) 2007-2011, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 ************************************************************************
6 */
7 
8 #include "fldset.h"
9 #include "intltest.h"
10 
11 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/regex.h"
13 
14 
FieldsSet()15 FieldsSet::FieldsSet() {
16     // NOTREACHED
17 }
18 
FieldsSet(int32_t fieldCount)19 FieldsSet::FieldsSet(int32_t fieldCount) {
20     construct((UDebugEnumType)-1, fieldCount);
21 }
22 
FieldsSet(UDebugEnumType field)23 FieldsSet::FieldsSet(UDebugEnumType field) {
24     construct(field, udbg_enumCount(field));
25 }
26 
~FieldsSet()27 FieldsSet::~FieldsSet() {
28 
29 }
30 
fieldCount() const31 int32_t FieldsSet::fieldCount() const {
32     return fFieldCount;
33 }
34 
construct(UDebugEnumType field,int32_t fieldCount)35 void FieldsSet::construct(UDebugEnumType field, int32_t fieldCount) {
36     fEnum = field;
37     if(fieldCount > U_FIELDS_SET_MAX) {
38         fieldCount = U_FIELDS_SET_MAX;
39     }
40     fFieldCount = fieldCount;
41     clear();
42 }
43 
diffFrom(const FieldsSet & other,UErrorCode & status) const44 UnicodeString FieldsSet::diffFrom(const FieldsSet& other, UErrorCode& status) const {
45     UnicodeString str;
46     if(!isSameType(other)) {
47         status = U_ILLEGAL_ARGUMENT_ERROR;
48         return UnicodeString("U_ILLEGAL_ARGUMENT_ERROR: FieldsSet of a different type!");
49     }
50     for (int i=0; i<fieldCount(); i++) {
51         if (isSet((UCalendarDateFields)i)) {
52             int32_t myVal = get(i);
53             int32_t theirVal = other.get(i);
54 
55             if(fEnum != -1) {
56                 const UnicodeString& fieldName = udbg_enumString(
57                         fEnum, i);
58 
59                 str = str + fieldName + UnicodeString("=")+myVal+UnicodeString(" not ")+theirVal+UnicodeString(", ");
60             } else {
61                 str = str + UnicodeString("some field") + "=" + myVal+" not " + theirVal+", ";
62             }
63         }
64     }
65     return str;
66 }
67 
split(const UnicodeString & src,UChar ch,int32_t & splits)68 static UnicodeString *split(const UnicodeString &src, UChar ch, int32_t &splits)
69 {
70     int32_t offset = -1;
71 
72     splits = 1;
73     while((offset = src.indexOf(ch, offset + 1)) >= 0) {
74         splits += 1;
75     }
76 
77     UnicodeString *result = new UnicodeString[splits];
78 
79     int32_t start = 0;
80     int32_t split = 0;
81     int32_t end;
82 
83     while((end = src.indexOf(ch, start)) >= 0) {
84         src.extractBetween(start, end, result[split++]);
85         start = end + 1;
86     }
87 
88     src.extractBetween(start, src.length(), result[split]);
89 
90     return result;
91 }
92 
parseFrom(const UnicodeString & str,const FieldsSet * inheritFrom,UErrorCode & status)93 int32_t FieldsSet::parseFrom(const UnicodeString& str, const
94         FieldsSet* inheritFrom, UErrorCode& status) {
95 
96     int goodFields = 0;
97 
98     if(U_FAILURE(status)) {
99         return -1;
100     }
101 
102     int32_t destCount = 0;
103     UnicodeString *dest = split(str, 0x002C /* ',' */, destCount);
104 
105     for(int i = 0; i < destCount; i += 1) {
106         int32_t dc = 0;
107         UnicodeString *kv = split(dest[i], 0x003D /* '=' */, dc);
108 
109         if(dc != 2) {
110             it_errln(UnicodeString("dc == ") + dc + UnicodeString("?"));
111         }
112 
113         int32_t field = handleParseName(inheritFrom, kv[0], kv[1], status);
114 
115         if(U_FAILURE(status)) {
116             char ch[256];
117             const UChar *u = kv[0].getBuffer();
118             int32_t len = kv[0].length();
119             u_UCharsToChars(u, ch, len);
120             ch[len] = 0; /* include terminating \0 */
121             it_errln(UnicodeString("Parse Failed: Field ") + UnicodeString(ch) + UnicodeString(", err ") + UnicodeString(u_errorName(status)));
122             delete[] kv;
123             delete[] dest;
124             return -1;
125         }
126 
127         if(field != -1) {
128             handleParseValue(inheritFrom, field, kv[1], status);
129 
130             if(U_FAILURE(status)) {
131                 char ch[256];
132                 const UChar *u = kv[1].getBuffer();
133                 int32_t len = kv[1].length();
134                 u_UCharsToChars(u, ch, len);
135                 ch[len] = 0; /* include terminating \0 */
136                 it_errln(UnicodeString("Parse Failed: Value ") + UnicodeString(ch) + UnicodeString(", err ") + UnicodeString(u_errorName(status)));
137                 delete[] kv;
138                 delete[] dest;
139                 return -1;
140             }
141 
142             goodFields += 1;
143         }
144 
145         delete[] kv;
146     }
147 
148     delete[] dest;
149 
150     return goodFields;
151 }
152 
isSameType(const FieldsSet & other) const153 UBool FieldsSet::isSameType(const FieldsSet& other) const {
154     return((&other==this)||
155            ((other.fFieldCount==fFieldCount) && (other.fEnum==fEnum)));
156 }
157 
clear()158 void FieldsSet::clear() {
159     for (int i=0; i<fieldCount(); i++) {
160         fValue[i]=-1;
161         fIsSet[i]=FALSE;
162     }
163 }
164 
clear(int32_t field)165 void FieldsSet::clear(int32_t field) {
166     if (field<0|| field>=fieldCount()) {
167         return;
168     }
169     fValue[field] = -1;
170     fIsSet[field] = FALSE;
171 }
set(int32_t field,int32_t amount)172 void FieldsSet::set(int32_t field, int32_t amount) {
173     if (field<0|| field>=fieldCount()) {
174         return;
175     }
176     fValue[field] = amount;
177     fIsSet[field] = TRUE;
178 }
179 
isSet(int32_t field) const180 UBool FieldsSet::isSet(int32_t field) const {
181     if (field<0|| field>=fieldCount()) {
182         return FALSE;
183     }
184     return fIsSet[field];
185 }
get(int32_t field) const186 int32_t FieldsSet::get(int32_t field) const {
187     if (field<0|| field>=fieldCount()) {
188         return -1;
189     }
190     return fValue[field];
191 }
192 
193 
handleParseName(const FieldsSet *,const UnicodeString & name,const UnicodeString &,UErrorCode & status)194 int32_t FieldsSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr*/ , UErrorCode& status) {
195     if(fEnum > -1) {
196         int32_t which = udbg_enumByString(fEnum, name);
197         if(which == UDBG_INVALID_ENUM) {
198             status = U_UNSUPPORTED_ERROR;
199         }
200         return which;
201     } else {
202         status = U_UNSUPPORTED_ERROR;
203         return -1;
204     }
205 }
206 
parseValueDefault(const FieldsSet * inheritFrom,int32_t field,const UnicodeString & substr,UErrorCode & status)207 void FieldsSet::parseValueDefault(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
208     int32_t value = -1;
209     if(substr.length()==0) { // inherit requested
210         // inherit
211         if((inheritFrom == NULL) || !inheritFrom->isSet((UCalendarDateFields)field)) {
212             // couldn't inherit from field
213             it_errln(UnicodeString("Parse Failed: Couldn't inherit field ") + field + UnicodeString(" [") + UnicodeString(udbg_enumName(fEnum, field)) + UnicodeString("]"));
214             status = U_ILLEGAL_ARGUMENT_ERROR;
215             return;
216         }
217         value = inheritFrom->get((UCalendarDateFields)field);
218     } else {
219         value = udbg_stoi(substr);
220     }
221     set(field, value);
222 }
223 
parseValueEnum(UDebugEnumType type,const FieldsSet * inheritFrom,int32_t field,const UnicodeString & substr,UErrorCode & status)224 void FieldsSet::parseValueEnum(UDebugEnumType type, const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
225     int32_t value = udbg_enumByString(type, substr);
226     if(value>=0) {
227         set(field, value);
228     } else {
229         // fallback
230         parseValueDefault(inheritFrom,field,substr,status);
231     }
232 }
233 
handleParseValue(const FieldsSet * inheritFrom,int32_t field,const UnicodeString & substr,UErrorCode & status)234 void FieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
235     parseValueDefault(inheritFrom, field, substr, status);
236 }
237 
238 /// CAL FIELDS
239 
240 
CalendarFieldsSet()241 CalendarFieldsSet::CalendarFieldsSet() :
242 FieldsSet(UDBG_UCalendarDateFields) {
243     // base class will call clear.
244 }
245 
~CalendarFieldsSet()246 CalendarFieldsSet::~CalendarFieldsSet() {
247 }
248 
handleParseValue(const FieldsSet * inheritFrom,int32_t field,const UnicodeString & substr,UErrorCode & status)249 void CalendarFieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
250     if(field==UCAL_MONTH) {
251         parseValueEnum(UDBG_UCalendarMonths, inheritFrom, field, substr, status);
252         // will fallback to default.
253     } else {
254         parseValueDefault(inheritFrom, field, substr, status);
255     }
256 }
257 
258 /**
259  * set the specified fields on this calendar. Doesn't clear first. Returns any errors the caller
260  */
setOnCalendar(Calendar * cal,UErrorCode &) const261 void CalendarFieldsSet::setOnCalendar(Calendar *cal, UErrorCode& /*status*/) const {
262     for (int i=0; i<UDAT_FIELD_COUNT; i++) {
263         if (isSet((UCalendarDateFields)i)) {
264             int32_t value = get((UCalendarDateFields)i);
265             cal->set((UCalendarDateFields)i, value);
266         }
267     }
268 }
269 
270 /**
271  * return true if the calendar matches in these fields
272  */
matches(Calendar * cal,CalendarFieldsSet & diffSet,UErrorCode & status) const273 UBool CalendarFieldsSet::matches(Calendar *cal, CalendarFieldsSet &diffSet,
274         UErrorCode& status) const {
275     UBool match = TRUE;
276     if (U_FAILURE(status)) {
277         return FALSE;
278     }
279     for (int i=0; i<UDAT_FIELD_COUNT; i++) {
280         if (isSet((UCalendarDateFields)i)) {
281             int32_t calVal = cal->get((UCalendarDateFields)i, status);
282             if (U_FAILURE(status))
283                 return FALSE;
284             if (calVal != get((UCalendarDateFields)i)) {
285                 match = FALSE;
286                 diffSet.set((UCalendarDateFields)i, calVal);
287                 //fprintf(stderr, "match failed: %s#%d=%d != %d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,cal->get((UCalendarDateFields)i,status), get((UCalendarDateFields)i));;
288             }
289         }
290     }
291     return match;
292 }
293 
294 
295 /**
296  * DateTimeStyleSet has two 'fields' -- date, and time.
297  */
298 enum DateTimeStyleSetFields {
299     DTS_DATE = 0,  /** Field one: the date (long, medium, short, etc). */
300     DTS_TIME,      /** Field two: the time (long, medium, short, etc). */
301     DTS_COUNT      /** The number of fields */
302 };
303 
304 /**
305  * DateTimeSet
306  * */
DateTimeStyleSet()307 DateTimeStyleSet::DateTimeStyleSet() :
308     FieldsSet(DTS_COUNT) {
309 }
310 
~DateTimeStyleSet()311 DateTimeStyleSet::~DateTimeStyleSet() {
312 
313 }
314 
getDateStyle() const315 UDateFormatStyle DateTimeStyleSet::getDateStyle() const {
316     if(!isSet(DTS_DATE)) {
317         return UDAT_NONE;
318     } else {
319         return (UDateFormatStyle)get(DTS_DATE);
320     }
321 }
322 
323 
getTimeStyle() const324 UDateFormatStyle DateTimeStyleSet::getTimeStyle() const {
325     if(!isSet(DTS_TIME)) {
326         return UDAT_NONE;
327     } else {
328         return (UDateFormatStyle)get(DTS_TIME);
329     }
330 }
331 
handleParseValue(const FieldsSet * inheritFrom,int32_t field,const UnicodeString & substr,UErrorCode & status)332 void DateTimeStyleSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
333     UnicodeString kRELATIVE_("RELATIVE_");
334     if(substr.startsWith(kRELATIVE_)) {
335         UnicodeString relativeas(substr,kRELATIVE_.length());
336         parseValueEnum(UDBG_UDateFormatStyle, inheritFrom, field, relativeas, status);
337         // fix relative value
338         if(isSet(field) && U_SUCCESS(status)) {
339             set(field, get(field) | UDAT_RELATIVE);
340         }
341     } else {
342         parseValueEnum(UDBG_UDateFormatStyle, inheritFrom, field, substr, status);
343     }
344 }
345 
handleParseName(const FieldsSet *,const UnicodeString & name,const UnicodeString &,UErrorCode & status)346 int32_t DateTimeStyleSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr */, UErrorCode& status) {
347     UnicodeString kDATE("DATE"); // TODO: static
348     UnicodeString kTIME("TIME"); // TODO: static
349     if(name == kDATE ) {
350         return DTS_DATE;
351     } else if(name == kTIME) {
352         return DTS_TIME;
353     } else {
354         status = U_ILLEGAL_ARGUMENT_ERROR;
355         return -1;
356     }
357 }
358 
359 #endif /*!UCONFIG_NO_FORMAT*/
360