diff --git a/uppdev/CoreTopics/AString.hpp b/uppdev/CoreTopics/AString.hpp new file mode 100644 index 000000000..340c2a1ef --- /dev/null +++ b/uppdev/CoreTopics/AString.hpp @@ -0,0 +1,205 @@ +template +void AString::Cat(int c, int count) +{ + tchar *s = B::Insert(GetLength(), count, NULL); + while(count--) + *s++ = c; +} + +template +int AString::Compare(const tchar *b) const +{ + const tchar *a = B::Begin(); + const tchar *ae = End(); + for(;;) { + if(a >= ae) + return *b == 0 ? 0 : -1; + if(*b == 0) + return 1; + int q = cmpval__(*a++) - cmpval__(*b++); + if(q) + return q; + } +} + +template +typename AString::String AString::Mid(int from, int count) const +{ + int l = GetLength(); + if(from > l) from = l; + if(from < 0) from = 0; + if(count < 0) + count = 0; + if(from + count > l) + count = l - from; + return String(B::Begin() + from, count); +} + +template +int AString::Find(int chr, int from) const +{ + ASSERT(from >= 0 && from <= GetLength()); + const tchar *e = End(); + const tchar *ptr = B::Begin(); + for(const tchar *s = ptr + from; s < e; s++) + if(*s == chr) + return (int)(s - ptr); + return -1; +} + +template +int AString::ReverseFind(int chr, int from) const +{ + ASSERT(from >= 0 && from <= GetLength()); + if(from < GetLength()) { + const tchar *ptr = B::Begin(); + for(const tchar *s = ptr + from; s >= ptr; s--) + if(*s == chr) + return (int)(s - ptr); + } + return -1; +} + +template +int AString::ReverseFind(int chr) const +{ + return B::GetCount() ? ReverseFind(chr, B::GetCount() - 1) : -1; +} + +template +int AString::Find(int len, const tchar *s, int from) const +{ + ASSERT(from >= 0 && from <= GetLength()); + const tchar *ptr = B::Begin(); + const tchar *p = ptr + from; + int l = GetLength() - len - from; + if(l < 0) + return -1; + const tchar *e = p + l; + len *= sizeof(tchar); + while(p <= e) { + if(memcmp(s, p, len) == 0) + return (int)(p - ptr); + p++; + } + return -1; +} + +template +bool AString::StartsWith(const tchar *s, int len) const +{ + if(len > GetLength()) return false; + return memcmp(s, B::Begin(), len * sizeof(tchar)) == 0; +} + +template +bool AString::EndsWith(const tchar *s, int len) const +{ + int l = GetLength(); + if(len > l) return false; + return memcmp(s, B::Begin() + l - len, len * sizeof(tchar)) == 0; +} + +template +int AString::Find(const tchar *s, int from) const +{ + return Find(strlen__(s), s, from); +} + +template +int AString::FindFirstOf(int len, const tchar *s, int from) const +{ + ASSERT(from >= 0 && from <= GetLength()); + const tchar *ptr = B::Begin(); + const tchar *e = B::End(); + const tchar *se = s + len; + if(len == 1) { + tchar c1 = s[0]; + for(const tchar *bs = ptr + from; bs < e; bs++) { + if(*bs == c1) + return (int)(bs - ptr); + } + return -1; + } + if(len == 2) { + tchar c1 = s[0]; + tchar c2 = s[1]; + for(const tchar *bs = ptr + from; bs < e; bs++) { + tchar ch = *bs; + if(ch == c1 || ch == c2) + return (int)(bs - ptr); + } + return -1; + } + if(len == 3) { + tchar c1 = s[0]; + tchar c2 = s[1]; + tchar c3 = s[2]; + for(const tchar *bs = ptr + from; bs < e; bs++) { + tchar ch = *bs; + if(ch == c1 || ch == c2 || ch == c3) + return (int)(bs - ptr); + } + return -1; + } + if(len == 4) { + tchar c1 = s[0]; + tchar c2 = s[1]; + tchar c3 = s[2]; + tchar c4 = s[3]; + for(const tchar *bs = ptr + from; bs < e; bs++) { + tchar ch = *bs; + if(ch == c1 || ch == c2 || ch == c3 || ch == c4) + return (int)(bs - ptr); + } + return -1; + } + for(const tchar *bs = ptr + from; bs < e; bs++) + for(const tchar *ss = s; ss < se; ss++) + if(*bs == *ss) + return (int)(bs - ptr); + return -1; +} + +template +int AString::FindFirstOf(const tchar *s, int from) const +{ + return FindFirstOf(strlen__(s), s, from); +} + +inline int String0::Compare(const String0& s) const +{ +#ifdef FAST_STRING_COMPARE + if((chr[KIND] | s.chr[KIND]) == 0) { + #ifdef CPU_64 + uint64 a64 = SwapEndian64(q[0]); + uint64 b64 = SwapEndian64(s.q[0]); + if(a64 != b64) + return a64 < b64 ? -1 : 1; + uint32 a32 = SwapEndian32(w[2]); + uint32 b32 = SwapEndian32(s.w[2]); + if(a32 != b32) + return a32 < b32 ? -1 : 1; + #else + uint32 a32 = SwapEndian32(w[0]); + uint32 b32 = SwapEndian32(s.w[0]); + if(a32 != b32) + return a32 < b32 ? -1 : 1; + a32 = SwapEndian32(w[1]); + b32 = SwapEndian32(s.w[1]); + if(a32 != b32) + return a32 < b32 ? -1 : 1; + a32 = SwapEndian32(w[2]); + b32 = SwapEndian32(s.w[2]); + if(a32 != b32) + return a32 < b32 ? -1 : 1; + #endif + uint16 a16 = SwapEndian16(v[6]); + uint16 b16 = SwapEndian16(s.v[6]); + if(a16 != b16) + return a16 < b16 ? -1 : 1; + return 0; + } +#endif + return LCompare(s); +} diff --git a/uppdev/CoreTopics/Algo.h b/uppdev/CoreTopics/Algo.h new file mode 100644 index 000000000..c91d3d04a --- /dev/null +++ b/uppdev/CoreTopics/Algo.h @@ -0,0 +1,1567 @@ +template +inline int sgn(T a) { return a > 0 ? 1 : a < 0 ? -1 : 0; } + +template +inline T tabs(T a) { return (a >= 0 ? a : -a); } + +template +inline int cmp(const T& a, const T& b) { return a > b ? 1 : a < b ? -1 : 0; } + +template +void Reverse(I start, I end) +{ + if(start != end && --end != start) + do + IterSwap(start, end); + while(++start != end && --end != start); +} + +template +void Reverse(C& container) +{ + Reverse(container.Begin(), container.End()); +} + +template +void Sum(V& sum, T ptr, T end) + +{ + while(ptr != end) + sum += *ptr++; +} + +template +typename T::ValueType Sum(const T& c, const typename T::ValueType& init = typename T::ValueType()) +{ + typename T::ValueType sum = init; + Sum(sum, c.Begin(), c.End()); + return sum; +} + +template +typename T::ValueType Sum0(const T& c) +{ + typename T::ValueType sum = 0; + Sum(sum, c.Begin(), c.End()); + return sum; +} + +template +T MinElement(T ptr, T end) +{ + ASSERT(ptr != end); + T min = ptr; + while(++ptr != end) + if(*ptr < *min) min = ptr; + return min; +} + +template +int MinIndex(const C& c) +{ + if(c.GetCount() == 0) + return -1; + typename C::ValueType m = c[0]; + int mi = 0; + for(int i = 1; i < c.GetCount(); i++) + if(c[i] < m) { + m = c[i]; + mi = i; + } + return mi; +} + +template +int MaxIndex(const C& c) +{ + if(c.GetCount() == 0) + return -1; + typename C::ValueType m = c[0]; + int mi = 0; + for(int i = 1; i < c.GetCount(); i++) + if(c[i] > m) { + m = c[i]; + mi = i; + } + return mi; +} + +template +const typename T::ValueType& Min(const T& c) +{ + return *MinElement(c.Begin(), c.End()); +} + +template +T MaxElement(T ptr, T end) +{ + ASSERT(ptr != end); + T max = ptr; + while(++ptr != end) + if(*max < *ptr) max = ptr; + return max; +} + +template +const typename T::ValueType& Max(const T& c) +{ + return *MaxElement(c.Begin(), c.End()); +} + +template +struct StdEqual +{ + bool operator () (const T& a, const T& b) const { return a == b; } +}; + +template +struct StdLess { + bool operator () (const T& a, const T& b) const { return a < b; } +}; + +template +struct StdGreater +{ + bool operator () (const T& a, const T& b) const { return a > b; } +}; + +/* +template +bool Compare(T ptr1, T end1, T ptr2, T end2, const C& compare) +{ + for(; ptr1 != end1 && ptr2 != end2; ++ptr1, ++ptr2) + if(!compare(*ptr1, *ptr2)) return false; + return ptr1 == end1 && ptr2 == end2; +} + +template +bool Compare(const T& c1, const T& c2, const C& compare) +{ + return Compare(c1.Begin(), c1.End(), c2.Begin(), c2.End(), compare); +} + +template +bool Compare(const T& c1, const T& c2) +{ + typedef typename T::ValueType VT; + return Compare(c1, c2, StdEqual()); +} +*/ + +template +bool IsEqual(T ptr1, T end1, T ptr2, T end2, const C& equal) +{ + for(; ptr1 != end1 && ptr2 != end2; ++ptr1, ++ptr2) + if(!equal(*ptr1, *ptr2)) return false; + return ptr1 == end1 && ptr2 == end2; +} + +template +bool IsEqual(const T& c1, const T& c2, const C& equal) +{ + return IsEqual(c1.Begin(), c1.End(), c2.Begin(), c2.End(), equal); +} + +template +bool IsEqual(const T& c1, const T& c2) +{ + typedef typename T::ValueType VT; + return IsEqual(c1, c2, StdEqual()); +} + +template +T Find(T ptr, T end, const V& value, const C& equal) +{ + while(ptr != end) { + if(equal(*ptr, value)) return ptr; + ptr++; + } + return NULL; +} + +template +T Find(T ptr, T end, const V& value) +{ + return Find(ptr, end, value, StdEqual()); +} + +template +int FindIndex(const T& cont, const V& value, const C& equal) +{ + for(int i = 0; i < cont.GetCount(); i++) + if(equal(cont[i], value)) return i; + return -1; +} + +template +int FindIndex(const T& cont, const V& value) +{ + for(int i = 0; i < cont.GetCount(); i++) + if(cont[i] == value) return i; + return -1; +} + +template +int BinFindIndex(I begin, I end, const K& key, const L& less) +{ + if(begin == end) + return 0; + int min = 0; + int max = end - begin; + + while(min < max) + { + int mid = (max + min) >> 1; + if(less(*(begin + mid), key)) + min = mid + 1; + else + max = mid; + } + return min; +} + +template +inline int BinFindIndex(const C& container, const K& key, const L& less) +{ + return BinFindIndex(container.Begin(), container.End(), key, less); +} + +template +inline int BinFindIndex(const C& container, const K& key) +{ + typedef typename C::ValueType VT; + return BinFindIndex(container, key, StdLess()); +} + +template +inline I BinFind(I begin, I end, const K& key, const L& less) +{ + return begin + BinFindIndex(begin, end, key, less); +} + +template +inline typename C::ConstIterator BinFind(const C& container, const K& key, const L& less) +{ + return BinFind(container.Begin(), container.End(), key, less); +} + +template +inline typename C::ConstIterator BinFind(const C& container, const K& key) +{ + typedef typename C::ValueType VT; + return BinFind(container, key, StdLess()); +} + +// ------------------------------------------------------------------- + +template +int IterCompare(I a, I a_end, I b, I b_end, const C& compare) +{ + for(;;) { + if(a >= a_end) + return b < b_end ? -1 : 0; + if(b >= b_end) + return a < a_end ? 1 : 0; + int q = compare(*a++, *b++); + if(q) + return q; + } +} + +template +int FindLowerBound(const C& v, int pos, int count, const T& val, const L& less) +{ + while(count > 0) { + int half = count >> 1; + int m = pos + half; + if(less(v[m], val)) { + pos = m + 1; + count = count - half - 1; + } + else + count = half; + } + return pos; +} + +template +I FindLowerBoundIter(I begin, I end, const T& val, const L& less) +{ + return begin + FindLowerBound(begin, 0, end - begin, val, less); +} + +template +I FindLowerBoundIter(I begin, I end, const T& val) +{ + return begin + FindLowerBound(begin, 0, end - begin, val, StdLess()); +} + +template +int FindLowerBound(const C& v, const T& val, const L& less) +{ + return FindLowerBound(v, 0, v.GetCount(), val, less); +} + +template +int FindLowerBound(const C& v, const T& val) +{ + return FindLowerBound(v, val, StdLess()); +} + +template +int FindUpperBound(const C& v, int pos, int count, const T& val, const L& less) +{ + while(count > 0) { + int half = count >> 1; + int m = pos + half; + if(less(val, v[m])) + count = half; + else { + pos = m + 1; + count = count - half - 1; + } + } + return pos; +} + +template +I FindUpperBoundIter(I begin, I end, const T& val, const L& less) +{ + return begin + FindUpperBound(begin, 0, end - begin, val, less); +} + +template +I FindUpperBoundIter(I begin, I end, const T& val) +{ + return begin + FindUpperBound(begin, 0, (int)(end - begin), val, StdLess()); +} + +template +int FindUpperBound(const C& v, const T& val, const L& less) +{ + return FindUpperBound(v, 0, v.GetCount(), val, less); +} + +template +int FindUpperBound(const C& v, const T& val) +{ + return FindUpperBound(v, val, StdLess()); +} + +template +int FindBinary(const C& v, const T& val, int pos, int count, const L& less) +{ + int i = FindLowerBound(v, pos, count, val, less); + return i < count && !less(val, v[i]) ? i : -1; +} + +template +I FindBinaryIter(I begin, I end, const T& val, const L& less) +{ + int q = FindUpperBound(begin, begin, end, val, less); + return q < 0 ? NULL : begin + q; +} + +template +I FindBinaryIter(I begin, I end, const T& val) +{ + return FindBinaryIter(begin, end, val, StdLess()); +} + +template +int FindBinary(const C& v, const T& val, const L& less) +{ + return FindBinary(v, val, 0, v.GetCount(), less); +} + +template +int FindBinary(const C& v, const T& val) +{ + return FindBinary(v, val, StdLess()); +} + +template +int BinFindCompIndex(I begin, I end, const K& key, const X& comp) +{ + if(begin == end) // empty array + return 0; + int min = 0; + int max = end - begin; + while(min < max) + { + int mid = (max + min) >> 1; + if(comp.Compare(key, *(begin + mid)) > 0) + min = mid + 1; + else + max = mid; + } + return min; +} + +template +inline int BinFindCompIndex(const C& container, const K& key, const X& comp) +{ + return BinFindCompIndex(container.Begin(), container.End(), key, comp); +} + +template +inline I BinFindComp(I begin, I end, const K& key, const X& comp) +{ + return begin + BinFindCompIndex(begin, end, key, comp); +} + +template +inline typename C::ConstIterator BinFindComp(const C& container, const K& key, const X& comp) +{ + return BinFindComp(container.Begin(), container.End(), key, comp); +} + +template +void Append(T& dst, V ptr, V end) +{ + for(; ptr != end; ++ptr) + dst.Add(*ptr); +} + +template +void Append(T& dst, V ptr, int n) +{ + for(; n--; ++ptr) + dst.Add(*ptr); +} + +template +void Append(T& dst, const V& src) +{ + Append(dst, src.Begin(), src.End()); +} + +template +C& FindAppend(C& dest, I begin, I end) +{ + for(; begin != end; ++begin) + dest.FindAdd(*begin); + return dest; +} + +template +inline C& FindAppend(C& dest, const S& source) +{ + return FindAppend(dest, source.Begin(), source.End()); +} + +template +C& AppendSorted(C& dest, const C& src, const L& less) +{ + if(src.IsEmpty()) + return dest; + if(dest.IsEmpty()) + { + dest <<= src; + return dest; + } + if(!less(*src, dest.Top())) + { + dest.Append(src); + return dest; + } + if(!less(*dest, src.Top())) + { + dest.Insert(0, src); + return dest; + } + int dc = dest.GetCount(); + int sc = src.GetCount(); + dest.SetCount(dc + sc); + typename C::Iterator de = dest.End(); + typename C::ConstIterator se = src.End(), pe = dest.GetIter(dc); + --se; + --pe; + for(;;) + { + if(less(*se, *pe)) + { + *--de = *pe; + if(pe == dest.Begin()) + { // dest items are finished + *--de = *se; + while(se != src.Begin()) + *--de = *--se; + return dest; + } + --pe; + } + else + { + *--de = *se; + if(se == src.Begin()) + return dest; // src items are finished, dest items are in place + --se; + } + } + return dest; +} + +template +C& AppendSorted(C& dest, const C& src) +{ + typedef typename C::ValueType VT; + return AppendSorted(dest, src, StdLess()); +} + +template +C& UnionSorted(C& dest, const C& src, const L& less) +{ + if(src.IsEmpty()) + return dest; + if(dest.IsEmpty()) + { + dest <<= src; + return dest; + } + if(less(dest.Top(), *src)) + { + dest.Append(src); + return dest; + } + if(less(src.Top(), *dest)) + { + dest.Insert(0, src); + return dest; + } + int dc = dest.GetCount(); + int sc = src.GetCount(); + dest.SetCount(dc + sc); + typename C::Iterator de = dest.End(); + typename C::ConstIterator se = src.End(), pe = dest.GetIter(dc); + --se; + --pe; + for(;;) + { + if(less(*se, *pe)) + { + *--de = *pe; + if(pe == dest.Begin()) + { // dest items are finished + *--de = *se; + while(se != src.Begin()) + *--de = *--se; + dest.Remove(0, dest.GetIndex(*de)); + return dest; + } + --pe; + } + else + { + *--de = *se; + if(!less(*pe, *se)) + { + if(pe == dest.Begin()) + { + while(se != src.Begin()) + *--de = *--se; + dest.Remove(0, dest.GetIndex(*de)); + return dest; + } + --pe; + } + if(se == src.Begin()) + { + int pi = (pe - dest.Begin()) + 1; + dest.Remove(pi, (de - dest.Begin()) - pi); + return dest; // src items are finished, dest items are in place + } + --se; + } + } + return dest; +} + +template +C& UnionSorted(C& dest, const C& src) +{ + typedef typename C::ValueType VT; + return UnionSorted(dest, src, StdLess()); +} + +template +C& RemoveSorted(C& from, const C& what, const L& less) +{ + if(from.IsEmpty() || what.IsEmpty() || + less(from.Top(), *what.Begin()) || less(what.Top(), *from.Begin())) + return from; + typename C::ConstIterator we = what.End(), wp = BinFind(what, from[0], less); + if(wp == we) + return from; + typename C::Iterator fp = from.Begin() + BinFindIndex(from, *wp), fe = from.End(), fd = fp; + if(fp == fe) + { + from.Clear(); + return from; + } + for(;;) + { + while(less(*fp, *wp)) + { + *fd = *fp; + ++fd; + if(++fp == fe) + { + from.SetCount(fd - from.Begin()); + return from; + } + } + if(less(*wp, *fp)) + { + do + if(++wp == we) + { + Copy(fd, fp, fe); + fd += (fe - fp); + from.SetCount(fd - from.Begin()); + return from; + } + while(less(*wp, *fp)); + } + else + { + const typename C::ValueType& value = *fp; + while(!less(value, *fp)) + if(++fp == fe) + { + from.SetCount(fd - from.Begin()); + return from; + } + do + if(++wp == we) + { + Copy(fd, fp, fe); + fd += (fe - fp); + from.SetCount(fd - from.Begin()); + return from; + } + while(!less(value, *wp)); + } + } +} + +template +C& RemoveSorted(C& from, const C& what) +{ + typedef typename C::ValueType VT; + return RemoveSorted(from, what, StdLess()); +} + +template +D& IntersectSorted(D& dest, const S& src, const L& less) +{ + if(dest.IsEmpty()) + return dest; + if(src.IsEmpty() || less(dest.Top(), src[0]) || less(src.Top(), dest[0])) + { // empty source set or disjunct intervals + dest.Clear(); + return dest; + } + typename S::ConstIterator ss = BinFind(src, dest[0], less), se = src.End(); + if(ss == se) + { + dest.Clear(); + return dest; + } + typename D::ConstIterator ds = BinFind(dest, src[0], less), de = dest.End(); + if(ds == de) + { + dest.Clear(); + return dest; + } + typename D::Iterator d = dest.Begin(); + int count = 0; + for(;;) + { + if(less(*ss, *ds)) + { + if(++ss == se) + break; + } + else + { + if(!less(*ds, *ss)) + { + *d = *ds; + ++d; + count++; + } + if(++ds == de) + break; + } + } + dest.SetCount(count); + return dest; +} + +template +D& IntersectSorted(D& dest, const S& src) +{ + typedef typename D::ValueType VT; + return IntersectSorted(dest, src, StdLess()); +} + +#ifdef UPP +template +void StreamContainer(Stream& s, T& cont) +{ + int n = cont.GetCount(); + s / n; + if(n < 0) { + s.LoadError(); + return; + } + if(s.IsLoading()) + { + cont.Clear(); + while(n--) + s % cont.Add(); + } + else + { + for(typename T::Iterator ptr = cont.Begin(); n--; ++ptr) + s % *ptr; + } +} +#endif + +template +void ForwardSort(I begin, I end, const Less& less) +{ + if(begin == end) + return; + I limit = end; + --limit; + while(!(begin == limit)) + { + for(I best = limit, next = limit, ptr = limit;; best = ptr) + if(!less(*best, *--ptr)) + { + if(ptr == begin) + { + begin = next; + break; + } + } + else + { + do + { + if(ptr == begin) + { + IterSwap(begin, best); + ++begin; + goto NEXT_ITEM; + } + } + while(less(*best, *--ptr)); + if(ptr == begin) + { + IterSwap(++begin, best); + ++begin; + break; + } + next = ptr; + ++next; + } + NEXT_ITEM: + ; + } +} + +template +void ForwardSort(T& c, const Less& less) +{ + ForwardSort(c.Begin(), c.End(), less); +} + +template +void ForwardSort(T& c) +{ + typedef typename T::ValueType VT; + ForwardSort(c.Begin(), c.End(), StdLess()); +} + +enum +{ + __SORT_THRESHOLD = 16, + __SORT_MEDIAN_PASSES = 2, +}; + +template +void Sort(I begin, I end, const Less& less) +{ + int count; + while((count = (int)(end - begin)) > __SORT_THRESHOLD) { + int expected = count >> 1, deviation = expected - (expected >> 8); + I b = begin, e = end, m = b + expected; + for(int pass = 1;; pass++) { + for(;; ++b) { + while(less(*m, *--e)) + ; + while(less(*b, *m)) + ++b; + if(!(b < e)) + break; + if(m == b) m = e; + else if(m == e) m = b; + IterSwap(b, e); + } + if(pass >= __SORT_MEDIAN_PASSES) + break; + int pos = (int)(b - begin); + if(pos <= expected - deviation) + e = end; + else if(pos >= expected + deviation) { + e = b; + b = begin; + } + else + break; + m = b + 1 + (int)((unsigned)rand() % (e - b - 2)); + } + if(b - begin < end - e) { + Sort(begin, b, less); + begin = b; + } + else { + Sort(b, end, less); + end = b; + } + } + if(count >= 2) + ForwardSort(begin, end, less); +} + +template +void Sort(T& c, const Less& less) +{ + Sort(c.Begin(), c.End(), less); +} + +template +void Sort(T& c) +{ + typedef typename T::ValueType VT; + Sort(c.Begin(), c.End(), StdLess()); +} + +template +struct StableSortItem { + const T& value; + int index; + + StableSortItem(const T& value, int index) : value(value), index(index) {} +}; + +template +struct StableSortIterator { + II ii; + int *vi; + + typedef StableSortIterator Iter; + + Iter& operator ++ () { ++ii; ++vi; return *this; } + Iter& operator -- () { --ii; --vi; return *this; } + Iter operator + (int i) const { return Iter(ii + i, vi + i); } + Iter operator - (int i) const { return Iter(ii - i, vi - i); } + int operator - (Iter b) const { return (int)(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + + StableSortItem operator*() const { return StableSortItem(*ii, *vi); } + + friend void IterSwap(Iter a, Iter b) { IterSwap(a.ii, b.ii); IterSwap(a.vi, b.vi); } + + StableSortIterator(II ii, int *vi) : ii(ii), vi(vi) {} +}; + +template +struct StableSortLess_ { + const Less& less; + + bool operator()(const StableSortItem& a, const StableSortItem& b) const { + if(less(a.value, b.value)) return true; + return less(b.value, a.value) ? false : a.index < b.index; + } + + StableSortLess_(const Less& less) : less(less) {} +}; + +template +void StableSort_(I begin, I end, const Less& less, const T *) +{ + int count = (int)(uintptr_t)(end - begin); + Buffer h(count); + for(int i = 0; i < count; i++) + h[i] = i; + Sort(StableSortIterator(begin, ~h), + StableSortIterator(end, ~h + count), + StableSortLess_(less)); +} + +template +void StableSort(I begin, I end, const Less& less) +{ + if(begin != end) + StableSort_(begin, end, less, &*begin); +} + +template +void StableSort(T& c, const Less& less) +{ + StableSort(c.Begin(), c.End(), less); +} + +template +void StableSort(T& c) +{ + StableSort(c.Begin(), c.End(), StdLess()); +} + +template +struct StableSortLessCmp_ { + const Cmp& cmp; + bool operator()(const StableSortItem& a, const StableSortItem& b) const { + int q = SgnCompare(a.value, b.value); + return q ? q < 0 : a.index < b.index; + } + + StableSortLessCmp_(const Cmp& cmp) : cmp(cmp) {} +}; + +template +void StableSortCmp_(I begin, I end, const Cmp& cmp, const T *) +{ + int count = end - begin; + Buffer h(count); + for(int i = 0; i < count; i++) + h[i] = i; + Sort(StableSortIterator(begin, ~h), + StableSortIterator(end, ~h + count), + StableSortLessCmp_(cmp)); +} + +template +void StableSortCmp(I begin, I end, const Cmp& cmp) +{ + if(begin != end) + StableSortCmp_(begin, end, cmp, &*begin); +} + +template +void StableSortCmp(T& c, const Cmp& cmp) +{ + StableSortCmp(c.Begin(), c.End(), cmp); +} + +template +struct StdCmp { + int operator()(const T& a, const T& b) const { + return SgnCompare(a, b); + } +}; + +template +void StableSortCmp(T& c) +{ + StableSort(c.Begin(), c.End(), StdCmp()); +} + +template +struct IndexSortIterator +{ + typedef IndexSortIterator Iter; + + IndexSortIterator(II ii, VI vi) : ii(ii), vi(vi) {} + + Iter& operator ++ () { ++ii; ++vi; return *this; } + Iter& operator -- () { --ii; --vi; return *this; } + const K& operator * () const { return *ii; } + Iter operator + (int i) const { return Iter(ii + i, vi + i); } + Iter operator - (int i) const { return Iter(ii - i, vi - i); } + int operator - (Iter b) const { return (int)(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + friend void IterSwap (Iter a, Iter b) { IterSwap(a.ii, b.ii); IterSwap(a.vi, b.vi); } + + II ii; + VI vi; +}; + +template +inline void __IndexSort(II begin, II end, VI pair, const Less& less, const K *) +{ + Sort(IndexSortIterator(begin, pair), + IndexSortIterator(end, pair + (end - begin)), + less); +} + +template +inline void IndexSort(II begin, II end, VI pair, const Less& less) +{ + if(begin != end) + __IndexSort(begin, end, pair, less, &*begin); +} + +template +inline void IndexSort(KC& keys, VC& values, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values.GetCount()); + if(keys.GetCount() >= 2) + __IndexSort(keys.Begin(), keys.End(), values.Begin(), less, (KT *)0); +} + +template +inline void IndexSort(KC& keys, VC& values) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __IndexSort(keys.Begin(), keys.End(), values.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSort(II begin, II end, VI pair, const Less& less, const K *) +{ + StableSort(IndexSortIterator(begin, pair), + IndexSortIterator(end, pair + (end - begin)), + less); +} + +template +inline void StableIndexSort(II begin, II end, VI pair, const Less& less) +{ + if(begin != end) + __StableIndexSort(begin, end, pair, less, &*begin); +} + +template +inline void StableIndexSort(KC& keys, VC& values, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSort(keys.Begin(), keys.End(), values.Begin(), less, (KT *)0); +} + +template +inline void StableIndexSort(KC& keys, VC& values) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSort(keys.Begin(), keys.End(), values.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSortCmp(II begin, II end, VI pair, const Cmp& cmp, const K *) +{ + StableSortCmp(IndexSortIterator(begin, pair), + IndexSortIterator(end, pair + (end - begin)), + cmp); +} + +template +inline void StableIndexSortCmp(II begin, II end, VI pair, const Cmp& cmp) +{ + if(begin != end) + __StableIndexSortCmp(begin, end, pair, cmp, &*begin); +} + +template +inline void StableIndexSortCmp(KC& keys, VC& values, const Cmp& cmp) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSortCmp(keys.Begin(), keys.End(), values.Begin(), cmp, (KT *)0); +} + +template +inline void StableIndexSortCmp(KC& keys, VC& values) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSortCmp(keys.Begin(), keys.End(), values.Begin(), StdCmp(), (KT *)0); +} + +template +struct IndexSort2Iterator +{ + typedef IndexSort2Iterator Iter; + + IndexSort2Iterator(II ii, VI vi, WI wi) : ii(ii), vi(vi), wi(wi) {} + + Iter& operator ++ () { ++ii; ++vi; ++wi; return *this; } + Iter& operator -- () { --ii; --vi; --wi; return *this; } + const K& operator * () const { return *ii; } + Iter operator + (int i) const { return Iter(ii + i, vi + i, wi + i); } + Iter operator - (int i) const { return Iter(ii - i, vi - i, wi - i); } + int operator - (Iter b) const { return (int)(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + friend void IterSwap (Iter a, Iter b) { IterSwap(a.ii, b.ii); IterSwap(a.vi, b.vi); IterSwap(a.wi, b.wi); } + + II ii; + VI vi; + WI wi; +}; + +template +inline void __IndexSort2(II begin, II end, VI pair1, WI pair2, const Less& less, const K *) +{ + int count = end - begin; + Sort(IndexSort2Iterator(begin, pair1, pair2), + IndexSort2Iterator(end, pair1 + count, pair2 + count), + less); +} + +template +inline void IndexSort2(II begin, II end, VI pair1, WI pair2, const Less& less) +{ + if(begin != end) + __IndexSort2(begin, end, pair1, pair2, less, &*begin); +} + +template +inline void IndexSort2(KC& keys, VC& values1, WC& values2, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount()); + if(keys.GetCount() >= 2) + __IndexSort2(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), less, (KT *)0); +} + +template +inline void IndexSort2(KC& keys, VC& values1, WC& values2) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __IndexSort2(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSort2(II begin, II end, VI pair1, WI pair2, const Less& less, const K *) +{ + int count = end - begin; + StableSort(IndexSort2Iterator(begin, pair1, pair2), + IndexSort2Iterator(end, pair1 + count, pair2 + count), + less); +} + +template +inline void StableIndexSort2(II begin, II end, VI pair1, WI pair2, const Less& less) +{ + if(begin != end) + __StableIndexSort2(begin, end, pair1, pair2, less, &*begin); +} + +template +inline void StableIndexSort2(KC& keys, VC& values1, WC& values2, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSort2(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), less, (KT *)0); +} + +template +inline void StableIndexSort2(KC& keys, VC& values1, WC& values2) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSort2(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSort2Cmp(II begin, II end, VI pair1, WI pair2, const Cmp& cmp, const K *) +{ + int count = end - begin; + StableSortCmp(IndexSort2Iterator(begin, pair1, pair2), + IndexSort2Iterator(end, pair1 + count, pair2 + count), + cmp); +} + +template +inline void StableIndexSort2Cmp(II begin, II end, VI pair1, WI pair2, const Cmp& cmp) +{ + if(begin != end) + __StableIndexSort2Cmp(begin, end, pair1, pair2, cmp, &*begin); +} + +template +inline void StableIndexSort2Cmp(KC& keys, VC& values1, WC& values2, const Cmp& cmp) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSort2Cmp(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), cmp, (KT *)0); +} + +template +inline void StableIndexSort2Cmp(KC& keys, VC& values1, WC& values2) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSort2Cmp(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), StdCmp(), (KT *)0); +} + +template +struct IndexSort3Iterator +{ + typedef IndexSort3Iterator Iter; + + IndexSort3Iterator(II ii, VI vi, WI wi, XI xi) : ii(ii), vi(vi), wi(wi), xi(xi) {} + + Iter& operator ++ () { ++ii; ++vi; ++wi; ++xi; return *this; } + Iter& operator -- () { --ii; --vi; --wi; --xi; return *this; } + const K& operator * () const { return *ii; } + Iter operator + (int i) const { return Iter(ii + i, vi + i, wi + i, xi + i); } + Iter operator - (int i) const { return Iter(ii - i, vi - i, wi - i, xi - i); } + int operator - (Iter b) const { return (int)(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + friend void IterSwap (Iter a, Iter b) { IterSwap(a.ii, b.ii); IterSwap(a.vi, b.vi); IterSwap(a.wi, b.wi); IterSwap(a.xi, b.xi); } + + II ii; + VI vi; + WI wi; + XI xi; +}; + +template +inline void __IndexSort3(II begin, II end, VI pair1, WI pair2, XI pair3, const Less& less, const K *) +{ + int count = end - begin; + Sort(IndexSort3Iterator(begin, pair1, pair2, pair3), + IndexSort3Iterator(end, pair1 + count, pair2 + count, pair3 + count), + less); +} + +template +inline void IndexSort3(II begin, II end, VI pair1, WI pair2, XI pair3, const Less& less) +{ + if(begin != end) + __IndexSort3(begin, end, pair1, pair2, pair3, less, &*begin); +} + +template +inline void IndexSort3(KC& keys, VC& values1, WC& values2, XC& values3, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount() + && keys.GetCount() == values3.GetCount()); + if(keys.GetCount() >= 2) + __IndexSort3(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), less, (KT *)0); +} + +template +inline void IndexSort3(KC& keys, VC& values1, WC& values2, XC& values3) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __IndexSort3(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSort3(II begin, II end, VI pair1, WI pair2, XI pair3, const Less& less, const K *) +{ + int count = end - begin; + StableSort(IndexSort3Iterator(begin, pair1, pair2, pair3), + IndexSort3Iterator(end, pair1 + count, pair2 + count, pair3 + count), + less); +} + +template +inline void StableIndexSort3(II begin, II end, VI pair1, WI pair2, XI pair3, const Less& less) +{ + if(begin != end) + __StableIndexSort3(begin, end, pair1, pair2, pair3, less, &*begin); +} + +template +inline void StableIndexSort3(KC& keys, VC& values1, WC& values2, XC& values3, const Less& less) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount() + && keys.GetCount() == values3.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSort3(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), less, (KT *)0); +} + +template +inline void StableIndexSort3(KC& keys, VC& values1, WC& values2, XC& values3) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSort3(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), StdLess(), (KT *)0); +} + +template +inline void __StableIndexSort3Cmp(II begin, II end, VI pair1, WI pair2, XI pair3, const Cmp& cmp, const K *) +{ + int count = end - begin; + StableSortCmp(IndexSort3Iterator(begin, pair1, pair2, pair3), + IndexSort3Iterator(end, pair1 + count, pair2 + count, pair3 + count), + cmp); +} + +template +inline void StableIndexSort3Cmp(II begin, II end, VI pair1, WI pair2, XI pair3, const Cmp& cmp) +{ + if(begin != end) + __StableIndexSort3Cmp(begin, end, pair1, pair2, pair3, cmp, &*begin); +} + +template +inline void StableIndexSort3Cmp(KC& keys, VC& values1, WC& values2, XC& values3, const Cmp& cmp) +{ + typedef typename KC::ValueType KT; + ASSERT(keys.GetCount() == values1.GetCount() && keys.GetCount() == values2.GetCount() + && keys.GetCount() == values3.GetCount()); + if(keys.GetCount() >= 2) + __StableIndexSort3Cmp(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), cmp, (KT *)0); +} + +template +inline void StableIndexSort3Cmp(KC& keys, VC& values1, WC& values2, XC& values3) +{ + typedef typename KC::ValueType KT; + if(keys.GetCount() >= 2) + __StableIndexSort3Cmp(keys.Begin(), keys.End(), values1.Begin(), values2.Begin(), values3.Begin(), StdCmp(), (KT *)0); +} + + +template +struct SortOrderIterator : PostfixOps< SortOrderIterator > +{ + typedef SortOrderIterator Iter; + + SortOrderIterator(int *ii, I vi) : ii(ii), vi(vi) {} + + Iter& operator ++ () { ++ii; return *this; } + Iter& operator -- () { --ii; return *this; } + const V& operator * () const { return *(vi + *ii); } + Iter operator + (int i) const { return Iter(ii + i, vi); } + Iter operator - (int i) const { return Iter(ii - i, vi); } + int operator - (Iter b) const { return int(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + friend void IterSwap (Iter a, Iter b) { IterSwap(a.ii, b.ii); } + + int *ii; + I vi; +}; + +template +inline void __SortOrder(int *begin, int *end, I data, const Less& less, const V *) +{ + Sort(SortOrderIterator(begin, data), SortOrderIterator(end, data), less); +} + +template +inline Vector GetSortOrder(I begin, I end, const Less& less) +{ + Vector index; + index.SetCount((int)(end - begin)); + for(int i = index.GetCount(); --i >= 0; index[i] = i) + ; + if(begin != end) + __SortOrder(index.Begin(), index.End(), begin, less, &*begin); + return index; +} + +template +inline Vector GetSortOrder(const C& container, const Less& less) +{ + return GetSortOrder(container.Begin(), container.End(), less); +} + +template +inline Vector GetSortOrder(const C& container) +{ + typedef typename C::ValueType V; + return GetSortOrder(container.Begin(), container.End(), StdLess()); +} + +template +struct StableSortOrderIterator : PostfixOps< StableSortOrderIterator > +{ + typedef StableSortOrderIterator Iter; + + StableSortOrderIterator(int *ii, I vi) : ii(ii), vi(vi) {} + + Iter& operator ++ () { ++ii; return *this; } + Iter& operator -- () { --ii; return *this; } + Iter operator + (int i) const { return Iter(ii + i, vi); } + Iter operator - (int i) const { return Iter(ii - i, vi); } + int operator - (Iter b) const { return int(ii - b.ii); } + bool operator == (Iter b) const { return ii == b.ii; } + bool operator != (Iter b) const { return ii != b.ii; } + bool operator < (Iter b) const { return ii < b.ii; } + friend void IterSwap (Iter a, Iter b) { IterSwap(a.ii, b.ii); } + + StableSortItem operator*() const { return StableSortItem(*(vi + *ii), *ii); } + + int *ii; + I vi; +}; + +template +inline void __StableSortOrder(int *ibegin, int *iend, I data, const Less& less, const T *) +{ + Sort(StableSortOrderIterator(ibegin, data), + StableSortOrderIterator(iend, data), + StableSortLess_(less)); +} + +template +inline Vector GetStableSortOrder(I begin, I end, const Less& less) +{ + Vector index; + index.SetCount((int)(end - begin)); + for(int i = index.GetCount(); --i >= 0; index[i] = i) + ; + if(begin != end) + __StableSortOrder(index.Begin(), index.End(), begin, less, &*begin); + return index; +} + +template +inline Vector GetStableSortOrder(const C& container, const Less& less) +{ + return GetStableSortOrder(container.Begin(), container.End(), less); +} + +template +inline Vector GetStableSortOrder(const C& container) +{ + typedef typename C::ValueType V; + return GetStableSortOrder(container.Begin(), container.End(), StdLess()); +} + +template +inline void __StableSortOrderCmp(int *ibegin, int *iend, I data, const Cmp& cmp, const T *) +{ + Sort(StableSortOrderIterator(ibegin, data), + StableSortOrderIterator(iend, data), + StableSortLessCmp_(cmp)); +} + +template +inline Vector GetStableSortOrderCmp(I begin, I end, const Cmp& cmp) +{ + Vector index; + index.SetCount((int)(end - begin)); + for(int i = index.GetCount(); --i >= 0; index[i] = i) + ; + if(begin != end) + __StableSortOrderCmp(index.Begin(), index.End(), begin, cmp, &*begin); + return index; +} + +template +inline Vector GetStableSortOrderCmp(const C& container, const Cmp& cmp) +{ + return GetStableSortOrderCmp(container.Begin(), container.End(), cmp); +} + +template +inline Vector GetStableSortOrderCmp(const C& container) +{ + typedef typename C::ValueType V; + return GetStableSortOrderCmp(container.Begin(), container.End(), StdCmp()); +} + +template +void GetFieldContainer(DC& dest, I begin, I end, F field) +{ + for(; begin != end; ++begin) + dest.Add((*begin).*field); +} + +template +void GetFieldContainer(DC& dest, const SC& src, F field) +{ GetFieldContainer(dest, src.Begin(), src.End(), field); } + +template +I FindField(I begin, I end, F field, const O& object, const E& equal) +{ + for(; begin != end && !equal((*begin).*field, object); ++begin) + ; + return begin; +} + +template +I FindField(I begin, I end, F field, const O& object) +{ return FindField(begin, end, field, object, StdEqual()); } + +template +int FindFieldIndex(const C& container, F field, const O& object, const E& equal) +{ + int i = 0; + for(typename C::ConstIterator b = container.Begin(), e = container.End(); b != e; ++b, ++i) + if(equal((*b).*field, object)) + return i; + return -1; +} + +template +int FindFieldIndex(const C& container, F field, const O& object) +{ return FindFieldIndex(container, field, object, StdEqual()); } + +template +class FieldRelationCls { + O T::*member; + const R& relation; + +public: + FieldRelationCls(O (T::*member), const R& relation) : member(member), relation(relation) {} + bool operator () (const T& t1, const T& t2) const { return relation(t1.*member, t2.*member); } +}; + +template +inline FieldRelationCls FieldRelation(O (T::*member), const R& relation) +{ return FieldRelationCls(member, relation); } + +template +class MethodRelationCls { + M method; + const R& relation; + +public: + MethodRelationCls(M method, const R& relation) : method(method), relation(relation) {} + bool operator () (const T& t1, const T& t2) const { + return relation((t1.*method)(), (t2.*method)()); + } +}; + +template +inline MethodRelationCls + MethodRelation(O (T::*method)(), const R& relation) +{ return MethodRelationCls(method, relation); } + +template +inline MethodRelationCls + MethodRelation(O (T::*method)() const, const R& relation) +{ return MethodRelationCls(method, relation); } + +template +void LruAdd(C& lru, T value, int limit = 10) { + int q = FindIndex(lru, value); + if(q >= 0) + lru.Remove(q); + lru.Insert(0, value); + if(lru.GetCount() > limit) + lru.SetCount(limit); +} diff --git a/uppdev/CoreTopics/App.cpp b/uppdev/CoreTopics/App.cpp new file mode 100644 index 000000000..e94bb6a47 --- /dev/null +++ b/uppdev/CoreTopics/App.cpp @@ -0,0 +1,366 @@ +#include "Core.h" + +#ifdef PLATFORM_WIN32 +#include +#endif + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +String GetExeFilePath() +{ + return GetModuleFileName(); +} + +String GetHomeDirectory() { + return FromSystemCharset(getenv("HOMEDRIVE")) + + FromSystemCharset(getenv("HOMEPATH")); +} + +#endif + +#ifdef PLATFORM_POSIX + +char Argv0__[_MAX_PATH + 1]; + +static void sSetArgv0__(const char *title) +{ + strcpy(Argv0__, title); +} + +extern char Argv0__[]; + +const char *procexepath_() { + static char h[_MAX_PATH + 1]; + ONCELOCK { + char link[100]; +#ifdef PLATFORM_FREEBSD + sprintf(link, "/proc/%d/file", getpid()); +#else + sprintf(link, "/proc/%d/exe", getpid()); +#endif + int ret = readlink(link, h, _MAX_PATH); + if(ret > 0 && ret < _MAX_PATH) + h[ret] = '\0'; + else + *h = '\0'; + } + return h; +} + +String GetExeFilePath() +{ + static String exepath; + ONCELOCK { + const char *exe = procexepath_(); + if(*exe) + exepath = exe; + else { + String x = Argv0__; + if(IsFullPath(x) && FileExists(x)) + exepath = x; + else { + exepath = GetHomeDirFile("upp"); + Vector p = Split(FromSystemCharset(Environment().Get("PATH")), ':'); + if(x.Find('/') >= 0) + p.Add(GetCurrentDirectory()); + for(int i = 0; i < p.GetCount(); i++) { + String ep = NormalizePath(AppendFileName(p[i], x)); + if(FileExists(ep)) + exepath = ep; + } + } + } + } + return exepath; +} + +#endif + +String GetExeDirFile(const char *filename) +{ + return AppendFileName(GetFileFolder(GetExeFilePath()), filename); +} + +String GetExeTitle() +{ + return GetFileTitle(GetExeFilePath()); +} + +#ifdef PLATFORM_POSIX + +static StaticCriticalSection sHlock; + +String& sHomeDir() { + static String s; + return s; +} + +String GetHomeDirectory() { + String r; + INTERLOCKED_(sHlock) { + String& s = sHomeDir(); + if(s.IsEmpty()) { + const char *home = getenv("HOME"); + s = FromSystemCharset(home ? home : "/root"); + } + r = s; + } + return r; +} + +void SetHomeDirectory(const char *dir) +{ + INTERLOCKED_(sHlock) { + sHomeDir() = dir; + } +} + +#endif//PLATFORM_POSIX + +String GetHomeDirFile(const char *fp) { + return AppendFileName(GetHomeDirectory(), fp); +} + +static bool sHomecfg; + +void UseHomeDirectoryConfig(bool b) +{ + sHomecfg = b; +} + +String ConfigFile(const char *file) { +#if defined(PLATFORM_WIN32) + if(sHomecfg) { + String p = GetHomeDirFile(GetExeTitle()); + ONCELOCK + RealizeDirectory(p); + return AppendFileName(p, file); + } + return GetExeDirFile(file); +#elif defined(PLATFORM_POSIX) + String p = GetHomeDirFile(".upp/" + GetExeTitle()); + ONCELOCK + RealizeDirectory(p); + return AppendFileName(p, file); +#else +#error ConfigFile not implemented for this platform, comment this line to get input string back + return file; +#endif//PLATFORM +} + +String ConfigFile() { + return ConfigFile(GetExeTitle() + ".cfg"); +} + +GLOBAL_VAR(Vector, coreCmdLine__) + +const Vector& CommandLine() +{ + return coreCmdLine__(); +} + +typedef VectorMap StringMap; +GLOBAL_VAR(StringMap, coreEnvPtr__) +const VectorMap& Environment() +{ + return coreEnvPtr__(); +} + +static int exitcode; +static bool sMainRunning; + +void SetExitCode(int code) { exitcode = code; } +int GetExitCode() { return exitcode; } + +bool IsMainRunning() +{ + return sMainRunning; +} + +void LoadLangFiles(const char *dir) +{ + FindFile ff(AppendFileName(dir, "*.tr")); + while(ff) { + LoadLngFile(AppendFileName(dir, ff.GetName())); + ff.Next(); + } +} + +void CommonInit() +{ +#ifdef PLATFORM_WIN32 + LoadLangFiles(GetFileFolder(GetExeFilePath())); +#else + LoadLangFiles(GetHomeDirectory()); +#endif + + Vector& cmd = coreCmdLine__(); + for(int i = 0; i < cmd.GetCount();) { + if(cmd[i] == "--export-tr") { + { + i++; + int lang = 0; + byte charset = CHARSET_UTF8; + String fn = "all"; + if(i < cmd.GetCount()) + if(cmd[i].GetLength() != 4 && cmd[i].GetLength() != 5) + lang = 0; + else { + lang = LNGFromText(cmd[i]); + fn = cmd[i]; + int c = cmd[i][4]; + if(c >= '0' && c <= '8') + charset = c - '0' + CHARSET_WIN1250; + if(c >= 'A' && c <= 'J') + charset = c - 'A' + CHARSET_ISO8859_1; + } + fn << ".tr"; + #ifdef PLATFORM_WIN32 + FileOut out(GetExeDirFile(fn)); + #else + FileOut out(GetHomeDirFile(fn)); + #endif + if(lang) + SaveLngFile(out, SetLNGCharset(lang, charset)); + else { + Index l = GetLngSet(); + for(int i = 0; i < l.GetCount(); i++) + SaveLngFile(out, SetLNGCharset(l[i], charset)); + } + } + exit(0); + } + #if defined(_DEBUG) && defined(UPP_HEAP) + if(cmd[i] == "--memory-breakpoint__" && i + 1 < cmd.GetCount()) { + MemoryBreakpoint(atoi(cmd[i + 1])); + cmd.Remove(i, 2); + } + else + i++; + #else + i++; + #endif + } + sMainRunning = true; +} + +#ifdef PLATFORM_POSIX + +void s_ill_handler(int) +{ + Panic("Illegal instruction!"); +} + +void s_segv_handler(int) +{ + Panic("Invalid memory access!"); +} + +void s_fpe_handler(int) +{ + Panic("Invalid arithmetic operation!"); +} + +void AppInit__(int argc, const char **argv, const char **envptr) +{ + SetLanguage(LNG_ENGLISH); + sSetArgv0__(argv[0]); + for(const char *var; (var = *envptr) != 0; envptr++) + { + const char *b = var; + while(*var && *var != '=') + var++; + String varname(b, var); + if(*var == '=') + var++; + coreEnvPtr__().Add(varname, var); + } + Vector& cmd = coreCmdLine__(); + for(int i = 1; i < argc; i++) + cmd.Add(argv[i]); + CommonInit(); + signal(SIGILL, s_ill_handler); + signal(SIGSEGV, s_segv_handler); + signal(SIGBUS, s_segv_handler); + signal(SIGFPE, s_fpe_handler); +} +#endif + +#if defined(PLATFORM_WIN32) + +void AppInitEnvironment__() +{ +#ifndef PLATFORM_WINCE + char *env = GetEnvironmentStrings(); + for(char *ptr = env; *ptr; ptr++) + { + const char *b = ptr; + if(*ptr) + ptr++; + while(*ptr && *ptr != '=') + ptr++; + String varname(b, ptr); + if(*ptr) + ptr++; + b = ptr; + while(*ptr) + ptr++; + coreEnvPtr__().GetAdd(ToUpper(varname)) = String(b, ptr); + } + FreeEnvironmentStrings(env); +#endif + CommonInit(); +} + +void AppInit__(int argc, const char **argv) +{ + SetLanguage(LNG_ENGLISH); + Vector& cmd = coreCmdLine__(); + for(int i = 1; i < argc; i++) + cmd.Add(argv[i]); + AppInitEnvironment__(); +} +#endif + +void AppExit__() +{ + sMainRunning = false; +#ifdef PLATFORM_POSIX + MemoryIgnoreLeaksBegin(); // Qt leaks on app exit... +#endif +} + +void LaunchWebBrowser(const String& url) +{ +#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE) + ShellExecute(NULL, "open", url, NULL, ".", SW_SHOWDEFAULT); +#endif +#ifdef PLATFORM_POSIX + const char * browser[] = { + "htmlview", "xdg-open", "x-www-browser", "firefox", "konqueror", "opera", "epiphany", "galeon", "netscape" + }; + for(int i = 0; i < __countof(browser); i++) + if(system("which " + String(browser[i])) == 0) { + system(String(browser[i]) + " " + url + " &"); + break; + } +#endif +} + +String GetDataFile(const char *filename) +{ + String s = Environment().Get("UPP_MAIN__", +#ifdef PLATFORM_WIN32 + GetFileFolder(GetExeFilePath()) +#endif +#ifdef PLATFORM_POSIX + GetHomeDirectory() +#endif + ); + + return AppendFileName(s, filename); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/App.h b/uppdev/CoreTopics/App.h new file mode 100644 index 000000000..e0765f773 --- /dev/null +++ b/uppdev/CoreTopics/App.h @@ -0,0 +1,75 @@ +String GetExeFilePath(); +String GetExeDirFile(const char *fp); + +String GetHomeDirFile(const char *fp); +String GetHomeDirectory(); + +#ifdef PLATFORM_POSIX + +void SetHomeDirectory(const char *dir); + +#endif + +String GetExeTitle(); + +void UseHomeDirectoryConfig(bool b = true); + +String ConfigFile(const char *file); +String ConfigFile(); + +const Vector& CommandLine(); +const VectorMap& Environment(); + +void SetExitCode(int code); +int GetExitCode(); + +bool IsMainRunning(); + +#ifndef flagSO +//void Main(); // By console application +#endif + +void AppExit__(); + +#ifdef PLATFORM_WIN32 + +void AppInit__(int argc, const char **argv); +void AppInitEnvironment__(); + +#define CONSOLE_APP_MAIN \ +void ConsoleMainFn_(); \ + \ +int main(int argc, char *argv[]) { \ + UPP::AppInit__(argc, (const char **)argv); \ + ConsoleMainFn_(); \ + UPP::DeleteUsrLog(); \ + UPP::AppExit__(); \ + return UPP::GetExitCode(); \ +} \ + \ +void ConsoleMainFn_() + +#endif + +#ifdef PLATFORM_POSIX + +void AppInit__(int argc, const char **argv, const char **envptr); + +#define CONSOLE_APP_MAIN \ +void ConsoleMainFn_(); \ + \ +int main(int argc, const char **argv, const char **envptr) { \ + UPP::AppInit__(argc, argv, envptr); \ + ConsoleMainFn_(); \ + UPP::DeleteUsrLog(); \ + UPP::AppExit__(); \ + return UPP::GetExitCode(); \ +} \ + \ +void ConsoleMainFn_() + +#endif + +String GetDataFile(const char *filename); + +void LaunchWebBrowser(const String& url); diff --git a/uppdev/CoreTopics/Authors b/uppdev/CoreTopics/Authors new file mode 100644 index 000000000..f52ff393f --- /dev/null +++ b/uppdev/CoreTopics/Authors @@ -0,0 +1,2 @@ +Mirek Fidler +Tomas Rylek \ No newline at end of file diff --git a/uppdev/CoreTopics/BiCont.h b/uppdev/CoreTopics/BiCont.h new file mode 100644 index 000000000..9607755ee --- /dev/null +++ b/uppdev/CoreTopics/BiCont.h @@ -0,0 +1,146 @@ +template +class BiVector : MoveableAndDeepCopyOption< BiVector > { +protected: + T *vector; + int start; + int items; + int alloc; + + int Ix(int i) const { return i + start < alloc ? i + start : i + start - alloc; } + + int EI() const { return Ix(items - 1); } + void ReAlloc(int newalloc); + void Add0(); + void DeepCopy0(const BiVector& src); + T *AddHead0() { AssertMoveable(); Add0(); return &vector[start = Ix(alloc - 1)/*(start + alloc - 1) % alloc*/]; } + T *AddTail0() { AssertMoveable(); Add0(); return &vector[EI()]; } + void Free(); + void Pick(pick_ BiVector& x) { vector = x.vector; start = x.start; items = x.items; + alloc = x.alloc; ((BiVector&)x).items = -1; } + void Copy(T *dst, int start, int count) const; + +public: + int GetCount() const { return items; } + bool IsEmpty() const { return items == 0; } + void Clear(); + + T& AddHead() { return *new(AddHead0()) T; } + T& AddTail() { return *new(AddTail0()) T; } + void AddHead(const T& x) { new(AddHead0()) T(x); } + void AddTail(const T& x) { new(AddTail0()) T(x); } + void AddHeadPick(pick_ T& x) { new(AddHead0()) T(x); } + void AddTailPick(pick_ T& x) { new(AddTail0()) T(x); } + T& Head() { ASSERT(items > 0); return vector[start]; } + T& Tail() { ASSERT(items > 0); return vector[EI()]; } + const T& Head() const { ASSERT(items > 0); return vector[start]; } + const T& Tail() const { ASSERT(items > 0); return vector[EI()]; } + void DropHead() { (&Head())->T::~T(); items--; start = Ix(1); } + void DropTail() { (&Tail())->T::~T(); items--; } + void DropHead(int n) { while(n-- > 0) BiVector::DropHead(); } + void DropTail(int n) { while(n-- > 0) BiVector::DropTail(); } + const T& operator[](int i) const { ASSERT(i >= 0 && i < items); return vector[Ix(i)]; } + T& operator[](int i) { ASSERT(i >= 0 && i < items); return vector[Ix(i)]; } + void Shrink(); + void Reserve(int n); + int GetAlloc() const { return alloc; } + +#ifdef UPP + void Serialize(Stream& s); +#endif + + bool IsPicked() { return items < 0; } + + BiVector(const BiVector& src, int) { DeepCopy0(src); } + BiVector(pick_ BiVector& src) { Pick(src); } + void operator=(pick_ BiVector& src) { Free(); Pick(src); } + BiVector() { start = items = alloc = 0; vector = NULL; } + ~BiVector() { Free(); } // gcc4.0 workaround!! + + typedef ConstIIterator ConstIterator; + typedef IIterator Iterator; + + typedef T ValueType; + + ConstIterator Begin() const { return ConstIterator(*this, 0); } + ConstIterator End() const { return ConstIterator(*this, GetCount()); } + ConstIterator GetIter(int pos) const { return ConstIterator(*this, pos); } + Iterator Begin() { return Iterator(*this, 0); } + Iterator End() { return Iterator(*this, GetCount()); } + Iterator GetIter(int pos) { return Iterator(*this, pos); } + + friend void Swap(BiVector& a, BiVector& b) { UPP::Swap(a.vector, b.vector); + UPP::Swap(a.start, b.start); + UPP::Swap(a.items, b.items); + UPP::Swap(a.alloc, b.alloc); } + + STL_BI_COMPATIBILITY(BiVector) +}; + +template +class BiArray : MoveableAndDeepCopyOption< BiArray > { +protected: + BiVector bv; + + void Free(); + void DeepCopy0(const BiArray& v); + +public: + int GetCount() const { return bv.GetCount(); } + bool IsEmpty() const { return GetCount() == 0; } + void Clear() { Free(); bv.Clear(); } + + T& AddHead() { T *q = new T; bv.AddHead(q); return *q; } + T& AddTail() { T *q = new T; bv.AddTail(q); return *q; } + void AddHead(const T& x) { bv.AddHead(DeepCopyNew(x)); } + void AddTail(const T& x) { bv.AddTail(DeepCopyNew(x)); } + void AddHeadPick(pick_ T& x) { bv.AddHead(new T(x)); } + void AddTailPick(pick_ T& x) { bv.AddTail(new T(x)); } + T& AddHead(T *newt) { bv.AddHead(newt); return *newt; } + T& AddTail(T *newt) { bv.AddTail(newt); return *newt; } + template TT& CreateHead() { TT *q = new TT; bv.AddHead(q); return *q; } + template TT& CreateTail() { TT *q = new TT; bv.AddTail(q); return *q; } + T& Head() { return *(T *) bv.Head(); } + T& Tail() { return *(T *) bv.Tail(); } + const T& Head() const { return *(const T *) bv.Head(); } + const T& Tail() const { return *(const T *) bv.Tail(); } + void DropHead() { delete (T*) bv.Head(); bv.DropHead(); } + void DropTail() { delete (T*) bv.Tail(); bv.DropTail(); } + T *DetachHead() { T *q = (T*) bv.Head(); bv.DropHead(); return q; } + T *DetachTail() { T *q = (T*) bv.Tail(); bv.DropTail(); return q; } + + T& operator[](int i) { return *(T *) bv[i]; } + const T& operator[](int i) const { return *(const T *) bv[i]; } + + void Shrink() { bv.Shrink(); } + void Reserve(int n) { bv.Reserve(n); } + int GetAlloc() const { return bv.GetAlloc(); } + +#ifdef UPP + void Serialize(Stream& s); +#endif + + bool IsPicked() const { return bv.IsPicked(); } + + BiArray(const BiArray& v, int) { DeepCopy0(v); } + + BiArray(pick_ BiArray& src) : bv(src.bv) {} + void operator=(pick_ BiArray& src) { Free(); bv = src.bv; } + BiArray() {} + ~BiArray() { Free(); } + + typedef ConstIIterator ConstIterator; + typedef IIterator Iterator; + + typedef T ValueType; + + ConstIterator Begin() const { return ConstIterator(*this, 0); } + ConstIterator End() const { return ConstIterator(*this, GetCount()); } + ConstIterator GetIter(int pos) const { return ConstIterator(*this, pos); } + Iterator Begin() { return Iterator(*this, 0); } + Iterator End() { return Iterator(*this, GetCount()); } + Iterator GetIter(int pos) { return Iterator(*this, pos); } + + friend void Swap(BiArray& a, BiArray& b) { UPP::Swap(a.bv, b.bv); } + + STL_BI_COMPATIBILITY(BiArray) +}; diff --git a/uppdev/CoreTopics/BlockStream.cpp b/uppdev/CoreTopics/BlockStream.cpp new file mode 100644 index 000000000..d679b5a39 --- /dev/null +++ b/uppdev/CoreTopics/BlockStream.cpp @@ -0,0 +1,512 @@ +#include "Core.h" + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) +#define LDUMP(x) // DUMP(x) +#define LLOGHEXDUMP(x, s) // LOGHEXDUMP(x, s) + +void BlockStream::SetBufferSize(dword size) { + int64 p; + if(IsOpen()) { + p = GetPos(); + Flush(); + } + int n = 1; + while(size >> (n + 1)) + n++; + pagesize = 1 << n; + pagemask = (int64)-1 << n; + if(buffer) + delete[] buffer; + buffer = new byte[pagesize]; + pos = 0; + ptr = rdlim = wrlim = buffer; + pagepos = -1; + if(IsOpen()) + Seek(p); +} + +BlockStream::BlockStream() +{ + buffer = NULL; +} + +BlockStream::~BlockStream() +{ + if(buffer) + delete[] buffer; +} + +int64 BlockStream::GetSize() const { + if(IsError()) return 0; + return max(streamsize, ptr - buffer + pos); +} + +void BlockStream::SyncSize() +{ + streamsize = max(streamsize, ptr - buffer + pos); +} + +void BlockStream::Flush() { + if(!IsOpen() || IsError()) return; + if(pagedirty && pagepos >= 0) { + SyncSize(); + int size = (int)min(streamsize - pagepos, pagesize); + LLOG("Write: " << pagepos << ", " << size); + Write(pagepos, buffer, size); + streamsize = max(streamsize, pagepos + size); + } + wrlim = buffer; + pagedirty = false; +} + +void BlockStream::SetPos(int64 p) +{ + SyncSize(); + pos = p & pagemask; + ptr = p - pos + buffer; + rdlim = wrlim = buffer; +} + +void BlockStream::Seek(int64 apos) { + if(IsError()) return; + LLOG("Seek " << apos); + if(style & STRM_WRITE) { + SetPos(apos); + if(apos > streamsize) { + SetStreamSize(apos); + streamsize = apos; + } + } + else { + if(apos > streamsize) + apos = streamsize; + SetPos(apos); + } +} + +bool BlockStream::SyncPage() +{ + if(pagepos != pos) { + int n = (int)min(streamsize - pos, pagesize); + Flush(); + pagepos = pos; + LLOG("Read:" << pagepos << ", " << n); + if(n > 0 && (int)Read(pagepos, buffer, n) != n) { + SetLastError(); + return false; + } + } + rdlim = wrlim = buffer; + return true; +} + +bool BlockStream::SyncPos() +{ + if(IsError()) + return false; + SetPos(GetPos()); + return SyncPage(); +} + +int BlockStream::_Term() { + if(IsError() || !IsOpen()) return -1; + if(ptr < rdlim) + return *ptr; + if(SyncPos()) + rdlim = buffer + (int)min(streamsize - pos, pagesize); + else { + rdlim = buffer; + return -1; + } + return ptr < rdlim ? *ptr : -1; +} + +void BlockStream::_Put(int c) { + if(!IsOpen()) return; + if(IsError() || !SyncPos()) + ptr = buffer; + wrlim = buffer + pagesize; + pagedirty = true; + *ptr++ = c; +} + +int BlockStream::_Get() { + if(IsError() || !IsOpen()) return -1; + int c = _Term(); + if(c >= 0) ptr++; + return c; +} + +void BlockStream::_Put(const void *data, dword size) { + if(IsError() || !IsOpen()) return; + LLOG("Put " << size); + if(!size) + return; + const byte *s = (const byte *)data; + if(!SyncPos()) + return; + int64 pos0 = GetPos(); + int64 pg0 = pos0 & pagemask; + int64 pos1 = pos0 + size; + int64 pg1 = pos1 & pagemask; + wrlim = buffer + pagesize; + pagedirty = true; + if(pg0 == pg1) { + memcpy(buffer + pos0 - pos, data, size); + ptr = buffer + pos1 - pos; + } + else { + int n = int(pos + pagesize - pos0); + memcpy(buffer + pos0 - pos, s, n); + s += n; + n = dword(pg1 - pg0) - pagesize; + Write(pos + pagesize, s, n); + streamsize = max(pos + pagesize + n, streamsize); + s += n; + SetPos(pos0 + size); + SyncPage(); + if(pos1 > pg1) { + wrlim = buffer + pagesize; + pagedirty = true; + memcpy(buffer, s, int(pos1 - pg1)); + } + } +} + +dword BlockStream::_Get(void *data, dword size) { + if(IsError() || !IsOpen()) return 0; + LLOG("Get " << size); + if(size == 0) return 0; + _Term(); + byte *t = (byte *)data; + int64 pos0 = GetPos(); + int64 pg0 = pos0 & pagemask; + size = (int)min(GetSize() - pos0, size); + int64 pos1 = pos0 + size; + int64 pg1 = pos1 & pagemask; + if(pg0 == pg1) { + SyncPage(); + memcpy(data, buffer + pos0 - pos, size); + ptr = buffer + pos1 - pos; + _Term(); + } + else { + int last = int(pos1 - pg1); + if(pagepos == pg1) { + memcpy(t + size - last, buffer, last); + last = 0; + } + SyncPage(); + int n = int(pos + pagesize - pos0); + memcpy(t, buffer + pos0 - pos, n); + dword q = dword(pg1 - pg0) - pagesize; + if(Read(pos + pagesize, t + n, q) != q) { + SetError(); + return 0; + } + SetPos(pos0 + size); + if(last) { + SyncPage(); + memcpy(t + size - last, buffer, last); + } + } + return size; +} + +void BlockStream::SetSize(int64 size) +{ + if(IsError() || !IsOpen()) return; + int64 pos = GetPos(); + Flush(); + Seek(0); + SetStreamSize(/*mediasize = streamsize =*/ size); // 06-08-29 TRC + // during call to SetStreamSize, mediasize must still contain the old file size + streamsize = size; + Seek(pos < size ? pos : size); +} + +dword BlockStream::Read(int64 at, void *ptr, dword size) { + NEVER(); + return 0; +} + +void BlockStream::Write(int64 at, const void *data, dword size) { + NEVER(); +} + +void BlockStream::SetStreamSize(int64 pos) { + NEVER(); +} + +void BlockStream::OpenInit(dword mode, int64 _filesize) { + streamsize = _filesize; + style = STRM_READ|STRM_SEEK; + SetLoading(); + mode &= ~SHAREMASK; + if(mode != READ) { + style |= STRM_WRITE; + SetStoring(); + } + rdlim = wrlim = ptr = buffer; + pos = 0; + pagepos = -1; + pagedirty = false; + if(!buffer) + SetBufferSize(4096); + if(mode == APPEND) SeekEnd(); +} + +// ---------------------------- File stream ----------------------------- + +#ifdef PLATFORM_WIN32 + +void FileStream::SetStreamSize(int64 pos) { + long lo = (dword)pos, hi = (dword)(pos >> 32); + if(SetFilePointer(handle, lo, &hi, FILE_BEGIN) == 0xffffffff && GetLastError() != NO_ERROR || + !SetEndOfFile(handle)) { + SetLastError(); + } +} + +void FileStream::SetPos(int64 pos) { + ASSERT(IsOpen()); + long lo = (dword)pos, hi = (dword)(pos >> 32); + if(SetFilePointer(handle, lo, &hi, FILE_BEGIN) == 0xffffffff && GetLastError() != NO_ERROR) + SetLastError(); +} + +dword FileStream::Read(int64 at, void *ptr, dword size) { + ASSERT(IsOpen() && (style & STRM_READ)); + dword n; + SetPos(at); + if(IsError()) return 0; + if(!ReadFile(handle, ptr, size, (DWORD *)&n, NULL)) { + SetLastError(); + return 0; + } + return n; +} + +void FileStream::Write(int64 at, const void *ptr, dword size) { + ASSERT(IsOpen() && (style & STRM_WRITE)); + dword n; + SetPos(at); + if(IsError()) return; + if(!WriteFile(handle, ptr, size, &n, NULL)) { + SetLastError(); + return; + } + if(n != size) + SetError(ERROR_NOT_ENOUGH_SPACE); +} + +FileTime FileStream::GetTime() const { + ASSERT(IsOpen()); + FileTime tm; + GetFileTime(handle, NULL, NULL, &tm); + return tm; +} + +void FileStream::SetTime(const FileTime& tm) { + ASSERT(IsOpen()); + Flush(); + if(!SetFileTime(handle, NULL, NULL, &tm)) + SetLastError(); +} + +bool FileStream::Open(const char *name, dword mode) { + LLOG("Open " << name << " mode: " << mode); + Close(); + int iomode = mode & ~SHAREMASK; + if(IsWinNT()) + handle = UnicodeWin32().CreateFileW(ToSystemCharsetW(name), + iomode == READ ? GENERIC_READ : GENERIC_READ|GENERIC_WRITE, + (mode & NOREADSHARE ? 0 : FILE_SHARE_READ) + | (mode & NOWRITESHARE ? 0 : FILE_SHARE_WRITE) + | (mode & DELETESHARE ? FILE_SHARE_DELETE : 0), + NULL, + iomode == READ ? OPEN_EXISTING : iomode == CREATE ? CREATE_ALWAYS : OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, + NULL + ); + else + handle = CreateFile(ToSystemCharset(name), + iomode == READ ? GENERIC_READ : GENERIC_READ|GENERIC_WRITE, + (mode & NOREADSHARE ? 0 : FILE_SHARE_READ) + | (mode & NOWRITESHARE ? 0 : FILE_SHARE_WRITE) + | (mode & DELETESHARE ? FILE_SHARE_DELETE : 0), + NULL, + iomode == READ ? OPEN_EXISTING : iomode == CREATE ? CREATE_ALWAYS : OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, + NULL + ); + if(handle == INVALID_HANDLE_VALUE) { + SetError(); + return FALSE; + } + dword fsz_lo, fsz_hi; + fsz_lo = ::GetFileSize(handle, &fsz_hi); + int64 fsz; + if(fsz_lo == 0xffffffff && GetLastError() != NO_ERROR) + fsz = 0; + else + fsz = fsz_lo | (int64(fsz_hi) << 32); + OpenInit(iomode, fsz); + LLOG("OPEN " << handle); + return TRUE; +} + +void FileStream::Close() { + if(!IsOpen()) return; + Flush(); + LLOG("CLOSE " << handle); + if(!CloseHandle(handle)) { + LLOG("CLOSE ERROR"); + LDUMP(GetLastErrorMessage()); + SetLastError(); + } + handle = INVALID_HANDLE_VALUE; +} + +bool FileStream::IsOpen() const { + return handle != INVALID_HANDLE_VALUE; +} + +FileStream::FileStream(const char *filename, dword mode) { + handle = INVALID_HANDLE_VALUE; + Open(filename, mode); +} + +FileStream::FileStream() { + handle = INVALID_HANDLE_VALUE; +} + +FileStream::~FileStream() { + Close(); +} + +#endif + +#ifdef PLATFORM_POSIX + +void FileStream::SetStreamSize(int64 pos) +{ + if(handle < 0) return; + LOFF_T_ cur = LSEEK64_(handle, 0, SEEK_CUR); + if(cur < 0) { + SetLastError(); + return; + } + LOFF_T_ len = LSEEK64_(handle, 0, SEEK_END); + if(len < 0) { + SetLastError(); + LSEEK64_(handle, cur, SEEK_SET); + return; + } + while(pos > len) { + static char buffer[1024]; + int64 diff = pos - len; + int chunk = (diff > sizeof(buffer) ? sizeof(buffer) : (int)diff); + if(write(handle, buffer, chunk) != chunk) { + SetLastError(); + LSEEK64_(handle, cur, SEEK_SET); + return; + } + len += chunk; + } + if(pos < len) { + if(cur > pos) + LSEEK64_(handle, cur = pos, SEEK_SET); + if(FTRUNCATE64_(handle, pos) < 0) + SetLastError(); + } + if(LSEEK64_(handle, cur, SEEK_SET) < 0) + SetLastError(); +} + +void FileStream::SetPos(int64 pos) { + ASSERT(IsOpen()); + if(LSEEK64_(handle, pos, SEEK_SET) < 0) + SetLastError(); +} + +dword FileStream::Read(int64 at, void *ptr, dword size) { + ASSERT(IsOpen() && (style & STRM_READ)); + SetPos(at); + if(IsError()) return 0; + int n = read(handle, ptr, size); + if(n < 0) { + SetLastError(); + return 0; + } + return n; +} + +void FileStream::Write(int64 at, const void *ptr, dword size) { + ASSERT(IsOpen() && (style & STRM_WRITE)); + SetPos(at); + if(IsError()) return; + int n = write(handle, ptr, size); + if(n < 0) { + SetLastError(); + return; + } + if((dword)n != size) + SetError(ERROR_NOT_ENOUGH_SPACE); +} + +FileTime FileStream::GetTime() const { + ASSERT(IsOpen()); + struct stat fst; + fstat(handle, &fst); + return fst.st_mtime; +} + +bool FileStream::Open(const char *name, dword mode, mode_t tmode) { + Close(); + int iomode = mode & ~SHAREMASK; + handle = open(ToSystemCharset(name), iomode == READ ? O_RDONLY : + iomode == CREATE ? O_CREAT|O_RDWR|O_TRUNC : + O_RDWR|O_CREAT, + tmode); + if(handle >= 0) { + int64 fsz = LSEEK64_(handle, 0, SEEK_END); + if(fsz >= 0) { + OpenInit(mode, fsz); + return true; + } + } + SetLastError(); + return false; +} + +void FileStream::Close() { + if(!IsOpen()) return; + Flush(); + if(close(handle) < 0) + SetLastError(); + handle = -1; +} + +bool FileStream::IsOpen() const { + return handle != -1; +} + +FileStream::FileStream(const char *filename, dword mode, mode_t acm) { + handle = -1; + Open(filename, mode, acm); +} + +FileStream::FileStream() { + handle = -1; +} + +FileStream::~FileStream() { + Close(); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Callback.cpp b/uppdev/CoreTopics/Callback.cpp new file mode 100644 index 000000000..5216f475f --- /dev/null +++ b/uppdev/CoreTopics/Callback.cpp @@ -0,0 +1,19 @@ +#include "Core.h" + +NAMESPACE_UPP + +//#BLITZ_APPROVE +#define CPP_PART__ +#include "Cbgen.h" + +void Callback::Execute() const +{ + if(action) action->Execute(); +} + +bool Gate::Execute() const +{ + return (void *)action == (void *)1 ? true : action ? action->Execute() : false; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Callback.h b/uppdev/CoreTopics/Callback.h new file mode 100644 index 000000000..785245b90 --- /dev/null +++ b/uppdev/CoreTopics/Callback.h @@ -0,0 +1,379 @@ +enum _CNULL { CNULL }; + +template +inline D brutal_cast(const S& source) { return *(D *)&source; } + +#include "Cbgen.h" + +template +struct CallbackMethodActionArgPte : public CallbackAction { + Ptr object; + METHOD_ method; + T arg; + + void Execute() { if(object) (object->*method)(arg); } + + CallbackMethodActionArgPte(OBJECT_ *object, METHOD_ method, T arg) + : object(object), method(method), arg(arg) {} +}; + +template +Callback pteback1(Object *object, void (M::*method)(P), T arg) { + return Callback(new CallbackMethodActionArgPte(object, method, arg)); +} + +template +struct CallbackMethodActionArg : public CallbackAction { + OBJECT_ *object; + METHOD_ method; + T arg; + + void Execute() { (object->*method)(arg); } + + CallbackMethodActionArg(OBJECT_ *object, METHOD_ method, T arg) + : object(object), method(method), arg(arg) {} +}; + +template +Callback callback1(Object *object, void (M::*method)(P), T arg) { + return Callback(new CallbackMethodActionArg + (object, method, arg)); +} + +template +Callback callback1(const Object *object, void (M::*method)(P) const, T arg) { + return Callback(new CallbackMethodActionArg + (object, method, arg)); +} + +template +struct CallbackActionCallArg : public CallbackAction { + F fn; + T arg; + void Execute() { fn(arg); } + + CallbackActionCallArg(F fn, T arg) : fn(fn), arg(arg) {} +}; + +template +Callback callback1(void (*fn)(P), T arg) +{ + return Callback(new CallbackActionCallArg(fn, arg)); +} + +template +struct CallbackMethodActionArg1Pte : public Callback1Action { + Ptr object; + METHOD_ method; + T arg; + void Execute(P1 p1) { if(object) (object->*method)(p1, arg); } + + CallbackMethodActionArg1Pte(OBJECT_ *object, METHOD_ method, T arg) + : object(object), method(method), arg(arg) {} +}; + +template +Callback1 pteback1(Object *object, void (M::*method)(P1, P), T arg) { + return Callback1(new CallbackMethodActionArg1Pte (object, method, arg)); +} + +template +struct CallbackMethodActionArg1 : public Callback1Action { + OBJECT_ *object; + METHOD_ method; + T arg; + void Execute(P1 p1) { (object->*method)(p1, arg); } + + CallbackMethodActionArg1(OBJECT_ *object, METHOD_ method, T arg) + : object(object), method(method), arg(arg) {} +}; + +template +Callback1 callback1(Object *object, void (M::*method)(P1, P), T arg) { + return Callback1(new CallbackMethodActionArg1 + (object, method, arg)); +} + +template +Callback1 callback1(const Object *object, void (M::*method)(P1, P) const, T arg) { + return Callback1(new CallbackMethodActionArg1 + (object, method, arg)); +} + +template +struct CallbackActionCallArg1 : Callback1Action { + F fn; + T arg; + void Execute(P1 p1) { fn(p1, arg); } + + CallbackActionCallArg1(F fn, T arg) : fn(fn), arg(arg) {} +}; + +template +Callback1 callback1(void (*fn)(P1, P), T arg) +{ + return Callback1(new CallbackActionCallArg1(fn, arg)); +} + +template +Callback callback1(Callback1

cb, T arg) +{ + return Callback(new CallbackActionCallArg, T>(cb, arg)); +} + +template +Callback1 callback1(Callback2 cb, T arg) { + return Callback1(new CallbackActionCallArg1, P1, T>(cb, arg)); +} + +template +bool Gate1::Execute(P1 p1) const { + return (void *)action == (void *)1 ? true : action ? action->Execute(p1) : false; +} + +template +bool Gate2::Execute(P1 p1, P2 p2) const { + return (void *)action == (void *)1 ? true : action ? action->Execute(p1, p2) : false; +} + +template +bool Gate3::Execute(P1 p1, P2 p2, P3 p3) const { + return (void *)action == (void *)1 ? true : action ? action->Execute(p1, p2, p3) : false; +} + +template +struct CallbackMethodActionArg2Pte : public CallbackAction { + Ptr object; + METHOD_ method; + T1 arg1; + T2 arg2; + void Execute() { if(object) (object->*method)(arg1, arg2); } + + CallbackMethodActionArg2Pte(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2) + : object(object), method(method), arg1(arg1), arg2(arg2) {} +}; + +template +Callback pteback2(Object *object, R (O::*method)(A, B), T1 arg1, T2 arg2) { + return Callback(new CallbackMethodActionArg2Pte + (object, method, arg1, arg2)); +} + +template +struct CallbackMethodActionArg2 : public CallbackAction { + OBJECT_ *object; + METHOD_ method; + T1 arg1; + T2 arg2; + void Execute() { (object->*method)(arg1, arg2); } + + CallbackMethodActionArg2(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2) + : object(object), method(method), arg1(arg1), arg2(arg2) {} +}; + +template +Callback callback2(Object *object, R (O::*method)(A, B), T1 arg1, T2 arg2) { + return Callback(new CallbackMethodActionArg2 + (object, method, arg1, arg2)); +} + +template +Callback callback2(const Object *object, R (O::*method)(A, B) const, T1 arg1, T2 arg2) { + return Callback(new CallbackMethodActionArg2 + (object, method, arg1, arg2)); +} + +template +struct CallbackActionCallArg2 : public CallbackAction { + X x; + T1 arg1; + T2 arg2; + void Execute() { x(arg1, arg2); } + + CallbackActionCallArg2(X x, T1 arg1, T2 arg2) : x(x), arg1(arg1), arg2(arg2) {} +}; + +template +Callback callback2(R (*fn)(A, B), T1 arg1, T2 arg2) { + return Callback(new CallbackActionCallArg2(fn, arg1, arg2)); +} + +template +Callback callback2(Callback2 cb, T1 arg1, T2 arg2) { + return Callback(new CallbackActionCallArg2, T1, T2>(cb, arg1, arg2)); +} + +template +struct CallbackMethodActionArg3Pte : public CallbackAction { + Ptr object; + METHOD_ method; + T1 arg1; + T2 arg2; + T3 arg3; + void Execute() { if(object) (object->*method)(arg1, arg2, arg3); } + + CallbackMethodActionArg3Pte(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2, T3 arg3) + : object(object), method(method), arg1(arg1), arg2(arg2), arg3(arg3) {} +}; + +template +Callback pteback3(Object *object, R (O::*method)(A, B, C), T1 arg1, T2 arg2, T3 arg3) { + return Callback(new CallbackMethodActionArg3Pte + (object, method, arg1, arg2, arg3)); +} + +template +struct CallbackMethodActionArg3 : public CallbackAction +{ + OBJECT_ *object; + METHOD_ method; + T1 arg1; + T2 arg2; + T3 arg3; + + void Execute() { (object->*method)(arg1, arg2, arg3); } + + CallbackMethodActionArg3(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2, T3 arg3) + : object(object), method(method), arg1(arg1), arg2(arg2), arg3(arg3) {} +}; + +template +Callback callback3(Object *object, R (O::*method)(A, B, C), T1 arg1, T2 arg2, T3 arg3) +{ + return Callback( + new CallbackMethodActionArg3(object, method, arg1, arg2, arg3)); +} + +template +Callback callback3(const Object *object, R (O::*method)(A, B, C) const, T1 arg1, T2 arg2, T3 arg3) { + return Callback(new CallbackMethodActionArg3 + (object, method, arg1, arg2, arg3)); +} + +template +struct CallbackActionCallArg3 : public CallbackAction { + X x; + T1 arg1; + T2 arg2; + T3 arg3; + void Execute() { x(arg1, arg2, arg3); } + + CallbackActionCallArg3(X x, T1 arg1, T2 arg2, T3 arg3) + : x(x), arg1(arg1), arg2(arg2), arg3(arg3) {} +}; + +template +Callback callback3(R (*fn)(A, B, C), T1 arg1, T2 arg2, T3 arg3) { + return Callback( + new CallbackActionCallArg3(fn, arg1, arg2, arg3)); +} + +template +Callback callback3(Callback3 cb, T1 arg1, T2 arg2, T3 arg3) { + return Callback( + new CallbackActionCallArg3, T1, T2, T3>(cb, arg1, arg2, arg3)); +} + +template +struct CallbackMethodActionArg4Pte : public CallbackAction { + Ptr object; + METHOD_ method; + T1 arg1; + T2 arg2; + T3 arg3; + T4 arg4; + void Execute() { if(object) (object->*method)(arg1, arg2, arg3, arg4); } + + CallbackMethodActionArg4Pte(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + : object(object), method(method), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} +}; + +template +Callback pteback4(Object *object, R (O::*method)(A, B,C,D), T1 arg1, T2 arg2, T3 arg3, T4 arg4) { + return Callback(new CallbackMethodActionArg4Pte + (object, method, arg1, arg2, arg3, arg4)); +} + +template +struct CallbackMethodActionArg4 : public CallbackAction +{ + OBJECT_ *object; + METHOD_ method; + T1 arg1; + T2 arg2; + T3 arg3; + T4 arg4; + + void Execute() { (object->*method)(arg1, arg2, arg3, arg4); } + + CallbackMethodActionArg4(OBJECT_ *object, METHOD_ method, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + : object(object), method(method), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} +}; + +template +Callback callback4(Object *object, R (O::*method)(A, B, C, D), T1 arg1, T2 arg2, T3 arg3, T4 arg4) +{ + return Callback( + new CallbackMethodActionArg4(object, method, arg1, arg2, arg3, arg4)); +} + +template +Callback callback4(const Object *object, R (O::*method)(A, B, C, D) const, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { + return Callback(new CallbackMethodActionArg4 + (object, method, arg1, arg2, arg3, arg4)); +} + +template +struct CallbackActionCallArg4 : public CallbackAction { + X x; + T1 arg1; + T2 arg2; + T3 arg3; + T4 arg4; + void Execute() { x(arg1, arg2, arg3, arg4); } + + CallbackActionCallArg4(X x, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + : x(x), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} +}; + +template +Callback callback4(R (*fn)(A, B, C, D), T1 arg1, T2 arg2, T3 arg3, T4 arg4) { + return Callback( + new CallbackActionCallArg4(fn, arg1, arg2, arg3, arg4)); +} + +template +Callback callback4(Callback4 cb, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { + return Callback( + new CallbackActionCallArg4, T1, T2, T3, T4>(cb, arg1, arg2, arg3, arg4)); +} + +#define THISBACK(x) callback(this, &CLASSNAME::x) +#define THISBACK1(x, arg) callback1(this, &CLASSNAME::x, arg) +#define THISBACK2(m, a, b) callback2(this, &CLASSNAME::m, a, b) +#define THISBACK3(m, a, b, c) callback3(this, &CLASSNAME::m, a, b, c) +#define THISBACK4(m, a, b, c, d) callback4(this, &CLASSNAME::m, a, b, c, d) + +#define PTEBACK(x) pteback(this, &CLASSNAME::x) +#define PTEBACK1(x, arg) pteback1(this, &CLASSNAME::x, arg) +#define PTEBACK2(m, a, b) pteback2(this, &CLASSNAME::m, a, b) +#define PTEBACK3(m, a, b, c) pteback3(this, &CLASSNAME::m, a, b, c) +#define PTEBACK4(m, a, b, c, d) pteback4(this, &CLASSNAME::m, a, b, c, d) + +template +class CallbackArgTarget +{ + T result; + + void SetResult(const T& value) { result = value; } + +public: + typedef CallbackArgTarget CLASSNAME; + + operator const T&() { return result; } + bool IsNullInstance() const { return IsNull(result); } + + Callback operator[](const T& value) { return THISBACK1(SetResult, value); } + + CallbackArgTarget() { result = Null; } +}; diff --git a/uppdev/CoreTopics/CallbackN.h b/uppdev/CoreTopics/CallbackN.h new file mode 100644 index 000000000..85d47beb2 --- /dev/null +++ b/uppdev/CoreTopics/CallbackN.h @@ -0,0 +1,180 @@ +#define CallbackTemplate(name, rettype, template_, template__, _template, _tsep_, classdef, \ + classlist, paramdef, paramlist, return_, extension) \ + \ +template_ classdef _template \ +struct name##Action { \ + int count; \ + virtual rettype Execute(paramdef) = 0; \ + virtual bool IsEqual(const name##Action *other) const = 0; \ + virtual unsigned GetHashValue() const = 0; \ + \ + name##Action() { count = 1; } \ + virtual ~name##Action() {} \ +}; \ + \ +template \ +struct name##MethodAction : public name##Action template__ classlist _template { \ + OBJECT_ *object; \ + METHOD_ method; \ + rettype Execute(paramdef) { return_ (object->*method)(paramlist); } \ + bool IsEqual(const name##Action template__ classlist _template *other) const { \ + const name##MethodAction *q = dynamic_cast(other); \ + return q ? q->object == object && q->method == method : false; \ + } \ + unsigned GetHashValue() const { \ + return (unsigned)object ^ brutal_cast(method); \ + } \ + \ + name##MethodAction(OBJECT_ *object, METHOD_ method) \ + : object(object), method(method) {} \ +}; \ + \ +template_ classdef _template \ +struct name##FnAction : public name##Action template__ classlist _template { \ + rettype (*fn)(paramdef); \ + rettype Execute(paramdef) { return_ (*fn)(paramlist); } \ + bool IsEqual(const name##Action template__ classlist _template *other) const { \ + const name##FnAction *q = dynamic_cast(other); \ + return q ? q->fn == fn : false; \ + } \ + unsigned GetHashValue() const { \ + return (unsigned)fn; \ + } \ + \ + name##FnAction(rettype (*fn)(paramdef)) : fn(fn) {} \ +}; \ + \ +template_ classdef _template \ +class name : Moveable< name template__ classlist _template > { \ + name##Action template__ classlist _template *action; \ + \ + void Retain() const { if(*this) action->count++; } \ + void Release() { if(*this && --action->count == 0) delete action; } \ + \ +public: \ + typedef name CLASSNAME; \ + name& operator=(const name& c); \ + name(const name& c); \ + void Clear() { Release(); action = NULL; } \ + extension \ +\ + unsigned GetHashValue() const { return action->GetHashValue(); } \ +\ + explicit name(name##Action template__ classlist _template *newaction) { action = newaction; } \ + name& operator=(name##Action template__ classlist _template *newaction) { action = newaction; return *this; } \ + name() { action = NULL; } \ + name(_CNULL) { action = NULL; } \ + ~name(); \ +\ + static name Empty() { return CNULL; } \ +\ + friend bool operator==(const name& a, const name& b) { return a.action ? a.action->IsEqual(b.action) : !b.action; } \ + friend bool operator!=(const name& a, const name& b) { return !(a == b); } \ + /*friend unsigned GetHashValue(const name& m) { return m.action->GetHashValue(); }*/ \ +}; \ + \ +template \ +name template__ classlist _template callback(Object *object, rettype (M::*method)(paramdef)) { \ + return name template__ classlist _template \ + (new name##MethodAction(object, method)); \ +} \ + \ +template \ +name template__ classlist _template callback(const Object *object, rettype (M::*method)(paramdef) const) { \ + return name template__ classlist _template \ + (new name##MethodAction(object, method)); \ +} \ + \ +template_ classdef _template \ +inline name template__ classlist _template callback(rettype (*fn)(paramdef)) { \ + return name template__ classlist _template \ + (new name##FnAction template__ classlist _template(fn)); \ +} \ +template_ classdef _template \ +struct name##ForkAction : public name##Action template__ classlist _template { \ + name template__ classlist _template cb1, cb2; \ + rettype Execute(paramdef) { cb1(paramlist); return_ cb2(paramlist); } \ + bool IsEqual(const name##Action template__ classlist _template *other) const { \ + const name##ForkAction *q = dynamic_cast(other); \ + return q ? q->cb1 == cb1 && q->cb2 == cb2 : false; \ + } \ + unsigned GetHashValue() const { \ + return ::GetHashValue(cb1) ^ ::GetHashValue(cb2); \ + } \ + \ + name##ForkAction(name template__ classlist _template cb1, \ + name template__ classlist _template cb2) : cb1(cb1), cb2(cb2) {} \ +}; \ + \ +template_ classdef _template \ +inline \ +name template__ classlist _template callback( \ + name template__ classlist _template cb1, \ + name template__ classlist _template cb2) { \ + return name template__ classlist _template \ + (new name##ForkAction template__ classlist _template(cb1, cb2)); \ +} \ + \ +template_ classdef _template \ +inline \ +name template__ classlist _template& operator<<( \ + name template__ classlist _template& a, \ + name template__ classlist _template b) { \ + if(a) \ + a = callback(a, b); \ + else \ + a = b; \ + return a; \ +} + +#define CallbackBodyTemplate(name, template_, tlist) \ +template_ \ +name tlist& name tlist::operator=(const name& c) { \ + c.Retain(); Release(); action = c.action; return *this; \ +} \ +\ +template_ \ +name tlist::name(const name& c) { action = c.action; Retain(); } \ +\ +template_ \ +name tlist::~name() { Release(); } + +#define _empty_ + +//$ struct Callback; + +//$- + +CallbackTemplate( + /* name */ Callback, + /* rettype */ void, + /* template_ */ _empty_, + /* template__ */ _empty_, + /* _template */ _empty_, + /* tsep */ _empty_, + /* classdef */ _empty_, + /* classlist */ _empty_, + /* paramdef */ _empty_, + /* paramlist */ _empty_, + /* return_ */ _empty_, + operator bool() const { return action; } + void operator()() const; +) + +CallbackTemplate( + /* name */ Callback1, + /* rettype */ void, + /* template_ */ template<, + /* template__ */ <, + /* _template */ >, + /* tsep */ _cm_, + /* classdef */ class P1, + /* classlist */ P1, + /* paramdef */ P1 p1, + /* paramlist */ p1, + /* return_ */ _empty_, + operator bool() const { return action; } + void operator()(P1 p1) const { if(action) action->Execute(p1); } +) + +CallbackBodyTemplate(Callback1, template, ) diff --git a/uppdev/CoreTopics/Cbgen.h b/uppdev/CoreTopics/Cbgen.h new file mode 100644 index 000000000..3146c4ecb --- /dev/null +++ b/uppdev/CoreTopics/Cbgen.h @@ -0,0 +1,1500 @@ +#ifndef CPP_PART__ + +// ----------------------------------------------------------- + +struct CallbackAction { + Atomic count; + + virtual void Execute() = 0; + virtual bool IsValid() const { return true; } + + CallbackAction() { count = 1; } + virtual ~CallbackAction() {} +}; + +template +struct CallbackMethodActionPte : public CallbackAction { + Ptr object; + METHOD method; + + void Execute() { if(object) (object->*method)(); } + bool IsValid() const { return object; } + + CallbackMethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct CallbackMethodAction : public CallbackAction { + OBJECT *object; + METHOD method; + + void Execute() { (object->*method)(); } + + CallbackMethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +struct CallbackFnAction : public CallbackAction { + void (*fn)(); + + void Execute() { (*fn)(); } + + CallbackFnAction(void (*fn)()) : fn(fn) {} +}; + +class Callback : Moveable< Callback > { + CallbackAction *action; + + void Retain() const { if(action ) AtomicInc(action->count); } + void Release() { if(action && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Callback&); + bool operator!=(const Callback&); + +public: + typedef Callback CLASSNAME; + + Callback& operator=(const Callback& c); + Callback(const Callback& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return action && action->IsValid(); } + void Execute() const; + void operator()() const { Execute(); } + + explicit Callback(CallbackAction *newaction) { action = newaction; } + Callback() { action = NULL; } + Callback(_CNULL) { action = NULL; } + ~Callback(); + + static Callback Empty() { return CNULL; } + +}; + +template +Callback pteback(OBJECT *object, void (METHOD::*method)()) { + return Callback(new CallbackMethodActionPte(object, method)); +} + +template +Callback callback(OBJECT *object, void (METHOD::*method)()) { + return Callback(new CallbackMethodAction(object, method)); +} + +template +Callback callback(const OBJECT *object, void (METHOD::*method)() const) { + return Callback(new CallbackMethodAction(object, method)); +} + +inline Callback callback(void (*fn)()) { + return Callback(new CallbackFnAction (fn)); +} + +struct CallbackForkAction : public CallbackAction { + Callback cb1, cb2; + + void Execute() { cb1(); cb2(); } + + CallbackForkAction(Callback cb1, Callback cb2) + : cb1(cb1), cb2(cb2) {} +}; + +inline Callback Proxy(Callback& cb) +{ + return callback(&cb, &Callback::Execute); +} + +Callback callback(Callback cb1, Callback cb2); +Callback& operator<<(Callback& a, Callback b); + +#endif +#ifdef CPP_PART__ + +Callback callback(Callback cb1, Callback cb2) +{ + return Callback(new CallbackForkAction (cb1, cb2)); +} + +Callback& operator<<(Callback& a, Callback b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +Callback& Callback::operator=(const Callback& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +Callback::Callback(const Callback& c) +{ + action = c.action; + Retain(); +} + +Callback::~Callback() +{ + Release(); +} + +#endif +#ifndef CPP_PART__ + +// ----------------------------------------------------------- + +template +struct Callback1Action { + Atomic count; + + virtual void Execute(P1 p1) = 0; + virtual bool IsValid() const { return true; } + + Callback1Action() { count = 1; } + virtual ~Callback1Action() {} +}; + +template +struct Callback1MethodActionPte : public Callback1Action { + Ptr object; + METHOD method; + + void Execute(P1 p1) { if(object) (object->*method)(p1); } + bool IsValid() const { return object; } + + Callback1MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback1MethodAction : public Callback1Action { + OBJECT *object; + METHOD method; + + void Execute(P1 p1) { (object->*method)(p1); } + + Callback1MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback1FnAction : public Callback1Action { + void (*fn)(P1 p1); + + void Execute(P1 p1) { (*fn)(p1); } + + Callback1FnAction(void (*fn)(P1 p1)) : fn(fn) {} +}; + +template +class Callback1 : Moveable< Callback1 > { + Callback1Action *action; + + void Retain() const { if(action ) AtomicInc(action->count); } + void Release() { if(action && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Callback1&); + bool operator!=(const Callback1&); + +public: + typedef Callback1 CLASSNAME; + + Callback1& operator=(const Callback1& c); + Callback1(const Callback1& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return action && action->IsValid(); } + void Execute(P1 p1) const { if(action) action->Execute(p1); } + void operator()(P1 p1) const { Execute(p1); } + + explicit Callback1(Callback1Action *newaction) { action = newaction; } + Callback1() { action = NULL; } + Callback1(_CNULL) { action = NULL; } + ~Callback1(); + + static Callback1 Empty() { return CNULL; } + +}; + +template +Callback1 pteback(OBJECT *object, void (METHOD::*method)(P1 p1)) { + return Callback1(new Callback1MethodActionPte(object, method)); +} + +template +Callback1 callback(OBJECT *object, void (METHOD::*method)(P1 p1)) { + return Callback1(new Callback1MethodAction(object, method)); +} + +template +Callback1 callback(const OBJECT *object, void (METHOD::*method)(P1 p1) const) { + return Callback1(new Callback1MethodAction(object, method)); +} + +template +inline Callback1 callback(void (*fn)(P1 p1)) { + return Callback1(new Callback1FnAction (fn)); +} + +template +struct Callback1ForkAction : public Callback1Action { + Callback1 cb1, cb2; + + void Execute(P1 p1) { cb1(p1); cb2(p1); } + + Callback1ForkAction(Callback1 cb1, Callback1 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Callback1 Proxy(Callback1& cb) +{ + return callback(&cb, &Callback1::Execute); +} + +template +Callback1 callback(Callback1 cb1, Callback1 cb2) +{ + return Callback1(new Callback1ForkAction (cb1, cb2)); +} + +template +Callback1& operator<<(Callback1& a, Callback1 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Callback1& Callback1::operator=(const Callback1& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Callback1::Callback1(const Callback1& c) +{ + action = c.action; + Retain(); +} + +template +Callback1::~Callback1() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Callback2Action { + Atomic count; + + virtual void Execute(P1 p1, P2 p2) = 0; + virtual bool IsValid() const { return true; } + + Callback2Action() { count = 1; } + virtual ~Callback2Action() {} +}; + +template +struct Callback2MethodActionPte : public Callback2Action { + Ptr object; + METHOD method; + + void Execute(P1 p1, P2 p2) { if(object) (object->*method)(p1, p2); } + bool IsValid() const { return object; } + + Callback2MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback2MethodAction : public Callback2Action { + OBJECT *object; + METHOD method; + + void Execute(P1 p1, P2 p2) { (object->*method)(p1, p2); } + + Callback2MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback2FnAction : public Callback2Action { + void (*fn)(P1 p1, P2 p2); + + void Execute(P1 p1, P2 p2) { (*fn)(p1, p2); } + + Callback2FnAction(void (*fn)(P1 p1, P2 p2)) : fn(fn) {} +}; + +template +class Callback2 : Moveable< Callback2 > { + Callback2Action *action; + + void Retain() const { if(action ) AtomicInc(action->count); } + void Release() { if(action && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Callback2&); + bool operator!=(const Callback2&); + +public: + typedef Callback2 CLASSNAME; + + Callback2& operator=(const Callback2& c); + Callback2(const Callback2& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return action && action->IsValid(); } + void Execute(P1 p1, P2 p2) const { if(action) action->Execute(p1, p2); } + void operator()(P1 p1, P2 p2) const { Execute(p1, p2); } + + explicit Callback2(Callback2Action *newaction) { action = newaction; } + Callback2() { action = NULL; } + Callback2(_CNULL) { action = NULL; } + ~Callback2(); + + static Callback2 Empty() { return CNULL; } + +}; + +template +Callback2 pteback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2)) { + return Callback2(new Callback2MethodActionPte(object, method)); +} + +template +Callback2 callback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2)) { + return Callback2(new Callback2MethodAction(object, method)); +} + +template +Callback2 callback(const OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2) const) { + return Callback2(new Callback2MethodAction(object, method)); +} + +template +inline Callback2 callback(void (*fn)(P1 p1, P2 p2)) { + return Callback2(new Callback2FnAction (fn)); +} + +template +struct Callback2ForkAction : public Callback2Action { + Callback2 cb1, cb2; + + void Execute(P1 p1, P2 p2) { cb1(p1, p2); cb2(p1, p2); } + + Callback2ForkAction(Callback2 cb1, Callback2 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Callback2 Proxy(Callback2& cb) +{ + return callback(&cb, &Callback2::Execute); +} + +template +Callback2 callback(Callback2 cb1, Callback2 cb2) +{ + return Callback2(new Callback2ForkAction (cb1, cb2)); +} + +template +Callback2& operator<<(Callback2& a, Callback2 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Callback2& Callback2::operator=(const Callback2& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Callback2::Callback2(const Callback2& c) +{ + action = c.action; + Retain(); +} + +template +Callback2::~Callback2() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Callback3Action { + Atomic count; + + virtual void Execute(P1 p1, P2 p2, P3 p3) = 0; + virtual bool IsValid() const { return true; } + + Callback3Action() { count = 1; } + virtual ~Callback3Action() {} +}; + +template +struct Callback3MethodActionPte : public Callback3Action { + Ptr object; + METHOD method; + + void Execute(P1 p1, P2 p2, P3 p3) { if(object) (object->*method)(p1, p2, p3); } + bool IsValid() const { return object; } + + Callback3MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback3MethodAction : public Callback3Action { + OBJECT *object; + METHOD method; + + void Execute(P1 p1, P2 p2, P3 p3) { (object->*method)(p1, p2, p3); } + + Callback3MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback3FnAction : public Callback3Action { + void (*fn)(P1 p1, P2 p2, P3 p3); + + void Execute(P1 p1, P2 p2, P3 p3) { (*fn)(p1, p2, p3); } + + Callback3FnAction(void (*fn)(P1 p1, P2 p2, P3 p3)) : fn(fn) {} +}; + +template +class Callback3 : Moveable< Callback3 > { + Callback3Action *action; + + void Retain() const { if(action ) AtomicInc(action->count); } + void Release() { if(action && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Callback3&); + bool operator!=(const Callback3&); + +public: + typedef Callback3 CLASSNAME; + + Callback3& operator=(const Callback3& c); + Callback3(const Callback3& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return action && action->IsValid(); } + void Execute(P1 p1, P2 p2, P3 p3) const { if(action) action->Execute(p1, p2, p3); } + void operator()(P1 p1, P2 p2, P3 p3) const { Execute(p1, p2, p3); } + + explicit Callback3(Callback3Action *newaction) { action = newaction; } + Callback3() { action = NULL; } + Callback3(_CNULL) { action = NULL; } + ~Callback3(); + + static Callback3 Empty() { return CNULL; } + +}; + +template +Callback3 pteback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3)) { + return Callback3(new Callback3MethodActionPte(object, method)); +} + +template +Callback3 callback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3)) { + return Callback3(new Callback3MethodAction(object, method)); +} + +template +Callback3 callback(const OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3) const) { + return Callback3(new Callback3MethodAction(object, method)); +} + +template +inline Callback3 callback(void (*fn)(P1 p1, P2 p2, P3 p3)) { + return Callback3(new Callback3FnAction (fn)); +} + +template +struct Callback3ForkAction : public Callback3Action { + Callback3 cb1, cb2; + + void Execute(P1 p1, P2 p2, P3 p3) { cb1(p1, p2, p3); cb2(p1, p2, p3); } + + Callback3ForkAction(Callback3 cb1, Callback3 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Callback3 Proxy(Callback3& cb) +{ + return callback(&cb, &Callback3::Execute); +} + +template +Callback3 callback(Callback3 cb1, Callback3 cb2) +{ + return Callback3(new Callback3ForkAction (cb1, cb2)); +} + +template +Callback3& operator<<(Callback3& a, Callback3 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Callback3& Callback3::operator=(const Callback3& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Callback3::Callback3(const Callback3& c) +{ + action = c.action; + Retain(); +} + +template +Callback3::~Callback3() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Callback4Action { + Atomic count; + + virtual void Execute(P1 p1, P2 p2, P3 p3, P4 p4) = 0; + virtual bool IsValid() const { return true; } + + Callback4Action() { count = 1; } + virtual ~Callback4Action() {} +}; + +template +struct Callback4MethodActionPte : public Callback4Action { + Ptr object; + METHOD method; + + void Execute(P1 p1, P2 p2, P3 p3, P4 p4) { if(object) (object->*method)(p1, p2, p3, p4); } + bool IsValid() const { return object; } + + Callback4MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback4MethodAction : public Callback4Action { + OBJECT *object; + METHOD method; + + void Execute(P1 p1, P2 p2, P3 p3, P4 p4) { (object->*method)(p1, p2, p3, p4); } + + Callback4MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Callback4FnAction : public Callback4Action { + void (*fn)(P1 p1, P2 p2, P3 p3, P4 p4); + + void Execute(P1 p1, P2 p2, P3 p3, P4 p4) { (*fn)(p1, p2, p3, p4); } + + Callback4FnAction(void (*fn)(P1 p1, P2 p2, P3 p3, P4 p4)) : fn(fn) {} +}; + +template +class Callback4 : Moveable< Callback4 > { + Callback4Action *action; + + void Retain() const { if(action ) AtomicInc(action->count); } + void Release() { if(action && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Callback4&); + bool operator!=(const Callback4&); + +public: + typedef Callback4 CLASSNAME; + + Callback4& operator=(const Callback4& c); + Callback4(const Callback4& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return action && action->IsValid(); } + void Execute(P1 p1, P2 p2, P3 p3, P4 p4) const { if(action) action->Execute(p1, p2, p3, p4); } + void operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { Execute(p1, p2, p3, p4); } + + explicit Callback4(Callback4Action *newaction) { action = newaction; } + Callback4() { action = NULL; } + Callback4(_CNULL) { action = NULL; } + ~Callback4(); + + static Callback4 Empty() { return CNULL; } + +}; + +template +Callback4 pteback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Callback4(new Callback4MethodActionPte(object, method)); +} + +template +Callback4 callback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Callback4(new Callback4MethodAction(object, method)); +} + +template +Callback4 callback(const OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4) const) { + return Callback4(new Callback4MethodAction(object, method)); +} + +template +inline Callback4 callback(void (*fn)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Callback4(new Callback4FnAction (fn)); +} + +template +struct Callback4ForkAction : public Callback4Action { + Callback4 cb1, cb2; + + void Execute(P1 p1, P2 p2, P3 p3, P4 p4) { cb1(p1, p2, p3, p4); cb2(p1, p2, p3, p4); } + + Callback4ForkAction(Callback4 cb1, Callback4 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Callback4 Proxy(Callback4& cb) +{ + return callback(&cb, &Callback4::Execute); +} + +template +Callback4 callback(Callback4 cb1, Callback4 cb2) +{ + return Callback4(new Callback4ForkAction (cb1, cb2)); +} + +template +Callback4& operator<<(Callback4& a, Callback4 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Callback4& Callback4::operator=(const Callback4& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Callback4::Callback4(const Callback4& c) +{ + action = c.action; + Retain(); +} + +template +Callback4::~Callback4() +{ + Release(); +} + +// ----------------------------------------------------------- + +struct GateAction { + Atomic count; + + virtual bool Execute() = 0; + virtual bool IsValid() const { return true; } + + GateAction() { count = 1; } + virtual ~GateAction() {} +}; + +template +struct GateMethodActionPte : public GateAction { + Ptr object; + METHOD method; + + bool Execute() { return object ? (object->*method)() : false; } + bool IsValid() const { return object; } + + GateMethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct GateMethodAction : public GateAction { + OBJECT *object; + METHOD method; + + bool Execute() { return (object->*method)(); } + + GateMethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +struct GateFnAction : public GateAction { + bool (*fn)(); + + bool Execute() { return (*fn)(); } + + GateFnAction(bool (*fn)()) : fn(fn) {} +}; + +class Gate : Moveable< Gate > { + GateAction *action; + + void Retain() const { if(action && (void *)action != (void *)1) AtomicInc(action->count); } + void Release() { if(action && (void *)action != (void *)1 && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Gate&); + bool operator!=(const Gate&); + +public: + typedef Gate CLASSNAME; + + Gate& operator=(const Gate& c); + Gate(const Gate& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return (void *)action != (void *)1 && action && action->IsValid(); } + bool Execute() const; + bool operator()() const { return Execute(); } + void ClearTrue() { Clear(); action = (GateAction *)(uintptr_t)1; } + void ClearFalse() { Clear(); } + + Gate(bool b) { action = (GateAction *)(uintptr_t)b; } + + explicit Gate(GateAction *newaction) { action = newaction; } + Gate() { action = NULL; } + Gate(_CNULL) { action = NULL; } + ~Gate(); + + static Gate Empty() { return CNULL; } + +}; + +template +Gate pteback(OBJECT *object, bool (METHOD::*method)()) { + return Gate(new GateMethodActionPte(object, method)); +} + +template +Gate callback(OBJECT *object, bool (METHOD::*method)()) { + return Gate(new GateMethodAction(object, method)); +} + +template +Gate callback(const OBJECT *object, bool (METHOD::*method)() const) { + return Gate(new GateMethodAction(object, method)); +} + +inline Gate callback(bool (*fn)()) { + return Gate(new GateFnAction (fn)); +} + +struct GateForkAction : public GateAction { + Gate cb1, cb2; + + bool Execute() { cb1(); return cb2(); } + + GateForkAction(Gate cb1, Gate cb2) + : cb1(cb1), cb2(cb2) {} +}; + +inline Gate Proxy(Gate& cb) +{ + return callback(&cb, &Gate::Execute); +} + +Gate callback(Gate cb1, Gate cb2); +Gate& operator<<(Gate& a, Gate b); + +#endif +#ifdef CPP_PART__ + +Gate callback(Gate cb1, Gate cb2) +{ + return Gate(new GateForkAction (cb1, cb2)); +} + +Gate& operator<<(Gate& a, Gate b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +Gate& Gate::operator=(const Gate& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +Gate::Gate(const Gate& c) +{ + action = c.action; + Retain(); +} + +Gate::~Gate() +{ + Release(); +} + +#endif +#ifndef CPP_PART__ + +// ----------------------------------------------------------- + +template +struct Gate1Action { + Atomic count; + + virtual bool Execute(P1 p1) = 0; + virtual bool IsValid() const { return true; } + + Gate1Action() { count = 1; } + virtual ~Gate1Action() {} +}; + +template +struct Gate1MethodActionPte : public Gate1Action { + Ptr object; + METHOD method; + + bool Execute(P1 p1) { return object ? (object->*method)(p1) : false; } + bool IsValid() const { return object; } + + Gate1MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate1MethodAction : public Gate1Action { + OBJECT *object; + METHOD method; + + bool Execute(P1 p1) { return (object->*method)(p1); } + + Gate1MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate1FnAction : public Gate1Action { + bool (*fn)(P1 p1); + + bool Execute(P1 p1) { return (*fn)(p1); } + + Gate1FnAction(bool (*fn)(P1 p1)) : fn(fn) {} +}; + +template +class Gate1 : Moveable< Gate1 > { + Gate1Action *action; + + void Retain() const { if(action && (void *)action != (void *)1) AtomicInc(action->count); } + void Release() { if(action && (void *)action != (void *)1 && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Gate1&); + bool operator!=(const Gate1&); + +public: + typedef Gate1 CLASSNAME; + + Gate1& operator=(const Gate1& c); + Gate1(const Gate1& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return (void *)action != (void *)1 && action && action->IsValid(); } + bool Execute(P1 p1) const; + bool operator()(P1 p1) const { return Execute(p1); } + void ClearTrue() { Clear(); action = (Gate1Action *)1; } + void ClearFalse() { Clear(); } + + Gate1(bool b) { action = (Gate1Action *)(uintptr_t)b; } + + explicit Gate1(Gate1Action *newaction) { action = newaction; } + Gate1() { action = NULL; } + Gate1(_CNULL) { action = NULL; } + ~Gate1(); + + static Gate1 Empty() { return CNULL; } + +}; + +template +Gate1 pteback(OBJECT *object, bool (METHOD::*method)(P1 p1)) { + return Gate1(new Gate1MethodActionPte(object, method)); +} + +template +Gate1 callback(OBJECT *object, bool (METHOD::*method)(P1 p1)) { + return Gate1(new Gate1MethodAction(object, method)); +} + +template +Gate1 callback(const OBJECT *object, bool (METHOD::*method)(P1 p1) const) { + return Gate1(new Gate1MethodAction(object, method)); +} + +template +inline Gate1 callback(bool (*fn)(P1 p1)) { + return Gate1(new Gate1FnAction (fn)); +} + +template +struct Gate1ForkAction : public Gate1Action { + Gate1 cb1, cb2; + + bool Execute(P1 p1) { cb1(p1); return cb2(p1); } + + Gate1ForkAction(Gate1 cb1, Gate1 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Gate1 Proxy(Gate1& cb) +{ + return callback(&cb, &Gate1::Execute); +} + +template +Gate1 callback(Gate1 cb1, Gate1 cb2) +{ + return Gate1(new Gate1ForkAction (cb1, cb2)); +} + +template +Gate1& operator<<(Gate1& a, Gate1 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Gate1& Gate1::operator=(const Gate1& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Gate1::Gate1(const Gate1& c) +{ + action = c.action; + Retain(); +} + +template +Gate1::~Gate1() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Gate2Action { + Atomic count; + + virtual bool Execute(P1 p1, P2 p2) = 0; + virtual bool IsValid() const { return true; } + + Gate2Action() { count = 1; } + virtual ~Gate2Action() {} +}; + +template +struct Gate2MethodActionPte : public Gate2Action { + Ptr object; + METHOD method; + + bool Execute(P1 p1, P2 p2) { return object ? (object->*method)(p1, p2) : false; } + bool IsValid() const { return object; } + + Gate2MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate2MethodAction : public Gate2Action { + OBJECT *object; + METHOD method; + + bool Execute(P1 p1, P2 p2) { return (object->*method)(p1, p2); } + + Gate2MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate2FnAction : public Gate2Action { + bool (*fn)(P1 p1, P2 p2); + + bool Execute(P1 p1, P2 p2) { return (*fn)(p1, p2); } + + Gate2FnAction(bool (*fn)(P1 p1, P2 p2)) : fn(fn) {} +}; + +template +class Gate2 : Moveable< Gate2 > { + Gate2Action *action; + + void Retain() const { if(action && (void *)action != (void *)1) AtomicInc(action->count); } + void Release() { if(action && (void *)action != (void *)1 && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Gate2&); + bool operator!=(const Gate2&); + +public: + typedef Gate2 CLASSNAME; + + Gate2& operator=(const Gate2& c); + Gate2(const Gate2& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return (void *)action != (void *)1 && action && action->IsValid(); } + bool Execute(P1 p1, P2 p2) const; + bool operator()(P1 p1, P2 p2) const { return Execute(p1, p2); } + void ClearTrue() { Clear(); action = (Gate2Action *)1; } + void ClearFalse() { Clear(); } + + Gate2(bool b) { action = (Gate2Action *)(uintptr_t)b; } + + explicit Gate2(Gate2Action *newaction) { action = newaction; } + Gate2() { action = NULL; } + Gate2(_CNULL) { action = NULL; } + ~Gate2(); + + static Gate2 Empty() { return CNULL; } + +}; + +template +Gate2 pteback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2)) { + return Gate2(new Gate2MethodActionPte(object, method)); +} + +template +Gate2 callback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2)) { + return Gate2(new Gate2MethodAction(object, method)); +} + +template +Gate2 callback(const OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2) const) { + return Gate2(new Gate2MethodAction(object, method)); +} + +template +inline Gate2 callback(bool (*fn)(P1 p1, P2 p2)) { + return Gate2(new Gate2FnAction (fn)); +} + +template +struct Gate2ForkAction : public Gate2Action { + Gate2 cb1, cb2; + + bool Execute(P1 p1, P2 p2) { cb1(p1, p2); return cb2(p1, p2); } + + Gate2ForkAction(Gate2 cb1, Gate2 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Gate2 Proxy(Gate2& cb) +{ + return callback(&cb, &Gate2::Execute); +} + +template +Gate2 callback(Gate2 cb1, Gate2 cb2) +{ + return Gate2(new Gate2ForkAction (cb1, cb2)); +} + +template +Gate2& operator<<(Gate2& a, Gate2 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Gate2& Gate2::operator=(const Gate2& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Gate2::Gate2(const Gate2& c) +{ + action = c.action; + Retain(); +} + +template +Gate2::~Gate2() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Gate3Action { + Atomic count; + + virtual bool Execute(P1 p1, P2 p2, P3 p3) = 0; + virtual bool IsValid() const { return true; } + + Gate3Action() { count = 1; } + virtual ~Gate3Action() {} +}; + +template +struct Gate3MethodActionPte : public Gate3Action { + Ptr object; + METHOD method; + + bool Execute(P1 p1, P2 p2, P3 p3) { return object ? (object->*method)(p1, p2, p3) : false; } + bool IsValid() const { return object; } + + Gate3MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate3MethodAction : public Gate3Action { + OBJECT *object; + METHOD method; + + bool Execute(P1 p1, P2 p2, P3 p3) { return (object->*method)(p1, p2, p3); } + + Gate3MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate3FnAction : public Gate3Action { + bool (*fn)(P1 p1, P2 p2, P3 p3); + + bool Execute(P1 p1, P2 p2, P3 p3) { return (*fn)(p1, p2, p3); } + + Gate3FnAction(bool (*fn)(P1 p1, P2 p2, P3 p3)) : fn(fn) {} +}; + +template +class Gate3 : Moveable< Gate3 > { + Gate3Action *action; + + void Retain() const { if(action && (void *)action != (void *)1) AtomicInc(action->count); } + void Release() { if(action && (void *)action != (void *)1 && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Gate3&); + bool operator!=(const Gate3&); + +public: + typedef Gate3 CLASSNAME; + + Gate3& operator=(const Gate3& c); + Gate3(const Gate3& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return (void *)action != (void *)1 && action && action->IsValid(); } + bool Execute(P1 p1, P2 p2, P3 p3) const; + bool operator()(P1 p1, P2 p2, P3 p3) const { return Execute(p1, p2, p3); } + void ClearTrue() { Clear(); action = (Gate3Action *)1; } + void ClearFalse() { Clear(); } + + Gate3(bool b) { action = (Gate3Action *)(uintptr_t)b; } + + explicit Gate3(Gate3Action *newaction) { action = newaction; } + Gate3() { action = NULL; } + Gate3(_CNULL) { action = NULL; } + ~Gate3(); + + static Gate3 Empty() { return CNULL; } + +}; + +template +Gate3 pteback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3)) { + return Gate3(new Gate3MethodActionPte(object, method)); +} + +template +Gate3 callback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3)) { + return Gate3(new Gate3MethodAction(object, method)); +} + +template +Gate3 callback(const OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3) const) { + return Gate3(new Gate3MethodAction(object, method)); +} + +template +inline Gate3 callback(bool (*fn)(P1 p1, P2 p2, P3 p3)) { + return Gate3(new Gate3FnAction (fn)); +} + +template +struct Gate3ForkAction : public Gate3Action { + Gate3 cb1, cb2; + + bool Execute(P1 p1, P2 p2, P3 p3) { cb1(p1, p2, p3); return cb2(p1, p2, p3); } + + Gate3ForkAction(Gate3 cb1, Gate3 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Gate3 Proxy(Gate3& cb) +{ + return callback(&cb, &Gate3::Execute); +} + +template +Gate3 callback(Gate3 cb1, Gate3 cb2) +{ + return Gate3(new Gate3ForkAction (cb1, cb2)); +} + +template +Gate3& operator<<(Gate3& a, Gate3 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Gate3& Gate3::operator=(const Gate3& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Gate3::Gate3(const Gate3& c) +{ + action = c.action; + Retain(); +} + +template +Gate3::~Gate3() +{ + Release(); +} + +// ----------------------------------------------------------- + +template +struct Gate4Action { + Atomic count; + + virtual bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) = 0; + virtual bool IsValid() const { return true; } + + Gate4Action() { count = 1; } + virtual ~Gate4Action() {} +}; + +template +struct Gate4MethodActionPte : public Gate4Action { + Ptr object; + METHOD method; + + bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) { return object ? (object->*method)(p1, p2, p3, p4) : false; } + bool IsValid() const { return object; } + + Gate4MethodActionPte(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate4MethodAction : public Gate4Action { + OBJECT *object; + METHOD method; + + bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) { return (object->*method)(p1, p2, p3, p4); } + + Gate4MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {} +}; + +template +struct Gate4FnAction : public Gate4Action { + bool (*fn)(P1 p1, P2 p2, P3 p3, P4 p4); + + bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) { return (*fn)(p1, p2, p3, p4); } + + Gate4FnAction(bool (*fn)(P1 p1, P2 p2, P3 p3, P4 p4)) : fn(fn) {} +}; + +template +class Gate4 : Moveable< Gate4 > { + Gate4Action *action; + + void Retain() const { if(action && (void *)action != (void *)1) AtomicInc(action->count); } + void Release() { if(action && (void *)action != (void *)1 && AtomicDec(action->count) == 0) delete action; } + + bool operator==(const Gate4&); + bool operator!=(const Gate4&); + +public: + typedef Gate4 CLASSNAME; + + Gate4& operator=(const Gate4& c); + Gate4(const Gate4& c); + void Clear() { Release(); action = NULL; } + + + operator bool() const { return (void *)action != (void *)1 && action && action->IsValid(); } + bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) const; + bool operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return Execute(p1, p2, p3, p4); } + void ClearTrue() { Clear(); action = (Gate4Action *)1; } + void ClearFalse() { Clear(); } + + Gate4(bool b) { action = (Gate4Action *)(uintptr_t)b; } + + explicit Gate4(Gate4Action *newaction) { action = newaction; } + Gate4() { action = NULL; } + Gate4(_CNULL) { action = NULL; } + ~Gate4(); + + static Gate4 Empty() { return CNULL; } + +}; + +template +Gate4 pteback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Gate4(new Gate4MethodActionPte(object, method)); +} + +template +Gate4 callback(OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Gate4(new Gate4MethodAction(object, method)); +} + +template +Gate4 callback(const OBJECT *object, bool (METHOD::*method)(P1 p1, P2 p2, P3 p3, P4 p4) const) { + return Gate4(new Gate4MethodAction(object, method)); +} + +template +inline Gate4 callback(bool (*fn)(P1 p1, P2 p2, P3 p3, P4 p4)) { + return Gate4(new Gate4FnAction (fn)); +} + +template +struct Gate4ForkAction : public Gate4Action { + Gate4 cb1, cb2; + + bool Execute(P1 p1, P2 p2, P3 p3, P4 p4) { cb1(p1, p2, p3, p4); return cb2(p1, p2, p3, p4); } + + Gate4ForkAction(Gate4 cb1, Gate4 cb2) + : cb1(cb1), cb2(cb2) {} +}; + +template +inline Gate4 Proxy(Gate4& cb) +{ + return callback(&cb, &Gate4::Execute); +} + +template +Gate4 callback(Gate4 cb1, Gate4 cb2) +{ + return Gate4(new Gate4ForkAction (cb1, cb2)); +} + +template +Gate4& operator<<(Gate4& a, Gate4 b) +{ + if(a) + a = callback(a, b); + else + a = b; + return a; +} + +template +Gate4& Gate4::operator=(const Gate4& c) +{ + c.Retain(); + Release(); + action = c.action; + return *this; +} + +template +Gate4::Gate4(const Gate4& c) +{ + action = c.action; + Retain(); +} + +template +Gate4::~Gate4() +{ + Release(); +} + + +#endif diff --git a/uppdev/CoreTopics/CharSet.cpp b/uppdev/CoreTopics/CharSet.cpp new file mode 100644 index 000000000..6795f5136 --- /dev/null +++ b/uppdev/CoreTopics/CharSet.cpp @@ -0,0 +1,1734 @@ +#include + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +#define CUNDEF DEFAULTCHAR + +word CHRTAB_ISO8859_1[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, +}; + +word CHRTAB_ISO8859_2[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9, +}; + +word CHRTAB_ISO8859_3[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, CUNDEF, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, CUNDEF, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, CUNDEF, 0x017C, + 0x00C0, 0x00C1, 0x00C2, CUNDEF, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + CUNDEF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, CUNDEF, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + CUNDEF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9, +}; + +word CHRTAB_ISO8859_4[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9, +}; + +word CHRTAB_ISO8859_5[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F, +}; + +word CHRTAB_ISO8859_6[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, CUNDEF, CUNDEF, CUNDEF, 0x00A4, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, 0x060C, 0x00AD, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, 0x061B, CUNDEF, CUNDEF, CUNDEF, 0x061F, + CUNDEF, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, +}; + +word CHRTAB_ISO8859_7[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, CUNDEF, CUNDEF, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, CUNDEF, 0x00AB, 0x00AC, 0x00AD, CUNDEF, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, CUNDEF, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, CUNDEF, +}; + +word CHRTAB_ISO8859_8[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, CUNDEF, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, CUNDEF, CUNDEF, 0x200E, 0x200F, CUNDEF, +}; + +word CHRTAB_ISO8859_9[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF, +}; + +word CHRTAB_ISO8859_10[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138, +}; + +word CHRTAB_ISO8859_13[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019, +}; + +word CHRTAB_ISO8859_14[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF, +}; + +word CHRTAB_ISO8859_15[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, +}; + +word CHRTAB_ISO8859_16[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B, + 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7, + 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A, + 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, + 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF, +}; + +word CHRTAB_WIN1250[128] = { + 0x20AC, CUNDEF, 0x201A, CUNDEF, 0x201E, 0x2026, 0x2020, 0x2021, + CUNDEF, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + CUNDEF, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9, +}; + +word CHRTAB_WIN1251[128] = { + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + CUNDEF, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, +}; + +word CHRTAB_WIN1252[128] = { + 0x20AC, CUNDEF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, CUNDEF, 0x017D, CUNDEF, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, CUNDEF, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, +}; + +word CHRTAB_WIN1253[128] = { + 0x20AC, CUNDEF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + CUNDEF, 0x2030, CUNDEF, 0x2039, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + CUNDEF, 0x2122, CUNDEF, 0x203A, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, CUNDEF, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, CUNDEF, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, CUNDEF, +}; + +word CHRTAB_WIN1254[128] = { + 0x20AC, CUNDEF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, CUNDEF, CUNDEF, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF, +}; + +word CHRTAB_WIN1255[128] = { + 0x20AC, CUNDEF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, CUNDEF, 0x2039, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, CUNDEF, 0x203A, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, CUNDEF, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, CUNDEF, CUNDEF, 0x200E, 0x200F, CUNDEF, +}; + +word CHRTAB_WIN1256[128] = { + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2, +}; + +word CHRTAB_WIN1257[128] = { + 0x20AC, CUNDEF, 0x201A, CUNDEF, 0x201E, 0x2026, 0x2020, 0x2021, + CUNDEF, 0x2030, CUNDEF, 0x2039, CUNDEF, 0x00A8, 0x02C7, 0x00B8, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + CUNDEF, 0x2122, CUNDEF, 0x203A, CUNDEF, 0x00AF, 0x02DB, CUNDEF, + 0x00A0, CUNDEF, 0x00A2, 0x00A3, 0x00A4, CUNDEF, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9, +}; + +word CHRTAB_WIN1258[128] = { + 0x20AC, CUNDEF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, CUNDEF, 0x2039, 0x0152, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, CUNDEF, 0x203A, 0x0153, CUNDEF, CUNDEF, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF, +}; + +word CHRTAB_KOI8_R[128] = { + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, CUNDEF, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A, +}; + +word CHRTAB_CP850[128] = { + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +word CHRTAB_CP852[128] = { + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, + 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, + 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, + 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, + 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, + 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0, +}; + +word CHRTAB_MJK[128] = { + 0x010c, 0x00fc, 0x00e9, 0x010f, 0x00e4, 0x010e, 0x0164, 0x010d, + 0x011b, 0x011a, 0x0139, 0x00cd, 0x013e, 0x013a, 0x00c4, 0x00c1, + 0x00c9, 0x017e, 0x017d, 0x00f4, 0x00f6, 0x00d3, 0x016f, 0x00da, + 0x00fd, 0x00d6, 0x00dc, 0x0160, 0x013d, 0x00dd, 0x0158, 0x0165, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x0148, 0x0147, 0x016e, 0x00d4, + 0x0161, 0x0159, 0x0155, 0x0154, 0x00ac, 0x00a7, 0x00bb, 0x00ab, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, +}; + +dword uni__info[2048] = { + 0x00000000,0x00400801,0x00801002,0x00c01803,0x01002004,0x01402805,0x01803006,0x01c03807, + 0x02004008,0x02404809,0x0280500a,0x02c0580b,0x0300600c,0x0340680d,0x0380700e,0x03c0780f, + 0x04008010,0x04408811,0x04809012,0x04c09813,0x0500a014,0x0540a815,0x0580b016,0x05c0b817, + 0x0600c018,0x0640c819,0x0680d01a,0x06c0d81b,0x0700e01c,0x0740e81d,0x0780f01e,0x07c0f81f, + 0x08010020,0x08410821,0x08811022,0x08c11823,0x09012024,0x09412825,0x09813026,0x09c13827, + 0x0a014028,0x0a414829,0x0a81502a,0x0ac1582b,0x0b01602c,0x0b41682d,0x0b81702e,0x0bc1782f, + 0x0c018030,0x0c418831,0x0c819032,0x0cc19833,0x0d01a034,0x0d41a835,0x0d81b036,0x0dc1b837, + 0x0e01c038,0x0e41c839,0x0e81d03a,0x0ec1d83b,0x0f01e03c,0x0f41e83d,0x0f81f03e,0x0fc1f83f, + 0x10020040,0x50420861,0x50821062,0x50c21863,0x51022064,0x51422865,0x51823066,0x51c23867, + 0x52024068,0x52424869,0x5282506a,0x52c2586b,0x5302606c,0x5342686d,0x5382706e,0x53c2786f, + 0x54028070,0x54428871,0x54829072,0x54c29873,0x5502a074,0x5542a875,0x5582b076,0x55c2b877, + 0x5602c078,0x5642c879,0x5682d07a,0x16c2d85b,0x1702e05c,0x1742e85d,0x1782f05e,0x17c2f85f, + 0x18030060,0x98420861,0x98821062,0x98c21863,0x99022064,0x99422865,0x99823066,0x99c23867, + 0x9a024068,0x9a424869,0x9a82506a,0x9ac2586b,0x9b02606c,0x9b42686d,0x9b82706e,0x9bc2786f, + 0x9c028070,0x9c428871,0x9c829072,0x9cc29873,0x9d02a074,0x9d42a875,0x9d82b076,0x9dc2b877, + 0x9e02c078,0x9e42c879,0x9e82d07a,0x1ec3d87b,0x1f03e07c,0x1f43e87d,0x1f83f07e,0x1fc3f87f, + 0x00040080,0x00040881,0x00041082,0x00041883,0x00042084,0x00042885,0x00043086,0x00043887, + 0x00044088,0x00044889,0x0004508a,0x0004588b,0x0004608c,0x0004688d,0x0004708e,0x0004788f, + 0x00048090,0x00048891,0x00049092,0x00049893,0x0004a094,0x0004a895,0x0004b096,0x0004b897, + 0x0004c098,0x0004c899,0x0004d09a,0x0004d89b,0x0004e09c,0x0004e89d,0x0004f09e,0x0004f89f, + 0x000500a0,0x000508a1,0x000510a2,0x000518a3,0x000520a4,0x000528a5,0x000530a6,0x000538a7, + 0x000540a8,0x000548a9,0x800550aa,0x000558ab,0x000560ac,0x000568ad,0x000570ae,0x000578af, + 0x000580b0,0x000588b1,0x000590b2,0x000598b3,0x0005a0b4,0x801ce0b5,0x0005b0b6,0x0005b8b7, + 0x0005c0b8,0x0005c8b9,0x8005d0ba,0x0005d8bb,0x0005e0bc,0x0005e8bd,0x0005f0be,0x0005f8bf, + 0x504600e0,0x504608e1,0x504610e2,0x504618e3,0x504620e4,0x504628e5,0x504630e6,0x50c638e7, + 0x514640e8,0x514648e9,0x514650ea,0x514658eb,0x524660ec,0x524668ed,0x524670ee,0x524678ef, + 0x514680f0,0x538688f1,0x53c690f2,0x53c698f3,0x53c6a0f4,0x53c6a8f5,0x53c6b0f6,0x0006b8d7, + 0x53c6c0f8,0x5546c8f9,0x5546d0fa,0x5546d8fb,0x5546e0fc,0x5646e8fd,0x5506f0fe,0x9cc6f8df, + 0x984600e0,0x984608e1,0x984610e2,0x984618e3,0x984620e4,0x984628e5,0x984630e6,0x98c638e7, + 0x994640e8,0x994648e9,0x994650ea,0x994658eb,0x9a4660ec,0x9a4668ed,0x9a4670ee,0x9a4678ef, + 0x994680f0,0x9b8688f1,0x9bc690f2,0x9bc698f3,0x9bc6a0f4,0x9bc6a8f5,0x9bc6b0f6,0x0007b8f7, + 0x9bc6c0f8,0x9d46c8f9,0x9d46d0fa,0x9d46d8fb,0x9d46e0fc,0x9e46e8fd,0x9d06f0fe,0x9e4bc0ff, + 0x50480101,0x98480101,0x50481103,0x98481103,0x50482105,0x98482105,0x50c83107,0x98c83107, + 0x50c84109,0x98c84109,0x50c8510b,0x98c8510b,0x50c8610d,0x98c8610d,0x5108710f,0x9908710f, + 0x51088111,0x99088111,0x51489113,0x99489113,0x5148a115,0x9948a115,0x5148b117,0x9948b117, + 0x5148c119,0x9948c119,0x5148d11b,0x9948d11b,0x51c8e11d,0x99c8e11d,0x51c8f11f,0x99c8f11f, + 0x51c90121,0x99c90121,0x51c91123,0x99c91123,0x52092125,0x9a092125,0x52093127,0x9a093127, + 0x52494129,0x9a494129,0x5249512b,0x9a49512b,0x5249612d,0x9a49612d,0x5249712f,0x9a49712f, + 0x52498069,0x99024931,0x40099133,0x80099133,0x5289a135,0x9a89a135,0x52c9b137,0x9ac9b137, + 0x9ac9c138,0x5309c93a,0x9b09c93a,0x5309d93c,0x9b09d93c,0x5309e93e,0x9b09e93e,0x5309f940, + 0x9b09f940,0x530a0942,0x9b0a0942,0x538a1944,0x9b8a1944,0x538a2946,0x9b8a2946,0x538a3948, + 0x9b8a3948,0x9b8a4949,0x514a514b,0x994a514b,0x53ca614d,0x9bca614d,0x53ca714f,0x9bca714f, + 0x53ca8151,0x9bca8151,0x400a9153,0x800a9153,0x548aa155,0x9c8aa155,0x548ab157,0x9c8ab157, + 0x548ac159,0x9c8ac159,0x54cad15b,0x9ccad15b,0x54cae15d,0x9ccae15d,0x54caf15f,0x9ccaf15f, + 0x54cb0161,0x9ccb0161,0x550b1163,0x9d0b1163,0x550b2165,0x9d0b2165,0x550b3167,0x9d0b3167, + 0x554b4169,0x9d4b4169,0x554b516b,0x9d4b516b,0x554b616d,0x9d4b616d,0x554b716f,0x9d4b716f, + 0x554b8171,0x9d4b8171,0x554b9173,0x9d4b9173,0x55cba175,0x9dcba175,0x564bb177,0x9e4bb177, + 0x564bc0ff,0x568bc97a,0x9e8bc97a,0x568bd97c,0x9e8bd97c,0x568be97e,0x9e8be97e,0x9b02997f, + 0x988c0180,0x508c0a53,0x508c1183,0x988c1183,0x550c2185,0x9d0c2185,0x53cc3254,0x50cc3988, + 0x98cc3988,0x504c4a56,0x510c5257,0x510c598c,0x990c598c,0x9d0c698d,0x548c71dd,0x54cc7a59, + 0x53cc825b,0x518c8992,0x998c8992,0x51cc9a60,0x51cca263,0x9a0fb195,0x524cb269,0x524cba68, + 0x52ccc199,0x9accc199,0x9b0cd19a,0x9b0cd99b,0x550ce26f,0x538cea72,0x9b91019e,0x53ccfa75, + 0x53cd01a1,0x9bcd01a1,0x53cd11a3,0x9bcd11a3,0x540d21a5,0x9c0d21a5,0x400d3280,0x550d39a8, + 0x9d0d39a8,0x514d4a83,0x800d51aa,0x9d0d59ab,0x550d61ad,0x9d0d61ad,0x550d7288,0x554d79b0, + 0x9d4d79b0,0x554d8a8a,0x558d928b,0x564d99b4,0x9e4d99b4,0x568da9b6,0x9e8da9b6,0x514dba92, + 0x514dc1b9,0x994dc1b9,0x994dd1ba,0x000dd9bb,0x550de1bd,0x9d0de1bd,0x800df1be,0x800fb9bf, + 0x000e01c0,0x000e09c1,0x000e11c2,0x000e19c3,0x510e21c6,0x110e29c5,0x990e21c6,0x530e39c9, + 0x130e41c8,0x9b0e39c9,0x538e51cc,0x138e59cb,0x9b8e51cc,0x504e69ce,0x984e69ce,0x524e79d0, + 0x9a4e79d0,0x53ce89d2,0x9bce89d2,0x554e99d4,0x9d4e99d4,0x554ea9d6,0x9d4ea9d6,0x554eb9d8, + 0x9d4eb9d8,0x554ec9da,0x9d4ec9da,0x554ed9dc,0x9d4ed9dc,0x9d0c71dd,0x504ef1df,0x984ef1df, + 0x504f01e1,0x984f01e1,0x504f11e3,0x984f11e3,0x51cf21e5,0x99cf21e5,0x51cf31e7,0x99cf31e7, + 0x52cf41e9,0x9acf41e9,0x53cf51eb,0x9bcf51eb,0x53cf61ed,0x9bcf61ed,0x514f71ef,0x994f71ef, + 0x9a8f81f0,0x510f89f3,0x110f91f2,0x990f89f3,0x51cfa1f5,0x99cfa1f5,0x520fb195,0x55cfb9bf, + 0x538fc1f9,0x9b8fc1f9,0x504fd1fb,0x984fd1fb,0x504fe1fd,0x984fe1fd,0x53cff1ff,0x9bcff1ff, + 0x50500201,0x98500201,0x50501203,0x98501203,0x51502205,0x99502205,0x51503207,0x99503207, + 0x52504209,0x9a504209,0x5250520b,0x9a50520b,0x53d0620d,0x9bd0620d,0x53d0720f,0x9bd0720f, + 0x54908211,0x9c908211,0x54909213,0x9c909213,0x5550a215,0x9d50a215,0x5550b217,0x9d50b217, + 0x54d0c219,0x9cd0c219,0x5510d21b,0x9d10d21b,0x5650e21d,0x9e50e21d,0x5210f21f,0x9a10f21f, + 0x5391019e,0x00110a21,0x53d11223,0x9bd11223,0x56912225,0x9e912225,0x50513227,0x98513227, + 0x51514229,0x99514229,0x53d1522b,0x9bd1522b,0x53d1622d,0x9bd1622d,0x53d1722f,0x9bd1722f, + 0x53d18231,0x9bd18231,0x56519233,0x9e519233,0x0011a234,0x0011aa35,0x0011b236,0x0011ba37, + 0x0011c238,0x0011ca39,0x0011d23a,0x0011da3b,0x0011e23c,0x0011ea3d,0x0011f23e,0x0011fa3f, + 0x00120240,0x00120a41,0x00121242,0x00121a43,0x00122244,0x00122a45,0x00123246,0x00123a47, + 0x00124248,0x00124a49,0x0012524a,0x00125a4b,0x0012624c,0x00126a4d,0x0012724e,0x00127a4f, + 0x9d128250,0x98528a51,0x9d129252,0x988c0a53,0x9bcc3254,0x98d2aa55,0x990c4a56,0x990c5257, + 0x9c92c258,0x9ccc7a59,0x9cd2d25a,0x9bcc825b,0x9c92e25c,0x9c92ea5d,0x98d2f25e,0x9912fa5f, + 0x99cc9a60,0x9cd30a61,0x80131262,0x99cca263,0x9c932264,0x9d132a65,0x9a133266,0x9a133a67, + 0x9a4cba68,0x9a4cb269,0x8013526a,0x9b135a6b,0x9b13626c,0x9b136a6d,0x9b13726e,0x9d0ce26f, + 0x9d138270,0x9b538a71,0x9b8cea72,0x9b939a73,0x8013a274,0x988cfa75,0x8013b276,0x98d3ba77, + 0x9c13c278,0x9d13ca79,0x9d13d27a,0x9d13da7b,0x9c93e27c,0x9c93ea7d,0x9c93f27e,0x9c93fa7f, + 0x800d3280,0x80140a81,0x9cd41282,0x994d4a83,0x99142284,0x9cd42a85,0x99543286,0x9d143a87, + 0x9d0d7288,0x9d544a89,0x9d4d8a8a,0x9d8d928b,0x9d14628c,0x9d146a8d,0x9d14728e,0x80147a8f, + 0x9e948290,0x9e948a91,0x994dba92,0x99549a93,0x8014a294,0x8014aa95,0x8014b296,0x8014ba97, + 0x8014c298,0x8014ca99,0x98d4d29a,0x8014da9b,0x8014e29c,0x9a94ea9d,0x9d14f29e,0x8014fa9f, + 0x9c5502a0,0x80150aa1,0x801512a2,0x99151aa3,0x991522a4,0x99152aa5,0x9d1532a6,0x9d153aa7, + 0x9d1542a8,0x99954aa9,0x9b1552aa,0x9b155aab,0x801562ac,0x80156aad,0x001572ae,0x00157aaf, + 0x001582b0,0x00158ab1,0x001592b2,0x00159ab3,0x0015a2b4,0x0015aab5,0x0015b2b6,0x0015bab7, + 0x0015c2b8,0x0015cab9,0x0015d2ba,0x0015dabb,0x0015e2bc,0x0015eabd,0x0015f2be,0x0015fabf, + 0x001602c0,0x00160ac1,0x001612c2,0x00161ac3,0x001622c4,0x00162ac5,0x001632c6,0x00163ac7, + 0x001642c8,0x00164ac9,0x001652ca,0x00165acb,0x001662cc,0x00166acd,0x001672ce,0x00167acf, + 0x001682d0,0x00168ad1,0x001692d2,0x00169ad3,0x0016a2d4,0x0016aad5,0x0016b2d6,0x0016bad7, + 0x0016c2d8,0x0016cad9,0x0016d2da,0x0016dadb,0x0016e2dc,0x0016eadd,0x0016f2de,0x0016fadf, + 0x001702e0,0x00170ae1,0x001712e2,0x00171ae3,0x001722e4,0x00172ae5,0x001732e6,0x00173ae7, + 0x001742e8,0x00174ae9,0x001752ea,0x00175aeb,0x001762ec,0x00176aed,0x001772ee,0x00177aef, + 0x001782f0,0x00178af1,0x001792f2,0x00179af3,0x0017a2f4,0x0017aaf5,0x0017b2f6,0x0017baf7, + 0x0017c2f8,0x0017caf9,0x0017d2fa,0x0017dafb,0x0017e2fc,0x0017eafd,0x0017f2fe,0x0017faff, + 0x00180300,0x00180b01,0x00181302,0x00181b03,0x00182304,0x00182b05,0x00183306,0x00183b07, + 0x00184308,0x00184b09,0x0018530a,0x00185b0b,0x0018630c,0x00186b0d,0x0018730e,0x00187b0f, + 0x00188310,0x00188b11,0x00189312,0x00189b13,0x0018a314,0x0018ab15,0x0018b316,0x0018bb17, + 0x0018c318,0x0018cb19,0x0018d31a,0x0018db1b,0x0018e31c,0x0018eb1d,0x0018f31e,0x0018fb1f, + 0x00190320,0x00190b21,0x00191322,0x00191b23,0x00192324,0x00192b25,0x00193326,0x00193b27, + 0x00194328,0x00194b29,0x0019532a,0x00195b2b,0x0019632c,0x00196b2d,0x0019732e,0x00197b2f, + 0x00198330,0x00198b31,0x00199332,0x00199b33,0x0019a334,0x0019ab35,0x0019b336,0x0019bb37, + 0x0019c338,0x0019cb39,0x0019d33a,0x0019db3b,0x0019e33c,0x0019eb3d,0x0019f33e,0x0019fb3f, + 0x001a0340,0x001a0b41,0x001a1342,0x001a1b43,0x001a2344,0x001a2b45,0x001a3346,0x001a3b47, + 0x001a4348,0x001a4b49,0x001a534a,0x001a5b4b,0x001a634c,0x001a6b4d,0x001a734e,0x001a7b4f, + 0x001a8350,0x001a8b51,0x001a9352,0x001a9b53,0x001aa354,0x001aab55,0x001ab356,0x001abb57, + 0x001ac358,0x001acb59,0x001ad35a,0x001adb5b,0x001ae35c,0x001aeb5d,0x001af35e,0x001afb5f, + 0x001b0360,0x001b0b61,0x001b1362,0x001b1b63,0x001b2364,0x001b2b65,0x001b3366,0x001b3b67, + 0x001b4368,0x001b4b69,0x001b536a,0x001b5b6b,0x001b636c,0x001b6b6d,0x001b736e,0x001b7b6f, + 0x001b8370,0x001b8b71,0x001b9372,0x001b9b73,0x001ba374,0x001bab75,0x001bb376,0x001bbb77, + 0x001bc378,0x001bcb79,0x001bd37a,0x001bdb7b,0x001be37c,0x001beb7d,0x001bf37e,0x001bfb7f, + 0x001c0380,0x001c0b81,0x001c1382,0x001c1b83,0x001c2384,0x001c2b85,0x401c33ac,0x001c3b87, + 0x401c43ad,0x401c4bae,0x401c53af,0x001c5b8b,0x401c63cc,0x001c6b8d,0x401c73cd,0x401c7bce, + 0x801c8390,0x401c8bb1,0x401c93b2,0x401c9bb3,0x401ca3b4,0x401cabb5,0x401cb3b6,0x401cbbb7, + 0x401cc3b8,0x401ccbb9,0x401cd3ba,0x401cdbbb,0x401ce3bc,0x401cebbd,0x401cf3be,0x401cfbbf, + 0x401d03c0,0x401d0bc1,0x001d13a2,0x401d1bc3,0x401d23c4,0x401d2bc5,0x401d33c6,0x401d3bc7, + 0x401d43c8,0x401d4bc9,0x401d53ca,0x401d5bcb,0x801c33ac,0x801c43ad,0x801c4bae,0x801c53af, + 0x801d83b0,0x801c8bb1,0x801c93b2,0x801c9bb3,0x801ca3b4,0x801cabb5,0x801cb3b6,0x801cbbb7, + 0x801cc3b8,0x801ccbb9,0x801cd3ba,0x801cdbbb,0x801ce3bc,0x801cebbd,0x801cf3be,0x801cfbbf, + 0x801d03c0,0x801d0bc1,0x801d1bc2,0x801d1bc3,0x801d23c4,0x801d2bc5,0x801d33c6,0x801d3bc7, + 0x801d43c8,0x801d4bc9,0x801d53ca,0x801d5bcb,0x801c63cc,0x801c73cd,0x801c7bce,0x001e7bcf, + 0x801c93d0,0x801cc3d1,0x401e93d2,0x401e9bd3,0x401ea3d4,0x801d33d5,0x801d03d6,0x801ebbd7, + 0x401ec3d9,0x801ec3d9,0x401ed3db,0x801ed3db,0x401ee3dd,0x801ee3dd,0x401ef3df,0x801ef3df, + 0x401f03e1,0x801f03e1,0x401f13e3,0x801f13e3,0x401f23e5,0x801f23e5,0x401f33e7,0x801f33e7, + 0x401f43e9,0x801f43e9,0x401f53eb,0x801f53eb,0x401f63ed,0x801f63ed,0x401f73ef,0x801f73ef, + 0x801cd3f0,0x801d0bf1,0x801d1bf2,0x801f9bf3,0x401fa3b8,0x801cabf5,0x001fb3f6,0x001fbbf7, + 0x001fc3f8,0x001fcbf9,0x001fd3fa,0x001fdbfb,0x001fe3fc,0x001febfd,0x001ff3fe,0x001ffbff, + 0x40200450,0x40200c51,0x40201452,0x40201c53,0x40202454,0x40202c55,0x40203456,0x40203c57, + 0x40204458,0x40204c59,0x4020545a,0x40205c5b,0x4020645c,0x40206c5d,0x4020745e,0x40207c5f, + 0x40208430,0x40208c31,0x40209432,0x40209c33,0x4020a434,0x4020ac35,0x4020b436,0x4020bc37, + 0x4020c438,0x4020cc39,0x4020d43a,0x4020dc3b,0x4020e43c,0x4020ec3d,0x4020f43e,0x4020fc3f, + 0x40210440,0x40210c41,0x40211442,0x40211c43,0x40212444,0x40212c45,0x40213446,0x40213c47, + 0x40214448,0x40214c49,0x4021544a,0x40215c4b,0x4021644c,0x40216c4d,0x4021744e,0x40217c4f, + 0x80208430,0x80208c31,0x80209432,0x80209c33,0x8020a434,0x8020ac35,0x8020b436,0x8020bc37, + 0x8020c438,0x8020cc39,0x8020d43a,0x8020dc3b,0x8020e43c,0x8020ec3d,0x8020f43e,0x8020fc3f, + 0x80210440,0x80210c41,0x80211442,0x80211c43,0x80212444,0x80212c45,0x80213446,0x80213c47, + 0x80214448,0x80214c49,0x8021544a,0x80215c4b,0x8021644c,0x80216c4d,0x8021744e,0x80217c4f, + 0x80200450,0x80200c51,0x80201452,0x80201c53,0x80202454,0x80202c55,0x80203456,0x80203c57, + 0x80204458,0x80204c59,0x8020545a,0x80205c5b,0x8020645c,0x80206c5d,0x8020745e,0x80207c5f, + 0x40230461,0x80230461,0x40231463,0x80231463,0x40232465,0x80232465,0x40233467,0x80233467, + 0x40234469,0x80234469,0x4023546b,0x8023546b,0x4023646d,0x8023646d,0x4023746f,0x8023746f, + 0x40238471,0x80238471,0x40239473,0x80239473,0x4023a475,0x8023a475,0x4023b477,0x8023b477, + 0x4023c479,0x8023c479,0x4023d47b,0x8023d47b,0x4023e47d,0x8023e47d,0x4023f47f,0x8023f47f, + 0x40240481,0x80240481,0x00241482,0x00241c83,0x00242484,0x00242c85,0x00243486,0x00243c87, + 0x00244488,0x00244c89,0x4024548b,0x8024548b,0x4024648d,0x8024648d,0x4024748f,0x8024748f, + 0x40248491,0x80248491,0x40249493,0x80249493,0x4024a495,0x8024a495,0x4024b497,0x8024b497, + 0x4024c499,0x8024c499,0x4024d49b,0x8024d49b,0x4024e49d,0x8024e49d,0x4024f49f,0x8024f49f, + 0x402504a1,0x802504a1,0x402514a3,0x802514a3,0x402524a5,0x802524a5,0x402534a7,0x802534a7, + 0x402544a9,0x802544a9,0x402554ab,0x802554ab,0x402564ad,0x802564ad,0x402574af,0x802574af, + 0x402584b1,0x802584b1,0x402594b3,0x802594b3,0x4025a4b5,0x8025a4b5,0x4025b4b7,0x8025b4b7, + 0x4025c4b9,0x8025c4b9,0x4025d4bb,0x8025d4bb,0x4025e4bd,0x8025e4bd,0x4025f4bf,0x8025f4bf, + 0x402604c0,0x40260cc2,0x80260cc2,0x40261cc4,0x80261cc4,0x40262cc6,0x80262cc6,0x40263cc8, + 0x80263cc8,0x40264cca,0x80264cca,0x40265ccc,0x80265ccc,0x40266cce,0x80266cce,0x00267ccf, + 0x402684d1,0x802684d1,0x402694d3,0x802694d3,0x4026a4d5,0x8026a4d5,0x4026b4d7,0x8026b4d7, + 0x4026c4d9,0x8026c4d9,0x4026d4db,0x8026d4db,0x4026e4dd,0x8026e4dd,0x4026f4df,0x8026f4df, + 0x402704e1,0x802704e1,0x402714e3,0x802714e3,0x402724e5,0x802724e5,0x402734e7,0x802734e7, + 0x402744e9,0x802744e9,0x402754eb,0x802754eb,0x402764ed,0x802764ed,0x402774ef,0x802774ef, + 0x402784f1,0x802784f1,0x402794f3,0x802794f3,0x4027a4f5,0x8027a4f5,0x0027b4f6,0x0027bcf7, + 0x4027c4f9,0x8027c4f9,0x0027d4fa,0x0027dcfb,0x0027e4fc,0x0027ecfd,0x0027f4fe,0x0027fcff, + 0x40280501,0x80280501,0x40281503,0x80281503,0x40282505,0x80282505,0x40283507,0x80283507, + 0x40284509,0x80284509,0x4028550b,0x8028550b,0x4028650d,0x8028650d,0x4028750f,0x8028750f, + 0x00288510,0x00288d11,0x00289512,0x00289d13,0x0028a514,0x0028ad15,0x0028b516,0x0028bd17, + 0x0028c518,0x0028cd19,0x0028d51a,0x0028dd1b,0x0028e51c,0x0028ed1d,0x0028f51e,0x0028fd1f, + 0x00290520,0x00290d21,0x00291522,0x00291d23,0x00292524,0x00292d25,0x00293526,0x00293d27, + 0x00294528,0x00294d29,0x0029552a,0x00295d2b,0x0029652c,0x00296d2d,0x0029752e,0x00297d2f, + 0x00298530,0x40298d61,0x40299562,0x40299d63,0x4029a564,0x4029ad65,0x4029b566,0x4029bd67, + 0x4029c568,0x4029cd69,0x4029d56a,0x4029dd6b,0x4029e56c,0x4029ed6d,0x4029f56e,0x4029fd6f, + 0x402a0570,0x402a0d71,0x402a1572,0x402a1d73,0x402a2574,0x402a2d75,0x402a3576,0x402a3d77, + 0x402a4578,0x402a4d79,0x402a557a,0x402a5d7b,0x402a657c,0x402a6d7d,0x402a757e,0x402a7d7f, + 0x402a8580,0x402a8d81,0x402a9582,0x402a9d83,0x402aa584,0x402aad85,0x402ab586,0x002abd57, + 0x002ac558,0x002acd59,0x002ad55a,0x002add5b,0x002ae55c,0x002aed5d,0x002af55e,0x002afd5f, + 0x002b0560,0x80298d61,0x80299562,0x80299d63,0x8029a564,0x8029ad65,0x8029b566,0x8029bd67, + 0x8029c568,0x8029cd69,0x8029d56a,0x8029dd6b,0x8029e56c,0x8029ed6d,0x8029f56e,0x8029fd6f, + 0x802a0570,0x802a0d71,0x802a1572,0x802a1d73,0x802a2574,0x802a2d75,0x802a3576,0x802a3d77, + 0x802a4578,0x802a4d79,0x802a557a,0x802a5d7b,0x802a657c,0x802a6d7d,0x802a757e,0x802a7d7f, + 0x802a8580,0x802a8d81,0x802a9582,0x802a9d83,0x802aa584,0x802aad85,0x802ab586,0x802c3d87, + 0x002c4588,0x002c4d89,0x002c558a,0x002c5d8b,0x002c658c,0x002c6d8d,0x002c758e,0x002c7d8f, + 0x002c8590,0x002c8d91,0x002c9592,0x002c9d93,0x002ca594,0x002cad95,0x002cb596,0x002cbd97, + 0x002cc598,0x002ccd99,0x002cd59a,0x002cdd9b,0x002ce59c,0x002ced9d,0x002cf59e,0x002cfd9f, + 0x002d05a0,0x002d0da1,0x002d15a2,0x002d1da3,0x002d25a4,0x002d2da5,0x002d35a6,0x002d3da7, + 0x002d45a8,0x002d4da9,0x002d55aa,0x002d5dab,0x002d65ac,0x002d6dad,0x002d75ae,0x002d7daf, + 0x002d85b0,0x002d8db1,0x002d95b2,0x002d9db3,0x002da5b4,0x002dadb5,0x002db5b6,0x002dbdb7, + 0x002dc5b8,0x002dcdb9,0x002dd5ba,0x002dddbb,0x002de5bc,0x002dedbd,0x002df5be,0x002dfdbf, + 0x002e05c0,0x002e0dc1,0x002e15c2,0x002e1dc3,0x002e25c4,0x002e2dc5,0x002e35c6,0x002e3dc7, + 0x002e45c8,0x002e4dc9,0x002e55ca,0x002e5dcb,0x002e65cc,0x002e6dcd,0x002e75ce,0x002e7dcf, + 0x002e85d0,0x002e8dd1,0x002e95d2,0x002e9dd3,0x002ea5d4,0x002eadd5,0x002eb5d6,0x002ebdd7, + 0x002ec5d8,0x002ecdd9,0x002ed5da,0x002edddb,0x002ee5dc,0x002eeddd,0x002ef5de,0x002efddf, + 0x002f05e0,0x002f0de1,0x002f15e2,0x002f1de3,0x002f25e4,0x002f2de5,0x002f35e6,0x002f3de7, + 0x002f45e8,0x002f4de9,0x002f55ea,0x002f5deb,0x002f65ec,0x002f6ded,0x002f75ee,0x002f7def, + 0x002f85f0,0x002f8df1,0x002f95f2,0x002f9df3,0x002fa5f4,0x002fadf5,0x002fb5f6,0x002fbdf7, + 0x002fc5f8,0x002fcdf9,0x002fd5fa,0x002fddfb,0x002fe5fc,0x002fedfd,0x002ff5fe,0x002ffdff, + 0x00300600,0x00300e01,0x00301602,0x00301e03,0x00302604,0x00302e05,0x00303606,0x00303e07, + 0x00304608,0x00304e09,0x0030560a,0x00305e0b,0x0030660c,0x00306e0d,0x0030760e,0x00307e0f, + 0x00308610,0x00308e11,0x00309612,0x00309e13,0x0030a614,0x0030ae15,0x0030b616,0x0030be17, + 0x0030c618,0x0030ce19,0x0030d61a,0x0030de1b,0x0030e61c,0x0030ee1d,0x0030f61e,0x0030fe1f, + 0x00310620,0x00310e21,0x00311622,0x00311e23,0x00312624,0x00312e25,0x00313626,0x00313e27, + 0x00314628,0x00314e29,0x0031562a,0x00315e2b,0x0031662c,0x00316e2d,0x0031762e,0x00317e2f, + 0x00318630,0x00318e31,0x00319632,0x00319e33,0x0031a634,0x0031ae35,0x0031b636,0x0031be37, + 0x0031c638,0x0031ce39,0x0031d63a,0x0031de3b,0x0031e63c,0x0031ee3d,0x0031f63e,0x0031fe3f, + 0x00320640,0x00320e41,0x00321642,0x00321e43,0x00322644,0x00322e45,0x00323646,0x00323e47, + 0x00324648,0x00324e49,0x0032564a,0x00325e4b,0x0032664c,0x00326e4d,0x0032764e,0x00327e4f, + 0x00328650,0x00328e51,0x00329652,0x00329e53,0x0032a654,0x0032ae55,0x0032b656,0x0032be57, + 0x0032c658,0x0032ce59,0x0032d65a,0x0032de5b,0x0032e65c,0x0032ee5d,0x0032f65e,0x0032fe5f, + 0x00330660,0x00330e61,0x00331662,0x00331e63,0x00332664,0x00332e65,0x00333666,0x00333e67, + 0x00334668,0x00334e69,0x0033566a,0x00335e6b,0x0033666c,0x00336e6d,0x0033766e,0x00337e6f, + 0x00338670,0x00338e71,0x00339672,0x00339e73,0x0033a674,0x0033ae75,0x0033b676,0x0033be77, + 0x0033c678,0x0033ce79,0x0033d67a,0x0033de7b,0x0033e67c,0x0033ee7d,0x0033f67e,0x0033fe7f, + 0x00340680,0x00340e81,0x00341682,0x00341e83,0x00342684,0x00342e85,0x00343686,0x00343e87, + 0x00344688,0x00344e89,0x0034568a,0x00345e8b,0x0034668c,0x00346e8d,0x0034768e,0x00347e8f, + 0x00348690,0x00348e91,0x00349692,0x00349e93,0x0034a694,0x0034ae95,0x0034b696,0x0034be97, + 0x0034c698,0x0034ce99,0x0034d69a,0x0034de9b,0x0034e69c,0x0034ee9d,0x0034f69e,0x0034fe9f, + 0x003506a0,0x00350ea1,0x003516a2,0x00351ea3,0x003526a4,0x00352ea5,0x003536a6,0x00353ea7, + 0x003546a8,0x00354ea9,0x003556aa,0x00355eab,0x003566ac,0x00356ead,0x003576ae,0x00357eaf, + 0x003586b0,0x00358eb1,0x003596b2,0x00359eb3,0x0035a6b4,0x0035aeb5,0x0035b6b6,0x0035beb7, + 0x0035c6b8,0x0035ceb9,0x0035d6ba,0x0035debb,0x0035e6bc,0x0035eebd,0x0035f6be,0x0035febf, + 0x003606c0,0x00360ec1,0x003616c2,0x00361ec3,0x003626c4,0x00362ec5,0x003636c6,0x00363ec7, + 0x003646c8,0x00364ec9,0x003656ca,0x00365ecb,0x003666cc,0x00366ecd,0x003676ce,0x00367ecf, + 0x003686d0,0x00368ed1,0x003696d2,0x00369ed3,0x0036a6d4,0x0036aed5,0x0036b6d6,0x0036bed7, + 0x0036c6d8,0x0036ced9,0x0036d6da,0x0036dedb,0x0036e6dc,0x0036eedd,0x0036f6de,0x0036fedf, + 0x003706e0,0x00370ee1,0x003716e2,0x00371ee3,0x003726e4,0x00372ee5,0x003736e6,0x00373ee7, + 0x003746e8,0x00374ee9,0x003756ea,0x00375eeb,0x003766ec,0x00376eed,0x003776ee,0x00377eef, + 0x003786f0,0x00378ef1,0x003796f2,0x00379ef3,0x0037a6f4,0x0037aef5,0x0037b6f6,0x0037bef7, + 0x0037c6f8,0x0037cef9,0x0037d6fa,0x0037defb,0x0037e6fc,0x0037eefd,0x0037f6fe,0x0037feff, + 0x00380700,0x00380f01,0x00381702,0x00381f03,0x00382704,0x00382f05,0x00383706,0x00383f07, + 0x00384708,0x00384f09,0x0038570a,0x00385f0b,0x0038670c,0x00386f0d,0x0038770e,0x00387f0f, + 0x00388710,0x00388f11,0x00389712,0x00389f13,0x0038a714,0x0038af15,0x0038b716,0x0038bf17, + 0x0038c718,0x0038cf19,0x0038d71a,0x0038df1b,0x0038e71c,0x0038ef1d,0x0038f71e,0x0038ff1f, + 0x00390720,0x00390f21,0x00391722,0x00391f23,0x00392724,0x00392f25,0x00393726,0x00393f27, + 0x00394728,0x00394f29,0x0039572a,0x00395f2b,0x0039672c,0x00396f2d,0x0039772e,0x00397f2f, + 0x00398730,0x00398f31,0x00399732,0x00399f33,0x0039a734,0x0039af35,0x0039b736,0x0039bf37, + 0x0039c738,0x0039cf39,0x0039d73a,0x0039df3b,0x0039e73c,0x0039ef3d,0x0039f73e,0x0039ff3f, + 0x003a0740,0x003a0f41,0x003a1742,0x003a1f43,0x003a2744,0x003a2f45,0x003a3746,0x003a3f47, + 0x003a4748,0x003a4f49,0x003a574a,0x003a5f4b,0x003a674c,0x003a6f4d,0x003a774e,0x003a7f4f, + 0x003a8750,0x003a8f51,0x003a9752,0x003a9f53,0x003aa754,0x003aaf55,0x003ab756,0x003abf57, + 0x003ac758,0x003acf59,0x003ad75a,0x003adf5b,0x003ae75c,0x003aef5d,0x003af75e,0x003aff5f, + 0x003b0760,0x003b0f61,0x003b1762,0x003b1f63,0x003b2764,0x003b2f65,0x003b3766,0x003b3f67, + 0x003b4768,0x003b4f69,0x003b576a,0x003b5f6b,0x003b676c,0x003b6f6d,0x003b776e,0x003b7f6f, + 0x003b8770,0x003b8f71,0x003b9772,0x003b9f73,0x003ba774,0x003baf75,0x003bb776,0x003bbf77, + 0x003bc778,0x003bcf79,0x003bd77a,0x003bdf7b,0x003be77c,0x003bef7d,0x003bf77e,0x003bff7f, + 0x003c0780,0x003c0f81,0x003c1782,0x003c1f83,0x003c2784,0x003c2f85,0x003c3786,0x003c3f87, + 0x003c4788,0x003c4f89,0x003c578a,0x003c5f8b,0x003c678c,0x003c6f8d,0x003c778e,0x003c7f8f, + 0x003c8790,0x003c8f91,0x003c9792,0x003c9f93,0x003ca794,0x003caf95,0x003cb796,0x003cbf97, + 0x003cc798,0x003ccf99,0x003cd79a,0x003cdf9b,0x003ce79c,0x003cef9d,0x003cf79e,0x003cff9f, + 0x003d07a0,0x003d0fa1,0x003d17a2,0x003d1fa3,0x003d27a4,0x003d2fa5,0x003d37a6,0x003d3fa7, + 0x003d47a8,0x003d4fa9,0x003d57aa,0x003d5fab,0x003d67ac,0x003d6fad,0x003d77ae,0x003d7faf, + 0x003d87b0,0x003d8fb1,0x003d97b2,0x003d9fb3,0x003da7b4,0x003dafb5,0x003db7b6,0x003dbfb7, + 0x003dc7b8,0x003dcfb9,0x003dd7ba,0x003ddfbb,0x003de7bc,0x003defbd,0x003df7be,0x003dffbf, + 0x003e07c0,0x003e0fc1,0x003e17c2,0x003e1fc3,0x003e27c4,0x003e2fc5,0x003e37c6,0x003e3fc7, + 0x003e47c8,0x003e4fc9,0x003e57ca,0x003e5fcb,0x003e67cc,0x003e6fcd,0x003e77ce,0x003e7fcf, + 0x003e87d0,0x003e8fd1,0x003e97d2,0x003e9fd3,0x003ea7d4,0x003eafd5,0x003eb7d6,0x003ebfd7, + 0x003ec7d8,0x003ecfd9,0x003ed7da,0x003edfdb,0x003ee7dc,0x003eefdd,0x003ef7de,0x003effdf, + 0x003f07e0,0x003f0fe1,0x003f17e2,0x003f1fe3,0x003f27e4,0x003f2fe5,0x003f37e6,0x003f3fe7, + 0x003f47e8,0x003f4fe9,0x003f57ea,0x003f5feb,0x003f67ec,0x003f6fed,0x003f77ee,0x003f7fef, + 0x003f87f0,0x003f8ff1,0x003f97f2,0x003f9ff3,0x003fa7f4,0x003faff5,0x003fb7f6,0x003fbff7, + 0x003fc7f8,0x003fcff9,0x003fd7fa,0x003fdffb,0x003fe7fc,0x003feffd,0x003ff7fe,0x003fffff, +}; + +byte DefaultCharset = 255; + +void SetDefaultCharset(byte charset) +{ + DefaultCharset = charset; +} + +byte GetDefaultCharset() +{ + return DefaultCharset; +} + +struct CharSetData { + const word *table; + static byte undef[128]; + byte *line[16]; + VectorMap map; + byte system; + + void Gen(); + + int ToUnicode(int chr) { return (byte)chr < 128 ? (byte)chr : table[(byte)chr - 128]; } + int FromUnicode(int chr, int def = DEFAULTCHAR); + void FromUnicode(char *t, const wchar *s, const wchar *end, int def = DEFAULTCHAR); + + CharSetData(); + ~CharSetData(); +}; + +byte CharSetData::undef[] = { + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, + CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, CUNDEF, +}; + +void CharSetData::Gen() +{ + int c; + line[0] = new byte[128]; + for(c = 0; c < 128; c++) + line[0][c] = c; + for(c = 0; c < 128; c++) { + int q = table[c]; + if(q < 16 * 128) { + int i = q >> 7; + if(!line[i]) { + line[i] = new byte[128]; + memset(line[i], CUNDEF, 128); + } + line[i][q & 0x7f] = c + 128; + } + else + if((q & 0xFF00) != 0xEE00) + map.Add(q, c + 128); + } + for(c = 0; c < 16; c++) + if(!line[c]) + line[c] = undef; +} + +inline int CharSetData::FromUnicode(int chr, int def) +{ + if(!line[0]) Gen(); + int c = chr < 16 * 128 ? line[chr >> 7][chr & 0x7f] + : (chr & 0xFF00) == 0xEE00 ? (chr & 255) + : map.Get(chr, CUNDEF); + return c == DEFAULTCHAR ? def : c; +} + +inline void CharSetData::FromUnicode(char *t, const wchar *s, const wchar *end, int def) +{ + if(!line[0]) Gen(); + if(def == DEFAULTCHAR) + while(s < end) { + int chr = *s++; + *t++ = chr < 16 * 128 ? line[chr >> 7][chr & 0x7f] + : (chr & 0xFF00) == 0xEE00 ? (chr & 255) + : map.Get(chr, CUNDEF); + } + else + while(s < end) { + int chr = *s++; + int c = chr < 16 * 128 ? line[chr >> 7][chr & 0x7f] + : (chr & 0xFF00) == 0xEE00 ? (chr & 255) + : map.Get(chr, CUNDEF); + *t++ = c == DEFAULTCHAR ? def : c; + } +} + +CharSetData::CharSetData() +{ + for(int i = 0; i < 16; i++) + line[i] = 0; +} + +CharSetData::~CharSetData() +{ + for(int i = 0; i < 16; i++) + if(line[i] && line[i] != undef) + delete[] line[i]; +} + +static void sInit() +{ +#ifdef PLATFORM_WIN32 + AddCharSetE("NONE" , CHRTAB_ISO8859_1, CHARSET_WIN1252); + AddCharSetE("iso8859-1", CHRTAB_ISO8859_1, CHARSET_WIN1252); + AddCharSetE("iso8859-2", CHRTAB_ISO8859_2, CHARSET_WIN1250); //?? + AddCharSetE("iso8859-3", CHRTAB_ISO8859_3, CHARSET_WIN1254); //?? + AddCharSetE("iso8859-4", CHRTAB_ISO8859_4, CHARSET_WIN1257); //?? + AddCharSetE("iso8859-5", CHRTAB_ISO8859_5, CHARSET_WIN1251); + AddCharSetE("iso8859-6", CHRTAB_ISO8859_6, CHARSET_WIN1256); + AddCharSetE("iso8859-7", CHRTAB_ISO8859_7, CHARSET_WIN1253); + AddCharSetE("iso8859-8", CHRTAB_ISO8859_8, CHARSET_WIN1255); //?? + AddCharSetE("iso8859-9", CHRTAB_ISO8859_9, CHARSET_WIN1254); + AddCharSetE("iso8859-10", CHRTAB_ISO8859_10, CHARSET_WIN1257); //?? + AddCharSetE("iso8859-13", CHRTAB_ISO8859_13, CHARSET_WIN1257); + AddCharSetE("iso8859-14", CHRTAB_ISO8859_14, CHARSET_WIN1252); //?? + AddCharSetE("iso8859-15", CHRTAB_ISO8859_15, CHARSET_WIN1252); //?? + AddCharSetE("iso8859-16", CHRTAB_ISO8859_16, CHARSET_WIN1250); //?? + AddCharSetE("windows-1250",CHRTAB_WIN1250, CHARSET_WIN1250); + AddCharSetE("windows-1251",CHRTAB_WIN1251, CHARSET_WIN1251); + AddCharSetE("windows-1252",CHRTAB_WIN1252, CHARSET_WIN1252); + AddCharSetE("windows-1253",CHRTAB_WIN1253, CHARSET_WIN1253); + AddCharSetE("windows-1254",CHRTAB_WIN1254, CHARSET_WIN1254); + AddCharSetE("windows-1255",CHRTAB_WIN1255, CHARSET_WIN1255); + AddCharSetE("windows-1256",CHRTAB_WIN1256, CHARSET_WIN1256); + AddCharSetE("windows-1257",CHRTAB_WIN1257, CHARSET_WIN1257); + AddCharSetE("windows-1258",CHRTAB_WIN1258, CHARSET_WIN1258); + AddCharSetE("koi8-r", CHRTAB_KOI8_R, CHARSET_WIN1251); + AddCharSetE("cp852", CHRTAB_CP852, CHARSET_WIN1250); + AddCharSetE("mjk", CHRTAB_MJK, CHARSET_WIN1250); + AddCharSetE("cp850", CHRTAB_CP850, CHARSET_WIN1252); +#else + AddCharSetE("NONE" , CHRTAB_ISO8859_1, CHARSET_ISO8859_1); + AddCharSetE("iso8859-1", CHRTAB_ISO8859_1, CHARSET_ISO8859_1); + AddCharSetE("iso8859-2", CHRTAB_ISO8859_2, CHARSET_ISO8859_2); + AddCharSetE("iso8859-3", CHRTAB_ISO8859_3, CHARSET_ISO8859_3); + AddCharSetE("iso8859-4", CHRTAB_ISO8859_4, CHARSET_ISO8859_4); + AddCharSetE("iso8859-5", CHRTAB_ISO8859_5, CHARSET_ISO8859_5); + AddCharSetE("iso8859-6", CHRTAB_ISO8859_6, CHARSET_ISO8859_6); + AddCharSetE("iso8859-7", CHRTAB_ISO8859_7, CHARSET_ISO8859_7); + AddCharSetE("iso8859-8", CHRTAB_ISO8859_8, CHARSET_ISO8859_8); + AddCharSetE("iso8859-9", CHRTAB_ISO8859_9, CHARSET_ISO8859_9); + AddCharSetE("iso8859-10", CHRTAB_ISO8859_10, CHARSET_ISO8859_10); + AddCharSetE("iso8859-13", CHRTAB_ISO8859_13, CHARSET_ISO8859_13); + AddCharSetE("iso8859-14", CHRTAB_ISO8859_14, CHARSET_ISO8859_14); + AddCharSetE("iso8859-15", CHRTAB_ISO8859_15, CHARSET_ISO8859_15); + AddCharSetE("iso8859-16", CHRTAB_ISO8859_16, CHARSET_ISO8859_16); + AddCharSetE("windows-1250",CHRTAB_WIN1250, CHARSET_ISO8859_2); + AddCharSetE("windows-1251",CHRTAB_WIN1251, CHARSET_ISO8859_5); + AddCharSetE("windows-1252",CHRTAB_WIN1252, CHARSET_ISO8859_1); + AddCharSetE("windows-1253",CHRTAB_WIN1253, CHARSET_ISO8859_7); + AddCharSetE("windows-1254",CHRTAB_WIN1254, CHARSET_ISO8859_9); + AddCharSetE("windows-1255",CHRTAB_WIN1255, CHARSET_ISO8859_8); + AddCharSetE("windows-1256",CHRTAB_WIN1256, CHARSET_ISO8859_6); + AddCharSetE("windows-1257",CHRTAB_WIN1257, CHARSET_ISO8859_13); + AddCharSetE("windows-1258",CHRTAB_WIN1258, CHARSET_ISO8859_9); + AddCharSetE("koi8-r", CHRTAB_KOI8_R, CHARSET_ISO8859_5); + AddCharSetE("cp852", CHRTAB_CP852, CHARSET_ISO8859_2); + AddCharSetE("mjk", CHRTAB_MJK, CHARSET_ISO8859_2); + AddCharSetE("cp850", CHRTAB_CP850, CHARSET_ISO8859_1); +#endif +} + +static ArrayMap& s_map() +{ + static bool init; + if(!init) + ONCELOCK { + init = true; + sInit(); + } + return Single< ArrayMap >(); +} + +byte AddCharSet(const char *name, const word *table, byte systemcharset) +{ +#ifdef _DEBUG + Index chk; + for(int i = 0; i < 128; i++) { + ASSERT(table[i] >= 128); + ASSERT(chk.Find(table[i]) < 0); + chk.Add(table[i]); + } +#endif + LLOG("Adding " << name << " charset"); + int q = s_map().GetCount(); + CharSetData& m = s_map().Add(name); + m.table = table; + m.system = systemcharset; + return q; +} + +byte AddCharSetE(const char *name, word *table, byte systemcharset) +{ + for(int i = 0; i < 128; i++) + if(table[i] == CUNDEF) + table[i] = i + 0xEE80; + return AddCharSet(name, table, systemcharset); +} + +const char *CharsetName(byte charset) +{ + if(charset == CHARSET_DEFAULT) + charset = GetDefaultCharset(); + if(charset == CHARSET_UTF8) + return "UTF-8"; + if(charset >= CharsetCount()) + return ""; + return s_map().GetKey(charset); +} + +int CharsetCount() +{ + return s_map().GetCount(); +} + +int cs_filter(int c) +{ + return IsDigit(c) ? c : IsAlpha(c) ? ToLower(c) : 0; +} + +int CharsetByName(const char *name) +{ + String nm = Filter(name, cs_filter); + if(nm == "utf8" || nm == "utf-8") + return CHARSET_UTF8; + for(int i = 1; i < CharsetCount(); i++) + if(nm == Filter(CharsetName(i), cs_filter)) + return i; + return 0; +} + +byte ResolveCharset(byte charset) +{ + return charset ? charset : DefaultCharset; +} + +inline +static CharSetData& s_cset(byte charset) +{ + return s_map()[ResolveCharset(charset)]; +} + +byte SystemCharset(byte charset) +{ + return s_cset(charset).system; +} + +int ToUnicode(int chr, byte charset) +{ + return s_cset(charset).ToUnicode(chr); +} + +int FromUnicode(wchar wchr, byte charset, int def) +{ + return s_cset(charset).FromUnicode(wchr, def); +} + +void ToUnicode(wchar *ws, const char *s, int n, byte charset) +{ + CharSetData& cs = s_cset(charset); + const char *lim = s + n; + while(s < lim) + *ws++ = cs.ToUnicode(*s++); +} + +void FromUnicode(char *s, const wchar *ws, int n, byte charset, int def) +{ + s_cset(charset).FromUnicode(s, ws, ws + n, def); +} + +void ConvertCharset(char *t, byte tcharset, const char *s, byte scharset, int n) +{ + CharSetData& cs = s_cset(scharset); + const char *lim = s + n; + if(tcharset == CHARSET_TOASCII) + while(s < lim) + *t++ = ToAscii(cs.ToUnicode(*s++)); + else { + CharSetData& ct = s_cset(tcharset); + while(s < lim) + *t++ = ct.FromUnicode(cs.ToUnicode(*s++)); + } +} + +bool utf8check(const char *_s, int len) +{ + const byte *s = (const byte *)_s; + const byte *lim = s + len; + int codePoint = 0; + while(s < lim) { + word code = (byte)*s++; + if(code >= 0x80) { + if(code < 0xC2) + return false; + else + if(code < 0xE0) { + if(s >= lim || *s < 0x80 || *s >= 0xc0) + return false; + codePoint = ((code - 0xC0) << 6) + *s - 0x80; + if(codePoint < 0x80 || codePoint > 0x07FF) + return false; + s++; + } + else + if(code < 0xF0) { + if(s + 1 >= lim || + s[0] < 0x80 || s[0] >= 0xc0 || + s[1] < 0x80 || s[1] >= 0xc0) + return false; + codePoint = ((code - 0xE0) << 12) + ((s[0] - 0x80) << 6) + s[1] - 0x80; + if(codePoint < 0x0800 || codePoint > 0xFFFF) + return false; + s += 2; + } + else + if(code < 0xF5) { + if(s + 2 >= lim || + s[0] < 0x80 || s[0] >= 0xc0 || + s[1] < 0x80 || s[1] >= 0xc0 || + s[2] < 0x80 || s[2] >= 0xc0) + return false; + codePoint = ((code - 0xf0) << 18) + ((s[0] - 0x80) << 12) + + ((s[1] - 0x80) << 6) + s[2] - 0x80; + if(codePoint < 0x010000 || codePoint > 0x10FFFF) + return false; + s += 3; + } + else + return false; + } + } + return true; +} + +int utf8len(const char *_s, int _len) +{ + const byte *s = (const byte *)_s; + const byte *lim = s + _len; + int len = 0; + if(_len > 4) + while(s < lim - 4) { + word code = (byte)*s++; + if(code < 0x80) + len++; + else + if(code < 0xC2) + len++; + else + if(code < 0xE0) { + word c = ((code - 0xC0) << 6) + s[0] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && c >= 0x80 && c < 0x800) + len++; + else + len += 2; + s += 1; + } + else + if(code < 0xF0) { + word c = ((code - 0xE0) << 12) + ((s[0] - 0x80) << 6) + s[1] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && s[1] >= 0x80 && s[1] < 0xc0 && c >= 0x800 + && !(c >= 0xEE00 && c <= 0xEEFF)) + len++; + else + len += 3; + s += 2; + } + else + len++; + } + while(s < lim) { + word code = (byte)*s++; + if(code < 0x80) + len++; + else + if(code < 0xC2) + len++; + else + if(code < 0xE0) { + if(s > lim - 1) { + len++; + break; + } + word c = ((code - 0xC0) << 6) + s[0] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && c >= 0x80 && c < 0x800) + len++; + else + len += 2; + s += 1; + } + else + if(code < 0xF0) { + if(s > lim - 2) { + len += 1 + (int)(lim - s); + break; + } + word c = ((code - 0xE0) << 12) + ((s[0] - 0x80) << 6) + s[1] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && s[1] >= 0x80 && s[1] < 0xc0 && c >= 0x800 + && !(c >= 0xEE00 && c <= 0xEEFF)) + len++; + else + len += 3; + s += 2; + } + else + len++; + } + return len; +} + +WString FromUtf8(const char *_s, int len) +{ + const byte *s = (const byte *)_s; + const byte *lim = s + len; + int tlen = utf8len(_s, len); + WStringBuffer result(tlen); + wchar *t = result; + if(len > 4) + while(s < lim - 4) { + word code = (byte)*s++; + if(code < 0x80) + *t++ = code; + else + if(code < 0xC2) + *t++ = 0xEE00 + code; + else + if(code < 0xE0) { + word c = ((code - 0xC0) << 6) + s[0] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && c >= 0x80 && c < 0x800) + *t++ = c; + else { + *t++ = 0xEE00 + code; + *t++ = 0xEE00 + s[0]; + } + s += 1; + } + else + if(code < 0xF0) { + word c = ((code - 0xE0) << 12) + ((s[0] - 0x80) << 6) + s[1] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && s[1] >= 0x80 && s[1] < 0xc0 && c >= 0x800 + && !(c >= 0xEE00 && c <= 0xEEFF)) + *t++ = c; + else { + *t++ = 0xEE00 + code; + *t++ = 0xEE00 + s[0]; + *t++ = 0xEE00 + s[1]; + } + s += 2; + } + else + *t++ = 0xEE00 + code; + } + while(s < lim) { + word code = (byte)*s++; + if(code < 0x80) + *t++ = code; + else + if(code < 0xC0) + *t++ = 0xEE00 + code; + else + if(code < 0xE0) { + if(s > lim - 1) { + *t++ = 0xEE00 + code; + break; + } + word c = ((code - 0xC0) << 6) + s[0] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && c >= 0x80 && c < 0x800) + *t++ = c; + else { + *t++ = 0xEE00 + code; + *t++ = 0xEE00 + s[0]; + } + s += 1; + } + else + if(code < 0xF0) { + if(s > lim - 2) { + *t++ = 0xEE00 + code; + while(s < lim) + *t++ = 0xEE00 + *s++; + break; + } + word c = ((code - 0xE0) << 12) + ((s[0] - 0x80) << 6) + s[1] - 0x80; + if(s[0] >= 0x80 && s[0] < 0xc0 && s[1] >= 0x80 && s[1] < 0xc0 && c >= 0x800 + && !(c >= 0xEE00 && c <= 0xEEFF)) + *t++ = c; + else { + *t++ = 0xEE00 + code; + *t++ = 0xEE00 + s[0]; + *t++ = 0xEE00 + s[1]; + } + s += 2; + } + else + *t++ = 0xEE00 + code; + } + ASSERT(t - ~result == tlen); + return result; +} + +int lenAsUtf8(const wchar *s, int len) +{ + const wchar *lim = s + len; + len = 0; + while(s < lim) { + word code = *s++; + if(code < 0x80) + len++; + else + if(code < 0x800) + len += 2; + else + if((code & 0xFF00) == 0xEE00) + len++; + else + len += 3; + } + return len; +} + +String ToUtf8(const wchar *s, int len) +{ + const wchar *lim = s + len; + int tlen = lenAsUtf8(s, len); + StringBuffer result(tlen); + char *t = result; + while(s < lim) { + word code = *s++; + if(code < 0x80) + *t++ = (char)code; + else + if(code < 0x800) { + *t++ = 0xc0 | (code >> 6); + *t++ = 0x80 | (code & 0x3f); + } + else + if((code & 0xFF00) == 0xEE00) + *t++ = (char) code; + else { + *t++ = 0xe0 | (code >> 12); + *t++ = 0x80 | ((code >> 6) & 0x3f); + *t++ = 0x80 | (code & 0x3f); + } + } + ASSERT(t - ~result == tlen); + return result; +} + +int utf8len(const char *s) +{ + return utf8len(s, (int)strlen(s)); +} + +int lenAsUtf8(const wchar *s) +{ + return lenAsUtf8(s, wstrlen(s)); +} + +String ToUtf8(wchar code) +{ + return ToUtf8(&code, 1); +} + +String ToUtf8(const WString& w) +{ + return ToUtf8(w, w.GetLength()); +} + +String ToUtf8(const wchar *s) +{ + return ToUtf8(s, wstrlen(s)); +} + +bool CheckUtf8(const String& src) +{ + return utf8check(~src, src.GetLength()); +} + +WString FromUtf8(const char *s) +{ + return FromUtf8(s, (int)strlen(s)); +} + +WString FromUtf8(const String& s) +{ + return FromUtf8(s, s.GetLength()); +} + +#ifdef flagSO +bool IsLetter(int c) { return (dword)c < 2048 ? uni__info[c] & 0xc0000000 : 0; } +bool IsUpper(int c) { return (dword)c < 2048 ? uni__info[c] & 0x40000000 : 0; } +bool IsLower(int c) { return (dword)c < 2048 ? uni__info[c] & 0x80000000 : 0; } +int ToUpper(int c) { return (dword)c < 2048 ? (uni__info[c] >> 11) & 2047 : c; } +int ToLower(int c) { return (dword)c < 2048 ? uni__info[c] & 2047 : c; } +int ToAscii(int c) { return (dword)c < 2048 ? (uni__info[c] >> 22) & 0x7f : 0; } +#endif + +void ToUpper(wchar *t, const wchar *s, int len) +{ + const wchar *lim = s + len; + while(s < lim) + *t++ = ToUpper(*s++); +} + +void ToLower(wchar *t, const wchar *s, int len) +{ + const wchar *lim = s + len; + while(s < lim) + *t++ = ToLower(*s++); +} + +void ToAscii(wchar *t, const wchar *s, int len) +{ + const wchar *lim = s + len; + while(s < lim) + *t++ = ToAscii(*s++); +} + +void ToUpper(wchar *s, int len) { ToUpper(s, s, len); } +void ToLower(wchar *s, int len) { ToLower(s, s, len); } +void ToAscii(wchar *s, int len) { ToAscii(s, s, len); } + +bool IsLetter(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return IsLetter(c); + CharSetData& cs = s_cset(charset); + return IsLetter(cs.ToUnicode(c)); +} + +bool IsUpper(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return IsUpper(c); + CharSetData& cs = s_cset(charset); + return IsUpper(cs.ToUnicode(c)); +} + +bool IsLower(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return IsLower(c); + CharSetData& cs = s_cset(charset); + return IsLower(cs.ToUnicode(c)); +} + +int ToUpper(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return ToUpper(c); + CharSetData& cs = s_cset(charset); + return cs.FromUnicode(ToUpper(cs.ToUnicode(c))); +} + +int ToLower(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return ToLower(c); + CharSetData& cs = s_cset(charset); + return cs.FromUnicode(ToLower(cs.ToUnicode(c))); +} + +int ToAscii(int c, byte charset) +{ + if((charset ? charset : DefaultCharset) == CHARSET_UTF8) + return ToAscii(c); + CharSetData& cs = s_cset(charset); + return cs.FromUnicode(ToAscii(cs.ToUnicode(c))); +} + +static word sComb(const word *s, word chr) +{ + while(*s) { + if(*s == chr) + return s[1]; + s += 2; + } + return 0; +} + +word UnicodeCombine(word chr, word combine) +{ + static word comb300[] = { 0x41, 0xC0, 0x45, 0xC8, 0x49, 0xCC, 0x4F, 0xD2, 0x55, 0xD9, 0x61, 0xE0, 0x65, 0xE8, 0x69, 0xEC, 0x6F, 0xF2, 0x75, 0xF9, 0xDC, 0x1DB, 0xFC, 0x1DC, 0x4E, 0x1F8, 0x6E, 0x1F9, 0x415, 0x400, 0x418, 0x40D, 0x435, 0x450, 0x438, 0x45D, 0 }; + static word comb301[] = { 0x41, 0xC1, 0x45, 0xC9, 0x49, 0xCD, 0x4F, 0xD3, 0x55, 0xDA, 0x59, 0xDD, 0x61, 0xE1, 0x65, 0xE9, 0x69, 0xED, 0x6F, 0xF3, 0x75, 0xFA, 0x79, 0xFD, 0x43, 0x106, 0x63, 0x107, 0x4C, 0x139, 0x6C, 0x13A, 0x4E, 0x143, 0x6E, 0x144, 0x52, 0x154, 0x72, 0x155, 0x53, 0x15A, 0x73, 0x15B, 0x5A, 0x179, 0x7A, 0x17A, 0xDC, 0x1D7, 0xFC, 0x1D8, 0x47, 0x1F4, 0x67, 0x1F5, 0xC5, 0x1FA, 0xE5, 0x1FB, 0xC6, 0x1FC, 0xE6, 0x1FD, 0xD8, 0x1FE, 0xF8, 0x1FF, 0x308, 0x344, 0xA8, 0x385, 0x391, 0x386, 0x395, 0x388, 0x397, 0x389, 0x399, 0x38A, 0x39F, 0x38C, 0x3A5, 0x38E, 0x3A9, 0x38F, 0x3CA, 0x390, 0x3B1, 0x3AC, 0x3B5, 0x3AD, 0x3B7, 0x3AE, 0x3B9, 0x3AF, 0x3CB, 0x3B0, 0x3BF, 0x3CC, 0x3C5, 0x3CD, 0x3C9, 0x3CE, 0x3D2, 0x3D3, 0x413, 0x403, 0x41A, 0x40C, 0x433, 0x453, 0x43A, 0x45C, 0 }; + static word comb302[] = { 0x41, 0xC2, 0x45, 0xCA, 0x49, 0xCE, 0x4F, 0xD4, 0x55, 0xDB, 0x61, 0xE2, 0x65, 0xEA, 0x69, 0xEE, 0x6F, 0xF4, 0x75, 0xFB, 0x43, 0x108, 0x63, 0x109, 0x47, 0x11C, 0x67, 0x11D, 0x48, 0x124, 0x68, 0x125, 0x4A, 0x134, 0x6A, 0x135, 0x53, 0x15C, 0x73, 0x15D, 0x57, 0x174, 0x77, 0x175, 0x59, 0x176, 0x79, 0x177, 0 }; + static word comb303[] = { 0x41, 0xC3, 0x4E, 0xD1, 0x4F, 0xD5, 0x61, 0xE3, 0x6E, 0xF1, 0x6F, 0xF5, 0x49, 0x128, 0x69, 0x129, 0x55, 0x168, 0x75, 0x169, 0 }; + static word comb304[] = { 0x41, 0x100, 0x61, 0x101, 0x45, 0x112, 0x65, 0x113, 0x49, 0x12A, 0x69, 0x12B, 0x4F, 0x14C, 0x6F, 0x14D, 0x55, 0x16A, 0x75, 0x16B, 0xDC, 0x1D5, 0xFC, 0x1D6, 0xC4, 0x1DE, 0xE4, 0x1DF, 0x226, 0x1E0, 0x227, 0x1E1, 0xC6, 0x1E2, 0xE6, 0x1E3, 0x1EA, 0x1EC, 0x1EB, 0x1ED, 0xD6, 0x22A, 0xF6, 0x22B, 0xD5, 0x22C, 0xF5, 0x22D, 0x22E, 0x230, 0x22F, 0x231, 0x59, 0x232, 0x79, 0x233, 0x418, 0x4E2, 0x438, 0x4E3, 0x423, 0x4EE, 0x443, 0x4EF, 0 }; + static word comb305[] = { 0 }; + static word comb306[] = { 0x41, 0x102, 0x61, 0x103, 0x45, 0x114, 0x65, 0x115, 0x47, 0x11E, 0x67, 0x11F, 0x49, 0x12C, 0x69, 0x12D, 0x4F, 0x14E, 0x6F, 0x14F, 0x55, 0x16C, 0x75, 0x16D, 0x423, 0x40E, 0x418, 0x419, 0x438, 0x439, 0x443, 0x45E, 0x416, 0x4C1, 0x436, 0x4C2, 0x410, 0x4D0, 0x430, 0x4D1, 0x415, 0x4D6, 0x435, 0x4D7, 0 }; + static word comb307[] = { 0x43, 0x10A, 0x63, 0x10B, 0x45, 0x116, 0x65, 0x117, 0x47, 0x120, 0x67, 0x121, 0x49, 0x130, 0x5A, 0x17B, 0x7A, 0x17C, 0x41, 0x226, 0x61, 0x227, 0x4F, 0x22E, 0x6F, 0x22F, 0 }; + static word comb308[] = { 0x41, 0xC4, 0x45, 0xCB, 0x49, 0xCF, 0x4F, 0xD6, 0x55, 0xDC, 0x61, 0xE4, 0x65, 0xEB, 0x69, 0xEF, 0x6F, 0xF6, 0x75, 0xFC, 0x79, 0xFF, 0x59, 0x178, 0x399, 0x3AA, 0x3A5, 0x3AB, 0x3B9, 0x3CA, 0x3C5, 0x3CB, 0x3D2, 0x3D4, 0x415, 0x401, 0x406, 0x407, 0x435, 0x451, 0x456, 0x457, 0x410, 0x4D2, 0x430, 0x4D3, 0x4D8, 0x4DA, 0x4D9, 0x4DB, 0x416, 0x4DC, 0x436, 0x4DD, 0x417, 0x4DE, 0x437, 0x4DF, 0x418, 0x4E4, 0x438, 0x4E5, 0x41E, 0x4E6, 0x43E, 0x4E7, 0x4E8, 0x4EA, 0x4E9, 0x4EB, 0x42D, 0x4EC, 0x44D, 0x4ED, 0x423, 0x4F0, 0x443, 0x4F1, 0x427, 0x4F4, 0x447, 0x4F5, 0x42B, 0x4F8, 0x44B, 0x4F9, 0 }; + static word comb309[] = { 0 }; + static word comb30A[] = { 0x41, 0xC5, 0x61, 0xE5, 0x55, 0x16E, 0x75, 0x16F, 0 }; + static word comb30B[] = { 0x4F, 0x150, 0x6F, 0x151, 0x55, 0x170, 0x75, 0x171, 0x423, 0x4F2, 0x443, 0x4F3, 0 }; + static word comb30C[] = { 0x43, 0x10C, 0x63, 0x10D, 0x44, 0x10E, 0x64, 0x10F, 0x45, 0x11A, 0x65, 0x11B, 0x4C, 0x13D, 0x6C, 0x13E, 0x4E, 0x147, 0x6E, 0x148, 0x52, 0x158, 0x72, 0x159, 0x53, 0x160, 0x73, 0x161, 0x54, 0x164, 0x74, 0x165, 0x5A, 0x17D, 0x7A, 0x17E, 0x41, 0x1CD, 0x61, 0x1CE, 0x49, 0x1CF, 0x69, 0x1D0, 0x4F, 0x1D1, 0x6F, 0x1D2, 0x55, 0x1D3, 0x75, 0x1D4, 0xDC, 0x1D9, 0xFC, 0x1DA, 0x47, 0x1E6, 0x67, 0x1E7, 0x4B, 0x1E8, 0x6B, 0x1E9, 0x1B7, 0x1EE, 0x292, 0x1EF, 0x6A, 0x1F0, 0x48, 0x21E, 0x68, 0x21F, 0 }; + static word comb30D[] = { 0 }; + static word comb30E[] = { 0 }; + static word comb30F[] = { 0x41, 0x200, 0x61, 0x201, 0x45, 0x204, 0x65, 0x205, 0x49, 0x208, 0x69, 0x209, 0x4F, 0x20C, 0x6F, 0x20D, 0x52, 0x210, 0x72, 0x211, 0x55, 0x214, 0x75, 0x215, 0x474, 0x476, 0x475, 0x477, 0 }; + static const word *comb[] = { + comb300, comb301, comb302, comb303, comb304, comb305, comb306, comb307, + comb308, comb309, comb30A, comb30B, comb30C, comb30D, comb30E, comb30F, + }; + if(combine >= 0x300 && combine <= 0x30F) + return sComb(comb[combine - 0x300], chr); + + static word comb311[] = { 0x41, 0x202, 0x61, 0x203, 0x45, 0x206, 0x65, 0x207, 0x49, 0x20A, 0x69, 0x20B, 0x4F, 0x20E, 0x6F, 0x20F, 0x52, 0x212, 0x72, 0x213, 0x55, 0x216, 0x75, 0x217, 0 }; + static word comb31B[] = { 0x4F, 0x1A0, 0x6F, 0x1A1, 0x55, 0x1AF, 0x75, 0x1B0, 0 }; + static word comb326[] = { 0x53, 0x218, 0x73, 0x219, 0x54, 0x21A, 0x74, 0x21B, 0 }; + static word comb327[] = { 0x43, 0xC7, 0x63, 0xE7, 0x47, 0x122, 0x67, 0x123, 0x4B, 0x136, 0x6B, 0x137, 0x4C, 0x13B, 0x6C, 0x13C, 0x4E, 0x145, 0x6E, 0x146, 0x52, 0x156, 0x72, 0x157, 0x53, 0x15E, 0x73, 0x15F, 0x54, 0x162, 0x74, 0x163, 0x45, 0x228, 0x65, 0x229, 0 }; + static word comb328[] = { 0x41, 0x104, 0x61, 0x105, 0x45, 0x118, 0x65, 0x119, 0x49, 0x12E, 0x69, 0x12F, 0x55, 0x172, 0x75, 0x173, 0x4F, 0x1EA, 0x6F, 0x1EB, 0 }; + static word comb653[] = { 0x627, 0x622, 0 }; + static word comb654[] = { 0x627, 0x623, 0x648, 0x624, 0x64A, 0x626, 0x6D5, 0x6C0, 0x6C1, 0x6C2, 0x6D2, 0x6D3, 0 }; + static word comb655[] = { 0x627, 0x625, 0 }; + + switch(combine) { + case 0x311: return sComb(comb311, chr); + case 0x31B: return sComb(comb31B, chr); + case 0x326: return sComb(comb326, chr); + case 0x327: return sComb(comb327, chr); + case 0x328: return sComb(comb328, chr); + case 0x653: return sComb(comb653, chr); + case 0x654: return sComb(comb654, chr); + case 0x655: return sComb(comb655, chr); + } + return 0; +} + +void ToUpper(char *t, const char *s, int len, byte charset) +{ + charset = ResolveCharset(charset); + CharSetData& cs = s_cset(charset); + const char *lim = s + len; + while(s < lim) + *t++ = cs.FromUnicode(UPP::ToUpper(cs.ToUnicode(*s++))); +} + +void ToLower(char *t, const char *s, int len, byte charset) +{ + charset = ResolveCharset(charset); + CharSetData& cs = s_cset(charset); + const char *lim = s + len; + while(s < lim) + *t++ = cs.FromUnicode(UPP::ToLower(cs.ToUnicode(*s++))); +} + +void ToAscii(char *t, const char *s, int len, byte charset) +{ + charset = ResolveCharset(charset); + CharSetData& cs = s_cset(charset); + const char *lim = s + len; + while(s < lim) + *t++ = cs.FromUnicode(UPP::ToAscii(cs.ToUnicode(*s++))); +} + +void ToUpper(char *s, int len, byte charset) +{ + ToUpper(s, s, len, charset); +} + +void ToLower(char *s, int len, byte charset) +{ + ToLower(s, s, len, charset); +} + +void ToAscii(char *s, int len, byte charset) +{ + ToAscii(s, s, len, charset); +} + + +WString ToUnicode(const char *src, int l, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return FromUtf8(src, l); + WStringBuffer result(l); + ToUnicode(result, src, l, charset); + return result; +} + +WString ToUnicode(const String& src, byte charset) +{ + return ToUnicode(src, src.GetLength(), charset); +} + +String FromUnicode(const WString& src, byte charset, int def) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(src); + int l = src.GetLength(); + StringBuffer result(l); + FromUnicode(result, src, l, charset, def); + return result; +} + +String ToCharset(byte charset, const String& src, byte scharset, int def) +{ + charset = ResolveCharset(charset); + scharset = ResolveCharset(scharset); + if(charset == scharset) + return src; + int slen = src.GetLength(); + if(scharset == CHARSET_UTF8) + return FromUnicode(FromUtf8(src, slen), charset, def); + if(charset == CHARSET_UTF8) + return ToUtf8(ToUnicode(src, scharset)); + StringBuffer result(slen); + ConvertCharset(result, charset, src, scharset, slen); + return result; +} + +WString InitCaps(const wchar *s) +{ + WString r; + bool spc = true; + while(*s) { + if(spc) + r.Cat(ToUpper(*s)); + else + r.Cat(ToLower(*s)); + spc = IsSpace(*s); + s++; + } + return r; +} + +WString ToUpper(const WString& w) +{ + int l = w.GetLength(); + WStringBuffer r(l); + ToUpper(r, w, l); + return r; +} + +WString ToLower(const WString& w) +{ + int l = w.GetLength(); + WStringBuffer r(l); + ToLower(r, w, l); + return r; +} + +WString ToAscii(const WString& w) +{ + int l = w.GetLength(); + WStringBuffer r(l); + ToAscii(r, w, l); + return r; +} + +String InitCaps(const char *s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(InitCaps(FromUtf8(s))); + StringBuffer r; + bool spc = true; + while(*s) { + if(spc) + r.Cat(ToUpper(*s, charset)); + else + r.Cat(ToLower(*s, charset)); + spc = IsSpace(*s); + s++; + } + return r; +} + +String ToUpper(const char *s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToUpper(FromUtf8(s))); + int l = (int)strlen(s); + StringBuffer r(l); + ToUpper(r, s, l, charset); + return r; +} + +String ToLower(const char *s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToLower(FromUtf8(s))); + int l = (int)strlen(s); + StringBuffer r(l); + ToLower(r, s, l, charset); + return r; +} + +String ToAscii(const char *s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToAscii(FromUtf8(s))); + int l = (int)strlen(s); + StringBuffer r(l); + ToAscii(r, s, l, charset); + return r; +} + +String ToUpper(const String& s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToUpper(FromUtf8(s))); + int l = s.GetLength(); + StringBuffer r(l); + ToUpper(r, s, l, charset); + return r; +} + +String ToLower(const String& s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToLower(FromUtf8(s))); + int l = s.GetLength(); + StringBuffer r(l); + ToLower(r, s, l, charset); + return r; +} + +String ToAscii(const String& s, byte charset) +{ + charset = ResolveCharset(charset); + if(charset == CHARSET_UTF8) + return ToUtf8(ToAscii(FromUtf8(s))); + int l = s.GetLength(); + StringBuffer r(l); + ToAscii(r, s, l, charset); + return r; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/CharSet.h b/uppdev/CoreTopics/CharSet.h new file mode 100644 index 000000000..81f41b8e9 --- /dev/null +++ b/uppdev/CoreTopics/CharSet.h @@ -0,0 +1,206 @@ +#define CHARSET_DEFAULT 0 + +#define CHARSET_ISO8859_1 1 +#define CHARSET_ISO8859_2 2 +#define CHARSET_ISO8859_3 3 +#define CHARSET_ISO8859_4 4 +#define CHARSET_ISO8859_5 5 +#define CHARSET_ISO8859_6 6 +#define CHARSET_ISO8859_7 7 +#define CHARSET_ISO8859_8 8 +#define CHARSET_ISO8859_9 9 +#define CHARSET_ISO8859_10 10 +#define CHARSET_ISO8859_13 11 +#define CHARSET_ISO8859_14 12 +#define CHARSET_ISO8859_15 13 +#define CHARSET_ISO8859_16 14 +#define CHARSET_WIN1250 15 +#define CHARSET_WIN1251 16 +#define CHARSET_WIN1252 17 +#define CHARSET_WIN1253 18 +#define CHARSET_WIN1254 19 +#define CHARSET_WIN1255 20 +#define CHARSET_WIN1256 21 +#define CHARSET_WIN1257 22 +#define CHARSET_WIN1258 23 +#define CHARSET_KOI8_R 24 +#define CHARSET_CP852 25 +#define CHARSET_MJK 26 +#define CHARSET_CP850 27 + +#define CHARSET_TOASCII 253 +#define CHARSET_UTF8 255 +#define CHARSET_UNICODE 255 + +enum { + DEFAULTCHAR = 0x1f +}; + +#ifndef flagSO + +extern word CHRTAB_ISO8859_1[128]; +extern word CHRTAB_ISO8859_2[128]; +extern word CHRTAB_ISO8859_3[128]; +extern word CHRTAB_ISO8859_4[128]; +extern word CHRTAB_ISO8859_5[128]; +extern word CHRTAB_ISO8859_6[128]; +extern word CHRTAB_ISO8859_7[128]; +extern word CHRTAB_ISO8859_8[128]; +extern word CHRTAB_ISO8859_9[128]; +extern word CHRTAB_ISO8859_10[128]; +extern word CHRTAB_ISO8859_13[128]; +extern word CHRTAB_ISO8859_14[128]; +extern word CHRTAB_ISO8859_15[128]; +extern word CHRTAB_ISO8859_16[128]; +extern word CHRTAB_WIN1250[128]; +extern word CHRTAB_WIN1251[128]; +extern word CHRTAB_WIN1252[128]; +extern word CHRTAB_WIN1253[128]; +extern word CHRTAB_WIN1254[128]; +extern word CHRTAB_WIN1255[128]; +extern word CHRTAB_WIN1256[128]; +extern word CHRTAB_WIN1257[128]; +extern word CHRTAB_WIN1258[128]; +extern word CHRTAB_KOI8_R[128]; +extern word CHRTAB_CP852[128]; +extern word CHRTAB_MJK[128]; + +#endif + +void SetDefaultCharset(byte charset); +byte GetDefaultCharset(); + +byte ResolveCharset(byte charset); + +byte AddCharSet(const char *name, const word *table, byte systemcharset = CHARSET_DEFAULT); +byte AddCharSetE(const char *name, word *table, byte systemcharset = CHARSET_DEFAULT); + +const char *CharsetName(byte charset); +int CharsetCount(); +int CharsetByName(const char *name); + +byte SystemCharset(byte charset); + +int ToUnicode(int chr, byte charset); +int FromUnicode(wchar wchr, byte charset, int defchar = DEFAULTCHAR); + +void ToUnicode(wchar *ws, const char *s, int n, byte charset); +void FromUnicode(char *s, const wchar *ws, int n, byte charset, int defchar = DEFAULTCHAR); + +void ConvertCharset(char *t, byte tcharset, const char *s, byte scharset, int n); + +inline bool IsUtf8Lead(int c) +{ + return (c & 0xc0) != 0x80; +} + +String ToUtf8(wchar code); +String ToUtf8(const wchar *s, int len); +String ToUtf8(const wchar *s); +String ToUtf8(const WString& w); + +WString FromUtf8(const char *_s, int len); +WString FromUtf8(const char *_s); +WString FromUtf8(const String& s); + +bool utf8check(const char *_s, int len); + +int utf8len(const char *s, int len); +int utf8len(const char *s); +int lenAsUtf8(const wchar *s, int len); +int lenAsUtf8(const wchar *s); + +bool CheckUtf8(const String& src); + +WString ToUnicode(const String& src, byte charset); +WString ToUnicode(const char *src, int n, byte charset); +String FromUnicode(const WString& src, byte charset = CHARSET_DEFAULT, int defchar = DEFAULTCHAR); + +String ToCharset(byte charset, const String& s, byte scharset = CHARSET_DEFAULT, int defchar = DEFAULTCHAR); + +#ifndef flagSO +extern dword uni__info[2048]; + +inline bool IsLetter(int c) { return (dword)c < 2048 ? uni__info[c] & 0xc0000000 : 0; } +inline bool IsUpper(int c) { return (dword)c < 2048 ? uni__info[c] & 0x40000000 : 0; } +inline bool IsLower(int c) { return (dword)c < 2048 ? uni__info[c] & 0x80000000 : 0; } +inline int ToUpper(int c) { return (dword)c < 2048 ? (uni__info[c] >> 11) & 2047 : c; } +inline int ToLower(int c) { return (dword)c < 2048 ? uni__info[c] & 2047 : c; } +inline int ToAscii(int c) { return (dword)c < 2048 ? (uni__info[c] >> 22) & 0x7f : 0; } +#else +bool IsLetter(int c); +bool IsUpper(int c); +bool IsLower(int c); +int ToUpper(int c); +int ToLower(int c); +int ToAscii(int c); +#endif + +inline bool IsLetter(char c) { return IsLetter((byte) c); }//????? +inline bool IsUpper(char c) { return IsUpper((byte) c); } +inline bool IsLower(char c) { return IsLower((byte) c); } +inline int ToUpper(char c) { return ToUpper((byte) c); } +inline int ToLower(char c) { return ToLower((byte) c); } +inline int ToAscii(char c) { return ToAscii((byte) c); } + +inline bool IsLetter(signed char c) { return IsLetter((byte) c); } +inline bool IsUpper(signed char c) { return IsUpper((byte) c); } +inline bool IsLower(signed char c) { return IsLower((byte) c); } +inline int ToUpper(signed char c) { return ToUpper((byte) c); } +inline int ToLower(signed char c) { return ToLower((byte) c); } +inline int ToAscii(signed char c) { return ToAscii((byte) c); } + +inline bool IsLetter(wchar c) { return IsLetter((int) c); } +inline bool IsUpper(wchar c) { return IsUpper((int) c); } +inline bool IsLower(wchar c) { return IsLower((int) c); } +inline int ToUpper(wchar c) { return ToUpper((int) c); } +inline int ToLower(wchar c) { return ToLower((int) c); } +inline int ToAscii(wchar c) { return ToAscii((int) c); } + +inline bool IsDigit(int c) { return c >= '0' && c <= '9'; } +inline bool IsAlpha(int c) { return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'; } +inline bool IsAlNum(int c) { return IsDigit(c) || IsAlpha(c); } +inline bool IsLeNum(int c) { return IsDigit(c) || IsLetter(c); } +inline bool IsPunct(int c) { return c != ' ' && !IsAlNum(c); } +inline bool IsSpace(int c) { return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\v' || c == '\t'; } +inline bool IsXDigit(int c) { return IsDigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; } + +inline bool IsCJKIdeograph(int c) { return c >= 0x2e80 && c <= 0xdfaf || c >= 0xf900 && c <= 0xfaff; } + +word UnicodeCombine(word chr, word combine); + +void ToUpper(wchar *t, const char *s, int len); +void ToLower(wchar *t, const char *s, int len); +void ToAscii(wchar *t, const char *s, int len); + +void ToUpper(wchar *s, int len); +void ToLower(wchar *s, int len); +void ToAscii(wchar *s, int len); + +bool IsLetter(int c, byte charset); +bool IsUpper(int c, byte charset); +bool IsLower(int c, byte charset); +int ToUpper(int c, byte charset); +int ToLower(int c, byte charset); +int ToAscii(int c, byte charset); + +void ToUpper(char *t, const char *s, int len, byte charset = CHARSET_DEFAULT); +void ToLower(char *t, const char *s, int len, byte charset = CHARSET_DEFAULT); +void ToAscii(char *t, const char *s, int len, byte charset = CHARSET_DEFAULT); + +void ToUpper(char *s, int len, byte charset = CHARSET_DEFAULT); +void ToLower(char *s, int len, byte charset = CHARSET_DEFAULT); +void ToAscii(char *s, int len, byte charset = CHARSET_DEFAULT); + +WString InitCaps(const wchar *s); +WString ToUpper(const WString& w); +WString ToLower(const WString& w); +WString ToAscii(const WString& w); + +String InitCaps(const char *s, byte charset = CHARSET_DEFAULT); +String ToUpper(const String& s, byte charset = CHARSET_DEFAULT); +String ToLower(const String& s, byte charset = CHARSET_DEFAULT); +String ToAscii(const String& s, byte charset = CHARSET_DEFAULT); +String ToUpper(const char *s, byte charset = CHARSET_DEFAULT); +String ToLower(const char *s, byte charset = CHARSET_DEFAULT); +String ToAscii(const char *s, byte charset = CHARSET_DEFAULT); diff --git a/uppdev/CoreTopics/CoWork.cpp b/uppdev/CoreTopics/CoWork.cpp new file mode 100644 index 000000000..803dac0d9 --- /dev/null +++ b/uppdev/CoreTopics/CoWork.cpp @@ -0,0 +1,143 @@ +#include "Core.h" + +NAMESPACE_UPP + +#ifdef _MULTITHREADED + +#define LLOG(x) // LOG(x) +#define LDUMP(x) // DUMP(x) + +CoWork::Pool& CoWork::pool() +{ + static Pool pool; + return pool; +} + +CoWork::Pool::Pool() +{ + LLOG("CoWork INIT"); + for(int i = 0; i < CPU_Cores() + 2; i++) + threads.Add().Run(callback1(&ThreadRun, i)); +} + +CoWork::Pool::~Pool() +{ + LLOG("Quit"); + MJob job; + job.work = NULL; + lock.Enter(); + jobs.Clear(); + jobs.Add(job); + lock.Leave(); + for(int i = 0; i < threads.GetCount(); i++) + waitforjob.Release(); + for(int i = 0; i < threads.GetCount(); i++) + threads[i].Wait(); + LLOG("Quit ended"); +} + +bool CoWork::Pool::DoJob() +{ + Pool& p = pool(); + if(p.jobs.Top().work == NULL) { + LLOG("Quit thread"); + return true; + } + MJob job = p.jobs.Pop(); + p.lock.Leave(); + job.cb(); + p.lock.Enter(); + if(--job.work->todo == 0) { + LLOG("Releasing waitforfinish of (CoWork " << FormatIntHex(job.work) << ")"); + job.work->waitforfinish.Release(); + } + LLOG("Finished, remaining todo " << job.work->todo << " (CoWork " << FormatIntHex(job.work) << ")"); + return false; +} + +void CoWork::Pool::ThreadRun(int tno) +{ + LLOG("CoWork thread #" << tno << " started"); + Pool& p = pool(); + p.lock.Enter(); + for(;;) { + while(p.jobs.GetCount() == 0) { + p.waiting_threads++; + p.lock.Leave(); + LLOG("#" << tno << " Waiting for job"); + p.waitforjob.Wait(); + LLOG("#" << tno << " Waiting ended"); + p.lock.Enter(); + } + LLOG("#" << tno << " Job acquired"); + if(DoJob()) + break; + LLOG("#" << tno << " Job finished"); + } + p.lock.Leave(); + LLOG("CoWork thread #" << tno << " finished"); +} + +void CoWork::Do(Callback cb) { +#ifdef _MULTITHREADED + Pool& p = pool(); + p.lock.Enter(); + if(p.jobs.GetCount() > 128) { + LLOG("Stack full: running in the main thread"); + p.lock.Leave(); + cb(); + return; + } + MJob job; + job.cb = cb; + job.work = this; + p.jobs.Add(job); + todo++; + LLOG("Adding job; todo: " << todo << " (CoWork " << FormatIntHex(this) << ")"); + if(p.waiting_threads) { + LLOG("Releasing thread waiting for job: " << p.waiting_threads); + p.waiting_threads--; + p.waitforjob.Release(); + } + p.lock.Leave(); +#else + cb(); +#endif +} + +void CoWork::Finish() { +#ifdef _MULTITHREADED + Pool &p = pool(); + p.lock.Enter(); + while(todo) { + LLOG("Finish: todo: " << todo << " (CoWork " << FormatIntHex(this) << ")"); + if(todo == 0) + break; + if(p.jobs.GetCount()) + Pool::DoJob(); + else { + p.lock.Leave(); + LLOG("WaitForFinish (CoWork " << FormatIntHex(this) << ")"); + waitforfinish.Wait(); + p.lock.Enter(); + } + } + p.lock.Leave(); + LLOG("CoWork finished"); +#endif +} + +CoWork::CoWork() +{ + LLOG("CoWork constructed " << FormatHex(this)); + todo = 0; +} + +CoWork::~CoWork() +{ + Finish(); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/CoWork.h b/uppdev/CoreTopics/CoWork.h new file mode 100644 index 000000000..2487136c5 --- /dev/null +++ b/uppdev/CoreTopics/CoWork.h @@ -0,0 +1,54 @@ +#ifdef _MULTITHREADED + +class CoWork : NoCopy { + typedef StaticCriticalSection Lock; + + struct MJob : Moveable { + Callback cb; + CoWork *work; + }; + + struct Pool { + Vector jobs; + int waiting_threads; + Array threads; + + CriticalSection lock; + Semaphore waitforjob; + + Pool(); + ~Pool(); + + static bool DoJob(); + static void ThreadRun(int tno); + }; + + friend struct Pool; + + static Pool& pool(); + + Semaphore waitforfinish; + int todo; + +public: + void Do(Callback cb); + CoWork& operator&(Callback cb) { Do(cb); return *this; } + + void Finish(); + + CoWork(); + ~CoWork(); + + static void Quit(); +}; + +#else + +class CoWork : NoCopy { +public: + void Do(Callback cb) { cb(); } + CoWork& operator&(Callback cb) { cb(); return *this; } + void Finish() {} +}; + +#endif diff --git a/uppdev/CoreTopics/Color.cpp b/uppdev/CoreTopics/Color.cpp new file mode 100644 index 000000000..04e813d93 --- /dev/null +++ b/uppdev/CoreTopics/Color.cpp @@ -0,0 +1,132 @@ +#include "Core.h" + +NAMESPACE_UPP + +void RGBtoHSV(double r, double g, double b, double& h, double& s, double& v) +{ + double delta; + if((v = max(r, max(g, b))) == 0 || (delta = v - min(r, min(g, b))) == 0) + { + h = s = 0; + return; + } + s = delta / v; + delta *= 6; + if(g == v) + h = 1 / 3.0 + (b - r) / delta; + else if(b == v) + h = 2 / 3.0 + (r - g) / delta; + else + if((h = (g - b) / delta) < 0) + h += 1; +} + +void HSVtoRGB(double h, double s, double v, double& r, double& g, double& b) +{ + if(s == 0) + { + r = g = b = v; + return; + } + double rem = fmod(h *= 6, 1); + double p = v * (1 - s); + double q = v * (1 - s * rem); + double t = v * (1 - s * (1 - rem)); + switch(ffloor(h)) + { + default: NEVER(); // invalid color! + case 6: + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case -1: + case 5: r = v; g = p; b = q; break; + } +} + +Color HsvColorf(double h, double s, double v) +{ + double r, g, b; + HSVtoRGB(h, s, v, r, g, b); + return Color(min(int(r * 255), 255), min(int(g * 255), 255), min(int(b * 255), 255)); +} + +dword Color::Get() const +{ + if(IsNullInstance()) return 0; + dword c = color; + return c & 0xffffff; +} + +Color::operator RGBA() const +{ + RGBA color; + if(IsNullInstance()) + Zero(color); + else { + color.r = GetR(); + color.g = GetG(); + color.b = GetB(); + color.a = 255; + } + return color; +} + +Color::Color(RGBA rgba) +{ + if(rgba.a == 0) + color = 0xffffffff; + else { + if(rgba.a == 255) + color = RGB(rgba.r, rgba.g, rgba.b); + else { + int alpha = 65536 / rgba.a; + color = RGB((alpha * rgba.r) >> 8, (alpha * rgba.g) >> 8, (alpha * rgba.b) >> 8); + } + } +} + +RGBA operator*(int alpha, Color c) +{ + RGBA r; + r.a = alpha; + alpha += (alpha >> 7); + r.r = (alpha * c.GetR()) >> 8; + r.g = (alpha * c.GetG()) >> 8; + r.b = (alpha * c.GetB()) >> 8; + return r; +} + +template<> +String AsString(const Color& c) { + if(IsNull(c)) + return "Color(Null)"; + return Format("Color(%d, %d, %d)", c.GetR(), c.GetG(), c.GetB()); +} + +String ColorToHtml(Color color) +{ + return Format("#%02X%02X%02X", color.GetR(), color.GetG(), color.GetB()); +} + +Color Blend(Color c1, Color c2, int alpha) +{ + int a = (alpha >> 7) + alpha; + return Color(min(((a * (c2.GetR() - c1.GetR())) >> 8) + c1.GetR(), 255), + min(((a * (c2.GetG() - c1.GetG())) >> 8) + c1.GetG(), 255), + min(((a * (c2.GetB() - c1.GetB())) >> 8) + c1.GetB(), 255)); +} + + +INITBLOCK { + RichValue::Register(); +} + +int Grayscale(const Color& c) +{ + return (77 * c.GetR() + 151 * c.GetG() + 28 * c.GetB()) >> 8; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Color.h b/uppdev/CoreTopics/Color.h new file mode 100644 index 000000000..d702bb54f --- /dev/null +++ b/uppdev/CoreTopics/Color.h @@ -0,0 +1,132 @@ +#ifdef PLATFORM_WIN32 +struct RGBA : Moveable { + byte b, g, r, a; +}; +#endif + +#ifdef PLATFORM_POSIX +#ifdef CPU_BE +struct RGBA : Moveable { + byte a, r, g, b; +}; +#else +struct RGBA : Moveable { + byte b, g, r, a; +}; +#endif +#endif + +#ifndef PLATFORM_WIN32 +inline int GetRValue(dword c) { return (byte)(c >> 0); } +inline int GetGValue(dword c) { return (byte)(c >> 8); } +inline int GetBValue(dword c) { return (byte)(c >> 16); } +inline dword RGB(byte r, byte g, byte b) { return r | (g << 8) | (b << 16); } +#endif + +const int COLOR_V = 39; + +class Color : AssignValueTypeNo > { +protected: + dword color; + + dword Get() const; + +public: + dword GetRaw() const { return color; } + + int GetR() const { return GetRValue(Get()); } + int GetG() const { return GetGValue(Get()); } + int GetB() const { return GetBValue(Get()); } + + bool IsNullInstance() const { return color == 0xffffffff; } + unsigned GetHashValue() const { return color; } + bool operator==(Color c) const { return color == c.color; } + bool operator!=(Color c) const { return color != c.color; } + + void Serialize(Stream& s) { s % color; } + + Color() { color = 0xffffffff; } + Color(int r, int g, int b) { color = RGB(r, g, b); } + Color(int n, int) { color = 0x80000000 | n; } + + Color(const Nuller&) { color = 0xffffffff; } + + operator Value() const { return RichValue(*this); } + Color(const Value& q) { color = RichValue::Extract(q).color; } + + operator RGBA() const; + Color(RGBA rgba); + + Color(Color (*fn)()) { color = (*fn)().color; } + + static Color FromRaw(dword co) { Color c; c.color = co; return c; } + +#ifdef PLATFORM_WIN32 + operator COLORREF() const { return (COLORREF) Get(); } + static Color FromCR(COLORREF cr) { Color c; c.color = (dword)cr; return c; } +#else + operator dword() const { return Get(); } +#endif +}; + +RGBA operator*(int alpha, Color c); + +inline Color StraightColor(RGBA rgba) { return Color(rgba.r, rgba.g, rgba.b); } + +typedef Color (*ColorF)(); + +inline unsigned GetHashValue(Color c) { return c.GetHashValue(); } +inline Color Nvl(Color a, Color b) { return IsNull(a) ? b : a; } + +template<> +String AsString(const Color& c); + + +inline Color GrayColor(int a = 128) { return Color(a, a, a); } + +inline Color Black() { return Color(0, 0, 0); } +inline Color Gray() { return Color(128, 128, 128); } +inline Color LtGray() { return Color(192, 192, 192); } +inline Color WhiteGray() { return Color(224, 224, 224); } +inline Color White() { return Color(255, 255, 255); } + +inline Color Red() { return Color(128, 0, 0); } +inline Color Green() { return Color(0, 128, 0); } +inline Color Brown() { return Color(128, 128, 0); } +inline Color Blue() { return Color(0, 0, 128); } +inline Color Magenta() { return Color(128, 0, 255); } +inline Color Cyan() { return Color(0, 128, 128); } +inline Color Yellow() { return Color(255, 255, 0); } +inline Color LtRed() { return Color(255, 0, 0); } +inline Color LtGreen() { return Color(0, 255, 0); } +inline Color LtYellow() { return Color(255, 255, 192); } +inline Color LtBlue() { return Color(0, 0, 255); } +inline Color LtMagenta() { return Color(255, 0, 255); } +inline Color LtCyan() { return Color(0, 255, 255); } + +void RGBtoHSV(double r, double g, double b, double& h, double& s, double& v); +void HSVtoRGB(double h, double s, double v, double& r, double& g, double& b); + +Color HsvColorf(double h, double s, double v); + +Color Blend(Color c1, Color c2, int alpha = 128); + +String ColorToHtml(Color color); + +int Grayscale(const Color& c); + + +inline bool operator==(const Value& v, Color x) { return v == x.operator Value(); } +inline bool operator==(Color x, const Value& v) { return v == x.operator Value(); } +inline bool operator!=(const Value& v, Color x) { return v != x.operator Value(); } +inline bool operator!=(Color x, const Value& v) { return v != x.operator Value(); } + +inline bool operator==(const Value& v, Color (*x)()) { return v == (*x)(); } +inline bool operator==(Color (*x)(), const Value& v) { return v == (*x)(); } +inline bool operator!=(const Value& v, Color (*x)()) { return v != (*x)(); } +inline bool operator!=(Color (*x)(), const Value& v) { return v != (*x)(); } + +inline bool operator==(Color c, Color (*x)()) { return c == (*x)(); } +inline bool operator==(Color (*x)(), Color c) { return c == (*x)(); } +inline bool operator!=(Color c, Color (*x)()) { return c != (*x)(); } +inline bool operator!=(Color (*x)(), Color c) { return c != (*x)(); } diff --git a/uppdev/CoreTopics/Convert.cpp b/uppdev/CoreTopics/Convert.cpp new file mode 100644 index 000000000..086e40a9a --- /dev/null +++ b/uppdev/CoreTopics/Convert.cpp @@ -0,0 +1,528 @@ +#include "Core.h" + +NAMESPACE_UPP + +unsigned stou(const char *s, void *endptr, unsigned base) +{ + ASSERT(base >= 2 && base <= 36); + unsigned digit = ctoi(*s); + if(digit >= base) + { // error + if(endptr) + *(const char **)endptr = s; + return ~0; + } + unsigned value = digit; + while((digit = ctoi(*++s)) < base) + value = value * base + digit; + if(endptr) + *(const char **)endptr = s; + return value; +} + +unsigned stou(const wchar *s, void *endptr, unsigned base) +{ + ASSERT(base >= 2 && base <= 36); + unsigned digit = ctoi(*s); + if(digit >= base) + { // error + if(endptr) + *(const wchar **)endptr = s; + return ~0; + } + unsigned value = digit; + while((digit = ctoi(*++s)) < base) + value = value * base + digit; + if(endptr) + *(const wchar **)endptr = s; + return value; +} + + +uint64 stou64(const char *s, void *endptr, unsigned base) +{ + ASSERT(base >= 2 && base <= 36); + unsigned digit = ctoi(*s); + if(digit >= base) + { // error + if(endptr) + *(const char **)endptr = s; + return ~0; + } + uint64 value = digit; + while((digit = ctoi(*++s)) < base) + value = value * base + digit; + if(endptr) + *(const char **)endptr = s; + return value; +} + +int ScanInt(const char *ptr, const char **endptr, int base) +{ + const char *s = ptr; + bool minus = false; + while(*s && (byte)*s <= ' ') + s++; + if(*s == '+' || *s == '-') + minus = (*s++ == '-'); + unsigned u = stou(s, endptr, base); + if(~u) + return (minus ? -(int)u : (int)u); + else + return Null; +} + +int ScanInt(const wchar *ptr, const wchar **endptr, int base) +{ + const wchar *s = ptr; + bool minus = false; + while(*s && *s <= ' ') + s++; + if(*s == '+' || *s == '-') + minus = (*s++ == '-'); + unsigned u = stou(s, endptr, base); + if(~u) + return (minus ? -(int)u : (int)u); + else + return Null; +} + +int64 ScanInt64(const char *ptr, const char **endptr, int base) +{ + const char *s = ptr; + bool minus = false; + while(*s && *s <= ' ') + s++; + if(*s == '+' || *s == '-') + minus = (*s++ == '-'); + uint64 u = stou64(s, endptr, base); + if(~u) + return (minus ? -(int64)u : (int64)u); + else + return Null; +} + +double ScanDouble(const char *p, const char **endptr, bool accept_comma) +{ + const char *begin = p; + while(*p && (byte)*p <= ' ') + p++; + bool neg = false; + if(*p == '+' || *p == '-') + neg = (*p++ == '-'); + if((byte)(*p - '0') >= 10 && !((*p == '.' || accept_comma && *p == ',') && (byte)(p[1] - '0') < 10)) { + if(endptr) *endptr = begin; + return Null; + } + double mantissa = 0; + char c; + int exp = 0; + while((byte)(*p - '0') < 10) + if((c = *p++) != '0') { + if(exp) { mantissa *= ipow10(exp); exp = 0; } + mantissa = 10 * mantissa + c - '0'; + } + else + exp++; + int raise = exp; + if(*p == '.' || accept_comma && *p == ',') // decimal part + while((byte)((c = *++p) - '0') < 10) + if(c != '0') { + if(raise) { mantissa *= ipow10(raise); exp -= raise; raise = 0; } + exp--; + mantissa = 10 * mantissa + c - '0'; + } + else + raise++; + if(*p == 'E' || *p == 'e') { // exponent + int vexp = ScanInt(p + 1, endptr); + if(!IsNull(vexp)) + exp += vexp; + } + else + if(endptr) *endptr = p; + if(exp) { + double e = ipow10(tabs(exp)); + mantissa = (exp > 0 ? mantissa * e : mantissa / e); + } + return neg ? -mantissa : mantissa; +} + +double ScanDouble(const wchar *p, const wchar **endptr, bool accept_comma) +{ + const wchar *begin = p; + while(*p && *p <= ' ') + p++; + bool neg = false; + if(*p == '+' || *p == '-') + neg = (*p++ == '-'); + if((unsigned)(*p - '0') >= 10) { + if(endptr) *endptr = begin; + return Null; + } + double mantissa = 0; + wchar c; + int exp = 0; + while((unsigned)(*p - '0') < 10) + if((c = *p++) != '0') { + if(exp) { mantissa *= ipow10(exp); exp = 0; } + mantissa = 10 * mantissa + c - '0'; + } + else + exp++; + int raise = exp; + if(*p == '.' || accept_comma && *p == ',') // decimal part + while((unsigned)((c = *++p) - '0') < 10) + if(c != '0') { + if(raise) { mantissa *= ipow10(raise); exp -= raise; raise = 0; } + exp--; + mantissa = 10 * mantissa + c - '0'; + } + else + raise++; + if(*p == 'E' || *p == 'e') { // exponent + int vexp = ScanInt(p + 1, endptr); + if(!IsNull(vexp)) + exp += vexp; + } + else + if(endptr) *endptr = p; + if(exp) { + double e = ipow10(tabs(exp)); + mantissa = (exp > 0 ? mantissa * e : mantissa / e); + } + return neg ? -mantissa : mantissa; +} + +Value StrIntValue(const char *s) +{ + if(s && *s) { + int64 q = ScanInt64(s); + return IsNull(q) ? ErrorValue(t_("Invalid number !")) : Value(q); + } + return Null; +} + +Value StrDblValue(const char *s) +{ + if(s && *s) { + double q = ScanDouble(s); + return IsNull(q) ? ErrorValue(t_("Invalid number !")) : Value(q); + } + return Null; +} + +Value Scan(dword qtype, const String& text) { + Date date; + const char *s; + switch(qtype) { + case INT64_V: + case INT_V: + case BOOL_V: + return StrIntValue(text); + case DATE_V: + if(text.IsEmpty()) return (Date) Null; + s = StrToDate(date, text); + if(s) + for(;;) { + if(IsDigit(*s)) + break; + if(*s == '\0') + return date; + s++; + } + return ErrorValue(t_("Invalid date !")); + case TIME_V: { + if(text.IsEmpty()) return (Time) Null; + s = StrToDate(date, text); + if(s) + try { + CParser p(s); + Time tm = ToTime(date); + if(p.IsEof()) + return tm; + int q = p.ReadInt(); + if(q < 0 || q > 23) + throw CParser::Error(""); + tm.hour = q; + if(p.IsEof()) + return tm; + p.PassChar(':'); + q = p.ReadInt(); + if(q < 0 || q > 59) + throw CParser::Error(""); + tm.minute = q; + if(p.IsEof()) + return tm; + p.PassChar(':'); + q = p.ReadInt(); + if(q < 0 || q > 59) + throw CParser::Error(""); + tm.second = q; + if(p.IsEof()) + return tm; + } + catch(CParser::Error) {} + return ErrorValue(t_("Invalid time !")); + } + case STRING_V: + case WSTRING_V: + return text; + case DOUBLE_V: + return StrDblValue(text); + default: + ASSERT(0); + break; + } + return Null; +} + +#ifdef flagSO +Convert::Convert() {} +Convert::~Convert() {} +#endif + +Value Convert::Format(const Value& q) const { + if(IsVoid(q) || q.IsNull()) return String(); + switch(q.GetType()) { + case INT64_V: + return IntStr64((int64)q); + case INT_V: + case BOOL_V: + return IntStr((int)q); + case DOUBLE_V: + return DblStr((double)q); + case DATE_V: + return UPP::Format(Date(q)); + case TIME_V: + return UPP::Format(Time(q)); + case STRING_V: + case WSTRING_V: + return q; + } + return q.ToString(); +} + +Value Convert::Scan(const Value& text) const { + return text; +}; + +int Convert::Filter(int chr) const { + return chr; +} + +GLOBAL_VAR_INIT(const Convert, StdConvert); + +String StdFormat(const Value& q) { + return StdConvert().Format(q); +} + +Value NotNullError() { + return ErrorValue(t_("Null value not allowed.")); +} + +#ifdef flagSO +ConvertInt::ConvertInt(int minval, int maxval, bool notnull) +: minval(minval), maxval(maxval), notnull(notnull) {} +ConvertInt::~ConvertInt() {} + +ConvertInt64::ConvertInt64(int64 minval, int64 maxval, bool notnull) { + MinMax(minval, maxval); NotNull(notnull); +} +ConvertInt64::~ConvertInt64() {} +#endif + +Value ConvertInt::Scan(const Value& text) const { + Value v = UPP::Scan(INT_V, text); + if(IsError(v)) return v; + if(IsNull(v)) return notnull ? NotNullError() : v; + int64 m = v; + if(m >= minval && m <= maxval) return v; + return ErrorValue(UPP::Format(t_("Number must be between %d and %d."), minval, maxval)); +} + +int ConvertInt::Filter(int chr) const { + return minval >= 0 ? CharFilterDigit(chr) : CharFilterInt(chr); +} + +Value ConvertDouble::Format(const Value& q) const +{ + if(IsNull(q)) + return Null; + return UPP::NFormat(pattern, (double)q); +} + +Value ConvertDouble::Scan(const Value& text) const { + Value v = UPP::Scan(DOUBLE_V, text); + if(IsError(v)) return v; + if(IsNull(v)) return notnull ? NotNullError() : v; + double m = v; + if(m >= minval && m <= maxval) return v; + return ErrorValue(UPP::Format(t_("Number must be between %g and %g."), minval, maxval)); +} + +int ConvertDouble::Filter(int chr) const { + return CharFilterDouble(chr); +} + +ConvertDouble::ConvertDouble(double minval, double maxval, bool notnull) + : minval(minval), maxval(maxval), notnull(notnull) +{ + pattern = "%.10g"; +} + +#ifdef flagSO +ConvertDouble::~ConvertDouble() {} +#endif + +ConvertDate::ConvertDate(Date minval, Date maxval, bool notnull) +: minval(minval), maxval(maxval), notnull(notnull) {} + +ConvertDate::~ConvertDate() +{ +} + +Value ConvertDate::Scan(const Value& text) const { + Value v = UPP::Scan(DATE_V, text); + if(IsError(v)) return v; + if(IsNull(v)) return notnull ? NotNullError() : v; + Date m = v; + if(m >= minval && m <= maxval) return v; + return ErrorValue(t_("Date must be between ") + UPP::Format(minval) + t_("range\v and ") + UPP::Format(maxval) + "."); +} + +int ConvertDate::Filter(int chr) const { + return CharFilterDate(chr); +} + +ConvertTime::ConvertTime(Time minval, Time maxval, bool notnull) +: minval(minval), maxval(maxval), notnull(notnull), seconds(true) {} + +ConvertTime::~ConvertTime() +{ +} + +Value ConvertTime::Scan(const Value& text) const +{ + Value v = UPP::Scan(TIME_V, text); + if(IsError(v)) return v; + if(IsNull(v)) return notnull ? NotNullError() : v; + Time m = v; + if(m >= minval && m <= maxval) return v; + return ErrorValue(t_("Time must be between ") + UPP::Format(minval) + t_("range\v and ") + UPP::Format(maxval) + "."); +} + +int ConvertTime::Filter(int chr) const +{ + if(IsDigit(chr) || chr == ' ' || chr == '.' || chr == ':') + return chr; + if(chr == ',') + return '.'; + return 0; +} + +Value ConvertTime::Format(const Value& q) const +{ + if(IsVoid(q) || q.IsNull()) + return String(); + else if(q.GetType() == TIME_V) + return UPP::Format(Time(q), seconds); + else + return Convert::Format(q); +} + +#ifdef flagSO +ConvertString::ConvertString(int maxlen, bool notnull) : maxlen(maxlen), notnull(notnull) {} +ConvertString::~ConvertString() {} +#endif + +Value ConvertString::Scan(const Value& text) const { + if(IsError(text)) return text; + if(IsNull(text)) return notnull ? NotNullError() : Value(text); + if(text.GetType() == STRING_V && String(text).GetLength() <= maxlen || + text.GetType() == WSTRING_V && WString(text).GetLength() <= maxlen) return text; + return ErrorValue(UPP::Format(t_("Please enter no more than %d characters."), maxlen)); +} + +GLOBAL_VAR_INIT(const ConvertInt, StdConvertInt) +GLOBAL_VARP_INIT(const ConvertInt, StdConvertIntNotNull, (-INT_MAX, INT_MAX, true)) +GLOBAL_VAR_INIT(const ConvertDouble, StdConvertDouble) +GLOBAL_VARP_INIT(const ConvertDouble, StdConvertDoubleNotNull, + (-DOUBLE_NULL_LIM, DOUBLE_NULL_LIM, true)) +GLOBAL_VAR_INIT(const ConvertDate, StdConvertDate) +GLOBAL_VARP_INIT(const ConvertDate, StdConvertDateNotNull, (Date(0, 0, 0), Date(3000, 12, 31), true)) +GLOBAL_VAR_INIT(const ConvertTime, StdConvertTime) +GLOBAL_VARP_INIT(const ConvertTime, StdConvertTimeNotNull, (Null, Null, true)) +GLOBAL_VAR_INIT(const ConvertString, StdConvertString); +GLOBAL_VARP_INIT(const ConvertString, StdConvertStringNotNull, (INT_MAX, true)) + +Value MapConvert::Format(const Value& q) const { + return map.Get(q, Null); +} + +Value NoConvertClass::Format(const Value& q) const { + return q; +} + +GLOBAL_VAR_INIT(const NoConvertClass, NoConvert) + +Value JoinConvert::Format(const Value& v) const { + String r; + ValueArray a = v; + for(int i = 0; i < item.GetCount(); i++) { + const Item& m = item[i]; + if(m.pos < 0) + r << m.text; + else + r << (String) StdConvert().Format(m.convert->Format(a[m.pos])); + } + return r; +} + +int JoinConvert::NextPos() const { + for(int i = item.GetCount() - 1; i >= 0; i--) + if(item[i].pos >= 0) return item[i].pos + 1; + return 0; +} + +JoinConvert& JoinConvert::Add(const char *text) { + Item& m = item.Add(); + m.pos = -1; + m.text = text; + return *this; +} + +JoinConvert& JoinConvert::Add(int pos, const Convert& cv) { + ASSERT(pos >= 0); + Item& m = item.Add(); + m.pos = pos; + m.convert = &cv; + return *this; +} + +JoinConvert& JoinConvert::Add(int pos) { + Add(pos, StdConvert()); + return *this; +} + +JoinConvert& JoinConvert::Add(const Convert& cv) { + Add(NextPos(), cv); + return *this; +} + +JoinConvert& JoinConvert::Add() { + Add(NextPos()); + return *this; +} + +Value FormatConvert::Format(const Value& v) const +{ + ValueArray va; + if(IsValueArray(v)) + va = v; + else + va.Add(v); + return UPP::Format(format, va.Get()); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Convert.h b/uppdev/CoreTopics/Convert.h new file mode 100644 index 000000000..b275b1500 --- /dev/null +++ b/uppdev/CoreTopics/Convert.h @@ -0,0 +1,264 @@ +unsigned stou(const char *ptr, void *endptr = NULL, unsigned base = 10); +inline unsigned stou(const byte *ptr, void *endptr = NULL, unsigned base = 10) { return stou((const char *)ptr, endptr, base); } +unsigned stou(const wchar *ptr, void *endptr = NULL, unsigned base = 10); + +uint64 stou64(const char *s, void *endptr = NULL, unsigned base = 10); +uint64 stou64(const wchar *s, void *endptr = NULL, unsigned base = 10); + +int ScanInt(const char *ptr, const char **endptr = NULL, int radix = 10); +int ScanInt(const wchar *ptr, const wchar **endptr = NULL, int radix = 10); + +int64 ScanInt64(const char *ptr, const char **endptr = NULL, int base = 10); + +double ScanDouble(const char *ptr, const char **endptr = NULL, bool accept_comma = true); +double ScanDouble(const wchar *ptr, const wchar **endptr = NULL, bool accept_comma = true); + +Value StrIntValue(const char *s); +inline int StrInt(const char* s) { return ScanInt(s); } +inline double IntDbl(int i) { return IsNull(i) ? double(Null) : double(i); } +inline int DblInt(double d) { return IsNull(d) ? int(Null) : fround(d); } +Value StrDblValue(const char* s); +inline double StrDbl(const char* s) { return ScanDouble(s); } + +Value NotNullError(); + +class Convert { +public: +#ifdef flagSO + Convert(); + virtual ~Convert(); +#else + virtual ~Convert() {} +#endif + + virtual Value Format(const Value& q) const; + virtual Value Scan(const Value& text) const; + virtual int Filter(int chr) const; + + Value operator()(const Value& q) const { return Format(q); } +}; + +const Convert& StdConvert(); + +String StdFormat(const Value& q); + +class ConvertInt : public Convert { +public: + virtual Value Scan(const Value& text) const; + virtual int Filter(int chr) const; + +protected: + int64 minval, maxval; + bool notnull; + +public: + ConvertInt& MinMax(int _min, int _max) { minval = _min; maxval = _max; return *this; } + ConvertInt& Min(int _min) { minval = _min; return *this; } + ConvertInt& Max(int _max) { maxval = _max; return *this; } + ConvertInt& NotNull(bool b = true) { notnull = b; return *this; } + ConvertInt& NoNotNull() { return NotNull(false); } + int GetMin() const { return (int)minval; } + int GetMax() const { return (int)maxval; } + bool IsNotNull() const { return notnull; } + +#ifdef flagSO + ConvertInt(int minval = -INT_MAX, int maxval = INT_MAX, bool notnull = false); + virtual ~ConvertInt(); +#else + ConvertInt(int minval = -INT_MAX, int maxval = INT_MAX, bool notnull = false) + : minval(minval), maxval(maxval), notnull(notnull) {} +#endif +}; + +const ConvertInt& StdConvertInt(); +const ConvertInt& StdConvertIntNotNull(); + +struct ConvertInt64 : public ConvertInt { + ConvertInt& MinMax(int64 _min, int64 _max) { minval = _min; maxval = _max; return *this; } + ConvertInt& Min(int64 _min) { minval = _min; return *this; } + ConvertInt& Max(int64 _max) { maxval = _max; return *this; } + int64 GetMin() const { return minval; } + int64 GetMax() const { return maxval; } + +#ifdef flagSO + ConvertInt64(int64 minval = -INT64_MAX, int64 maxval = INT64_MAX, bool notnull = false); + virtual ~ConvertInt64(); +#else + ConvertInt64(int64 minval = -INT64_MAX, int64 maxval = INT64_MAX, bool notnull = false) { + MinMax(minval, maxval); NotNull(notnull); + } +#endif +}; + +class ConvertDouble : public Convert { +public: + virtual Value Format(const Value& q) const; + virtual Value Scan(const Value& text) const; + virtual int Filter(int chr) const; + +protected: + double minval, maxval; + bool notnull; + String pattern; + +public: + ConvertDouble& Pattern(const char *p) { pattern = p; return *this; } + ConvertDouble& MinMax(double _min, double _max) { minval = _min; maxval = _max; return *this; } + ConvertDouble& Min(double _min) { minval = _min; return *this; } + ConvertDouble& Max(double _max) { maxval = _max; return *this; } + ConvertDouble& NotNull(bool b = true) { notnull = b; return *this; } + ConvertDouble& NoNotNull() { return NotNull(false); } + double GetMin() const { return minval; } + double GetMax() const { return maxval; } + bool IsNotNull() const { return notnull; } + + ConvertDouble(double minval = DOUBLE_NULL_LIM, double maxval = -DOUBLE_NULL_LIM, + bool notnull = false); +#ifdef flagSO + virtual ~ConvertDouble(); +#endif +}; + +const ConvertDouble& StdConvertDouble(); +const ConvertDouble& StdConvertDoubleNotNull(); + +class ConvertDate : public Convert { +public: + virtual Value Scan(const Value& text) const; + virtual int Filter(int chr) const; + +protected: + Date minval, maxval; + bool notnull; + +public: + ConvertDate& MinMax(Date _min, Date _max) { minval = _min; maxval = _max; return *this; } + ConvertDate& Min(Date _min) { minval = _min; return *this; } + ConvertDate& Max(Date _max) { maxval = _max; return *this; } + ConvertDate& NotNull(bool b = true) { notnull = b; return *this; } + ConvertDate& NoNotNull() { return NotNull(false); } + Date GetMin() const { return minval; } + Date GetMax() const { return maxval; } + bool IsNotNull() const { return notnull; } + + ConvertDate(Date minval = Date::Low(), Date maxval = Date::High(), bool notnull = false); + virtual ~ConvertDate(); +}; + +const ConvertDate& StdConvertDate(); +const ConvertDate& StdConvertDateNotNull(); + +class ConvertTime : public Convert { +public: + virtual Value Scan(const Value& text) const; + virtual int Filter(int chr) const; + virtual Value Format(const Value& q) const; + +protected: + Time minval, maxval; + bool notnull; + bool seconds; + +public: + ConvertTime& MinMax(Time _min, Time _max) { minval = _min; maxval = _max; return *this; } + ConvertTime& NotNull(bool b = true) { notnull = b; return *this; } + ConvertTime& NoNotNull() { return NotNull(false); } + ConvertTime& Seconds(bool b = true) { seconds = b; return *this; } + ConvertTime& NoSeconds() { return Seconds(false); } + Time GetMin() const { return minval; } + Time GetMax() const { return maxval; } + bool IsNotNull() const { return notnull; } + + ConvertTime(Time minval = ToTime(Date::Low()), Time maxval = ToTime(Date::High()), bool notnull = false); + virtual ~ConvertTime(); +}; + +const ConvertTime& StdConvertTime(); +const ConvertTime& StdConvertTimeNotNull(); + +class ConvertString : public Convert { +public: + virtual Value Scan(const Value& text) const; + +protected: + int maxlen; + bool notnull; + +public: + ConvertString& MaxLen(int _maxlen) { maxlen = _maxlen; return *this; } + int GetMaxLength() const { return maxlen; } + ConvertString& NotNull(bool b = true) { notnull = b; return *this; } + ConvertString& NoNotNull() { return NotNull(false); } + bool IsNotNull() const { return notnull; } + +#ifdef flagSO + ConvertString(int maxlen = INT_MAX, bool notnull = false); + virtual ~ConvertString(); +#else + ConvertString(int maxlen = INT_MAX, bool notnull = false) + : maxlen(maxlen), notnull(notnull) {} +#endif +}; + +const ConvertString& StdConvertString(); +const ConvertString& StdConvertStringNotNull(); + +class NoConvertClass : public Convert { +public: + virtual Value Format(const Value& q) const; +}; + +const NoConvertClass& NoConvert(); + +class MapConvert : public Convert { +public: + virtual Value Format(const Value& q) const; + +protected: + VectorMap map; + +public: + void Clear() { map.Clear(); } + MapConvert& Add(const Value& a, const Value& b) { map.Add(a, b); return *this; } + + int GetCount() const { return map.GetCount(); } + int Find(const Value& v) const { return map.Find(v); } + const Value& GetKey(int i) const { return map.GetKey(i); } + const Value& GetValue(int i) const { return map[i]; } + const Value& operator[](int i) const { return map[i]; } + + virtual ~MapConvert() {} +}; + +class JoinConvert : public Convert { +public: + virtual Value Format(const Value& v) const; + +protected: + struct Item { + int pos; + const Convert *convert; + String text; + }; + Array item; + + int NextPos() const; + +public: + JoinConvert& Add(const char *text); + JoinConvert& Add(int pos, const Convert& cv); + JoinConvert& Add(int pos); + JoinConvert& Add(const Convert& cv); + JoinConvert& Add(); +}; + +class FormatConvert : public Convert { +public: + virtual Value Format(const Value& v) const; + +private: + String format; + +public: + void SetFormat(const char *fmt) { format = fmt; } +}; diff --git a/uppdev/CoreTopics/Copying b/uppdev/CoreTopics/Copying new file mode 100644 index 000000000..306c7974b --- /dev/null +++ b/uppdev/CoreTopics/Copying @@ -0,0 +1,30 @@ +Copyright (C) 2005 Mirek Fidler, Tomas Rylek and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----------- + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. diff --git a/uppdev/CoreTopics/Copying-plain b/uppdev/CoreTopics/Copying-plain new file mode 100644 index 000000000..5b4491072 --- /dev/null +++ b/uppdev/CoreTopics/Copying-plain @@ -0,0 +1,33 @@ +Plain English Copyright Notice + +This file is not intended to be the actual License. The reason this file +exists is that we here are programmers and engineers. We aren't lawyers. We +provide licenses that we THINK say the right things, but we have our own +intentions at heart. This is a plain-english explanation of what those +intentions are, and if you follow them you will be within the "spirit" of +the license. + +The intent is for us to enjoy writing software that is useful to us (the +AUTHORS) and allow others to use it freely and also benefit from the work we +put into making it. We don't want to restrict others using it. They should +not *HAVE* to make the source code of the applications they write that +simply link to these libraries (be that statically or dynamically), or for +them to be limited as to what license they choose to use (be it open, closed +or anything else). But we would like to know you are using these libraries. +We simply would like to know that it has been useful to someone. This is why +we ask for acknowledgement of some sort. + +You can do what you want with the source of this software - it doesn't +matter. We still have it here for ourselves and it is open and free to use +and download and play with. It can't be taken away. We don't really mind what +you do with the source to your software. We would simply like to know that +you are using it - especially if it makes it to a commerical product. If you +simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and +then make sure you include a paragraph or page in the manual or in the "About.." +box for the product with the copyright notice and state that you used this +software, we will be very happy. If you want to contribute back modifications +and fixes you may have made we will welcome those too with open arms (generally). +If you want help with changes needed, ports needed or features to be added, +arrangements can be easily made with some dialogue. + +Mirek Fidler diff --git a/uppdev/CoreTopics/Core.h b/uppdev/CoreTopics/Core.h new file mode 100644 index 000000000..fea93088f --- /dev/null +++ b/uppdev/CoreTopics/Core.h @@ -0,0 +1,511 @@ +#ifndef CORE_H +#define CORE_H + +#define QLIB3 + +#if defined(flagMT) + #define _MULTITHREADED + #ifdef flagDLL + #define flagUSEMALLOC + #endif +#endif + +#ifdef flagMSC8ARM + #define PLATFORM_WIN32 + #define PLATFORM_PDA + #define PLATFORM_WINCE + #define CPU_ARM + #define COMPILER_MSC + #define COMPILER_MSC8 + + #ifndef _WIN32_WCE + #define ARM + #define _ARM_ + #define _WIN32_WCE 0x420 + #define WIN32_PLATFORM_PSPC + #define _UNICODE + #define UNICODE + #define UNDER_CE + #endif + + #define CPU_32 + #define CPU_ARM + #define CPU_LE + #define CPU_LITTLE_ENDIAN // is it really? + #define CPU_ALIGNED + + #ifndef _CPPRTTI + #error RTTI must be enabled !!! + #endif // _CPPRTTI + #pragma warning(disable: 4786) + + #define NO_ERRNO_H +#endif + +#ifdef flagLINUX + #define PLATFORM_LINUX + #define PLATFORM_POSIX + #ifdef flagGUI + #define PLATFORM_X11 + #endif + + #ifdef flagTESTLEAKS + #define TESTLEAKS + #endif + +#endif + +#ifdef flagSOLARIS + #define PLATFORM_SOLARIS + #define PLATFORM_POSIX + #define __NOASSEMBLY__ + #ifdef flagGUI + #define PLATFORM_X11 + #endif + + #ifdef flagTESTLEAKS + #define TESTLEAKS + #endif +#endif + +#ifdef flagFREEBSD + #define PLATFORM_FREEBSD + #define PLATFORM_POSIX + #ifdef flagGUI + #define PLATFORM_X11 + #endif + + #ifdef flagTESTLEAKS + #define TESTLEAKS + #endif +#endif + +#ifdef flagOSX11 + #define PLATFORM_OSX11 + #define PLATFORM_POSIX + + #define flagUSEMALLOC // A bug in carbon?! - MacOS X seems to crash when custom allocator is used + + #ifdef flagGUI + #define PLATFORM_X11 + #ifndef flagNOGTK + #define flagNOGTK + #endif + #endif + + #ifdef flagTESTLEAKS + #define TESTLEAKS + #endif + + // defines set by OsX for us. + #ifdef __POWERPC__ + #define flagPOWERPC + #endif + + #ifdef __i386__ + #define flagX86 + #endif + +#endif + +#if defined(flagWIN) || defined(flagWIN32) + #define PLATFORM_WIN32 + #ifdef __CYGWIN__ + #define PLATFORM_CYGWIN + #endif +#endif + +#ifdef _MSC_VER + #define COMPILER_MSC + #ifndef _CPPRTTI + #error RTTI must be enabled !!! + #endif //_CPPRTTI + #if _MSC_VER <= 1300 + #error MSC 6.0 not supported anymore + #endif + #pragma warning(disable: 4786) + #define _CRT_SECURE_NO_DEPRECATE // we really need strcpy etc. to work with MSC 8.0 +#endif + +#ifdef flagGNU + #define COMPILER_GCC + #define COMPILER_GNU + #define COMPILER_GNU2 +#endif + +#ifdef flagGNU3 + #define COMPILER_GCC + #define COMPILER_GNU + #define COMPILER_GNU3 +#endif + +#if defined(flagGCC) || defined(flagGCC32) + #define COMPILER_GCC + #define COMPILER_GNU + #define COMPILER_GNU3 + #define __NOASSEMBLY__ +#endif + +#ifdef flagDM + #define COMPILER_DM +#endif + +#ifdef flagOSTRING + #define OSTRING +#endif + +#ifdef flagHEAPDBG + #define HEAPDBG +#endif + +#if defined(flagDEBUG) + #ifndef _DEBUG + #define _DEBUG + #endif + #ifndef TESTLEAKS + #define TESTLEAKS + #endif + #ifndef HEAPDBG + #define HEAPDBG + #endif +#else + #ifndef _RELEASE + #define _RELEASE + #endif +#endif + +#ifdef flagDLL + #define _USRDLL +#endif + +#ifdef flagEXPERIMENTAL + #define EXPERIMENTAL +#endif + +#ifdef flagNEWSTRING + #define NEWSTRING +#endif + +#if defined(flagSPARC) + #define CPU_32 + #define CPU_SPARC + #define CPU_BE + #define CPU_BIG_ENDIAN + #define CPU_ALIGNED +#elif defined(flagARM) || defined(ARM) + #define CPU_32 + #define CPU_ARM + #define CPU_LE + #define CPU_LITTLE_ENDIAN // is it really? + #define CPU_ALIGNED +#elif defined(flagPOWERPC) + #define CPU_32 + #define CPU_POWERPC + #define CPU_BE + #define CPU_BIG_ENDIAN + #define CPU_ALIGNED +#else + #define CPU_X86 + #if defined(__amd64) || defined(_WIN64) + #define CPU_AMD64 + #define CPU_64 + #define __NOASSEMBLY__ + #define CPU_SSE2 + #else + #define CPU_IA32 + #define CPU_32 + #ifdef flagSSE2 + #define CPU_SSE2 + #endif + #endif + #define CPU_LE + #define CPU_LITTLE_ENDIAN + #define CPU_UNALIGNED +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PLATFORM_POSIX) + #define DIR_SEP '/' + #define DIR_SEPS "/" + #define PLATFORM_PATH_HAS_CASE 1 + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #ifdef PLATFORM_SOLARIS + #include + #else + #include + #endif +#endif //PLATFORM_POSIX + +#ifdef PLATFORM_POSIX +#define LOFF_T_ off_t +#define LSEEK64_ lseek +#define FTRUNCATE64_ ftruncate +#endif + +#ifdef PLATFORM_LINUX +#undef LOFF_T_ +#define LOFF_T_ loff_t +#undef LSEEK64_ +#define LSEEK64_ lseek64 +#undef FTRUNCATE64_ +#define FTRUNCATE64_ ftruncate64 +#endif + +#ifdef PLATFORM_WIN32 + + #if defined(COMPILER_MSC) && defined(CPU_X86) + #pragma warning(disable: 4035) + #else + #ifndef __NOASSEMBLY__ + #define __NOASSEMBLY__ + #endif + #endif + + #define DIR_SEP '\\' + #define DIR_SEPS "\\" + #define PLATFORM_PATH_HAS_CASE 0 + #ifndef PLATFORM_WINCE + #include + #endif + #ifndef PLATFORM_MFC // just mini Windows headers + #ifdef COMPILER_MSC + #ifndef CPU_ARM + #ifndef CPU_AMD64 + #ifndef _X86_ + #define _X86_ + #endif + #else + #ifndef _AMD64_ + #define _AMD64_ + #endif + #ifndef __NOASSEMBLY__ + #define __NOASSEMBLY__ + #endif + #ifndef WIN64 + #define WIN64 + #endif + #endif + #endif + #ifndef _WINDOWS_ + #define _WINDOWS_ + #endif + #ifndef _INC_WINDOWS + #define _INC_WINDOWS + #endif + #ifndef _STRUCT_NAME + #define _STRUCT_NAME(x) + #define DUMMYSTRUCTNAME + #define DUMMYSTRUCTNAME2 + #define DUMMYSTRUCTNAME3 + #endif + #ifndef NO_STRICT + #ifndef STRICT + #define STRICT 1 + #endif + #endif + #include + #include + #include + #include + #include + #define byte win32_byte_ // RpcNdr defines byte -> class with Upp::byte + #define CY win32_CY_ + #include + #include + #undef byte + #undef CY + typedef DWORD LCTYPE; + #else + #define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ + #include + #include + #endif + #include + #endif + + #ifdef RGBA + #undef RGBA + #endif +#endif + +#include +#include + +// fix MSC8 beta problem.... +#ifdef COMPILER_MSC +#ifndef PLATFORM_WINCE +namespace std { + inline void __cdecl _Debug_message(const wchar_t *, const wchar_t *, unsigned int line) {} +}; +#endif +#endif + +namespace Upp {}; + +#ifdef flagNONAMESPACE +#define NAMESPACE_UPP +#define END_UPP_NAMESPACE +#define UPP +#else +#define NAMESPACE_UPP namespace Upp { +#define END_UPP_NAMESPACE }; +#define UPP Upp +#endif + +NAMESPACE_UPP + +#include + +END_UPP_NAMESPACE + +#ifdef UPP_HEAP +#include + +inline void *operator new(size_t size) throw(std::bad_alloc) { void *ptr = UPP::MemoryAlloc(size); return ptr; } +inline void operator delete(void *ptr) throw() { UPP::MemoryFree(ptr); } + +inline void *operator new[](size_t size) throw(std::bad_alloc) { void *ptr = UPP::MemoryAlloc(size); return ptr; } +inline void operator delete[](void *ptr) throw() { UPP::MemoryFree(ptr); } + +inline void *operator new(size_t size, const std::nothrow_t&) throw() { void *ptr = UPP::MemoryAlloc(size); return ptr; } +inline void operator delete(void *ptr, const std::nothrow_t&) throw() { UPP::MemoryFree(ptr); } + +inline void *operator new[](size_t size, const std::nothrow_t&) throw() { void *ptr = UPP::MemoryAlloc(size); return ptr; } +inline void operator delete[](void *ptr, const std::nothrow_t&) throw() { UPP::MemoryFree(ptr); } + +#endif + +NAMESPACE_UPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#if (defined(HEAPDBG) || defined(TESTLEAKS)) && defined(PLATFORM_POSIX) +extern int sMemDiagInitCount; +#endif + +#ifdef PLATFORM_WIN32 +NTL_MOVEABLE(POINT) +NTL_MOVEABLE(SIZE) +NTL_MOVEABLE(RECT) +#endif + +END_UPP_NAMESPACE + +#if (defined(TESTLEAKS) || defined(HEAPDBG)) && defined(PLATFORM_POSIX) && !defined(PLATFORM_OSX11) && defined(UPP_HEAP) + +//Place it to the begining of each file to be the first function called in whole executable... + +//$- +struct MemDiagCls { + MemDiagCls() { if(!UPP::sMemDiagInitCount++) UPP::MemoryInitDiagnostics(); } + ~MemDiagCls() { if(!--UPP::sMemDiagInitCount) UPP::MemoryDumpLeaks(); } +}; +static const MemDiagCls sMemDiagHelper__upp__; +//$+ + + +#endif + +//some global definitions + +#ifndef STLPORT +inline UPP::int64 abs(UPP::int64 x) { return x < 0 ? -x : x; } +#endif + +void RegisterTopic__(const char *topicfile, const char *topic, const char *title, const UPP::byte *data, int len); + +#ifdef PLATFORM_WIN32 +typedef HMODULE DLLHANDLE; +#else +typedef void *DLLHANDLE; +#endif + +DLLHANDLE LoadDll__(UPP::String& fn, const char *const *names, void *const *procs); +void FreeDll__(DLLHANDLE dllhandle); + +#ifndef flagNONAMESPACE +using Upp::byte; // Dirty solution to Windows.h typedef byte... +#endif + +#ifdef PLATFORM_WIN32 +#define DLLFILENAME "Kernel32.dll" +#define DLIMODULE UnicodeWin32 +#define DLIHEADER +#include + +#define DLLFILENAME "Mpr.dll" +#define DLIMODULE UnicodeWin32Net +#define DLIHEADER +#include +#endif + +#endif //CORE_H diff --git a/uppdev/CoreTopics/Core.t b/uppdev/CoreTopics/Core.t new file mode 100644 index 000000000..85c56f096 --- /dev/null +++ b/uppdev/CoreTopics/Core.t @@ -0,0 +1,1083 @@ +#ifdef _MSC_VER +#pragma setlocale("C") +#endif +// Util.cpp + +T_("Aborted by user.") +csCZ("Operace byla pÅ™eruÅ¡ena uživatelem.") +deDE("Vom Benutzer abgebrochen") +esES("Abortado por el usuario.") +fiFI("Käyttäjän peruuttama.") +frFR("Annulé par l'utilisateur.") +huHU("Megszakította a felhasználó") +itIT("Annullato dall'utente") +plPL("Anulowany przez użytkownika") +roRO("Anulat de către utilizator.") +ruRU("Прервано пользователем") +srSP("Prekinuto od strane korisnika.") +trTR("Kullanıcı tarafından iptal edildi.") +zhCN("用户放弃") +zhTW("ä½¿ç”¨è€…å–æ¶ˆ") + + +// TimeDate.cpp + +T_("date\vSunday") +csCZ("NedÄ›le") +deDE("Sonntag") +esES("Domingo") +fiFI("Sunnuntai") +frFR("Dimanche") +huHU("Vasárnap") +itIT("Domenica") +plPL("Niedziela") +roRO("Duminică") +ruRU("Суббота") +srSP("Nedelja") +trTR("Pazar") +zhCN("星期日") +zhTW("星期日") + +T_("date\vMonday") +csCZ("PondÄ›lí") +deDE("Montag") +esES("Lunes") +fiFI("Maanantai") +frFR("Lundi") +huHU("HétfÅ‘") +itIT("Lunedì") +plPL("PoniedziaÅ‚ek") +roRO("Luni") +ruRU("Понедельник") +srSP("Ponedeljak") +trTR("Pazartesi") +zhCN("星期一") +zhTW("星期一") + +T_("date\vTuesday") +csCZ("Úterý") +deDE("Dienstag") +esES("Martes") +fiFI("Tiistai") +frFR("Mardi") +huHU("Kedd") +itIT("Martedì") +plPL("Wtorek") +roRO("MarÅ£i") +ruRU("Вторник") +srSP("Utorak") +trTR("Salı") +zhCN("星期二") +zhTW("星期二") + +T_("date\vWednesday") +csCZ("StÅ™eda") +deDE("Mittwoch") +esES("Miercoles") +fiFI("Keskiviikko") +frFR("Mercredi") +huHU("Szerda") +itIT("Mercoledì") +plPL("Åšroda") +roRO("Miercuri") +ruRU("Среда") +srSP("Sreda") +trTR("ÇarÅŸamba") +zhCN("星期三") +zhTW("星期三") + +T_("date\vThursday") +csCZ("ÄŒtvrtek") +deDE("Donnerstag") +esES("Jueves") +fiFI("Torstai") +frFR("Jeudi") +huHU("Csütörtök") +itIT("Giovedì") +plPL("Czwartek") +roRO("Joi") +ruRU("Четверг") +srSP("ÄŒetvrtak") +trTR("PerÅŸembe") +zhCN("星期四") +zhTW("星期四") + +T_("date\vFriday") +csCZ("Pátek") +deDE("Freitag") +esES("Viernes") +fiFI("Perjantai") +frFR("Vendredi") +huHU("Péntek") +itIT("Venerdì") +plPL("PiÄ…tek") +roRO("Vineri") +ruRU("ПÑтница") +srSP("Petak") +trTR("Cuma") +zhCN("星期五") +zhTW("星期五") + +T_("date\vSaturday") +csCZ("Sobota") +deDE("Samstag") +esES("Sábado") +fiFI("Lauantai") +frFR("Samedi") +huHU("Szombat") +itIT("Sabato") +plPL("Sobota") +roRO("Sâmbătă") +ruRU("ВоÑкреÑенье") +srSP("Subota") +trTR("Cumartesi") +zhCN("星期六") +zhTW("星期六") + +T_("date\vSu") +csCZ("Ne") +deDE("So") +esES("Do") +fiFI("Su") +frFR("Sam") +huHU("Vas") +itIT("Do") +plPL("So") +roRO("Du") +ruRU("Ð’Ñ") +srSP("Ne") +trTR("Pz") +zhCN("Fri") +zhTW("Fri") + +T_("date\vMo") +csCZ("Po") +deDE("Mo") +esES("Lu") +fiFI("Ma") +frFR("Lun") +huHU("Hé") +itIT("Lu") +plPL("Po") +roRO("Lu") +ruRU("Пн") +srSP("Po") +trTR("Pts") +zhCN("Mon") +zhTW("Mon") + +T_("date\vTu") +csCZ("Út") +deDE("Di") +esES("Ma") +fiFI("Ti") +frFR("Mar") +huHU("Ke") +itIT("Ma") +plPL("Wt") +roRO("Ma") +ruRU("Ð’Ñ‚") +srSP("Ut") +trTR("Sl") +zhCN("Tue") +zhTW("Tue") + +T_("date\vWe") +csCZ("St") +deDE("Mi") +esES("Mi") +fiFI("Ke") +frFR("Mer") +huHU("Sze") +itIT("Me") +plPL("Åšr") +roRO("Mi") +ruRU("Ср") +srSP("Sr") +trTR("ÇrÅŸ") +zhCN("Wed") +zhTW("Wed") + +T_("date\vTh") +csCZ("ÄŒt") +deDE("Do") +esES("Ju") +fiFI("To") +frFR("Jeu") +huHU("Csüt") +itIT("Gi") +plPL("Cz") +roRO("Jo") +ruRU("Чт") +srSP("ÄŒe") +trTR("PrÅŸ") +zhCN("Thu") +zhTW("Thu") + +T_("date\vFr") +csCZ("Pa") +deDE("Fr") +esES("Vi") +fiFI("Pe") +frFR("Ven") +huHU("Pé") +itIT("Ve") +plPL("Pt") +roRO("Vi") +ruRU("Пт") +srSP("Pe") +trTR("Cu") +zhCN("") +zhTW("") + +T_("date\vSa") +csCZ("So") +deDE("Sa") +esES("Sá") +fiFI("La") +frFR("Dim") +huHU("Szo") +itIT("Sa") +plPL("Nd") +roRO("Sâ") +ruRU("Сб") +srSP("Su") +trTR("Cts") +zhCN("Sun") +zhTW("Sun") + +T_("date\vJanuary") +csCZ("Leden") +deDE("Januar") +esES("Enero") +fiFI("Tammikuu") +frFR("Janvier") +huHU("Január") +itIT("Gennaio") +plPL("StyczeÅ„") +roRO("Ianuarie") +ruRU("Январь") +srSP("Januar") +trTR("Ocak") +zhCN("一月") +zhTW("一月") + +T_("date\vFebruary") +csCZ("Únor") +deDE("Februar") +esES("Febrero") +fiFI("Helmikuu") +frFR("Février") +huHU("Február") +itIT("Febbraio") +plPL("Luty") +roRO("Februarie") +ruRU("Февраль") +srSP("Februar") +trTR("Åžubat") +zhCN("二月") +zhTW("二月") + +T_("date\vMarch") +csCZ("BÅ™ezen") +deDE("März") +esES("Marzo") +fiFI("Maaliskuu") +frFR("Mars") +huHU("Március") +itIT("Marzo") +plPL("Marzec") +roRO("Martie") +ruRU("Март") +srSP("Mart") +trTR("Mart") +zhCN("三月") +zhTW("三月") + +T_("date\vApril") +csCZ("Duben") +deDE("April") +esES("Abril") +fiFI("Huhtikuu") +frFR("Avril") +huHU("Ãprilis") +itIT("Aprile") +plPL("KwiecieÅ„") +roRO("Aprilie") +ruRU("Ðпрель") +srSP("April") +trTR("Nisan") +zhCN("四月") +zhTW("四月") + +T_("date\vMay") +csCZ("KvÄ›ten") +deDE("Mai") +esES("Mayo") +fiFI("Toukokuu") +frFR("Mai") +huHU("Május") +itIT("Maggio") +plPL("Maj") +roRO("Mai") +ruRU("Май") +srSP("Maj") +trTR("Mayıs") +zhCN("五月") +zhTW("五月") + +T_("date\vJune") +csCZ("ÄŒerven") +deDE("Juni") +esES("Junio") +fiFI("Kesäkuu") +frFR("Juin") +huHU("Június") +itIT("Giugno") +plPL("Czerwiec") +roRO("Iunie") +ruRU("Июнь") +srSP("Jun") +trTR("Haziran") +zhCN("六月") +zhTW("六月") + +T_("date\vJuly") +csCZ("ÄŒervenec") +deDE("Juli") +esES("Julio") +fiFI("Heinäkuu") +frFR("Juillet") +huHU("Július") +itIT("Luglio") +plPL("Lipiec") +roRO("Iulie") +ruRU("Июль") +srSP("Jul") +trTR("Temmuz") +zhCN("七月") +zhTW("七月") + +T_("date\vAugust") +csCZ("Srpen") +deDE("August") +esES("Agosto") +fiFI("Elokuu") +frFR("Août") +huHU("Augusztus") +itIT("Agosto") +plPL("SierpieÅ„") +roRO("August") +ruRU("ÐвгуÑÑ‚") +srSP("Avgust") +trTR("AÄŸustos") +zhCN("八月") +zhTW("八月") + +T_("date\vSeptember") +csCZ("Září") +deDE("September") +esES("Septiembre") +fiFI("Syyskuu") +frFR("Septembre") +huHU("Szeptember") +itIT("Settembre") +plPL("WrzesieÅ„") +roRO("Septembrie") +ruRU("СентÑбрь") +srSP("Septembar") +trTR("Eylül") +zhCN("乿œˆ") +zhTW("乿œˆ") + +T_("date\vOctober") +csCZ("Říjen") +deDE("Oktober") +esES("Octubre") +fiFI("Lokakuu") +frFR("Octobre") +huHU("Október") +itIT("Ottobre") +plPL("Październik") +roRO("Octombrie") +ruRU("ОктÑбрь") +srSP("Oktobar") +trTR("Ekim") +zhCN("åæœˆ") +zhTW("åæœˆ") + +T_("date\vNovember") +csCZ("Listopad") +deDE("November") +esES("Noviembre") +fiFI("Marraskuu") +frFR("Novembre") +huHU("November") +itIT("Novembre") +plPL("Listopad") +roRO("Noiembrie") +ruRU("ÐоÑбрь") +srSP("Novembar") +trTR("Kasım") +zhCN("å一月") +zhTW("å一月") + +T_("date\vDecember") +csCZ("Prosinec") +deDE("Dezember") +esES("Diciembre") +fiFI("Joulukuu") +frFR("Décembre") +huHU("December") +itIT("Dicembre") +plPL("GrudzieÅ„") +roRO("Decembrie") +ruRU("Декабрь") +srSP("Decembar") +trTR("Aralık") +zhCN("å二月") +zhTW("å二月") + +T_("sdate\vJan") +csCZ("Led") +deDE("Jan") +esES("Ene") +fiFI("Tam") +frFR("Jan") +huHU("Jan") +itIT("Gen") +plPL("Sty") +roRO("Ian") +ruRU("Янв") +srSP("Jan") +trTR("Ock") +zhCN("Jan") +zhTW("Jan") + +T_("sdate\vFeb") +csCZ("Úno") +deDE("Feb") +esES("Feb") +fiFI("Hel") +frFR("Fév") +huHU("Feb") +itIT("Feb") +plPL("Lut") +roRO("Feb") +ruRU("Фев") +srSP("Feb") +trTR("Åžub") +zhCN("Feb") +zhTW("Feb") + +T_("sdate\vMar") +csCZ("BÅ™e") +deDE("Mär") +esES("Mar") +fiFI("Maa") +frFR("Mar") +huHU("Márc") +itIT("Mar") +plPL("Mar") +roRO("Mar") +ruRU("Мрт") +srSP("Mar") +trTR("Mar") +zhCN("Mar") +zhTW("Mar") + +T_("sdate\vApr") +csCZ("Dub") +deDE("Apr") +esES("Abr") +fiFI("Huh") +frFR("Avr") +huHU("Ãpr") +itIT("Apr") +plPL("Kwi") +roRO("Apr") +ruRU("Ðпр") +srSP("Apr") +trTR("Nis") +zhCN("Apr") +zhTW("Apr") + +T_("sdate\vMay") +csCZ("KvÄ›") +deDE("Mai") +esES("May") +fiFI("Tou") +frFR("Mai") +huHU("Máj") +itIT("Mag") +plPL("Maj") +roRO("Mai") +ruRU("Май") +srSP("Maj") +trTR("May") +zhCN("May") +zhTW("May") + +T_("sdate\vJun") +csCZ("ÄŒer") +deDE("Jun") +esES("Jun") +fiFI("Kes") +frFR("Jun") +huHU("Jún") +itIT("Giu") +plPL("Cze") +roRO("Iun") +ruRU("Инь") +srSP("Jun") +trTR("Haz") +zhCN("Jun") +zhTW("Jun") + +T_("sdate\vJul") +csCZ("ÄŒec") +deDE("Jul") +esES("Jul") +fiFI("Hei") +frFR("Jui") +huHU("Júl") +itIT("Lug") +plPL("Lip") +roRO("Iul") +ruRU("Иль") +srSP("Jul") +trTR("Tem") +zhCN("Jul") +zhTW("Jul") + +T_("sdate\vAug") +csCZ("Srp") +deDE("Aug") +esES("Ago") +fiFI("Elo") +frFR("Aou") +huHU("Aug") +itIT("Ago") +plPL("Sie") +roRO("Aug") +ruRU("Ðвг") +srSP("Avg") +trTR("AÄŸu") +zhCN("Aug") +zhTW("Aug") + +T_("sdate\vSep") +csCZ("Zář") +deDE("Sep") +esES("Sep") +fiFI("Syy") +frFR("Sep") +huHU("Szept") +itIT("Set") +plPL("Wrz") +roRO("Sep") +ruRU("Сен") +srSP("Sep") +trTR("Eyl") +zhCN("Sep") +zhTW("Sep") + +T_("sdate\vOct") +csCZ("Říj") +deDE("Okt") +esES("Oct") +fiFI("Lok") +frFR("Oct") +huHU("Okt") +itIT("Ott") +plPL("Paź") +roRO("Oct") +ruRU("Окт") +srSP("Okt") +trTR("Ekm") +zhCN("Oct") +zhTW("Oct") + +T_("sdate\vNov") +csCZ("Lis") +deDE("Nov") +esES("Nov") +fiFI("Mar") +frFR("Nov") +huHU("Nov") +itIT("Nov") +plPL("Lis") +roRO("Nov") +ruRU("ÐоÑ") +srSP("Nov") +trTR("Kas") +zhCN("Nov") +zhTW("Nov") + +T_("sdate\vDec") +csCZ("Pro") +deDE("Dez") +esES("Dic") +fiFI("Jou") +frFR("Déc") +huHU("Dec") +itIT("Dic") +plPL("Gru") +roRO("Dec") +ruRU("Дек") +srSP("Dec") +trTR("Arl") +zhCN("Dec") +zhTW("Dec") + + +// Convert.cpp + +T_("Invalid number !") +csCZ("Chybný zápis Äísla !") +deDE("Ungültige Zahl!") +esES("Número invalido !") +fiFI("Virheellinen numero!") +frFR("Nombre invalide !") +huHU("Érvénytelen szám") +itIT("Numero non valido !") +plPL("Niepoprawny numer !") +roRO("Număr invalid !") +ruRU("Ðеправильное чиÑло!") +srSP("PogreÅ¡an broj!") +trTR("Geçersiz sayı !") +zhCN("无效数字!") +zhTW("無效數字!") + +T_("Invalid date !") +csCZ("Chybný zápis data !") +deDE("Ungültiges Datum!") +esES("Fecha invalida !") +fiFI("Virheellinen päivämäärä!") +frFR("Date invalide !") +huHU("Érvénytelen dátum") +itIT("Data non valida !") +plPL("Niepoprawna data !") +roRO("Dată invalidă !") +ruRU("ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ð´Ð°Ñ‚Ð°!") +srSP("PogreÅ¡an datum!") +trTR("Geçersiz tarih !") +zhCN("无效日期") +zhTW("無效日期") + +T_("Invalid time !") +csCZ("Chybný Äas") +deDE("Ungültige Zeitangabe!") +esES("Hora invalida !") +fiFI("Virheellinen aika!") +frFR("") +huHU("Érvénytelen idÅ‘pont") +itIT("") +plPL("") +roRO("Oră invalidă !") +ruRU("Ðеправильное Ð²Ñ€ÐµÐ¼Ñ !") +srSP("") +trTR("Geçersiz Zaman !") +zhCN("") +zhTW("無效時間") + +T_("Null value not allowed.") +csCZ("Hodnota nesmí být prázdná.") +deDE("Null nicht erlaubt.") +esES("No se permite valor nulo.") +fiFI("Arvon puuttuminen ei ole sallittua.") +frFR("Valeur nulle non autorisée.") +huHU("Nullérték nem megengedett") +itIT("Lo zero non è ammesso") +plPL("Pusta wartość jest niedozwolona.") +roRO("Valoare nulă nu este permisă.") +ruRU("Ðулевое значение не разрешено.") +srSP("Bez vrednosti nisu dopuÅ¡tene.") +trTR("Bu alan boÅŸ bırakılamaz.") +zhCN("ä¸å…许空值.") +zhTW("ä¸å…許空值.") + +T_("Number must be between %d and %d.") +csCZ("Číslo musí být v rozsahu %d až %d.") +deDE("Zahl muss zwischen %d und %d liegen.") +esES("El número debe estar entre %d y %d.") +fiFI("Arvon täytyy olla välillä %d.. %d.") +frFR("Le nombre doit être compris entre %d et %d.") +huHU("A számnak %d és %d közé kell esnie") +itIT("Il numero deve essere compreso tra %d e %d.") +plPL("Numer musi być z przedziaÅ‚u %d i %d.") +roRO("Numărul trebuie să fie între %d È™i %d.") +ruRU("ЧиÑло должно быть в пределах между %d и " + "%d") +srSP("Broj mora biti izmeÄ‘u %d i %d.") +trTR("Girilen sayı %d ile %d aralığında olmaldır.") +zhCN("数字必须在%då’Œ%d之间.") +zhTW("數字必須在%då’Œ%d之間.") + +T_("Number must be between %g and %g.") +csCZ("Číslo musí být v rozsahu %g až %g.") +deDE("Zahl muss zwischen %g und %g liegen.") +esES("El número debe estar entre %g y %g.") +fiFI("Arvon täytyy olla välillä %g.. %g.") +frFR("Le nombre doit être compris entre %g et %g.") +huHU("A számnak %g és %g közé kell esnie") +itIT("Il numero deve essere compreso tra %g e %g.") +plPL("Numer musi być z przedziaÅ‚u %g i %g.") +roRO("Numărul trebuie să fie între %g È™i %g.") +ruRU("ЧиÑло должно быть в пределах между %g и " + "%g") +srSP("Broj mora biti izmeÄ‘u %g i %g.") +trTR("Girilen sayı %g ile %g aralığında olmaldır.") +zhCN("数字必须在%gå’Œ%g之间.") +zhTW("數字必須在%gå’Œ%g之間.") + +T_("Date must be between ") +csCZ("Datum musí být v rozsahu ") +deDE("Datum muss liegen zwischen ") +esES("La fecha debe estar entre ") +fiFI("Päivämäärän täytyy olla välillä ") +frFR("La date doit comprise entre") +huHU("A dátum érvényes határai ") +itIT("La data deve essere compre tra ") +plPL("Data musi być z zakresu ") +roRO("Data trebuie să fie în intervalul ") +ruRU("Дата должна быть в пределах ") +srSP("Datum mora biti izmeÄ‘u ") +trTR("Girilen tarih") +zhCN("日期必须介入") +zhTW("日期必須介於") + +T_("range\v and ") +csCZ(" až ") +deDE(" und ") +esES("rango\v y ") +fiFI(" ja ") +frFR(" et ") +huHU(" és ") +itIT(" e ") +plPL(" i ") +roRO(" È™i ") +ruRU(" и ") +srSP(" i ") +trTR(" and ") +zhCN(" å’Œ ") +zhTW(" å’Œ ") + +T_("Time must be between ") +csCZ("ÄŒas musí být od") +deDE("Zeitangabe muss liegen zwischen ") +esES("La fecha debe estar entre ") +fiFI("Ajan täytyy olla välillä ") +frFR("") +huHU("Az idÅ‘pont a köv. kettÅ‘ között legyen: ") +itIT("") +plPL("") +roRO("Ora trebuie să fie în intervalul ") +ruRU("Ð’Ñ€ÐµÐ¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ð¾ быть в интервале") +srSP("") +trTR("Time must be between ") +zhCN("") +zhTW("時間必須介於 ") + +T_("Please enter no more than %d characters.") +csCZ("Text nesmí být delší než %d znaků.") +deDE("Bitte geben Sie nicht mehr als %d Zeichen ein.") +esES("Ingrese no más de %d caracteres.") +fiFI("Syötä enintään %d merkkiä.") +frFR("Veuillez ne pas saisir plus de %d caractères.") +huHU("Ne adjon be többet %d karakternél.") +itIT("Non scrivere più di %d caratteri.") +plPL("ProszÄ™ wprowadzić nie wiÄ™cej niż %d znaków.") +roRO("IntroduceÈ›i până la %d caractere") +ruRU("ПожайлуÑта, введите не более чем %d Ñимволов.") +srSP("Molim vas unesite najviÅ¡e %d slova.") +trTR("Lütfen en fazla %d karakter girin.") +zhCN("输入请ä¸è¦è¶…过%d字符") +zhTW("輸入請ä¸è¦è¶…éŽ%då­—å…ƒ") + + +// t.cpp + +T_("date-format\a%2:02d/%3:02d/%1:4d") +csCZ("%3:02d.%2:02d.%1:04d") +deDE("%3:02d.%2:02d.%1:4d") +esES("") +fiFI("%3:02d.%2:02d.%1:04d") +frFR("%3:02d/%2:02d/%1:04d") +huHU("%1:04d.%2:02d.%3:02d.") +itIT("%3:02d/%2:02d/%1:04d") +plPL("%3:02d.%2:02d.%1:04d") +roRO("format-dată\a%2:02d/%3:02d/%1:4d") +ruRU("%3:02d.%2:02d.%1:04d") +srSP("%3:02d.%2:02d.%1:04d") +trTR("%3:02d.%2:02d.%1:04d") +zhCN("%2:02d/%3:02d/%1:4d") +zhTW("%2:02d/%3:02d/%1:4d") + +T_("date-scan\amdy") +csCZ("dmy") +deDE("dmy") +esES("") +fiFI("dmy") +frFR("dmy") +huHU("ymd") +itIT("dmy") +plPL("dmy") +roRO("") +ruRU("dmy") +srSP("dmy") +trTR("dmy") +zhCN("mdy") +zhTW("mdy") + +T_("date-filter\aA/\a .-") +csCZ(".\a /,") +deDE("A/\a .-") +esES("") +fiFI(".\a ,-/") +frFR("/\a .,") +huHU("A.\a .-") +itIT("/\a .,") +plPL("\a .,-/") +roRO("") +ruRU(".\a /,") +srSP(".\a /,") +trTR(".\a /,") +zhCN("A/\a .-") +zhTW("A/\a .-") + + +// Lang.cpp + +T_("Invalid language specification.") +csCZ("Chybná specifikace jazyka.") +deDE("Ungültige Sprachenbezeichnung") +esES("Especificación de lenguaje no válida") +fiFI("Virheellinen kielimääritys.") +frFR("Langue spécifiée invalide.") +huHU("Érvénytelen nyelvbeállítás") +itIT("Lingua specificata non valida.") +plPL("Niepoprawna specyfikacja jÄ™zyka.") +roRO("Specificare de limbă invalidă") +ruRU("ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ ÑÐ¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñзыка.") +srSP("Nevalidna specifikacija jezika.") +trTR("Geçersiz dil.") +zhCN("无效语言指示") +zhTW("無效語言指示") + + +// Obsolete + +T_("invalid day number.") +csCZ("neplatné Äíslo dne.") +deDE("Ungültige Tageszahl") +esES("") +fiFI("virheellinen päivä.") +frFR("jour invalide.") +huHU("érvénytelen nap.") +itIT("giorno non valido.") +plPL("niepoprawny numer dnia.") +roRO("număr de zi invalid.") +ruRU("неправильное чиÑло Ð´Ð½Ñ Ð¼ÐµÑÑца.") +srSP("nevalidan dan.") +trTR("geçersiz gün.") +zhCN("无效天数") +zhTW("無效天數") + +T_("invalid month number.") +csCZ("neplatné Äíslo mÄ›síce.") +deDE("Ungültige Monatszahl") +esES("") +fiFI("virheellinen kuukausi.") +frFR("mois invalide.") +huHU("érvénytelen hónap.") +itIT("mese non valido.") +plPL("niepoprawny numer miesiÄ…ca.") +roRO("număr de lună invalid") +ruRU("неправильное чиÑло меÑÑца.") +srSP("nevalidan mesec.") +trTR("geçersiz ay.") +zhCN("无效月数") +zhTW("無效月數") + +T_("invalid year number.") +csCZ("neplatné Äíslo roku.") +deDE("Ungültige Jahreszahl") +esES("") +fiFI("virheellinen vuosi.") +frFR("année invalide.") +huHU("érvénytelen év.") +itIT("anno non valido.") +plPL("niepoprawny numer roku.") +roRO("an invalid") +ruRU("неправильное чиÑло года.") +srSP("nevalidana godina.") +trTR("geçersiz yıl.") +zhCN("无效年数") +zhTW("無效年數") + +T_("invalid hour number.") +csCZ("chybné Äíslo hodiny.") +deDE("Ungültige Stundenzahl") +esES("") +fiFI("virheellinen tunti.") +frFR("heure invalide.") +huHU("érvénytelen óra.") +itIT("ora non valida.") +plPL("niepoprawna wartość godziny.") +roRO("oră invalidă") +ruRU("неправильное чиÑло чаÑа.") +srSP("nevalidan sat.") +trTR("geçersiz saat.") +zhCN("æ— æ•ˆå°æ—¶") +zhTW("ç„¡æ•ˆå°æ™‚") + +T_("invalid minute number.") +csCZ("chybné Äíslo minuty.") +deDE("Ungültige Minutenzahl") +esES("") +fiFI("virheellinen minuutti.") +frFR("minute invalide.") +huHU("érvénytelen perc.") +itIT("minuti non valido.") +plPL("niepoprawna wartość minuty.") +roRO("minut invalid") +ruRU("неправильное чиÑло минуты.") +srSP("nevalidna minuta.") +trTR("geçersiz dakika.") +zhCN("无效分") +zhTW("無效分") + +T_("invalid second number.") +csCZ("chybné Äíslo sekundy.") +deDE("Ungültige Sekundenzahl") +esES("") +fiFI("virheellinen sekunti.") +frFR("seconde invalide.") +huHU("érvénytelen másodperc.") +itIT("secondi non valido.") +plPL("niepoprawna druga wartość.") +roRO("secundă invalidă") +ruRU("неправильное чиÑло Ñекунды.") +srSP("nevalidna sekunda.") +trTR("geçersiz saniye.") +zhCN("无效秒") +zhTW("無效秒") + +T_("invalid character '%c' following date/time.") +csCZ("neplatný znak '%c' za koncem data.") +deDE("Ungültiges Zeichen '%c' folgt Datum/Zeit.") +esES("") +fiFI("virheellinen merkki '%c' seuraa päivämäärää/kellonaikaa.") +frFR("caractère invalide '%c' suivant la date.") +huHU("érvénytelen karakter '%c' a dátum/idÅ‘ mellett.") +itIT("carattere non valido '%c' dopo la data.") +plPL("niepoprawny znak '%c' na koÅ„cu daty/czasu.") +roRO("data/ora este urmată de caracterul invalid '%c'") +ruRU("неправильный Ñимвол '%c' идущий за датой/временем.") +srSP("nevalidni karakter '%c' posle datuma/vremena.") +trTR("girilen tarih/zaman bilgisi içindeki '%c' geçersiz bir karakterdir.") +zhCN("日期/æ—¶é—´åŽè·Ÿå­—符 '%c' 无效") +zhTW("日期/時間後跟字元 '%c' 無效") + +T_("invalid day number %d - February in year %d has only %d days.") +csCZ("neplatné Äíslo dne %d - únor v roce %d má pouze %d dní.") +deDE("Ungültige Tagesnummer %d - Februar im Jahr %d hat nur %d Tage.") +esES("") +fiFI("virheellinen päivä %d - Helmikuussa %d on vain %d päivää.") +frFR("jour %d invalide pour Février qui n'a que %d jours.") +huHU("érvénytelen nap %d - a február a(z) %d évben csak %d napos.") +itIT("Febbraio ha solo %d giorni.") +plPL("niepoprawny numer dnia %d - Luty w roku %d ma tylko %d dni.") +roRO("ziua %d invalidă - februarie are doar %d zile în anul %d") +ruRU("неправильное чиÑло меÑÑца %d - Ð’ феврале " + "%d года только %d дней.") +srSP("nevalidan dan %d - Februar u godini %d ima %d dana.") +trTR("%d geçersiz bir gün sayısıdır - %d yılında Åžubat ayı %d gün " + "çeker.") +zhCN("无效天数 %d - %då¹´äºŒæœˆåªæœ‰%d天.") +zhTW("無效天數 %d - %då¹´äºŒæœˆåªæœ‰%d天.") + +T_("invalid day number %d - %month has only %d days.") +csCZ("neplatné Äíslo dne %d - %month má pouze %d dní.") +deDE("Ungültige Tagesnummer %d - %month hat nur %d Tage.") +esES("") +fiFI("virheellinen päivä %d - %monthssa on vain %d päivää.") +frFR("jour %d invalide pour %month qui n'a que %d jours.") +huHU("érvénytelen nap %d - %month csak % napos.") +itIT("Giorno non valido %d - %month ha solo %d giorni.") +plPL("niepoprawny numer dnia - %month ma tylko %d dni.") +roRO("ziua %d invalidă - %month are numai %d zile") +ruRU("неправильное чиÑло меÑÑца %d - Ð’ %month только " + "%d дней.") +srSP("nevalidan dan %d - %month ima %d dana.") +trTR("%d geçersiz bir gün sayısıdır - %month ayı %d gün çeker.") +zhCN("无效天数 %d - %monthæœˆåªæœ‰ %d 天.") +zhTW("無效天數 %d - %monthæœˆåªæœ‰ %d 天.") + +T_("exceeded valid range (lower bound: %`).") +csCZ("pÅ™ekroÄení povoleného rozsahu (dolní mez: %`).") +deDE("Gültigkeitsbereich unterschritten (untere Grenze: %`).") +esES("") +fiFI("sallitun alueen ulkopuolella (alaraja: %`).") +frFR("validité de l'intervalle dépassée (limite inférieure : %d`).") +huHU("érvényes tartomány alatt (alsó határ: %`).") +itIT("range valido superato (limite inferiore: %`).") +plPL("przekroczono dopuszczalny zakres (dolna granica: %`).") +roRO("interval depășit (margine inferioară: %`).") +ruRU("превышен допуÑтимый предел (нижний предел: " + "%`).") +srSP("prekoraÄena validna granica (donja granica: %`).") +trTR("Geçerli aralık aşıldı (alt sınır: %`).") +zhCN("超出有效范围(下é™:%`).") +zhTW("超出有效範åœ(下é™:%`).") + +T_("exceeded valid range (upper bound: %`).") +csCZ("pÅ™ekroÄení povoleného rozsahu (horní mez: %`).") +deDE("Gültigkeitsbereich überschritten (obere Grenze: %`).") +esES("") +fiFI("sallitun alueen ulkopuolella (yläraja: %`).") +frFR("validité de l'intervalle dépassée (limite supérieure : %d`).") +huHU("érvényes tartomány fölött (felsÅ‘ határ: %`)") +itIT("range valido superato (limite superiore: %`).") +plPL("przekroczono dopuszczalny zakres (górna granica: %`).") +roRO("interval depășit (margine superioară: %`).") +ruRU("превышен допуÑтимый предел (верхний предел: " + "%`).") +srSP("prekoraÄena validna granica (gornja granica: %`).") +trTR("Geçerli aralık aşıldı (üst sınır: %`).") +zhCN("超出有效范围(上é™:%`).") +zhTW("超出有效範åœ(上é™:%`).") + +T_("Invalid date/time: digit expected, found character") +csCZ("Chybné datum/Äas: oÄekávána Äíslice, nalezen znak") +deDE("Ungültige(s) Datum/Zeit: Ziffer erwartet, Zeichen vorgefunden") +esES("") +fiFI("Virheellinen pvm/aika: Käytä numeroita kirjaimien sijaan.") +frFR("Date/heure invalide : chiffre attendu, caractère détecté") +huHU("érvénytelen dátum/idÅ‘: számjegy helyett más karakter áll") +itIT("Data/ora non valida") +plPL("Niepoprawna data/czas: oczekiwano cyfry, znaleziono znak") +roRO("Dată/oră invalidă: se aÈ™teaptă cifră, caracter găsit") +ruRU("Ðеправильные дата/времÑ: ожидаетÑÑ Ñ†Ð¸Ñ„Ñ€Ð°, " + "а найден Ñимвол") +srSP("Nevalidan datum/vreme: oÄekuje se cifra, pronaÄ‘en karakter") +trTR("Geçersiz tarih/zaman: sayı olması gereken yerde harf var") +zhCN("无效日期/æ—¶é—´:åªèƒ½æ˜¯æ•°å­—,ä¸èƒ½ä¸ºå­—符") +zhTW("無效日期/時間:åªèƒ½æ˜¯æ•¸ä½,ä¸èƒ½ç‚ºå­—å…ƒ") + +T_("Invalid date/time:") +csCZ("Chybné datum/Äas:") +deDE("Ungültige(s) Datum/Zeit:") +esES("") +fiFI("Virheellinen pvm/aika:") +frFR("Date/heure invalide :") +huHU("érvénytelen dátum/idÅ‘") +itIT("Data/ora non valida:") +plPL("Niepoprawna data/czas:") +roRO("Dată/oră invalidă:") +ruRU("Ðеправильные дата/времÑ:") +srSP("Nevalidan datum/vreme:") +trTR("Geçersiz tarih/zaman:") +zhCN("无效日期/æ—¶é—´:") +zhTW("無效日期/時間:") diff --git a/uppdev/CoreTopics/CoreTopics.upp b/uppdev/CoreTopics/CoreTopics.upp new file mode 100644 index 000000000..d2ac24bf4 --- /dev/null +++ b/uppdev/CoreTopics/CoreTopics.upp @@ -0,0 +1,148 @@ +description "Non-GUI code. Streams, NTL containers, concrete types, Value, XML, C parsing etc..."; + +acceptflags + USEMALLOC; + +uses(WIN32) plugin\z; + +library(MSC !MSC8ARM) "kernel32 user32"; + +library(WIN32 !GUI !GNU !GCC) "ole32 oleaut32 oldnames"; + +library(LINUX) "pthread dl"; + +library(FREEBSD) pthread; + +library(WIN32 !MSC8ARM) "advapi32 shell32 winmm mpr"; + +library(SOLARIS) "posix4 dl"; + +library(WIN32 GCC) "ole32 oleaut32 uuid"; + +library(MSC8ARM WIN32) "coredll.lib corelibc.lib ole32.lib oleaut32.lib uuid.lib commctrl.lib ccrtrtti.lib"; + +library(!WIN32) z; + +options(XGNU) -O0; + +options(XGNU) -ffunction-sections; + +link(SOLARIS) "-Wl,-R -Wl,/usr/local/lib"; + +file + Core.h, + Defs.h, + Cpu.cpp optimize_speed, + Mt.h, + Mt.cpp, + OL_Set.cpp, + Global.h, + HeapImp.h, + heaputil.cpp optimize_speed, + sheap.cpp optimize_speed, + lheap.cpp optimize_speed, + heap.cpp optimize_speed, + heapdbg.cpp optimize_speed, + String.h, + AString.hpp, + String.cpp optimize_speed, + WString.cpp optimize_speed, + StrUtil.cpp optimize_speed, + CharSet.h, + CharSet.cpp optimize_speed, + Kernel32W.dli, + Mpr32W.dli, + Path.h, + Path.cpp, + NetNode.cpp, + App.h, + App.cpp, + Stream.h, + Stream.cpp optimize_speed, + BlockStream.cpp optimize_speed, + Profile.h, + Diag.h, + Log.cpp, + Debug.cpp, + Util.h, + Util.cpp optimize_speed, + mathutil.cpp optimize_speed, + Containers readonly separator, + Algo.h, + Topt.h, + Vcont.h, + BiCont.h, + Vcont.hpp, + Vcont.cpp optimize_speed, + Index.h, + Map.h, + Index.hpp, + Other.h, + Hash.cpp optimize_speed, + Concretes readonly separator, + Cbgen.h, + Callback.h, + Callback.cpp optimize_speed, + TimeDate.h, + TimeDate.cpp optimize_speed, + Value.h, + Value.cpp optimize_speed, + Format.h, + Format.cpp optimize_speed, + Convert.h, + Convert.cpp optimize_speed, + Color.h, + Color.cpp optimize_speed, + Gtypes.h, + Gtypes.cpp optimize_speed, + Language readonly separator, + i18n.h, + t.cpp optimize_speed, + Core.t charset "UTF-8", + t.h, + Lang.h, + Lang.cpp, + lcid.txt, + "Other files" readonly separator, + Parser.h, + parser.cpp optimize_speed, + XML.h, + XML.cpp optimize_speed, + Xmlize.h, + Xmlize.cpp optimize_speed, + Uuid.h, + Uuid.cpp optimize_speed, + Ptr.h, + Ptr.cpp optimize_speed, + z.h, + z.cpp, + Topic.h, + topic_group.h, + Topic.cpp, + CoWork.h, + CoWork.cpp, + "Runtime linking" readonly separator, + dli.h, + dli_header.h, + dli_source.h, + Dli.cpp, + "Win32 support" readonly separator, + Win32Util.h, + Win32Util.cpp, + Meta readonly separator, + sub.upt, + core.upt, + Info readonly separator, + test.tpp, + app.tpp, + src.tpp, + srcdoc.tpp, + srcimp.tpp, + Copying, + Copying-plain, + Authors; + +mainconfig + "Normal" = "", + "Remote shared" = "SHARED"; + diff --git a/uppdev/CoreTopics/Core_init.icpp b/uppdev/CoreTopics/Core_init.icpp new file mode 100644 index 000000000..e2fedffcd --- /dev/null +++ b/uppdev/CoreTopics/Core_init.icpp @@ -0,0 +1,4 @@ +#include "Core.h" + +#define TFILE +#include diff --git a/uppdev/CoreTopics/Cpu.cpp b/uppdev/CoreTopics/Cpu.cpp new file mode 100644 index 000000000..3cd9888ae --- /dev/null +++ b/uppdev/CoreTopics/Cpu.cpp @@ -0,0 +1,146 @@ +#include "Core.h" + +NAMESPACE_UPP + +#ifdef CPU_X86 + +static bool sHasMMX; +static bool sHasSSE; +static bool sHasSSE2; +static bool sHasSSE3; + +static void sCheckCPU() +{ + static bool done; + if(done) return; + done = true; +#ifdef PLATFORM_OSX11 +// __asm__("pushl %%ebx\n\tmovl $1, %%eax\n\tcpuid\n\tpopl %%ebx" : "=d" (info1), "=c" (info2) : : "%eax"); + sHasMMX = true; + sHasSSE = true; + sHasSSE2 = true; +#else +#ifdef CPU_AMD64 + sHasMMX = true; + sHasSSE = true; + sHasSSE2 = true; +#else +#ifdef COMPILER_MSC + dword info1; + dword info2; + __asm { + mov eax, 1 + cpuid + mov info1, edx + mov info2, ecx + } +#else + dword info1; + dword info2; + __asm__("movl $1, %%eax\n\tcpuid" : "=d" (info1), "=c" (info2) : : "%eax", "%ebx"); +#endif + sHasMMX = ((info1 >> 23) & 0x1); + sHasSSE = ((info1 >> 25) & 0x1); + sHasSSE2 = ((info1 >> 26) & 0x1); + sHasSSE3 = ((info2) & 0x1); +#endif +#endif +} + +INITBLOCK { +// sCheckCPU(); +} + +bool CpuMMX() { sCheckCPU(); return sHasMMX; } +bool CpuSSE() { sCheckCPU(); return sHasSSE; } +bool CpuSSE2() { sCheckCPU(); return sHasSSE2; } +bool CpuSSE3() { sCheckCPU(); return sHasSSE3; } + +#ifdef PLATFORM_POSIX +#ifdef PLATFORM_FREEBSD +#include +#else +#include +#endif +#endif + +int CPU_Cores() +{ + static int n; + ONCELOCK { +#ifdef PLATFORM_WIN32 +#ifdef CPU_64 + uint64 pa, sa; + GetProcessAffinityMask(GetCurrentProcess(), &pa, &sa); + for(int i = 0; i < 64; i++) + n += !!(sa & ((uint64)1 << i)); +#else + DWORD pa, sa; + GetProcessAffinityMask(GetCurrentProcess(), &pa, &sa); + for(int i = 0; i < 32; i++) + n += !!(sa & (1 << i)); +#endif +#elif defined(PLATFORM_POSIX) +#if defined(PLATFORM_FREEBSD) || defined(PLATFORM_SOLARIS) + n = minmax((int)sysconf(_SC_NPROCESSORS_ONLN), 1, 256); +#else + n = minmax(get_nprocs(), 1, 256); +#endif +#else + n = 1; +#endif + } + return n; +} + +#endif + +#ifdef PLATFORM_WIN32 +bool IsDecentMachine() +{ + if(!IsWin2K()) + return false; + MEMORYSTATUS m; + GlobalMemoryStatus(&m); + return m.dwTotalPhys > 500 * 1024 * 1024; + +} +#else +bool IsDecentMachine() +{ + return true; +} +#endif + +#ifndef CPU_X86 +int64 PeekI64(const void *ptr) { + const byte *p = (const byte *)ptr; + dword a = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + dword b = p[4] | (p[5] << 8) | (p[6] << 16) | (p[7] << 24); + return (int64)a | ((int64)b << 32); +} +#endif + +#ifndef CPU_X86 +void PokeI64(void *ptr, int64 value) { + byte *p = (byte *)ptr; + p[0] = (byte)(value >> 8 * 0); + p[1] = (byte)(value >> 8 * 1); + p[2] = (byte)(value >> 8 * 2); + p[3] = (byte)(value >> 8 * 3); + p[4] = (byte)(value >> 8 * 4); + p[5] = (byte)(value >> 8 * 5); + p[6] = (byte)(value >> 8 * 6); + p[7] = (byte)(value >> 8 * 7); +} +#endif +#define ENDIAN_SWAP { while(count--) { EndianSwap(*v++); } } + +void EndianSwap(word *v, int count) ENDIAN_SWAP +void EndianSwap(int16 *v, int count) ENDIAN_SWAP +void EndianSwap(dword *v, int count) ENDIAN_SWAP +void EndianSwap(int *v, int count) ENDIAN_SWAP +void EndianSwap(int64 *v, int count) ENDIAN_SWAP +void EndianSwap(uint64 *v, int count) ENDIAN_SWAP + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Debug.cpp b/uppdev/CoreTopics/Debug.cpp new file mode 100644 index 000000000..2e79dfe17 --- /dev/null +++ b/uppdev/CoreTopics/Debug.cpp @@ -0,0 +1,478 @@ +#include "Core.h" + +NAMESPACE_UPP + +#define LTIMING(x) // TIMING(x) + +int msecs(int from) { return (int)GetTickCount() - from; } + +#ifdef PLATFORM_WIN32 +#include +#endif + +#ifdef PLATFORM_WIN32 +static void sLogFile(char *fn, const char *app = ".log") +{ +#ifdef PLATFORM_WINCE + wchar wfn[256]; + ::GetModuleFileName(NULL, wfn, 512); + strcpy(fn, FromSysChrSet(wfn)); +#else + ::GetModuleFileName(NULL, fn, 512); +#endif + char *e = fn + strlen(fn), *s = e; + while(s > fn && *--s != '\\' && *s != '.') + ; + strcpy(*s == '.' ? s : e, app); +} +#endif + +#ifdef PLATFORM_POSIX +const char *procexepath_(); +extern char Argv0__[_MAX_PATH + 1]; + +static void sLogFile(char *fn, const char *app = ".log") +{ + char *path = fn; + const char *ehome = getenv("HOME"); + strcpy(fn, ehome ? ehome : "/root"); + if(!*fn || (fn += strlen(fn))[-1] != '/') + *fn++ = '/'; + *fn = '\0'; + strcat(path, ".upp/"); + const char *exe = procexepath_(); + if(!exe) { + exe = Argv0__; + } + const char *q = strrchr(exe, '/'); + if(q) + exe = q + 1; + if(!exe) + exe = "upp"; + strcat(path, exe); + mkdir(path, 0755); + strcat(path, "/"); + strcat(path, exe); + strcat(path, app); +} +#endif + +static Stream *__logstream; +static char __logfilename[512]; +static int __logfilesizelimit = 10000000; +static bool __logfilenodeleteonstartup = false; + +void SetVppLogSizeLimit(int limit) { __logfilesizelimit = limit; } +void SetVppLogNoDeleteOnStartup() { __logfilenodeleteonstartup = true; } + +static void sOpenVppLog(LogStream *s) +{ + if(!*__logfilename) + sLogFile(__logfilename); + s->Create(__logfilename, __logfilenodeleteonstartup); + s->SetLimit(__logfilesizelimit); +} + +LogStream& StdLogStream() +{ + static LogStream *s; + ReadMemoryBarrier(); + if(!s) { + static StaticCriticalSection lock; + lock.Enter(); + if(!s) { + static byte lb[sizeof(LogStream)]; + LogStream *strm = new(lb) LogStream; + sOpenVppLog(strm); + WriteMemoryBarrier(); + s = strm; + } + lock.Leave(); + } + return *s; +} + +void StdLogSetup(dword options) +{ + StdLogStream().SetOptions(options); +} + +Stream& StdLog() +{ + return StdLogStream(); +} + +void SetVppLog(Stream& log) { + __logstream = &log; +} + +Stream& VppLog() { + if(!__logstream) __logstream = &StdLog(); + return *__logstream; +} + +void SetVppLogName(const String& file) { + strcpy(__logfilename, file); + sOpenVppLog(&StdLogStream()); +} + +void sTime(char *h, const char *ext) +{ + Time t = GetSysTime(); + char th[200]; + sprintf(th, ".%d-%02d-%02d-%02d-%02d-%02d", t.year, t.month, t.day, t.hour, t.minute, t.second); + strcat(th, ext); + sLogFile(h, th); +} + +bool snobuglog; + +void DeactivateBugLog() +{ + snobuglog = true; +} + +Stream& BugLog() +{ + if(snobuglog) + return NilStream(); + static LogStream *s; + if(!s) { + INTERLOCKED + if(!s) { + static byte lb[sizeof(LogStream)]; + s = new(lb) LogStream; + char h[200]; + sTime(h, ".buglog"); + s->Create(h, false); + } + } + return *s; +} + +LogStream& UsrLogStream() +{ + static LogStream *s; + if(!s) { + INTERLOCKED + if(!s) { + static byte lb[sizeof(LogStream)]; + s = new(lb) LogStream; + char h[200]; + sTime(h, ".usrlog"); + s->Create(h, false); + } + } + return *s; +} + +bool susrlog; +bool susrlogpersistent; + +void ActivateUsrLog() +{ + UsrLogStream(); + susrlog = true; +} + +void ActivatePersistentUsrLog() +{ + ActivateUsrLog(); + susrlogpersistent = true; +} + +Stream& UsrLog() +{ + return susrlog ? (Stream&)UsrLogStream() : NilStream(); +} + +Stream& UsrLog(const char *line) +{ + if(!susrlog) + return NilStream(); + return UsrLogStream() << line << "\r\n"; +} + +Stream& UsrLogT(int indent, const char *line) +{ + if(!susrlog) + return NilStream(); + Time tm = GetSysTime(); + char h[256]; + sprintf(h, "%02d:%02d:%02d ", tm.hour, tm.minute, tm.second); + Stream& s = UsrLogStream() << h; + while(indent--) + s << " "; + s << line << "\r\n"; + return s; +} + +Stream& UsrLogT(const char *line) +{ + return UsrLogT(0, line); +} + +bool IsUsrLog() +{ + return susrlog; +} + +void DeleteUsrLog() +{ + if(susrlogpersistent) { + if(susrlog) + UsrLogStream() << "log is persistent"; + } + else { + if(!UsrLogStream().Delete()) + RLOG("Unable to delete UsrLog, " << GetLastErrorMessage()); + susrlog = false; + } +} + +void __LOGF__(const char *fmt, ...) { + char buffer[1024]; + va_list argptr; + va_start(argptr, fmt); + vsprintf(buffer, fmt, argptr); + va_end(argptr); + VppLog().Put(buffer); +} + +String GetTypeName(const char *s) +{ + static const char _struct[] = "struct ", _class[] = "class "; + enum { LEN_S = sizeof(_struct) - 1, LEN_C = sizeof(_class) - 1 }; + int len = (dword)strlen(s); + if(len > LEN_C && !memcmp(s, _class, LEN_C)) + s += LEN_C; + else if(len > LEN_S && !memcmp(s, _struct, LEN_S)) + s += LEN_S; + return s; +} + +bool TimingInspector::active = true; + +#if defined(PLATFORM_POSIX) || defined(PLATFORM_WINCE) +inline int tmGetTime() { + return GetTickCount(); +} +#else +inline int tmGetTime() { + return timeGetTime(); +} +#endif + +static TimingInspector& s_zero() +{ + static TimingInspector *s_zero = NULL; + static bool init = false; + if(!init) { + init = true; + static TimingInspector s_zero_; + s_zero = &s_zero_; + int w = GetTickCount(); + while(GetTickCount() - w < 200) + TimingInspector::Routine __(*s_zero); + } + return *s_zero; +} + +TimingInspector::TimingInspector(const char *_name) { + s_zero(); //!! atexit + name = _name ? _name : ""; + start_time = 0; + all_count = call_count = max_nesting = nesting_depth = min_time = max_time = total_time = 0; + static bool init; + if(!init) { +#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE) + timeBeginPeriod(1); +#endif + init = true; + } +} + +TimingInspector::~TimingInspector() { + Mutex::Lock __(mutex); + if(this == &s_zero()) return; + StdLog() << Dump() << "\r\n"; +} + +void TimingInspector::Start() { + Mutex::Lock __(mutex); + if(!active) return; + if(!nesting_depth++) + start_time = tmGetTime(); + if(nesting_depth > max_nesting) + max_nesting = nesting_depth; +} + +void TimingInspector::End() { + Mutex::Lock __(mutex); + if(!active) return; + all_count++; + if(!--nesting_depth) { + dword time = tmGetTime() - start_time; + total_time += time; + if(call_count++ == 0) + min_time = max_time = time; + else { + if(time < min_time) + min_time = time; + if(time > max_time) + max_time = time; + } + } +} + +String TimingInspector::Dump() { + Mutex::Lock __(mutex); + String s = Sprintf("TIMING %-15s: ", name); + if(call_count == 0) + return s + "No active hit"; + double tm = max(0.0, double(total_time) / call_count / 1000 - + double(s_zero().total_time) / s_zero().call_count / 1000); + return s + + timeFormat(tm * call_count) + + " - " + timeFormat(tm) + + " (" + timeFormat((double)total_time / 1000) + " / " + + Sprintf("%d )", call_count) + + ", min: " + timeFormat((double)min_time / 1000) + + ", max: " + timeFormat((double)max_time / 1000) + + Sprintf(", nesting: %d - %d", max_nesting, all_count); +} + +HitCountInspector::~HitCountInspector() +{ + Mutex::Lock __(mutex); + RLOG("HITCOUNT " << name << ": hit count = " << hitcount); +} + +void HexDump(Stream& s, const void *ptr, int size, int maxsize) { + char h[256]; + sprintf(h, "Memory at %p, size 0x%X = %d\n", ptr, size, size); + s.Put(h); +#ifdef PLATFORM_WIN32 + if(IsBadReadPtr(ptr, size)) { + s.Put(" \n"); + return; + } +#endif + int a, b; + byte *q = (byte *)ptr; + a = 0; + if(size > maxsize) size = maxsize; + while(a < size) { + #ifdef CPU_64 + uint64 aa = a + (uint64)ptr; + sprintf(h, "%+6d 0x%08X%08X ", a, (int)(aa >> 32), (int)aa); + s.Put(h); + #else + sprintf(h, "%+6d 0x%08X ", a, a + dword(ptr)); + s.Put(h); + #endif + for(b = 0; b < 16; b++) + if(a + b < size) { + sprintf(h, "%02X ", q[a + b]); + s.Put(h); + } + else + s.Put(" "); + s.Put(" "); + for(b = 0; b < 16; b++) + if(a + b < size) + s.Put(q[a + b] < ' ' ? '.' : q[a + b]); + else + s.Put(' '); + a += 16; + s << '\n'; + } +} + +#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE) + +template +void Put(HANDLE file, T& data) { + dword dummy; + WriteFile(file, &data, sizeof(data), &dummy, NULL); +} + +static LPTOP_LEVEL_EXCEPTION_FILTER sPrev; +static dword sESP; +static char appInfo[20]; +static char crashfilename[MAX_PATH]; + +void SetCrashFileName(const char *cfile) +{ + ASSERT(strlen(cfile) < MAX_PATH); + strcpy(crashfilename, cfile); +} + +LONG __stdcall sDumpHandler(LPEXCEPTION_POINTERS ep) { + SYSTEMTIME st; + GetLocalTime(&st); + if(!*crashfilename) { + ::GetModuleFileName(NULL, crashfilename, 512); + wsprintf(crashfilename + strlen(crashfilename), ".%d-%02d-%02d-%02d-%02d-%02d%s.crash", + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, appInfo); + } + HANDLE file = CreateFile(crashfilename, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + dword v = 1; + Put(file, v); + EXCEPTION_RECORD *er = ep->ExceptionRecord; + Put(file, er->ExceptionCode); + Put(file, er->ExceptionAddress); + Put(file, er->NumberParameters); + for(int i = 0; i < (int)er->NumberParameters; i++) + Put(file, er->ExceptionInformation[i]); + +#ifdef CPU_AMD64 + qword esp = ep->ContextRecord->Rsp; +#else + dword esp = ep->ContextRecord->Esp; +#endif + + WriteFile(file, (void *) esp, (dword)(sESP - esp), &v, NULL); + /* dword base = ep->ContextRecord->Ebp; + for(;;) { + dword new_base = *(dword *)base; + dword caller = *(dword *)(base + 4); + Put(file, caller); + if(new_base < base) + break; + base = new_base; + }*/ + CloseHandle(file); + char h[200]; + sprintf(h, "CRASH: %d-%02d-%02d %02d:%02d:%02d code: 0x%X address: 0x%p", + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, + er->ExceptionCode, er->ExceptionAddress); + UsrLogT("============ CRASH ================================================"); + UsrLogT(h); + BugLog() << h << "\r\n"; + return sPrev ? (*sPrev)(ep) : 0 /*EXCEPTION_CONTINUE_SEARCH*/; +} + +void InstallCrashDump(const char *info) { + memset(appInfo, 0, sizeof(appInfo)); + if(info && *info) { + appInfo[0] = '.'; + strncpy(appInfo + 1, info, sizeof(appInfo) - 1); + appInfo[sizeof(appInfo) - 1] = '\0'; + } + if(!sPrev) { + sPrev = SetUnhandledExceptionFilter(sDumpHandler); +#ifndef CPU_AMD64 +#ifdef COMPILER_MSC + __asm mov sESP, esp +#else + //todo +#endif +#endif + } +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Defs.h b/uppdev/CoreTopics/Defs.h new file mode 100644 index 000000000..f927263e9 --- /dev/null +++ b/uppdev/CoreTopics/Defs.h @@ -0,0 +1,543 @@ +#ifdef PLATFORM_WIN32 +#define __BREAK__ (*(int *)0 = 0) +#else +#define __BREAK__ (*(int *)0 = 0) // kill(getpid(), SIGTRAP) +#endif + +#ifdef COMPILER_MSC + #pragma warning(disable : 4800) + #pragma warning(disable : 4129) + #pragma warning(disable : 4290) + #pragma warning(disable : 4068) + #pragma warning(disable : 4005) + #pragma warning(disable : 4675) + #pragma warning(disable : 4996) + + #pragma setlocale("C") +#endif + +bool IsPanicMode(); + +void Panic(const char *msg); + +void AssertFailed(const char *file, int line, const char *cond); + +void InstallPanicMessageBox(void (*mb)(const char *title, const char *text)); +void PanicMessageBox(const char *title, const char *text); + +#define VERIFY(x) ((x) ? (void)0 : UPP::AssertFailed(__FILE__, __LINE__, #x)) + +#ifdef _DEBUG + +#define ASSERT_(x, msg) ((x) ? (void)0 : UPP::AssertFailed(__FILE__, __LINE__, msg)) +#define ASSERT(x) ASSERT_(x, #x) + +#else + +#define ASSERT_(x, msg) +#define ASSERT(x) + +#endif + +#define _cm_ , + +#define __countof(a) int(sizeof(a) / sizeof(a[0])) + +#define __Expand1(x) x(1) +#define __Expand2(x) __Expand1(x) x(2) +#define __Expand3(x) __Expand2(x) x(3) +#define __Expand4(x) __Expand3(x) x(4) +#define __Expand5(x) __Expand4(x) x(5) +#define __Expand6(x) __Expand5(x) x(6) +#define __Expand7(x) __Expand6(x) x(7) +#define __Expand8(x) __Expand7(x) x(8) +#define __Expand9(x) __Expand8(x) x(9) +#define __Expand10(x) __Expand9(x) x(10) +#define __Expand11(x) __Expand10(x) x(11) +#define __Expand12(x) __Expand11(x) x(12) +#define __Expand13(x) __Expand12(x) x(13) +#define __Expand14(x) __Expand13(x) x(14) +#define __Expand15(x) __Expand14(x) x(15) +#define __Expand16(x) __Expand15(x) x(16) +#define __Expand17(x) __Expand16(x) x(17) +#define __Expand18(x) __Expand17(x) x(18) +#define __Expand19(x) __Expand18(x) x(19) +#define __Expand20(x) __Expand19(x) x(20) +#define __Expand21(x) __Expand20(x) x(21) +#define __Expand22(x) __Expand21(x) x(22) +#define __Expand23(x) __Expand22(x) x(23) +#define __Expand24(x) __Expand23(x) x(24) +#define __Expand25(x) __Expand24(x) x(25) +#define __Expand26(x) __Expand25(x) x(26) +#define __Expand27(x) __Expand26(x) x(27) +#define __Expand28(x) __Expand27(x) x(28) +#define __Expand29(x) __Expand28(x) x(29) +#define __Expand30(x) __Expand29(x) x(30) +#define __Expand31(x) __Expand30(x) x(31) +#define __Expand32(x) __Expand31(x) x(32) +#define __Expand33(x) __Expand32(x) x(33) +#define __Expand34(x) __Expand33(x) x(34) +#define __Expand35(x) __Expand34(x) x(35) +#define __Expand36(x) __Expand35(x) x(36) +#define __Expand37(x) __Expand36(x) x(37) +#define __Expand38(x) __Expand37(x) x(38) +#define __Expand39(x) __Expand38(x) x(39) +#define __Expand40(x) __Expand39(x) x(40) + +#define __Expand(x) __Expand40(x) + +#define __List1(x) x(1) +#define __List2(x) __List1(x), x(2) +#define __List3(x) __List2(x), x(3) +#define __List4(x) __List3(x), x(4) +#define __List5(x) __List4(x), x(5) +#define __List6(x) __List5(x), x(6) +#define __List7(x) __List6(x), x(7) +#define __List8(x) __List7(x), x(8) +#define __List9(x) __List8(x), x(9) +#define __List10(x) __List9(x), x(10) +#define __List11(x) __List10(x), x(11) +#define __List12(x) __List11(x), x(12) +#define __List13(x) __List12(x), x(13) +#define __List14(x) __List13(x), x(14) +#define __List15(x) __List14(x), x(15) +#define __List16(x) __List15(x), x(16) +#define __List17(x) __List16(x), x(17) +#define __List18(x) __List17(x), x(18) +#define __List19(x) __List18(x), x(19) +#define __List20(x) __List19(x), x(20) +#define __List21(x) __List20(x), x(21) +#define __List22(x) __List21(x), x(22) +#define __List23(x) __List22(x), x(23) +#define __List24(x) __List23(x), x(24) +#define __List25(x) __List24(x), x(25) +#define __List26(x) __List25(x), x(26) +#define __List27(x) __List26(x), x(27) +#define __List28(x) __List27(x), x(28) +#define __List29(x) __List28(x), x(29) +#define __List30(x) __List29(x), x(30) +#define __List31(x) __List30(x), x(31) +#define __List32(x) __List31(x), x(32) +#define __List33(x) __List32(x), x(33) +#define __List34(x) __List33(x), x(34) +#define __List35(x) __List34(x), x(35) +#define __List36(x) __List35(x), x(36) +#define __List37(x) __List36(x), x(37) +#define __List38(x) __List37(x), x(38) +#define __List39(x) __List38(x), x(39) +#define __List40(x) __List39(x), x(40) + +#define E__p(I) p##I + +#define ASSTRING_(x) #x +#define ASSTRING(x) ASSTRING_(x) + +#define COMBINE__(a, b) a##b +#define COMBINE(a, b) COMBINE__(a, b) + +#define COMBINE3__(a, b, c) a##b##c +#define COMBINE3(a, b, c) COMBINE3__(a, b, c) + +#define COMBINE4__(a, b, c, d) a##b##c##d +#define COMBINE4(a, b, c, d) COMBINE4__(a, b, c, d) + +#define COMBINE5__(a, b, c, d, e) a##b##c##d##e +#define COMBINE5(a, b, c, d, e) COMBINE5__(a, b, c, d, e) + +#define MK__s__(x) s__s##x +#define MK__s_(x) MK__s__(x) + +#ifdef BLITZ_INDEX__ +#define MK__s MK__s_(COMBINE3(BLITZ_INDEX__, _, __LINE__)) +#else +#define MK__s MK__s_(__LINE__) +#endif + +#ifdef flagCHECKINIT +void InitBlockBegin__(const char *fn, int line); +void InitBlockEnd__(const char *fn, int line); +#else +inline void InitBlockBegin__(const char *, int) {} +inline void InitBlockEnd__(const char *, int) {} +#endif + +struct Callinit { + Callinit(void (*fn)(), const char *cpp, int line) { InitBlockBegin__(cpp, line); fn(); InitBlockEnd__(cpp, line); } + Callinit(void (*fn)()) { fn(); } +}; + +struct Callexit { + Callexit(void (*fn)()) { atexit(fn); } +}; + + +// deprecated, use INITBLOCK +#define INITCODE(x) \ +static void COMBINE(MK__s, _fn)() { x } static UPP::Callinit MK__s(COMBINE(MK__s, _fn), __FILE__, __LINE__); + + +#define INITBLOCK \ +static void COMBINE(MK__s, _fn)(); static UPP::Callinit MK__s(COMBINE(MK__s, _fn), __FILE__, __LINE__); \ +static void COMBINE(MK__s, _fn)() + +#define INITBLOCK_(x) \ +static void COMBINE(x, _fn)(); static UPP::Callinit x(COMBINE(x, _fn), __FILE__, __LINE__); \ +static void COMBINE(x, _fn)() + + +// deprecated, use EXITBLOCK +#define EXITCODE(x) \ +static void COMBINE(MK__s, _fn)() { x } static UPP::Callexit MK__s(COMBINE(MK__s, _fn)); + + +#define EXITBLOCK \ +static void COMBINE(MK__s, _fn)(); static UPP::Callexit MK__s(COMBINE(MK__s, _fn)); \ +static void COMBINE(MK__s, _fn)() + +#define EXITBLOCK_(x) \ +static void COMBINE(x, _fn)(); static UPP::Callexit x(COMBINE(x, _fn)); \ +static void COMBINE(x, _fn)() + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +template inline const T& min(const T& a, const T& b) { return a < b ? a : b; } +template inline const T& max(const T& a, const T& b) { return a > b ? a : b; } + +template +inline T minmax(T x, T _min, T _max) { return min(max(x, _min), _max); } + +typedef unsigned char byte; +typedef signed char int8; +typedef unsigned char uint8; + +typedef short unsigned word; +typedef short int int16; +typedef short unsigned uint16; + +#ifdef PLATFORM_WIN32 +typedef unsigned long dword; +typedef long int32; +typedef unsigned long uint32; +typedef WCHAR wchar; +#else +typedef unsigned int dword; +typedef int int32; +typedef unsigned int uint32; +typedef word wchar; +#endif + + +#ifdef COMPILER_MSC +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int int64; +typedef long long unsigned uint64; +#endif + +typedef uint64 qword; + +#ifdef COMPILER_MSC + #define I64(c) ((int64)COMBINE(c, i64)) +#else + #define I64(c) ((int64)COMBINE(c, LL)) +#endif + +#ifndef INT64_MIN +#define INT64_MIN I64(-0x8000000000000000) +#endif +#ifndef INT64_MAX +#define INT64_MAX I64(+0x7FFFFFFFFFFFFFFF) +#endif + +#if !defined(PLATFORM_WIN32) + +#define HIBYTE(a) (byte)((a) >> 8) +#define LOBYTE(a) byte(a) +#define HIWORD(a) (word)((a) >> 16) +#define LOWORD(a) word(a) + +#define MAKEWORD(a, b) ((word) (((byte) (a)) | ((word) ((byte) (b))) << 8)) +#define MAKELONG(a, b) ((dword) (((word) (a)) | ((dword) ((word) (b))) << 16)) + +#endif + +#define MAKEQWORD(a, b) ((qword) (((dword) (a)) | ((qword) ((dword) (b))) << 32)) +#define HIDWORD(a) (dword)((a) >> 32) +#define LODWORD(a) dword(a) + +#define OFFSETOF(clss, mbr) ((int)(uintptr_t)&(((clss *)1)->mbr) - 1) + +#ifdef COMPILER_MSC +#define pick_ +#else +#define pick_ const +#endif + +#define init_ + +#define BINARY(i, f) \ +extern "C" byte *i; \ +extern "C" int COMBINE(i, _length); + +#define BINARY_ARRAY(i, x, f) \ +extern "C" byte *i[]; \ +extern "C" int COMBINE(i, _length)[]; \ +extern "C" int COMBINE(i, _count); + +#define BINARY_MASK(i, m) \ +extern "C" byte *i[]; \ +extern "C" int COMBINE(i, _length)[]; \ +extern "C" int COMBINE(i, _count); \ +extern "C" char *COMBINE(i, _files)[]; + +int RegisterTypeNo__(const char *type); + +template +int RegisterTypeNo___() +{ + return RegisterTypeNo__(typeid(T).name()); +} + +template +inline int StaticTypeNo() { + static int typeno = -1; + if(typeno < 0) + typeno = RegisterTypeNo___(); + return typeno; +} + +#if defined(flagMT) + #if defined(PLATFORM_WIN32) && defined(COMPILER_GCC) + #define flagUSEMALLOC //MINGW does not support + #endif +#endif + +#ifndef flagUSEMALLOC +#define UPP_HEAP +#endif + +#ifdef UPP_HEAP + +void *MemoryAllocPermanent(size_t size); + +void *MemoryAllocSz(size_t& size); +void *MemoryAlloc(size_t size); +void MemoryFree(void *ptr); +void *MemoryAlloc32(); +void MemoryFree32(void *ptr); +void *MemoryAlloc48(); +void MemoryFree48(void *ptr); +void MemoryFreeThread(); +void MemoryCheck(); +int MemoryUsedKb(); + + +void MemoryBreakpoint(dword serial); + +void MemoryInitDiagnostics(); +void MemoryDumpLeaks(); + +enum MemoryProbeFlags { + MEMORY_PROBE_FULL = 1, + MEMORY_PROBE_FREE = 2, + MEMORY_PROBE_MIXED = 4, + MEMORY_PROBE_LARGE = 8, + MEMORY_PROBE_SUMMARY = 16, +}; + +#ifdef HEAPDBG +void MemoryIgnoreLeaksBegin(); +void MemoryIgnoreLeaksEnd(); + +void MemoryCheckDebug(); +#else +inline void MemoryIgnoreLeaksBegin() {} +inline void MemoryIgnoreLeaksEnd() {} + +inline void MemoryCheckDebug() {} +#endif + +struct MemoryProfile { + int allocated[1024]; + int fragmented[1024]; + int freepages; + int large_count; + size_t large_size[1024]; + size_t large_total; + int large_free_count; + size_t large_free_size[1024]; + int large_free_total; + + MemoryProfile(); +}; + +MemoryProfile *PeakMemoryProfile(); + +#else + +inline void *MemoryAllocPermanent(size_t size) { return malloc(size); } +inline void *MemoryAlloc(size_t size) { return new byte[size]; } +inline void *MemoryAllocSz(size_t &size) { return new byte[size]; } +inline void MemoryFree(void *p) { delete[] (byte *) p; } +inline void *MemoryAlloc32() { return new byte[32]; } +inline void *MemoryAlloc48() { return new byte[48]; } +inline void MemoryFree32(void *ptr) { delete[] (byte *)ptr; } +inline void MemoryFree48(void *ptr) { delete[] (byte *)ptr; } +inline void MemoryInitDiagnostics() {} +inline void MemoryCheck() {} +inline void MemoryCheckDebug() {} +inline int MemoryUsedKb() { return 0; } + +inline void MemoryIgnoreLeaksBegin() {} +inline void MemoryIgnoreLeaksEnd() {} + +struct MemoryProfile { + int allocated[1024]; + int fragmented[1024]; + int freepages; + int large_count; + int large_size[4096]; + int large_total; + int large_free_count; + int large_free_size[4096]; + int large_free_total; + + MemoryProfile() { memset(this, 0, sizeof(MemoryProfile)); } +}; + +inline MemoryProfile *PeakMemoryProfile() { return NULL; } + +#endif + +struct MemoryIgnoreLeaksBlock { + MemoryIgnoreLeaksBlock() { MemoryIgnoreLeaksBegin(); } + ~MemoryIgnoreLeaksBlock() { MemoryIgnoreLeaksEnd(); } +}; + +#ifdef CPU_X86 +bool CpuMMX(); +bool CpuSSE(); +bool CpuSSE2(); +bool CpuSSE3(); +#endif + +int CPU_Cores(); + +bool IsDecentMachine(); + +template +inline void Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } + +#if defined(CPU_UNALIGNED) && defined(CPU_LE) +inline int Peek16le(const void *ptr) { return *(const word *)ptr; } +inline int Peek32le(const void *ptr) { return *(const dword *)ptr; } +inline int64 Peek64le(const void *ptr) { return *(const int64 *)ptr; } + +inline void Poke16le(const void *ptr, int val) { *(word *)ptr = val; } +inline void Poke32le(const void *ptr, int val) { *(dword *)ptr = val; } +inline void Poke64le(const void *ptr, int64 val) { *(int64 *)ptr = val; } +#else +inline int Peek16le(const void *ptr) { return MAKEWORD(((byte *)ptr)[0], ((byte *)ptr)[1]); } +inline int Peek32le(const void *ptr) { return MAKELONG(Peek16le(ptr), Peek16le((byte *)ptr + 2)); } +inline int64 Peek64le(const void *ptr) { return MAKEQWORD(Peek32le(ptr), Peek32le((byte *)ptr + 4)); } + +inline void Poke16le(const void *ptr, int val) { ((byte *)ptr)[0] = LOBYTE(val); ((byte *)ptr)[1] = HIBYTE(val); } +inline void Poke32le(const void *ptr, int val) { Poke16le(ptr, LOWORD(val)); Poke16le((byte *)ptr + 2, HIWORD(val)); } +inline void Poke64le(const void *ptr, int64 val) { Poke32le(ptr, LODWORD(val)); Poke32le((byte *)ptr + 4, HIDWORD(val)); } +#endif + +inline int Peek16be(const void *ptr) { return MAKEWORD(((byte *)ptr)[1], ((byte *)ptr)[0]); } +inline int Peek32be(const void *ptr) { return MAKELONG(Peek16be((byte *)ptr + 2), Peek16be(ptr)); } +inline int64 Peek64be(const void *ptr) { return MAKEQWORD(Peek32be((byte *)ptr + 4), Peek32be(ptr)); } + +inline void Poke16be(const void *ptr, int val) { ((byte *)ptr)[1] = LOBYTE(val); ((byte *)ptr)[0] = HIBYTE(val); } +inline void Poke32be(const void *ptr, int val) { Poke16be(ptr, HIWORD(val)); Poke16be((byte *)ptr + 2, LOWORD(val)); } +inline void Poke64be(const void *ptr, int64 val) { Poke32be(ptr, HIDWORD(val)); Poke32be((byte *)ptr + 4, LODWORD(val)); } + +#if defined(CPU_X86) && (defined(COMPILER_GCC) || defined(COMPILER_MSC)) +#ifdef COMPILER_GCC +#ifdef CPU_64 +inline word SwapEndian16(word v) { __asm__("xchgb %b0,%h0" : "=Q" (v) : "0" (v)); return v; } +inline int16 SwapEndian16(int16 v) { __asm__("xchgb %b0,%h0" : "=Q" (v) : "0" (v)); return v; } +#else +inline word SwapEndian16(word v) { __asm__("xchgb %b0,%h0" : "=q" (v) : "0" (v)); return v; } +inline int16 SwapEndian16(int16 v) { __asm__("xchgb %b0,%h0" : "=q" (v) : "0" (v)); return v; } +#endif +inline dword SwapEndian32(dword v) { __asm__("bswap %0" : "=r" (v) : "0" (v)); return v; } +inline int SwapEndian32(int v) { __asm__("bswap %0" : "=r" (v) : "0" (v)); return v; } +#endif + +#ifdef COMPILER_MSC +#pragma intrinsic (_byteswap_ushort, _byteswap_ulong, _byteswap_uint64) + +inline word SwapEndian16(word v) { return _byteswap_ushort(v); } +inline int16 SwapEndian16(int16 v) { return _byteswap_ushort(v); } +inline dword SwapEndian32(dword v) { return _byteswap_ulong(v); } +inline int SwapEndian32(int v) { return _byteswap_ulong(v); } +#endif + +inline void EndianSwap(word& v) { v = SwapEndian16(v); } +inline void EndianSwap(int16& v) { v = SwapEndian16(v); } +inline void EndianSwap(dword& v) { v = SwapEndian32(v); } +inline void EndianSwap(int& v) { v = SwapEndian32(v); } + +#else +inline void EndianSwap(word& v) { byte *x = (byte *)(&v); Swap(x[0], x[1]); } +inline void EndianSwap(int16& v) { EndianSwap(*(word *)&v); } +inline void EndianSwap(dword& v) { byte *x = (byte *)&v; Swap(x[0], x[3]); Swap(x[1], x[2]); } +inline void EndianSwap(int& v) { EndianSwap(*(dword *)&v); } +inline word SwapEndian16(word v) { EndianSwap(v); return v; } +inline int16 SwapEndian16(int16 v) { EndianSwap(v); return v; } +inline dword SwapEndian32(dword v) { EndianSwap(v); return v; } +inline int SwapEndian32(int v) { EndianSwap(v); return v; } +#endif + +#if defined(CPU_AMD64) && (defined(COMPILER_GCC) || defined(COMPILER_MSC)) +#ifdef COMPILER_GCC +inline uint64 SwapEndian64(uint64 v) { __asm__("bswap %0" : "=r" (v) : "0" (v)); return v; } +inline int64 SwapEndian64(int64 v) { __asm__("bswap %0" : "=r" (v) : "0" (v)); return v; } +#endif +#ifdef COMPILER_MSC +inline uint64 SwapEndian64(uint64 v) { return _byteswap_uint64(v); } +inline int64 SwapEndian64(int64 v) { return _byteswap_uint64(v); } +#endif + +inline void EndianSwap(int64& v) { v = SwapEndian64(v); } +inline void EndianSwap(uint64& v) { v = SwapEndian64(v); } + +#else +inline void EndianSwap(int64& v) { byte *x = (byte *)&v; Swap(x[0], x[7]); Swap(x[1], x[6]); Swap(x[2], x[5]); Swap(x[3], x[4]); } +inline void EndianSwap(uint64& v) { EndianSwap(*(int64 *)&v); } +inline int64 SwapEndian64(int64 v) { EndianSwap(v); return v; } +inline uint64 SwapEndian64(uint64 v) { EndianSwap(v); return v; } +#endif + +void EndianSwap(word *v, int count); +void EndianSwap(int16 *v, int count); +void EndianSwap(dword *v, int count); +void EndianSwap(int *v, int count); +void EndianSwap(int64 *v, int count); +void EndianSwap(uint64 *v, int count); + +//Quick fix.... +#ifdef PLATFORM_WINCE +const char *FromSysChrSet(const wchar *s); +const wchar *ToSysChrSet(const char *s); +#else +inline const char *FromSysChrSet(const char *s) { return s; } +inline const char *ToSysChrSet(const char *s) { return s; } +#endif + +#ifdef _DEBUG +void __LOGF__(const char *format, ...); +#define LOGF UPP::__LOGF__ +#else +inline void __LOGF__(const char *format, ...); +#endif diff --git a/uppdev/CoreTopics/Diag.h b/uppdev/CoreTopics/Diag.h new file mode 100644 index 000000000..f603126f7 --- /dev/null +++ b/uppdev/CoreTopics/Diag.h @@ -0,0 +1,231 @@ + +const char LOG_BEGIN = '\1'; +const char LOG_END = '\2'; + +class LogStream : public Stream { +#ifdef PLATFORM_WIN32 + HANDLE hfile; +#endif +#ifdef PLATFORM_POSIX + enum { INVALID_HANDLE_VALUE = -1 }; + int hfile; +#endif + + CriticalSection cs; + char filename[512]; + char backup[512]; + byte buffer[512]; + int filesize; + byte *p; + + int sizelimit; + int part; + dword options; + int16 depth; + bool bol; + + void Flush(); + void Put0(int w); + +protected: + virtual void _Put(int w); + virtual void _Put(const void *data, dword size); + virtual int64 GetSize() const { return filesize; } + +public: + virtual bool IsOpen() const; + void Create(const char *path, bool append); + void SetLimit(int maxsize) { sizelimit = maxsize; } + + void SetOptions(dword _options) { options = _options; } + + bool Delete(); + void Close(); + + LogStream(); + ~LogStream(); +}; + +void ActivateUsrLog(); +void ActivatePersistentUsrLog(); +bool IsUsrLog(); +Stream& UsrLog(); +Stream& UsrLog(const char *line); +Stream& UsrLogT(const char *line); +Stream& UsrLogT(int indent, const char *line); +void DeleteUsrLog(); + +Stream& BugLog(); +void DeactivateBugLog(); + +Stream& StdLog(); +enum LogOptions { + LOG_FILE = 1, LOG_COUT = 2, LOG_CERR = 4, LOG_DBG = 8 +}; +void StdLogSetup(dword options); + +Stream& VppLog(); +void SetVppLog(Stream& log); +void SetVppLogName(const String& file); +void SetVppLogSizeLimit(int filesize); +void SetVppLogNoDeleteOnStartup(); + +void HexDump(Stream& s, const void *ptr, int size, int maxsize = INT_MAX); + +int msecs(int from = 0); + +String GetTypeName(const char *type_name); +inline String GetTypeName(const ::std::type_info& tinfo) { return GetTypeName(tinfo.name()); } + +void __LOGF__(const char *format, ...); + +#ifdef _MULTITHREADED +void LockLog(); +void UnlockLog(); +#else +inline void LockLog() {} +inline void UnlockLog() {} +#endif + +#ifdef _DEBUG + +#define _DBG_ + +#define DEBUGCODE(x) x + +#define LOG(a) UPP::LockLog(), UPP::VppLog() << a << EOL, UPP::UnlockLog() +#define LOGF UPP::__LOGF__ +#define LOGBEGIN() UPP::LockLog(), UPP::VppLog() << LOG_BEGIN +#define LOGEND() UPP::VppLog() << LOG_END, UPP::UnlockLog() +#define LOGBLOCK(n) RLOGBLOCK(n) +#define LOGHEXDUMP(s, a) UPP::HexDump(VppLog(), s, a) +#define QUOTE(a) { LOG(#a); a; } +#define LOGSRCPOS() UPP::LockLog(), UPP::VppLog() << __FILE__ << '#' << __LINE__ << EOL, UPP::UnlockLog() +#define DUMP(a) UPP::LockLog(), UPP::VppLog() << #a << " = " << (a) << EOL, UPP::UnlockLog() +#define DUMPC(c) UPP::LockLog(), UPP::DumpContainer(VppLog() << #c << ':' << EOL, (c)), UPP::UnlockLog() +#define DUMPCC(c) UPP::LockLog(), UPP::DumpContainer2(VppLog() << #c << ':' << EOL, (c)), UPP::UnlockLog() +#define DUMPCCC(c) UPP::LockLog(), UPP::DumpContainer3(VppLog() << #c << ':' << EOL, (c)), UPP::UnlockLog() +#define XASSERT(c, d) if(!bool(c)) { LOG("XASSERT failed"); LOGSRCPOS(); LOG(d); ASSERT(0); } else +#define NEVER() ASSERT(0) +#define XNEVER(d) if(1) { LOG("NEVER failed"); LOGSRCPOS(); LOG(d); ASSERT(0); } else +#define CHECK(c) if(!bool(c)) { ASSERT(0); } else +#define XCHECK(c, d) if(!bool(c)) { LOG("XCHECK failed"); LOGSRCPOS(); LOG(d); ASSERT(0); } else + +#define TIMING(x) RTIMING(x) +#define HITCOUNT(x) RHITCOUNT(x) +#define ACTIVATE_TIMING() UPP::TimingInspector::Activate(true); +#define DEACTIVATE_TIMING() UPP::TimingInspector::Activate(false); + +#define DLOG(x) LOG(x) +#define DDUMP(x) DUMP(x) +#define DDUMPC(x) DUMPC(x) + +#else + +#define DLOG(x) @ // To clean logs after debugging, this produces error in release mode +#define DDUMP(x) @ +#define DDUMPC(x) @ + +#define ASSERT(x) + +#define DEBUGCODE(x) + +inline void LOGF(const char *format, ...) {} + +#define LOG(a) +#define LOGBEGIN() +#define LOGEND() +#define LOGBLOCK(n) +#define LOGHEXDUMP(s, a) +#define QUOTE(a) a +#define LOGSRCPOS() +#define DUMP(a) +#define DUMPC(a) +#define DUMPCC(a) +#define DUMPCCC(a) +#define XASSERT(c, d) +#define NEVER() +#define XNEVER(d) +#define CHECK(c) (c) +#define XCHECK(c, d) (c) + +#define TIMING(x) +#define HITCOUNT(x) +#define ACTIVATE_TIMING() +#define DEACTIVATE_TIMING() + +#endif + +struct DebugLogBlock +{ + DebugLogBlock(const char *name) : name(name) { VppLog() << name << EOL << LOG_BEGIN; } + ~DebugLogBlock() { VppLog() << LOG_END << "//" << name << EOL; } + const char *name; +}; + +#define RLOG(a) UPP::LockLog(), UPP::VppLog() << a << EOL, UPP::UnlockLog() +#define RLOGBEGIN() UPP::LockLog(), UPP::VppLog() << LOG_BEGIN +#define RLOGEND() UPP::VppLog() << LOG_END, UPP::UnlockLog() +#define RLOGBLOCK(n) UPP::DebugLogBlock MK__s(n) +#define RLOGHEXDUMP(s, a) UPP::HexDump(UPP::VppLog(), s, a) +#define RQUOTE(a) { LOG(#a); a; } +#define RLOGSRCPOS() UPP::LockLog(), UPP::VppLog() << __FILE__ << '#' << __LINE__ << EOL +#define RDUMP(a) UPP::LockLog(), UPP::VppLog() << #a << " = " << (a) << EOL, UPP::UnlockLog() +#define RDUMPC(c) UPP::LockLog(), UPP::DumpContainer(UPP::VppLog() << #c << ':' << EOL, (c)), UPP::UnlockLog() + +// Crash support + +void InstallCrashDump(const char *app_info = NULL); +void SetCrashFileName(const char *cfile); + +// Dumping templates + +template +void DumpContainer(Stream& s, T ptr, T end) { + int i = 0; + s << LOG_BEGIN; + while(ptr != end) + s << '[' << i++ << "] = " << *ptr++ << EOL; + s << LOG_END; +} + +template +void DumpContainer(Stream& s, const C& c) { + DumpContainer(s, c.Begin(), c.End()); +} + +template +void DumpContainer2(Stream& s, T ptr, T end) { + int i = 0; + s << LOG_BEGIN; + while(ptr != end) { + s << '[' << i++ << "] =" << EOL; + DumpContainer(s, (*ptr).Begin(), (*ptr).End()); + ptr++; + } + s << LOG_END; +} + +template +void DumpContainer2(Stream& s, const C& c) { + DumpContainer2(s, c.Begin(), c.End()); +} + +template +void DumpContainer3(Stream& s, T ptr, T end) { + int i = 0; + s << LOG_BEGIN; + while(ptr != end) { + s << '[' << i++ << "] =" << EOL; + DumpContainer2(s, (*ptr).Begin(), (*ptr).End()); + ptr++; + } + s << LOG_END; +} + +template +void DumpContainer3(Stream& s, const C& c) { + DumpContainer3(s, c.Begin(), c.End()); +} + +String AsString(MemoryProfile& mem); diff --git a/uppdev/CoreTopics/Dli.cpp b/uppdev/CoreTopics/Dli.cpp new file mode 100644 index 000000000..ecac2159a --- /dev/null +++ b/uppdev/CoreTopics/Dli.cpp @@ -0,0 +1,231 @@ +#include "Core.h" + +#ifdef PLATFORM_WIN32 +typedef HMODULE DLLHANDLE; +#else +typedef void *DLLHANDLE; +#endif + +#define LLOG(x) + +#ifdef PLATFORM_WIN32 + +#include + +NAMESPACE_UPP + +class PeFile +{ +public: + PeFile(const char *data = 0) { Open(data); } + + bool Open(const char *data); + + int GetExportCount() const; + const char *GetExport(int index) const; + const char *FindExportRaw(const char *name, bool case_sensitive = true) const; + + int GetSectionIndex(const char *name) const; + +private: + const char *data; + const IMAGE_NT_HEADERS *headers; + const IMAGE_SECTION_HEADER *sections; + const IMAGE_EXPORT_DIRECTORY *exports; +}; + +bool PeFile::Open(const char *_data) +{ + data = _data; + if(!data || data[0] != 'M' || data[1] != 'Z') + return false; + int pe = Peek32le(data + 0x3C); + if(IsBadReadPtr(data + pe, sizeof(IMAGE_NT_HEADERS))) + return false; + if(memcmp(data + pe, "PE\0\0", 4)) + return false; + headers = (const IMAGE_NT_HEADERS *)(data + pe); + sections = (const IMAGE_SECTION_HEADER *)(headers + 1); + exports = (const IMAGE_EXPORT_DIRECTORY *)(data + + headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + return true; +} + +int PeFile::GetSectionIndex(const char *name) const +{ + for(int i = 0, n = headers->FileHeader.NumberOfSections; i < n; i++) + if(!strcmp((const char *)sections[i].Name, name)) + return i; + return -1; +} + +int PeFile::GetExportCount() const +{ + return exports ? exports->NumberOfNames : 0; +} + +const char *PeFile::GetExport(int index) const +{ + if(!exports || index < 0 || index >= (int) exports->NumberOfNames) + return 0; + return data + ((const dword *)(data + (dword)exports->AddressOfNames))[index]; +} + +static bool EqualMem(const char *a, const char *b, int len, bool case_sensitive) +{ + if(case_sensitive) + return !memcmp(a, b, len); + else + return !MemICmp(a, b, len); +} + +const char *PeFile::FindExportRaw(const char *name, bool case_sensitive) const +{ + if(!exports || !name || !*name) + return 0; + int len = (int)strlen(name); + const dword *pnames = (const dword *)(data + (dword)exports->AddressOfNames); + for(int i = 0; i < (int) exports->NumberOfNames; i++) { + const char *exp = data + pnames[i]; + int elen = (int)strlen(exp); + if(elen < len) + continue; + if(elen == len && EqualMem(exp, name, len, case_sensitive)) + return exp; + if(EqualMem(exp, name, len, case_sensitive) && exp[len] == '@') + return exp; + if(exp[0] == '_' && EqualMem(exp + 1, name, len, case_sensitive) + && (exp[len + 1] == '@' || exp[len + 1] == 0)) + return exp; + } + return 0; +} + +END_UPP_NAMESPACE + +HMODULE CheckDll__(const char *fn, const char *const *names, UPP::Vector& plist) +{ +#ifdef PLATFORM_WINCE + HMODULE hmod = LoadLibrary(UPP::ToSysChrSet(fn)); +#else + HMODULE hmod = LoadLibrary(fn); +#endif + if(!hmod) + return 0; + + UPP::PeFile pe; + if(!pe.Open((const char *)hmod)) { + FreeLibrary(hmod); + return 0; + } + + int missing = 0; + for(const char *const *p = names; *p; p++) { + const char *exp = *p; + bool optional = (*exp == '?'); + if(optional) exp++; + const char *name = pe.FindExportRaw(exp); + void *proc = 0; +#ifdef PLATFORM_WINCE + if(!name || !(proc = (void *)GetProcAddress(hmod, UPP::ToSysChrSet(name)))) +#else + if(!name || !(proc = (void *)GetProcAddress(hmod, name))) +#endif + if(!optional) { + if(!missing) { + LLOG(fn << " missing exports:"); + } + LLOG(exp); + missing++; + } + plist.Add(proc); + } + if(missing) { + LLOG(missing << " total"); + FreeLibrary(hmod); + return 0; + } + return hmod; +} + +void FreeDll__(HMODULE hmod) +{ + FreeLibrary(hmod); +} + +#endif + +#ifdef PLATFORM_POSIX + +#include + +void *CheckDll__(const char *fn, const char *const *names, UPP::Vector& plist) +{ + void *hmod = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL); + if(!hmod) { + LLOG("Error loading library " << fn << ": " << dlerror()); +/* + for(int i = 0; i < 100; i++) { + hmod = dlopen(fn + ("." + UPP::AsString(i)), RTLD_LAZY | RTLD_GLOBAL); + if(hmod) + break; + } + if(!hmod) +*/ return 0; + } + + int missing = 0; + for(const char *const *p = names; *p; p++) { + const char *exp = *p; + bool optional = (*exp == '?'); + if(optional) exp++; + void *proc = dlsym(hmod, exp); + if(!proc && !optional) { + if(!missing) + LLOG(fn << " missing exports:"); + LLOG(exp); + } + plist.Add(proc); + } + + if(missing) { + LLOG(missing << " missing symbols total"); + dlclose(hmod); + return 0; + } + + return hmod; +} + +void FreeDll__(void *hmod) +{ + if(hmod) + dlclose(hmod); +} + +#endif//PLATFORM_POSIX + +DLLHANDLE LoadDll__(UPP::String& inoutfn, const char *const *names, void *const *procs) +{ + const char *fn = inoutfn; + while(*fn) { + const char *b = fn; + while(*fn && *fn != ';' +#ifndef PLATFORM_WIN32 + && *fn != ':' +#endif + ) + fn++; + UPP::String libname(b, fn); + if(*fn) + fn++; + UPP::Vector plist; + if(DLLHANDLE hmod = CheckDll__(libname, names, plist)) { + for(int i = 0; i < plist.GetCount(); i++) + *(void **)*procs++ = plist[i]; + inoutfn = libname; + return hmod; + } + } + return 0; +} diff --git a/uppdev/CoreTopics/Format.cpp b/uppdev/CoreTopics/Format.cpp new file mode 100644 index 000000000..559065a24 --- /dev/null +++ b/uppdev/CoreTopics/Format.cpp @@ -0,0 +1,1142 @@ +#include "Core.h" +//#BLITZ_APPROVE +#include + +NAMESPACE_UPP + +// Old format --------------------------- + +String VFormat(const char *fmt, va_list ptr) { + int limit = 2 * (int)strlen(fmt) + 1024; + Buffer buffer(limit); + vsprintf(buffer, fmt, ptr); + va_end(ptr); + int len = (int)strlen(buffer); + ASSERT(len <= limit); + return String(buffer, len); +} + +// Formatting routines --------------------------- + +String FormatIntBase(int i, int base, int width, char lpad, int sign) +{ + enum { BUFFER = sizeof(int) * 8 + 1 }; + ASSERT(base >= 2 && base <= 36); + char buffer[BUFFER]; + char *const e = buffer + (int)BUFFER; + char *p = e; + static const char itoc[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + ASSERT(__countof(itoc) == 37); + if(sign < 0 || !IsNull(i)) + { + unsigned x = i; + if(sign >= 0 && i < 0) + x = -i; + do + *--p = itoc[x % base]; + while(x /= base); + } + bool minus = (sign >= 0 && i < 0 && !IsNull(i)); + bool do_sign = (sign > 0 || sign >= 0 && minus); + if(do_sign && lpad != '0') + *--p = (minus ? '-' : '+'); + if(width > e - p) + { + char *b = e - min(width, BUFFER); + while(p > b) + *--p = lpad; + } + if(do_sign && lpad == '0') + *--p = (minus ? '-' : '+'); + int dwd = (int)(e - p); + int pad = (width = max(width, dwd)) - dwd; + StringBuffer out(width); + char *o = out; + if(dwd < width) + memset(o, lpad, pad); + memcpy(o + pad, p, dwd); + return out; +} + +String FormatInt(int i) +{ + return FormatIntBase(i, 10, 0, ' ', 0); +} + +String FormatIntDec(int i, int width, char lpad, bool always_sign) +{ + return FormatIntBase(i, 10, width, lpad, always_sign ? 1 : 0); +} + +String FormatIntHex(int i, int width, char lpad) +{ + return FormatIntBase(i, 16, width, lpad, -1); +} + +String FormatIntOct(int i, int width, char lpad) +{ + return FormatIntBase(i, 8, width, lpad, -1); +} + +String FormatIntAlpha(int i, bool upper) +{ + if(IsNull(i) || i == 0) + return Null; + String out; + if(i < 0) + { + out << '-'; + i = -i; + } + char temp[10], *p = temp; + i--; + char start = (upper ? 'A' : 'a'); + do + *p++ = start + (i % 26); + while(i /= 26); + while(p > temp) + out << *--p; + return out; +} + +String FormatIntRoman(int i, bool upper) +{ + if(IsNull(i) || i == 0) + return Null; + + String out; + if(i < 0) + { + out << '-'; + i = -i; + } + int m = i / 1000; + if(m) + { + out.Cat('M', m); + i -= 1000 * m; + } + + char shift = upper ? 0 : 'a' - 'A'; + static const int value[] = { 1000, 500, 100, 50, 10, 5, 1 }; + static const char letter[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' }; + for(int n = 0; i && n < __countof(value); n++) + { + int v = value[n]; + while(i >= v) + { + out << (char)(letter[n] + shift); + i -= v; + } + if(n < __countof(value) - 1) + for(int j = n + (value[n + 1] * 2 >= v ? 2 : 1); j < __countof(value); j++) + if(i >= v - value[j]) + { // subtraction scheme + out << (char)(letter[j] + shift) << (char)(letter[n] + shift); + i -= v - value[j]; + break; + } + } + return out; +} + +String Format64(uint64 a) +{ + char b[50]; + char *p = b + 50; + do { + *--p = char(a % 10 + '0'); + a /= 10; + } + while(a); + return String(p, b + 50); +} + +String Format64Hex(uint64 a) +{ + char b[50]; + char *p = b + 50; + do { + *--p = "0123456789abcdef"[a & 15]; + a >>= 4; + } + while(a); + return String(p, b + 50); +} + +String FormatInteger(int a) { return IsNull(a) ? String() : FormatInt(a); } +String FormatUnsigned(unsigned long a) { return Sprintf("%u", a); } +String FormatDouble(double a) { return IsNull(a) ? String() : FormatDouble(a, 10, FD_REL); } +String FormatBool(bool a) { return a ? "true" : "false"; } +String FormatPtr(const void *p) { return "0x" + FormatHex(p); } + +String FormatInt64(int64 a) +{ + return IsNull(a) ? String() : a < 0 ? "-" + Format64(-a) : Format64(a); +} + +static char *PutDigits(char *out, unsigned number, int count) +{ + char temp[10]; + char *t = temp; + do + *t++ = number % 10 + '0'; + while(number /= 10); + ASSERT(t - temp <= __countof(temp)); + if((count -= (int)(t - temp)) > 0) + { + char *e = out + count; + while(out < e) + *out++ = '0'; + } + while(t > temp) + *out++ = *--t; + return out; +} + +enum { DBL_DIGITS = (int)(DBL_MANT_DIG * M_LN2 / M_LN10) + 2 }; + +String FormatDoubleDigits(double d, int raw_digits, int flags, int& exponent) +{ + if(IsNull(d)) + { + exponent = Null; + return Null; + } + d = fabs(normalize(d, exponent)); + if(IsNull(exponent)) + return "0"; + int digits = raw_digits + (flags & FD_REL ? 0 : exponent + 1); + int count = minmax(digits, 1, DBL_DIGITS - 2); + Buffer buffer(max(digits, 0) + 10); + char *p = buffer; + if(count == 0) + d /= 10; + else + { + static double powtbl[] = { 1e0, 1e1, 1e2, 1e3, 1e4 }; + int part1 = min(count, 5); + unsigned i = (unsigned)(d * powtbl[part1 - 1]); + p = PutDigits(p, i, 0); + d = double((long double)d * (long double)powtbl[part1 - 1] - i); + count -= part1; + while(count >= 4) + { + i = minmax(0, (unsigned)(d * 10000), 9999); + p = PutDigits(p, i, 4); + d = double((long double)d * (long double)10000 - i); + count -= 4; + } + if(count > 0) + { + i = (unsigned)(d * powtbl[count]); + p = PutDigits(p, i, count); + d = d * powtbl[count] - i; + } + } + if(p - ~buffer < DBL_DIGITS && d >= 0.5) + { // round + while(p > ~buffer && p[-1] == '9') + p--; + if(p == ~buffer) + { + *p++ = '1'; + exponent++; + if(!(flags & FD_REL)) + digits++; + } + else + p[-1]++; + } + if(flags & FD_ZERO) + { + char *e = p; + while(e > ~buffer && e[-1] == '0') + e--; + if(e == buffer) + exponent = Null; + e = ~buffer + digits; + while(p < e) + *p++ = '0'; + } + else + { + while(p > ~buffer && p[-1] == '0') + p--; + if(p == ~buffer) + { + exponent = Null; + *p++ = '0'; + } + } + return String(~buffer, (int)(p - ~buffer)); +} + +String FormatDouble(double d, int digits, int flags, int pad_exp) +{ + if(IsNull(d)) + return Null; + + double ad = fabs(d); + bool is_exp = (flags & FD_EXP); + if(!(flags & FD_FIX)) + { + is_exp = ad && (ad <= 1e-15 || ad >= 1e15); + if(flags & FD_REL) + { + double bd = ipow10(2 * digits); + if(ad && (ad * bd <= 1 || ad >= bd)) + is_exp = true; + } + } + if(is_exp) + return FormatDoubleExp(d, digits, flags, pad_exp); + else + return FormatDoubleFix(d, digits, flags); +} + +String FormatDoubleFix(double d, int digits, int flags) +{ + if(IsNull(d)) + return Null; + int exp; + String dig = FormatDoubleDigits(d, digits, flags, exp); + if(flags & FD_REL) + digits = max(0, digits - Nvl(exp, 0) - 1); + String out; + if(flags & FD_SIGN || d < 0 && !IsNull(exp)) + out.Cat(d >= 0 ? '+' : '-'); + if(IsNull(exp) || exp < -digits) + { + out.Cat('0'); + if(flags & FD_ZERO) + { + out.Cat('.'); + out.Cat('0', digits); + } + } + else if(exp < 0) + { + out.Cat("0."); + out.Cat('0', -1 - exp); + int fill = digits + exp + 1; + if(!(flags & FD_ZERO) || dig.GetLength() >= fill) + out.Cat(dig, min(fill, dig.GetLength())); + else + { + out.Cat(dig); + out.Cat('0', fill - dig.GetLength()); + } + } + else if(exp < dig.GetLength()) + { + out.Cat(dig, ++exp); + if(digits > 0 && ((flags & FD_ZERO) || dig.GetLength() > exp)) + { + out.Cat('.'); + if(!(flags & FD_ZERO) || dig.GetLength() - exp >= digits) + out.Cat(dig.Begin() + exp, min(dig.GetLength() - exp, digits)); + else + { + out.Cat(dig.Begin() + exp, dig.GetLength() - exp); + out.Cat('0', digits - (dig.GetLength() - exp)); + } + } + } + else + { + out.Cat(dig); + out.Cat('0', exp - dig.GetLength() + 1); + if(digits > 0 && (flags & FD_ZERO)) + { + out.Cat('.'); + out.Cat('0', digits); + } + } + return out; +} + +String FormatDoubleExp(double d, int digits, int flags, int fill_exp) +{ + if(IsNull(d)) + return Null; + int exp; + String dig = FormatDoubleDigits(d, digits, flags | FD_REL, exp); + exp = Nvl(exp, 0); + String out; + if(flags & FD_SIGN || d < 0 && !IsNull(exp)) + out.Cat(d >= 0 ? '+' : '-'); + out.Cat(dig[0]); + if(dig.GetLength() > 1) + { + out.Cat('.'); + out.Cat(dig.Begin() + 1, dig.GetLength() - 1); + } + out.Cat(flags & FD_CAP_E ? 'E' : 'e'); + out.Cat(FormatIntDec(exp, fill_exp, '0', flags & FD_SIGN_EXP)); + return out; +} + +String FormatDate(Date date, const char *format, int language) +{ + if(IsNull(date)) + return Null; + if(!format || !*format) + return Format(date); + return FormatTime(ToTime(date), format, language); +} + +String FormatTime(Time t, const char *s, int language) +{ + if(IsNull(t)) + return Null; + String result; + if(!s || !*s) + return Format(t); + while(*s) { + int q = 0; + if(*s == 'M') { + while(*s == 'M') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.month)); + else + result.Cat(Format("%02d", t.month)); + } + else + if(*s == 'D') { + while(*s == 'D') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.day)); + else + result.Cat(Format("%02d", t.day)); + } + else + if(*s == 'Y') { + while(*s == 'Y') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.year % 100)); + else + if(q == 2) + result.Cat(Format("%02d", t.year % 100)); + else + result.Cat(Format("%d", t.year)); + } + else + if(*s == 'h') { + while(*s == 'h') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.hour)); + else + result.Cat(Format("%02d", t.hour)); + } + else + if(*s == 'H') { + while(*s == 'H') { s++; q++; } + int h = ((t.hour + 11) % 12 + 1); + if(q == 1) + result.Cat(Format("%d", h)); + else + result.Cat(Format("%02d", h)); + } + else + if(*s == '<') { + s++; + while(*s && *s != '/') { + if(t.hour <= 12) + result.Cat(*s); + s++; + } + if(!*s) break; + s++; + while(*s && *s != '>') { + if(t.hour > 12) + result.Cat(*s); + s++; + } + if(!*s) break; + s++; + } + else + if(*s == 'm') { + while(*s == 'm') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.minute)); + else + result.Cat(Format("%02d", t.minute)); + } + else + if(*s == 's') { + while(*s == 's') { s++; q++; } + if(q == 1) + result.Cat(Format("%d", t.second)); + else + result.Cat(Format("%02d", t.second)); + } + else + if(*s == '`' && s[1]) { + s++; + result.Cat(*s++); + } + else + result.Cat(*s++); + } + return result; +} + +// New format ---------------------------- + +struct FormId : Moveable { + FormId(String id, int type) : id(id), type(type) {} + String id; + int type; +}; + +unsigned GetHashValue(const FormId& fid) +{ + return CombineHash(fid.type, GetHashValue(fid.id)); +} + +bool operator==(const FormId& a, const FormId& b) +{ + return a.type == b.type && a.id == b.id; +} + +VectorMap& formatmap() +{ + return Single< VectorMap > (); +} + +void RegisterFormatter(int type, const char *id, Formatter f) +{ + AssertST(); + INTERLOCKED { + FormId fid(id, type); + formatmap().FindAdd(fid, f); + formatmap().Find(fid); + } +} + +void RegisterValueFormatter(const char *id, Formatter f) +{ + RegisterFormatter(VALUE_V, id, f); +} + +void RegisterNullFormatter(const char *id, Formatter f) +{ + RegisterFormatter(VOID_V, id, f); + RegisterFormatter(ERROR_V, id, f); +} + +void RegisterNumberFormatter(const char *id, Formatter f) +{ + RegisterFormatter(DOUBLE_V, id, f); + RegisterFormatter(INT64_V, id, f); + RegisterFormatter(INT_V, id, f); + RegisterFormatter(BOOL_V, id, f); + RegisterNullFormatter(id, f); +} + +void RegisterStringFormatter(const char *id, Formatter f) +{ + RegisterFormatter(WSTRING_V, id, f); + RegisterFormatter(STRING_V, id, f); + RegisterNullFormatter(id, f); +} + +void RegisterDateTimeFormatter(const char *id, Formatter f) +{ + RegisterFormatter(TIME_V, id, f); + RegisterFormatter(DATE_V, id, f); + RegisterNullFormatter(id, f); +} + +String IntFormatter(const Formatting& f) +{ + StringBuffer q; + q.SetLength(1000); + q.SetLength(sprintf(q, '%' + f.format + f.id, (int)f.arg)); + return q; +} + +String IntLowerAlphaFormatter(const Formatting& f) +{ + return FormatIntAlpha(f.arg, false); +} + +String IntUpperAlphaFormatter(const Formatting& f) +{ + return FormatIntAlpha(f.arg, true); +} + +String IntLowerRomanFormatter(const Formatting& f) +{ + return FormatIntRoman(f.arg, false); +} + +String IntUpperRomanFormatter(const Formatting& f) +{ + return FormatIntRoman(f.arg, true); +} + +String FloatFormatter(const Formatting& f) +{ + StringBuffer q; + q.SetLength(1000); + q.SetLength(sprintf(q, '%' + f.format + f.id, (double)f.arg)); + return q; +} + +String RealFormatter(const Formatting& f) +{ + if(IsNull(f.arg)) + return Null; + double value = f.arg; + const char *s = f.format; + int digits = 6, fill_exp = 0; + const char *id = f.id; + int flags = (*id++ == 'v' ? FD_REL : 0); + if(*s == '+') { + flags |= FD_SIGN; + s++; + } + if(IsDigit(*s) || *s == '-' && IsDigit(s[1])) { + digits = (int)strtol(s, NULL, 10); + while(IsDigit(*++s)) + ; + } + if(*s == '!') { s++; flags |= FD_ZERO; } + if(*s == '^') { + if(*++s == '+') { + flags |= FD_SIGN_EXP; + s++; + } + if(IsDigit(*s)) { + fill_exp = (int)strtol(s, NULL, 10); + while(IsDigit(*++s)) + ; + } + } + bool lng = false; + if(*id == 'l') { + lng = true; + id++; + } + if(*id == 'e') flags |= FD_EXP; + else if(*id == 'f') flags |= FD_FIX; + if(lng) + return GetLanguageInfo(f.language).FormatDouble(value, digits, flags, fill_exp); + else + return FormatDouble(value, digits, flags, fill_exp); +} + +String StringFormatter(const Formatting& f) +{ + String s = f.arg; + Buffer h(max(f.maxn, s.GetLength()) + 16); + int n = sprintf(h, '%' + f.format + f.id, ~s); + return String(h, n); +} + +String DateFormatter(const Formatting& f) +{ + return GetLanguageInfo(f.language).FormatDate(f.arg); +} + +String TimeFormatter(const Formatting& f) +{ + return GetLanguageInfo(f.language).FormatTime(f.arg); +} + +String SwitchFormatter(const Formatting& f) +{ + const char *s = f.format; + int i = f.arg; + int o = i; + for(;;) { + int n = 0; + while(IsDigit(*s)) + n = 10 * n + *s++ - '0'; + if(!*s) return Null; + if(*s == '%') { + o = i % max(n, 1); + s++; + } + else + if(*s == ',' || *s == ':') { + if(o == n) { + while(*s && *s != ':') + s++; + if(!*s) return Null; + ++s; + const char *b = s; + while(*s && *s != ';') + s++; + return String(b, s); + } + if(*s == ':') + while(*s && *s != ';') + s++; + if(!*s) return Null; + s++; + } + else + return s; + } + return String(); +} + +String StdFormatFormatter(const Formatting& f) +{ + String out = StdFormat(f.arg); + if(!IsNull(out)) + return out; + return f.format; +} + +String MonthFormatter(const Formatting& f) +{ + return MonthName((int)f.arg - 1, f.language); +} + +String MONTHFormatter(const Formatting& f) +{ + return ToUpper(MonthFormatter(f), GetLNGCharset(f.language)); +} + +String monthFormatter(const Formatting& f) +{ + return ToLower(MonthFormatter(f), GetLNGCharset(f.language)); +} + +String MonFormatter(const Formatting& f) +{ + return MonName((int)f.arg - 1, f.language); +} + +String MONFormatter(const Formatting& f) +{ + return ToUpper(MonFormatter(f), GetLNGCharset(f.language)); +} + +String monFormatter(const Formatting& f) +{ + return ToLower(MonFormatter(f), GetLNGCharset(f.language)); +} + +String DayFormatter(const Formatting& f) +{ + return DayName((int)f.arg, f.language); +} + +String DAYFormatter(const Formatting& f) +{ + return ToUpper(DayFormatter(f), GetLNGCharset(f.language)); +} + +String dayFormatter(const Formatting& f) +{ + return ToLower(DayFormatter(f), GetLNGCharset(f.language)); +} + +String DyFormatter(const Formatting& f) +{ + return DyName((int)f.arg, f.language); +} + +String DYFormatter(const Formatting& f) +{ + return ToUpper(DyFormatter(f), GetLNGCharset(f.language)); +} + +String dyFormatter(const Formatting& f) +{ + return ToLower(DyFormatter(f), GetLNGCharset(f.language)); +} + +String twFormatter(const Formatting& f) +{ + int q = f.arg; + return Sprintf(*f.format == '0' ? "%02d" : "%d", q ? q % 12 : 12); +} + +String NumberFormatter(const Formatting& f) +{ + int q = f.arg; + return AsString(q); +} + +void IntDoubleRegister(int type) +{ + RegisterFormatter(type, "", &NumberFormatter); + + RegisterFormatter(type, "c", &IntFormatter); + RegisterFormatter(type, "d", &IntFormatter); + RegisterFormatter(type, "i", &IntFormatter); + RegisterFormatter(type, "o", &IntFormatter); + RegisterFormatter(type, "x", &IntFormatter); + RegisterFormatter(type, "X", &IntFormatter); + RegisterFormatter(type, "ld", &IntFormatter); + RegisterFormatter(type, "li", &IntFormatter); + RegisterFormatter(type, "lo", &IntFormatter); + RegisterFormatter(type, "lx", &IntFormatter); + RegisterFormatter(type, "lX", &IntFormatter); + + RegisterFormatter(type, "e", &FloatFormatter); + RegisterFormatter(type, "E", &FloatFormatter); + RegisterFormatter(type, "f", &FloatFormatter); + RegisterFormatter(type, "g", &FloatFormatter); + RegisterFormatter(type, "G", &FloatFormatter); + + RegisterFormatter(type, "s", &SwitchFormatter); + + RegisterFormatter(type, "month", &monthFormatter); + RegisterFormatter(type, "Month", &MonthFormatter); + RegisterFormatter(type, "MONTH", &MONTHFormatter); + RegisterFormatter(type, "mon", &monFormatter); + RegisterFormatter(type, "Mon", &MonFormatter); + RegisterFormatter(type, "MON", &MONFormatter); + RegisterFormatter(type, "Day", &DayFormatter); + RegisterFormatter(type, "DAY", &DAYFormatter); + RegisterFormatter(type, "day", &dayFormatter); + RegisterFormatter(type, "Dy", &DyFormatter); + RegisterFormatter(type, "DY", &DYFormatter); + RegisterFormatter(type, "dy", &dyFormatter); + RegisterFormatter(type, "tw", &twFormatter); +} + +static void sRegisterFormatters() +{ + ONCELOCK { + IntDoubleRegister(BOOL_V); + IntDoubleRegister(INT_V); + IntDoubleRegister(INT64_V); + IntDoubleRegister(DOUBLE_V); + + RegisterStringFormatter("s", &StringFormatter); + RegisterNullFormatter("", &DateFormatter); + RegisterFormatter(DATE_V, "", &DateFormatter); + RegisterFormatter(TIME_V, "", &TimeFormatter); + + RegisterNumberFormatter("n", &RealFormatter); + RegisterNumberFormatter("ne", &RealFormatter); + RegisterNumberFormatter("nf", &RealFormatter); + RegisterNumberFormatter("nl", &RealFormatter); + RegisterNumberFormatter("nle", &RealFormatter); + RegisterNumberFormatter("nlf", &RealFormatter); + RegisterNumberFormatter("v", &RealFormatter); + RegisterNumberFormatter("ve", &RealFormatter); + RegisterNumberFormatter("vf", &RealFormatter); + RegisterNumberFormatter("vl", &RealFormatter); + RegisterNumberFormatter("vle", &RealFormatter); + RegisterNumberFormatter("vlf", &RealFormatter); + + // real number formats (n = fixed decimals, v = valid decimals) + // ne, ve - force exponential notation; nf, vf - force fixed notation; nl, vl - language-based formatting + // Options: [+][[-]][!][^[+]] + // + .. always prepend sign + // [-] .. number of decimals to print (negative = left of decimal point, default = 6) + // ! .. keep insignificant zeros + // ^ .. exponent options: + // + .. always prepend sign to exponent + // exponent padding width + + RegisterNumberFormatter("a", &IntLowerAlphaFormatter); + RegisterNumberFormatter("A", &IntUpperAlphaFormatter); + RegisterNumberFormatter("r", &IntLowerRomanFormatter); + RegisterNumberFormatter("R", &IntUpperRomanFormatter); + + RegisterValueFormatter("vt", &StdFormatFormatter); + RegisterValueFormatter("", &StdFormatFormatter); + } +} + +INITBLOCK { + sRegisterFormatters(); +} + +String NFormat0(int language, const char *s, const Value **v, int count) +{ + sRegisterFormatters(); + Formatting f; + f.language = language; + String result; + int pos = 0; + const char *b; + for(;;) { + int n = 0; + b = s; + for(;;) { + while(*s && *s != '%') + ++s; + result.Cat(b, (int)(s - b)); + if(*s == '\0') + return result; + ++s; + if(*s == '%') { + result.Cat('%'); + ++s; + } + else + break; + b = s; + } + f.format.Clear(); + f.id.Clear(); + f.maxn = 0; + b = s; + int pad = -1; + int padn; + String nvl_value = String::GetVoid(); + for(;;) { + if(*s == '$') { + pos = n - 1; + b = ++s; + n = 0; + } + else + if(*s == ':') { + pos = n - 1; + b = ++s; + n = 0; + } + else + if(*s == '*') { + f.format.Cat(b, (int)(s - b)); + f.format.Cat(FormatInt(*v[pos++])); + b = ++s; + } + else + if(*s == '<') { + padn = n; + pad = ALIGN_LEFT; + b = ++s; + n = 0; + } + else + if(*s == '>') { + padn = n; + pad = ALIGN_RIGHT; + b = ++s; + n = 0; + } + else + if(*s == '=') { + padn = n; + pad = ALIGN_CENTER; + b = ++s; + n = 0; + } + else + if(*s == '[') { + f.format.Cat(b, (int)(s - b)); + s++; + b = s; + while(*s && *s != ']') + s++; + f.format.Cat(b, (int)(s - b)); + if(*s) s++; + b = s; + if(!IsAlpha(*s) && *s != '~') break; + } + else if(*s == '~') { + nvl_value = f.format; + f.format = Null; + b = ++s; + } + else + if(!*s || *s == '`' || IsAlpha(*s)) + break; + else { + ASSERT(*s); + if(IsDigit(*s)) + n = 10 * n + *s - '0'; + else { + if(n > f.maxn) + f.maxn = n; + n = 0; + } + s++; + } + } + f.format.Cat(b, (int)(s - b)); + b = s; + while(IsAlpha(*s)) + s++; + f.id = String(b, s); +#ifndef _DEBUG + if(pos < 0 || pos >= count) + { + result << "!!ARGPOS=" << pos; + if(*s == '`') + s++; + continue; + } +#endif + f.arg = *v[pos++]; + if(n > f.maxn) + f.maxn = n; + String r; + if(!nvl_value.IsVoid() && IsNull(f.arg)) + r = nvl_value; + else + { + Formatter ft = NULL; +#ifdef _DEBUG + int fi = formatmap().Find(FormId(f.id, f.arg.GetType())); + if(fi < 0) fi = formatmap().Find(FormId(f.id, VALUE_V)); + if(fi < 0) + { + LOG("Missing formatter '" << f.id << "' for type " << f.arg.GetType()); + String fmt_types; + for(int fm = 0; fm < formatmap().GetCount(); fm++) + if(formatmap().GetKey(fm).id == f.id) + fmt_types << ' ' << formatmap().GetKey(fm).type; + LOG("Formatter available for type(s): " << fmt_types); + NEVER(); + } + ft = formatmap()[fi]; +#else + for(;;) { + int fi = formatmap().Find(FormId(f.id, f.arg.GetType())); + if(fi < 0) fi = formatmap().Find(FormId(f.id, VALUE_V)); + if(fi >= 0) + { + ft = formatmap()[fi]; + break; + } + if(f.id.GetLength() == 0) break; + f.id.Trim(f.id.GetLength() - 1); + s--; + } +#endif + if(ft) + r = (*ft)(f); + else + r << ""; + } + switch(pad) + { + case ALIGN_LEFT: + ASSERT(padn >= 0); + if(r.GetLength() < padn) + r.Cat(' ', padn - r.GetLength()); + else + r.Trim(padn); + break; + case ALIGN_RIGHT: + ASSERT(padn >= 0); + if(r.GetLength() < padn) { + String fill(' ', padn - r.GetLength()); + r = fill + r; + } + else + r.Trim(padn); + break; + case ALIGN_CENTER: + ASSERT(padn >= 0); + if(r.GetLength() < padn) { + String fill(' ', (padn - r.GetLength()) / 2); + r = fill + r; + r.Cat(' ', padn - r.GetLength()); + } + else + r.Trim(padn); + break; + } + result.Cat(r); + if(*s == '`') + s++; + } +} + +String NFormat0(const char *s, const Value **v, int count) +{ + return NFormat0(GetCurrentLanguage(), s, v, count); +} + +String NFormat(int language, const char *s, const Vector& v) +{ + Buffer bv(v.GetCount()); + for(int i = 0; i < v.GetCount(); i++) + bv[i] = &v[i]; + return NFormat0(language, s, bv, v.GetCount()); +} + +String NFormat(const char *s, const Vector& v) { return NFormat(GetCurrentLanguage(), s, v); } + +//$- +#define E__NFSetArg(I) arg[I - 1] = &COMBINE(p, I) +#define E__NFValue(I) const Value& COMBINE(p, I) + +#define E__NFBody(I) \ +String NFormat(const char *fmt, __List##I(E__NFValue)) \ +{ \ + const Value *arg[I]; \ + __List##I(E__NFSetArg); \ + return NFormat0(fmt, arg, I); \ +} \ +String NFormat(int language, const char *fmt, __List##I(E__NFValue)) \ +{ \ + const Value *arg[I]; \ + __List##I(E__NFSetArg); \ + return NFormat0(language, fmt, arg, I); \ +} + +__Expand10(E__NFBody) + +#if 1 + +#define E__FBody(I) \ +String Format(const char *fmt, __List##I(E__NFValue)) \ +{\ + const Value *arg[I]; \ + __List##I(E__NFSetArg); \ + return NFormat0(fmt, arg, I); \ +} \ +String Format(int language, const char *fmt, __List##I(E__NFValue)) \ +{ \ + const Value *arg[I]; \ + __List##I(E__NFSetArg); \ + return NFormat0(language, fmt, arg, I); \ +} + +__Expand20(E__FBody) +//$+ +String Format(const char *s, const Vector& v) +{ + return NFormat(s, v); +} + +String Format(int language, const char *s, const Vector& v) +{ + return NFormat(language, s, v); +} + +#else + +String Format(const char *fmt, ...) { + va_list argptr; + va_start(argptr, fmt); + return VFormat(fmt, argptr); +} + +#endif + +String Sprintf(const char *fmt, ...) { + va_list argptr; + va_start(argptr, fmt); + return VFormat(fmt, argptr); +} + +String DeFormat(const char *text) +{ + StringBuffer x; + while(*text) { + if(*text == '%') + x.Cat('%'); + x.Cat(*text++); + } + return x; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Format.h b/uppdev/CoreTopics/Format.h new file mode 100644 index 000000000..c0213531f --- /dev/null +++ b/uppdev/CoreTopics/Format.h @@ -0,0 +1,124 @@ +String FormatIntBase(int i, int base, int width = 0, char lpad = ' ', int sign = 0); +String FormatInt(int i); +String FormatIntDec(int i, int width, char lpad = ' ', bool always_sign = false); +String FormatIntHex(int i, int width = 8, char lpad = '0'); +String FormatIntOct(int i, int width = 12, char lpad = '0'); +String FormatIntRoman(int i, bool upper = false); +String FormatIntAlpha(int i, bool upper = true); +String Format64(uint64 a); +String Format64Hex(uint64 a); + +#ifdef CPU_64 +inline String FormatIntHex(const void *ptr) { return Format64Hex((int64)(uintptr_t)ptr); } +inline String FormatHex(const void *ptr) { return Format64Hex((int64)(uintptr_t)ptr); } +#else +inline String FormatIntHex(const void *ptr) { return FormatIntHex((int)(uintptr_t)ptr); } +inline String FormatHex(const void *ptr) { return FormatIntHex((int)(uintptr_t)ptr); } +#endif + +String FormatInteger(int a); +String FormatUnsigned(unsigned long a); +String FormatDouble(double a); +String FormatBool(bool a); +String FormatInt64(int64 a); + +template<> inline String AsString(const short& a) { return FormatInteger(a); } +template<> inline String AsString(const unsigned short& a) { return FormatUnsigned(a); } +template<> inline String AsString(const int& a) { return FormatInteger(a); } +template<> inline String AsString(const unsigned int& a) { return FormatUnsigned(a); } +template<> inline String AsString(const long& a) { return FormatInteger(a); } +template<> inline String AsString(const unsigned long& a) { return FormatUnsigned(a); } +template<> inline String AsString(const double& a) { return FormatDouble(a); } +template<> inline String AsString(const float& a) { return FormatDouble(a); } +//template<> inline String AsString(const bool& a) { return FormatBool(a); } // TRC: moved to String.h by CXL +template<> inline String AsString(const int64& a) { return FormatInt64(a); } +template<> inline String AsString(const uint64& a) { return Format64(a); } + +enum +{ + FD_SIGN = 0x01, // always prepend sign (+10) + FD_REL = 0x02, // relative decimal places (valid digits) + FD_SIGN_EXP = 0x04, // always prepend sign to exponent (1e+2) + FD_CAP_E = 0x08, // capital E for exponent (1E10) + FD_ZERO = 0x10, // keep trailing zeros (1.25000) + FD_FIX = 0x20, // always use fixed notation (FormatDouble) + FD_EXP = 0x40, // always use exponential notation (FormatDouble) +}; +String FormatDoubleDigits(double d, int digits, int flags, int& exponent); +String FormatDouble(double d, int digits, int flags = 0, int fill_exp = 0); +String FormatDoubleFix(double d, int digits, int flags = 0); +String FormatDoubleExp(double d, int digits, int flags = 0, int fill_exp = 0); + +String FormatDate(Date date, const char *format, int language = 0); +String FormatTime(Time time, const char *format, int language = 0); + +inline String IntStr(int i) { return FormatInt(i); } +inline String IntStr64(int64 i) { return FormatInt64(i); } +inline String DblStr(double d) { return FormatDouble(d, 10); } + +/* +Date ScanDate(const char *text, const char **endptr, const char *format, int language, Date base_date); +Time ScanTime(const char *text, const char **endptr, const char *format, int language, Time base_time); +*/ + +struct Formatting +{ + int language; + int maxn; + Value arg; + String format; + String id; +}; + +typedef String (*Formatter)(const Formatting& fmt); + +void RegisterFormatter(int type, const char *id, Formatter f) init_; +void RegisterNullFormatter(const char *id, Formatter f) init_; +void RegisterNumberFormatter(const char *id, Formatter f) init_; +void RegisterStringFormatter(const char *id, Formatter f) init_; +void RegisterDateTimeFormatter(const char *id, Formatter f) init_; +void RegisterValueFormatter(const char *id, Formatter f) init_; + +#define E__NFValue(I) const Value& COMBINE(p, I) +#define E__NFBody(I) \ +String NFormat(const char *fmt, __List##I(E__NFValue)); \ +String NFormat(int language, const char *fmt, __List##I(E__NFValue)); + +//$-String NFormat(const char *fmt, Value p1, ...); +//$ String NFormat(int language, const char *fmt, Value p1, ...); +__Expand20(E__NFBody) +//$+ + +#undef E__NFBody +#undef E__NFValue + +String NFormat(const char *s, const Vector& v); +String NFormat(int language, const char *s, const Vector& v); + +String VFormat(const char *fmt, va_list args); +String Sprintf(const char *fmt, ...); + +//$- + +#if 1 + +#define E__NFValue(I) const Value& COMBINE(p, I) +#define E__NFBody(I) \ +String Format(const char *fmt, __List##I(E__NFValue)); \ +String Format(int language, const char *fmt, __List##I(E__NFValue)); + +__Expand20(E__NFBody) + +#undef E__NFBody +#undef E__NFValue + +String Format(const char *s, const Vector& v); +String Format(int language, const char *s, const Vector& v); + +#else + +String Format(const char *fmt, ...); + +#endif + +String DeFormat(const char *text); diff --git a/uppdev/CoreTopics/Global.h b/uppdev/CoreTopics/Global.h new file mode 100644 index 000000000..bb41d609d --- /dev/null +++ b/uppdev/CoreTopics/Global.h @@ -0,0 +1,43 @@ +#define GLOBAL_VP(type, name, param) \ +name() \ +{ \ + static type x param; \ + return x; \ +} + +#define GLOBAL_VARP(type, name, param) \ +type& GLOBAL_VP(type, name, param) + +#define GLOBAL_V(type, name) GLOBAL_VP(type, name, init_) +#define GLOBAL_VAR(type, name) type& GLOBAL_V(type, name) + +#define GLOBAL_VP_INIT(type, name, param) \ +name() \ +{ \ + static type x param; \ + return x; \ +} \ +INITBLOCK { name(); } + +#define GLOBAL_VARP_INIT(type, name, param) \ +type& GLOBAL_VP_INIT(type, name, param) + +#define GLOBAL_V_INIT(type, name) GLOBAL_VP_INIT(type, name, init_) +#define GLOBAL_VAR_INIT(type, name) type& GLOBAL_V_INIT(type, name) + + +// DEPRECATED! (USE ONCELOCK_) +#define INIT_LOCKV(init, code) \ +if(!init) { \ + static StaticCriticalSection cs; \ + CriticalSection::Lock __(cs); \ + if(!init) { \ + init = true; \ + code \ + } \ +} + +// DEPRECATED! (USE ONCELOCK) +#define INIT_LOCK(code) \ +static bool init; \ +INIT_LOCKV(init, code) diff --git a/uppdev/CoreTopics/Gtypes.cpp b/uppdev/CoreTopics/Gtypes.cpp new file mode 100644 index 000000000..a223bb9e9 --- /dev/null +++ b/uppdev/CoreTopics/Gtypes.cpp @@ -0,0 +1,117 @@ +#include "Core.h" + +NAMESPACE_UPP + +INITBLOCK { + Point p; + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); + RichValue::Register(); +} + +//template <> +//void Rect_::Union(const Rect_& r) { +void Rect_double_Union(Rect_& self, const Rect_& r) { + if(IsNull(r)) return; + if(IsNull(self)) { + self.Set(r); + return; + } + if(r.left < self.left) self.left = r.left; + if(r.top < self.top) self.top = r.top; + if(r.right > self.right) self.right = r.right; + if(r.bottom > self.bottom) self.bottom = r.bottom; +} + +//bool Rect_double_Contains(const Rect_& self, const Point_& p) { +// return p.x >= self.left && p.x <= self.right && p.y >= self.top && p.y <= self.bottom; +//} + +//template <> +//bool Rect_::Intersects(const Rect_& r) const { +bool Rect_double_Intersects(const Rect_& self, const Rect_& r) { + if(IsNull(self) || IsNull(r)) return false; + return r.right >= self.left && r.bottom >= self.top && r.left <= self.right && r.top <= self.bottom; +} + +//template <> +//Point_ Rect_::Bind(Point_ pt) const +Point_ Rect_double_Bind(const Rect_& self, Point_ pt) { + return Point_(pt.x < self.left ? self.left : pt.x > self.right ? self.right : pt.x, + pt.y < self.top ? self.top : pt.y > self.bottom ? self.bottom : pt.y); +} + +Size iscale(Size a, int b, int c) +{ + return Size(iscale(a.cx, b, c), iscale(a.cy, b, c)); +} + +Size iscalefloor(Size a, int b, int c) +{ + return Size(iscalefloor(a.cx, b, c), iscalefloor(a.cy, b, c)); +} + +Size iscaleceil(Size a, int b, int c) +{ + return Size(iscaleceil(a.cx, b, c), iscaleceil(a.cy, b, c)); +} + +Size idivfloor(Size a, int b) +{ + return Size(idivfloor(a.cx, b), idivfloor(a.cy, b)); +} + +Size idivceil(Size a, int b) +{ + return Size(idivceil(a.cx, b), idivceil(a.cy, b)); +} + +Size iscale(Size a, Size b, Size c) +{ + return Size(iscale(a.cx, b.cx, c.cx), iscale(a.cy, b.cy, c.cy)); +} + +Size iscalefloor(Size a, Size b, Size c) +{ + return Size(iscalefloor(a.cx, b.cx, c.cx), iscalefloor(a.cy, b.cy, c.cy)); +} + +Size iscaleceil(Size a, Size b, Size c) +{ + return Size(iscaleceil(a.cx, b.cx, c.cx), iscaleceil(a.cy, b.cy, c.cy)); +} + +Size idivfloor(Size a, Size b) +{ + return Size(idivfloor(a.cx, b.cx), idivfloor(a.cy, b.cy)); +} + +Size idivceil(Size a, Size b) +{ + return Size(idivceil(a.cx, b.cx), idivceil(a.cy, b.cy)); +} + +Size GetRatioSize(Size sz, int cx, int cy) +{ + return cx == 0 ? cy == 0 ? sz : sz.cy ? Size(sz.cx * cy / sz.cy, cy) : Size(0, 0) + : cy == 0 ? sz.cx ? Size(cx, sz.cy * cx / sz.cx) : Size(0, 0) + : Size(cx, cy); +} + +Size GetFitSize(Size sz, int cx, int cy) +{ + if(cx <= 0 || cy <= 0 || sz.cx <= 0 || sz.cy <= 0) + return Size(0, 0); + if(cx * sz.cy >= cy * sz.cx) // too high + return iscale(sz, cy, sz.cy); + else + return iscale(sz, cx, sz.cx); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Gtypes.h b/uppdev/CoreTopics/Gtypes.h new file mode 100644 index 000000000..f9063a3e5 --- /dev/null +++ b/uppdev/CoreTopics/Gtypes.h @@ -0,0 +1,699 @@ +template struct Point_; +template struct Size_; +template struct Rect_; + +template +struct Size_ : Moveable< Size_ > { + T cx, cy; + + void Clear() { cx = cy = 0; } + bool IsEmpty() const { return cx == 0 || cy == 0; } + + void SetNull() { cx = Null; } + bool IsNullInstance() const { return UPP::IsNull(cx); } + + Size_& operator+=(Size_ p) { cx += p.cx; cy += p.cy; return *this; } + Size_& operator+=(T t) { cx += t; cy += t; return *this; } + Size_& operator-=(Size_ p) { cx -= p.cx; cy -= p.cy; return *this; } + Size_& operator-=(T t) { cx -= t; cy -= t; return *this; } + Size_& operator*=(Size_ p) { cx *= p.cx; cy *= p.cy; return *this; } + Size_& operator*=(T t) { cx *= t; cy *= t; return *this; } + Size_& operator/=(Size_ p) { cx /= p.cx; cy /= p.cy; return *this; } + Size_& operator/=(T t) { cx /= t; cy /= t; return *this; } + Size_& operator<<=(int sh) { cx <<= sh; cy <<= sh; return *this; } + Size_& operator>>=(int sh) { cx >>= sh; cy >>= sh; return *this; } + + Size_& operator++() { ++cx; ++cy; return *this; } + Size_& operator--() { --cx; --cy; return *this; } + + friend Size_ operator+(Size_ s) { return s; } + friend Size_ operator-(Size_ s) { return Size_(-s.cx, -s.cy); } + + friend Size_ operator+(Size_ a, Size_ b) { return a += b; } + friend Size_ operator+(Size_ a, T t) { return a += t; } + friend Size_ operator+(T t, Size_ b) { return b += t; } + friend Size_ operator-(Size_ a, Size_ b) { return a -= b; } + friend Size_ operator-(Size_ a, T t) { return a -= t; } + friend Size_ operator-(T t, Size_ b) { b = -b; return b += t; } + friend Size_ operator*(Size_ a, Size_ b) { return a *= b; } + friend Size_ operator*(Size_ a, T b) { return a *= b; } + friend Size_ operator*(T a, Size_ b) { return b *= a; } + friend Size_ operator/(Size_ a, Size_ b) { return a /= b; } + friend Size_ operator/(Size_ a, T b) { return a /= b; } + friend Size_ operator<<(Size_ a, int sh) { return a <<= sh; } + friend Size_ operator>>(Size_ a, int sh) { return a >>= sh; } + + friend bool operator==(Size_ a, Size_ b) { return a.cx == b.cx && a.cy == b.cy; } + friend bool operator!=(Size_ a, Size_ b) { return !(a == b); } + + friend Size_ min(Size_ a, Size_ b) { return Size_(min(a.cx, b.cx), min(a.cy, b.cy)); } + friend Size_ max(Size_ a, Size_ b) { return Size_(max(a.cx, b.cx), max(a.cy, b.cy)); } + + friend Size_ Nvl(Size_ a, Size_ b) { return IsNull(a) ? b : a; } + + friend T ScalarProduct(Size_ a, Size_ b) { return a.cx * b.cx + a.cy * b.cy; } + friend T VectorProduct(Size_ a, Size_ b) { return a.cx * b.cy - a.cy * b.cx; } + friend T Squared(Size_ a) { return a.cx * a.cx + a.cy * a.cy; } + friend double Length(Size_ a) { return hypot(a.cx, a.cy); } + + unsigned GetHashValue() const { return UPP::GetHashValue(cx) ^ UPP::GetHashValue(cy); } + + String ToString() const; + + Size_() {} + Size_(T cx, T cy) : cx(cx), cy(cy) {} + + Size_(const Size_& sz) : cx((T)sz.cx), cy((T)sz.cy) {} + Size_(const Size_& sz) : cx((T)sz.cx), cy((T)sz.cy) {} + Size_(const Size_& sz) : cx((T)sz.cx), cy((T)sz.cy) {} + Size_(const Size_& sz) : cx((T)sz.cx), cy((T)sz.cy) {} + + Size_(const Point_& pt) : cx(pt.x), cy(pt.y) {} + + Size_(const Nuller&) { cx = cy = Null; } + + operator Value() const { return RichValue(*this); } + Size_(const Value& src) { *this = RichValue::Extract(src); } + + void Serialize(Stream& s) { s % cx % cy; } + +#ifdef PLATFORM_WIN32 + operator SIZE*() { ASSERT(sizeof(*this) == sizeof(SIZE)); return (SIZE*)this; } + operator const SIZE*() const { ASSERT(sizeof(*this) == sizeof(SIZE)); return (SIZE*)this; } + operator SIZE() const { SIZE sz; sz.cx = cx; sz.cy = cy; return sz; } + LONG GetLONG() const { return MAKELONG(cx, cy); } + + Size_(POINT pt) : cx((T)pt.x), cy((T)pt.y) {} + Size_(SIZE sz) : cx((T)sz.cx), cy((T)sz.cy) {} + explicit Size_(LONG lParam) { cx = (T)(int16)LOWORD(lParam); cy = (T)(int16)HIWORD(lParam); } +#endif +}; + +template +String Size_::ToString() const { + String ss; + return ss << '(' << cx << ", " << cy << ')'; +} + +template +struct Point_ : Moveable< Point_ > { + T x, y; + + typedef Size_ Sz; + + void Clear() { x = y = 0; } + bool IsZero() const { return x == 0 && y == 0; } + + void SetNull() { x = y = Null; } + bool IsNullInstance() const { return UPP::IsNull(x); } + + void Offset(T dx, T dy) { x += dx; y += dy; } + + Point_& operator+=(Sz p) { x += p.cx; y += p.cy; return *this; } + Point_& operator+=(Point_ p) { x += p.x; y += p.y; return *this; } + Point_& operator+=(T t) { x += t; y += t; return *this; } + Point_& operator-=(Sz p) { x -= p.cx; y -= p.cy; return *this; } + Point_& operator-=(Point_ p) { x -= p.x; y -= p.y; return *this; } + Point_& operator-=(T t) { x -= t; y -= t; return *this; } + Point_& operator*=(Sz p) { x *= p.cx; y *= p.cy; return *this; } + Point_& operator*=(Point_ p) { x *= p.x; y *= p.y; return *this; } + Point_& operator*=(T t) { x *= t; y *= t; return *this; } + Point_& operator/=(Sz p) { x /= p.cx; y /= p.cy; return *this; } + Point_& operator/=(Point_ p) { x /= p.x; y /= p.y; return *this; } + Point_& operator/=(T t) { x /= t; y /= t; return *this; } + Point_& operator<<=(int sh) { x <<= sh; y <<= sh; return *this; } + Point_& operator>>=(int sh) { x >>= sh; y >>= sh; return *this; } + + Point_& operator++() { ++x; ++y; return *this; } + Point_& operator--() { --x; --y; return *this; } + + friend Point_ operator+(Point_ p) { return p; } + friend Point_ operator-(Point_ p) { return Point_(-p.x, -p.y); } + + friend Point_ operator+(Point_ a, Sz b) { return a += b; } + friend Point_ operator+(Point_ a, Point_ b) { return a += b; } + friend Point_ operator+(Point_ a, T t) { return a += t; } + friend Point_ operator+(T t, Point_ b) { return b += t; } + friend Sz operator+(Sz a, Point_ b) { return Point_(a) + b; } + friend Sz& operator+=(Sz& a, Point_ b) { return a = a + b; } + friend Point_ operator-(Point_ a, Sz b) { return a -= b; } + friend Point_ operator-(Point_ a, T t) { return a -= t; } + friend Sz operator-(Point_ a, Point_ b) { return a -= b; } + friend Sz operator-(Sz a, Point_ b) { return Point_(a) - b; } + friend Sz& operator-=(Sz& a, Point_ b) { return a = a - b; } + friend Point_ operator*(Point_ a, Point_ b) { return a *= b; } + friend Point_ operator*(Point_ a, T b) { return a *= b; } + friend Point_ operator*(T a, Point_ b) { return b *= a; } + friend Point_ operator/(Point_ a, Sz b) { return a /= b; } + friend Point_ operator/(Point_ a, T b) { return a /= b; } + friend Point_ operator<<(Point_ a, int sh) { return a <<= sh; } + friend Point_ operator>>(Point_ a, int sh) { return a >>= sh; } + + + friend bool operator==(Point_ a, Point_ b) { return a.x == b.x && a.y == b.y; } + friend bool operator!=(Point_ a, Point_ b) { return a.x != b.x || a.y != b.y; } + + friend Point_ min(Point_ a, Point_ b) { return Point_(min(a.x, b.x), min(a.y, b.y)); } + friend Point_ max(Point_ a, Point_ b) { return Point_(max(a.x, b.x), max(a.y, b.y)); } + + friend Point_ Nvl(Point_ a, Point_ b) { return IsNull(a) ? b : a; } + + unsigned GetHashValue() const { return UPP::GetHashValue(x) ^ UPP::GetHashValue(y); } + + String ToString() const; + + Point_() {} + Point_(T x, T y) : x(x), y(y) {} + + Point_(const Point_& pt) : x((T)pt.x), y((T)pt.y) {} + Point_(const Point_& pt) : x((T)pt.x), y((T)pt.y) {} + Point_(const Point_& pt) : x((T)pt.x), y((T)pt.y) {} + Point_(const Point_& pt) : x((T)pt.x), y((T)pt.y) {} + + Point_(const Size_& sz) : x(sz.cx), y(sz.cy) {} + + Point_(const Nuller&) { x = y = Null; } + + operator Value() const { return RichValue(*this); } + /*explicit */Point_(const Value& src) { *this = RichValue::Extract(src); } + + void Serialize(Stream& s) { s % x % y; } + +#ifdef PLATFORM_WIN32 + operator POINT*() { ASSERT(sizeof(*this) == sizeof(POINT)); return (POINT*)this; } + operator const POINT*() const { ASSERT(sizeof(*this) == sizeof(POINT)); return (POINT*)this; } + operator POINT() const { POINT p; p.x = x; p.y = y; return p; } + LONG GetLONG() const { return MAKELONG(x, y); } + + Point_(POINT pt) : x((T)pt.x), y((T)pt.y) {} + Point_(SIZE sz) : x((T)sz.cx), y((T)sz.cy) {} + explicit Point_(LONG lParam) { x = (T)(int16)LOWORD(lParam); y = (T)(int16)HIWORD(lParam); } +#endif +}; + +template +String Point_::ToString() const { + String ss; + return ss << '[' << x << ", " << y << ']'; +} + +template +T GHalf_(T t) { return t >> 1; } + +template <> +inline double GHalf_(double d) { return d / 2; } + +template +struct Rect_ : Moveable< Rect_ > { + T left, top, right, bottom; + + typedef Point_ Pt; + typedef Size_ Sz; + + void Clear() { left = top = right = bottom = 0; } + + bool IsEmpty() const { return right <= left || bottom <= top; } + bool IsNullInstance() const; + + Pt TopLeft() const { return Pt(left, top); } + Pt TopCenter() const { return Pt(GHalf_(left + right), top); } + Pt TopRight() const { return Pt(right, top); } + Pt CenterLeft() const { return Pt(left, GHalf_(top + bottom)); } + Pt CenterPoint() const { return Pt(GHalf_(left + right), GHalf_(top + bottom)); } + Pt CenterRight() const { return Pt(right, GHalf_(top + bottom)); } + Pt BottomLeft() const { return Pt(left, bottom); } + Pt BottomCenter() const { return Pt(GHalf_(left + right), bottom); } + Pt BottomRight() const { return Pt(right, bottom); } + T Width() const { return right - left; } + T Height() const { return bottom - top; } + Sz Size() const { return Sz(right - left, bottom - top); } + + T GetWidth() const { return right - left; } + T GetHeight() const { return bottom - top; } + Sz GetSize() const { return Sz(right - left, bottom - top); } + + Pt CenterPos(T cx, T cy) const; + Pt CenterPos(Sz sz) const { return CenterPos(sz.cx, sz.cy); } + Rect_ CenterRect(Sz sz) const { return Rect_(CenterPos(sz), sz); } + Rect_ CenterRect(T cx, T cy) const { return CenterRect(Sz(cx, cy)); } + + void Set(T l, T t, T r, T b) { left = l; top = t; right = r; bottom = b; } + void Set(Pt a, Pt b) { left = a.x; top = a.y; right = b.x; bottom = b.y; } + void Set(Pt a, Sz sz) { Set(a, a + sz); } + void Set(const Rect_& r) { Set(r.left, r.top, r.right, r.bottom); } + + void SetSize(int cx, int cy) { right = left + cx; bottom = top + cy; } + void SetSize(Sz sz) { SetSize(sz.cx, sz.cy); } + + void InflateHorz(T dx) { left -= dx; right += dx; } + void InflateVert(T dy) { top -= dy; bottom += dy; } + void Inflate(T dx, T dy) { InflateHorz(dx); InflateVert(dy); } + void Inflate(Sz sz) { Inflate(sz.cx, sz.cy); } + void Inflate(T dxy) { Inflate(dxy, dxy); } + void Inflate(T l, T t, T r, T b) { left -= l; top -= t; right += r; bottom += b; } + void Inflate(const Rect_& r) { Inflate(r.left, r.top, r.right, r.bottom); } + + void DeflateHorz(T dx) { InflateHorz(-dx); } + void DeflateVert(T dy) { InflateVert(-dy); } + void Deflate(T dx, T dy) { Inflate(-dx, -dy); } + void Deflate(Sz sz) { Inflate(-sz); } + void Deflate(T dxy) { Inflate(-dxy); } + void Deflate(T l, T t, T r, T b) { Inflate(-l, -t, -r, -b); } + void Deflate(const Rect_& r) { Deflate(r.left, r.top, r.right, r.bottom); } + + Rect_ InflatedHorz(T dx) const { Rect_ r = *this; r.InflateHorz(dx); return r; } + Rect_ InflatedVert(T dy) const { Rect_ r = *this; r.InflateVert(dy); return r; } + Rect_ Inflated(T dx, T dy) const { Rect_ r = *this; r.Inflate(dx, dy); return r; } + Rect_ Inflated(Sz sz) const { Rect_ r = *this; r.Inflate(sz); return r; } + Rect_ Inflated(T dxy) const { Rect_ r = *this; r.Inflate(dxy); return r; } + Rect_ Inflated(T l, T t, T r, T b) const { Rect_ m = *this; m.Inflate(l, t, r, b); return m; } + Rect_ Inflated(const Rect_& q) const { Rect_ r = *this; r.Inflate(q); return r; } + + Rect_ DeflatedHorz(T dx) const { Rect_ r = *this; r.DeflateHorz(dx); return r; } + Rect_ DeflatedVert(T dy) const { Rect_ r = *this; r.DeflateVert(dy); return r; } + Rect_ Deflated(T dx, T dy) const { Rect_ r = *this; r.Deflate(dx, dy); return r; } + Rect_ Deflated(Sz sz) const { Rect_ r = *this; r.Deflate(sz); return r; } + Rect_ Deflated(T dxy) const { Rect_ r = *this; r.Deflate(dxy); return r; } + Rect_ Deflated(T l, T t, T r, T b) const { Rect_ m = *this; m.Deflate(l, t, r, b); return m; } + Rect_ Deflated(const Rect_& q) const { Rect_ r = *this; r.Deflate(q); return r; } + + void OffsetHorz(T dx) { left += dx; right += dx; } + void OffsetVert(T dy) { top += dy; bottom += dy; } + void Offset(T dx, T dy) { OffsetHorz(dx); OffsetVert(dy); } + void Offset(Sz sz) { Offset(sz.cx, sz.cy); } + void Offset(Pt p) { Offset(p.x, p.y); } + + Rect_ OffsetedHorz(T dx) const { Rect_ r = *this; r.OffsetHorz(dx); return r; } + Rect_ OffsetedVert(T dy) const { Rect_ r = *this; r.OffsetVert(dy); return r; } + Rect_ Offseted(T dx, T dy) const { Rect_ r = *this; r.Offset(dx, dy); return r; } + Rect_ Offseted(Sz sz) const { Rect_ r = *this; r.Offset(sz); return r; } + Rect_ Offseted(Pt p) const { Rect_ r = *this; r.Offset(p); return r; } + + void Normalize(); + Rect_ Normalized() const { Rect_ r = *this; r.Normalize(); return r; } + + void Union(Pt p); + void Union(const Rect_& rc); + void Intersect(const Rect_& rc); + + bool Contains(T x, T y) const; + bool Contains(Pt p) const { return Contains(p.x, p.y); } + bool Contains(const Rect_& rc) const; + bool Intersects(const Rect_& rc) const; + + Pt Bind(Pt pt) const; + + Rect_& operator+=(Sz sz) { Offset(sz); return *this; } + Rect_& operator+=(Pt p) { Offset(p); return *this; } + Rect_& operator+=(const Rect_& b); + Rect_& operator-=(Sz sz) { Offset(-sz); return *this; } + Rect_& operator-=(Pt p) { Offset(-p); return *this; } + Rect_& operator-=(const Rect_& b); + + Rect_& operator|=(Pt p) { Union(p); return *this; } + Rect_& operator|=(const Rect_& rc) { Union(rc); return *this; } + Rect_& operator&=(const Rect_& rc) { Intersect(rc); return *this; } + + bool operator==(const Rect_& b) const; + bool operator!=(const Rect_& b) const { return !operator==(b); } + + friend Rect_ operator+(Rect_ a, Sz b) { return a += b; } + friend Rect_ operator+(Sz a, Rect_ b) { return b += a; } + friend Rect_ operator+(Rect_ a, Pt b) { return a += b; } + friend Rect_ operator+(Pt a, Rect_ b) { return b += a; } + friend Rect_ operator+(Rect_ a, const Rect_& b) { return a += b; } + friend Rect_ operator-(Rect_ a, Sz b) { return a -= b; } + friend Rect_ operator-(Rect_ a, Pt b) { return a -= b; } + friend Rect_ operator-(Rect_ a, const Rect_& b) { return a -= b; } + friend Rect_ operator|(Rect_ a, Rect_ b) { a.Union(b); return a; } + friend Rect_ operator&(Rect_ a, Rect_ b) { a.Intersect(b); return a; } + friend bool operator&&(const Rect_& a, const Rect_& b) { return a.Intersects(b); } + friend bool operator>=(const Rect_& a, Pt b) { return a.Contains(b); } + friend bool operator<=(Pt a, const Rect_& b) { return b.Contains(a); } + friend bool operator<=(const Rect_& a, const Rect_& b) { return b.Contains(a); } + friend bool operator>=(const Rect_& b, const Rect_& a) { return a.Contains(b); } + + friend const Rect_& Nvl(const Rect_& a, const Rect_& b) { return IsNull(a) ? b : a; } + + unsigned GetHashValue() const { return UPP::GetHashValue(left) ^ UPP::GetHashValue(top) ^ UPP::GetHashValue(right) ^ UPP::GetHashValue(bottom); } + + String ToString() const; + + Rect_() {} + Rect_(T l, T t, T r, T b) { Set(l, t, r, b); } + Rect_(Pt a, Pt b) { Set(a, b); } + Rect_(Pt a, Sz sz) { Set(a, sz); } + Rect_(Sz sz) { Set(0, 0, sz.cx, sz.cy); } + + Rect_(const Rect_& r) { Set((T)r.left, (T)r.top, (T)r.right, (T)r.bottom); } + Rect_(const Rect_& r) { Set((T)r.left, (T)r.top, (T)r.right, (T)r.bottom); } + Rect_(const Rect_& r) { Set((T)r.left, (T)r.top, (T)r.right, (T)r.bottom); } + Rect_(const Rect_& r) { Set((T)r.left, (T)r.top, (T)r.right, (T)r.bottom); } + + Rect_(const Nuller&); + + operator Value() const { return RichValue(*this); } + /*explicit */Rect_(const Value& src) { *this = RichValue::Extract(src); } + + void Serialize(Stream& s) { s % left % top % right % bottom; } + +#ifdef PLATFORM_WIN32 + operator const RECT*() const { ASSERT(sizeof(*this) == sizeof(RECT)); return (RECT*)this; } + operator RECT*() { ASSERT(sizeof(*this) == sizeof(RECT)); return (RECT*)this; } + operator RECT&() { ASSERT(sizeof(*this) == sizeof(RECT)); return *(RECT*)this; } + operator RECT() const { RECT r; r.top = top; r.bottom = bottom; + r.left = left; r.right = right; return r; } + Rect_(const RECT& rc) { Set((T)rc.left, (T)rc.top, (T)rc.right, (T)rc.bottom); } +#endif +}; + +template +inline Rect_::Rect_(const Nuller&) { + left = top = right = bottom = Null; +} + +template <> +inline Rect_::Rect_(const Nuller&) { + left = top = 0; + right = bottom = -1; +} + +template +bool Rect_::IsNullInstance() const { + return IsNull(left); +} + +template <> +inline bool Rect_::IsNullInstance() const { + return left > right || top > bottom; +} + +template +Point_ Rect_::CenterPos(T cx, T cy) const { + return Point_(left + GHalf_(Width() - cx), top + GHalf_(Height() - cy)); +} + +template +void Rect_::Normalize() { + if(left > right) Swap(left, right); + if(top > bottom) Swap(top, bottom); +} + +template +void Rect_::Union(Pt p) { + if(IsNull(p)) return; + if(IsNullInstance()) { + right = 1 + (left = p.x); + bottom = 1 + (top = p.y); + } + else + { + if(p.x >= right) right = p.x + 1; + else if(p.x < left) left = p.x; + if(p.y >= bottom) bottom = p.y + 1; + else if(p.y < top) top = p.y; + } +} + +template <> +inline void Rect_::Union(Point_ p) { + if(IsNull(p)) return; + if(IsNullInstance()) + { + left = right = p.x; + top = bottom = p.y; + } + else + { + if(p.x < left) left = p.x; + else if(p.x > right) right = p.x; + if(p.y < top) top = p.y; + else if(p.y > bottom) bottom = p.y; + } +} + +template +void Rect_::Union(const Rect_& r) { + if(IsNull(r)) return; + if(IsNullInstance()) { + Set(r); + return; + } + if(r.left < left) left = r.left; + if(r.top < top) top = r.top; + if(r.right > right) right = r.right; + if(r.bottom > bottom) bottom = r.bottom; +} + +void Rect_double_Union(Rect_& self, const Rect_& r); + +template <> +inline void Rect_::Union(const Rect_& r) { + Rect_double_Union(*this, r); +} + +template +void Rect_::Intersect(const Rect_& r) { + if(r.left > left) left = r.left; + if(r.top > top) top = r.top; + if(right < left) right = left; + if(r.right < right) right = r.right; + if(r.bottom < bottom) bottom = r.bottom; + if(bottom < top) bottom = top; +} + +template +bool Rect_::Contains(T x, T y) const { + return x >= left && x < right && y >= top && y < bottom; +} + +template <> +inline bool Rect_::Contains(double x, double y) const { + return x >= left && x <= right && y >= top && y <= bottom; +} + +template +bool Rect_::Contains(const Rect_& r) const { + return r.left >= left && r.top >= top && r.right <= right && r.bottom <= bottom; +} + +template +bool Rect_::Intersects(const Rect_& r) const { + if(IsEmpty() || r.IsEmpty()) return false; + return r.right > left && r.bottom > top && r.left < right && r.top < bottom; +} + +bool Rect_double_Intersects(const Rect_& self, const Rect_& r); + +template <> +inline bool Rect_::Intersects(const Rect_& r) const { + return Rect_double_Intersects(*this, r); +} + +template +Point_ Rect_::Bind(Point_ pt) const { + return Point_(pt.x < left ? left : pt.x >= right ? right - 1 : pt.x, + pt.y < top ? top : pt.y >= bottom ? bottom - 1 : pt.y); +} + +Point_ Rect_double_Bind(const Rect_& self, Point_ pt); + +template <> +inline Point_ Rect_::Bind(Point_ pt) const { + return Rect_double_Bind(*this, pt); +} + +template +Rect_& Rect_::operator-=(const Rect_& b) { + left -= b.left; + top -= b.top; + right -= b.right; + bottom -= b.bottom; + return *this; +} + +template +Rect_& Rect_::operator+=(const Rect_& b) { + left += b.left; + top += b.top; + right += b.right; + bottom += b.bottom; + return *this; +} + +template +bool Rect_::operator==(const Rect_& b) const { + return top == b.top && bottom == b.bottom && left == b.left && right == b.right; +} + +template +String Rect_::ToString() const +{ + String str; + return str << AsString(TopLeft()) << " - " << AsString(BottomRight()) + << " : " << AsString(Size()); +} + +typedef Size_ Size; +typedef Point_ Point; +typedef Rect_ Rect; + +typedef Size_ Size16; +typedef Point_ Point16; +typedef Rect_ Rect16; + +typedef Size_ Sizef; +typedef Point_ Pointf; +typedef Rect_ Rectf; + +typedef Size_ Size64; +typedef Point_ Point64; +typedef Rect_ Rect64; + +const int SIZE_V = 70; +const int SIZE16_V = 71; +const int SIZEF_V = 72; +const int SIZE64_V = 79; + +template<> inline dword ValueTypeNo(const Size&) { return SIZE_V; } +template<> inline dword ValueTypeNo(const Size16&) { return SIZE16_V; } +template<> inline dword ValueTypeNo(const Size64&) { return SIZE64_V; } +template<> inline dword ValueTypeNo(const Sizef&) { return SIZEF_V; } + +const int POINT_V = 73; +const int POINT16_V = 74; +const int POINTF_V = 75; +const int POINT64_V = 80; + +template<> inline dword ValueTypeNo(const Point&) { return POINT_V; } +template<> inline dword ValueTypeNo(const Point16&) { return POINT16_V; } +template<> inline dword ValueTypeNo(const Point64&) { return POINT64_V; } +template<> inline dword ValueTypeNo(const Pointf&) { return POINTF_V; } + +const int RECT_V = 76; +const int RECT16_V = 77; +const int RECTF_V = 78; +const int RECT64_V = 81; + +template<> inline dword ValueTypeNo(const Rect&) { return RECT_V; } +template<> inline dword ValueTypeNo(const Rect16&) { return RECT16_V; } +template<> inline dword ValueTypeNo(const Rect64&) { return RECT64_V; } +template<> inline dword ValueTypeNo(const Rectf&) { return RECTF_V; } + +Rect RectC(int x, int y, int cx, int cy); +Rect16 Rect16C(int16 x, int16 y, int16 cx, int16 cy); +Rectf RectfC(double x, double y, double cx, double cy); + +inline Size& operator*=(Size& sz, double a) +{ + sz.cx = int(sz.cx * a); + sz.cy = int(sz.cy * a); + return sz; +} + +inline Size& operator/=(Size& sz, double a) +{ + sz.cx = int(sz.cx / a); + sz.cy = int(sz.cy / a); + return sz; +} + +inline Size& operator*=(Size& sz, Sizef a) +{ + sz.cx = int(sz.cx * a.cx); + sz.cy = int(sz.cy * a.cy); + return sz; +} + +inline Size& operator/=(Size& sz, Sizef a) +{ + sz.cx = int(sz.cx / a.cx); + sz.cy = int(sz.cy / a.cy); + return sz; +} + +inline Sizef operator*(Size sz, double a) { return Sizef(sz.cx * a, sz.cy * a); } +inline Sizef operator*(double a, Size sz) { return Sizef(sz.cx * a, sz.cy * a); } +inline Sizef operator/(Size sz, double a) { return Sizef(sz.cx / a, sz.cy / a); } +inline Sizef operator*(Size sz, Sizef a) { return Sizef(sz.cx * a.cx, sz.cy * a.cy); } +inline Sizef operator*(Sizef a, Size sz) { return Sizef(sz.cx * a.cx, sz.cy * a.cy); } +inline Sizef operator/(Size sz, Sizef a) { return Sizef(sz.cx / a.cx, sz.cy / a.cy); } + +inline Size16& operator*=(Size16& sz, double a) +{ + sz.cx = int16(sz.cx * a); + sz.cy = int16(sz.cy * a); + return sz; +} + +inline Size16& operator/=(Size16& sz, double a) +{ + sz.cx = int16(sz.cx / a); + sz.cy = int16(sz.cy / a); + return sz; +} + +inline Size16& operator*=(Size16& sz, Sizef a) +{ + sz.cx = int16(sz.cx * a.cx); + sz.cy = int16(sz.cy * a.cy); + return sz; +} + +inline Size16& operator/=(Size16& sz, Sizef a) +{ + sz.cx = int16(sz.cx / a.cx); + sz.cy = int16(sz.cy / a.cy); + return sz; +} + +inline Sizef operator*(Size16 sz, double a) { return Sizef(sz.cx * a, sz.cy * a); } +inline Sizef operator*(double a, Size16 sz) { return Sizef(sz.cx * a, sz.cy * a); } +inline Sizef operator/(Size16 sz, double a) { return Sizef(sz.cx / a, sz.cy / a); } +inline Sizef operator*(Size16 sz, Sizef a) { return Sizef(sz.cx * a.cx, sz.cy * a.cy); } +inline Sizef operator*(Sizef a, Size16 sz) { return Sizef(sz.cx * a.cx, sz.cy * a.cy); } +inline Sizef operator/(Size16 sz, Sizef a) { return Sizef(sz.cx / a.cx, sz.cy / a.cy); } + +inline Rect RectC(int x, int y, int cx, int cy) { + return Rect(x, y, x + cx, y + cy); +} + +inline Rect16 Rect16C(int16 x, int16 y, int16 cx, int16 cy) { + return Rect16(x, y, x + cx, y + cy); +} + +inline Rectf RectfC(double x, double y, double cx, double cy) { + return Rectf(x, y, x + cx, y + cy); +} + +inline Rect RectSort(Point a, Point b) { return Rect(min(a, b), max(a, b) + 1); } +inline Rectf RectfSort(Pointf a, Pointf b) { return Rectf(min(a, b), max(a, b)); } + +Stream& Pack16(Stream& s, Point& p); +Stream& Pack16(Stream& s, Size& sz); +Stream& Pack16(Stream& s, Rect& r); + +Size iscale(Size a, int b, int c); +Size iscalefloor(Size a, int b, int c); +Size iscaleceil(Size a, int b, int c); +Size idivfloor(Size a, int b); +Size idivceil(Size a, int b); +Size iscale(Size a, Size b, Size c); +Size iscalefloor(Size a, Size b, Size c); +Size iscaleceil(Size a, Size b, Size c); +Size idivfloor(Size a, Size b); +Size idivceil(Size a, Size b); + +enum Alignment { + ALIGN_NULL, + ALIGN_LEFT, + ALIGN_TOP = ALIGN_LEFT, + ALIGN_RIGHT, + ALIGN_BOTTOM = ALIGN_RIGHT, + ALIGN_CENTER, + ALIGN_JUSTIFY, +}; + +Size GetRatioSize(Size stdsize, int cx, int cy); +Size GetFitSize(Size objsize, int cx, int cy); +inline Size GetFitSize(Size objsize, Size intosize) { return GetFitSize(objsize, intosize.cx, intosize.cy); } diff --git a/uppdev/CoreTopics/Hash.cpp b/uppdev/CoreTopics/Hash.cpp new file mode 100644 index 000000000..512162ac3 --- /dev/null +++ b/uppdev/CoreTopics/Hash.cpp @@ -0,0 +1,369 @@ +#include + +NAMESPACE_UPP + +#ifdef _MSC_VER +#pragma inline_depth(255) +#pragma optimize("t", on) +#endif + +unsigned Pow2Bound(unsigned i) +{ + unsigned n = 1; + while(n < i) { + n <<= 1; + if(n == 0) + return 1 << 31; + } + return n; +} + +unsigned PrimeBound(unsigned n) +{ + static unsigned prime_tab[] = { + 17, 29, 61, 127, 257, 509, 1021, 2053, 4093, 8191, 16381, + 32771, 65537, 131071, 262147, 524287, 1048573, 2097143, + 4194301, 8388617, 16777213, 33554467, 67108859, 134217757, + 268435459, 536870909, 1073741827, 2147483647u, 4294967291u + }; + return *FindUpperBoundIter(prime_tab, prime_tab + __countof(prime_tab), n); +} + +#ifdef FOLDHASH +inline unsigned HashBound(unsigned i) { return Pow2Bound(i); } +#else +inline unsigned HashBound(unsigned i) { return PrimeBound(i); } +#endif + +void HashBase::Free() +{ + if(map) + delete [](byte *)map; + map = NULL; + mcount = 0; +} + +void HashBase::ClearIndex() +{ + link.Clear(); + unlinked = -1; + Free(); +} + +HashBase::HashBase() +{ + unlinked = -1; + map = NULL; + mcount = 0; +} + +HashBase::HashBase(pick_ HashBase& b) +: hash(b.hash), + link(b.link) +{ + map = b.map; + mcount = b.mcount; + unlinked = b.unlinked; + const_cast(b).map = NULL; +} + +void HashBase::operator=(pick_ HashBase& b) +{ + hash = b.hash; + link = b.link; + Free(); + map = b.map; + mcount = b.mcount; + unlinked = b.unlinked; + const_cast(b).map = NULL; +} + +HashBase::HashBase(const HashBase& b, int) +: hash(b.hash, 0) +{ + unlinked = -1; + mcount = 0; + map = NULL; + Reindex(); +} + +void HashBase::operator<<=(const HashBase& b) +{ + ClearIndex(); + hash <<= b.hash; + Reindex(); +} + +HashBase::~HashBase() +{ + Free(); +} + +inline void HashBase::LinkBefore(int i, Link& l, int bi) +{ + Link& bl = link[bi]; + l.next = bi; + l.prev = bl.prev; + bl.prev = i; + link[l.prev].next = i; +} + +void HashBase::Trim(int count) +{ + ASSERT(count <= hash.GetCount() && count >= 0); + for(int i = count; i < link.GetCount(); i++) + Unlink(i, link[i]); + link.Trim(count); + hash.SetCount(count); +} + +void HashBase::Drop(int n) +{ + Trim(hash.GetCount() - n); +} + +void HashBase::FinishIndex() +{ + int q = link.GetCount(); + link.Reserve(hash.GetAlloc()); + link.AddN(hash.GetCount() - q); + for(int i = q; i < hash.GetCount(); i++) + LinkTo(i, link[i], hash[i] & UNSIGNED_HIBIT ? unlinked : Mapi(i)); +} + +void HashBase::Reindex(int n) +{ + ClearIndex(); + Free(); + mcount = n = HashBound(n); + map = (int *)new byte[n * sizeof(int)]; + Fill(map, map + n, -1); + FinishIndex(); +} + +void HashBase::Reindex() +{ + Reindex(hash.GetCount()); +} + +void HashBase::Add(unsigned _hash) +{ + hash.Add(_hash & ~UNSIGNED_HIBIT); + DoIndex(); +} + +void HashBase::SetUn(int i, unsigned _hash) +{ + if(map) { + Link& lnk = link[i]; + Unlink(i, lnk); + LinkTo(i, lnk, Maph(_hash & ~UNSIGNED_HIBIT)); + } + hash[i] = _hash & ~UNSIGNED_HIBIT; +} + +Vector HashBase::GetUnlinked() const +{ + Vector r; + int q = unlinked; + if(q >= 0) { + do { + r.Add(q); + q = link[q].next; + } + while(q != unlinked); + } + return r; +} + +int HashBase::Put(unsigned _hash) +{ + if(unlinked < 0) return -1; + Link& l = link[unlinked]; + int i = unlinked; + unlinked = link[unlinked].next; + if(i == unlinked) + unlinked = -1; + else { + link[l.next].prev = l.prev; + link[l.prev].next = l.next; + } + LinkTo(i, l, Maph(_hash & ~UNSIGNED_HIBIT)); + hash[i] = _hash & ~UNSIGNED_HIBIT; + return i; +} + +void HashBase::Set(int i, unsigned _hash) { + if(map) { + Link& lnk = link[i]; + Unlink(i, lnk); + int& mi = Maph(_hash & ~UNSIGNED_HIBIT); + int ii = mi; + if(ii < 0) + mi = lnk.prev = lnk.next = i; + else + if(i < ii) { + LinkBefore(i, lnk, ii); + mi = i; + } + else { + int l = ii; + int h = link[ii].prev; + if(h - i < i - l) { + while(i < h) { + h = link[h].prev; + } + LinkBefore(i, lnk, link[h].next); + } + else { + l = link[l].next; + while(i > l && l != ii) { + l = link[l].next; + } + LinkBefore(i, lnk, l); + } + } + } + hash[i] = _hash & ~UNSIGNED_HIBIT; +} + +void HashBase::Shrink() { + hash.Shrink(); + if((int)HashBound(hash.GetCount()) < mcount) { + ClearIndex(); + DoIndex(); + } + else + link.Shrink(); +} + +void HashBase::Reserve(int n) +{ + hash.Reserve(n); + link.Reserve(n); + if((int)HashBound(n) > mcount) + Reindex(n); +} + +void HashBase::Remove(int i) +{ + hash.Remove(i); + ClearIndex(); + Reindex(); +} + +void HashBase::Remove(int i, int count) +{ + hash.Remove(i, count); + ClearIndex(); + Reindex(); +} + +void HashBase::Remove(const int *sorted_list, int count) +{ + hash.Remove(sorted_list, count); + ClearIndex(); + Reindex(); +} + +void HashBase::Insert(int i, unsigned _hash) { + hash.Insert(i, _hash & ~UNSIGNED_HIBIT); + ClearIndex(); + Reindex(); +} + +#ifdef UPP +void HashBase::Serialize(Stream& s) { + int version = 0; + s / version; + if(s.IsLoading()) + ClearIndex(); + hash.Serialize(s); + Reindex(); +} +#endif + +void HashBase::Swap(HashBase& b) { + UPP::Swap(hash, b.hash); + UPP::Swap(link, b.link); + UPP::Swap(map, b.map); + UPP::Swap(mcount, b.mcount); + UPP::Swap(unlinked, b.unlinked); +} + + +#ifdef CPU_X86 + +unsigned memhash(const void *ptr, size_t count) +{ + unsigned hash = 1234567890U; + + const unsigned *ds = (unsigned *)ptr; + const unsigned *de = ds + (count >> 2); + while(ds < de) + hash = ((hash << 5) - hash) ^ *ds++; + + const byte *s = (byte *)ds; + const byte *e = s + (count & 3); + while(s < e) + hash = ((hash << 5) - hash) ^ *s++; + + return hash; +} + +#else + +unsigned memhash(const void *ptr, size_t count) +{ + unsigned hash = 1234567890U; + + const byte *s = (byte *)ptr; + const byte *e = s + count; + while(s < e) + hash = ((hash << 5) - hash) ^ *s++; + + return hash; +} + +#endif + +unsigned GetHashValue0(const double& d) +{ + return memhash(&d, sizeof(double)); +} + +void Bits::Clear() +{ + if(bp && alloc >= 0) + delete[] bp; + alloc = 0; + bp = NULL; +} + +void Bits::Set(int i, bool b) +{ + ASSERT(i >= 0 && alloc >= 0); + int q = i >> 5; + if(q >= alloc) { + int nalloc = 2 * q + 1; + dword *nbp = new dword[nalloc]; + if(bp) { + Copy(nbp, bp, bp + alloc); + delete[] bp; + } + Fill(nbp + alloc, nbp + nalloc, (dword)0); + bp = nbp; + alloc = nalloc; + } + i &= 31; + ASSERT(q < alloc); + bp[q] = (bp[q] & ~(1 << i)) | (b << i); +} + +void Bits::Set(int i, bool b, int count) +{ //! Optimize !!! + while(count--) + Set(i++, b); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/HeapImp.h b/uppdev/CoreTopics/HeapImp.h new file mode 100644 index 000000000..53c954ca5 --- /dev/null +++ b/uppdev/CoreTopics/HeapImp.h @@ -0,0 +1,164 @@ +void *SysAllocRaw(size_t size); +void SysFreeRaw(void *ptr, size_t size); + +void *AllocRaw4KB(); +void *AllocRaw64KB(); +void *LAlloc(size_t& size); +void LFree(void *ptr); + +struct Heap { + enum { CACHE = 16 }; + + static int Ksz(int k) { + return k < 14 ? (k + 1) << 4 : k == 17 ? 576 : k == 16 ? 448 : k == 15 ? 368 : 288; + } + + struct FreeLink { + FreeLink *next; + }; + + struct Page { + byte klass; + byte active; + Heap *heap; + FreeLink *freelist; + Page *next; + Page *prev; + + void LinkSelf() { Dbl_Self(this); } + void Unlink() { Dbl_Unlink(this); } + void Link(Page *lnk) { Dbl_LinkAfter(this, lnk); } + + void Format(int k); + + byte *Begin() { return (byte *)this + sizeof(Page); } + byte *End() { return (byte *)this + 4096; } + int Count() { return (int)(uintptr_t)(End() - Begin()) / Ksz(klass); } + }; + + struct Header; + + struct DLink { + DLink *next; + DLink *prev; + + void LinkSelf() { Dbl_Self(this); } + void Unlink() { Dbl_Unlink(this); } + void Link(DLink *lnk) { Dbl_LinkAfter(this, lnk); } + + Header *GetHeader() { return (Header *)this - 1; } + }; + + struct Header { + byte free; + byte filler1, filler2, filler3; + word size; + word prev; + Heap *heap; + #ifdef CPU_32 + dword filler4; + #endif + + DLink *GetBlock() { return (DLink *)(this + 1); } + Header *Next() { return (Header *)((byte *)this + size) + 1; } + Header *Prev() { return (Header *)((byte *)this - prev) - 1; } + }; + + struct BigHdr : DLink { + size_t size; + }; + + enum { + NKLASS = 18, + LBINS = 113, + LARGEHDRSZ = 24, + MAXBLOCK = 65536 - 2 * sizeof(Header) - LARGEHDRSZ, + BIGHDRSZ = 56, + }; + static StaticMutex mutex; + + Page work[NKLASS][1]; + Page full[NKLASS][1]; + Page *empty[NKLASS]; + FreeLink *cache[NKLASS]; + int cachen[NKLASS]; + + bool initialized; + + static word BinSz[LBINS]; + static byte SzBin[MAXBLOCK / 8 + 1]; + static byte BlBin[MAXBLOCK / 8 + 1]; + + DLink large[1]; + int lcount; + DLink freebin[LBINS][1]; + static DLink lempty[1]; + + FreeLink *remote_free; + + static DLink big[1]; + static Heap aux; + +#ifdef HEAPDBG + static void DbgFreeFill(void *ptr, size_t size); + static void DbgFreeCheck(void *ptr, size_t size); + static void DbgFreeFillK(void *ptr, int k); + static void *DbgFreeCheckK(void *p, int k); +#else + static void DbgFreeFill(void *ptr, size_t size) {} + static void DbgFreeCheck(void *ptr, size_t size) {} + static void DbgFreeFillK(void *ptr, int k) {} + static void *DbgFreeCheckK(void *p, int k) { return p; } +#endif + +#ifdef flagHEAPSTAT + static void Stat(size_t sz); +#else + static void Stat(size_t sz) {} +#endif + + void FreeRemoteRaw(); + void FreeRemote(); + + void Init(); + + static int CheckPageFree(FreeLink *l, int k); + void Check(); + static void Assert(bool b); + static void DblCheck(Page *p); + static void AssertLeaks(bool b); + + Page *WorkPage(int k); + void *AllocK(int k); + void FreeK(void *ptr, Page *page, int k); + void *Allok(int k); + void Freek(void *ptr, int k); + void FreeDirect(void *ptr); + void MoveLarge(Heap *dest, DLink *l); + void MoveToEmpty(DLink *l, Header *bh); + + static void GlobalLInit(); + static int SizeToBin(int n) { return SzBin[(n - 1) >> 3]; } + + void LinkFree(DLink *b, int size); + DLink *AddChunk(); + void *DivideBlock(DLink *b, int size, int ii); + void *TryLAlloc(int ii, size_t size); + void *LAlloc(size_t& size); + void LFree(void *ptr); + void Make(MemoryProfile& f); + + void RemoteFree(void *ptr); + void Shutdown(); + static void AuxFinalCheck(); + + void *Alloc(size_t sz); + void *AllocSz(size_t& sz); + void Free(void *ptr); + void *Alloc32(); + void Free32(void *ptr); + void *Alloc48(); + void Free48(void *ptr); +}; + +extern thread__ Heap heap; diff --git a/uppdev/CoreTopics/Index.h b/uppdev/CoreTopics/Index.h new file mode 100644 index 000000000..addc8bd47 --- /dev/null +++ b/uppdev/CoreTopics/Index.h @@ -0,0 +1,240 @@ +#define FOLDHASH + +enum { UNSIGNED_HIBIT = 0x80000000 }; + +class HashBase : Moveable { + struct Link : Moveable { + int next; + int prev; + }; + Vector hash; + Vector link; + int *map; + int mcount; + int unlinked; + + void LinkBefore(int i, Link& l, int bi); + void LinkTo(int i, Link& l, int& m); + void Unlink(int i, Link& l, int& mi); + void Unlink(int i, Link& l); + int& Maph(unsigned _hash) const; + int& Mapi(int i) const; + void FinishIndex(); + void DoIndex(); + void Free(); + +public: + void ClearIndex(); + void Reindex(int n); + void Reindex(); + + void Add(unsigned hash); + void Set(int i, unsigned hash); + void SetUn(int i, unsigned hash); + unsigned operator [] (int i) const { return hash[i]; } + int Find(unsigned hash) const; + int FindNext(int i) const; + int FindLast(unsigned hash) const; + int FindPrev(int i) const; + int Put(unsigned hash); + + bool IsUnlinked(int i) const { return hash[i] & UNSIGNED_HIBIT; } + void Unlink(int i); + Vector GetUnlinked() const; + + void Remove(int i); + void Remove(int i, int count); + void Remove(const int *sorted_list, int count); + void Insert(int i, unsigned hash); + + int GetCount() const { return hash.GetCount(); } + void Trim(int count); + void Drop(int n); + void Clear() { hash.Clear(); ClearIndex(); } + + void Reserve(int n); + void Shrink(); + +#ifdef UPP + void Serialize(Stream& s); +#endif + + HashBase(); + ~HashBase(); + + HashBase(pick_ HashBase& b); + void operator=(pick_ HashBase& b); + HashBase(const HashBase& b, int); + void operator<<=(const HashBase& b); + + bool IsPicked() const { return hash.IsPicked(); } + + const unsigned *Begin() const { return hash.Begin(); } + const unsigned *End() const { return hash.End(); } + + void Swap(HashBase& b); +}; + +template +struct StdHash { + unsigned operator()(const T& x) const { return GetHashValue(x); } +}; + +struct PtrHash { + unsigned operator()(const void *x) const { return GetHashValue((unsigned)(uintptr_t)x); } +}; + +template +class AIndex { +protected: + V key; + HashBase hash; + + int Find0(const T& x, int i) const { + while(i >= 0 && !(x == key[i])) i = hash.FindNext(i); + return i; + } + int FindB(const T& x, int i) const { + while(i >= 0 && !(x == key[i])) i = hash.FindPrev(i); + return i; + } + void Hash(); + +public: + HashFn hashfn; + + void Add(const T& x, unsigned _hash); + void Add(const T& x); + int FindAdd(const T& key, unsigned _hash); + int FindAdd(const T& key); + AIndex& operator<<(const T& x) { Add(x); return *this; } + + int Put(const T& x, unsigned _hash); + int Put(const T& x); + int FindPut(const T& key, unsigned _hash); + int FindPut(const T& key); + + int Find(const T& x, unsigned _hash) const; + int Find(const T& x) const; + int FindNext(int i) const; + int FindLast(const T& x, unsigned _hash) const; + int FindLast(const T& x) const; + int FindPrev(int i) const; + + void Set(int i, const T& x, unsigned _hash); + void Set(int i, const T& x); + + const T& operator[](int i) const { return key[i]; } + int GetCount() const { return key.GetCount(); } + bool IsEmpty() const { return key.IsEmpty(); } + + void Clear() { hash.Clear(); key.Clear(); } + + void ClearIndex() { hash.ClearIndex(); } + void Reindex(int n) { hash.Reindex(n); } + void Reindex() { hash.Reindex(); } + + void Unlink(int i) { hash.Unlink(i); } + int UnlinkKey(const T& k, unsigned h); + int UnlinkKey(const T& k); + bool IsUnlinked(int i) const { return hash.IsUnlinked(i); } + Vector GetUnlinked() const { return hash.GetUnlinked(); } + void Sweep(); + + void Insert(int i, const T& k, unsigned h); + void Insert(int i, const T& k); + void Remove(int i); + void Remove(int i, int count); + void Remove(const int *sorted_list, int count); + void Remove(const Vector& sorted_list); + int RemoveKey(const T& k, unsigned h); + int RemoveKey(const T& k); + + void Trim(int n) { key.SetCount(n); hash.Trim(n); } + void Drop(int n = 1) { key.Drop(n); hash.Drop(n); } + const T& Top() const { return key.Top(); } + + void Reserve(int n) { key.Reserve(n); hash.Reserve(n); } + void Shrink() { key.Shrink(); hash.Shrink(); } + int GetAlloc() const { return key.GetAlloc(); } + +#ifdef UPP + void Serialize(Stream& s); +#endif + + V PickKeys() pick_ { return key; } + const V& GetKeys() const { return key; } + +// Pick assignment & copy. Picked source can only Clear(), ~AIndex(), operator=, operator<<= + + AIndex& operator=(pick_ V& s); + AIndex& operator<<=(const V& s); + +// Standard container interface + typedef T ValueType; + typedef typename V::ConstIterator ConstIterator; + ConstIterator Begin() const { return key.Begin(); } + ConstIterator End() const { return key.End(); } + ConstIterator GetIter(int pos) const { return key.GetIter(pos); } + + void Swap(AIndex& b) { UPP::Swap(hash, b.hash); + UPP::Swap(key, b.key); } +// Optimalizations + friend int GetCount(const AIndex& v) { return v.GetCount(); } + +protected: + AIndex(pick_ V& s); + AIndex(const V& s, int); + AIndex() {} + AIndex(const AIndex& s, int); +}; + +template > +class Index : MoveableAndDeepCopyOption< Index >, + public AIndex, HashFn> { + typedef AIndex< T, Vector, HashFn > B; +public: + T Pop() { T x = B::Top(); B::Drop(); return x; } + + Index() {} + Index(pick_ Index& s) : B(s) {} + Index(const Index& s, int) : B(s, 1) {} + Index(pick_ Vector& s) : B(s) {} + Index(const Vector& s, int) : B(s, 1) {} + + Index& operator=(pick_ Vector& x) { B::operator=(x); return *this; } + + friend void Swap(Index& a, Index& b) { a.B::Swap(b); } + + typedef typename B::ConstIterator ConstIterator; // GCC bug (?) + STL_INDEX_COMPATIBILITY(Index) +}; + +template > +class ArrayIndex : MoveableAndDeepCopyOption< ArrayIndex >, + public AIndex, HashFn> { + typedef AIndex< T, Array, HashFn > B; +public: + void Add(const T& x, unsigned _hash) { B::Add(x, _hash); } + void Add(const T& x) { B::Add(x); } + void Set(int i, const T& x, unsigned _hash) { B::Set(i, x, _hash); } + void Set(int i, const T& x) { B::Set(i, x); } + + void Add(T *newt, unsigned _hash); + void Add(T *newt); + void Set(int i, T *newt, unsigned _hash); + void Set(int i, T *newt); + + ArrayIndex() {} + ArrayIndex(pick_ ArrayIndex& s) : B(s) {} + ArrayIndex(const ArrayIndex& s, int) : B(s, 1) {} + ArrayIndex(pick_ Array& s) : B(s) {} + ArrayIndex(const Array& s, int) : B(s, 1) {} + + ArrayIndex& operator=(pick_ Array& x) { B::operator=(x); return *this; } + + friend void Swap(ArrayIndex& a, ArrayIndex& b) { a.B::Swap(b); } + + typedef typename B::ConstIterator ConstIterator; // GCC bug (?) + STL_INDEX_COMPATIBILITY(ArrayIndex) +}; diff --git a/uppdev/CoreTopics/Index.hpp b/uppdev/CoreTopics/Index.hpp new file mode 100644 index 000000000..51b652d4b --- /dev/null +++ b/uppdev/CoreTopics/Index.hpp @@ -0,0 +1,539 @@ +inline void HashBase::LinkTo(int i, Link& l, int& m) +{ + if(m >= 0) { + Link& bl = link[m]; + l.next = m; + l.prev = bl.prev; + bl.prev = i; + link[l.prev].next = i; + } + else + m = l.prev = l.next = i; +} + +inline void HashBase::Unlink(int i, Link& l, int& m) +{ + if(i == m) { + if(l.next == i) { + m = -1; + return; + } + m = l.next; + } + link[l.next].prev = l.prev; + link[l.prev].next = l.next; +} + +inline void HashBase::Unlink(int i, Link& l) +{ + Unlink(i, l, hash[i] & UNSIGNED_HIBIT ? unlinked : Mapi(i)); +} + +inline int& HashBase::Mapi(int i) const +{ + return Maph(hash[i]); +} + +inline int& HashBase::Maph(unsigned _hash) const +{ + unsigned h = _hash & ~UNSIGNED_HIBIT; +#ifdef FOLDHASH + return map[(mcount - 1) & (((h >> 23) - (h >> 15) - (h >> 7) - h))]; +#else + return map[h % mcount]; +#endif +} + +inline void HashBase::DoIndex() +{ + if(hash.GetCount() < mcount) + FinishIndex(); + else + Reindex(); +} + +inline int HashBase::Find(unsigned _hash) const +{ + if(hash.GetCount() == 0) return -1; + return Maph(_hash); +} + +inline int HashBase::FindNext(int i) const +{ + int q = link[i].next; + return q == Mapi(i) ? -1 : q; +} + +inline int HashBase::FindLast(unsigned _hash) const +{ + if(hash.GetCount() == 0) return - 1; + int i = Find(_hash & ~UNSIGNED_HIBIT); + return i >= 0 ? link[i].prev : -1; +} + +inline int HashBase::FindPrev(int i) const +{ + int q = link[i].prev; + return q == link[Mapi(i)].prev ? -1 : q; +} + +inline void HashBase::Unlink(int i) +{ + ASSERT(!IsUnlinked(i)); + hash[i] |= UNSIGNED_HIBIT; + if(i < link.GetCount()) { + Link& lnk = link[i]; + Unlink(i, lnk, Mapi(i)); + LinkTo(i, lnk, unlinked); + } +} + +template +AIndex::AIndex(const AIndex& s, int) +: key(s.key, 0), + hash(s.hash, 0) {} + +template +void AIndex::Hash() { + for(int i = 0; i < key.GetCount(); i++) + hash.Add(hashfn(key[i])); +} + +template +AIndex& AIndex::operator=(pick_ V& s) { + key = s; + hash.Clear(); + Hash(); + return *this; +} + +template +AIndex& AIndex::operator<<=(const V& s) { + key <<= s; + hash.Clear(); + Hash(); + return *this; +} + +template +AIndex::AIndex(pick_ V& s) : key(s) { + Hash(); +} + +template +AIndex::AIndex(const V& s, int) : key(s, 1) { + Hash(); +} + +template +void AIndex::Add(const T& x, unsigned _hash) { + key.Add(x); + hash.Add(_hash); +} + +template +void AIndex::Add(const T& x) { + Add(x, hashfn(x)); +} + +template +int AIndex::FindAdd(const T& _key, unsigned _hash) { + int i = Find(_key, _hash); + if(i >= 0) return i; + i = key.GetCount(); + Add(_key, _hash); + return i; +} + +template +int AIndex::Put(const T& x, unsigned _hash) +{ + int q = hash.Put(_hash); + if(q < 0) { + q = key.GetCount(); + Add(x, _hash); + } + else + key[q] = x; + return q; +} + +template +int AIndex::Put(const T& x) +{ + return Put(x, hashfn(x)); +} + +template +int AIndex::FindPut(const T& _key, unsigned _hash) +{ + int i = Find(_key, _hash); + if(i >= 0) return i; + return Put(_key, _hash); +} + +template +int AIndex::FindPut(const T& key) +{ + return FindPut(key, hashfn(key)); +} + +template +inline int AIndex::Find(const T& x, unsigned _hash) const { + return Find0(x, hash.Find(_hash)); +} + +template +int AIndex::Find(const T& x) const { + return Find(x, hashfn(x)); +} + +template +int AIndex::FindNext(int i) const { + return Find0(key[i], hash.FindNext(i)); +} + +template +inline int AIndex::FindLast(const T& x, unsigned _hash) const { + return FindB(x, hash.FindLast(_hash)); +} + +template +int AIndex::FindLast(const T& x) const { + return FindLast(x, hashfn(x)); +} + +template +int AIndex::FindPrev(int i) const { + return FindB(key[i], hash.FindPrev(i)); +} + +template +int AIndex::FindAdd(const T& key) { + return FindAdd(key, hashfn(key)); +} + +template +void AIndex::Set(int i, const T& x, unsigned _hash) { + key[i] = x; + hash.Set(i, _hash); +} + +template +void AIndex::Set(int i, const T& x) { + Set(i, x, hashfn(x)); +} + +#ifdef UPP +template +void AIndex::Serialize(Stream& s) { + if(s.IsLoading()) ClearIndex(); + key.Serialize(s); + hash.Serialize(s); +} +#endif + +template +int AIndex::UnlinkKey(const T& k, unsigned h) +{ + int n = 0; + int q = hash.Find(h); + while(q >= 0) { + int w = q; + q = hash.FindNext(q); + if(k == key[w]) { + hash.Unlink(w); + n++; + } + } + return n; +} + +template +int AIndex::UnlinkKey(const T& k) +{ + return UnlinkKey(k, hashfn(k)); +} + +template +void AIndex::Sweep() +{ + Vector b = hash.GetUnlinked(); + Sort(b); + Remove(b); +} + +template +void AIndex::Insert(int i, const T& k, unsigned h) { + key.Insert(i, k); + hash.Insert(i, h); +} + +template +void AIndex::Insert(int i, const T& k) { + key.Insert(i, k); + hash.Insert(i, hashfn(k)); +} + +template +void AIndex::Remove(int i) +{ + key.Remove(i); + hash.Remove(i); +} + +template +void AIndex::Remove(int i, int count) +{ + key.Remove(i, count); + hash.Remove(i, count); +} + +template +void AIndex::Remove(const int *sorted_list, int count) +{ + key.Remove(sorted_list, count); + hash.Remove(sorted_list, count); +} + +template +void AIndex::Remove(const Vector& sl) +{ + Remove(sl, sl.GetCount()); +} + +template +int AIndex::RemoveKey(const T& k, unsigned h) +{ + Vector rk; + int q = Find(k, h); + while(q >= 0) { + rk.Add(q); + q = FindNext(q); + } + Remove(rk); + return rk.GetCount(); +} + +template +int AIndex::RemoveKey(const T& k) +{ + return RemoveKey(k, hashfn(k)); +} + +// ------------------ + +template +void ArrayIndex::Add(T *newt, unsigned _hash) { + B::key.Add(newt); + B::hash.Add(_hash); +} + +template +void ArrayIndex::Add(T *newt) { + Add(newt, B::hashfn(*newt)); +} + +template +void ArrayIndex::Set(int i, T *newt, unsigned _hash) { + B::key.Set(i, newt); + B::hash.Set(i, _hash); +} + +template +void ArrayIndex::Set(int i, T *newt) { + Set(i, newt, B::hashfn(*newt)); +} + +// -------------------- + +template +int AMap::FindAdd(const K& k) { + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = GetCount(); + key.Add(k, hash); + value.Add(); + } + return i; +} + +template +int AMap::FindAdd(const K& k, const T& x) { + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = GetCount(); + key.Add(k, hash); + value.Add(x); + } + return i; +} + +template +int AMap::FindAddPick(const K& k, pick_ T& x) { + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = GetCount(); + key.Add(k, hash); + value.Add(x); + } + return i; +} + +template +int AMap::Put(const K& k, const T& x) +{ + int i = key.Put(k); + if(i < value.GetCount()) + value[i] = x; + else { + ASSERT(i == value.GetCount()); + value.Add(x); + } + return i; +} + +template +int AMap::PutPick(const K& k, pick_ T& x) +{ + int i = key.Put(k); + if(i < value.GetCount()) + value[i] = x; + else { + ASSERT(i == value.GetCount()); + value.AddPick(x); + } + return i; +} + +template +T& AMap::Put(const K& k) +{ + int i = key.Put(k); + if(i < value.GetCount()) + return value[i]; + else { + ASSERT(i == value.GetCount()); + return value.Add(); + } +} + +template +int AMap::FindPut(const K& k) +{ + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = key.Put(k, hash); + value.At(i); + } + return i; +} + +template +int AMap::FindPut(const K& k, const T& init) +{ + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = key.Put(k, hash); + if(i >= value.GetCount()) { + ASSERT(i == value.GetCount()); + i = value.GetCount(); + value.Add(init); + } + else + value[i] = init; + } + return i; +} + +template +int AMap::FindPutPick(const K& k, pick_ T& init) +{ + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i < 0) { + i = key.Put(k, hash); + value.At(i) = init; + } + return i; +} + +template +T& AMap::GetAdd(const K& k) { + unsigned hash = key.hashfn(k); + int i = key.Find(k, hash); + if(i >= 0) + return value[i]; + key.Add(k, hash); + return value.Add(); +} + +template +T& AMap::GetAdd(const K& k, const T& x) { + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i >= 0) return value[i]; + key.Add(k, hash); + value.Add(x); + return value.Top(); +} + +template +T& AMap::GetAddPick(const K& k, pick_ T& x) { + unsigned hash = key.hashfn(k); + int i = Find(k, hash); + if(i >= 0) return value[i]; + key.Add(k, hash); + value.AddPick(x); + return value.Top(); +} + +template +T& AMap::GetPut(const K& k) { + return value[FindAdd(k)]; +} + +template +T& AMap::GetPut(const K& k, const T& x) { + return value[FindAdd(k, x)]; +} + +template +T& AMap::GetPutPick(const K& k, pick_ T& x) { + return value[FindAddPick(k, x)]; +} + +#ifdef UPP +template +void AMap::Serialize(Stream& s) { + int version = 0; + s / version % key % value; +} +#endif + +template +int AMap::RemoveKey(const K& k) +{ + Vector rk; + int q = Find(k); + while(q >= 0) { + rk.Add(q); + q = FindNext(q); + } + Remove(rk); + return rk.GetCount(); +} + +template +void AMap::Sweep() +{ + Vector b = key.GetUnlinked(); + Sort(b); + key.Remove(b); + value.Remove(b); +} diff --git a/uppdev/CoreTopics/Kernel32W.dli b/uppdev/CoreTopics/Kernel32W.dli new file mode 100644 index 000000000..47f57211f --- /dev/null +++ b/uppdev/CoreTopics/Kernel32W.dli @@ -0,0 +1,16 @@ +FN_C(UINT, WINAPI, GetSystemDirectoryW, (LPWSTR lpBuffer, UINT uSize)) +FN_C(DWORD, WINAPI, GetTempPathW, (DWORD nBufferLength, LPWSTR lpBuffer)) +FN_C(UINT , WINAPI, GetWindowsDirectoryW, (LPWSTR lpBuffer, UINT uSize)) +FN_C(DWORD , WINAPI, GetModuleFileNameW, (HMODULE hModule, LPWSTR lpFilename, DWORD nSize)) +FN_C(int , WINAPI, GetLocaleInfoW, (LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData)) +FN_C(DWORD , WINAPI, GetCurrentDirectoryW, (DWORD nBufferLength, LPWSTR lpBuffer)) +FN_C(DWORD , WINAPI, GetFullPathNameW, (LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart)) +FN_C(HANDLE , WINAPI, FindFirstFileW, (LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)) +FN_C(BOOL, WINAPI, FindNextFileW, (HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)) +FN_C(BOOL , WINAPI, GetVolumeInformationA, (LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize)) +FN_C(HANDLE , WINAPI, CreateFileW, (LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)) +FN_C(BOOL , WINAPI, CopyFileW, (LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)) +FN_C(BOOL , WINAPI, MoveFileW, (LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)) +FN_C(BOOL , WINAPI, DeleteFileW, (LPCWSTR lpFileName)) +FN_C(BOOL , WINAPI, RemoveDirectoryW, (LPCWSTR lpPathName)) +FN_C(BOOL , WINAPI, CreateDirectoryW, (LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)) diff --git a/uppdev/CoreTopics/Lang.cpp b/uppdev/CoreTopics/Lang.cpp new file mode 100644 index 000000000..739013b29 --- /dev/null +++ b/uppdev/CoreTopics/Lang.cpp @@ -0,0 +1,1098 @@ +#include "Core.h" + +#ifdef PLATFORM_WIN32 +#include +#include +#endif +#ifdef PLATFORM_POSIX +#include +#include +#endif + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +String LNGAsText(int d) +{ + String result; + int c = (d >> 15) & 31; + if(c) { + result.Cat(c + 'A' - 1); + c = (d >> 10) & 31; + if(c) { + result.Cat(c + 'A' - 1); + c = (d >> 5) & 31; + if(c) { + result.Cat('-'); + result.Cat(c + 'A' - 1); + c = d & 31; + if(c) result.Cat(c + 'A' - 1); + } + } + } + c = (d >> 20) & 255; + if(c) + result << ' ' << CharsetName(c); + return result; +} + +byte GetLNGCharset(int d) +{ + byte cs = byte(d >> 20); + return cs ? cs : CHARSET_UTF8; +} + +int SetLNGCharset(int lng, byte chrset) +{ + return (lng & ~(0xffffffff << 20)) | (chrset << 20); +} + +int LNGFromText(const char *s) +{ + int l = 0; + if(IsAlpha(*s)) { + l = (ToUpper(*s++) - 'A' + 1) << 15; + if(IsAlpha(*s)) { + l |= (ToUpper(*s++) - 'A' + 1) << 10; + if(*s && !IsAlpha(*s)) + s++; + if(IsAlpha(*s)) { + l |= (ToUpper(*s++) - 'A' + 1) << 5; + if(IsAlpha(*s)) { + l |= (ToUpper(*s++) - 'A' + 1); + while(*s && *s != ' ') + s++; + if(*s == ' ') { + s++; + int cs = CharsetByName(s); + if(cs > 0) + l |= (cs << 20); + else + return 0; + } + return l; + } + } + } + } + return 0; +} + +#ifdef PLATFORM_WIN32 + +String GetUserLocale(dword type) +{ +#ifdef PLATFORM_WINCE + wchar h[256]; + int n = ::GetLocaleInfo(GetUserDefaultLCID(), type, h, 256); + return n ? WString(h, n - 1).ToString() : String(); +#else + char h[256]; + int n =:: GetLocaleInfo(GetUserDefaultLCID(), type, h, 256); + return n ? String(h, n - 1) : String(); +#endif +} + +int GetSystemLNG() +{ + static int lang; + ONCELOCK { + lang = LNGFromText(GetUserLocale(LOCALE_SISO639LANGNAME) + GetUserLocale(LOCALE_SISO3166CTRYNAME)); + if(!lang) + lang = LNG_ENGLISH; + int cs = atoi(GetUserLocale(LOCALE_IDEFAULTANSICODEPAGE)); + if(cs >= 1250 && cs <= 1258) + lang = SetLNGCharset(lang, CHARSET_WIN1250 + cs - 1250); + } + return lang; +} +#endif + +#ifdef PLATFORM_POSIX +int GetSystemLNG() { + static int lang; + ONCELOCK { + String s = Environment().Get("LANG", Null); + lang = LNGFromText(s); + if(!lang) + lang = LNG_ENGLISH; + const char *q = strchr(s, '.'); + if(q) + lang = SetLNGCharset(lang, CharsetByName(q + 1)); + }; + return lang; +}; + +#endif + +class LangConvertClass : public Convert { + virtual Value Format(const Value& q) const { + return LNGAsText((int)q); + } + + virtual Value Scan(const Value& text) const { + if(IsNull(text)) return 0; + int q = LNGFromText((String)text); + if(!q) return ErrorValue(t_("Invalid language specification.")); + return (int) q; + } + + virtual int Filter(int chr) const { + return chr == ' ' || chr == '-' || IsDigit(chr) ? chr : IsAlpha(chr) ? ToUpper(chr) : 0; + } +}; + +Convert& LNGConvert() +{ + return Single(); +} + +static int sCurrentLanguage = -1; + +int GetCurrentLanguage() { + return sCurrentLanguage; +} + +#ifdef PLATFORM_WIN32 + +typedef VectorMap LCIDMap; +GLOBAL_VAR(LCIDMap, GetLCIDMap) + +#ifdef PLATFORM_WINCE //TODO? +String GetLocaleInfoA(LCID lcid, LCTYPE lctype) +{ + wchar cbuf[1000]; + ::GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharset(cbuf); +} +#else +String GetLocaleInfoA(LCID lcid, LCTYPE lctype) +{ + if(IsWinNT()) { + wchar cbuf[1000]; + UnicodeWin32().GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharsetW(cbuf); + } + else { + char cbuf[1000]; + ::GetLocaleInfoA(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharset(cbuf); + } +} +#endif + +WString GetLocaleInfoW(LCID lcid, LCTYPE lctype) +{ + union { + wchar wbuf[1000]; + char abuf[1000]; + }; + Zero(wbuf); + if(::GetLocaleInfoW(lcid, lctype, (WCHAR *)wbuf, __countof(wbuf))) + return wbuf; +#ifdef PLATFORM_WINCE + return Null; +#else + ::GetLocaleInfoA(lcid, lctype, abuf, __countof(abuf)); + return ToUnicode(abuf, CHARSET_DEFAULT); +#endif +} + +#ifdef PLATFORM_WINCE +static BOOL CALLBACK sEnumLocale(wchar *locale_string) +#else +static BOOL CALLBACK sEnumLocale(char *locale_string) +#endif +{ + LLOG(locale_string); + LCID lcid = stou(locale_string, NULL, 16); +#ifdef PLATFORM_WINCE + wchar buffer[10]; +#else + char buffer[10]; +#endif + ::GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, buffer, 10); + int language = (ToUpper(buffer[0]) << 24) + (ToUpper(buffer[1]) << 16); + ::GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, buffer, 10); + language += (ToUpper(buffer[0]) << 8) + (ToUpper(buffer[1]) << 0); + LLOG(FormatIntHex(language, 8) << ", " << LNGAsText(language) << "->" << FormatIntHex(lcid, 8)); + GetLCIDMap().GetAdd(language, lcid); + return TRUE; +} + +LCID GetLanguageLCID(int language) +{ + if(language == 0) + return 0x400; + ONCELOCK { + EnumSystemLocales(&sEnumLocale, LCID_SUPPORTED); + } + return GetLCIDMap().Get(language, MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT)); +} +#endif + +void SetLanguage(int lang) { + if(lang != LNG_CURRENT) { + sCurrentLanguage = lang; + SetDefaultCharset(GetLNGCharset(lang)); + } + SetCurrentLanguage(lang); +} + +const int *GetAllLanguages() { + static int all_langs[] = { + LNG_('E', 'N', 'U', 'S'), + LNG_('E', 'N', 'G', 'B'), + LNG_('E', 'N', 'A', 'U'), + LNG_('E', 'N', 'C', 'A'), + LNG_('E', 'N', 'N', 'Z'), + LNG_('E', 'N', 'I', 'E'), + LNG_('E', 'N', 'Z', 'A'), + LNG_('E', 'N', 'J', 'M'), + LNG_('E', 'N', 'C', 'B'), + LNG_('E', 'N', 'B', 'Z'), + LNG_('E', 'N', 'T', 'T'), + LNG_('B', 'G', 'B', 'G'), + LNG_('C', 'S', 'C', 'Z'), + LNG_('D', 'A', 'D', 'K'), + LNG_('D', 'E', 'D', 'E'), + LNG_('D', 'E', 'C', 'H'), + LNG_('D', 'E', 'A', 'T'), + LNG_('D', 'E', 'L', 'U'), + LNG_('D', 'E', 'L', 'I'), + LNG_('E', 'L', 'G', 'R'), + LNG_('E', 'S', 'E', 'S'), + LNG_('E', 'S', 'M', 'X'), + LNG_('E', 'S', 'E', 'S'), + LNG_('E', 'S', 'G', 'T'), + LNG_('E', 'S', 'C', 'R'), + LNG_('E', 'S', 'P', 'A'), + LNG_('E', 'S', 'D', 'O'), + LNG_('E', 'S', 'V', 'E'), + LNG_('E', 'S', 'C', 'O'), + LNG_('E', 'S', 'P', 'E'), + LNG_('E', 'S', 'A', 'R'), + LNG_('E', 'S', 'E', 'C'), + LNG_('E', 'S', 'C', 'L'), + LNG_('E', 'S', 'U', 'Y'), + LNG_('E', 'S', 'P', 'Y'), + LNG_('E', 'S', 'B', 'O'), + LNG_('E', 'S', 'S', 'V'), + LNG_('E', 'S', 'H', 'N'), + LNG_('E', 'S', 'N', 'I'), + LNG_('E', 'S', 'P', 'R'), + LNG_('F', 'I', 'F', 'I'), + LNG_('F', 'R', 'F', 'R'), + LNG_('F', 'R', 'B', 'E'), + LNG_('F', 'R', 'C', 'A'), + LNG_('F', 'R', 'C', 'H'), + LNG_('F', 'R', 'L', 'U'), + LNG_('H', 'U', 'H', 'U'), + LNG_('I', 'S', 'I', 'S'), + LNG_('I', 'T', 'I', 'T'), + LNG_('I', 'T', 'C', 'H'), + LNG_('N', 'L', 'N', 'L'), + LNG_('N', 'L', 'B', 'E'), + LNG_('N', 'O', 'N', 'O'), + LNG_('N', 'O', 'N', 'O'), + LNG_('P', 'L', 'P', 'L'), + LNG_('P', 'T', 'B', 'R'), + LNG_('P', 'T', 'P', 'T'), + LNG_('R', 'O', 'R', 'O'), + LNG_('R', 'U', 'R', 'U'), + LNG_('H', 'R', 'H', 'R'), + LNG_('S', 'R', 'S', 'P'), + LNG_('S', 'R', 'S', 'P'), + LNG_('S', 'K', 'S', 'K'), + LNG_('S', 'V', 'S', 'E'), + LNG_('S', 'V', 'F', 'I'), + LNG_('T', 'R', 'T', 'R'), + LNG_('S', 'L', 'S', 'I'), + LNG_('A', 'F', 'Z', 'A'), + LNG_('S', 'Q', 'A', 'L'), + LNG_('E', 'U', 'E', 'S'), + LNG_('B', 'E', 'B', 'Y'), + LNG_('C', 'A', 'E', 'S'), + LNG_('E', 'T', 'E', 'E'), + LNG_('F', 'O', 'F', 'O'), + LNG_('I', 'D', 'I', 'D'), + LNG_('L', 'V', 'L', 'V'), + LNG_('L', 'T', 'L', 'T'), + LNG_('U', 'K', 'U', 'A'), + LNG_('Z', 'H', 'C', 'N'), + LNG_('Z', 'H', 'T', 'W'), + LNG_('K', 'O', 'K', 'R'), + LNG_('J', 'A', 'J', 'P'), + 0 + }; + return all_langs; +} + +String GetLangName(int language) +{ + return GetLanguageInfo(language).english_name; +} + +/* + char buffer[200]; + if(language & 0x1000000) { + language &= 15; + static char *name[] = { + "ANSI", + "RUSSIAN", + "EASTEUROPE", + "GREEK", + "TURKISH", + "BALTIC", + "HEBREW", + "ARABIC" + }; + return String(name[language & 7]) + (language < 8 ? " I" : " II"); + } + return GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_SENGLANGUAGE, buffer, 200) + ? buffer : ""; +*/ + +String GetNativeLangName(int language) { + return GetLanguageInfo(language).native_name.ToString(); +/* + char buffer[200]; + return GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_SNATIVELANGNAME, buffer, 200) + ? buffer : ~GetLangName(language); +*/ +} + +byte GetLangCharset(int language) { + return GetLanguageInfo(language).charset; +/* + static struct { byte charset; dword codepage; } tab[] = { + { CHARSET_WIN1252, 1252 }, + { CHARSET_WIN1251, 1251 }, + { CHARSET_WIN1250, 1250 }, + { CHARSET_WIN1253, 1253 }, + { CHARSET_WIN1254, 1254 }, + { CHARSET_WIN1257, 1257 }, + { CHARSET_WIN1255, 1255 }, + { CHARSET_WIN1256, 1256 }, +// { SHIFTJIS_CHARSET, 932 }, +// { HANGEUL_CHARSET, 949 }, +// { GB2312_CHARSET, 936 }, +// { CHINESEBIG5_CHARSET, 950 }, + }; + if(language & 0x1000000) + return tab[language & 7].charset; + char buffer[20]; + GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, buffer, 20); + int codepage = atoi(buffer); + for(int i = 0; i < __countof(tab); i++) + if(tab[i].codepage == codepage) + return tab[i].charset; + return CHARSET_DEFAULT; +*/ +} +LanguageInfo::LanguageInfo(int lang_) +: language(lang_) +{ + charset = CHARSET_DEFAULT; + +#ifdef PLATFORM_WIN32 + LCID lcid = GetLanguageLCID(lang_); + english_name = GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE); + native_name = GetLocaleInfoW(lcid, LOCALE_SNATIVELANGNAME); + thousand_separator = GetLocaleInfoA(lcid, LOCALE_STHOUSAND); + decimal_point = GetLocaleInfoA(lcid, LOCALE_SDECIMAL); + static const LCTYPE months[] = + { + LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, + LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, + LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, + LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, + }; + static const LCTYPE smonths[] = + { + LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, + LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, + LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, + LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, + }; + ASSERT(__countof(months) == __countof(month_names)); + int i; + for(i = 0; i < __countof(months); i++) + { + month_names[i] = GetLocaleInfoW(lcid, months[i]); + short_month_names[i] = GetLocaleInfoW(lcid, smonths[i]); + } + static const LCTYPE days[] = + { + LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, + LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, + }; + static const LCTYPE sdays[] = + { + LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, + LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7, + }; + ASSERT(__countof(days) == __countof(day_names)); + for(i = 0; i < __countof(days); i++) + { + day_names[i] = GetLocaleInfoW(lcid, days[i]); + short_day_names[i] = GetLocaleInfoW(lcid, sdays[i]); + } + + static struct { byte charset; dword codepage; } tab[] = + { + { CHARSET_WIN1252, 1252 }, + { CHARSET_WIN1251, 1251 }, + { CHARSET_WIN1250, 1250 }, + { CHARSET_WIN1253, 1253 }, + { CHARSET_WIN1254, 1254 }, + { CHARSET_WIN1257, 1257 }, + { CHARSET_WIN1255, 1255 }, + { CHARSET_WIN1256, 1256 }, +// { SHIFTJIS_CHARSET, 932 }, +// { HANGEUL_CHARSET, 949 }, +// { GB2312_CHARSET, 936 }, +// { CHINESEBIG5_CHARSET, 950 }, + }; + int codepage = atoi(GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE)); + for(i = 0; i < __countof(tab); i++) + if(tab[i].codepage == codepage) + { + charset = tab[i].charset; + break; + } +#endif + +#ifdef PLATFORM_POSIX + String langtext = LNGAsText(language); + char ltext[6]; + ltext[0] = ToLower(langtext[0]); + ltext[1] = ToLower(langtext[1]); + ltext[2] = '_'; + ltext[3] = ToUpper(langtext[3]); + ltext[4] = ToUpper(langtext[4]); + ltext[5] = 0; + String oldloc = setlocale(LC_ALL, NULL); +// puts(String() << "setting locale " << ltext << ", old locale = " << oldloc); + if(setlocale(LC_ALL, ltext)) + { +// puts(String() << "set locale " << ltext << " succeeded"); + const struct lconv *lc = localeconv(); + decimal_point = lc->decimal_point; + thousand_separator = lc->thousands_sep; + //lc->grouping - controls thousands grouping + static const int months[] = + { + MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12, + }; + static const int smonths[] = + { + ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12, + }; + ASSERT(__countof(months) == __countof(month_names) && __countof(smonths) == __countof(month_names)); + int i; + for(i = 0; i < __countof(months); i++) + { + month_names[i] = nl_langinfo(months[i]); + short_month_names[i] = nl_langinfo(smonths[i]); + } + static const int days[] = + { // Linux locale starts with Sunday + DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1, + }; + static const int sdays[] = + { + ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABDAY_1, + }; + ASSERT(__countof(days) == __countof(day_names) && __countof(sdays) == __countof(day_names)); + for(i = 0; i < __countof(days); i++) + { + day_names[i] = nl_langinfo(days[i]); + short_day_names[i] = nl_langinfo(sdays[i]); + } + + setlocale(LC_ALL, oldloc); + } +#endif +} + +String LanguageInfo::ToString() const +{ + String out; + out << "LANGUAGE={" << LNGAsText(language) << "}\n" +#ifdef PLATFORM_WIN32 + << NFormat("LCID={%08x}\n", (int)GetLanguageLCID(language)) +#endif + << "ENGLISH_NAME={" << english_name << "}\n" + "NATIVE_NAME={" << FromUnicode(native_name) << "}\n" + "CHARSET={" << charset << "}\n" + "THOUSAND_SEPARATOR={" << thousand_separator << "}\n" + "DECIMAL_POINT={" << decimal_point << "}\n" + "MONTH_NAMES={\n"; + int i; + for(i = 0; i < __countof(month_names); i++) + out << " {" << FromUnicode(month_names[i]) << "} / {" << FromUnicode(short_month_names[i]) << "}\n"; + out << "}\n" + "DAY_NAMES={\n"; + for(i = 0; i < __countof(day_names); i++) + out << " {" << FromUnicode(day_names[i]) << "} / {" << FromUnicode(short_day_names[i]) << "}\n"; + out << "}\n"; + return out; +} + +static const char *NlsFindDigits(const char *src, String& dest) +{ + if(*src && !IsDigit(*src)) + { + const char *start = src; + while(*++src && !IsDigit(*src)) + ; + dest.Cat(start, (int)(src - start)); + } + return src; +} + +static const char *NlsCopyDigits(const char *src, String& dest, String thousands) +{ + if(IsDigit(*(src = NlsFindDigits(src, dest)))) + { + const char *p = src; + while(IsDigit(*++src)) + ; + int first = ((int)(src - p) + 2) % 3 + 1; + while(p < src) + { + dest.Cat(p, first); + if((p += first) < src) + { + dest.Cat(thousands); + first = 3; + } + } + } + return src; +} + +static String NlsFormatRaw(const char *n, String thousands, String decimals) +{ + if(*n == 0) + return Null; +// puts(String() << "NlsFormatRaw, n = <" << n << ">, thousands <" << thousands << ">, decimal <" << decimals << ">"); + String result; + n = NlsCopyDigits(n, result, thousands); + if(*n == (wchar)'.') + { // decimal separator + n++; + result.Cat(decimals); + const char *s = n; + while(IsDigit(*n)) + n++; + result.Cat(s, (int)(n - s)); + } + if(*(n = NlsCopyDigits(n, result, thousands))) + result.Cat(n); + return result; +} + +String LanguageInfo::FormatInt(int value) const +{ + if(IsNull(value)) + return Null; + String dest; + String is = UPP::FormatInt(value); + const char *p = NlsCopyDigits(is, dest, thousand_separator); + if(*p) + dest.Cat(p); + return dest; +} + +String LanguageInfo::FormatDouble(double value, int digits, int FD_flags, int fill_exp) const +{ + if(IsNull(value)) + return Null; +// puts(String() << "LanguageInfo(" << LNGAsText(language) << "): thousands <" << thousand_separator << ">, decimal <" << decimal_point << ">"); + return NlsFormatRaw(UPP::FormatDouble(value, digits, FD_flags, fill_exp), thousand_separator, decimal_point); +} + +String LanguageInfo::FormatDate(Date date) const +{ + return UPP::FormatDate(date, date_format, language); +} + +String LanguageInfo::FormatTime(Time time) const +{ + return UPP::FormatTime(time, time_format, language); +} + +/* +int LanguageInfo::ScanInt(const char *text, const char **endptr) const +{ + return ScanInt(text, endptr); //!! todo +} +*/ + +/* +double LanguageInfo::ScanDouble(const char *text, const char **endptr) const +{ + return ScanDouble(text, endptr); //!! todo +} +*/ + +/* +Date LanguageInfo::ScanDate(const char *text, const char **endptr, Date base_date) const +{ + return UPP::ScanDate(text, endptr, date_format, language, base_date); +} +*/ + +/* +Time LanguageInfo::ScanTime(const char *text, const char **endptr, Time base_time) const +{ + return UPP::ScanTime(text, endptr, time_format, language, base_time); +} +*/ + +WString LanguageInfo::GetIndexLetter(const wchar *text) const +{ + return IsLetter(*text) ? WString(text, 1) : WString(Null); +} + +static int LangCompareDigits(const wchar *&a, const wchar *&b, const wchar *e1, const wchar *e2) +{ + const wchar *p1 = a, *p2 = b; + while(p1 < e1 && *p1 == '0') + p1++; + while(p2 < e2 && *p2 == '0') + p2++; + const wchar *x1 = p1, *x2 = p2; + while(p1 < e1 && IsDigit(*p1)) + p1++; + while(p2 < e2 && IsDigit(*p2)) + p2++; + if(p1 - x1 != p2 - x2) + return cmp(p1 - x1, p2 - x2); + for(; x1 != p1; x1++, x2++) + if(*x1 != *x2) + return *x1 > *x2 ? 1 : -1; + a = p1; + b = p2; + return 0; +} + +int LanguageInfo::Compare(const wchar *a, const wchar *b, int a_length, int b_length) const +{ + ASSERT(language != LNG_CZECH); // use RegisterLanguageInfoCS to register true czech compare + + int little = 0, middle = 0; + const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; + + while(p1 < e1 && p2 < e2) + { + wchar c1 = *p1++; + wchar c2 = *p2++; + + int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); + int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); + if(level1 != level2) + return cmp(level1, level2); + if(level1 <= 1) + { + if(c1 != c2) + return cmp(c1, c2); + continue; + } + if(level1 == 2) + { // digits + const wchar *dp1 = --p1, *dp2 = --p2; + int res = LangCompareDigits(dp1, dp2, e1, e2); + if(res) + return res; + p1 = dp1; + p2 = dp2; + continue; + } + + int u1, u2, i1, i2; + + i1 = ToAscii(u1 = ToUpper(c1)); + i2 = ToAscii(u2 = ToUpper(c2)); + + if(i1 != i2) + return i1 >= i2 ? 1 : -1; + + if(u1 != u2) // different diacritics + if(middle == 0) + middle = u1 - u2; + + if(c1 != c2) // different case + { + if(little == 0) + little = (u1 != c1) - (u2 != c2); + } + } + little += 4 * middle; + if(little == 0) + little = a_length - b_length; + return sgn(little); +} + +/* +static bool ContainsAccents(const wchar *s) +{ + for(; *s; s++) + if(*s != ToAscii(*s)) + return true; + return false; +} +*/ + +class DefaultWildcardCompare : public LanguageInfo::WildcardCompare +{ +public: + DefaultWildcardCompare(const wchar *templ) + { + raw_templ = 0; +// cvt_ascii = true; + if(*templ == 0) + return; +// if((*templ == '.' && templ[1] != 0 && *++templ != '.') || ContainsAccents(templ)) +// cvt_ascii = true; + raw_templ = templ; +// if(cvt_ascii) +// cvt_templ = ToUpper(ToAscii(raw_templ)); +// else + cvt_templ = ToUpper(raw_templ); + } + + virtual bool Matches(const wchar *s) const + { + return !raw_templ || RawMatches(s, cvt_templ); + } + +private: + bool RawMatches(const wchar *s, const wchar *templ) const + { + for(;;) + switch(*templ++) + { + case 0: return true; + case '.': if(*templ == 0) return *s == 0; // force end of string + case '?': if(*s++ == 0) return false; break; + case '*': + do + if(RawMatches(s, templ)) + return true; + while(*s++); + return false; + case '\\': + if(*templ == 0 || *s++ != *templ++) + return false; + break; + + default: +// if(templ[-1] != ToUpper(cvt_ascii ? ToAscii(*s) : *s)) + if(templ[-1] != ToUpper(*s)) + return false; + s++; + break; + } + return true; + } + +private: + const wchar *raw_templ; +// bool cvt_ascii; + WString cvt_templ; +}; + +One LanguageInfo::GetWildcardCompare(const wchar *wildcard_text) const +{ + return new DefaultWildcardCompare(wildcard_text); +} + +typedef ArrayMap LanguageInfoMap; +GLOBAL_VAR(LanguageInfoMap, LanguageInfo::Map) +static StaticMutex sMapMutex; + +void LanguageInfo::Register(One info) +{ + INTERLOCKED_(sMapMutex) { + int lang = info->language; + int f = Map().Find(lang); + if(f >= 0) + Map().Set(f, -info); + else + Map().Add(lang, -info); + } +} + +class LanguageInfoCS : public LanguageInfo +{ +public: + LanguageInfoCS(); + + virtual WString GetIndexLetter(const wchar *text) const; + + virtual int Compare(const wchar *a, const wchar *b, int a_length, int b_length) const; + virtual One GetWildcardCompare(const wchar *wildcard_text) const; + +public: +}; + +LanguageInfoCS::LanguageInfoCS() +: LanguageInfo(LNG_CZECH) +{ + english_name = "Czech"; + native_name = ToUnicode("Èesky", CHARSET_WIN1250); // __FILE__CHARSET__ +// charset = CHARSET_WIN1250; +// thousand_separator = L" "; +// decimal_point = L","; +} + +WString LanguageInfoCS::GetIndexLetter(const wchar *s) const +{ + wchar temp[3]; + temp[0] = temp[1] = temp[2] = 0; + if(*s <= 2047 && IsLetter(*s)) // IsLetter + { + temp[0] = ToUpper(*s); + if(s[1] <= 2047 && IsLetter(s[1])) + temp[1] = ToLower(s[1]); + if(temp[0] != 'C' || temp[1] != 'h') + temp[1] = 0; + switch(ToUpper(ToAscii(*s))) + { + case 'A': case 'E': case 'I': case 'N': + case 'O': case 'T': case 'U': case 'Y': + temp[0] = ToAscii(temp[0]); + break; + } + } + return temp; +} + +int LanguageInfoCS::Compare(const wchar *a, const wchar *b, int a_length, int b_length) const +{ + int little = 0, middle = 0; + const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; + + while(p1 < e1 && p2 < e2) + { + wchar c1 = *p1++; + wchar c2 = *p2++; + + int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); + int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); + if(level1 != level2) + return cmp(level1, level2); + if(level1 <= 1) + { + if(c1 != c2) + return cmp(c1, c2); + continue; + } + if(level1 == 2) + { // digits + const wchar *dp1 = --p1, *dp2 = --p2; + int res = LangCompareDigits(dp1, dp2, e1, e2); + if(res) + return res; + p1 = dp1; + p2 = dp2; + continue; + } + + int u1, u2, i1, i2; + + if((c1 == 'C' || c1 == 'c') && (p1 < e1 && (*p1 == 'H' || *p1 == 'h'))) + { // CH + i1 = 'H'; + u1 = 65535; + p1++; + } + else + i1 = ToAscii(u1 = ToUpper(c1)); + if((c2 == 'C' || c2 == 'c') && (p2 < e2 && (*p2 == 'H' || *p2 == 'h'))) + { // CH + i2 = 'H'; + u2 = 65535; + p2++; + } + else + i2 = ToAscii(u2 = ToUpper(c2)); + + if(i1 != i2) + return i1 >= i2 ? 1 : -1; + + if(u1 != u2) // different diacritics + switch(i1) + { + case 'A': case 'E': case 'I': case 'N': + case 'O': case 'T': case 'U': case 'Y': + if(middle == 0) + middle = u1 - u2; + continue; + default: + return u1 >= u2 ? 1 : -1; + } + if(c1 != c2) // different case + { + if(little == 0) + + little = (u1 != c1) - (u2 != c2); + } + } + little += 4 * middle; + if(little == 0) + little = a_length - b_length; + return sgn(little); +} + +class WildcardCompareCS : public LanguageInfo::WildcardCompare +{ +public: + WildcardCompareCS(const wchar *templ) + { + raw_templ = 0; +// cvt_ascii = false; + if(*templ == 0) + return; +// if((*templ == '.' && templ[1] != 0 && *++templ != '.') || ContainsAccents(templ)) +// { +// exclude_ch = (ToUpper(*templ) == 'C' && templ[1] == 0); +// cvt_ascii = false; +// } + raw_templ = templ; +// if(cvt_ascii) +// cvt_templ = ToUpper(ToAscii(raw_templ)); +// else + cvt_templ = ToUpper(raw_templ); + } + + virtual bool Matches(const wchar *s) const + { +// if(exclude_ch && *s && (s[1] == 'h' || s[1] == 'H')) +// return false; + return !raw_templ || RawMatches(s, cvt_templ); + } + +private: + bool RawMatches(const wchar *s, const wchar *templ) const + { + for(;;) + switch(*templ++) + { + case 0: return true; + case '.': if(*templ == 0) return *s == 0; // force end of string + case '?': if(*s++ == 0) return false; break; + case '*': + do + if(RawMatches(s, templ)) + return true; + while(*s++); + return false; + case '\\': if(*templ == 0 || *templ++ != *s++) return false; break; + default: if(templ[-1] != ToUpper(*s++)) return false; + break; + } + return true; + } + +private: + const wchar *raw_templ; +// bool exclude_ch; +// bool cvt_ascii; + WString cvt_templ; +}; + +One LanguageInfoCS::GetWildcardCompare(const wchar *wildcard_text) const +{ + return new WildcardCompareCS(wildcard_text); +} + +class LanguageInfoEN : public LanguageInfo +{ +public: + LanguageInfoEN() + : LanguageInfo(LNG_('E', 'N', 'U', 'S')) + { + english_name = "English"; + native_name = ToUnicode("English", CHARSET_DEFAULT); +// thousand_separator = " "; +// decimal_point = "."; + } +}; + +class LanguageInfoGE : public LanguageInfo +{ +public: + LanguageInfoGE() + : LanguageInfo(LNG_('D', 'E', 'D', 'E')) + { + english_name = "German"; + native_name = ToUnicode("Deutsch", CHARSET_WIN1250); + } +}; + +class LanguageInfoFR : public LanguageInfo +{ +public: + LanguageInfoFR() + : LanguageInfo(LNG_('F', 'R', 'F', 'R')) + { + english_name = "Franch"; + native_name = ToUnicode("Francaise", CHARSET_WIN1250); + } +}; + +class LanguageInfoES : public LanguageInfo +{ +public: + LanguageInfoES() + : LanguageInfo(LNG_('E', 'S', 'E', 'S')) + { + english_name = "Spanish"; + native_name = ToUnicode("Espagnnol", CHARSET_WIN1250); + } +}; + +const LanguageInfo& GetLanguageInfo(int lcode) +{ + static bool init_std = false; + if(!init_std) + { + init_std = true; + LanguageInfo::Register(new LanguageInfoCS); + LanguageInfo::Register(new LanguageInfoEN); + LanguageInfo::Register(new LanguageInfoGE); + LanguageInfo::Register(new LanguageInfoFR); + LanguageInfo::Register(new LanguageInfoES); + } + + static int recent = 0; + LanguageInfo *rinfo = 0; + if(rinfo && lcode == recent) + return *rinfo; + if(lcode == 0) + lcode = GetCurrentLanguage(); //!! todo - decide on default / neutral language code + INTERLOCKED_(sMapMutex) { + LanguageInfoMap& map = LanguageInfo::Map(); + int f = map.Find(lcode); + if(f < 0) + { + f = map.GetCount(); + map.Add(lcode, new LanguageInfo(lcode)); + } + recent = lcode; + return *(rinfo = &map[f]); + } + return *rinfo; +} + +const LanguageInfo& GetLanguageInfo() +{ + return GetLanguageInfo(GetCurrentLanguage()); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Lang.h b/uppdev/CoreTopics/Lang.h new file mode 100644 index 000000000..55a51772b --- /dev/null +++ b/uppdev/CoreTopics/Lang.h @@ -0,0 +1,120 @@ +#define LNG_(a, b, c, d) ( (((a - 'A' + 1) & 31) << 15) | (((b - 'A' + 1) & 31) << 10) | \ + (((c - 'A' + 1) & 31) << 5) | (((d - 'A' + 1) & 31) << 0) ) + +#define LNGC_(a, b, c, d, cs) ( (((a - 'A' + 1) & 31) << 15) | (((b - 'A' + 1) & 31) << 10) | \ + (((c - 'A' + 1) & 31) << 5) | (((d - 'A' + 1) & 31) << 0) | \ + ((cs & 255) << 20) ) + +int LNGFromText(const char *s); +String LNGAsText(int d); + +Convert& LNGConvert(); + +byte GetLNGCharset(int d); +int SetLNGCharset(int lng, byte chrset); + +#define LNG_CZECH 0xF1CC7A // Deprecated, corresponds to CS-CZ windows-1250 +#define LNG_ENGLISH 0x2BAB3 // LNG_('E', 'N', 'U', 'S') + +#define LNG_CURRENT -1 +#define LNG_MASTER -2 + +void SetLanguage(int lang); +int GetCurrentLanguage(); + +int GetSystemLNG(); + +VectorMap GetLanguage(int lang);//rename... +Vector GetLanguages(); +const int *GetAllLanguages(); + +String GetLangName(int language); +String GetNativeLangName(int language); +byte GetLangCharset(int language); + +String txtGet(const char *id, int language = LNG_CURRENT); + +void ExportLNGtoT(); + +#ifdef PLATFORM_WIN32 +LCID GetLanguageLCID(int language); +String GetLocaleInfoA(LCID lcid, LCTYPE lctype); +WString GetLocaleInfoW(LCID lcid, LCTYPE lctype); +#endif + +class LanguageInfo +{ +public: + LanguageInfo(int language); + virtual ~LanguageInfo() {} + + String ToString() const; + + virtual String FormatInt(int value) const; + virtual String FormatDouble(double value, int digits, int FD_flags = 0, int fill_exp = 0) const; + virtual String FormatDate(Date date) const; + virtual String FormatTime(Time time) const; + +// virtual int ScanInt(const char *text, const char **endptr) const; +// virtual double ScanDouble(const char *text, const char **endptr) const; +// virtual Date ScanDate(const char *text, const char **endptr, Date base_date = GetSysDate()) const; +// virtual Time ScanTime(const char *text, const char **endptr, Time base_time = GetSysTime()) const; + + virtual WString GetIndexLetter(const wchar *text) const; + + virtual int Compare(const wchar *a, const wchar *b, int a_length, int b_length) const; + int Compare(const wchar *a, const wchar *b) const { return Compare(a, b, wstrlen(a), wstrlen(b)); } + int Compare(WString a, WString b) const { return Compare(a, b, a.GetLength(), b.GetLength()); } + int Compare(const char *a, const char *b) const { return Compare(ToUnicode(a, CHARSET_DEFAULT), ToUnicode(b, CHARSET_DEFAULT)); } + int Compare(String a, String b) const { return Compare(a.ToWString(), b.ToWString()); } + + bool operator () (const wchar *a, const wchar *b) const { return Compare(a, b) < 0; } + bool operator () (WString a, WString b) const { return Compare(a, b) < 0; } + bool operator () (const char *a, const char *b) const { return Compare(a, b) < 0; } + bool operator () (String a, String b) const { return Compare(a, b) < 0; } + + struct WildcardCompare + { + virtual ~WildcardCompare() {} + virtual bool Matches(const wchar *s) const = 0; + }; + + virtual One GetWildcardCompare(const wchar *wildcard_text) const; + + static ArrayMap& Map(); + static void Register(One info); + +public: + int language; + String english_name; + WString native_name; + byte charset; + + String thousand_separator; + String decimal_point; + String date_format; + String time_format; + + WString month_names[12], short_month_names[12]; + WString day_names[7], short_day_names[7]; +}; + +const LanguageInfo& GetLanguageInfo(int lcode); +const LanguageInfo& GetLanguageInfo(); + +// ------ Language internals ---------------- + +#include "Lang_s.h" + +struct LangModuleRecord { + const char *id; + const char **ptr; +}; + +struct LangTextRecord { + const char **ptr; + const char *text; +}; + +void AddLangModule(const char *file, const char *modulename, int masterlang, const LangModuleRecord *module); +void AddLanguage(const char *modulename, int lang, const LangTextRecord *langtext); diff --git a/uppdev/CoreTopics/Lang_s.h b/uppdev/CoreTopics/Lang_s.h new file mode 100644 index 000000000..02ca5d9b5 --- /dev/null +++ b/uppdev/CoreTopics/Lang_s.h @@ -0,0 +1,6 @@ +#ifndef __temp_aux__Lang_s_h_ +#define __temp_aux__Lang_s_h_ + +#define s_(x) txt##x + +#endif diff --git a/uppdev/CoreTopics/Log.cpp b/uppdev/CoreTopics/Log.cpp new file mode 100644 index 000000000..14328c1d6 --- /dev/null +++ b/uppdev/CoreTopics/Log.cpp @@ -0,0 +1,331 @@ +#include "Core.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WINCE +const char *FromSysChrSet(const wchar *s) +{ + static char out[256]; + FromUnicode(out, s, wstrlen(s), CHARSET_DEFAULT); + return out; +} + +const wchar *ToSysChrSet(const char *s) +{ + static wchar out[1024]; + ToUnicode(out, s, strlen(s), CHARSET_DEFAULT); + return out; +} +#endif + +LogStream::LogStream() +{ +#ifdef PLATFORM_POSIX + hfile = -1; +#else + hfile = INVALID_HANDLE_VALUE; +#endif + part = 0; + sizelimit = 0; + *filename = 0; + options = LOG_FILE; + depth = 0; + bol = false; +} + +LogStream::~LogStream() {} + +void LogStream::Close() +{ +#ifdef PLATFORM_POSIX + if(hfile >= 0) + close(hfile); + hfile = -1; +#else + if(hfile != INVALID_HANDLE_VALUE) + CloseHandle(hfile); + hfile = INVALID_HANDLE_VALUE; +#endif +} + +bool LogStream::Delete() +{ + Close(); + if(*filename) { + if(!FileDelete(filename)) { + BugLog() << "Error deleting " << filename << ": " << GetLastErrorMessage(); + return false; + } + *filename = 0; + } + return true; +} + +void LogStream::Create(const char *path, bool append) +{ + Close(); + + strcpy(filename, path); + strcpy(backup, filename); + strcat(backup, ".old"); + +#if defined(PLATFORM_WIN32) + + #if defined(PLATFORM_WINCE) + wchar_t pwcs[512]; + mbstowcs(pwcs, backup, strlen(backup)); + DeleteFile(pwcs); + #else + DeleteFile(backup); + #endif + +#elif defined(PLATFORM_POSIX) + unlink(backup); +#else + #error +#endif + +#if defined(PLATFORM_WIN32) + #if defined(PLATFORM_WINCE) + wchar_t wfilename[512]; + mbstowcs(wfilename, filename, strlen(filename)); + MoveFile(wfilename, pwcs); + #else + MoveFile(filename, backup); + #endif +#elif defined(PLATFORM_POSIX) + rename(filename, backup); +#else + #error +#endif + + filesize = 0; + +#ifdef PLATFORM_WIN32 + hfile = CreateFile(ToSysChrSet(filename), + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if(append) + filesize = (int)SetFilePointer(hfile, 0, NULL, FILE_END); +#else + hfile = open(filename, append ? O_CREAT|O_RDWR|O_APPEND : O_CREAT|O_RDWR|O_TRUNC, 0644); + if(append) + filesize = (int)lseek(hfile, 0, SEEK_END); +#endif + wrlim = ptr = (byte *)this; + p = buffer; + + Time t = GetSysTime(); +#ifdef PLATFORM_WINCE + wchar exe[512]; +#else + char exe[512]; +#endif + char user[500]; + *user = 0; + +#ifdef PLATFORM_WIN32 + GetModuleFileName(AppGetHandle(), exe, 512); +#ifndef PLATFORM_WINCE + dword w = 2048; + GetUserName(user, &w); +#endif +#else //# + const char *procexepath_(); + strcpy(exe, procexepath_()); + const char *uenv = getenv("USER"); + strcpy(user, uenv ? uenv : "boot"); +#endif + + char h[1000]; + sprintf(h, "* %s %02d.%02d.%04d %02d:%02d:%02d, user: %s\n", + FromSysChrSet(exe), + t.day, t.month, t.year, t.hour, t.minute, t.second, user); +#ifdef PLATFORM_WIN32 + dword n; + WriteFile(hfile, h, (dword)strlen(h), &n, NULL); + if(part) { + sprintf(h, ", #%d", part); + WriteFile(hfile, h, (dword)strlen(h) , &n, NULL); + } + WriteFile(hfile, "\r\n", 2, &n, NULL); +#else + write(hfile, h, strlen(h)); + if(part) { + sprintf(h, ", #%d", part); + write(hfile, h, strlen(h)); + } + write(hfile, "\r\n", 2); +#endif +} + +void LogStream::Flush() +{ + int count = (int)(p - buffer); + if(count == 0) return; + if(options & LOG_COUT) + Cout().Put(buffer, count); + if(options & LOG_CERR) + Cerr().Put(buffer, count); +#ifdef PLATFORM_WIN32 + if(options & LOG_FILE) + if(hfile != INVALID_HANDLE_VALUE) { + dword n; + WriteFile(hfile, buffer, count, &n, NULL); + } + if(options & LOG_DBG) { + *p = 0; + ::OutputDebugString((LPCSTR)buffer); + } +#else + if(options & LOG_FILE) + if(hfile >= 0) + write(hfile, buffer, count); + if(options & LOG_DBG) + Cerr().Put(buffer, count); +#endif + filesize += count; + p = buffer; + if(sizelimit > 0 && filesize > sizelimit) + Create(filename, false); +} + +void LogStream::Put0(int w) +{ + if(w == LOG_BEGIN) + depth++; + else + if(w == LOG_END) + depth--; + else { + if(bol) { + bol = false; + for(int q = depth; q--;) + Put0('\t'); + } + *p++ = w; + if(w == '\n') { + Flush(); + bol = true; + } + else + if(p == buffer + 512) + Flush(); + } +} + +void LogStream::_Put(int w) +{ + CriticalSection::Lock __(cs); + Put0(w); +} + +void LogStream::_Put(const void *data, dword size) +{ + CriticalSection::Lock __(cs); + const byte *q = (byte *)data; + while(size--) + Put0(*q++); +} + +bool LogStream::IsOpen() const +{ +#ifdef PLATFORM_POSIX + return hfile >= 0; +#else + return hfile != INVALID_HANDLE_VALUE; +#endif +} + +static void sLarge(String& text, size_t *large, int count, const char *txt) +{ + int n = min(1024, count); + Sort(large, large + n, StdLess()); + int i = 0; + while(i < n) { + size_t q = large[i]; + int nn = i++; + while(i < n && large[i] == q) i++; + nn = i - nn; + if(q < 10000) + text << Format("%4d B, %5d %s (%6d KB)\r\n", (int)(uintptr_t)q, nn, txt, (int)(uintptr_t)((nn * q) >> 10)); + else + text << Format("%4d`KB, %5d %s (%6d KB)\r\n", (int)(uintptr_t)(q >> 10), nn, txt, (int)(uintptr_t)((nn * q) >> 10)); + } +} + +String AsString(MemoryProfile& mem) +{ + String text; + int acount = 0; + size_t asize = 0; + int fcount = 0; + size_t fsize = 0; + for(int i = 0; i < 1024; i++) + if(mem.allocated[i]) { + int sz = 4 * i; + text << Format("%4d B, %6d allocated (%5d KB), %6d fragmented (%5d KB)\n", + sz, mem.allocated[i], (mem.allocated[i] * sz) >> 10, + mem.fragmented[i], (mem.fragmented[i] * sz) >> 10); + acount += mem.allocated[i]; + asize += mem.allocated[i] * sz; + fcount += mem.fragmented[i]; + fsize += mem.fragmented[i] * sz; + } + text << Format(" TOTAL, %6d allocated (%5d KB), %6d fragmented (%5d KB)\n", + acount, int(asize >> 10), fcount, int(fsize >> 10)); + text << "Free pages " << mem.freepages << " (" << mem.freepages * 4 << " KB)\n"; + text << "Large block count " << mem.large_count + << ", total size " << (mem.large_total >> 10) << " KB\n"; +// sLarge(text, mem.large_size, mem.large_count, "allocated"); + text << "Large fragments count " << mem.large_free_count + << ", total size " << (mem.large_free_total >> 10) << " KB\n"; +// sLarge(text, mem.large_free_size, mem.large_free_count, "fragments"); + return text; +} + + +#ifdef _MULTITHREADED + +StaticCriticalSection sLogLock; + +void LockLog() +{ + sLogLock.Enter(); +} + +void UnlockLog() +{ + sLogLock.Leave(); +} + +#endif + +#ifdef flagCHECKINIT + +void InitBlockBegin__(const char *fn, int line) { + RLOG(fn << " " << line << " init block"); +#ifdef HEAPDBG + MemoryCheckDebug(); +#else + MemoryCheck(); +#endif +} + +void InitBlockEnd__(const char *fn, int line) { + RLOG(fn << " " << line << " init block finished"); +#ifdef HEAPDBG + MemoryCheckDebug(); +#else + MemoryCheck(); +#endif +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Map.h b/uppdev/CoreTopics/Map.h new file mode 100644 index 000000000..e957a69cd --- /dev/null +++ b/uppdev/CoreTopics/Map.h @@ -0,0 +1,188 @@ +template +class AMap { +protected: + Index key; + V value; + +public: + void Add(const K& k, const T& x) { key.Add(k); value.Add(x); } + void AddPick(const K& k, pick_ T& x) { key.Add(k); value.AddPick(x); } + T& Add(const K& k) { key.Add(k); return value.Add(); } + + int Find(const K& k, unsigned h) const { return key.Find(k, h); } + int Find(const K& k) const { return key.Find(k); } + int FindNext(int i) const { return key.FindNext(i); } + int FindLast(const K& k, unsigned h) const { return key.FindLast(k, h); } + int FindLast(const K& k) const { return key.FindLast(k); } + int FindPrev(int i) const { return key.FindPrev(i); } + + int FindAdd(const K& k); + int FindAdd(const K& k, const T& init); + int FindAddPick(const K& k, pick_ T& init); + + int Put(const K& k, const T& x); + int PutPick(const K& k, pick_ T& x); + T& Put(const K& k); + + int FindPut(const K& k); + int FindPut(const K& k, const T& init); + int FindPutPick(const K& k, pick_ T& init); + + T& Get(const K& k) { return value[Find(k)]; } + const T& Get(const K& k) const { return value[Find(k)]; } + const T& Get(const K& k, const T& d) const { int i = Find(k); return i >= 0 ? value[i] : d; } + + T& GetAdd(const K& k); + + T& GetAdd(const K& k, const T& x); + T& GetAddPick(const K& k, pick_ T& x); + + T& GetPut(const K& k); + + T& GetPut(const K& k, const T& x); + T& GetPutPick(const K& k, pick_ T& x); + + void SetKey(int i, const K& k) { key.Set(i, k); } + + T *FindPtr(const K& k) { int i = Find(k); return i >= 0 ? &value[i] : NULL; } + const T *FindPtr(const K& k) const { int i = Find(k); return i >= 0 ? &value[i] : NULL; } + +// PRECHANGE VACATION :) +// T& operator()(const K& k) { return Get(k); } +// const T& operator()(const K& k) const { return Get(k); } +// const T& operator()(const K& k, const T& d) const { return Get(k, d); } + + void Unlink(int i) { key.Unlink(i); } + int UnlinkKey(const K& k, unsigned h) { return key.UnlinkKey(k, h); } + int UnlinkKey(const K& k) { return key.UnlinkKey(k); } + bool IsUnlinked(int i) const { return key.IsUnlinked(i); } + void Sweep(); + + T& Insert(int i, const K& k) { key.Insert(i, k); return value.Insert(i); } + void Insert(int i, const K& k, const T& x) { key.Insert(i, k); value.Insert(i, x); } + void Remove(int i) { key.Remove(i); value.Remove(i); } + void Remove(int i, int count) { key.Remove(i, count); value.Remove(i, count); } + void Remove(const int *sl, int n) { key.Remove(sl, n); value.Remove(sl, n); } + void Remove(const Vector& sl) { Remove(sl, sl.GetCount()); } + int RemoveKey(const K& k); + + const T& operator[](int i) const { return value[i]; } + T& operator[](int i) { return value[i]; } + int GetCount() const { return value.GetCount(); } + bool IsEmpty() const { return value.IsEmpty(); } + void Clear() { key.Clear(); value.Clear(); } + void Shrink() { value.Shrink(); key.Shrink(); } + void Reserve(int xtra) { value.Reserve(xtra); key.Reserve(xtra); } + int GetAlloc() const { return value.GetAlloc(); } + + void Drop(int n = 1) { key.Drop(n); value.Drop(n); } + T& Top() { return value.Top(); } + const T& Top() const { return value.Top(); } + const K& TopKey() const { return key.Top(); } +// T Pop() { T h = Top(); Drop(); return h; } + K PopKey() { K h = TopKey(); Drop(); return h; } + void Trim(int n) { key.Trim(n); value.SetCount(n); } + + const K& GetKey(int i) const { return key[i]; } + +#ifdef UPP + void Serialize(Stream& s); +#endif + + void Swap(AMap& x) { UPP::Swap(value, x.value); + UPP::Swap(key, x.key); } + const Index& GetIndex() const { return key; } + Index PickIndex() pick_ { return key; } + + const Vector& GetKeys() const { return key.GetKeys(); } + Vector PickKeys() pick_ { return key.PickKeys(); } + + const V& GetValues() const { return value; } + V PickValues() pick_ { return value; } + + AMap() {} + AMap(const AMap& s, int) : key(s.key, 0), value(s.value, 0) {} + AMap(pick_ Index& ndx, pick_ V& val) : value(val), key(ndx) {} + AMap(pick_ Vector& ndx, pick_ V& val) : value(val), key(ndx) {} + + typedef K KeyType; + typedef typename Index::ConstIterator KeyConstIterator; + + KeyConstIterator KeyBegin() const { return key.Begin(); } + KeyConstIterator KeyEnd() const { return key.End(); } + KeyConstIterator KeyGetIter(int pos) const { return key.GetIter(pos); } + + typedef T ValueType; + typedef typename V::ConstIterator ConstIterator; + typedef typename V::Iterator Iterator; + + Iterator Begin() { return value.Begin(); } + Iterator End() { return value.End(); } + Iterator GetIter(int pos) { return value.GetIter(pos); } + ConstIterator Begin() const { return value.Begin(); } + ConstIterator End() const { return value.End(); } + ConstIterator GetIter(int pos) const { return value.GetIter(pos); } + + friend int GetCount(const AMap& v) { return v.GetCount(); } +}; + +template > +class VectorMap : public MoveableAndDeepCopyOption >, + public AMap< K, T, Vector, HashFn > { + typedef AMap< K, T, Vector, HashFn > B; +public: + T Pop() { T h = B::Top(); B::Drop(); return h; } + + VectorMap(const VectorMap& s, int) : AMap, HashFn>(s, 1) {} + VectorMap(pick_ Index& ndx, pick_ Vector& val) : AMap, HashFn>(ndx, val) {} + VectorMap(pick_ Vector& ndx, pick_ Vector& val) : AMap, HashFn>(ndx, val) {} + VectorMap() {} + + friend void Swap(VectorMap& a, VectorMap& b) { a.B::Swap(b); } + + typedef typename AMap< K, T, Vector, HashFn >::ConstIterator ConstIterator; // GCC bug (?) + typedef typename AMap< K, T, Vector, HashFn >::Iterator Iterator; // GCC bug (?) + STL_MAP_COMPATIBILITY(VectorMap) +}; + +template > +class ArrayMap : public MoveableAndDeepCopyOption< ArrayMap >, + public AMap< K, T, Array, HashFn > { + typedef AMap< K, T, Array, HashFn > B; +public: + void Add(const K& k, const T& x) { B::Add(k, x); } + T& Add(const K& k) { return B::Add(k); } + T& Add(const K& k, T *newt) { B::key.Add(k); B::value.Add(newt); return *newt; } + template TT& Create(const K& k) { TT *q = new TT; B::key.Add(k); B::value.Add(q); return *q; } + + void Set(int i, T *ptr) { B::value.Set(i, ptr); } + T *PopDetach() { B::key.Drop(); return B::value.PopDetach(); } + + ArrayMap(const ArrayMap& s, int) : AMap, HashFn>(s, 1) {} + ArrayMap(pick_ Index& ndx, pick_ Array& val) : AMap, HashFn>(ndx, val) {} + ArrayMap(pick_ Vector& ndx, pick_ Array& val) : AMap, HashFn>(ndx, val) {} + ArrayMap() {} + + friend void Swap(ArrayMap& a, ArrayMap& b) { a.B::Swap(b); } + + typedef typename AMap< K, T, Array, HashFn >::ConstIterator ConstIterator; // GCC bug (?) + typedef typename AMap< K, T, Array, HashFn >::Iterator Iterator; // GCC bug (?) + STL_MAP_COMPATIBILITY(ArrayMap) +}; + +template > +class SegtorMap : public MoveableAndDeepCopyOption< SegtorMap >, + public AMap< K, T, Segtor, HashFn > { + typedef AMap< K, T, Segtor, HashFn > B; +public: + SegtorMap(const SegtorMap& s, int) : AMap, HashFn>(s, 1) {} + SegtorMap(pick_ Index& ndx, pick_ Segtor& val) : AMap, HashFn>(ndx, val) {} + SegtorMap(pick_ Vector& ndx, pick_ Segtor& val) : AMap, HashFn>(ndx, val) {} + SegtorMap() {} + + friend void Swap(SegtorMap& a, SegtorMap& b) { a.B::Swap(b); } + + typedef typename B::ConstIterator ConstIterator; // GCC bug (?) + typedef typename B::Iterator Iterator; // GCC bug (?) + STL_MAP_COMPATIBILITY(SegtorMap) +}; diff --git a/uppdev/CoreTopics/Mpr32W.dli b/uppdev/CoreTopics/Mpr32W.dli new file mode 100644 index 000000000..8b1588a93 --- /dev/null +++ b/uppdev/CoreTopics/Mpr32W.dli @@ -0,0 +1 @@ +FN_C(DWORD, APIENTRY, WNetEnumResourceW, (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)) diff --git a/uppdev/CoreTopics/Mt.cpp b/uppdev/CoreTopics/Mt.cpp new file mode 100644 index 000000000..206fac0cf --- /dev/null +++ b/uppdev/CoreTopics/Mt.cpp @@ -0,0 +1,447 @@ +#include "Core.h" + +NAMESPACE_UPP + +#ifdef _MULTITHREADED + +static Mutex& sMutexLock() +{ + static Mutex *section; + if(!section) { + static byte b[sizeof(Mutex)]; + section = new(b) Mutex; + } + return *section; +} + +INITBLOCK { + sMutexLock(); +} + +Thread::Thread() +{ + sMutexLock(); +#ifdef PLATFORM_WIN32 + handle = 0; +#endif +#ifdef PLATFORM_POSIX + handle = 0; +#endif +} + +void Thread::Detach() +{ +#if defined(PLATFORM_WIN32) + if(handle) { + CloseHandle(handle); + handle = 0; + } +#elif defined(PLATFORM_POSIX) + if(handle) { + CHECK(!pthread_detach(handle)); + handle = 0; + } +#endif +} + +static Atomic sThreadCount; + +#if defined(PLATFORM_WIN32) || defined(PLATFORM_POSIX) +static +#ifdef PLATFORM_WIN32 +#ifdef CPU_64 +unsigned int +#else +uintptr_t __stdcall +#endif +#else +void * +#endif +sThreadRoutine(void *arg) +{ + Callback *cb = (Callback *)arg; + (*cb)(); + AtomicDec(sThreadCount); + delete cb; +#ifdef UPP_HEAP + MemoryFreeThread(); +#endif + return 0; +} +#endif + +static bool threadr; + +bool Thread::IsST() +{ + return !threadr; +} + +bool Thread::Run(Callback _cb) +{ + AtomicInc(sThreadCount); + threadr = true; + Detach(); + Callback *cb = new Callback(_cb); +#ifdef PLATFORM_WIN32 + unsigned thread_id; + handle = (HANDLE)_beginthreadex(0, 0, sThreadRoutine, cb, 0, &thread_id); +#endif +#ifdef PLATFORM_POSIX + if(pthread_create(&handle, 0, sThreadRoutine, cb)) + handle = 0; +#endif + return handle; +} + +int Thread::GetCount() +{ + return ReadWithBarrier(sThreadCount); +} + +static Atomic sShutdown; + +void Thread::ShutdownThreads() +{ + AtomicInc(sShutdown); + while(sThreadCount) + Sleep(100); + AtomicDec(sShutdown); +} + +bool Thread::IsShutdownThreads() +{ + return sShutdown; +} + +int Thread::Wait() +{ + if(!IsOpen()) + return -1; + int out; +#ifdef PLATFORM_WIN32 + dword exit; + if(!GetExitCodeThread(handle, &exit)) + return -1; + if(exit != STILL_ACTIVE) + out = (int)exit; + else + { + if(WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0) + return Null; + out = GetExitCodeThread(handle, &exit) ? int(exit) : int(Null); + } + Detach(); +#endif +#ifdef PLATFORM_POSIX + void *thread_return; + if(pthread_join(handle, &thread_return)) + out = Null; + else + out = (int)(intptr_t)thread_return; + handle = 0; +#endif + return out; +} + +void Thread::Priority(int percent) +{ + ASSERT(IsOpen()); +#ifdef PLATFORM_WIN32 + int prior; + if(percent <= 25) + prior = THREAD_PRIORITY_LOWEST; + else if(percent <= 75) + prior = THREAD_PRIORITY_BELOW_NORMAL; + else if(percent <= 125) + prior = THREAD_PRIORITY_NORMAL; + else if(percent <= 175) + prior = THREAD_PRIORITY_ABOVE_NORMAL; + else + prior = THREAD_PRIORITY_HIGHEST; + SetThreadPriority(handle, prior); +#endif +#ifdef PLATFORM_POSIX + //!! todo +#endif +} + +void Thread::Start(Callback cb) +{ + Thread t; + t.Run(cb); + t.Detach(); +} + +void Thread::Sleep(int msec) +{ +#ifdef PLATFORM_WIN32 + ::Sleep(msec); +#endif +#ifdef PLATFORM_POSIX + timespec tval; + tval.tv_sec = msec / 1000; + tval.tv_nsec = (msec % 1000) * 1000000; + nanosleep(&tval, NULL); +#endif +} + +#ifdef CPU_X86 + +#ifndef CPU_SSE2 + +static bool sSSE2 = false; //CPU_SSE2(); + +inline void ReadMemoryBarrier() +{ +#ifdef CPU_AMD64 + #ifdef COMPILER_MSC + _mm_lfence(); + #else + __asm__("lfence"); + #endif +#else + if(sSSE2) + #ifdef COMPILER_MSC + __asm lfence; + #else + __asm__("lfence"); + #endif + else { + static Atomic x; + AtomicInc(x); + } +#endif +} + +void WriteMemoryBarrier() { +#ifdef CPU_AMD64 + #ifdef COMPILER_MSC + _mm_sfence(); + #else + __asm__("sfence"); + #endif +#else + if(sSSE2) + #ifdef COMPILER_MSC + __asm sfence; + #else + __asm__("sfence"); + #endif + else { + static Atomic x; + AtomicInc(x); + } +#endif +} +#endif + +#endif + +#ifdef flagPROFILEMT +MtInspector *MtInspector::Dumi() +{ + static MtInspector h(NULL); + return &h; +} + +MtInspector::~MtInspector() +{ + if(name) + RLOG("Mutex " << name << '(' << number << ") " << blocked << "/" << locked << + " = " << Sprintf("%.4f", locked ? (double)blocked / locked : 0) << " blocked/locked times"); +} +#endif + +#ifdef PLATFORM_WIN32 + +void Semaphore::Release() +{ + ReleaseSemaphore(handle, 1, NULL); +} + +void Semaphore::Wait() +{ + WaitForSingleObject(handle, INFINITE); +} + +Semaphore::Semaphore() +{ + handle = CreateSemaphore(NULL, 0, INT_MAX, NULL); +} + +Semaphore::~Semaphore() +{ + CloseHandle(handle); +} + +Mutex& sMutexLock(); + + +typedef BOOL (WINAPI *TEC)(LPCRITICAL_SECTION lpCriticalSection); + +static TEC sTec; + +bool Mutex::TryEnter() +{ + if(!sTec) { + if(HMODULE hDLL = LoadLibrary("Kernel32")) + sTec = (TEC) GetProcAddress(hDLL, "TryEnterCriticalSection"); + } +/* TODO! TryEntery0 +#ifdef flagPROFILEMT + bool b = (*sTec)(§ion); + mti->blocked += b; + return b; +#else +*/ + return (*sTec)(§ion); +//#endif +} + +/* Win32 RWMutex implementation by Chris Thomasson, cristom@comcast.net */ + +void RWMutex::EnterWrite() +{ + EnterCriticalSection ( &m_wrlock ); + LONG count = InterlockedExchangeAdd(&m_count, -LONG_MAX); + if(count < LONG_MAX) + if(InterlockedExchangeAdd ( &m_rdwake, LONG_MAX - count ) + LONG_MAX - count ) + WaitForSingleObject ( m_wrwset, INFINITE ); +} + +void RWMutex::LeaveWrite() +{ + LONG count = InterlockedExchangeAdd ( &m_count, LONG_MAX ); + if (count < 0) + ReleaseSemaphore ( m_rdwset, count * -1, 0 ); + LeaveCriticalSection ( &m_wrlock ); +} + +void RWMutex::EnterRead() +{ + LONG count = InterlockedDecrement ( &m_count ); + if(count < 0) + WaitForSingleObject ( m_rdwset, INFINITE ); +} + +void RWMutex::LeaveRead() +{ + LONG count = InterlockedIncrement ( &m_count ); + if ( count < 1 ) + if ( ! InterlockedDecrement ( &m_rdwake ) ) + SetEvent ( m_wrwset ); +} + +RWMutex::RWMutex() +: m_count ( LONG_MAX ), + m_rdwake ( 0 ), + m_wrwset ( CreateEvent ( 0, FALSE, FALSE, 0 ) ), + m_rdwset ( CreateSemaphore ( 0, 0, LONG_MAX, 0 ) ) +{ + InitializeCriticalSection ( &m_wrlock ); +} + +RWMutex::~RWMutex() +{ + DeleteCriticalSection ( &m_wrlock ); + CloseHandle ( m_rdwset ); + CloseHandle ( m_wrwset ); +} + +#endif + +#ifdef PLATFORM_POSIX + +Mutex::Mutex() +{ + pthread_mutexattr_t mutex_attr[1]; + pthread_mutexattr_init(mutex_attr); + pthread_mutexattr_settype(mutex_attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(mutex, mutex_attr); +#ifdef flagPROFILEMT + mti = MtInspector::Dumi(); +#endif +} + +RWMutex::RWMutex() +{ + pthread_rwlock_init(rwlock, NULL); +} + +RWMutex::~RWMutex() +{ + pthread_rwlock_destroy(rwlock); +} + +/* +Event::Event() +{ + pthread_mutex_init(mutex, NULL); + pthread_cond_init(cond, NULL); +} + +Event::~Event() +{ + pthread_mutex_destroy(mutex); + pthread_cond_destroy(cond); +} + +void Event::Wait() +{ + pthread_mutex_lock(mutex); + pthread_cond_wait(cond, mutex); + pthread_mutex_unlock(mutex); +} + +void Event::Go() +{ + pthread_cond_signal(cond); +} +*/ +void Semaphore::Release() +{ + sem_post(&sem); +} + +void Semaphore::Wait() +{ + sem_wait(&sem); +} + +Semaphore::Semaphore() +{ + sem_init(&sem, 0, 0); +} + +Semaphore::~Semaphore() +{ + sem_destroy(&sem); +} + +#endif + +void StaticMutex::Initialize() +{ + Mutex::Lock __(sMutexLock()); + if(!ReadWithBarrier(section)) + BarrierWrite(section, new(buffer) Mutex); +} + +void StaticRWMutex::Initialize() +{ + Mutex::Lock __(sMutexLock()); + if(!ReadWithBarrier(rw)) + BarrierWrite(rw, new(buffer) RWMutex); +} + +void StaticSemaphore::Initialize() +{ + Mutex::Lock __(sMutexLock()); + if(!ReadWithBarrier(semaphore)) + BarrierWrite(semaphore, new(buffer) Semaphore); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Mt.h b/uppdev/CoreTopics/Mt.h new file mode 100644 index 000000000..59ff2580f --- /dev/null +++ b/uppdev/CoreTopics/Mt.h @@ -0,0 +1,443 @@ +#ifndef _DEBUG +inline void AssertST() {} +#endif + +#ifdef _MULTITHREADED + +#ifdef COMPILER_MSC +#define thread__ __declspec(thread) +#else +#define thread__ __thread +#endif + +#ifdef flagPROFILEMT +class Mutex; +class StaticMutex; + +struct MtInspector { + const char *name; + int number; + int locked; + int blocked; + + static MtInspector *Dumi(); + + MtInspector(const char *s, int n = -1) { name = s; number = n; locked = blocked = 0; } + ~MtInspector(); +}; + +#define PROFILEMT(mutex) \ + { static MtInspector MK__s(__FILE__, __LINE__); mutex.Set(MK__s); } + +#define PROFILEMT_(mutex, id) \ + { static MtInspector MK__s(id); mutex.Set(MK__s); } + +#else + +#define PROFILEMT(mutex) +#define PROFILEMT_(mutex, id) + +#endif + +class Callback; + +class Thread { +#ifdef PLATFORM_WIN32 + HANDLE handle; +#endif +#ifdef PLATFORM_POSIX + pthread_t handle; +#endif + +public: + bool Run(Callback cb); + + void Detach(); + int Wait(); + + bool IsOpen() const { return handle; } + +#ifdef PLATFORM_WIN32 + HANDLE GetHandle() const { return handle; } +#endif +#ifdef PLATFORM_POSIX + pthread_t GetHandle() const { return handle; } +#endif + + void Priority(int percent); // 0 = lowest, 100 = normal + + static void Start(Callback cb); + + static void Sleep(int ms); + + static bool IsST(); + static int GetCount(); + static void ShutdownThreads(); + static bool IsShutdownThreads(); + + + Thread(); + ~Thread() { Detach(); } + +private: + void operator=(const Thread&); + Thread(const Thread&); +}; + +#ifdef _DEBUG +inline void AssertST() { ASSERT(Thread::IsST()); } +#endif + +void ReadMemoryBarrier(); +void WriteMemoryBarrier(); + +#ifdef CPU_SSE2 +inline void ReadMemoryBarrier() +{ +#ifdef CPU_AMD64 + #ifdef COMPILER_MSC + _mm_lfence(); + #else + __asm__("lfence"); + #endif +#else + #ifdef COMPILER_MSC + __asm lfence; + #else + __asm__("lfence"); + #endif +#endif +} + +inline void WriteMemoryBarrier() { +#ifdef CPU_AMD64 + #ifdef COMPILER_MSC + _mm_sfence(); + #else + __asm__("sfence"); + #endif +#else + #ifdef COMPILER_MSC + __asm sfence; + #else + __asm__("sfence"); + #endif +#endif +} +#endif + +template +inline U ReadWithBarrier(const volatile U& b) +{ + /*volatile*/ U tmp = b; + ReadMemoryBarrier(); + return tmp; +} + +template +inline void BarrierWrite(volatile U& ptr, V data) +{ + WriteMemoryBarrier(); + ptr = data; +} + +class Semaphore { +#ifdef PLATFORM_WIN32 + HANDLE handle; +#else + sem_t sem; +#endif + +public: + void Wait(); + void Release(); + + Semaphore(); + ~Semaphore(); +}; + +class StaticSemaphore { + volatile Semaphore *semaphore; + byte buffer[sizeof(Semaphore)]; + + void Initialize(); + +public: + Semaphore& Get() { if(!ReadWithBarrier(semaphore)) Initialize(); return *const_cast(semaphore); } + operator Semaphore&() { return Get(); } + void Wait() { Get().Wait(); } + void Release() { Get().Release(); } +}; + +struct MtInspector; + +#ifdef PLATFORM_WIN32 + +typedef LONG Atomic; + +inline int AtomicInc(volatile Atomic& t) { return InterlockedIncrement((Atomic *)&t); } +inline int AtomicDec(volatile Atomic& t) { return InterlockedDecrement((Atomic *)&t); } +inline int AtomicXAdd(volatile Atomic& t, int incr) { return InterlockedExchangeAdd((Atomic *)&t, incr); } + +class Mutex { +protected: + CRITICAL_SECTION section; + MtInspector *mti; + + Mutex(int) {} + +public: + bool TryEnter(); + void Leave() { LeaveCriticalSection(§ion); } + +#ifdef flagPROFILEMT + void Enter() { if(!TryEnter()) { mti->blocked++; EnterCriticalSection(§ion); }; mti->locked++; } + void Set(MtInspector& m) { mti = &m; } + + Mutex() { mti = MtInspector::Dumi(); InitializeCriticalSection(§ion); } +#else + void Enter() { EnterCriticalSection(§ion); } + + Mutex() { InitializeCriticalSection(§ion); } +#endif + + ~Mutex() { DeleteCriticalSection(§ion); } + + struct Lock; +}; + +/* Win32 RWMutex implementation by Chris Thomasson, cristom@comcast.net */ + +class RWMutex { + LONG m_count, m_rdwake; + HANDLE m_wrwset, m_rdwset; + CRITICAL_SECTION m_wrlock; + +public: + void EnterWrite(); + void LeaveWrite(); + + void EnterRead(); + void LeaveRead(); + + RWMutex(); + ~RWMutex(); + + struct ReadLock; + struct WriteLock; +}; + +#endif + +#ifdef PLATFORM_POSIX + +typedef _Atomic_word Atomic; + +inline int AtomicXAdd(volatile Atomic& t, int incr) { using namespace __gnu_cxx; return __exchange_and_add(&t, incr); } + +inline int AtomicInc(volatile Atomic& t) { return AtomicXAdd(t, +1) + 1; } +inline int AtomicDec(volatile Atomic& t) { return AtomicXAdd(t, -1) - 1; } + +class Mutex { +protected: + pthread_mutex_t mutex[1]; + MtInspector *mti; + +public: +#ifdef flagPROFILEMT + bool TryEnter() { bool b = pthread_mutex_trylock(mutex) == 0; mti->locked += b; return b; } + void Enter() { if(pthread_mutex_trylock(mutex) != 0) { mti->blocked++; pthread_mutex_lock(mutex); } mti->locked++; } + void Set(MtInspector& m) { mti = &m; } +#else + bool TryEnter() { return pthread_mutex_trylock(mutex) == 0; } + void Enter() { pthread_mutex_lock(mutex); } +#endif + void Leave() { pthread_mutex_unlock(mutex); } + + struct Lock; + + Mutex(); + ~Mutex() { pthread_mutex_destroy(mutex); } +}; + +class RWMutex { + pthread_rwlock_t rwlock[1]; + +public: + void EnterWrite() { pthread_rwlock_wrlock(rwlock); } + void LeaveWrite() { pthread_rwlock_unlock(rwlock); } + void EnterRead() { pthread_rwlock_rdlock(rwlock); } + void LeaveRead() { pthread_rwlock_unlock(rwlock); } + + RWMutex(); + ~RWMutex(); + + struct ReadLock; + struct WriteLock; +}; + +#endif + +inline int AtomicRead(const volatile Atomic& t) { return ReadWithBarrier(t); } +inline void AtomicWrite(volatile Atomic& t, int val) { BarrierWrite(t, val); } + +struct Mutex::Lock { + Mutex& s; + Lock(Mutex& s) : s(s) { s.Enter(); } + ~Lock() { s.Leave(); } +}; + +struct RWMutex::ReadLock { + RWMutex& s; + ReadLock(RWMutex& s) : s(s) { s.EnterRead(); } + ~ReadLock() { s.LeaveRead(); } +}; + +struct RWMutex::WriteLock { + RWMutex& s; + WriteLock(RWMutex& s) : s(s) { s.EnterWrite(); } + ~WriteLock() { s.LeaveWrite(); } +}; + +class StaticMutex { + volatile Mutex *section; + byte buffer[sizeof(Mutex)]; + + void Initialize(); + +public: + Mutex& Get() { if(!ReadWithBarrier(section)) Initialize(); return *const_cast(section); } + operator Mutex&() { return Get(); } + bool TryEnter() { return Get().TryEnter();} + void Enter() { Get().Enter();} + void Leave() { Get().Leave(); } +#ifdef flagPROFILEMT + void Set(MtInspector& mti) { Get().Set(mti); } +#endif +}; + +class StaticRWMutex { + volatile RWMutex *rw; + byte buffer[sizeof(RWMutex)]; + + void Initialize(); + +public: + RWMutex& Get() { if(!ReadWithBarrier(rw)) Initialize(); return *const_cast(rw); } + operator RWMutex&() { return Get(); } + void EnterRead() { Get().EnterRead();} + void LeaveRead() { Get().LeaveRead(); } + void EnterWrite() { Get().EnterWrite();} + void LeaveWrite() { Get().LeaveWrite(); } +}; + +#define INTERLOCKED \ +for(bool i_b_ = true; i_b_;) \ + for(static UPP::StaticMutex i_ss_; i_b_;) \ + for(UPP::Mutex::Lock i_ss_lock__(i_ss_); i_b_; i_b_ = false) + +struct H_l_ : Mutex::Lock { + bool b; + H_l_(Mutex& cs) : Mutex::Lock(cs) { b = true; } +}; + +#define INTERLOCKED_(cs) \ +for(UPP::H_l_ i_ss_lock__(cs); i_ss_lock__.b; i_ss_lock__.b = false) + +void Set__(volatile bool& b); + +#define ONCELOCK \ +for(static volatile bool o_b_; !ReadWithBarrier(o_b_);) \ + for(static StaticMutex o_ss_; !o_b_;) \ + for(Mutex::Lock o_ss_lock__(o_ss_); !o_b_; BarrierWrite(o_b_, true)) + +#define ONCELOCK_(o_b_) \ +for(static StaticMutex o_ss_; !ReadWithBarrier(o_b_);) \ + for(Mutex::Lock o_ss_lock__(o_ss_); !o_b_; BarrierWrite(o_b_, true)) + +#define ONCELOCK_PTR(ptr, init) \ +if(!ReadWithBarrier(ptr)) { \ + static StaticMutex cs; \ + cs.Enter(); \ + if(!ptr) \ + BarrierWrite(ptr, init); \ + cs.Leave(); \ +} + +#else + +#define thread__ + +#define PROFILEMT(mutex) +#define PROFILEMT_(mutex, id) + +typedef int Atomic; + +inline int AtomicRead(const volatile Atomic& t) { return t; } +inline void AtomicWrite(volatile Atomic& t, int data) { t = data; } + +inline int AtomicInc(volatile Atomic& t) { ++t; return t; } +inline int AtomicDec(volatile Atomic& t) { --t; return t; } +inline int AtomicXAdd(volatile Atomic& t, int incr) { Atomic x = t; t += incr; return x; } + +struct Mutex { + bool TryEnter() { return true; } + void Enter() {} + void Leave() {} + + struct Lock; +}; + +typedef Mutex StaticMutex; + +struct Mutex::Lock { + Lock(Mutex&) {} + ~Lock() {} +}; + +struct RWMutex { + void EnterWrite() {} + void LeaveWrite() {} + + void EnterRead() {} + void LeaveRead() {} + + struct ReadLock; + struct WriteLock; +}; + +struct RWMutex::ReadLock { + ReadLock(RWMutex&) {} + ~ReadLock() {} +}; + +struct RWMutex::WriteLock { + WriteLock(RWMutex&) {} + ~WriteLock() {} +}; + +typedef RWMutex StaticRWMutex; + +#define INTERLOCKED +#define INTERLOCKED_(x) { x.Enter(); } + +#define ONCELOCK \ +for(static bool o_b_; !o_b_; o_b_ = true) + +#define ONCELOCK_(o_b_) \ +for(; !o_b_; o_b_ = true) \ + +#define ONCELOCK_PTR(ptr, init) \ +if(!ptr) ptr = init; + +inline void ReadMemoryBarrier() {} +inline void WriteMemoryBarrier() {} + +#ifdef _DEBUG +inline void AssertST() {} +#endif + +#endif + +typedef Mutex CriticalSection; // deprecated +typedef StaticMutex StaticCriticalSection; // deprecated diff --git a/uppdev/CoreTopics/NetNode.cpp b/uppdev/CoreTopics/NetNode.cpp new file mode 100644 index 000000000..0cd6d9215 --- /dev/null +++ b/uppdev/CoreTopics/NetNode.cpp @@ -0,0 +1,108 @@ +#include "Core.h" + +#ifdef PLATFORM_WIN32 + +NAMESPACE_UPP + +NetNode::NetNode() +{ + memset(&net, 0, sizeof(NETRESOURCE)); +} + +NetNode& NetNode::operator=(const NetNode& s) +{ + net = s.net; + local = s.local; + remote = s.remote; + comment = s.comment; + provider = s.provider; + name = s.name; + path = s.path; + SetPtrs(); + return *this; +} + +String DosInitCaps(const char *name) +{ + for(const char *s = name; *s; s++) + if(IsLetter(*s) && IsLower(*s)) + return name; + return InitCaps(name); +} + +void NetNode::SetPtr(String& s, char *& ptr) +{ + if(ptr) ptr = (char *)~s; +} + +void NetNode::SetPtrs() +{ + SetPtr(local, net.lpLocalName); + SetPtr(remote, net.lpRemoteName); + SetPtr(comment, net.lpComment); + SetPtr(provider, net.lpProvider); +} + +void NetNode::Serialize(Stream& s) +{ + s % net.dwScope % net.dwType % net.dwDisplayType % net.dwUsage; + s % local % remote % comment % provider % name % path; + SetPtrs(); +} + +Array NetNode::Enum() const +{ + HANDLE hEnum; + if(::WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, (NETRESOURCE *)&net, &hEnum)) + return Array(); + return Enum0(hEnum); +} + +Array NetNode::EnumRoot() +{ + HANDLE hEnum; + if(::WNetOpenEnum(RESOURCE_CONTEXT, RESOURCETYPE_DISK, 0, NULL, &hEnum)) + return Array(); + return Enum0(hEnum); +} + +Array NetNode::Enum0(HANDLE hEnum) +{ + Array r; + DWORD cEntries = (DWORD)-1, cbBuffer = 0x4000; + Buffer lpnr(cbBuffer); + while(::WNetEnumResource(hEnum, &cEntries, lpnr, &cbBuffer) == 0) { + for(int i = 0; i < (int)cEntries; i++) { + NETRESOURCE& sn = lpnr[i]; + const char *s = sn.lpRemoteName; + NetNode& nn = r.Add(); + NETRESOURCE& n = nn.net; + n = sn; + nn.local = n.lpLocalName; + nn.remote = n.lpRemoteName; + nn.comment = n.lpComment; + nn.provider = n.lpProvider; + nn.SetPtrs(); + if(s) { + if(s[0] == '\\' && s[1] == '\\') + nn.name = FromSystemCharset(DosInitCaps(GetFileName(s))); + else + nn.name = FromSystemCharset(s); + } + if(n.lpComment && *n.lpComment) + if(nn.name.GetCount()) + nn.name = String().Cat() << FromSystemCharset(n.lpComment) + << " (" << nn.name << ")"; + else + nn.name = FromSystemCharset(n.lpComment); + if(!(n.dwUsage & RESOURCEUSAGE_CONTAINER)) + nn.path = FromSystemCharset(n.lpRemoteName); + } + } + ::WNetCloseEnum(hEnum); + return r; +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppdev/CoreTopics/OL_Set.cpp b/uppdev/CoreTopics/OL_Set.cpp new file mode 100644 index 000000000..bb3ff3b01 --- /dev/null +++ b/uppdev/CoreTopics/OL_Set.cpp @@ -0,0 +1,15 @@ +//#BLITZ_PROHIBIT + +#ifndef flagNONAMESPACE +namespace Upp { +#endif + +void Set__(volatile bool& b) +{ + //WriteMemoryBarrier should be here + b = true; +} + +#ifndef flagNONAMESPACE +}; +#endif diff --git a/uppdev/CoreTopics/Other.h b/uppdev/CoreTopics/Other.h new file mode 100644 index 000000000..0f4b999df --- /dev/null +++ b/uppdev/CoreTopics/Other.h @@ -0,0 +1,423 @@ +template +T& Single() { + static T *p; + ONCELOCK { + static T o; + p = &o; + } + return *p; +} + +template +class One : MoveableAndDeepCopyOption< One > { + mutable T *ptr; + + void Free() { if(ptr && ptr != (T*)1) delete ptr; } + void Chk() const { ASSERT(ptr != (T*)1); } + void ChkP() const { Chk(); ASSERT(ptr); } + void Pick(pick_ One& data) { T *p = data.ptr; data.ptr = (T*)1; ptr = p; } + +public: + void Attach(T *data) { Free(); ptr = data; } + T *Detach() pick_ { ChkP(); T *t = ptr; ptr = NULL; return t; } + T *operator-() pick_ { return Detach(); } + void Clear() { Free(); ptr = NULL; } + + void operator=(T *data) { Attach(data); } + void operator=(pick_ One& d) { Free(); Pick(d); } + + const T *operator->() const { ChkP(); return ptr; } + T *operator->() { ChkP(); return ptr; } + const T *operator~() const { Chk(); return ptr; } + T *operator~() { Chk(); return ptr; } + const T& operator*() const { ChkP(); return *ptr; } + T& operator*() { ChkP(); return *ptr; } + + template + TT& Create() { TT *q = new TT; Attach(q); return *q; } + T& Create() { T *q = new T; Attach(q); return *q; } + + bool IsPicked() const { return ptr == (T*)1; } + bool IsEmpty() const { Chk(); return !ptr; } + + operator bool() const { return ptr; } + + One() { ptr = NULL; } + One(T *newt) { ptr = newt; } + One(pick_ One& p) { Pick(p); } + One(const One& p, int) { ptr = p.IsEmpty() ? NULL : DeepCopyNew(*p); } + ~One() { Free(); } +}; + +class Any : Moveable { + struct BaseData { + int typeno; + + virtual ~BaseData() {} + }; + + template + struct Data : BaseData { + T data; + + Data() { typeno = StaticTypeNo(); } + }; + + BaseData *ptr; + + void Chk() const { ASSERT(ptr != (void *)1); } + void Pick(pick_ Any& s) { ptr = s.ptr; const_cast(s).ptr = (BaseData *)1; } + +public: + template T& Create() { Clear(); Data *x = new Data; ptr = x; return x->data; } + template bool Is() const { return ptr && ptr->typeno == StaticTypeNo(); } + template T& Get() { ASSERT(Is()); Chk(); return ((Data*)ptr)->data; } + template const T& Get() const { ASSERT(Is()); Chk(); return ((Data*)ptr)->data; } + + void Clear() { if(ptr) delete ptr; ptr = NULL; } + + bool IsEmpty() const { return ptr == NULL; } + bool IsPicked() const { return ptr == (void *)1; } + + void operator=(pick_ Any& s) { Clear(); Pick(s); } + Any(pick_ Any& s) { Pick(s); } + + Any() { ptr = NULL; } + ~Any() { Clear(); } +}; + +template +class Buffer : Moveable< Buffer > { + mutable T *ptr; + +public: + operator T*() { return ptr; } + operator const T*() const { return ptr; } + T *operator~() { return ptr; } + const T *operator~() const { return ptr; } + + void Alloc(int size) { Clear(); ptr = new T[size]; } + void Alloc(int size, const T& in) { Clear(); ptr = new T[size]; + Fill(ptr, ptr + size, in); } + + void Clear() { if(ptr) delete[] ptr; ptr = NULL; } + + Buffer() { ptr = NULL; } + Buffer(int size) { ptr = new T[size]; } + Buffer(int size, const T& init) { ptr = new T[size]; Fill(ptr, ptr + size, init); } + ~Buffer() { if(ptr) delete[] ptr; } + + void operator=(pick_ Buffer& v) { if(ptr) delete[] ptr; ptr = v.ptr; v.ptr = NULL; } + Buffer(pick_ Buffer& v) { ptr = v.ptr; v.ptr = NULL; } +}; + +class Bits : Moveable { + mutable int alloc; + dword *bp; + +public: + void Clear(); + void Set(int i, bool b = true); + void Set(int i, bool b, int count); + bool Get(int i) const { ASSERT(i >= 0 && alloc >= 0); int q = i >> 5; + return q < alloc ? bp[q] & (1 << (i & 31)) : false; } + bool operator[](int i) const { return Get(i); } + + Bits() { bp = NULL; alloc = 0; } + ~Bits() { Clear(); } + + Bits(pick_ Bits& b) { alloc = b.alloc; bp = b.bp; b.alloc = -1; } + void operator=(pick_ Bits& b) { Clear(); alloc = b.alloc; bp = b.bp; b.alloc = -1; } +}; + +//# System dependent +template +class Mitor : Moveable< Mitor > { + union { + mutable unsigned count; + mutable Vector *vector; + }; + byte elem0[sizeof(T)]; + + T& Get(int i) const; + void Pick(pick_ Mitor& m); + void Copy(const Mitor& m); + void Chk() const { ASSERT(count != 2); } + +public: + T& operator[](int i) { return Get(i); } + const T& operator[](int i) const { return Get(i); } + int GetCount() const; + T& Add(); + void Add(const T& x); + void Clear(); + void Shrink(); + + Mitor(pick_ Mitor& m) { Pick(m); } + void operator=(pick_ Mitor& m) { Clear(); Pick(m); } + + Mitor(Mitor& m, int) { Copy(m); } + void operator<<=(const Mitor& m) { Clear(); Copy(m); } + + Mitor() { count = 0; } + ~Mitor() { Clear(); } +}; + +template +T& Mitor::Get(int i) const +{ + ASSERT(i >= 0 && i < GetCount()); + return i == 0 ? *(T*)elem0 : (*const_cast*>(vector))[i - 1]; +} + +template +void Mitor::Pick(pick_ Mitor& m) +{ + m.Chk(); + vector = m.vector; + memcpy(&elem0, &m.elem0, sizeof(T)); + m.count = 2; +} + +template +void Mitor::Copy(const Mitor& m) +{ + m.Chk(); + if(m.count > 0) + DeepCopyConstruct((T*)elem0, m.elem0); + if(m.count > 1) + vector = new Vector(m.vector, 1); +} + +template +int Mitor::GetCount() const +{ + Chk(); + return count > 1 ? vector->GetCount() + 1 : count; +} + +template +T& Mitor::Add() +{ + Chk(); + if(count == 0) { + count = 1; + return *new(elem0) T; + } + if(count == 1) + vector = new Vector; + return vector->Add(); +} + +template +void Mitor::Add(const T& x) +{ + Chk(); + if(count == 0) { + count = 1; + new((T*) elem0) T(x); + } + else { + if(count == 1) + vector = new Vector; + vector->Add(x); + } +} + +template +void Mitor::Clear() +{ + if(count > 2) + delete vector; + if(count && count != 2) + ((T*)elem0)->T::~T(); + count = 0; +} + +template +void Mitor::Shrink() +{ + if(count > 2) + vector->Shrink(); +} + +//# +template +class Link { +protected: + T *prev[N]; + T *next[N]; + + void LPN(int i) { prev[i]->next[i] = next[i]->prev[i] = (T *)this; } + +public: + T *GetPtr() { return (T *) this; } + const T *GetPtr() const { return (const T *) this; } + T *GetNext(int i = 0) { return next[i]; } + T *GetPrev(int i = 0) { return prev[i]; } + const T *GetNext(int i = 0) const { return next[i]; } + const T *GetPrev(int i = 0) const { return prev[i]; } + + void LinkSelf(int i = 0) { next[i] = prev[i] = (T *)this; } + void LinkSelfAll() { for(int i = 0; i < N; i++) LinkSelf(i); } + void Unlink(int i = 0) { next[i]->prev[i] = prev[i]; prev[i]->next[i] = next[i]; + LinkSelf(i); } + void UnlinkAll() { for(int i = 0; i < N; i++) Unlink(i); } + void LinkBefore(Link *n, int i = 0) { next[i] = (T *)n; prev[i] = next[i]->prev[i]; LPN(i); } + void LinkAfter(Link *p, int i = 0) { prev[i] = (T *)p; next[i] = prev[i]->next[i]; LPN(i); } + + T *InsertNext(int i = 0) { T *x = new T; x->LinkAfter(this, i); return x; } + T *InsertPrev(int i = 0) { T *x = new T; x->LinkBefore(this, i); return x; } + + void DeleteList(int i = 0) { while(next[i] != GetPtr()) delete next[i]; } + + bool InList(int i = 0) const { return next[i] != GetPtr(); } + bool IsEmpty(int i = 0) const { return !InList(i); } + + Link() { LinkSelfAll(); } + ~Link() { UnlinkAll(); } + +private: + Link(const Link&); + void operator=(const Link&); + +public: +#ifdef _DEBUG + void Dump() { + for(T *t = GetNext(); t != this; t = t->GetNext()) + LOG(t); + LOG("-------------------------------------"); + } +#endif +}; + +template +class LinkOwner : public Link { +public: + ~LinkOwner() { Link::DeleteList(); } +}; + +template +struct LRUCache { + struct Maker { + virtual String Key() const = 0; + virtual int Make(T& object) const = 0; + virtual ~Maker() {} + }; + +private: + struct Item : Moveable { + int16 prev, next; + int size; + One data; + bool flag; + }; + + Index key; + Vector data; + int head; + + int size; + int count; + + int foundsize; + int newsize; + bool flag; + + + void Unlink(int i); + void LinkHead(int i); + +public: + int GetSize() const { return size; } + + void Shrink(int maxsize); + + const T& Get(const Maker& m); + + void ClearCounters(); + int GetFoundSize() const { return foundsize; } + int GetNewSize() const { return newsize; } + + LRUCache() { head = -1; size = 0; count = 0; ClearCounters(); } +}; + +template +void LRUCache::LinkHead(int i) +{ + Item& m = data[i]; + if(head >= 0) { + int tail = data[head].prev; + m.next = head; + m.prev = tail; + data[head].prev = i; + data[tail].next = i; + } + else + m.prev = m.next = i; + head = i; + count++; +} + + +template +void LRUCache::Unlink(int i) +{ + Item& m = data[i]; + if(m.prev == i) + head = -1; + else { + if(head == i) + head = m.next; + data[(int)m.next].prev = m.prev; + data[(int)m.prev].next = m.next; + } + count--; +} + +template +void LRUCache::Shrink(int maxsize) +{ + if(maxsize < 0) + return; + while((count > 30000 || size > maxsize) && head >= 0) { + int tail = data[head].prev; + size -= data[tail].size; + data[tail].data.Clear(); + Unlink(tail); + key.Unlink(tail); + } +} + +template +void LRUCache::ClearCounters() +{ + flag = !flag; + newsize = foundsize = 0; +} + +template +const T& LRUCache::Get(const Maker& m) +{ + String k = m.Key(); + k.Cat((const char *)&typeid(m), sizeof(void *)); + int q = key.Find(k); + if(q < 0) { + q = key.Put(k); + Item& t = data.At(q); + t.size = m.Make(t.data.Create()); + size += t.size; + newsize += t.size; + t.flag = flag; + } + else { + Item& t = data[q]; + Unlink(q); + if(t.flag != flag) { + t.flag = flag; + foundsize += t.size; + } + } + LinkHead(q); + return *data[q].data; +} diff --git a/uppdev/CoreTopics/Parser.h b/uppdev/CoreTopics/Parser.h new file mode 100644 index 000000000..af1d664c4 --- /dev/null +++ b/uppdev/CoreTopics/Parser.h @@ -0,0 +1,129 @@ +inline bool iscib(int c) { + return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'; +} + +inline bool iscid(int c) { + return iscib(c) || c >= '0' && c <= '9'; +} + +class CParser { +protected: + const char *term; + int line; + String fn; + bool skipspaces; + + bool Spaces0(); + bool Id0(const char *id); + void DoSpaces() { if(skipspaces) Spaces(); } + +public: + struct Error : public Exc { Error(const char *s) : Exc(s) {} }; + + void ThrowError(const char *s); + + void NoSkipSpaces() { skipspaces = false; } + void SkipSpaces() { skipspaces = true; } + + bool Spaces() { return (byte)*term <= ' ' || *term == '/' ? Spaces0() : false; } + char PeekChar() { return *term; } + char GetChar(); + + bool IsChar(char c) { return *term == c; } + bool IsChar2(char c1, char c2) { return term[0] == c1 && term[1] == c2; } + bool IsChar3(char c1, char c2, char c3) { return term[0] == c1 && term[1] == c2 && term[2] == c3; } + bool Char(char c); + bool Char2(char c1, char c2); + bool Char3(char c1, char c2, char c3); + void PassChar(char c) throw(Error); + void PassChar2(char c1, char c2) throw(Error); + void PassChar3(char c1, char c2, char c3) throw(Error); + bool Id(const char *s) { return term[0] == s[0] && (s[1] == 0 || term[1] == s[1]) && Id0(s); } + void PassId(const char *s) throw(Error); + bool IsId() { return iscib(*term); } + String ReadId() throw(Error); + String ReadIdt() throw(Error); + bool IsInt(); + int ReadInt() throw(Error); + bool IsNumber() { return IsDigit(*term); } + bool IsNumber(int base); + uint32 ReadNumber(int base = 10) throw(Error); + uint64 ReadNumber64(int base = 10) throw(Error); + bool IsDouble() { return IsInt(); } + double ReadDouble() throw(Error); + bool IsString() { return IsChar('\"'); }; + String ReadOneString(bool chkend = false) throw(Error); + String ReadString(bool chkend = false) throw(Error); + String ReadOneString(int delim, bool chkend = false) throw(Error); + String ReadString(int delim, bool chkend = false) throw(Error); + + void SkipTerm(); + + struct Pos { + const char *ptr; + int line; + String fn; + + Pos(const char *ptr = NULL, int line = 1, String fn = Null) : ptr(ptr), line(line), fn(fn) {} + }; + + const char *GetPtr() { return (const char *)term; } + + Pos GetPos(); + void SetPos(const Pos& pos); + + bool IsEof() const { return *term == '\0'; } + operator bool() const { return *term; } + + int GetLine() const { return line; } + String GetFileName() const { return fn; } + + void Set(const char *ptr, const char *fn, int line = 1); + void Set(const char *ptr); + + CParser(const char *ptr); + CParser(const char *ptr, const char *fn, int line = 1); + CParser(); +}; + +inline bool CParser::Char(char c) +{ + if(IsChar(c)) { + term++; + DoSpaces(); + return true; + } + return false; +} + +inline bool CParser::Char2(char c1, char c2) +{ + if(IsChar2(c1, c2)) { + term += 2; + DoSpaces(); + return true; + } + return false; +} + +inline bool CParser::Char3(char c1, char c2, char c3) +{ + if(IsChar3(c1, c2, c3)) { + term += 3; + DoSpaces(); + return true; + } + return false; +} + +enum { + ASCSTRING_SMART = 0x01, + ASCSTRING_OCTALHI = 0x02, +}; + +String AsCString(const char *s, const char *end, int linemax = INT_MAX, const char *linepfx = NULL, + dword flags = 0); +String AsCString(const char *s, int linemax = INT_MAX, const char *linepfx = NULL, + dword flags = 0); +String AsCString(const String& s, int linemax = INT_MAX, const char *linepfx = NULL, + dword flags = 0); diff --git a/uppdev/CoreTopics/Path.cpp b/uppdev/CoreTopics/Path.cpp new file mode 100644 index 000000000..a019c79fd --- /dev/null +++ b/uppdev/CoreTopics/Path.cpp @@ -0,0 +1,1051 @@ +#include "Core.h" +//#BLITZ_APPROVE + +#ifdef PLATFORM_POSIX +#include +#include +#endif//PLATFORM_POSIX + +#ifdef PLATFORM_WIN32 +#define DLLFILENAME "Kernel32.dll" +#define DLIMODULE UnicodeWin32 +#define DLIHEADER +#include + +#define DLLFILENAME "Mpr.dll" +#define DLIMODULE UnicodeWin32Net +#define DLIHEADER +#include +#endif + +NAMESPACE_UPP + +static int sDirSep(int c) { + return c == '/' || c == '\\' ? c : 0; +} + +static bool strecmp0(const char *p, const char *s) { + while(*p) { + if(*p == '*') { + while(*p == '*') p++; + do + if(*p == *s && strecmp0(p, s)) return true; + while(*s++); + return false; + } + if(*p == '?') { + if(*s == '\0') return false; + } + else + if(ToUpper(*p) != ToUpper(*s)) return false; + s++; + p++; + } + return *s == '\0'; +} + +bool PatternMatch(const char *p, const char *s) { + const char *q; + q = strchr(p, '.'); + if(q) { + if(q[1] == '\0') { + if(strchr(s, '.')) return false; + String h(p, q); + return strecmp0(h, s); + } + else + if(q[1] == '*' && q[2] == '\0') { + String h(p, q); + return strecmp0(h, s) || strecmp0(p, s); + } + } + return strecmp0(p, s); +} + +bool PatternMatchMulti(const char *p, const char *s) { + String pt; + while(*p) { + if(*p == ';' || *p == ',' || *p == ' ') { + if(PatternMatch(pt, s)) return true; + p++; + while(*p == ';' || *p == ',' || *p == ' ') p++; + pt.Clear(); + } + else + pt.Cat(*p++); + } + return pt.IsEmpty() ? false : PatternMatch(pt, s); +} + +const char *GetFileNamePos(const char *fileName) { + const char *s = fileName; + const char *fname = s; + char c; + while((c = *s++) != '\0') + #ifdef PLATFORM_WIN32 + if(c == '\\' || c == ':' || c == '/') + #else + if(c == '/') + #endif + fname = s; + return fname; +} + +const char *GetFileExtPos(const char *fileName) { + fileName = GetFileNamePos(fileName); + const char *ext = strrchr(fileName, '.'); + return ext ? ext : fileName + strlen(fileName); +} + +bool HasFileName(const char *fileName) { + return *GetFileNamePos(fileName); +} + +bool HasFileExt(const char *fileName) { + return *GetFileExtPos(fileName); +} + +bool HasWildcards(const char *fileName) { + return strchr(fileName, '*') || strchr(fileName, '?'); +} + +bool IsFullPath(const char *r) { +#ifdef PLATFORM_WIN32 + return *r && r[1] && (r[1] == ':' || r[0] == '\\' && r[1] == '\\' || r[0] == '/' && r[1] == '/'); +#endif +#ifdef PLATFORM_POSIX + return *r == '/'; +#endif +} + +String GetFileDirectory(const char *fileName) { + return String(fileName, (int)(GetFileNamePos(fileName) - fileName)); +} + +String GetFileFolder(const char *fileName) { + const char *s = GetFileNamePos(fileName); +#ifdef PLATFORM_WIN32 + if(s - fileName == 3 && fileName[1] == ':') + return String(fileName, 3); +#endif +#ifdef PLATFORM_POSIX + if(s - fileName == 1 && s[0] == '/') + return "/"; +#endif + if(s > fileName) + return String(fileName, (int)(s - fileName) - 1); + return Null; +} + +String GetFileTitle(const char *fileName) { + fileName = GetFileNamePos(fileName); + const char *ext = GetFileExtPos(fileName); + if(*ext) + return String(fileName, (int)(ext - fileName)); + else + return fileName; +} + +String GetFileExt(const char *fileName) { + return GetFileExtPos(fileName); +} + +String GetFileName(const char *fileName) { + return GetFileNamePos(fileName); +} + +String AppendFileName(const String& path, const char *fileName) { + String result = path; + if(result.GetLength() && *result.Last() != DIR_SEP) + result += DIR_SEP; + result += fileName; + return result; +} + +#ifdef PLATFORM_WIN32 +bool PathIsEqual(const char *p1, const char *p2) +{ + return ToLower(NormalizePath(p1)) == ToLower(NormalizePath(p2)); +} +#endif + +#ifdef PLATFORM_POSIX +bool PathIsEqual(const char *p1, const char *p2) +{ + return NormalizePath(p1) == NormalizePath(p2); +} +#endif + +int ComparePath(const char *a, const char *b, int length) { + ASSERT(length >= 0); + if(length <= 0) + return 0; +#if PLATFORM_PATH_HAS_CASE + return memcmp(a, b, length); +#else + return MemICmp(a, b, length); +#endif +} + +int ComparePath(String fa, String fb) { + int la = fa.GetLength(), lb = fb.GetLength(); + int r = ComparePath(fa, fb, min(la, lb)); + return r ? r : cmp(la, lb); +} + +#ifndef PLATFORM_WINCE +String GetCurrentDirectory() { +#if defined(PLATFORM_WIN32) + if(IsWinNT()) { + wchar h[MAX_PATH]; + UnicodeWin32().GetCurrentDirectoryW(MAX_PATH, h); + return FromSystemCharsetW(h); + } + else { + char h[MAX_PATH]; + ::GetCurrentDirectory(MAX_PATH, h); + return FromSystemCharset(h); + } +#elif defined(PLATFORM_POSIX) + char h[1024]; + getcwd(h, 1024); + return FromSystemCharset(h); +#else +#error GetCurrentDirectory not implemented for this platform, comment this line to get Null + return Null; +#endif//PLATFORM +} +#endif + +#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE) + +String GetTempPath() +{ + if(IsWinNT()) { + wchar h[MAX_PATH]; + UnicodeWin32().GetTempPathW(MAX_PATH, h); + return FromSystemCharsetW(h); + } + else { + char h[MAX_PATH]; + ::GetTempPath(MAX_PATH, h); + return FromSystemCharset(h); + } +} + +#endif + +#ifdef PLATFORM_POSIX + +String GetTempPath() +{ + return FromSystemCharset(P_tmpdir); +} + +#endif + +#ifndef PLATFORM_WINCE +String GetTempFileName(const char *prefix) { + Uuid id = Uuid::Create(); + return AppendFileName(GetTempPath(), String(prefix) + Format(id) + ".tmp"); +} +#endif + +String FromUnixName(const char* fn, const char* stop = NULL) { + String s; + char c; + while(fn != stop && (c = *fn++)) + s += (c == '/' ? '\\' : c); + return s; +} + +String ToUnixName(const char* fn, const char* stop = NULL) { + String s; + char c; + while(fn != stop && (c = *fn++)) + s += (c == '\\' ? '/' : c); + return s; +} + +#ifndef PLATFORM_WINCE +String GetFullPath(const char *file) { +#ifdef PLATFORM_WIN32 + if(IsWinNT()) { + String ufn = FromUnixName(file); + wchar h[MAX_PATH]; + UnicodeWin32().GetFullPathNameW(ToSystemCharsetW(ufn), MAX_PATH, h, 0); + return FromSystemCharsetW(h); + } + else { + String ufn = FromUnixName(file); + char h[MAX_PATH]; + GetFullPathName(ToSystemCharset(ufn), MAX_PATH, h, 0); + return FromSystemCharset(h); + } +#else + return NormalizePath(file); +#endif +} +#endif + +String GetFileOnPath(const char* file, const char* paths, bool current, const char *curdir) { + String ufn = NativePath(file); + if(IsFullPath(ufn)) + return ufn; + String fn; +#ifdef PLATFORM_WINCE + if(current && curdir && FileExists(fn = NormalizePath(ufn, curdir))) + ; +#else + String cd = curdir; + if(!curdir) + cd = GetCurrentDirectory(); + if(current && FileExists(fn = NormalizePath(ufn, cd))) + ; +#endif + else if(paths) + { + fn = Null; + while(*paths) { + const char* start = paths; +#ifdef PLATFORM_WIN32 + while(*paths && *paths != ';') + paths++; +#else + while(*paths && *paths != ';' && *paths != ':') + paths++; +#endif + String dir(start, (int)(paths - start)); + if(!dir.IsEmpty()) { +#ifdef PLATFORM_WINCE + dir = NormalizePath(AppendFileName(NativePath(dir), ufn)); +#else + dir = NormalizePath(AppendFileName(NativePath(dir), ufn), cd); +#endif + if(FileExists(dir)) { + fn = dir; + break; + } + } + if(*paths) + paths++; + } + } + return fn; +} + +String WinPath(const char *p) { + String r; + while(*p) { + r.Cat(*p == '/' ? '\\' : *p); + p++; + } + return r; +} + +String UnixPath(const char *p) { + String r; + while(*p) { + r.Cat(*p == '\\' ? '/' : *p); + p++; + } + return r; +} + +String AppendExt(const char* fn, const char* ext) { + String result = NativePath(fn); + if(!HasFileExt(fn)) + result += ext; + return result; +} + +String ForceExt(const char* fn, const char* ext) { + return NativePath(String(fn, GetFileExtPos(fn))) + ext; +} + +#ifdef PLATFORM_WIN32 + +void FindFile::Init() +{ + if(IsWinNT()) { + w = new WIN32_FIND_DATAW; + a = NULL; + } + else { + a = new WIN32_FIND_DATA; + w = NULL; + } +} + +FindFile::~FindFile() +{ + Close(); + delete a; + delete w; +} + +FindFile::FindFile() +{ + Init(); + handle = INVALID_HANDLE_VALUE; +} + +FindFile::FindFile(const char *name) { + Init(); + handle = INVALID_HANDLE_VALUE; + Search(name); +} + +bool FindFile::Search(const char *name) { + Close(); + if(w) + handle = UnicodeWin32().FindFirstFileW(ToSystemCharsetW(name), w); + else + handle = FindFirstFile(ToSystemCharset(name), a); + return handle != INVALID_HANDLE_VALUE; +} + +void FindFile::Close() { + if(handle != INVALID_HANDLE_VALUE) FindClose(handle); + handle = INVALID_HANDLE_VALUE; +} + +bool FindFile::Next() { + if(w) { + if(!UnicodeWin32().FindNextFileW(handle, w)) { + Close(); + return false; + } + } + else { + if(!FindNextFile(handle, a)) { + Close(); + return false; + } + } + return true; +} + +dword FindFile::GetAttributes() const +{ + return w ? w->dwFileAttributes : a->dwFileAttributes; +} + +String FindFile::GetName() const +{ + return w ? FromSystemCharsetW(w->cFileName) : FromSystemCharset(a->cFileName); +} + +int64 FindFile::GetLength() const +{ + if(w) + return (int64)w->nFileSizeLow | ((int64)w->nFileSizeHigh << 32); + else + return (int64)a->nFileSizeLow | ((int64)a->nFileSizeHigh << 32); +} + +FileTime FindFile::GetCreationTime() const +{ + return w ? w->ftCreationTime : a->ftCreationTime; +} + +FileTime FindFile::GetLastAccessTime() const +{ + return w ? w->ftLastAccessTime : a->ftLastAccessTime; +} + +FileTime FindFile::GetLastWriteTime() const +{ + return w ? w->ftLastWriteTime : a->ftLastWriteTime; +} + +bool FindFile::IsDirectory() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + : a->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; +} + + +bool FindFile::IsFolder() const { + if(w) + return IsDirectory() + && !(w->cFileName[0] == '.' && w->cFileName[1] == 0) + && !(w->cFileName[0] == '.' && w->cFileName[1] == '.' && w->cFileName[2] == 0); + else + return IsDirectory() + && !(a->cFileName[0] == '.' && a->cFileName[1] == 0) + && !(a->cFileName[0] == '.' && a->cFileName[1] == '.' && a->cFileName[2] == 0); +} + +bool FindFile::IsArchive() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE + : a->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE; +} + +bool FindFile::IsCompressed() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED + : a->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED; +} + +bool FindFile::IsHidden() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN + : a->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN; +} + +bool FindFile::IsReadOnly() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_READONLY + : a->dwFileAttributes & FILE_ATTRIBUTE_READONLY; +} + +bool FindFile::IsSystem() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM + : a->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM; +} + +bool FindFile::IsTemporary() const +{ + return w ? w->dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY + : a->dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY; +} + +String NormalizePath(const char *path, const char *currdir) +{ + String join_path; + if(!IsFullPath(path)) + path = join_path = AppendFileName(currdir, path); + String out; + if(*path && path[1] == ':') { + out << path[0] << ":\\"; + path += 3; + } + else + if(path[0] == '\\' && path[1] == '\\') { + out = "\\\\"; + path += 2; + } + else + if(sDirSep(*path)) { + if(*currdir) + out << *currdir << ':'; + out.Cat(DIR_SEP); + path++; + } + int outstart = out.GetLength(); + while(*path) { + if(sDirSep(*path)) { + while(sDirSep(*path)) + path++; + if(*path == '\0') + break; + if(out.IsEmpty() || *out.Last() != DIR_SEP) + out.Cat(DIR_SEP); + } + const char *b = path; + while(*path && !sDirSep(*path)) + path++; + if(path - b == 1 && *b == '.') + ; //no-op + else if(path - b == 2 && *b == '.' && b[1] == '.') { + const char *ob = ~out + outstart, *oe = out.End(); + if(oe - 1 > ob && oe[-1] == DIR_SEP) + oe--; + while(oe > ob && oe[-1] != DIR_SEP) + oe--; + out.Trim((int)(oe - out.Begin())); + } + else + out.Cat(b, (int)(path - b)); + } + return out; +} + +#endif + +#ifdef PLATFORM_POSIX + +void FindFile::Close() { + if(dir) { + closedir(dir); + dir = NULL; + } +} + +bool FindFile::IsFolder() const { + return IsDirectory() + && !(name[0] == '.' && name[1] == '\0') + && !(name[0] == '.' && name[1] == '.' && name[2] == '\0'); +} + +struct stat& FindFile::Stat() const { + if(!statis) { + statis = true; + if(file) + stat(AppendFileName(path, name), &statf); + } + return statf; +} + +bool FindFile::Next() { + if(!dir) return false; + statis = false; + for(;;) { + struct dirent *e = readdir(dir); + if(!e) { + name.Clear(); + file = false; + Close(); + return false; + } + name = FromSystemCharset(e->d_name); + if(PatternMatch(pattern, name)) { + file = true; + return true; + } + } +} + +bool FindFile::Search(const char *fn) { + Close(); + path = GetFileDirectory(fn); + statis = false; + file = false; + if(HasWildcards(fn)) { + pattern = GetFileName(fn); + dir = opendir(ToSystemCharset(path)); + return Next(); + } + else { + name = GetFileName(fn); + if(stat(ToSystemCharset(fn), &statf)) return false; + statis = true; + file = true; + return true; + } +} + +FindFile::FindFile(const char *fn) { + dir = NULL; + Search(fn); +} + +String NormalizePath(const char *path, const char *currdir) { + Vector si = Split(path, CharFilterTextTest(sDirSep)); + Vector p; + int i = 0; + String out; + if(path[0] == '~') { + out = GetHomeDirectory(); + i++; + } + else + if(sDirSep(path[0])) + out = (sDirSep(path[1]) ? "//" : "/"); + else { + out = (sDirSep(currdir[0]) && sDirSep(currdir[1]) ? "//" : "/"); + p = Split(currdir, CharFilterTextTest(sDirSep)); + } + bool quote = false; + for(; i < si.GetCount(); i++) { + String s = si[i]; + if(s != "." && !s.IsEmpty()) + if(s[0] == '.' && s[1] == '.') { + if(!p.IsEmpty()) p.Drop(); + } + else { + p.Add(s); + if(s.Find(' ') >= 0) + quote = true; + } + } + out.Cat(Join(p, DIR_SEPS)); +// if(quote) +// return '\"' + out + '\"'; +// else + return out; +} + +#endif//PLATFORM_POSIX + +bool FileExists(const char *name) { + FindFile ff(name); + return ff && ff.IsFile(); +} + +int64 GetFileLength(const char *name) { + FindFile ff(name); + return ff ? ff.GetLength() : -1; +} + +bool DirectoryExists(const char *name) { + FindFile ff(name); + return ff && ff.IsDirectory(); +} + +bool IsFolder(String path) +{ + if(IsNull(path) || *path.Last() == '\\' || *path.Last() == '/' || *path.Last() == ':') + return true; + if(path.Find('?') >= 0 || path.Find('*') >= 0) + return false; + FindFile ff(path); + return ff && ff.IsDirectory(); +} + +String NormalizePath(const char *path) { +#ifdef PLATFORM_WINCE + return NormalizePath(path, ""); +#else + return NormalizePath(path, GetCurrentDirectory()); +#endif +} + +bool FileCopy(const char *oldname, const char *newname) +{ +#if defined(PLATFORM_WIN32) + if(IsWinNT()) + return UnicodeWin32().CopyFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname), false); + else + return CopyFile(ToSystemCharset(oldname), ToSystemCharset(newname), false); +#elif defined(PLATFORM_POSIX) + FileIn fi(oldname); + if(!fi.IsOpen()) + return false; + FileOut fo(newname); + if(!fo.IsOpen()) + return false; + CopyStream(fo, fi, fi.GetLeft()); + fi.Close(); + fo.Close(); + if(fo.IsError()) + { + unlink(newname); + return false; + } + FileSetTime(newname, FileGetTime(oldname)); + return true; +#else + #error +#endif//PLATFORM +} + +bool FileMove(const char *oldname, const char *newname) +{ +#if defined(PLATFORM_WIN32) + if(IsWinNT()) + return !!UnicodeWin32().MoveFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname)); + else + return !!MoveFile(ToSystemCharset(oldname), ToSystemCharset(newname)); +#elif defined(PLATFORM_POSIX) + return !rename(ToSystemCharset(oldname), ToSystemCharset(newname)); +#else + #error +#endif//PLATFORM +} + +bool FileDelete(const char *filename) +{ +#if defined(PLATFORM_WIN32) + if(IsWinNT()) + return !!UnicodeWin32().DeleteFileW(ToSystemCharsetW(filename)); + else + return !!DeleteFile(ToSystemCharset(filename)); +#elif defined(PLATFORM_POSIX) + return !unlink(ToSystemCharset(filename)); +#else + #error +#endif//PLATFORM +} + +bool DirectoryDelete(const char *dirname) +{ +#if defined(PLATFORM_WIN32) + if(IsWinNT()) + return !!UnicodeWin32().RemoveDirectoryW(ToSystemCharsetW(dirname)); + else + return !!RemoveDirectory(ToSystemCharset(dirname)); +#elif defined(PLATFORM_POSIX) + return !rmdir(ToSystemCharset(dirname)); +#else + #error +#endif//PLATFORM +} + +#ifdef PLATFORM_WIN32 +int Compare_FileTime(const FileTime& fa, const FileTime& fb) +{ + return CompareFileTime(&fa, &fb); +} +#endif + +Time FileGetTime(const char *filename) +{ +#if defined(PLATFORM_WIN32) + HANDLE handle; + if(IsWinNT()) + handle = UnicodeWin32().CreateFileW(ToSystemCharsetW(filename), GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + else + handle = CreateFile(ToSystemCharset(filename), GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if(handle == INVALID_HANDLE_VALUE) + return Null; + FileTime ft; + bool res = GetFileTime(handle, 0, 0, &ft); + CloseHandle(handle); + return res ? Time(ft) : Time(Null); +#elif defined(PLATFORM_POSIX) + struct stat st; + if(stat(ToSystemCharset(filename), &st)) + return Null; + return Time(st.st_mtime); +#else + #error +#endif//PLATFORM +} + +bool SetFileTime(const char *filename, FileTime ft) +{ +#if defined(PLATFORM_WIN32) + HANDLE handle; + if(IsWinNT()) + handle = UnicodeWin32().CreateFileW(ToSystemCharsetW(filename), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + else + handle = CreateFile(ToSystemCharset(filename), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + if(handle == INVALID_HANDLE_VALUE) + return false; + bool res = SetFileTime(handle, 0, 0, &ft); + CloseHandle(handle); + return res; +#elif defined(PLATFORM_POSIX) + struct utimbuf ub; + ub.actime = ub.modtime = ft; + return !utime(ToSystemCharset(filename), &ub); +#else + #error +#endif//PLATFORM +} + +bool FileSetTime(const char *filename, Time time) +{ + return SetFileTime(filename, TimeToFileTime(time)); +} + +FileTime TimeToFileTime(Time time) +{ +#ifdef PLATFORM_WIN32 + SYSTEMTIME tm; + Zero(tm); + tm.wYear = time.year; + tm.wMonth = time.month; + tm.wDay = time.day; + tm.wHour = time.hour; + tm.wMinute = time.minute; + tm.wSecond = time.second; + FileTime ftl, ftg; + SystemTimeToFileTime(&tm, &ftl); + LocalFileTimeToFileTime(&ftl, &ftg); + return ftg; +#endif +#ifdef PLATFORM_POSIX + struct tm t; + t.tm_sec = time.second; + t.tm_min = time.minute; + t.tm_hour = time.hour; + t.tm_mday = time.day; + t.tm_mon = time.month - 1; + t.tm_year = time.year - 1900; + return mktime(&t); +#endif +} + +#ifdef PLATFORM_POSIX +bool DirectoryCreate(const char *path, int mode) +{ + return ::mkdir(ToSystemCharset(path), mode) == 0; +} +#else +bool DirectoryCreate(const char *path) +{ + if(IsWinNT()) + return !!UnicodeWin32().CreateDirectoryW(ToSystemCharsetW(path), 0); + else + return !!CreateDirectory(ToSystemCharset(path), 0); +} +#endif + +#ifdef PLATFORM_WIN32 +#define DIR_MIN 3 //!! wrong! what about \a\b\c ? +#endif + +#ifdef PLATFORM_POSIX +#define DIR_MIN 1 +#endif + +void RealizeDirectory(String dir) +{ + if(dir.GetLength() > DIR_MIN) { + RealizeDirectory(GetFileFolder(dir)); + if(!DirectoryExists(dir)) + DirectoryCreate(dir); + } +} + +void RealizePath(String file) +{ + RealizeDirectory(GetFileFolder(file)); +} + +bool DeleteFolderDeep(const char *dir) +{ + { + FindFile ff(AppendFileName(dir, "*.*")); + while(ff) { + String name = ff.GetName(); + String p = AppendFileName(dir, name); + if(ff.IsFile()) + FileDelete(p); + else + if(ff.IsFolder()) + DeleteFolderDeep(p); + ff.Next(); + } + } + return DirectoryDelete(dir); +} + +FileSystemInfo::FileInfo::FileInfo() +: length(Null), read_only(false), is_directory(false) + , is_folder(false), is_file(false), is_symlink(false), is_archive(false) + , is_compressed(false), is_hidden(false), is_read_only(false), is_system(false) + , is_temporary(false), root_style(ROOT_NO_ROOT_DIR) +{} + +GLOBAL_VAR(FileSystemInfo, StdFileSystemInfo) + +int FileSystemInfo::GetStyle() const +{ +#ifdef PLATFORM_WIN32 + return STYLE_WIN32; +#endif +#ifdef PLATFORM_POSIX + return STYLE_POSIX; +#endif +} + +Array FileSystemInfo::Find(String mask, int max_count) const +{ + Array fi; + if(IsNull(mask)) + { // root +#ifdef PLATFORM_WINCE + FileInfo& f = fi.Add(); + f.filename = "\\"; + f.root_style = ROOT_FIXED; +#elif defined(PLATFORM_WIN32) + char drive[4] = "?:\\"; + for(int c = 'A'; c <= 'Z'; c++) { + *drive = c; + int n = GetDriveType(drive); + if(n == DRIVE_NO_ROOT_DIR/* || IsWin32() && *drive == 'B'*/) continue; + FileInfo& f = fi.Add(); + f.filename = drive; + char name[256], system[256]; + DWORD d; + if(c != 'A' && c != 'B' && n != DRIVE_REMOTE && n != DRIVE_UNKNOWN) { + bool b = GetVolumeInformation(drive, name, 256, &d, &d, &d, system, 256); + if(b) { + if(*name) f.root_desc << " " << FromSystemCharset(name); + if(*system) f.root_desc << " [ " << FromSystemCharset(system) << " ]"; + } + else + if(n == DRIVE_REMOVABLE) { + fi.Drop(); + continue; + } + } + switch(n) + { + default: + case DRIVE_UNKNOWN: f.root_style = ROOT_UNKNOWN; break; + case DRIVE_NO_ROOT_DIR: f.root_style = ROOT_NO_ROOT_DIR; break; + case DRIVE_REMOVABLE: f.root_style = ROOT_REMOVABLE; break; + case DRIVE_FIXED: f.root_style = ROOT_FIXED; break; + case DRIVE_REMOTE: f.root_style = ROOT_REMOTE; break; + case DRIVE_CDROM: f.root_style = ROOT_CDROM; break; + case DRIVE_RAMDISK: f.root_style = ROOT_RAMDISK; break; + } + } +#elif defined(PLATFORM_POSIX) + FileInfo& f = fi.Add(); + f.filename = "/"; + f.root_style = ROOT_FIXED; +#endif + } + else + { + FindFile ff; + if(ff.Search(mask)) + do + { + FileInfo& f = fi.Add(); + f.filename = ff.GetName(); +#ifndef PLATFORM_POSIX + f.is_archive = ff.IsArchive(); + f.is_compressed = ff.IsCompressed(); + f.is_hidden = ff.IsHidden(); + f.is_system = ff.IsSystem(); + f.is_temporary = ff.IsTemporary(); +#endif + f.is_read_only = ff.IsReadOnly(); + f.length = ff.GetLength(); +#ifdef PLATFORM_POSIX + f.creation_time = ff.GetLastChangeTime(); + f.unix_mode = ff.GetMode(); +#endif + f.last_access_time = ff.GetLastAccessTime(); + f.last_write_time = ff.GetLastWriteTime(); +#ifdef PLATFORM_WIN32 + f.creation_time = ff.GetCreationTime(); + f.unix_mode = 0; +#endif + f.read_only = ff.IsReadOnly(); + f.is_directory = ff.IsDirectory(); + f.is_folder = ff.IsFolder(); + f.is_file = ff.IsFile(); +#ifdef PLATFORM_POSIX + f.is_symlink = ff.IsSymLink(); +#endif + } + while(ff.Next() && fi.GetCount() < max_count); + } + return fi; +} + +bool FileSystemInfo::CreateFolder(String path, String& error) const +{ + if(UPP::DirectoryCreate(path)) + return true; + error = GetErrorMessage(GetLastError()); + return false; +} + +bool FileSystemInfo::FolderExists(String path) const +{ + if(IsNull(path)) + return true; + if(path.Find('*') >= 0 || path.Find('?') >= 0) + return false; + Array fi = Find(path, 1); + return !fi.IsEmpty() && fi[0].is_directory; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Path.h b/uppdev/CoreTopics/Path.h new file mode 100644 index 000000000..3a73f361f --- /dev/null +++ b/uppdev/CoreTopics/Path.h @@ -0,0 +1,295 @@ + +bool PatternMatch(const char *p, const char *s); +bool PatternMatchMulti(const char *p, const char *s); + +const char *GetFileNamePos(const char *fileName); +const char *GetFileExtPos(const char *fileName); + +bool HasFileName(const char *fp); +bool HasFileExt(const char *fp); +bool HasWildcards(const char *fp); +bool IsFullPath(const char *fp); + +String GetFileDirectory(const char *fp); // with DIR_SEP at the end +String GetFileFolder(const char *fileName); // without DIR_SEP at the end, if not Win32 root +String GetFileTitle(const char *fp); +String GetFileExt(const char *fp); +String GetFileName(const char *fp); + +String AppendFileName(const String& path, const char *fp); + +bool PathIsEqual(const char *p1, const char *p2); + +int ComparePath(const char *a, const char *b, int length); +int ComparePath(String fa, String fb); + +inline bool LessPath(String fa, String fb) { return ComparePath(fa, fb) < 0; } + +String WinPath(const char *path); +String UnixPath(const char *path); + +#ifdef PLATFORM_WIN32 +inline String NativePath(const char *path) { return WinPath(path); } +#endif + +#ifdef PLATFORM_POSIX +inline String NativePath(const char *path) { return UnixPath(path); } +#endif + +String AppendExt(const char *fn, const char *ext); +String ForceExt(const char *fn, const char *ext); + +String GetFileOnPath(const char *file, const char *paths, bool current = true, const char *curdir = NULL); + +#ifndef PLATFORM_WINCE +String GetFullPath(const char *path); +String GetCurrentDirectory(); +#endif + +struct FileTime; + +int Compare_FileTime(const FileTime& fa, const FileTime& fb); + +#ifdef PLATFORM_WIN32 + +struct FileTime : FILETIME, CompareRelOps { + FileTime() {} + FileTime(const FILETIME& ft) { dwLowDateTime = ft.dwLowDateTime; + dwHighDateTime = ft.dwHighDateTime; } +}; + +class FindFile { + WIN32_FIND_DATA *a; + WIN32_FIND_DATAW *w; + HANDLE handle; + + void Init(); + +public: + bool Search(const char *name); + bool Next(); + void Close(); + + dword GetAttributes() const; + String GetName() const; + int64 GetLength() const; + FileTime GetCreationTime() const; + FileTime GetLastAccessTime() const; + FileTime GetLastWriteTime() const; + + bool IsDirectory() const; + bool IsFolder() const; + bool IsFile() const { return !IsDirectory(); } + + bool IsArchive() const; + bool IsCompressed() const; + bool IsHidden() const; + bool IsReadOnly() const; + bool IsSystem() const; + bool IsTemporary() const; + + operator bool() const { return handle != INVALID_HANDLE_VALUE; } + + FindFile(); + FindFile(const char *name); + ~FindFile(); +}; + +#endif + +#ifdef PLATFORM_POSIX + +struct FileTime : CompareRelOps +{ + FileTime() {} + FileTime(time_t ft) : ft(ft) {} + + operator time_t () const { return ft; } + + time_t ft; +}; + +inline int Compare_FileTime(const FileTime& f, const FileTime& g) { return f.ft < g.ft ? -1 : f.ft > g.ft ? 1 : 0; } + +class FindFile { + bool file; + DIR *dir; + mutable bool statis; + mutable struct stat statf; + String path; + String name; + String pattern; + + struct stat &Stat() const; + +public: + bool Search(const char *name); + bool Next(); + void Close(); + + dword GetMode() const { return Stat().st_mode; } + String GetName() const { return name; } + int64 GetLength() const { return Stat().st_size; } + FileTime GetLastChangeTime() const { return Stat().st_ctime; } + FileTime GetLastAccessTime() const { return Stat().st_atime; } + FileTime GetLastWriteTime() const { return Stat().st_mtime; } + + bool IsReadOnly() const { return !(GetMode() & (S_IWUSR|S_IWGRP|S_IWOTH)); } + + bool IsDirectory() const { return S_ISDIR(GetMode()); } + bool IsFolder() const; + + bool IsFile() const { return S_ISREG(GetMode()); } + bool IsSymLink() const { return S_ISLNK(GetMode()); } + + operator bool() const { return file; } + + FindFile() { file = false; dir = NULL; } + FindFile(const char *name); + ~FindFile() { Close(); } +}; + +// POSIX FileTime is unfortunately long int and clashes with Date::operator int() +inline bool operator==(Time a, FileTime b) { return a == Time(b); } +inline bool operator!=(Time a, FileTime b) { return a != Time(b); } + +inline bool operator==(FileTime a, Time b) { return Time(a) == b; } +inline bool operator!=(FileTime a, Time b) { return Time(a) != b; } + +#endif + +int64 GetFileLength(const char *name); +bool FileExists(const char *name); +bool IsFolder(String path); + +String NormalizePath(const char *path); +String NormalizePath(const char *path, const char *currdir); + +bool FileCopy(const char *oldname, const char *newname); +bool FileMove(const char *oldname, const char *newname); +bool FileDelete(const char *filename); + +bool DirectoryExists(const char *name); +#ifdef PLATFORM_POSIX +bool DirectoryCreate(const char *dirname, int mode = 0755); +#else +bool DirectoryCreate(const char *dirname); +#endif +bool DirectoryDelete(const char *dirname); +void RealizeDirectory(String dir); +void RealizePath(String file); + +struct Time; +Time FileGetTime(const char *filename); +bool SetFileTime(const char *filename, FileTime ft); +bool FileSetTime(const char *filename, Time time); +FileTime TimeToFileTime(Time time); + +#ifdef PLATFORM_POSIX +inline bool DeleteFile(const char *fn) { return unlink(fn) == 0; } +#endif + +bool DeleteFolderDeep(const char *dir); + +#ifndef PLATFORM_WINCE +String GetTempPath(); +String GetTempFileName(const char *prefix = NULL); +#endif + +template +class Array; + +class FileSystemInfo { +public: + enum + { + ROOT_UNKNOWN = 0, + ROOT_NO_ROOT_DIR = 1, + ROOT_REMOVABLE = 2, + ROOT_FIXED = 3, + ROOT_REMOTE = 4, + ROOT_CDROM = 5, + ROOT_RAMDISK = 6, + ROOT_NETWORK = 7, + ROOT_COMPUTER = 8, + }; + + enum + { + STYLE_WIN32 = 0x0001, + STYLE_POSIX = 0x0002, + }; + + struct FileInfo + { + FileInfo(); + + operator bool () const { return !IsNull(filename); } + + String filename; + String msdos_name; + String root_desc; + int64 length; + Time last_access_time; + Time last_write_time; + Time creation_time; + bool read_only; + bool is_directory; + bool is_folder; + bool is_file; + bool is_symlink; + bool is_archive; + bool is_compressed; + bool is_hidden; + bool is_read_only; + bool is_system; + bool is_temporary; + char root_style; + dword unix_mode; + }; + + virtual int GetStyle() const; + bool IsWin32() const { return GetStyle() & STYLE_WIN32; } + bool IsPosix() const { return GetStyle() & STYLE_POSIX; } + + virtual Array Find(String mask, int max_count = 1000000) const; // mask = Null -> root + virtual bool CreateFolder(String path, String& error) const; + + bool FolderExists(String path) const; + + virtual ~FileSystemInfo() {} +}; + +FileSystemInfo& StdFileSystemInfo(); + +#ifdef PLATFORM_WIN32 + +class NetNode : Moveable { + NETRESOURCE net; + String local, remote, comment, provider; + + String name; + String path; + + static void Copy(String& t, char *s); + static Array Enum0(HANDLE hEnum); + static void SetPtr(String& s, char *& ptr); + + void SetPtrs(); + +public: + String GetName() const { return name; } + String GetPath() const { return path; } + Array Enum() const; + + void Serialize(Stream& s); + + static Array EnumRoot(); + + NetNode(); + NetNode(const NetNode& s) { *this = s; } + + NetNode& operator=(const NetNode& s); +}; + +#endif diff --git a/uppdev/CoreTopics/Profile.h b/uppdev/CoreTopics/Profile.h new file mode 100644 index 000000000..00f66df8a --- /dev/null +++ b/uppdev/CoreTopics/Profile.h @@ -0,0 +1,64 @@ +class String; + +class TimingInspector { +protected: + static bool active; + + const char *name; + int call_count; + dword total_time; + dword min_time; + dword max_time; + int nesting_depth; + int max_nesting; + int all_count; + dword start_time; + StaticMutex mutex; + +public: + TimingInspector(const char *name = NULL); // Not String !!! + ~TimingInspector(); + + void Start(); + void End(); + + String Dump(); + + class Routine { + public: + Routine(TimingInspector& stat) : stat(stat) { stat.Start(); } + ~Routine() { stat.End(); } + + protected: + TimingInspector& stat; + }; + + static void Activate(bool b) { active = b; } +}; + +class HitCountInspector +{ +public: + HitCountInspector(const char *name, int hitcount = 0) : name(name), hitcount(hitcount) {} + ~HitCountInspector(); + + void Step() { Mutex::Lock __(mutex); hitcount++; } + void Add(int i) { Mutex::Lock __(mutex); hitcount += i; } + void operator ++ () { Step(); } + void operator += (int i) { Add(i); } + +private: + const char *name; + int hitcount; + Mutex mutex; +}; + +#define RTIMING(x) \ + static TimingInspector COMBINE(sTmStat, __LINE__)(x); \ + TimingInspector::Routine COMBINE(sTmStatR, __LINE__)(COMBINE(sTmStat, __LINE__)); + +#define RACTIVATE_TIMING() TimingInspector::Activate(true); +#define RDEACTIVATE_TIMING() TimingInspector::Activate(false); + +#define RHITCOUNT(n) \ + { static HitCountInspector hitcount(n); hitcount.Step(); } diff --git a/uppdev/CoreTopics/Ptr.cpp b/uppdev/CoreTopics/Ptr.cpp new file mode 100644 index 000000000..21c4e2e9d --- /dev/null +++ b/uppdev/CoreTopics/Ptr.cpp @@ -0,0 +1,87 @@ +#include "Core.h" + +NAMESPACE_UPP + +/* Faster, but consuming more memory.... +PteBase::Prec *PteBase::PtrAdd() +{ + AtomicInc(prec->n); + return prec; +} + +void PteBase::PtrRelease(Prec *prec) +{ + if(prec && AtomicDec(prec->n) == 0) + delete prec; +} + +PteBase::PteBase() +{ + prec = new Prec; + prec->n = 1; + prec->ptr = this; +} +*/ + +static StaticCriticalSection sPteLock; + +PteBase::Prec *PteBase::PtrAdd() +{ + sPteLock.Enter(); + if(prec) { + ++prec->n; + sPteLock.Leave(); + } + else { + sPteLock.Leave(); + prec = new Prec; + prec->n = 1; + prec->ptr = this; + } + return const_cast(prec); +} + +void PteBase::PtrRelease(Prec *prec) +{ + CriticalSection::Lock __(sPteLock); + if(prec && --prec->n == 0) { + if(prec->ptr) + prec->ptr->prec = NULL; + delete prec; + } +} + +PteBase::PteBase() +{ + prec = NULL; +} + +PteBase::~PteBase() +{ + CriticalSection::Lock __(sPteLock); + if(prec) + prec->ptr = NULL; +} + +void PtrBase::Release() +{ + PteBase::PtrRelease(prec); +} + +void PtrBase::Set(PteBase *p) +{ + prec = p ? p->PtrAdd() : NULL; +} + +void PtrBase::Assign(PteBase *p) +{ + Release(); + Set(p); +} + +PtrBase::~PtrBase() +{ + Release(); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Ptr.h b/uppdev/CoreTopics/Ptr.h new file mode 100644 index 000000000..4d0fd3e5d --- /dev/null +++ b/uppdev/CoreTopics/Ptr.h @@ -0,0 +1,75 @@ +template class Ptr; + +class PteBase { +protected: + struct Prec { + PteBase *ptr; + Atomic n; + }; + + volatile Prec *prec; + + Prec *PtrAdd(); + static void PtrRelease(Prec *prec); + static Prec *PtrAdd(const Uuid& uuid); + + PteBase(); + ~PteBase(); + + friend class PtrBase; +}; + +class PtrBase { +protected: + PteBase::Prec *prec; + void Set(PteBase *p); + void Release(); + void Assign(PteBase *p); + +public: + ~PtrBase(); +}; + +template +class Pte : public PteBase { + friend class Ptr; +}; + +template +class Ptr : public PtrBase, Moveable< Ptr > { + T *Get() const { return prec ? static_cast(prec->ptr) : NULL; } + +public: + T *operator->() const { return Get(); } + T *operator~() const { return Get(); } + operator T*() const { return Get(); } + + Ptr& operator=(T *ptr) { Assign(ptr); return *this; } + Ptr& operator=(const Ptr& ptr) { Assign(ptr.Get()); return *this; } + + Ptr() { prec = NULL; } + Ptr(T *ptr) { Set(ptr); } + Ptr(const Ptr& ptr) { Set(ptr.Get()); } + + String ToString() const; + + friend bool operator==(const Ptr& a, const T *b) { return a.Get() == b; } + friend bool operator==(const T *a, const Ptr& b) { return a == b.Get(); } + friend bool operator==(const Ptr& a, const Ptr& b) { return a.prec == b.prec; } + + friend bool operator==(const Ptr& a, T *b) { return a.Get() == b; } + friend bool operator==(T *a, const Ptr& b) { return a == b.Get(); } + + friend bool operator!=(const Ptr& a, const T *b) { return a.Get() != b; } + friend bool operator!=(const T *a, const Ptr& b) { return a != b.Get(); } + friend bool operator!=(const Ptr& a, const Ptr& b) { return a.prec != b.prec; } + + friend bool operator!=(const Ptr& a, T *b) { return a.Get() != b; } + friend bool operator!=(T *a, const Ptr& b) { return a != b.Get(); } +}; + +template +String Ptr::ToString() const +{ + return prec ? FormatPtr(Get()) : String("0x0"); +} diff --git a/uppdev/CoreTopics/StrUtil.cpp b/uppdev/CoreTopics/StrUtil.cpp new file mode 100644 index 000000000..d21c98f01 --- /dev/null +++ b/uppdev/CoreTopics/StrUtil.cpp @@ -0,0 +1,107 @@ +#include + +NAMESPACE_UPP + +int wstrlen(const wchar *s) +{ + const wchar *q = s; + while(*q) q++; + return (int)(q - s); +} + +unsigned ctoi(int c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'A' && c <= 'Z') + return c - 'A' + 10; + if(c >= 'a' && c <= 'z') + return c - 'a' + 10; + return (unsigned)-1; +} + +int CharFilterAscii(int c) +{ + return c >= 32 && c < 256 ? c : 0; +} + +int CharFilterAscii128(int c) +{ + return c >= 32 && c < 128 ? c : 0; +} + +int CharFilterUnicode(int c) +{ + return c >= 32 && c < 65536 ? c : 0; +} + +int CharFilterDigit(int c) +{ + return IsDigit(c) ? c : 0; +} + +int CharFilterInt(int c) +{ + if(c == '+' || c == '-') return c; + return CharFilterDigit(c); +} + +int CharFilterDouble(int c) +{ + if(c == ',' || c == '.') return '.'; + if(c == 'e' || c == 'E') return 'E'; + return CharFilterInt(c); +} + +int CharFilterWhitespace(int c) +{ + return IsSpace(c) ? c : 0; +} + +int CharFilterAlpha(int c) +{ + return IsAlpha(c) ? c : 0; +} + +int CharFilterAlphaToUpper(int c) +{ + return IsAlpha(c) ? IsUpper(c) ? c : ToUpper(c) : 0; +} + +int CharFilterAlphaToLower(int c) +{ + return IsAlpha(c) ? IsLower(c) ? c : ToLower(c) : 0; +} + +int CharFilterDefaultToUpperAscii(int c) +{ + return ToUpper(ToAscii(c, CHARSET_DEFAULT)); +} + +int CharFilterCrLf(int c) +{ + return c == '\r' || c == '\n' ? c : 0; +} + +String Filter(const char *s, int (*filter)(int)) +{ + String result; + while(*s) { + int c = (*filter)((byte)*s++); + if(c) result.Cat(c); + } + return result; +} + +String FilterWhile(const char *s, int (*filter)(int)) +{ + String result; + while(*s) { + int c = (*filter)((byte)*s++); + if(!c) break; + result.Cat(c); + } + return result; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Stream.cpp b/uppdev/CoreTopics/Stream.cpp new file mode 100644 index 000000000..0a0a9a480 --- /dev/null +++ b/uppdev/CoreTopics/Stream.cpp @@ -0,0 +1,1652 @@ +#include "Core.h" + +#ifdef PLATFORM_POSIX +#include +#endif + +NAMESPACE_UPP + +#define LLOG(x) // RLOG(x) +#define LDUMP(x) // RDUMP(x) +#define LLOGHEXDUMP(x, y) // RLOGHEXDUMP(x, y) + +void Stream::_Put(const void *data, dword size) { + const byte *s = (const byte *) data; + while(size--) + Put(*s++); +} + +dword Stream::_Get(void *data, dword size) { + int c; + byte *s = (byte *) data; + dword sz; + for(sz = 0; sz < size && (c = Get()) >= 0; sz++) + *s++ = c; + return sz; +} + +void Stream::_Put(int w) { + SetError(ERROR_NOT_ENOUGH_SPACE); +} + +int Stream::_Get() { + return -1; +} + +int Stream::_Term() { + return -1; +} + +void Stream::Seek(int64) { + NEVER(); +} + +int64 Stream::GetSize() const { + return 0; +} + +void Stream::SetSize(int64) { + NEVER(); +} + +bool Stream::IsOpen() const { return false; } + +void Stream::Close() {} + +void Stream::Flush() {} + +Stream::Stream() { + pos = style = 0; + buffer = NULL; + ptr = rdlim = wrlim = NULL; +} + +Stream::~Stream() {} + +bool Stream::_IsEof() const +{ + return GetPos() >= GetSize(); +} + +void Stream::LoadError() { + SetError(ERROR_LOADING_FAILED); + if(style & STRM_THROW) + throw LoadingError(); +} + +bool Stream::GetAll(void *data, dword size) { + if(Get(data, size) != size) { + LoadError(); + return false; + } + return true; +} + +String Stream::Get(dword size) +{ + StringBuffer b(size); + int n = Get(~b, size); + b.SetCount(n); + String s = b; + s.Trim(n); + return s; +} + +int Stream::_Get8() +{ + int c = Get(); + if(c < 0) { + LoadError(); + return -1; + } + return c; +} + +int Stream::_Get16() { + word w; + return GetAll(&w, 2) ? w : -1; +} + +int Stream::_Get32() { + int l; + return GetAll(&l, 4) ? l : -1; +} + +int64 Stream::_Get64() { + int64 l; + return GetAll(&l, 8) ? l : -1; +} + +#ifdef CPU_LE +int Stream::Get16be() { + byte h[2]; + int q; + h[1] = Get(); + h[0] = q = Get(); + if(q < 0) { + LoadError(); + return -1; + } + return *(word *)h; +} + +int Stream::Get32be() { + byte h[4]; + int q; + h[3] = Get(); + h[2] = Get(); + h[1] = Get(); + h[0] = q = Get(); + if(q < 0) { + LoadError(); + return -1; + } + return *(int32 *)h; +} + +int64 Stream::Get64be() { + byte h[8]; + int q; + h[7] = Get(); + h[6] = Get(); + h[5] = Get(); + h[4] = Get(); + h[3] = Get(); + h[2] = Get(); + h[1] = Get(); + h[0] = q = Get(); + if(q < 0) { + LoadError(); + return -1; + } + return *(int64 *)h; +} +#else +int Stream::Get16le() { + byte h[2]; + int q; + h[0] = Get(); + h[1] = q = Get(); + return q < 0 ? -1 : *(word *)h; +} + +int Stream::Get32le() { + byte h[4]; + int q; + h[0] = Get(); + h[1] = Get(); + h[2] = Get(); + h[3] = q = Get(); + return q < 0 ? -1 : *(int32 *)h; +} + +int64 Stream::Get64le() { + byte h[8]; + int q; + h[0] = Get(); + h[1] = Get(); + h[2] = Get(); + h[3] = Get(); + h[4] = Get(); + h[5] = Get(); + h[6] = Get(); + h[7] = q = Get(); + return q < 0 ? -1 : *(int64 *)h; +} +#endif + +int Stream::GetUtf8() +{ + int code = Get(); + if(code <= 0) { + LoadError(); + return -1; + } + if(code < 0x80) + return code; + else + if(code < 0xC2) + return -1; + else + if(code < 0xE0) { + if(IsEof()) { + LoadError(); + return -1; + } + return ((code - 0xC0) << 6) + Get() - 0x80; + } + else + if(code < 0xF0) { + int c0 = Get(); + int c1 = Get(); + if(c1 < 0) { + LoadError(); + return -1; + } + return ((code - 0xE0) << 12) + ((c0 - 0x80) << 6) + c1 - 0x80; + } + else + if(code < 0xF8) { + int c0 = Get(); + int c1 = Get(); + int c2 = Get(); + if(c2 < 0) { + LoadError(); + return -1; + } + return ((code - 0xf0) << 18) + ((c0 - 0x80) << 12) + ((c1 - 0x80) << 6) + c2 - 0x80; + } + else + if(code < 0xFC) { + int c0 = Get(); + int c1 = Get(); + int c2 = Get(); + int c3 = Get(); + if(c3 < 0) { + LoadError(); + return -1; + } + return ((code - 0xF8) << 24) + ((c0 - 0x80) << 18) + ((c1 - 0x80) << 12) + + ((c2 - 0x80) << 6) + c3 - 0x80; + } + else + if(code < 0xFE) { + int c0 = Get(); + int c1 = Get(); + int c2 = Get(); + int c3 = Get(); + int c4 = Get(); + if(c4 < 0) { + LoadError(); + return -1; + } + return ((code - 0xFC) << 30) + ((c0 - 0x80) << 24) + ((c1 - 0x80) << 18) + + ((c2 - 0x80) << 12) + ((c3 - 0x80) << 6) + c4 - 0x80; + + } + else { + LoadError(); + return -1; + } +} + +String Stream::GetLine() { + byte *q = ptr; + while(q < rdlim) + if(*q == '\n') { + String result((const char *)ptr, (int)(uintptr_t)(q - ptr - (q > ptr && q[-1] == '\r'))); + ptr = q + 1; + return result; + } + else + q++; + String result((const char *)ptr, (int)(uintptr_t)(q - ptr)); + ptr = q; + for(;;) { + byte *q = ptr; + while(q < rdlim && *q != '\n') + q++; + result.Cat(ptr, (int)(uintptr_t)(q - ptr)); + ptr = q; + int c = Get(); + if(c == '\n') + break; + if(c < 0) { + if(result.GetCount() == 0) + return String::GetVoid(); + break; + } + result.Cat(c); + } + if(*result.Last() == '\r') + result.Trim(result.GetLength() - 1); + return result; +} + +#ifdef CPU_LE +void Stream::Put16be(word q) { + byte *h = (byte *) &q; + Put(h[1]); + Put(h[0]); +} + +void Stream::Put32be(dword q) { + byte *h = (byte *) &q; + Put(h[3]); + Put(h[2]); + Put(h[1]); + Put(h[0]); +} + +void Stream::Put64be(int64 q) { + byte *h = (byte *) &q; + Put(h[7]); + Put(h[6]); + Put(h[5]); + Put(h[4]); + Put(h[3]); + Put(h[2]); + Put(h[1]); + Put(h[0]); +} +#else +void Stream::Put16le(word q) { + byte *h = (byte *) &q; + Put(h[0]); + Put(h[1]); +} + +void Stream::Put32le(dword q) { + byte *h = (byte *) &q; + Put(h[0]); + Put(h[1]); + Put(h[2]); + Put(h[3]); +} + +void Stream::Put64le(int64 q) { + byte *h = (byte *) &q; + Put(h[0]); + Put(h[1]); + Put(h[2]); + Put(h[3]); + Put(h[4]); + Put(h[5]); + Put(h[6]); + Put(h[7]); +} +#endif + +void Stream::PutUtf8(int c) +{ + word code = c; + if(code < 0x80) + Put(code); + else + if(code < 0x800) { + Put(0xc0 | (code >> 6)); + Put(0x80 | (code & 0x3f)); + } + else + if((code & 0xFF00) == 0xEE00) + Put(code); + else { + Put(0xe0 | (code >> 12)); + Put(0x80 | ((code >> 6) & 0x3f)); + Put(0x80 | (code & 0x3f)); + } +} + +void Stream::Put(const char *s) +{ + while(*s) Put(*s++); +} + +void Stream::Put(int c, int count) { + + while(count) { + int n = min(count, (int)(intptr_t)(wrlim - ptr)); + if(n > 0) { + memset(ptr, c, n); + ptr += n; + count -= n; + } + else { + Put(c); + count--; + } + } +} + +void Stream::PutLine(const char *s) { + Put(s); + PutEol(); +} + +void Stream::PutLine(const String& s) { + Put(s); + PutEol(); +} + +void Stream::Put(Stream& s, int64 size, dword click) { + Buffer buffer(click); + while(size) { + dword n = s.Get(buffer, (int)min(click, size)); + Put(buffer.operator const byte *(), click); + size -= n; + } +} + +void Stream::SerializeRLE(byte *data, dword size) +{ + if(IsError()) return; + byte *s = (byte *)data; + byte *lim = s + size; + if(IsLoading()) + while(s != lim) { + if(IsEof() || s > lim) { + LoadError(); + return; + } + byte c = Get(); + if(c == 0xcb) { + c = Get(); + int n = Get(); + if(s + n > lim) { + LoadError(); + return; + } + memset(s, c, n); + s += n; + } + else + *s++ = c; + } + else + while(s < lim) { + byte c = *s; + byte *t = s + 1; + byte *lm = min(s + 250, lim); + while(*t == c && t < lm) + t++; + if(t >= s + 3 || c == 0xcb) { + Put(0xcb); + Put(c); + Put(byte(t - s)); + } + else { + Put(*s); + + if(t == s + 2) + Put(*s); + } + if(IsError()) break; + s = t; + } +} + +void Stream::SerializeRaw(byte *data, dword size) { + if(IsError()) return; + if(IsLoading()) + GetAll(data, size); + else + Put(data, size); +} + +void Stream::SerializeRaw(word *data, dword count) { +#ifdef CPU_BE + EndianSwap(data, count); +#endif + SerializeRaw((byte *)data, 2 * count); +#ifdef CPU_BE + EndianSwap(data, count); +#endif +} + +void Stream::SerializeRaw(dword *data, dword count) { +#ifdef CPU_BE + EndianSwap(data, count); +#endif + SerializeRaw((byte *)data, 4 * count); +#ifdef CPU_BE + EndianSwap(data, count); +#endif +} + +void Stream::SerializeRaw(uint64 *data, dword count) { +#ifdef CPU_BE + EndianSwap(data, count); +#endif + SerializeRaw((byte *)data, 8 * count); +#ifdef CPU_BE + EndianSwap(data, count); +#endif +} + +void Stream::Pack(dword& w) { + if(IsError()) return; + if(IsLoading()) { + int q = Get(); + if(q < 0) + LoadError(); + else { + if(q != 255) + w = q; + else + SerializeRaw(&w, 1); + } + } + else { + if(w < 255) + Put(w); + else { + Put(255); + SerializeRaw(&w, 1); + } + } +} + +void Stream::Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f, bool& g, bool& h) { + if(IsError()) return; + if(IsLoading()) { + int f = Get(); + if(f < 0) LoadError(); + else { + a = !!(f & 0x80); + b = !!(f & 0x40); + c = !!(f & 0x20); + d = !!(f & 0x10); + e = !!(f & 0x08); + f = !!(f & 0x04); + g = !!(f & 0x02); + h = !!(f & 0x01); + } + } + else { + int f = 0; + if(a) f |= 0x80; + if(b) f |= 0x40; + if(c) f |= 0x20; + if(d) f |= 0x10; + if(e) f |= 0x08; + if(f) f |= 0x04; + if(g) f |= 0x02; + if(h) f |= 0x01; + Put(f); + } +} + +void Stream::Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f, bool& g) { + bool h = false; Pack(a, b, c, d, e, f, g, h); +} + +void Stream::Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f) { + bool h = false; Pack(a, b, c, d, e, f, h, h); +} + +void Stream::Pack(bool& a, bool& b, bool& c, bool& d, bool& e) { + bool h = false; Pack(a, b, c, d, e, h, h, h); +} + +void Stream::Pack(bool& a, bool& b, bool& c, bool& d) { + bool h = false; Pack(a, b, c, d, h, h, h, h); +} + +void Stream::Pack(bool& a, bool& b, bool& c) { + bool h = false; Pack(a, b, c, h, h, h, h, h); +} + +void Stream::Pack(bool& a, bool& b) { + bool h = false; Pack(a, b, h, h, h, h, h, h); +} + +#if 1 +Stream& Stream::operator%(bool& d) +{ + SerializeRaw((byte *)&d, 1); + return *this; +} + +Stream& Stream::operator%(char& d) +{ + SerializeRaw((byte *)&d, 1); + return *this; +} + +Stream& Stream::operator%(signed char& d) +{ + SerializeRaw((byte *)&d, 1); + return *this; +} + +Stream& Stream::operator%(unsigned char& d) +{ + SerializeRaw((byte *)&d, 1); + return *this; +} + +Stream& Stream::operator%(short& d) +{ + SerializeRaw((word *)&d, 1); + return *this; +} + +Stream& Stream::operator%(unsigned short& d) +{ + SerializeRaw((word *)&d, 1); + return *this; +} + +Stream& Stream::operator%(int& d) +{ + SerializeRaw((dword *)&d, 1); + return *this; +} + +Stream& Stream::operator%(unsigned int& d) +{ + SerializeRaw((dword *)&d, 1); + return *this; +} + +Stream& Stream::operator%(long& d) +{ + SerializeRaw((dword *)&d, 1); + return *this; +} + +Stream& Stream::operator%(unsigned long& d) +{ + SerializeRaw((dword *)&d, 1); + return *this; +} + +Stream& Stream::operator%(float& d) +{ + SerializeRaw((dword *)&d, 1); + return *this; +} + +Stream& Stream::operator%(double& d) +{ + SerializeRaw((uint64 *)&d, 1); + return *this; +} + +Stream& Stream::operator%(int64& d) +{ + SerializeRaw((uint64 *)&d, 1); + return *this; +} + +Stream& Stream::operator%(uint64& d) +{ + SerializeRaw((uint64 *)&d, 1); + return *this; +} + +#else + +Stream& Stream::operator%(bool& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(char& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(signed char& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(unsigned char& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(short& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(unsigned short& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(int& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(unsigned int& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(long& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(unsigned long& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(float& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(double& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(int64& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} + +Stream& Stream::operator%(uint64& d) +{ + SerializeRaw((byte *)&d, sizeof(d)); + return *this; +} +#endif + + +Stream& Stream::operator%(String& s) { + if(IsError()) return *this; + if(IsLoading()) { + dword len; + len = Get(); + if(len != 0xff) { + if(len & 0x80) { + len &= 0x7f; + Get(); // reserved for future use... or removal + } + } + else { + len = Get32le(); + if(len & 0x80000000) { + len &= 0x7fffffff; + Get(); // reserved for future use... or removal + } + } + if(IsError() || len + GetPos() > GetSize()) + LoadError(); + else { + StringBuffer sb(len); + SerializeRaw((byte*)~sb, len); + s = sb; + } + } + else { + dword len = s.GetLength(); + if(len < 127) + Put(len); + else { + Put(0xff); + Put32le(len); + } + SerializeRaw((byte *)~s, len); + } + return *this; +} + +Stream& Stream::operator/(String& s) { + if(IsError()) return *this; + dword len = s.GetLength(); + Pack(len); + if(IsLoading()) { + StringBuffer b(len); + SerializeRLE((byte *)~b, len); + s = b; + } + else + SerializeRLE((byte *)~s, len); + return *this; +} + +Stream& Stream::operator%(WString& s) { + if(IsError()) return *this; + if(IsLoading()) { + dword len; + Pack(len); + if(IsError() || len + GetPos() > GetSize()) + LoadError(); + else { + WStringBuffer sb(len); + SerializeRaw((byte*)~sb, len * sizeof(wchar)); + s = sb; + } + } + else { + dword len = s.GetLength(); + if(len < 0xff) + Put(len); + else { + Put(0xff); + Put32le(len); + } + SerializeRaw((byte*)~s, len * sizeof(wchar)); + } + return *this; +} + +Stream& Stream::operator/(WString& s) { + if(IsError()) return *this; + String h = ToUtf8(s); + *this / h; + s = FromUtf8(h); + return *this; +} + +void Stream::Magic(dword magic) { + dword a = magic; + *this % a; + if(magic != a) LoadError(); +} + +// -------------------------- String stream ----------------------------- + +void StringStream::SetWriteBuffer() +{ + buffer = (byte *)wdata.Begin(); + rdlim = buffer; + wrlim = (byte *)wdata.End(); +} + +void StringStream::SetWriteMode() +{ + if(writemode) return; + intptr_t p = ptr - buffer; + size = data.GetLength(); + wdata = data; + SetWriteBuffer(); + ptr = buffer + p; + writemode = true; +} + +void StringStream::SetReadMode() +{ + if(!writemode) return; + wdata.SetLength((dword)GetSize()); + dword p = (dword)(uintptr_t)(ptr - buffer); + data = wdata; + buffer = (byte *) ~data; + ptr = buffer + p; + wrlim = buffer; + rdlim = buffer + data.GetCount(); + writemode = false; +} + +void StringStream::Open(const String& adata) +{ + pos = 0; + data = adata; + style = STRM_READ|STRM_WRITE|STRM_SEEK|STRM_LOADING; + wdata.Clear(); + buffer = (byte *) ~data; + ptr = wrlim = buffer; + rdlim = buffer + data.GetCount(); + writemode = false; + ClearError(); +} + +void StringStream::Create() +{ + Open(String()); + SetStoring(); + SetWriteMode(); + ClearError(); +} + +int64 StringStream::GetSize() const +{ + return writemode ? max(GetPos(), size) : data.GetLength(); +} + +String StringStream::GetResult() +{ + SetReadMode(); + return data; +} + +void StringStream::_Put(const void *d, dword sz) +{ + SetWriteMode(); + if(ptr + sz >= wrlim) { + intptr_t p = ptr - buffer; + #ifdef _DEBUG + wdata.SetLength(max(1, max(2 * (int)GetSize(), (int)GetSize() + (int)sz))); + #else + wdata.SetLength(max(128, max(2 * (int)GetSize(), (int)GetSize() + (int)sz))); + #endif + SetWriteBuffer(); + ptr = buffer + p; + } + memcpy(ptr, d, sz); + ptr += sz; +} + +void StringStream::_Put(int w) +{ + byte h = w; + _Put(&h, 1); +} + +dword StringStream::_Get(void *data, dword sz) +{ + SetReadMode(); + dword read = min((dword)(uintptr_t)(rdlim - ptr), sz); + memcpy(data, ptr, read); + ptr += read; + return read; +} + +int StringStream::_Get() +{ + SetReadMode(); + return ptr < rdlim ? *ptr++ : -1; +} + +int StringStream::_Term() { + SetReadMode(); + return ptr < rdlim ? *ptr : -1; +} + +void StringStream::Seek(int64 pos) { + size = (dword)GetSize(); + if(pos > size) { + SetWriteMode(); + size = (dword)pos; + wdata.SetLength((dword)pos + 100); + SetWriteBuffer(); + } + ptr = buffer + min(GetSize(), pos); +} + +void StringStream::SetSize(int64 asize) { + SetWriteMode(); + dword p = (dword)(uintptr_t)GetPos(); + Seek(asize); + size = (dword)asize; + Seek(min(p, size)); +} + +bool StringStream::IsOpen() const { + return true; +} + +// -------------------- Memory read-write stream ------------------------ + +void MemStream::Seek(int64 pos) { + ptr = buffer + min(pos, int64(rdlim - buffer)); +} + +int64 MemStream::GetSize() const { + return rdlim - buffer; +} + +dword MemStream::_Get(void *data, dword size) { + if(size > (dword)(intptr_t)(rdlim - ptr)) + size = (dword)(intptr_t)(rdlim - ptr); + memcpy(data, ptr, size); + ptr += size; + return size; +} + +void MemStream::_Put(const void *data, dword size) { + if(size > (dword)(uintptr_t)(wrlim - ptr)) { + SetError(ERROR_NOT_ENOUGH_SPACE); + return; + } + memcpy(ptr, data, size); + ptr += size; +} + +bool MemStream::IsOpen() const { + return true; +} + +void MemStream::Create(void *data, int size) +{ + style = STRM_WRITE|STRM_READ|STRM_SEEK|STRM_LOADING; + ptr = buffer = (byte *) data; + wrlim = rdlim = buffer + size; + pos = 0; +} + +MemStream::MemStream(void *data, int size) { + Create(data, size); +} + +MemStream::MemStream() {} + +#ifdef flagSO +MemStream::~MemStream() {} +#endif + +// ----------------------- Memory read streamer ------------------------- + +void MemReadStream::Create(const void *data, int size) +{ + MemStream::Create((void *)data, size); + style = STRM_READ|STRM_SEEK|STRM_LOADING; + wrlim = buffer; +} + +MemReadStream::MemReadStream(const void *data, int size) +{ + Create(data, size); +} + +MemReadStream::MemReadStream() {} + +// --------------------------- Size stream ----------------------- + +void SizeStream::Seek(int64 apos) { + if(ptr - buffer + pos > size) + size = ptr - buffer + pos; + pos = apos; + if(pos > GetSize()) + pos = GetSize(); + ptr = buffer; +} + +int64 SizeStream::GetSize() const { + return max(int64(ptr - buffer + pos), size); +} + +void SizeStream::SetSize(int64 asize) { + size = asize; + if(ptr - buffer + pos > size) { + ptr = buffer; + pos = size; + } +} + +void SizeStream::_Put(const void *, dword sz) { + wrlim = buffer + 128; + pos += ptr - buffer + sz; + ptr = buffer; +} + +void SizeStream::_Put(int w) { + _Put(NULL, 1); +} + +bool SizeStream::IsOpen() const { + return true; +} + +SizeStream::SizeStream() { + size = 0; + style = STRM_WRITE|STRM_SEEK; + buffer = h; +} + +// ------------------------------ Compare stream ---------------------------- + +CompareStream::CompareStream() { + stream = NULL; + equal = false; + size = 0; + buffer = h; +} + +CompareStream::CompareStream(Stream& astream) { + stream = NULL; + buffer = h; + Open(astream); +} + +void CompareStream::Open(Stream& astream) { + ASSERT(astream.IsOpen()); + Close(); + style = STRM_WRITE|STRM_SEEK; + stream = &astream; + size = pos = 0; + wrlim = buffer + 128; + ptr = buffer; + equal = true; +} + +bool CompareStream::IsOpen() const { + return !!stream; +} + +int64 CompareStream::GetSize() const { + return max(int64(ptr - buffer + pos), size); +} + +void CompareStream::Close() { + if(!stream) return; + if(GetPos() > size) + size = GetPos(); + Flush(); + if(stream->GetSize() != GetSize()) + equal = false; + stream = NULL; +} + +void CompareStream::SetSize(int64 asize) { + Flush(); + pos += ptr - buffer; + ptr = buffer; + size = asize; + if(pos > size) + pos = size; +} + +void CompareStream::Seek(int64 apos) { + Flush(); + int64 sz = ptr - buffer + pos; + if(sz > size) + size = sz; + pos = apos; + ptr = buffer; +} + +void CompareStream::Compare(int64 pos, const void *data, dword size) { + ASSERT(stream); + if(!size) return; + Buffer b(size); + if(stream->GetPos() != pos) + stream->Seek(pos); + if(stream->Get(b, size) != size || memcmp(b.operator const byte *(), data, size)) + equal = false; +} + +void CompareStream::Flush() { + Compare(pos, buffer, (int)(ptr - buffer)); +} + +void CompareStream::_Put(const void *data, dword size) { + wrlim = buffer + 128; + ASSERT(ptr <= wrlim); + Flush(); + pos += ptr - buffer; + ptr = buffer; + byte *b = (byte *) data; + while(size && equal) { + int sz = min(size, 128); + Compare(pos, b, sz); + pos += sz; + b += sz; + size -= sz; + } +} + +void CompareStream::_Put(int w) { + byte b = w; + _Put(&b, 1); +} + +struct NilStreamClass : public Stream { + virtual void _Put(int w) {} + virtual bool IsOpen() const { return true; } + virtual int _Term() { return -1; } + virtual int _Get() { return -1; } +}; + +Stream& NilStream() +{ + return Single(); +} + +#ifndef PLATFORM_WINCE +class CoutStream : public Stream { + void Put0(int w) { +#ifdef PLATFORM_WIN32 + static HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + char s[1]; + s[0] = w; + dword dummy; + WriteFile(h, s, 1, &dummy, NULL); +#else + putchar(w); +#endif + } + virtual void _Put(int w) { + if(w == '\n') { +#ifdef PLATFORM_WIN32 + Put0('\r'); +#endif + Put0('\n'); + } + else + if(w != '\r') + Put0(w); + } + virtual bool IsOpen() const { return true; } +}; + +Stream& Cout() +{ + return Single(); +} + +class CerrStream : public Stream { + virtual void _Put(int w) { + #ifdef PLATFORM_WIN32 + static HANDLE h = GetStdHandle(STD_ERROR_HANDLE); + char s[1]; + s[0] = w; + dword dummy; + WriteFile(h, s, 1, &dummy, NULL); + #else + putc(w, stderr); + #endif + } + virtual bool IsOpen() const { return true; } +}; + +Stream& Cerr() +{ + return Single(); +} +#endif + +static int sMappingGranularity_() +{ +#ifdef PLATFORM_WIN32 + static int mg = 0; + if(!mg) { + SYSTEM_INFO info; + GetSystemInfo(&info); + mg = info.dwAllocationGranularity; + } +#else + static int mg = 4096; +#endif + return mg; +} + +FileMapping::FileMapping(const char *file_, bool delete_share_) +{ +#ifdef PLATFORM_WIN32 + hfile = INVALID_HANDLE_VALUE; + hmap = NULL; +#endif +#ifdef PLATFORM_POSIX + hfile = -1; + Zero(hfstat); +#endif + base = rawbase = NULL; + size = rawsize = 0; + offset = rawoffset = 0; + filesize = -1; + write = false; + if(file_) + Open(file_, delete_share_); + +} + +bool FileMapping::Open(const char *file, bool delete_share) +{ + Close(); + write = false; +#ifdef PLATFORM_WIN32 + if(IsWinNT()) + hfile = UnicodeWin32().CreateFileW(ToSystemCharsetW(file), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | (delete_share && IsWinNT() ? FILE_SHARE_DELETE : 0), + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + else + hfile = CreateFile(ToSystemCharset(file), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | (delete_share && IsWinNT() ? FILE_SHARE_DELETE : 0), + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if(hfile == INVALID_HANDLE_VALUE) + return false; + filesize = ::GetFileSize(hfile, NULL); + hmap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL); + if(!hmap) { + Close(); + return false; + } +#endif +#ifdef PLATFORM_POSIX + hfile = open(ToSystemCharset(file), O_RDONLY); + if(hfile == -1) + return false; + if(fstat(hfile, &hfstat) == -1) { + Close(); + return false; + } + filesize = hfstat.st_size; +#endif + return true; +} + +bool FileMapping::Create(const char *file, int64 filesize_, bool delete_share) +{ + Close(); + write = true; +#ifdef PLATFORM_WIN32 + if(IsWinNT()) + hfile = UnicodeWin32().CreateFileW(ToSystemCharsetW(file), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | (delete_share ? FILE_SHARE_DELETE : 0), + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + else + hfile = CreateFile(ToSystemCharset(file), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | (delete_share ? FILE_SHARE_DELETE : 0), + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if(hfile == INVALID_HANDLE_VALUE) + return false; + hmap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, 0, NULL); + if(!hmap) { + Close(); + return false; + } +#endif +#ifdef PLATFORM_POSIX + hfile = open(ToSystemCharset(file), O_RDWR | O_CREAT); + if(hfile == -1) + return false; +#endif + filesize = filesize_; + return true; +} + +bool FileMapping::Map(int64 mapoffset, dword maplen) +{ + ASSERT(IsOpen()); + if(maplen == 0) + return Unmap(); + mapoffset = minmax(mapoffset, 0, filesize); + int gran = sMappingGranularity_(); + int64 rawoff = mapoffset & -gran; + maplen = (dword)min(maplen, filesize - mapoffset); + dword rawsz = (dword)min((maplen + (dword)(mapoffset - rawoff) + gran - 1) & -gran, filesize - rawoff); + if(rawbase && (mapoffset < rawoffset || mapoffset + maplen > rawoffset + rawsize)) + Unmap(); + if(!rawbase) { + rawoffset = rawoff; + rawsize = rawsz; +#ifdef PLATFORM_WIN32 + rawbase = (byte *)MapViewOfFile(hmap, /*write ? FILE_MAP_WRITE :*/ FILE_MAP_READ, + (dword)(rawoffset >> 32), (dword)(rawoffset >> 0), rawsize); +#else + rawbase = (byte *)mmap(0, rawsize, PROT_READ | PROT_WRITE, +#ifdef PLATFORM_FREEBSD + MAP_NOSYNC, +#else + MAP_SHARED, +#endif + hfile, (dword)rawoffset); +#endif + if(!rawbase) + return false; + } + offset = mapoffset; + size = maplen; + base = rawbase + (int)(offset - rawoffset); + return true; +} + +bool FileMapping::Unmap() +{ + bool ok = true; + if(rawbase) { +#ifdef PLATFORM_WIN32 + ok = !!UnmapViewOfFile(rawbase); +#endif +#ifdef PLATFORM_POSIX + ok = (munmap((void *)rawbase, rawsize) == 0); +#endif + } + base = rawbase = NULL; + size = 0; + return ok; +} + +bool FileMapping::Expand(int64 new_filesize) +{ + ASSERT(IsOpen()); + if(new_filesize > filesize) { + if(!Unmap()) + return false; +#ifdef PLATFORM_WIN32 + if(!CloseHandle(hmap)) { + hmap = NULL; + return false; + } + hmap = NULL; +#endif +#ifdef PLATFORM_POSIX + if(FTRUNCATE64_(hfile, (dword)(new_filesize - filesize)) != 0) { + Close(); + return false; + } +#endif + filesize = new_filesize; + } + return true; +} + +bool FileMapping::Close() +{ + bool ok = Unmap(); +#ifdef PLATFORM_WIN32 + if(hmap) { + if(!CloseHandle(hmap)) ok = false; + hmap = NULL; + } + if(IsOpen()) { + if(!CloseHandle(hfile)) ok = false; + hfile = INVALID_HANDLE_VALUE; + } +#endif +#ifdef PLATFORM_POSIX + if(IsOpen()) { + if(close(hfile) != 0) ok = false; + Zero(hfstat); + hfile = -1; + } +#endif + filesize = -1; + offset = 0; + size = 0; + write = false; + return ok; +} + +Time FileMapping::GetTime() const +{ + ASSERT(IsOpen()); +#ifdef PLATFORM_WIN32 + FileTime ft; + GetFileTime(hfile, NULL, NULL, &ft); + return ft; +#endif +#ifdef PLATFORM_POSIX + return Time(hfstat.st_mtime); +#endif +} + +String FileMapping::GetData(int64 offset, dword len) +{ + if(IsOpen() && Map(offset, len)) + return String(base, len); + else { + NEVER(); + return String::GetVoid(); + } +} + +String ReadStdIn() +{ + String r; + for(;;) { + int c = getchar(); + if(c < 0 || c == '\n') + return r; + r.Cat(c); + } +} + +// --------------------------------------------------------------------------- + +String LoadStream(Stream& in) { + if(in.IsOpen()) { + in.ClearError(); + int size = (int)in.GetLeft(); + StringBuffer s(size); + if((dword)size != 0xffffffff) + in.Get(s, size); + if(!in.IsError()) + return s; + } + return String::GetVoid(); +} + +String LoadFile(const char *filename) { + FileIn in(filename); + return LoadStream(in); +} + +bool SaveStream(Stream& out, const String& data) { + if(!out.IsOpen() || out.IsError()) return false; + out.Put((const char *)data, data.GetLength()); + out.Close(); + return out.IsOK(); +} + +bool SaveFile(const char *filename, const String& data) { + FileOut out(filename); + return SaveStream(out, data); +} + +int64 CopyStream(Stream& dest, Stream& src, int64 count) { + int block = (int)min(count, 65536); + Buffer temp(block); + int loaded; + int64 done = 0; + while(count > 0 && (loaded = src.Get(temp, (int)min(count, block))) > 0) { + dest.Put(temp.operator const byte *(), loaded); + count -= loaded; + done += loaded; + } + return done; +} + +void CheckedSerialize(const Callback1 serialize, Stream& stream) +{ + int pos = (int)stream.GetPos(); + stream.Magic(0x61746164); + serialize(stream); + stream.Magic(0x00646e65); + pos = int(stream.GetPos() - pos); + stream.Magic(pos); +} + +bool Load(Callback1 serialize, Stream& stream) { + StringStream backup; + backup.SetStoring(); + serialize(backup); + ASSERT(!backup.IsError()); + stream.SetLoading(); + stream.LoadThrowing(); + try { + CheckedSerialize(serialize, stream); + } + catch(LoadingError) { + backup.Seek(0); + backup.SetLoading(); + serialize(backup); + ASSERT(!backup.IsError()); + return false; + } + return true; +} + +bool Store(Callback1 serialize, Stream& stream) { + stream.SetStoring(); + CheckedSerialize(serialize, stream); + return !stream.IsError(); +} + +String Cfgname(const char *file) { + return file ? String(file) : ConfigFile(); +} + +bool LoadFromFile(Callback1 serialize, const char *file) { + FileIn f(Cfgname(file)); + return f ? Load(serialize, f) : false; +} + +bool StoreToFile(Callback1 serialize, const char *file) { + FileOut f(Cfgname(file)); + return f ? Store(serialize, f) : false; +} + +Stream& Pack16(Stream& s, int& i) { + if(s.IsLoading()) { + i = (int16) s.Get16le(); + if(i == -32768) + i = s.Get32le(); + } + else + if(i < -32767 || i > 32767) { + s.Put16le((word)-32768); + s.Put32le(i); + } + else + s.Put16le((word)i); + return s; +} + +Stream& Pack16(Stream& s, int& i1, int& i2) { + Pack16(s, i1); + Pack16(s, i2); + return s; +} + +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3) { + Pack16(s, i1, i2); + Pack16(s, i3); + return s; +} + +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3, int& i4) { + Pack16(s, i1, i2, i3); + Pack16(s, i4); + return s; +} + +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3, int& i4, int& i5) { + Pack16(s, i1, i2, i3, i4); + Pack16(s, i5); + return s; +} + +int StreamHeading(Stream& stream, int ver, int minver, int maxver, const char* tag) +{ + if(stream.IsLoading() && stream.IsEof() || stream.IsError()) + return Null; + String text = tag; + dword len = text.GetLength(); + stream.Pack(len); + if(stream.IsLoading()) { + if(stream.IsError() || (int)len != text.GetLength()) { + stream.SetError(); + return Null; + } + StringBuffer b(len); + stream.SerializeRaw((byte *)~b, len); + String in = b; + if(stream.IsError() || in != text) { + stream.SetError(); + return Null; + } + } + else + stream.SerializeRaw((byte *)(const char*)text, len); + stream / ver; + if(ver < minver || ver > maxver) { + stream.SetError(); + return Null; + } + return ver; +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/Stream.h b/uppdev/CoreTopics/Stream.h new file mode 100644 index 000000000..fa88fe1fa --- /dev/null +++ b/uppdev/CoreTopics/Stream.h @@ -0,0 +1,631 @@ +#ifdef _DEBUG +#define NEWBLOCKSTREAM +#endif + +enum { + STRM_ERROR = 0x20, + STRM_READ = 0x10, + STRM_WRITE = 0x08, + STRM_SEEK = 0x04, + STRM_LOADING = 0x02, + STRM_THROW = 0x01, + + ERROR_NOT_ENOUGH_SPACE = -1, + ERROR_LOADING_FAILED = -2 +}; + +struct StreamError {}; +struct LoadingError : StreamError {}; + +enum EOLenum { EOL }; + +class Stream { +protected: + int64 pos; + byte *buffer; + byte *ptr; + byte *rdlim; + byte *wrlim; + + unsigned style:6; + unsigned errorcode:16; + + enum { + BEGINOFLINE = 0x02, + }; + + virtual void _Put(int w); + virtual int _Term(); + virtual int _Get(); + virtual void _Put(const void *data, dword size); + virtual dword _Get(void *data, dword size); + +private: + int _Get8(); + int _Get16(); + int _Get32(); + int64 _Get64(); + bool _IsEof() const; + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual void SetSize(int64 size); + virtual void Flush(); + virtual void Close(); + virtual bool IsOpen() const = 0; + + Stream(); + virtual ~Stream(); + + word GetStyle() const { return style; } + + bool IsError() const { return style & STRM_ERROR; } + bool IsOK() const { return !IsError(); } + void SetError(int c = 0) { style |= STRM_ERROR; errorcode = c; } +#ifdef PLATFORM_WIN32 + void SetLastError() { SetError(GetLastError()); } +#endif +#ifdef PLATFORM_POSIX + void SetLastError() { SetError(errno); } +#endif + int GetError() const { return errorcode; } + void ClearError() { style &= ~STRM_ERROR; errorcode = 0; } + + int64 GetPos() const { return dword(ptr - buffer) + pos; } + bool IsEof() const { return ptr >= rdlim && _IsEof(); } + int64 GetLeft() const { return GetSize() - GetPos(); } + void SeekEnd(int64 rel = 0) { Seek(GetSize() + rel); } + void SeekCur(int64 rel) { Seek(GetPos() + rel); } + + void Put(int c) { if(ptr < wrlim) *ptr++ = c; else _Put(c); } + int Term() { return ptr < rdlim ? *ptr : _Term(); } + int Get() { return ptr < rdlim ? *ptr++ : _Get(); } + + void Put(const void *data, dword size) { if(ptr + size <= wrlim) { memcpy(ptr, data, size); ptr += size; } else _Put(data, size); } + dword Get(void *data, dword size) { if(ptr + size <= rdlim) { memcpy(data, ptr, size); ptr += size; return size; } return _Get(data, size); } + + void Put(const String& s) { Put((const char *) s, s.GetLength()); } + String Get(dword size); + + void LoadThrowing() { style |= STRM_THROW; } + void LoadError(); + + bool GetAll(void *data, dword size); + + int Get8() { return ptr < rdlim ? *ptr++ : _Get8(); } +#ifdef CPU_X86 + int Get16() { if(ptr + 1 >= rdlim) return _Get16(); int q = *(word *)ptr; ptr += 2; return q; } + int Get32() { if(ptr + 3 >= rdlim) return _Get32(); int q = *(dword *)ptr; ptr += 4; return q; } + int64 Get64() { if(ptr + 7 >= rdlim) return _Get64(); int64 q = *(int64 *)ptr; ptr += 8; return q; } +#else + int Get16() { return _Get16(); } + int Get32() { return _Get32(); } + int Get64() { return _Get32(); } +#endif + +#ifdef CPU_LE + int Get16le() { return Get16(); } + int Get32le() { return Get32(); } + int64 Get64le() { return Get64(); } + int Get16be(); + int Get32be(); + int64 Get64be(); +#else + int Get16le(); + int Get32le(); + int64 Get64le(); + int Get16be() { return Get16(); } + int Get32be() { return Get32(); } + int64 Get64be() { return Get64(); } +#endif + + int GetUtf8(); + + String GetLine(); + +#ifdef CPU_X86 + void Put16(word q) { if(ptr + 1 < wrlim) { *(word *)ptr = q; ptr += 2; } else Put(&q, 2); } + void Put32(dword q) { if(ptr + 3 < wrlim) { *(dword *)ptr = q; ptr += 4; } else Put(&q, 4); } + void Put64(int64 q) { if(ptr + 7 < wrlim) { *(int64 *)ptr = q; ptr += 8; } else Put(&q, 8); } +#else + void Put16(word q) { Put(&q, 2); } + void Put32(dword q) { Put(&q, 4); } + void Put64(int64 q) { Put(&q, 8); } +#endif + +#ifdef CPU_LE + void Put16le(word q) { Put(&q, 2); } + void Put32le(dword q) { Put(&q, 4); } + void Put64le(int64 q) { Put(&q, 8); } + void Put16be(word q); + void Put32be(dword q); + void Put64be(int64 q); +#else + void Put16le(word q); + void Put32le(dword q); + void Put64le(int64 q); + void Put16be(word q) { Put(&q, 2); } + void Put32be(dword q) { Put(&q, 4); } + void Put64be(int64 q) { Put(&q, 8); } +#endif + + void PutUtf8(int c); + + void Put(const char *s); + void Put(int c, int count); + void Put0(int count) { Put(0, count); } + + void PutCrLf() { Put16(MAKEWORD('\r', '\n')); } +#ifdef PLATFORM_WIN32 + void PutEol() { PutCrLf(); } +#else + void PutEol() { Put('\n'); } +#endif + + Stream& operator<<(EOLenum) { PutEol(); return *this; } + + void PutLine(const char *s); + void PutLine(const String& s); + + void PutW(const wchar *s, int count) { Put(s, count * 2); } + dword GetW(wchar *s, int count) { return Get(s, count * 2) / 2; } + bool GetAllW(wchar *s, int count) { return GetAll(s, count * 2); } + + void Put(Stream& s, int64 size = INT64_MAX, dword click = 4096); + +// Stream as serialization streamer + void SetLoading() { ASSERT(style & STRM_READ); style |= STRM_LOADING; } + void SetStoring() { ASSERT(style & STRM_WRITE); style &= ~STRM_LOADING; } + bool IsLoading() { return style & STRM_LOADING; } + bool IsStoring() { return !IsLoading(); } + + void SerializeRaw(byte *data, dword count); + void SerializeRaw(word *data, dword count); + void SerializeRaw(dword *data, dword count); + void SerializeRaw(uint64 *data, dword count); + + void SerializeRLE(byte *data, dword count); + + Stream& operator%(bool& d); + Stream& operator%(char& d); + Stream& operator%(signed char& d); + Stream& operator%(unsigned char& d); + Stream& operator%(short& d); + Stream& operator%(unsigned short& d); + Stream& operator%(int& d); + Stream& operator%(unsigned int& d); + Stream& operator%(long& d); + Stream& operator%(unsigned long& d); + Stream& operator%(float& d); + Stream& operator%(double& d); + Stream& operator%(int64& d); + Stream& operator%(uint64& d); + + Stream& operator%(String& s); + Stream& operator/(String& s); + + Stream& operator%(WString& s); + Stream& operator/(WString& s); + + void Pack(dword& i); + Stream& operator/(int& i) { dword w = i + 1; Pack(w); i = w - 1; return *this; } + Stream& operator/(unsigned int& i) { Pack(*(dword *)&i); return *this; } + Stream& operator/(long& i) { dword w = i + 1; Pack(w); i = w - 1; return *this; } + Stream& operator/(unsigned long& i) { dword w = i + 1; Pack(w); i = w - 1; return *this; } + + void Magic(dword magic = 0x7d674d7b); + + void Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f, bool& g, bool& h); + void Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f, bool& g); + void Pack(bool& a, bool& b, bool& c, bool& d, bool& e, bool& f); + void Pack(bool& a, bool& b, bool& c, bool& d, bool& e); + void Pack(bool& a, bool& b, bool& c, bool& d); + void Pack(bool& a, bool& b, bool& c); + void Pack(bool& a, bool& b); + +//* deprecated + int GetW() { return Get16(); } + int GetL() { return Get32(); } + int GetIW() { return Get16le(); } + int GetIL() { return Get32le(); } + int GetMW() { return Get16be(); } + int GetML() { return Get32be(); } + void PutW(int c) { Put16(c); } + void PutL(int c) { Put32(c); } + void PutIW(int c) { Put16le(c); } + void PutIL(int c) { Put32le(c); } + void PutMW(int c) { Put16be(c); } + void PutML(int c) { Put32be(c); } +//*/ +private: // No copy + Stream(const Stream& s); + void operator=(const Stream& s); +}; + +class StringStream : public Stream { +protected: + virtual void _Put(int w); + virtual int _Term(); + virtual int _Get(); + virtual void _Put(const void *data, dword size); + virtual dword _Get(void *data, dword size); + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual void SetSize(int64 size); + virtual bool IsOpen() const; + +protected: + bool writemode; + String data; + StringBuffer wdata; + dword size; + + void InitReadMode(); + void SetWriteBuffer(); + void SetReadMode(); + void SetWriteMode(); + +public: + void Open(const String& data); + void Create(); + + String GetResult(); + operator String() { return GetResult(); } + + StringStream() { Create(); } + StringStream(const String& data) { Open(data); } +}; + +class MemStream : public Stream { +protected: + virtual void _Put(const void *data, dword size); + virtual dword _Get(void *data, dword size); + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual bool IsOpen() const; + +public: + void Create(void *data, int size); + + MemStream(); + MemStream(void *data, int size); +#ifdef flagSO + virtual ~MemStream(); +#endif +}; + +class MemReadStream : public MemStream { +public: + void Create(const void *data, int size); + + MemReadStream(const void *data, int size); + MemReadStream(); +}; + +class BlockStream : public Stream { +protected: + virtual void _Put(int w); + virtual int _Term(); + virtual int _Get(); + virtual void _Put(const void *data, dword size); + virtual dword _Get(void *data, dword size); + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual void SetSize(int64 size); + virtual void Flush(); + +private: + int pagesize; + int64 pagemask; + int64 pagepos; + bool pagedirty; + + int64 streamsize; + + void SetPos(int64 p); + void SyncSize(); + bool SyncPage(); + bool SyncPos(); + void ReadData(void *data, int64 at, int size); + +protected: + virtual dword Read(int64 at, void *ptr, dword size); + virtual void Write(int64 at, const void *data, dword size); + virtual void SetStreamSize(int64 size); + +public: + enum { + READ, CREATE, APPEND, READWRITE, + + NOWRITESHARE = 0x10, + DELETESHARE = 0x20, + NOREADSHARE = 0x40, + SHAREMASK = 0x70, + }; +// typedef int OpenMode; // obsolete, use dword + + dword GetBufferSize() const { return pagesize; } + void SetBufferSize(dword newsize); + int64 GetStreamSize() const { return streamsize; } + + BlockStream(); + virtual ~BlockStream(); + +protected: + void OpenInit(dword mode, int64 file_size); +}; + +class FileStream : public BlockStream { +protected: + virtual void SetStreamSize(int64 size); + virtual dword Read(int64 at, void *ptr, dword size); + virtual void Write(int64 at, const void *data, dword size); + +public: + virtual void Close(); + virtual bool IsOpen() const; + +protected: +#ifdef PLATFORM_WIN32 + HANDLE handle; +#endif +#ifdef PLATFORM_POSIX + int handle; +#endif + + void SetPos(int64 pos); + void Init(int64 size); + +public: + operator bool() const { return IsOpen(); } + FileTime GetTime() const; + +#ifdef PLATFORM_WIN32 + void SetTime(const FileTime& tm); + bool Open(const char *filename, dword mode); + + FileStream(const char *filename, dword mode); +#endif + +#ifdef PLATFORM_POSIX + bool Open(const char *filename, dword mode, mode_t acm = 0644); + FileStream(const char *filename, dword mode, mode_t acm = 0644); + FileStream(int std_handle); +#endif + + FileStream(); + ~FileStream(); + +#ifdef PLATFORM_WIN32 + HANDLE GetHandle() const { return handle; } +#endif +#ifdef PLATFORM_POSIX + int GetHandle() const { return handle; } +#endif +}; + +class FileOut : public FileStream { +public: +#ifdef PLATFORM_POSIX + bool Open(const char *fn, mode_t acm = 0644) + { return FileStream::Open(fn, FileStream::CREATE, acm); } +#endif +#ifdef PLATFORM_WIN32 + bool Open(const char *fn) { return FileStream::Open(fn, FileStream::CREATE); } +#endif + + + FileOut(const char *fn) { Open(fn); } + FileOut() {} +}; + +class FileAppend : public FileStream { +public: + bool Open(const char *fn) { return FileStream::Open(fn, FileStream::APPEND); } + + FileAppend(const char *fn) { Open(fn); } + FileAppend() {} +}; + +class FileIn : public FileStream { +public: + bool Open(const char *fn) { return FileStream::Open(fn, FileStream::READ); } + + FileIn(const char *fn) { Open(fn); } + FileIn() {} +}; + +class SizeStream : public Stream { +protected: + virtual void _Put(int w); + virtual void _Put(const void *data, dword size); + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual void SetSize(int64 size); + virtual bool IsOpen() const; + +protected: + int64 size; + byte h[128]; + +public: + operator int64() const { return GetSize(); } + + void Open() { ptr = buffer; size = 0; } + + SizeStream(); +}; + +class CompareStream : public Stream { +protected: + virtual void _Put(int w); + virtual void _Put(const void *data, dword size); + +public: + virtual void Seek(int64 pos); + virtual int64 GetSize() const; + virtual void SetSize(int64 size); + virtual void Close(); + virtual bool IsOpen() const; + virtual void Flush(); + +private: + Stream *stream; + bool equal; + int64 size; + byte h[128]; + + void Compare(int64 pos, const void *data, dword size); + +public: + void Open(Stream& aStream); + + bool IsEqual() { Flush(); return equal; } + operator bool() { Flush(); return equal; } + + CompareStream(); + CompareStream(Stream& aStream); +}; + +class FileMapping +{ +public: + FileMapping(const char *file = NULL, bool delete_share = false); + ~FileMapping() { Close(); } + + bool Open(const char *file, bool delete_share = false); + bool Create(const char *file, int64 filesize, bool delete_share = false); + bool Expand(int64 filesize); + bool Map(int64 offset, dword len); + bool Unmap(); + bool Close(); + + bool IsOpen() const { return hfile != INVALID_HANDLE_VALUE; } + + int64 GetFileSize() const { return filesize; } + Time GetTime() const; + String GetData(int64 offset, dword len); + + int64 GetOffset() const { return offset; } + dword GetCount() const { return size; } + + int64 GetRawOffset() const { return rawoffset; } + dword GetRawCount() const { return rawsize; } + + const byte *operator ~ () const { ASSERT(IsOpen()); return base; } + const byte *Begin() const { ASSERT(IsOpen()); return base; } + const byte *End() const { ASSERT(IsOpen()); return base + size; } + const byte *GetIter(int i) const { ASSERT(IsOpen() && i >= 0 && (dword)i <= size); return base + i; } + const byte& operator [] (int i) const { ASSERT(IsOpen() && i >= 0 && (dword)i < size); return base[i]; } + + byte *operator ~ () { ASSERT(IsOpen()); return base; } + byte *Begin() { ASSERT(IsOpen()); return base; } + byte *End() { ASSERT(IsOpen()); return base + size; } + byte *GetIter(int i) { ASSERT(IsOpen() && i >= 0 && (dword)i <= size); return base + i; } + byte& operator [] (int i) { ASSERT(IsOpen() && i >= 0 && (dword)i < size); return base[i]; } + +private: +#ifdef PLATFORM_WIN32 + HANDLE hfile; + HANDLE hmap; +#endif +#ifdef PLATFORM_POSIX + enum { INVALID_HANDLE_VALUE = -1 }; + int hfile; + struct stat hfstat; +#endif + byte *base; + byte *rawbase; + int64 filesize; + int64 offset; + int64 rawoffset; + dword size; + dword rawsize; + bool write; +}; + + +String LoadStream(Stream& in); +bool SaveStream(Stream& out, const String& data); + +int64 CopyStream(Stream& dest, Stream& src, int64 count); +inline int64 CopyStream(Stream& dest, Stream& src) { return CopyStream(dest, src, src.GetLeft()); } + +#ifndef PLATFORM_WINCE +Stream& Cout(); +Stream& Cerr(); +String ReadStdIn(); +#endif + +Stream& NilStream(); + +String LoadFile(const char *filename); +bool SaveFile(const char *filename, const String& data); + +template +inline Stream& operator%(Stream& s, T& x) +{ + x.Serialize(s); + return s; +} + +inline Stream& operator<<(Stream& s, const char *x) +{ + s.Put(x); + return s; +} + +inline Stream& operator<<(Stream& s, char *x) +{ + s.Put(x); + return s; +} + +inline Stream& operator<<(Stream& s, const String &x) +{ + s.Put(x); + return s; +} + +inline Stream& operator<<(Stream& s, char x) +{ + s.Put((int) x); + return s; +} + +inline Stream& operator<<(Stream& s, const void *x) +{ + s << FormatPtr(x); + return s; +} + +inline Stream& operator<<(Stream& s, void *x) +{ + s << FormatPtr(x); + return s; +} + +template +inline Stream& operator<<(Stream& s, const T& x) { + s << AsString(x); + return s; +} + +// ------ + +Stream& Pack16(Stream& s, int& i); +Stream& Pack16(Stream& s, int& i1, int& i2); +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3); +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3, int& i4); +Stream& Pack16(Stream& s, int& i1, int& i2, int& i3, int& i4, int& i5); + +int StreamHeading(Stream& stream, int ver, int minver, int maxver, const char* tag); diff --git a/uppdev/CoreTopics/String.cpp b/uppdev/CoreTopics/String.cpp new file mode 100644 index 000000000..4c7e7250c --- /dev/null +++ b/uppdev/CoreTopics/String.cpp @@ -0,0 +1,466 @@ +#include "Core.h" + +NAMESPACE_UPP + +#ifdef _DEBUG +void String0::Dsyn() +{ + String *d_str = static_cast(this); + d_str->s = Begin(); + d_str->len = GetCount(); +} +#endif + +String0::Rc String0::voidptr[2] = { { 2, 0 }, { 0, 0 } }; + +void String0::LSet(const String0& s) +{ + w[2] = s.w[2]; + w[3] = s.w[3]; + if(s.IsRef()) { + ptr = s.ptr; + if(ptr != (char *)(voidptr + 1)) + AtomicInc(s.Ref()->refcount); + } + else { + ptr = (char *)MemoryAlloc32(); + qword *d = qptr; + const qword *q = s.qptr; + d[0] = q[0]; d[1] = q[1]; d[2] = q[2]; d[3] = q[3]; + } +} + +void String0::LFree() +{ + if(IsRef()) { + if(ptr != (char *)(voidptr + 1)) { + Rc *rc = Ref(); + ASSERT(rc->refcount > 0); + if(AtomicDec(rc->refcount) == 0) MemoryFree(rc); + } + } + else + MemoryFree32(ptr); +} + +dword String0::LEqual(const String0& s) const +{ + int l = GetCount(); + if(s.GetCount() != l) return 1; +#ifdef CPU_64 + const qword *qa = (const qword *)Begin(); + const qword *qb = (const qword *)s.Begin(); + while(l >= 8) { + if(*qa++ != *qb++) return 1; + l -= 8; + } + const dword *da = (const dword *)qa; + const dword *db = (const dword *)qb; + if((l & 4) && *da++ != *db++) return 1; +#else + const dword *da = (const dword *)Begin(); + const dword *db = (const dword *)s.Begin(); + while(l >= 4) { + if(*da++ != *db++) return 1; + l -= 4; + } +#endif + const word *wa = (const word *)da; + const word *wb = (const word *)db; + if((l & 2) && *wa++ != *wb++) return 1; + return (l & 1) ? *(const char *)wa != *(const char *)wb : 0; +} + +unsigned String0::LHashValue() const +{ + int l = LLen(); + if(l < 15) { + dword w[4]; + w[0] = w[1] = w[2] = w[3] = 0; + memcpy(w, ptr, l); + ((byte *)w)[SLEN] = l; + return CombineHash(w[0], w[1], w[2], w[3]); + } + return memhash(ptr, l); +} + +int String0::LCompare(const String0& s) const +{ + const char *a = Begin(); + int la = GetLength(); + const char *b = s.Begin(); + int lb = s.GetLength(); + int l = min(la, lb); + for(int i = 0; i < l; i++) { + int q = (byte)a[i] - (byte)b[i]; + if(q) return q; + } + return la - lb; +} + +char *String0::Alloc(int count, char& kind) +{ + if(count < 32) { + kind = MEDIUM; + return (char *)MemoryAlloc32(); + } + size_t sz = sizeof(Rc) + count + 1; + Rc *rc = (Rc *)MemoryAlloc(sz); + rc->alloc = (int)sz - sizeof(Rc) - 1; + rc->refcount = 1; + kind = min(rc->alloc, 255); + return (char *)(rc + 1); +} + +char *String0::Insert(int pos, int count, const char *s) +{ + ASSERT(pos >= 0 && count >= 0 && pos <= GetCount()); + int len = GetCount(); + int newlen = len + count; + char *str = (char *)Begin(); + if(newlen < GetAlloc() && !IsSharedRef() && (!s || s < str || s > str + len)) { + if(pos < len) + memmove(str + pos + count, str + pos, len - pos); + if(IsSmall()) + SLen() = newlen; + else + LLen() = newlen; + str[newlen] = 0; + if(s) + memcpy(str + pos, s, count); + Dsyn(); + return str + pos; + } + char kind; + char *p = Alloc(max(2 * len, newlen), kind); + if(pos > 0) + memcpy(p, str, pos); + if(pos < len) + memcpy(p + pos + count, str + pos, len - pos); + if(s) + memcpy(p + pos, s, count); + p[newlen] = 0; + Free(); + ptr = p; + LLen() = newlen; + SLen() = 15; + chr[KIND] = kind; + Dsyn(); + return ptr + pos; +} + +void String0::UnShare() +{ + if(IsSharedRef()) { + int len = LLen(); + char kind; + char *p = Alloc(len, kind); + memcpy(p, ptr, len + 1); + Free(); + chr[KIND] = kind; + ptr = p; + } +} + +void String0::SetSLen(int l) +{ + SLen() = l; + memset(chr + l, 0, 15 - l); +} + +void String0::Remove(int pos, int count) +{ + ASSERT(pos >= 0 && count >= 0 && pos + count <= GetCount()); + UnShare(); + char *s = (char *)Begin(); + memmove(s + pos, s + pos + count, GetCount() - pos - count + 1); + if(IsSmall()) + SetSLen(SLen() - count); + else + LLen() -= count; + Dsyn(); +} + +void String0::Set(int pos, int chr) +{ + ASSERT(pos >= 0 && pos < GetCount()); + UnShare(); + Ptr()[pos] = chr; +} + +void String0::Trim(int pos) +{ + ASSERT(pos >= 0 && pos <= GetCount()); + if(IsSmall()) { + chr[pos] = 0; + SetSLen(pos); + } + else { + UnShare(); + ptr[pos] = 0; + LLen() = pos; + } + Dsyn(); +} + +void String0::LCat(int c) +{ + if(IsSmall()) { + qword *x = (qword *)MemoryAlloc32(); + x[0] = q[0]; + x[1] = q[1]; + LLen() = SLen(); + SLen() = 15; + chr[KIND] = MEDIUM; + qptr = x; + } + int l = LLen(); + if(IsRef() ? !IsShared() && l < (int)Ref()->alloc : l < 31) { + ptr[l] = c; + ptr[LLen() = l + 1] = 0; + } + else { + char *s = Insert(l, 1, NULL); + s[0] = c; + s[1] = 0; + } +} + +void String0::Cat(const char *s, int len) +{ + if(IsSmall()) { + if(SLen() + len < 14) { + memcpy(chr + SLen(), s, len); + SLen() += len; + chr[(int)SLen()] = 0; + Dsyn(); + return; + } + } + else + if((int)LLen() + len < LAlloc() && !IsSharedRef()) { + memcpy(ptr + LLen(), s, len); + LLen() += len; + ptr[LLen()] = 0; + Dsyn(); + return; + } + Insert(GetCount(), len, s); +} + +void String0::Reserve(int r) +{ + int l = GetCount(); + Insert(GetCount(), r, NULL); + Trim(l); +} + +void String0::Set(const char *s, int len) +{ + w[0] = w[1] = w[2] = w[3] = 0; + switch(len) { + #define MOV(x) case x: chr[x - 1] = s[x - 1]; + MOV(14) MOV(13) MOV(12) MOV(11) MOV(10) MOV(9) MOV(8) + MOV(7) MOV(6) MOV(5) MOV(4) MOV(3) MOV(2) MOV(1) + case 0: + SLen() = len; + break; + default: + char *p = Alloc(len, chr[KIND]); + memcpy(p, s, len); + p[len] = 0; + ptr = p; + LLen() = len; + SLen() = 15; + }; + Dsyn(); +} + +String& String::operator=(const char *s) +{ + int len = GetCount(); + char *str = (char *)Begin(); + if(s >= str && s <= str + len) + return *this = String(s, strlen__(s)); + String0::Free(); + String0::Set(s, strlen__(s)); + return *this; +} + +String String::GetVoid() +{ + String s; + s.ptr = (char *)(voidptr + 1); + s.LLen() = 0; + s.SLen() = 15; + s.chr[KIND] = 50; + return s; +} + +bool String::IsVoid() const +{ + return IsRef() && ptr == (char *)(voidptr + 1); +} + +WString String::ToWString() const +{ + return WString(Begin(), GetCount()); +} + +String::String(StringBuffer& b) +{ + if(b.begin == b.buffer) { + String0::Set(b.begin, (int)(uintptr_t)(b.end - b.begin)); + return; + } + int l = b.GetLength(); + if(l <= 14) { + Zero(); + memcpy(chr, b.begin, l); + SLen() = l; + b.Free(); + } + else { + ptr = b.begin; + ptr[l] = 0; + SLen() = 15; + LLen() = l; + chr[KIND] = min(b.GetAlloc(), 255); + } + b.Zero(); + Dsyn(); +} + +char *StringBuffer::Alloc(int count, int& alloc) +{ + if(count <= 31) { + char *s = (char *)MemoryAlloc32(); + alloc = 31; + return s; + } + else { + size_t sz = sizeof(Rc) + count + 1; + Rc *rc = (Rc *)MemoryAlloc(sz); + alloc = rc->alloc = (int)sz - sizeof(Rc) - 1; + rc->refcount = 1; + return (char *)(rc + 1); + } +} + +void StringBuffer::Free() +{ + if(begin == buffer) + return; + int all = (int)(limit - begin); + if(all == 31) + MemoryFree32(begin); + if(all > 31) + MemoryFree((Rc *)begin - 1); +} + +void StringBuffer::Realloc(int n, const char *cat, int l) +{ + int al; + int ep = (int)(end - begin); + char *p = Alloc(n, al); + memcpy(p, begin, min(GetLength(), n)); + if(cat) { + memcpy(p + ep, cat, l); + ep += l; + } + Free(); + begin = p; + end = begin + ep; + limit = begin + al; +} + +void StringBuffer::Expand() +{ + Realloc(GetLength() * 2); +} + +void StringBuffer::SetLength(int l) +{ + Realloc(l); + end = begin + l; +} + +void StringBuffer::Cat(const char *s, int l) +{ + if(end + l > limit) + Realloc(max(GetLength(), l) + GetLength(), s, l); + else { + memcpy(end, s, l); + end += l; + } +} + +void StringBuffer::Cat(int c, int l) +{ + if(end + l > limit) + Realloc(max(GetLength(), l) + GetLength(), NULL, l); + memset(end, c, l); + end += l; +} + +void StringBuffer::Set(String& s) +{ + s.UnShare(); + int l = s.GetLength(); + if(s.GetAlloc() == 14) { + begin = (char *)MemoryAlloc32(); + limit = begin + 31; + memcpy(begin, s.Begin(), l); + end = begin + l; + } + else { + begin = s.ptr; + end = begin + l; + limit = begin + s.GetAlloc(); + } + s.Zero(); +} + +String TrimLeft(const String& str) +{ + const char *s = str; + if(!IsSpace(*s)) + return str; + while(IsSpace((byte)*s)) s++; + return String(s, str.End()); +} + +String TrimRight(const String& str) +{ + if(str.IsEmpty()) + return str; + const char *s = str.Last(); + if(!IsSpace(*s)) + return str; + while(s >= ~str && IsSpace((byte)*s)) s--; + return String(~str, s + 1); +} + +struct StringICompare__ +{ + int encoding; + int operator()(char a, char b) const { return ToUpper(a, encoding) - ToUpper(b, encoding); } + + StringICompare__(int e) : encoding(e) {} +}; + +int CompareNoCase(const String& a, const String& b, byte encoding) +{ + if(encoding == CHARSET_DEFAULT) encoding = GetDefaultCharset(); + if(encoding == CHARSET_UTF8) return CompareNoCase(FromUtf8(a), FromUtf8(b)); + return IterCompare(a.Begin(), a.End(), b.Begin(), b.End(), StringICompare__(encoding)); +} + +int CompareNoCase(const String& a, const char *b, byte encoding) +{ + if(encoding == CHARSET_DEFAULT) encoding = GetDefaultCharset(); + if(encoding == CHARSET_UTF8) return CompareNoCase(FromUtf8(a), FromUtf8(b, (int)strlen(b))); + return IterCompare(a.Begin(), a.End(), b, b + strlen(b), StringICompare__(encoding)); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/String.h b/uppdev/CoreTopics/String.h new file mode 100644 index 000000000..3a25640e0 --- /dev/null +++ b/uppdev/CoreTopics/String.h @@ -0,0 +1,783 @@ +class Nuller; + +#if defined(CPU_X86) && (defined(COMPILER_MSC) || defined(COMPILER_GCC)) +#define FAST_STRING_COMPARE +#endif + +int wstrlen(const wchar *s); + +#ifdef PLATFORM_POSIX +inline int stricmp(const char *a, const char *b) { return strcasecmp(a, b); } +inline int strnicmp(const char *a, const char *b, int n) { return strncasecmp(a, b, n); } +#endif + +#ifdef PLATFORM_WINCE +inline int stricmp(const char *a, const char *b) { return _stricmp(a, b); } +inline int strnicmp(const char *a, const char *b, int n) { return _strnicmp(a, b, n); } +#endif + +inline int strlen__(const char *s) { return s ? (int)strlen(s) : 0; } +inline int strlen__(const wchar *s) { return s ? (int)wstrlen(s) : 0; } + +inline int cmpval__(char x) { return (byte)x; } +inline int cmpval__(wchar x) { return (word)x; } + +class String; +class WString; +class StringBuffer; +class WStringBuffer; + +template +class AString : public B { + typedef typename B::tchar tchar; + typedef typename B::bchar bchar; + typedef typename B::Buffer buffer; + typedef typename B::String String; + +public: + void Clear() { B::Free(); B::Zero(); } + int GetLength() const { return B::GetCount(); } + bool IsEmpty() const { return B::GetCount() == 0; } + + const tchar *End() const { return B::Begin() + GetLength(); } + const tchar *Last() const { return End() - !!B::GetCount(); } + const tchar *GetIter(int i) const { ASSERT(i >= 0 && i <= B::GetCount()); return B::Begin() + i; } + + int operator*() const { return *B::Begin(); } + int operator[](int i) const { ASSERT(i >= 0 && i <= B::GetCount()); return B::Begin()[i]; } + + operator const tchar *() const { return B::Begin(); } + const tchar *operator~() const { return B::Begin(); } + operator const bchar *() const { return (bchar *)B::Begin(); } + operator const void *() const { return B::Begin(); } + + void Insert(int pos, int c) { *B::Insert(pos, 1, NULL) = c; } + void Insert(int pos, const tchar *s, int count) { B::Insert(pos, count, s); } + void Insert(int pos, const String& s) { Insert(pos, s, s.GetCount()); } + void Insert(int pos, const char *s) { Insert(pos, s, strlen__(s)); } + + void Cat(int c) { B::Cat(c); } + void Cat(const tchar *s, int len) { B::Cat(s, len); } + void Cat(const tchar *s) { Cat(s, strlen__(s)); } + void Cat(const String& s) { Cat(~s, s.GetLength()); } + void Cat(int c, int count); + void Cat(const tchar *s, const tchar *lim) { ASSERT(s <= lim); Cat(s, int(lim - s)); } + void Cat(const String& s, int len) { B::Cat(~s, len); } + void Cat(const bchar *s, int len) { Cat((const tchar *) s, len); } + + String& Cat() { return *(String *)this; } + + int Compare(const String& s) const { return B::Compare(s); } + int Compare(const tchar *s) const; + + bool IsEqual(const String& s) const { return B::IsEqual(s); } + bool IsEqual(const tchar *s) const { return Compare(s) == 0; } + + String Mid(int pos, int length) const; + String Mid(int pos) const { return Mid(pos, GetLength() - pos); } + String Right(int count) const { return Mid(GetLength() - count); } + String Left(int count) const { return Mid(0, count); } + + int Find(int chr, int from = 0) const; + int ReverseFind(int chr, int from) const; + int ReverseFind(int chr) const; + + int Find(int len, const tchar *s, int from) const; + int Find(const tchar *s, int from = 0) const; + int Find(const String& s, int from = 0) const { return Find(s.GetCount(), ~s, from); } + + bool StartsWith(const tchar *s, int len) const; + bool StartsWith(const tchar *s) const { return StartsWith(s, strlen__(s)); } + bool StartsWith(const String& s) const { return StartsWith(~s, s.GetLength()); } + + bool EndsWith(const tchar *s, int len) const; + bool EndsWith(const tchar *s) const { return EndsWith(s, strlen__(s)); } + bool EndsWith(const String& s) const { return EndsWith(~s, s.GetLength()); } + + int FindFirstOf(int len, const tchar *s, int from) const; + int FindFirstOf(const tchar *s, int from = 0) const; + int FindFirstOf(const String& s, int from = 0) const { return FindFirstOf(s.GetCount(), ~s, from); } + + friend bool operator<(const String& a, const String& b) { return a.Compare(b) < 0; } + friend bool operator<(const String& a, const tchar *b) { return a.Compare(b) < 0; } + friend bool operator<(const tchar *a, const String& b) { return b.Compare(a) > 0; } + + friend bool operator<=(const String& a, const String& b) { return a.Compare(b) <= 0; } + friend bool operator<=(const String& a, const tchar *b) { return a.Compare(b) <= 0; } + friend bool operator<=(const tchar *a, const String& b) { return b.Compare(a) >= 0; } + + friend bool operator>(const String& a, const String& b) { return a.Compare(b) > 0; } + friend bool operator>(const String& a, const tchar *b) { return a.Compare(b) > 0; } + friend bool operator>(const tchar *a, const String& b) { return b.Compare(a) < 0; } + + friend bool operator>=(const String& a, const String& b) { return a.Compare(b) >= 0; } + friend bool operator>=(const String& a, const tchar *b) { return a.Compare(b) >= 0; } + friend bool operator>=(const tchar *a, const String& b) { return b.Compare(a) <= 0; } + + friend bool operator==(const String& a, const String& b) { return a.IsEqual(b); } + friend bool operator!=(const String& a, const String& b) { return !a.IsEqual(b); } + friend bool operator==(const String& a, const tchar *b) { return a.Compare(b) == 0; } + friend bool operator==(const tchar *a, const String& b) { return b.Compare(a) == 0; } + friend bool operator!=(const String& a, const tchar *b) { return a.Compare(b) != 0; } + friend bool operator!=(const tchar *a, const String& b) { return b.Compare(a) != 0; } + + friend String operator+(const String& a, const String& b) { String c(a); c += b; return c; } + friend String operator+(const String& a, const tchar *b) { String c(a); c += b; return c; } + friend String operator+(const tchar *a, const String& b) { String c(a); c += b; return c; } + friend String operator+(const String& a, int b) { String c(a); c += b; return c; } + friend String operator+(int a, const String& b) { String c(a, 1); c += b; return c; } + friend String operator+(const String& a, tchar b) { String c(a); c += b; return c; } + friend String operator+(tchar a, const String& b) { String c(a, 1); c += b; return c; } +}; + +class String0 : Moveable { + enum { SMALL, MEDIUM = 31 }; + enum { KIND = 14, SLEN = 15, LLEN = 2 }; + +#if defined(_DEBUG) && defined(COMPILER_GCC) + int len; + const char *s; +#endif + + struct Rc { + Atomic refcount; + int alloc; + + char *GetPtr() const { return (char*)(this + 1); } + void Release(); + void Retain(); + }; + + union { + char chr[16]; + char *ptr; + dword *wptr; + qword *qptr; + word v[8]; + dword w[4]; + qword q[2]; + }; + +#ifdef _DEBUG + void Dsyn(); +#else + void Dsyn() {} +#endif + + char& SLen() { return chr[SLEN]; } + char SLen() const { return chr[SLEN]; } + dword& LLen() { return w[LLEN]; } + dword LLen() const { return w[LLEN]; } + bool IsSmall() const { return chr[KIND] == SMALL; } + bool IsLarge() const { return chr[KIND] != SMALL; } + bool IsMedium() const { return chr[KIND] == MEDIUM; } + bool IsRef() const { return (byte)chr[KIND] > MEDIUM; } + Rc *Ref() const { return (Rc *)ptr - 1; } + bool IsShared() const { return Ref()->refcount != 1; } + bool IsSharedRef() const { return IsRef() && IsShared(); } + int LAlloc() const { int b = (byte)chr[KIND]; return b == 255 ? Ref()->alloc : b; } + dword LEqual(const String0& s) const; + int LCompare(const String0& s) const; + + void LSet(const String0& s); + void LFree(); + void LCat(int c); + unsigned LHashValue() const; + + void UnShare(); + void SetSLen(int l); + + char *Ptr() { return IsSmall() ? chr : ptr; } + char *Alloc(int count, char& kind); + + static String0::Rc voidptr[2]; + + void Swap(String0& b) { UPP::Swap(q[0], b.q[0]); UPP::Swap(q[1], b.q[1]); Dsyn(); b.Dsyn(); } + + friend class String; + friend class StringBuffer; + +protected: + void Zero() { q[0] = q[1] = 0; Dsyn(); } + void Free() { if(IsLarge()) LFree(); } + void Set(const String0& s) { + if(s.IsSmall()) { q[0] = s.q[0]; q[1] = s.q[1]; } + else LSet(s); + Dsyn(); + } + void Assign(const String0& s) { + if(s.IsSmall()) { + if(IsLarge()) LFree(); + q[0] = s.q[0]; q[1] = s.q[1]; + } + else + if(this != &s) { + Free(); + LSet(s); + } + Dsyn(); + } + void Set(const char *s, int len); + char *Insert(int pos, int count, const char *str); + +public: // should be protected, bug in gcc 3.4 + typedef char tchar; + typedef byte bchar; + typedef StringBuffer Buffer; + typedef Upp::String String; + +public: + bool IsEqual(const String0& s) const { + return (chr[KIND] | s.chr[KIND] ? LEqual(s) : + #ifdef CPU_64 + ((q[0] ^ s.q[0]) | (q[1] ^ s.q[1])) + #else + ((w[0] ^ s.w[0]) | (w[1] ^ s.w[1]) | (w[2] ^ s.w[2]) | (w[3] ^ s.w[3])) + #endif + ) == 0; + } + + int Compare(const String0& s) const; + + unsigned GetHashValue() const { + return chr[KIND] ? LHashValue() : (unsigned)CombineHash(w[0], w[1], w[2], w[3]); + } + + void Cat(int c) { + if(SLen() < 14) + chr[int(SLen()++)] = c; + else + LCat(c); + Dsyn(); + } + + void Cat(const char *s, int len); + + void Set(int i, int chr); + void Trim(int pos); + + const char *Begin() const { return IsSmall() ? chr : ptr; } + + int operator[](int i) const { ASSERT(i >= 0 && i <= GetCount()); return Begin()[i]; } + + operator const char *() const { return Begin(); } + const char *operator~() const { return Begin(); } + + void Remove(int pos, int count = 1); + void Clear() { Free(); Zero(); } + + int GetCount() const { return IsSmall() ? chr[SLEN] : w[LLEN]; } + int GetLength() const { return GetCount(); } + int GetAlloc() const { return IsSmall() ? 14 : LAlloc(); } + + void Reserve(int r); + + String0& operator=(const String0& s) { Free(); Set(s); return *this; } + + String0() { Zero(); } + ~String0() { Free(); } +}; + +class String : public Moveable > { + void Swap(String& b) { String0::Swap(b); } + +#ifdef _DEBUG +#ifndef COMPILER_GCC + int len; + const char *s; +#endif + friend class String0; +#endif + +public: + const String& operator+=(char c) { Cat(c); return *this; } + const String& operator+=(const char *s) { Cat(s); return *this; } + const String& operator+=(const String& s) { Cat(s); return *this; } + + String& operator=(const char *s); + String& operator=(const String& s) { String0::Assign(s); return *this; } + String& operator=(StringBuffer& b) { *this = String(b); return *this; } + String& operator<<=(const String& s) { if(this != &s) { String0::Free(); String0::Set(s, s.GetCount()); } return *this; } + + void Shrink() { *this = String(Begin(), GetLength()); } + + String() {} + String(const Nuller&) {} + String(const String& s) { String0::Set(s); } + String(const char *s) { String0::Set(s, strlen__(s)); } + String(const String& s, int n) { ASSERT(n >= 0 && n <= s.GetLength()); String0::Set(~s, n); } + String(const char *s, int n) { String0::Set(s, n); } + String(const byte *s, int n) { String0::Set((const char *)s, n); } + String(const char *s, const char *lim) { String0::Set(s, (int)(lim - s)); } + String(int chr, int count) { String0::Zero(); Cat(chr, count); } + String(StringBuffer& b); + + WString ToWString() const; + const String& ToString() const { return *this; } + + static String GetVoid(); + bool IsVoid() const; + + friend void Swap(String& a, String& b) { a.Swap(b); } + + String(const std::string& s) { String0::Set(s.c_str(), (int)s.length()); } + operator std::string() const { return std::string(Begin(), End()); } +}; + +inline std::string to_string(const String& s) { return std::string(s.Begin(), s.End()); } + +class StringBuffer : NoCopy { + char *begin; + char *end; + char *limit; + char buffer[256]; + + friend class String; + + typedef String0::Rc Rc; + + char *Alloc(int len, int& alloc); + void Realloc(int n, const char *cat = NULL, int l = 0); + void Expand(); + void Zero() { begin = end = buffer; limit = begin + 255; } + void Free(); + void Set(String& s); + +public: + char *Begin() { *end = '\0'; return begin; } + char *End() { *end = '\0'; return end; } + + operator char*() { return Begin(); } + char *operator~() { return Begin(); } + + void SetLength(int l); + void SetCount(int l) { SetLength(l); } + int GetLength() const { return (int)(end - begin); } + int GetCount() const { return GetLength(); } + void Strlen() { SetLength((int)strlen(begin)); } + void Clear() { Free(); Zero(); } + void Reserve(int r) { int l = GetLength(); SetLength(l + r); SetLength(l); } + + void Cat(int c) { if(end >= limit) Expand(); *end++ = c; } + void Cat(int c, int count); + void Cat(const char *s, int l); + void Cat(const char *s) { Cat(s, (int)strlen(s)); } + void Cat(const String& s) { Cat(s, s.GetLength()); } + + int GetAlloc() const { return (int)(limit - begin); } + + void operator=(String& s) { Free(); Set(s); } + + StringBuffer() { Zero(); } + StringBuffer(String& s) { Set(s); } + StringBuffer(int len) { Zero(); SetLength(len); } + ~StringBuffer() { if(begin != buffer) Free(); } +}; + +inline bool IsEmpty(const String& s) { return s.IsEmpty(); } + +template bool IsNull(const T& x) { return x.IsNullInstance(); } + +String FormatPtr(const void *p); + +template +inline String AsString(const T& x) +{ + return x.ToString(); +} + +/* +template +inline String AsString(T *x) +{ + return FormatPtr(x); +} +*/ + +#ifdef PLATFORM_MSC +inline String AsString(const void *x) +{ + return FormatPtr(x); +} +#endif + +inline String& operator<<(String& s, const char *x) +{ + s.Cat(x); + return s; +} + +inline String& operator<<(String& s, char *x) +{ + s.Cat(x); + return s; +} + +inline String& operator<<(String& s, const String &x) +{ + s.Cat(x); + return s; +} + +inline String& operator<<(String& s, char x) +{ + s.Cat((int) x); + return s; +} + +inline String& operator<<(String& s, const void *x) +{ + s << FormatPtr(x); + return s; +} + +inline String& operator<<(String& s, void *x) +{ + s << FormatPtr(x); + return s; +} + +template +inline String& operator<<(String& s, const T& x) +{ + s.Cat(AsString(x)); + return s; +} + +template<> +inline String& operator<<(String& s, const char * const &x) +{ + s.Cat(x); + return s; +} + +template<> +inline String& operator<<(String& s, const String &x) +{ + s.Cat(x); + return s; +} + +template<> +inline String& operator<<(String& s, const char& x) +{ + s.Cat(x); + return s; +} + +template<> +inline bool IsNull(const String& s) { return s.IsEmpty(); } + +template<> +inline String AsString(const String& s) { return s; } + +template<> +inline unsigned GetHashValue(const String& s) { return memhash(~s, s.GetLength()); } + +int CompareNoCase(const String& a, const String& b, byte encoding = 0); +int CompareNoCase(const String& a, const char *b, byte encoding = 0); + +inline +int CompareNoCase(const char *a, const String& b, byte encoding = 0) { + return -CompareNoCase(b, a, encoding); +} + +String TrimLeft(const String& s); +String TrimRight(const String& s); + +inline StringBuffer& operator<<(StringBuffer& s, const char *x) +{ + s.Cat(x); + return s; +} + +inline StringBuffer& operator<<(StringBuffer& s, char *x) +{ + s.Cat(x); + return s; +} + +inline StringBuffer& operator<<(StringBuffer& s, const String &x) +{ + s.Cat(x); + return s; +} + +inline StringBuffer& operator<<(StringBuffer& s, char x) +{ + s.Cat((int) x); + return s; +} + +inline StringBuffer& operator<<(StringBuffer& s, const void *x) +{ + s << FormatPtr(x); + return s; +} + +inline StringBuffer& operator<<(StringBuffer& s, void *x) +{ + s << FormatPtr(x); + return s; +} + +template +inline StringBuffer& operator<<(StringBuffer& s, const T& x) +{ + s.Cat(AsString(x)); + return s; +} + +template<> +inline StringBuffer& operator<<(StringBuffer& s, const char * const &x) +{ + s.Cat(x); + return s; +} + +template<> +inline StringBuffer& operator<<(StringBuffer& s, const String &x) +{ + s.Cat(x); + return s; +} + +template<> +inline StringBuffer& operator<<(StringBuffer& s, const char& x) +{ + s.Cat(x); + return s; +} + +template +void RawCat(String& s, const T& x) +{ + s.Cat((const char *)&x, sizeof(x)); +} + +template +void RawCat(StringBuffer& s, const T& x) +{ + s.Cat((const char *)&x, sizeof(x)); +} + +class WString0 { + enum { SMALL = 23 }; + + wchar *ptr; + int length; + int alloc; + +#ifdef _DEBUG + void Dsyn(); +#else + void Dsyn() {} +#endif + + static Atomic voidptr[2]; + + bool IsRc() const { return alloc > SMALL; } + Atomic& Rc() { return *((Atomic *)ptr - 1); } + bool IsShared() { return IsRc() && Rc() > 1; } + + wchar *Alloc(int& count); + void LCat(int c); + void UnShare(); + + friend class WStringBuffer; + friend class WString; + +public: // should be protected, bug in GCC 3.4 + typedef wchar tchar; + typedef int16 bchar; + typedef WStringBuffer Buffer; + typedef WString String; + +protected: + void Zero() { static wchar e[2]; length = alloc = 0; ptr = e; Dsyn(); ASSERT(*ptr == 0); } + void Set(const wchar *s, int length); + void Set(const WString0& s); + void Free(); + void Swap(WString0& b) { Upp::Swap(ptr, b.ptr); Upp::Swap(length, b.length); Upp::Swap(alloc, b.alloc); Dsyn(); b.Dsyn(); } + wchar *Insert(int pos, int count, const wchar *data); + +public: + const wchar *Begin() const { return ptr; } + int operator[](int i) const { return ptr[i]; } + + operator const wchar *() const { return Begin(); } + const wchar *operator~() const { return Begin(); } + + void Cat(int c) { if(!IsRc() && length < alloc) { ptr[length++] = c; ptr[length] = 0; } else LCat(c); Dsyn(); } + void Cat(const wchar *s, int length); + + int GetCount() const { return length; } + int GetLength() const { return length; } + int GetAlloc() const { return alloc; } + + unsigned GetHashValue() const { return memhash(ptr, length * sizeof(wchar)); } + bool IsEqual(const WString0& s) const { return s.length == length && memcmp(ptr, s.ptr, length * sizeof(wchar)) == 0; } + int Compare(const WString0& s) const; + + void Remove(int pos, int count = 1); + void Insert(int pos, const wchar *s, int count); + void Clear() { Free(); Zero(); } + + void Set(int pos, int ch); + void Trim(int pos); + + WString0() { Zero(); } + ~WString0() { Free(); } +}; + +class WString : public Moveable > +{ + void Swap(WString& b) { WString0::Swap(b); } + +#ifdef _DEBUG + int len; + const wchar *s; + friend class WString0; +#endif + +public: + UPP::String ToString() const; + + const WString& operator+=(wchar c) { Cat(c); return *this; } + const WString& operator+=(const wchar *s) { Cat(s); return *this; } + const WString& operator+=(const WString& s) { Cat(s); return *this; } + + WString& operator<<(wchar c) { Cat(c); return *this; } + WString& operator<<(const WString& s) { Cat(s); return *this; } + WString& operator<<(const wchar *s) { Cat(s); return *this; } + + WString& operator=(const wchar *s); + WString& operator=(const WString& s) { if(this != &s) { WString0::Free(); WString0::Set(s); } return *this; } + WString& operator=(WStringBuffer& b) { *this = WString(b); return *this; } + WString& operator<<=(const WString& s) { if(this != &s) { WString0::Free(); WString0::Set(s, s.GetCount()); } return *this; } + + void Shrink() { *this = WString(Begin(), GetLength()); } + + WString() {} + WString(const Nuller&) {} + WString(const WString& s) { WString0::Set(s); } + WString(const wchar *s) { WString0::Set(s, strlen__(s)); } + WString(const WString& s, int n) { ASSERT(n >= 0 && n <= s.GetLength()); WString0::Set(~s, n); } + WString(const wchar *s, int n) { WString0::Set(s, n); } + WString(const wchar *s, const wchar *lim) { WString0::Set(s, (int)(lim - s)); } + WString(int chr, int count) { WString0::Zero(); Cat(chr, count); } + WString(WStringBuffer& b); + + WString(const char *s); + WString(const char *s, int n); + WString(const char *s, const char *lim); + + static WString GetVoid(); + bool IsVoid() const { return alloc < 0; } + + friend void Swap(WString& a, WString& b) { a.Swap(b); } + friend WString operator+(const WString& a, char b) { WString c(a); c += b; return c; } + friend WString operator+(char a, const WString& b) { WString c(a, 1); c += b; return c; } + + WString(const std::wstring& s); + operator std::wstring() const; +}; + +inline std::wstring to_string(const WString& s) { return std::wstring(s.Begin(), s.End()); } + +class WStringBuffer : NoCopy { + wchar *begin; + wchar *end; + wchar *limit; + + friend class WString; + + wchar *Alloc(int len, int& alloc); + void Expand(int n, const wchar *cat = NULL, int l = 0); + void Expand(); + void Zero(); + void Free(); + void Set(WString& s); + +public: + wchar *Begin() { *end = '\0'; return begin; } + wchar *End() { *end = '\0'; return end; } + + operator wchar*() { return Begin(); } + wchar *operator~() { return Begin(); } + + void SetLength(int l); + void SetCount(int l) { SetLength(l); } + int GetLength() const { return (int)(end - begin); } + int GetCount() const { return GetLength(); } + void Strlen() { SetLength(wstrlen(begin)); } + void Clear() { Free(); Zero(); } + void Reserve(int r) { int l = GetLength(); SetLength(l + r); SetLength(l); } + + void Cat(int c) { if(end >= limit) Expand(); *end++ = c; } + void Cat(int c, int count); + void Cat(const wchar *s, int l); + void Cat(const wchar *s) { Cat(s, wstrlen(s)); } + void Cat(const WString& s) { Cat(s, s.GetLength()); } + void Cat(const char *s) { Cat(WString(s)); } + + int GetAlloc() const { return (int)(limit - begin); } + + void operator=(WString& s) { Free(); Set(s); } + + WStringBuffer() { Zero(); } + WStringBuffer(WString& s) { Set(s); } + WStringBuffer(int len) { Zero(); SetLength(len); } + ~WStringBuffer() { Free(); } +}; + +inline bool IsEmpty(const WString& s) { return s.IsEmpty(); } + +template<> +inline bool IsNull(const WString& s) { return s.IsEmpty(); } + +//template<> +//inline String AsString(const WString& s) { return s; } + +template<> +inline unsigned GetHashValue(const WString& s) { return memhash(~s, 2 * s.GetLength()); } + +WString TrimLeft(const WString& str); +WString TrimRight(const WString& s); + +int CompareNoCase(const WString& a, const WString& b); +int CompareNoCase(const WString& a, const wchar *b); + +inline +int CompareNoCase(const wchar *a, const WString& b) { + return -CompareNoCase(b, a); +} + +template<> inline String AsString(const char * const &s) { return s; } +template<> inline String AsString(char * const &s) { return s; } +template<> inline String AsString(const char& a) { return String(a, 1); } +template<> inline String AsString(const signed char& a) { return String(a, 1); } +template<> inline String AsString(const unsigned char& a) { return String(a, 1); } +template<> inline String AsString(const bool& a) { return a ? "true" : "false"; } + +unsigned ctoi(int c); + +typedef int (*CharFilter)(int); + +int CharFilterAscii(int c); +int CharFilterAscii128(int c); +int CharFilterUnicode(int c); +int CharFilterDigit(int c); +int CharFilterWhitespace(int c); +int CharFilterAlpha(int c); +int CharFilterAlphaToUpper(int c); +int CharFilterAlphaToLower(int c); +int CharFilterInt(int c); +int CharFilterDouble(int c); +int CharFilterDefaultToUpperAscii(int c); +int CharFilterCrLf(int c); + +String Filter(const char *s, int (*filter)(int)); +String FilterWhile(const char *s, int (*filter)(int)); + +#include "AString.hpp" diff --git a/uppdev/CoreTopics/TimeDate.cpp b/uppdev/CoreTopics/TimeDate.cpp new file mode 100644 index 000000000..abfc1fd00 --- /dev/null +++ b/uppdev/CoreTopics/TimeDate.cpp @@ -0,0 +1,420 @@ +#include "Core.h" + +NAMESPACE_UPP + +static int s_month[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static int s_month_off[] = { + 0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334 +}; + +bool IsLeapYear(int year) +{ + return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); +} + +void Date::Serialize(Stream& s) +{ + s % day % month % year; +} + +int GetDaysOfMonth(int m, int y) { + return s_month[m - 1] + (m == 2) * IsLeapYear(y); +} + +bool Date::IsValid() const { + return year == -32768 /* TRC fix 2007/06/17:was == 0 */ || month >= 1 && month <= 12 && + day >= 1 && day <= GetDaysOfMonth(month, year); +} + +String DayName(int i, int lang) +{ + static const char *day[] = { + tt_("date\vSunday"), tt_("date\vMonday"), tt_("date\vTuesday"), + tt_("date\vWednesday"), tt_("date\vThursday"), tt_("date\vFriday"), tt_("date\vSaturday") + }; + return i >= 0 && i < 7 ? Nvl(GetLngString(lang, day[i]), GetENUS(day[i])) : String(); +} + +String DyName(int i, int lang) +{ + static const char *day[] = { + tt_("date\vSu"), tt_("date\vMo"), tt_("date\vTu"), + tt_("date\vWe"), tt_("date\vTh"), tt_("date\vFr"), tt_("date\vSa") + }; + return i >= 0 && i < 7 ? Nvl(GetLngString(lang, day[i]), GetENUS(day[i])) : String(); +} + +String MonthName(int i, int lang) +{ + static const char *month[] = { + tt_("date\vJanuary"), tt_("date\vFebruary"), tt_("date\vMarch"), tt_("date\vApril"), tt_("date\vMay"), + tt_("date\vJune"), tt_("date\vJuly"), tt_("date\vAugust"), tt_("date\vSeptember"), tt_("date\vOctober"), + tt_("date\vNovember"), tt_("date\vDecember") + }; + return i >= 0 && i < 12 ? Nvl(GetLngString(lang, month[i]), GetENUS(month[i])) : String(); +} + +String MonName(int i, int lang) +{ + static const char *month[] = { + tt_("sdate\vJan"), tt_("sdate\vFeb"), tt_("sdate\vMar"), tt_("sdate\vApr"), tt_("sdate\vMay"), + tt_("sdate\vJun"), tt_("sdate\vJul"), tt_("sdate\vAug"), tt_("sdate\vSep"), tt_("sdate\vOct"), + tt_("sdate\vNov"), tt_("sdate\vDec") + }; + return i >= 0 && i < 12 ? Nvl(GetLngString(lang, month[i]), GetENUS(month[i])) : String(); +} + +static char s_date_format[64] = "%2:02d/%3:02d/%1:4d"; + +void SetDateFormat(const char *fmt) +{ + strncpy(s_date_format, fmt, 63); +} + +String Format(Date date) { + String s; + if(IsNull(date)) + return String(); + return Format(s_date_format, date.year, date.month, date.day, DayOfWeek(date)); +} + +static char s_date_scan[64] = "mdy"; + +void SetDateScan(const char *scan) +{ + strncpy(s_date_scan, scan, 63); +} + +const char *StrToDate(Date& d, const char *s) +{ + const char *fmt = s_date_scan; + if(*s == 0) { + d = Null; + return s; + } + d = GetSysDate(); + while(*fmt) { + while(*s && !IsDigit(*s) && !IsAlpha(*s) && (byte)*s < 128) + s++; + int n; + if(IsDigit(*s)) { + char *q; + n = strtoul(s, &q, 10); + s = q; + } + else + if(IsAlpha(*s) || (byte)*s >= 128) { + if(*fmt != 'm') + return NULL; + String m; + while(IsAlpha(*s) || (byte)*s >= 128) + m.Cat(*s++); + m = ToUpper(m); + for(int i = 0; i < 12; i++) + if(m == ToUpper(MonthName(i)) || m == ToUpper(MonName(i))) { + n = i + 1; + goto found; + } + return NULL; + found: + ; + } + else + break; + + switch(*fmt) { + case 'd': + if(n < 1 || n > 31) + return NULL; + d.day = n; + break; + case 'm': + if(n < 1 || n > 12) + return NULL; + d.month = n; + break; + case 'y': + d.year = n; + if(d.year < 20) d.year += 2000; // Check again in 2015.... + else + if(d.year < 100) d.year += 1900; + break; + default: + NEVER(); + } + fmt++; + } + return d.IsValid() ? s : NULL; +} + +static bool s_date_letters = true, s_date_upper = true; +static char s_date_seps[64] = "A/\a .-"; + +void SetDateFilter(const char *seps) +{ + s_date_letters = false; + s_date_upper = false; + if(*seps == 'a') { + s_date_letters = true; + seps++; + } + else + if(*seps == 'A') { + s_date_letters = true; + s_date_upper = true; + seps++; + } + strncpy(s_date_seps, seps, 63); +} + +int CharFilterDate(int c) +{ + if(IsDigit(c)) + return c; + if(s_date_letters && IsLetter(c)) + return s_date_upper ? ToUpper(c) : c; + ; + int a = 0; + for(const char *s = s_date_seps; *s; s++) { + if(c == (byte)*s) + return a ? a : *s; + if(s[1] == '\a') + a = *s++; + } + return 0; +} + +int Date::Get() const { + return year * 365 + s_month_off[month - 1] + (day - 1) + + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1 + + (month > 2) * IsLeapYear(year); +} + +void Date::Set(int d) { + int q, leap; + year = 0; + q = d / (400 * 365 + 100 - 3); + year += 400 * q; + d -= q * (400 * 365 + 100 - 3); + leap = 1; + if(d >= 100 * 365 + 24 + 1) { + d--; + q = d / (100 * 365 + 24); + year += 100 * q; + d -= q * (100 * 365 + 24); + leap = 0; + } + if(d >= 365 * 4 + leap) { + q = (d + 1 - leap) / (365 * 4 + 1); + year += 4 * q; + d -= q * (365 * 4 + 1) - 1 + leap; + leap = 1; + } + if(d >= 365 + leap) { + q = (d - leap) / 365; + year += q; + d -= q * 365 + leap; + leap = 0; + } + int i; + for(i = 0; i < 12; i++) { + int q = s_month[i] + (i == 1) * leap; + if(q > d) break; + d -= q; + } + month = i + 1; + day = d + 1; +} + +bool operator<(Date a, Date b) { + if(a.year < b.year) return true; + if(a.year > b.year) return false; + if(a.month < b.month) return true; + if(a.month > b.month) return false; + return a.day < b.day; +} + +int operator-(Date a, Date b) { return a.Get() - b.Get(); } +Date operator+(Date a, int b) { Date q; q.Set(a.Get() + b); return q; } +Date operator+(int a, Date b) { Date q; q.Set(b.Get() + a); return q; } +Date operator-(Date a, int b) { Date q; q.Set(a.Get() - b); return q; } +Date& operator+=(Date& a, int b) { a.Set(a.Get() + b); return a; } +Date& operator-=(Date& a, int b) { a.Set(a.Get() - b); return a; } + +int DayOfWeek(Date date) { + return (date.Get() + 6) % 7; +} + +Date LastDayOfMonth(Date d) { + d.day = GetDaysOfMonth(d.month, d.year); + return d; +} + +Date FirstDayOfMonth(Date d) { + d.day = 1; + return d; +} + +Date LastDayOfYear(Date d) +{ + d.day = 31; + d.month = 12; + return d; +} + +Date FirstDayOfYear(Date d) +{ + d.day = 1; + d.month = 1; + return d; +} + +Date AddMonths(Date date, int months) { + months += date.month - 1; + int year = idivfloor(months, 12); + months -= 12 * year; + year += date.year; + date.year = year; + date.month = months + 1; + date.day = min(date.day, LastDayOfMonth(date).day); + return date; +} + +Date AddYears(Date date, int years) { + date.year += years; + date.day = min(date.day, LastDayOfMonth(date).day); + return date; +} + +void Time::Serialize(Stream& s) +{ + s % day % month % year % hour % minute % second; +} + +#ifdef PLATFORM_WIN32 +Time::Time(FileTime filetime) { + SYSTEMTIME tm; + FileTime ft; + FileTimeToLocalFileTime(&filetime, &ft); + FileTimeToSystemTime(&ft, &tm); + *this = Time(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); +} + +FileTime Time::AsFileTime() const { + SYSTEMTIME tm; + tm.wYear = year; + tm.wMonth = month; + tm.wDay = day; + tm.wHour = hour; + tm.wMinute = minute; + tm.wSecond = second; + tm.wMilliseconds = 0; + FileTime ft, filetime; + SystemTimeToFileTime(&tm, &ft); + LocalFileTimeToFileTime(&ft, &filetime); + return filetime; +} +#endif + +#ifdef PLATFORM_POSIX +Time::Time(FileTime filetime) { + struct tm *time = localtime(&filetime.ft); + *this = Time(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); +} + +FileTime Time::AsFileTime() const { + struct tm time; + time.tm_year = year - 1900; + time.tm_mon = month - 1; + time.tm_mday = day; + time.tm_hour = hour; + time.tm_min = minute; + time.tm_sec = second; + time.tm_isdst = -1; + return mktime(&time); +} +#endif + +bool operator==(Time a, Time b) { + return a.day == b.day && a.month == b.month && a.year == b.year && + a.hour == b.hour && a.minute == b.minute && a.second == b.second; +} + +bool operator<(Time a, Time b) { + if(a.year < b.year) return true; + if(a.year > b.year) return false; + if(a.month < b.month) return true; + if(a.month > b.month) return false; + if(a.day < b.day) return true; + if(a.day > b.day) return false; + if(a.hour < b.hour) return true; + if(a.hour > b.hour) return false; + if(a.minute < b.minute) return true; + if(a.minute > b.minute) return false; + return a.second < b.second; +} + +void Time::Set(int64 scalar) +{ + int q = (int)(scalar / (24 * 3600)); + Date::Set(q); + int n = int(scalar - (int64)q * 24 * 3600); + hour = n / 3600; + n %= 3600; + minute = n / 60; + second = n % 60; +} + +int64 Time::Get() const +{ + return Date::Get() * (int64)24 * 3600 + hour * 3600 + minute * 60 + second; +} + +int64 operator-(Time a, Time b) { + return a.Get() - b.Get(); +} + +Time operator+(Time time, int64 secs) { + time.Set(time.Get() + secs); + return time; +} + +Time operator+(int64 seconds, Time a) { return a + seconds; } +Time operator-(Time a, int64 secs) { return a + (-secs); } +Time& operator+=(Time& a, int64 secs) { a = a + secs; return a; } +Time& operator-=(Time& a, int64 secs) { a = a - secs; return a; } + +String Format(Time time, bool seconds) { + if(IsNull(time)) return String(); + String s = Format(Date(time)); + if(time.hour == 0 && time.minute == 0 && time.second == 0) + return s; + else + return s + (seconds ? Format(" %02d:%02d:%02d", time.hour, time.minute, time.second) + : Format(" %02d:%02d", time.hour, time.minute)); +} + +#ifdef PLATFORM_WIN32 +Time GetSysTime() { + SYSTEMTIME st; + GetLocalTime(&st); + return Time(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); +} +#endif + +#ifdef PLATFORM_POSIX +Time GetSysTime() { + return Time(time(NULL)); +} +#endif + +Date GetSysDate() { + return GetSysTime(); +} + +END_UPP_NAMESPACE diff --git a/uppdev/CoreTopics/TimeDate.h b/uppdev/CoreTopics/TimeDate.h new file mode 100644 index 000000000..3aa025ae1 --- /dev/null +++ b/uppdev/CoreTopics/TimeDate.h @@ -0,0 +1,128 @@ +class Nuller; +class Stream; +struct FileTime; + +struct Date : RelOps< Date, Moveable > { + byte day; + byte month; + int16 year; + + void Serialize(Stream& s); + + bool IsValid() const; + void Set(int scalar); + int Get() const; + + static Date Low() { return Date(-4000, 1, 1); } + static Date High() { return Date(4000, 1, 1); } + + Date() { year = -32768; day = month = 0; } + Date(const Nuller&) { year = -32768; day = month = 0; } + Date(int y, int m, int d) { day = d; month = m; year = y; } +}; + +inline unsigned GetHashValue(Date t) { + return 512 * t.year + 32 * t.month + t.day; +} + +inline bool operator==(Date a, Date b) { + return a.day == b.day && a.month == b.month && a.year == b.year; +} + +bool operator<(Date a, Date b); + +int operator-(Date a, Date b); +Date operator+(Date a, int b); +Date operator+(int a, Date b); +Date operator-(Date a, int b); +Date& operator+=(Date& a, int b); +Date& operator-=(Date& a, int b); + +bool IsLeapYear(int year); + +int GetDaysOfMonth(int m, int y); + +int DayOfWeek(Date date); +Date LastDayOfMonth(Date d); +Date FirstDayOfMonth(Date d); +Date LastDayOfYear(Date d); +Date FirstDayOfYear(Date d); + +Date AddMonths(Date date, int months); +Date AddYears(Date date, int years); + +Date GetSysDate(); + +String DayName(int i, int lang = 0); +String DyName(int i, int lang = 0); +String MonthName(int i, int lang = 0); +String MonName(int i, int lang = 0); + +void SetDateFormat(const char *fmt); +void SetDateScan(const char *scan); +void SetDateFilter(const char *seps); + +const char *StrToDate(Date& d, const char *s); +String Format(Date date); +int CharFilterDate(int c); + +template<> +inline String AsString(const Date& date) { return Format(date); } + +struct Time : Date, RelOps< Time, Moveable