1 #include "Core.h"
2 
3 namespace Upp {
4 
stou(const char * s,void * endptr,unsigned base)5 unsigned stou(const char *s, void *endptr, unsigned base)
6 {
7 	ASSERT(base >= 2 && base <= 36);
8 	unsigned digit = ctoi(*s);
9 	if(digit >= base)
10 	{ // error
11 		if(endptr)
12 			*(const char **)endptr = s;
13 		return ~0;
14 	}
15 	unsigned value = digit;
16 	while((digit = ctoi(*++s)) < base) {
17 		unsigned v0 = value;
18 		value = value * base + digit;
19 		if(v0 > value) // overflow
20 			return ~0;
21 	}
22 	if(endptr)
23 		*(const char **)endptr = s;
24 	return value;
25 }
26 
stou(const wchar * s,void * endptr,unsigned base)27 unsigned stou(const wchar *s, void *endptr, unsigned base)
28 {
29 	ASSERT(base >= 2 && base <= 36);
30 	unsigned digit = ctoi(*s);
31 	if(digit >= base)
32 	{ // error
33 		if(endptr)
34 			*(const wchar **)endptr = s;
35 		return ~0;
36 	}
37 	unsigned value = digit;
38 	while((digit = ctoi(*++s)) < base) {
39 		unsigned v0 = value;
40 		value = value * base + digit;
41 		if(v0 > value) // overflow
42 			return ~0;
43 	}
44 	if(endptr)
45 		*(const wchar **)endptr = s;
46 	return value;
47 }
48 
49 
stou64(const char * s,void * endptr,unsigned base)50 uint64 stou64(const char *s, void *endptr, unsigned base)
51 {
52 	ASSERT(base >= 2 && base <= 36);
53 	unsigned digit = ctoi(*s);
54 	if(digit >= base)
55 	{ // error
56 		if(endptr)
57 			*(const char **)endptr = s;
58 		return ~0;
59 	}
60 	uint64 value = digit;
61 	while((digit = ctoi(*++s)) < base) {
62 		uint64 v0 = value;
63 		value = value * base + digit;
64 		if(v0 > value) // overflow
65 			return ~0;
66 	}
67 	if(endptr)
68 		*(const char **)endptr = s;
69 	return value;
70 }
71 
ScanInt(const char * ptr,const char ** endptr,int base)72 int ScanInt(const char *ptr, const char **endptr, int base)
73 {
74 	const char *s = ptr;
75 	bool minus = false;
76 	while(*s && (byte)*s <= ' ')
77 		s++;
78 	if(*s == '+' || *s == '-')
79 		minus = (*s++ == '-');
80 	unsigned u = stou(s, endptr, base);
81 	if(~u)
82 		return (minus ? -(int)u : (int)u);
83 	else
84 		return Null;
85 }
86 
ScanInt(const wchar * ptr,const wchar ** endptr,int base)87 int ScanInt(const wchar *ptr, const wchar **endptr, int base)
88 {
89 	const wchar *s = ptr;
90 	bool minus = false;
91 	while(*s && *s <= ' ')
92 		s++;
93 	if(*s == '+' || *s == '-')
94 		minus = (*s++ == '-');
95 	unsigned u = stou(s, endptr, base);
96 	if(~u)
97 		return (minus ? -(int)u : (int)u);
98 	else
99 		return Null;
100 }
101 
ScanInt64(const char * ptr,const char ** endptr,int base)102 int64 ScanInt64(const char *ptr, const char **endptr, int base)
103 {
104 	const char *s = ptr;
105 	bool minus = false;
106 	while(*s && *s <= ' ')
107 		s++;
108 	if(*s == '+' || *s == '-')
109 		minus = (*s++ == '-');
110 	uint64 u = stou64(s, endptr, base);
111 	if(~u)
112 		return (minus ? -(int64)u : (int64)u);
113 	else
114 		return Null;
115 }
116 
117 template <class T>
ScanDoubleT(const T * p,const T ** endptr,bool accept_comma)118 double ScanDoubleT(const T *p, const T **endptr, bool accept_comma)
119 {
120 	const T *begin = p;
121 	while(*p && (byte)*p <= ' ')
122 		p++;
123 	bool neg = false;
124 	if(endptr)
125 		*endptr = p;
126 	if(*p == '+' || *p == '-')
127 		neg = (*p++ == '-');
128 	if((byte)(*p - '0') >= 10 && !((*p == '.' || accept_comma && *p == ',') && (byte)(p[1] - '0') < 10)) {
129 		if(endptr) *endptr = begin;
130 		return Null;
131 	}
132 	double mantissa = 0;
133 	T c;
134 	int exp = 0;
135 	while((byte)(*p - '0') < 10)
136 		if((c = *p++) != '0') {
137 			if(exp) { mantissa *= ipow10(exp); exp = 0; }
138 			mantissa = 10 * mantissa + c - '0';
139 		}
140 		else
141 			exp++;
142 	int raise = exp;
143 	if(*p == '.' || accept_comma && *p == ',') // decimal part
144 		while((byte)((c = *++p) - '0') < 10) {
145 			if(c != '0') {
146 				if(raise) {
147 					mantissa *= ipow10(raise);
148 					exp -= raise;
149 					raise = 0;
150 				}
151 				exp--;
152 				mantissa = 10 * mantissa + c - '0';
153 				if(!IsFin(mantissa))
154 					return Null;
155 			}
156 			else
157 				raise++;
158 		}
159 	if(*p == 'E' || *p == 'e') { // exponent
160 		int vexp = ScanInt(p + 1, &p);
161 		if(IsNull(vexp))
162 			return Null;
163 		exp += vexp;
164 	}
165 	if(endptr) *endptr = p;
166 	if(exp) {
167 		double e = ipow10(tabs(exp));
168 		mantissa = (exp > 0 ? mantissa * e : mantissa / e);
169 	}
170 	if(!IsFin(mantissa))
171 		return Null;
172 	return neg ? -mantissa : mantissa;
173 }
174 
ScanDouble(const char * p,const char ** endptr,bool accept_comma)175 double ScanDouble(const char *p, const char **endptr, bool accept_comma)
176 {
177 	return ScanDoubleT(p, endptr, accept_comma);
178 }
179 
ScanDouble(const wchar * p,const wchar ** endptr,bool accept_comma)180 double ScanDouble(const wchar *p, const wchar **endptr, bool accept_comma)
181 {
182 	return ScanDoubleT(p, endptr, accept_comma);
183 }
184 
Atof(const char * s)185 double Atof(const char *s)
186 {
187 	return Nvl(ScanDouble(s));
188 }
189 
StrIntValue(const char * s)190 Value StrIntValue(const char *s)
191 {
192 	if(s && *s) {
193 		const char *p;
194 		int64 q = ScanInt64(s, &p);
195 		if(!IsNull(q))
196 			while(*p) {
197 				if((byte)*p > ' ')
198 					return ErrorValue(t_("Invalid number !"));
199 				p++;
200 			}
201 		return IsNull(q) ? ErrorValue(t_("Invalid number !")) : Value(q);
202 	}
203 	return (int)Null;
204 }
205 
StrDblValue(const char * s)206 Value StrDblValue(const char *s)
207 {
208 	if(s && *s) {
209 		const char *p;
210 		double q = ScanDouble(s, &p);
211 		if(!IsNull(q))
212 			while(*p) {
213 				if((byte)*p > ' ')
214 					return ErrorValue(t_("Invalid number !"));
215 				p++;
216 			}
217 		return IsNull(q) ? ErrorValue(t_("Invalid number !")) : Value(q);
218 	}
219 	return (double)Null;
220 }
221 
Scan(dword qtype,const String & text,const Value & def,bool * hastime)222 Value Scan(dword qtype, const String& text, const Value& def, bool *hastime) {
223 	Date date;
224 	const char *s;
225 	if(hastime)
226 		*hastime = false;
227 	switch(qtype) {
228 	case INT64_V:
229 	case INT_V:
230 	case BOOL_V:
231 		return StrIntValue(text);
232 	case DATE_V:
233 		if(text.IsEmpty()) return (Date) Null;
234 		s = StrToDate(date, text, (Date)def);
235 		if(s)
236 			for(;;) {
237 				if(IsDigit(*s))
238 					break;
239 				if(*s == '\0')
240 					return date;
241 				s++;
242 			}
243 		return ErrorValue(t_("Invalid date !"));
244 	case TIME_V: {
245 		if(text.IsEmpty()) return (Time) Null;
246 		s = StrToDate(date, text, (Date)def);
247 		if(s)
248 			try {
249 				CParser p(s);
250 				Time tm = ToTime(date);
251 				Time d = (Time)def;
252 				tm.hour = d.hour;
253 				tm.minute = d.minute;
254 				tm.second = d.second;
255 				if(p.IsEof())
256 					return tm;
257 				if(hastime)
258 					*hastime = true;
259 				int q = p.ReadInt();
260 				if(q < 0 || q > 23)
261 					throw CParser::Error("");
262 				tm.hour = q;
263 				if(p.IsEof())
264 					return tm;
265 				p.PassChar(':');
266 				q = p.ReadInt();
267 				if(q < 0 || q > 59)
268 					throw CParser::Error("");
269 				tm.minute = q;
270 				if(p.IsEof())
271 					return tm;
272 				p.PassChar(':');
273 				q = p.ReadInt();
274 				if(q < 0 || q > 59)
275 					throw CParser::Error("");
276 				tm.second = q;
277 				if(p.IsEof())
278 					return tm;
279 			}
280 			catch(CParser::Error) {}
281 		return ErrorValue(t_("Invalid time !"));
282 	}
283 	case STRING_V:
284 	case WSTRING_V:
285 		return text;
286 	case DOUBLE_V:
287 		return StrDblValue(text);
288 	default:
289 		ASSERT(0);
290 		break;
291 	}
292 	return Null;
293 }
294 
Convert()295 Convert::Convert() {}
~Convert()296 Convert::~Convert() {}
297 
Format(const Value & q) const298 Value  Convert::Format(const Value& q) const {
299 	if(IsVoid(q) || q.IsNull()) return String();
300 	switch(q.GetType()) {
301 	case INT64_V:
302 		return IntStr64((int64)q);
303 	case INT_V:
304 	case BOOL_V:
305 		return IntStr((int)q);
306 	case DOUBLE_V:
307 		return DblStr((double)q);
308 	case DATE_V:
309 		return UPP::Format(Date(q));
310 	case TIME_V:
311 		return UPP::Format(Time(q));
312 	case STRING_V:
313 	case WSTRING_V:
314 		return q;
315 	}
316 	return q.ToString();
317 }
318 
Scan(const Value & text) const319 Value  Convert::Scan(const Value& text) const {
320 	return text;
321 };
322 
Filter(int chr) const323 int    Convert::Filter(int chr) const {
324 	return chr;
325 }
326 
StdConvert()327 const Convert& StdConvert()
328 {
329 	static Convert h;
330 	return h;
331 }
332 
StdFormat(const Value & q)333 String StdFormat(const Value& q) {
334 	return StdConvert().Format(q);
335 }
336 
NotNullError()337 Value NotNullError() {
338 	return ErrorValue(t_("Null value not allowed."));
339 }
340 
Scan(const Value & text) const341 Value ConvertInt::Scan(const Value& text) const {
342 	Value v = UPP::Scan(INT_V, text);
343 	if(IsError(v)) return v;
344 	if(IsNull(v)) return notnull ? NotNullError() : v;
345 	int64 m = v;
346 	if(m >= minval && m <= maxval) {
347 		if(m >= INT_MIN && m <= INT_MAX)
348 			return (int)m;
349 		else
350 			return v;
351 	}
352 	return ErrorValue(UPP::Format(t_("Number must be between %d and %d."), minval, maxval));
353 }
354 
Filter(int chr) const355 int   ConvertInt::Filter(int chr) const {
356 	return minval >= 0 ? CharFilterDigit(chr) : CharFilterInt(chr);
357 }
358 
Format(const Value & q) const359 Value ConvertDouble::Format(const Value& q) const
360 {
361 	if(IsNull(q))
362 		return Null;
363 	return UPP::Format(pattern, (double)q);
364 }
365 
Scan(const Value & txt) const366 Value ConvertDouble::Scan(const Value& txt) const {
367 	String text = txt;
368 	if(pattern.GetCount() && pattern != "%.10g") { // Fix text with patterns like "%2.!n EUR" (e.g. 1.2 EUR)
369 		text = UPP::Filter(text, CharFilterDouble);
370 		while(ToUpper(*text.Last()) == 'E')
371 			text.Trim(text.GetCount() - 1);
372 	}
373 	Value v = UPP::Scan(DOUBLE_V, text);
374 	if(IsError(v)) return v;
375 	if(IsNull(v)) return notnull ? NotNullError() : v;
376 	double m = v;
377 	if(m >= minval && m <= maxval) return v;
378 	return ErrorValue(UPP::Format(t_("Number must be between %g and %g."), minval, maxval));
379 }
380 
Filter(int chr) const381 int   ConvertDouble::Filter(int chr) const {
382 	chr = CharFilterDouble(chr);
383 	return comma && chr == '.' ? ',' : chr;
384 }
385 
ConvertDouble(double minval,double maxval,bool notnull)386 ConvertDouble::ConvertDouble(double minval, double maxval, bool notnull)
387   : minval(minval), maxval(maxval), notnull(notnull)
388 {
389 	pattern = "%.10g";
390 	comma = false;
391 }
392 
Pattern(const char * p)393 ConvertDouble& ConvertDouble::Pattern(const char *p)
394 {
395 	pattern = p;
396 	comma = String(Format(1.1)).Find(',') >= 0;
397 	return *this;
398 }
399 
default_min()400 Date& ConvertDate::default_min()
401 {
402 	static Date v = Date::Low();
403 	return v;
404 }
405 
default_max()406 Date& ConvertDate::default_max()
407 {
408 	static Date v = Date::High();
409 	return v;
410 }
411 
SetDefaultMinMax(Date min,Date max)412 void ConvertDate::SetDefaultMinMax(Date min, Date max)
413 {
414 	default_min() = min;
415 	default_max() = max;
416 }
417 
ConvertDate(Date minval,Date maxval,bool notnull)418 ConvertDate::ConvertDate(Date minval, Date maxval, bool notnull)
419 : minval(minval), maxval(maxval), notnull(notnull) {
420 	defaultval = Null;
421 }
422 
Format(const Value & q) const423 Value ConvertDate::Format(const Value& q) const
424 {
425 	if(IsDateTime(q))
426 		return Convert::Format((Date)q);
427 	return Convert::Format(q);
428 }
429 
Scan(const Value & text) const430 Value ConvertDate::Scan(const Value& text) const {
431 	Value v = UPP::Scan(DATE_V, text, defaultval);
432 	if(IsError(v)) return v;
433 	if(IsNull(v)) return notnull ? NotNullError() : v;
434 	Date m = v;
435 	Date minval = GetMin();
436 	Date maxval = GetMax();
437 	if(m >= minval && m <= maxval) return v;
438 	return ErrorValue(t_("Date must be between ") + UPP::Format(minval) + t_("range\v and ") + UPP::Format(maxval) + ".");
439 }
440 
Filter(int chr) const441 int   ConvertDate::Filter(int chr) const {
442 	return CharFilterDate(chr);
443 }
444 
ConvertTime(Time minval,Time maxval,bool notnull)445 ConvertTime::ConvertTime(Time minval, Time maxval, bool notnull)
446 : minval(minval), maxval(maxval), notnull(notnull), seconds(true) {
447 	defaultval = Null;
448 	timealways = false;
449 	dayend = false;
450 }
451 
~ConvertTime()452 ConvertTime::~ConvertTime()
453 {
454 }
455 
Scan(const Value & text) const456 Value ConvertTime::Scan(const Value& text) const
457 {
458 	bool hastime;
459 	Value v = UPP::Scan(TIME_V, text, defaultval, &hastime);
460 	if(IsError(v)) return v;
461 	if(IsNull(v)) return notnull ? NotNullError() : v;
462 	Time m = v;
463 	if(!hastime && dayend) {
464 		m.hour = 23;
465 		m.minute = 59;
466 		m.second = 59;
467 		v = m;
468 	}
469 	Time minval = GetMin();
470 	Time maxval = GetMax();
471 	if(m >= minval && m <= maxval) return v;
472 	return ErrorValue(t_("Time must be between ") + UPP::Format(minval) + t_("range\v and ") + UPP::Format(maxval) + ".");
473 }
474 
Filter(int chr) const475 int ConvertTime::Filter(int chr) const
476 {
477 	if(IsDigit(chr) || chr == ' ' || chr == '.' || chr == ':')
478 		return chr;
479 	if(chr == ',')
480 		return '.';
481 	return CharFilterDate(chr);
482 }
483 
Format(const Value & q) const484 Value ConvertTime::Format(const Value& q) const
485 {
486 	if(IsVoid(q) || q.IsNull())
487 		return String();
488 	else
489 	if(q.GetType() == TIME_V || timealways)
490 		return ToTime((Date)q) != (Time)q || timealways ? UPP::Format(Time(q), seconds) : UPP::Format(Date(q));
491 	else
492 		return Convert::Format(q);
493 }
494 
Scan(const Value & text) const495 Value ConvertString::Scan(const Value& text) const {
496 	if(IsError(text)) return text;
497 	if(text.GetType() == STRING_V) {
498 		String s = text;
499 		if(trimleft)
500 			s = Upp::TrimLeft(s);
501 		if(trimright)
502 			s = Upp::TrimRight(s);
503 		if(IsNull(s)) return notnull ? NotNullError() : Value(s);
504 		if(s.GetLength() <= maxlen) return s;
505 	}
506 	if(text.GetType() == WSTRING_V) {
507 		WString s = text;
508 		if(trimleft)
509 			s = Upp::TrimLeft(s);
510 		if(trimright)
511 			s = Upp::TrimRight(s);
512 		if(IsNull(s)) return notnull ? NotNullError() : Value(s);
513 		if(s.GetLength() <= maxlen) return s;
514 	}
515 	return ErrorValue(UPP::Format(t_("Please enter no more than %d characters."), maxlen));
516 }
517 
StdConvertInt()518 const ConvertInt& StdConvertInt() { static ConvertInt h; return h; }
StdConvertIntNotNull()519 const ConvertInt& StdConvertIntNotNull() { static ConvertInt h(-INT_MAX, INT_MAX, true); return h; }
520 
StdConvertDouble()521 const ConvertDouble& StdConvertDouble() { static ConvertDouble h; return h; }
StdConvertDoubleNotNull()522 const ConvertDouble& StdConvertDoubleNotNull() { static ConvertDouble h(DOUBLE_NULL_LIM, -DOUBLE_NULL_LIM, true); return h; }
523 
StdConvertDate()524 const ConvertDate& StdConvertDate() { static ConvertDate h; return h; }
StdConvertDateNotNull()525 const ConvertDate& StdConvertDateNotNull() { static ConvertDate h(Date(0, 0, 0), Date(3000, 12, 31), true); return h; }
526 
StdConvertTime()527 const ConvertTime& StdConvertTime() { static ConvertTime h; return h; }
StdConvertTimeNotNull()528 const ConvertTime& StdConvertTimeNotNull() { static ConvertTime h(Null, Null, true); return h; }
529 
StdConvertString()530 const ConvertString& StdConvertString() { static ConvertString h; return h; }
StdConvertStringNotNull()531 const ConvertString& StdConvertStringNotNull() { static ConvertString h(INT_MAX, true); return h; }
532 
Format(const Value & q) const533 Value  MapConvert::Format(const Value& q) const {
534 	return map.Get(q, default_value);
535 }
536 
NoConvertClass()537 NoConvertClass::NoConvertClass() {}
538 
Format(const Value & q) const539 Value NoConvertClass::Format(const Value& q) const {
540 	return q;
541 }
542 
NoConvert()543 const NoConvertClass& NoConvert() {
544 	return Single<NoConvertClass>();
545 }
546 
Scan(const Value & v) const547 Value ErrorConvertClass::Scan(const Value& v) const
548 {
549 	return ErrorValue();
550 }
551 
ErrorConvert()552 const ErrorConvertClass& ErrorConvert()
553 {
554 	return Single<ErrorConvertClass>();
555 }
556 
Format(const Value & v) const557 Value JoinConvert::Format(const Value& v) const {
558 	String r;
559 	ValueArray a = v;
560 	for(int i = 0; i < item.GetCount(); i++) {
561 		const Item& m = item[i];
562 		if(m.pos < 0)
563 			r << m.text;
564 		else
565 			r << (String) StdConvert().Format(m.convert->Format(a[m.pos]));
566 	}
567 	return r;
568 }
569 
NextPos() const570 int JoinConvert::NextPos() const {
571 	for(int i = item.GetCount() - 1; i >= 0; i--)
572 		if(item[i].pos >= 0) return item[i].pos + 1;
573 	return 0;
574 }
575 
Add(const char * text)576 JoinConvert& JoinConvert::Add(const char *text) {
577 	Item& m = item.Add();
578 	m.pos = -1;
579 	m.text = text;
580 	return *this;
581 }
582 
Add(int pos,const Convert & cv)583 JoinConvert& JoinConvert::Add(int pos, const Convert& cv) {
584 	ASSERT(pos >= 0);
585 	Item& m = item.Add();
586 	m.pos = pos;
587 	m.convert = &cv;
588 	return *this;
589 }
590 
Add(int pos)591 JoinConvert& JoinConvert::Add(int pos) {
592 	Add(pos, StdConvert());
593 	return *this;
594 }
595 
Add(const Convert & cv)596 JoinConvert& JoinConvert::Add(const Convert& cv) {
597 	Add(NextPos(), cv);
598 	return *this;
599 }
600 
Add()601 JoinConvert& JoinConvert::Add() {
602 	Add(NextPos());
603 	return *this;
604 }
605 
Format(const Value & v) const606 Value FormatConvert::Format(const Value& v) const
607 {
608 	ValueArray va;
609 	if(IsValueArray(v))
610 		va = v;
611 	else
612 		va.Add(v);
613 	return UPP::Format(format, va.Get());
614 }
615 
616 }
617