MT5APIStr.h 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. //+------------------------------------------------------------------+
  2. //| MetaTrader 5 API |
  3. //| Copyright 2000-2019, MetaQuotes Software Corp. |
  4. //| http://www.metaquotes.net |
  5. //+------------------------------------------------------------------+
  6. #pragma once
  7. #include <new.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <memory.h>
  12. #include <winnls.h>
  13. //+------------------------------------------------------------------+
  14. //| String base class |
  15. //+------------------------------------------------------------------+
  16. class CMTStr
  17. {
  18. protected:
  19. wchar_t *m_str; // string body
  20. UINT m_str_len; // string length
  21. const UINT m_str_max; // string buffer max size
  22. public:
  23. CMTStr(wchar_t *buf,const UINT size):m_str(buf),m_str_len(0),m_str_max(size) { if(m_str) m_str[0]=0; }
  24. virtual ~CMTStr() { m_str=NULL; m_str_len=0; }
  25. //--- base functionality
  26. void Clear() { m_str_len=0; if(m_str) m_str[0]=0; }
  27. bool Empty() const { return(m_str_len<1 || m_str==NULL || m_str[0]==0); }
  28. UINT Len() const { return(m_str_len); }
  29. static UINT Len(LPCWSTR str) { return(str ? (UINT)wcslen(str):0); }
  30. UINT Max() const { return(m_str_max); }
  31. const wchar_t* Str() const { return(m_str); }
  32. wchar_t* Buffer() { return(m_str); }
  33. void Refresh() { m_str_len=(m_str ? (UINT)wcsnlen(m_str,m_str_max):0); }
  34. const wchar_t operator[](UINT ind) const { return((ind<m_str_len && m_str) ? m_str[ind] : L'\0'); }
  35. bool operator!() const { return(m_str_len==0); }
  36. CMTStr& operator= (const CMTStr& src) { if(this!=&src) Assign(src); return(*this); }
  37. //--- assign
  38. void Assign(const CMTStr &from);
  39. void Assign(LPCWSTR from);
  40. void Assign(LPCWSTR from,const UINT from_len);
  41. void Assign(LPCSTR from);
  42. void Assign(LPCSTR from,const UINT from_len);
  43. //--- operations
  44. int Format(LPCWSTR fmt,...);
  45. void ToLower();
  46. void ToUpper();
  47. void Trim(UINT len);
  48. void TrimSpaces();
  49. static void TrimSpaces(LPWSTR str);
  50. void ReplaceChar(wchar_t findchar,wchar_t repchar);
  51. void Replace(wchar_t *findstr,const wchar_t *repstr);
  52. void Delete(UINT pos,UINT len);
  53. template <UINT dstsize>
  54. static void Delete(wchar_t (&dst)[dstsize],UINT pos,UINT len) { Delete(dst,dstsize,pos,len); }
  55. static void Delete(LPWSTR dst,UINT dstsize,UINT pos,UINT len);
  56. static void ToLower(LPWSTR str,UINT size);
  57. static void ToUpper(LPWSTR str,UINT size);
  58. template <UINT size>
  59. static void ToLower(wchar_t (&str)[size]) { ToLower(str,size); }
  60. template <UINT size>
  61. static void ToUpper(wchar_t (&str)[size]) { ToUpper(str,size); }
  62. template <UINT strsize>
  63. static int FormatStr(wchar_t (&str)[strsize],LPCWSTR fmt,...);
  64. static int FormatStr(LPWSTR str,UINT size,LPCWSTR fmt,...);
  65. template <UINT strsize>
  66. static void Terminate(wchar_t (&str)[strsize]) { str[strsize-1]=L'\0'; }
  67. //--- append
  68. void Append(LPCWSTR appstring);
  69. void Append(const CMTStr &appstring);
  70. void Append(wchar_t appchar);
  71. template <UINT dstsize>
  72. static void Append(wchar_t (&dst)[dstsize],LPCWSTR src) { Append(dst,dstsize,src); }
  73. static void Append(LPWSTR dst,UINT dstsize,LPCWSTR src);
  74. //--- insert
  75. void Insert(UINT pos,LPCWSTR insstring);
  76. void Insert(UINT pos,const CMTStr &insstring);
  77. void Insert(UINT pos,wchar_t inschar);
  78. //--- copy
  79. void Copy(LPWSTR string,UINT maxlen) const;
  80. void Copy(LPSTR string,UINT maxlen) const;
  81. template <UINT dstsize>
  82. static void Copy(wchar_t (&dst)[dstsize],LPCWSTR src) { Copy(dst,dstsize,src); }
  83. template <UINT dstsize>
  84. static void Copy(wchar_t (&dst)[dstsize],LPCWSTR src,UINT srccount) { Copy(dst,dstsize,src,srccount); }
  85. static void Copy(LPWSTR dst,UINT dstsize,LPCWSTR src);
  86. static void Copy(LPWSTR dst,UINT dstsize,LPCWSTR src,UINT srccount);
  87. template <UINT dstsize>
  88. static void Copy(char (&dst)[dstsize],LPCWSTR src) { Copy(dst,dstsize,src); }
  89. static void Copy(LPSTR dst,UINT dstsize,LPCWSTR src);
  90. static void Copy(LPWSTR dst,UINT dstsize,LPCSTR src);
  91. static void CopyCodePage(LPWSTR dst,UINT dstsize,LPCSTR src,UINT codepage);
  92. //--- compare
  93. int Compare(LPCWSTR str) const;
  94. int Compare(LPCWSTR str,UINT count) const;
  95. int Compare(const CMTStr& str) const;
  96. static int Compare(LPCWSTR str1,LPCWSTR str2);
  97. static int Compare(LPCWSTR str1,LPCWSTR str2,UINT count);
  98. //--- compare no case
  99. int CompareNoCase(LPCWSTR str) const;
  100. int CompareNoCase(LPCWSTR str,UINT count) const;
  101. int CompareNoCase(const CMTStr& str) const;
  102. static int CompareNoCase(LPCWSTR str1,LPCWSTR str2);
  103. static int CompareNoCase(LPCWSTR str1,LPCWSTR str2,UINT count);
  104. //--- check groups mask
  105. static bool CheckGroupMask(LPCWSTR groupsmask,LPCWSTR group);
  106. //--- find symbol & substring
  107. int Find(LPCWSTR substring,UINT startpos) const;
  108. int Find(LPCWSTR substring) const;
  109. int FindNoCase(LPCWSTR substring,UINT startpos) const;
  110. int FindNoCase(LPCWSTR substring) const { return FindNoCase(substring,(UINT)0); }
  111. int FindR(LPCWSTR substring) const;
  112. int FindChar(const wchar_t character) const;
  113. int FindRChar(const wchar_t character) const;
  114. static int Find(LPCWSTR str,LPCWSTR substr);
  115. static int FindNoCase(LPCWSTR str,LPCWSTR substr);
  116. static int FindR(LPCWSTR str,LPCWSTR substr);
  117. static int FindChar(LPCWSTR str,wchar_t character);
  118. static int FindRChar(LPCWSTR str,wchar_t character);
  119. //--- error description method
  120. LPCWSTR ErrorMsg(const DWORD error);
  121. protected:
  122. CMTStr();
  123. CMTStr(const CMTStr &from);
  124. CMTStr(LPWSTR buf,const UINT size,LPCWSTR from):m_str(buf),m_str_len(0),m_str_max(size)
  125. {
  126. if(m_str) m_str[0]=0;
  127. Assign(from);
  128. }
  129. private:
  130. static bool CheckGroupTemplate(LPWSTR expr,LPCWSTR group);
  131. };
  132. //+------------------------------------------------------------------+
  133. //| Stack string template |
  134. //+------------------------------------------------------------------+
  135. template <UINT buflen> class TMTStrStatic : public CMTStr
  136. {
  137. wchar_t m_buffer[buflen];
  138. public:
  139. TMTStrStatic() : CMTStr(m_buffer,buflen) {}
  140. TMTStrStatic(LPCWSTR from) : CMTStr(m_buffer,buflen,from) {}
  141. TMTStrStatic(const TMTStrStatic& from) : CMTStr(m_buffer,buflen) { Assign(from); }
  142. TMTStrStatic(const CMTStr& from) : CMTStr(m_buffer,buflen) { Assign(from); }
  143. };
  144. //+------------------------------------------------------------------+
  145. //| Stack strings types |
  146. //+------------------------------------------------------------------+
  147. typedef TMTStrStatic<16> CMTStr16;
  148. typedef TMTStrStatic<32> CMTStr32;
  149. typedef TMTStrStatic<64> CMTStr64;
  150. typedef TMTStrStatic<128> CMTStr128;
  151. typedef TMTStrStatic<256> CMTStr256;
  152. typedef TMTStrStatic<260> CMTStrPath;
  153. typedef TMTStrStatic<512> CMTStr512;
  154. typedef TMTStrStatic<1024> CMTStr1024;
  155. typedef TMTStrStatic<2048> CMTStr2048;
  156. typedef TMTStrStatic<4096> CMTStr4096;
  157. //+------------------------------------------------------------------+
  158. //| Assign from CMTStr |
  159. //+------------------------------------------------------------------+
  160. inline void CMTStr::Assign(const CMTStr &from)
  161. {
  162. //--- check
  163. if(m_str)
  164. {
  165. UINT newlen=from.Len();
  166. //--- calc new length
  167. if(newlen>=m_str_max) newlen=m_str_max-1;
  168. memcpy(m_str,from.Str(),newlen*sizeof(wchar_t));
  169. m_str_len=newlen;
  170. //--- terminate
  171. m_str[m_str_len]=0;
  172. }
  173. //---
  174. }
  175. //+------------------------------------------------------------------+
  176. //| Assign from ptr |
  177. //+------------------------------------------------------------------+
  178. inline void CMTStr::Assign(LPCWSTR from)
  179. {
  180. //--- check
  181. if(m_str)
  182. {
  183. //--- check empty string
  184. if(!from) m_str_len=0;
  185. else
  186. {
  187. UINT newlen=(UINT)wcsnlen(from,m_str_max);
  188. //--- calculate new length and copy
  189. if(newlen>=m_str_max) newlen=m_str_max-1;
  190. memcpy(m_str,from,newlen*sizeof(wchar_t));
  191. m_str_len=newlen;
  192. }
  193. //--- terminate string
  194. m_str[m_str_len]=0;
  195. }
  196. }
  197. //+------------------------------------------------------------------+
  198. //| Assign from ptr with len |
  199. //+------------------------------------------------------------------+
  200. inline void CMTStr::Assign(LPCWSTR from,const UINT from_len)
  201. {
  202. //--- check
  203. if(m_str)
  204. {
  205. //--- check empty string
  206. if(!from) m_str_len=0;
  207. else
  208. {
  209. UINT newlen=(UINT)wcsnlen(from,(from_len<m_str_max)?(from_len):(m_str_max));
  210. //--- calculate new length and copy
  211. if(newlen>=m_str_max) newlen=m_str_max-1;
  212. memcpy(m_str,from,newlen*sizeof(wchar_t));
  213. m_str_len=newlen;
  214. }
  215. //--- terminate string
  216. m_str[m_str_len]=0;
  217. }
  218. }
  219. //+------------------------------------------------------------------+
  220. //| Assign from one-byte string |
  221. //+------------------------------------------------------------------+
  222. inline void CMTStr::Assign(LPCSTR from)
  223. {
  224. //--- check
  225. if(m_str)
  226. {
  227. //--- check empty string
  228. if(!from) m_str[0]=0;
  229. else
  230. {
  231. //--- copy string
  232. int len=::MultiByteToWideChar(CP_ACP,0,from,-1,m_str,int(m_str_max-1));
  233. //--- check result
  234. if(len==0 && GetLastError()==ERROR_INSUFFICIENT_BUFFER) m_str[m_str_max-1]=0;
  235. else
  236. {
  237. //--- len must be greater or equal than 0
  238. len=(0>len)?(0):(len);
  239. //--- limit len
  240. len=(len<((int)m_str_max-1))?(len):((int)m_str_max-1);
  241. //--- terminate string
  242. m_str[len]=0;
  243. }
  244. }
  245. //--- refresh
  246. Refresh();
  247. }
  248. }
  249. //+------------------------------------------------------------------+
  250. //| Assign from one-byte string with length |
  251. //+------------------------------------------------------------------+
  252. inline void CMTStr::Assign(LPCSTR from,const UINT from_len)
  253. {
  254. //--- check
  255. if(m_str)
  256. {
  257. //--- check empty string
  258. if(!from) m_str[0]=0;
  259. else
  260. {
  261. //--- copy string
  262. int len=::MultiByteToWideChar(CP_ACP,0,from,int(from_len),m_str,int(m_str_max-1));
  263. //--- check result
  264. if(len==0 && GetLastError()==ERROR_INSUFFICIENT_BUFFER) m_str[m_str_max-1]=0;
  265. else
  266. {
  267. //--- len must be greater or equal than 0
  268. len=(0>len)?(0):(len);
  269. //--- limit len
  270. len=(len<((int)m_str_max-1))?(len):((int)m_str_max-1);
  271. //--- terminate string
  272. m_str[len]=0;
  273. }
  274. }
  275. //--- refresh
  276. Refresh();
  277. }
  278. }
  279. //+------------------------------------------------------------------+
  280. //| Copy from ptr with len |
  281. //+------------------------------------------------------------------+
  282. inline void CMTStr::Copy(LPWSTR string,UINT maxlen) const
  283. {
  284. if(string && maxlen>0 && m_str) wcsncpy_s(string,maxlen,m_str,_TRUNCATE);
  285. }
  286. //+------------------------------------------------------------------+
  287. //| Copy from one-byte string with len |
  288. //+------------------------------------------------------------------+
  289. inline void CMTStr::Copy(LPSTR string,UINT maxlen) const
  290. {
  291. if(string && maxlen>0 && m_str)
  292. ::WideCharToMultiByte(CP_ACP,0,m_str,-1,string,int(maxlen),NULL,NULL);
  293. }
  294. //+------------------------------------------------------------------+
  295. //| Static copy from string with len |
  296. //+------------------------------------------------------------------+
  297. inline void CMTStr::Copy(LPWSTR dst,UINT dstsize,LPCWSTR src)
  298. {
  299. if(dst && src && dstsize>0)
  300. {
  301. //--- copy string
  302. wcsncpy_s(dst,dstsize,src,_TRUNCATE);
  303. //--- remove trash symbols from CRT in Debug
  304. #ifdef _DEBUG
  305. for(UINT pos=Len(dst)+1;pos<dstsize;pos++) dst[pos]=(wchar_t)0;
  306. #endif
  307. }
  308. }
  309. //+------------------------------------------------------------------+
  310. //| Static copy from string with len |
  311. //+------------------------------------------------------------------+
  312. inline void CMTStr::Copy(LPWSTR dst,UINT dstsize,LPCWSTR src,UINT srccount)
  313. {
  314. if(dst && src && dstsize>0 && srccount>0)
  315. {
  316. //--- copy string
  317. wcsncpy_s(dst,dstsize,src,dstsize>srccount ? srccount:_TRUNCATE);
  318. //--- remove trash symbols from CRT in Debug
  319. #ifdef _DEBUG
  320. for(UINT pos=Len(dst)+1;pos<dstsize;pos++) dst[pos]=(wchar_t)0;
  321. #endif
  322. }
  323. }
  324. //+------------------------------------------------------------------+
  325. //| Copy from one-byte to unicode string |
  326. //+------------------------------------------------------------------+
  327. inline void CMTStr::Copy(LPSTR dst,UINT dstsize,LPCWSTR src)
  328. {
  329. if(dst && src && dstsize>0)
  330. ::WideCharToMultiByte(CP_ACP,0,src,-1,dst,int(dstsize),NULL,NULL);
  331. }
  332. //+------------------------------------------------------------------+
  333. //| Copy from unicode to one-byte string |
  334. //+------------------------------------------------------------------+
  335. inline void CMTStr::Copy(LPWSTR dst,UINT dstsize,LPCSTR src)
  336. {
  337. if(dst && src)
  338. ::MultiByteToWideChar(CP_ACP,0,src,-1,dst,int(dstsize));
  339. }
  340. //+------------------------------------------------------------------+
  341. //| Copy from unicode to one-byte string with codepage |
  342. //+------------------------------------------------------------------+
  343. inline void CMTStr::CopyCodePage(LPWSTR dst,UINT dstsize,LPCSTR src,UINT codepage)
  344. {
  345. if(dst && src)
  346. ::MultiByteToWideChar(codepage,0,src,-1,dst,int(dstsize));
  347. }
  348. //+------------------------------------------------------------------+
  349. //| String format |
  350. //+------------------------------------------------------------------+
  351. inline int CMTStr::Format(LPCWSTR fmt,...)
  352. {
  353. int len=-1;
  354. //---
  355. if(fmt && m_str)
  356. {
  357. va_list marker;
  358. //--- format text
  359. va_start(marker,fmt);
  360. len=_vsnwprintf_s(m_str,m_str_max,_TRUNCATE,fmt,marker);
  361. va_end(marker);
  362. //--- check result
  363. if(len>=0) m_str_len=UINT(len);
  364. else m_str_len=(UINT)wcsnlen(m_str,m_str_max);
  365. }
  366. //---
  367. return(len);
  368. }
  369. //+------------------------------------------------------------------+
  370. //| Convert to lower case |
  371. //+------------------------------------------------------------------+
  372. inline void CMTStr::ToLower()
  373. {
  374. if(m_str) _wcslwr_s(m_str,m_str_max);
  375. }
  376. //+------------------------------------------------------------------+
  377. //| Convert to upper case |
  378. //+------------------------------------------------------------------+
  379. inline void CMTStr::ToUpper()
  380. {
  381. if(m_str) _wcsupr_s(m_str,m_str_max);
  382. }
  383. //+------------------------------------------------------------------+
  384. //| Trim symbols from right |
  385. //+------------------------------------------------------------------+
  386. inline void CMTStr::Trim(UINT len)
  387. {
  388. if(m_str && len<m_str_len)
  389. {
  390. m_str_len=len;
  391. m_str[m_str_len]=0;
  392. }
  393. }
  394. //+------------------------------------------------------------------+
  395. //| Trim spaces |
  396. //+------------------------------------------------------------------+
  397. inline void CMTStr::TrimSpaces()
  398. {
  399. UINT pos;
  400. //--- check
  401. if(m_str_len==0 || !m_str) return;
  402. //--- remove lead spaces
  403. for(pos=0;m_str[pos]==L' ';) pos++;
  404. if(pos>0)
  405. {
  406. memmove(&m_str[0],&m_str[pos],(m_str_len-pos+1)*sizeof(m_str[0]));
  407. m_str_len-=pos;
  408. }
  409. //--- remove last spaces
  410. for(pos=m_str_len;pos>0;pos--)
  411. {
  412. if(m_str[pos-1]==L' ') m_str[pos-1]=L'\0';
  413. else break;
  414. }
  415. //--- refresh length
  416. m_str_len=pos;
  417. }
  418. //+------------------------------------------------------------------+
  419. //| Trim spaces |
  420. //+------------------------------------------------------------------+
  421. inline void CMTStr::TrimSpaces(LPWSTR str)
  422. {
  423. size_t len,pos;
  424. //--- check
  425. if(!str || (len=wcslen(str))==0) return;
  426. //--- remove lead spaces
  427. for(pos=0;str[pos]==L' ';) pos++;
  428. if(pos>0)
  429. {
  430. memmove(&str[0],&str[pos],(len-pos+1)*sizeof(str[0]));
  431. len-=pos;
  432. }
  433. //--- remove last spaces
  434. for(pos=len;pos>0;pos--)
  435. if(str[pos-1]==L' ') str[pos-1]=L'\0';
  436. else break;
  437. }
  438. //+------------------------------------------------------------------+
  439. //| Replace symbol |
  440. //+------------------------------------------------------------------+
  441. inline void CMTStr::ReplaceChar(wchar_t findchar,wchar_t repchar)
  442. {
  443. //--- check
  444. if(m_str_len==0 || !m_str) return;
  445. //--- replace
  446. for(UINT pos=0;pos<m_str_len;pos++)
  447. if(m_str[pos]==findchar) m_str[pos]=repchar;
  448. }
  449. //+------------------------------------------------------------------+
  450. //| Replace substring |
  451. //+------------------------------------------------------------------+
  452. inline void CMTStr::Replace(wchar_t *findstr,const wchar_t *repstr)
  453. {
  454. //--- check
  455. if(findstr && repstr && m_str)
  456. {
  457. wchar_t *from=m_str;
  458. wchar_t *cp;
  459. size_t newsize=0,findstr_len=wcslen(findstr);
  460. wchar_t *newstr =NULL;
  461. //--- search
  462. while((cp=wcsstr(from,findstr))!=NULL)
  463. {
  464. //--- buffer allocated?
  465. if(!newstr)
  466. {
  467. newsize=m_str_max;
  468. newstr =new(std::nothrow) wchar_t[newsize];
  469. //--- fail
  470. if(newstr==NULL) break;
  471. }
  472. *cp=0;
  473. m_str_len=_snwprintf_s(newstr,newsize,_TRUNCATE,L"%s%s%s",m_str,repstr,cp+findstr_len);
  474. //--- copy
  475. if(m_str_len>=m_str_max) m_str_len=m_str_max-1;
  476. memcpy(m_str,newstr,m_str_len*sizeof(wchar_t));
  477. m_str[m_str_len]=0;
  478. //--- next position
  479. from=m_str+(cp-m_str)+wcslen(repstr);
  480. }
  481. //--- free buffer
  482. if(newstr)
  483. {
  484. delete[] newstr;
  485. newstr=NULL;
  486. }
  487. }
  488. }
  489. //+------------------------------------------------------------------+
  490. //| Delete len symbols from pos position |
  491. //+------------------------------------------------------------------+
  492. inline void CMTStr::Delete(UINT pos,UINT len)
  493. {
  494. //--- check
  495. if(pos>=m_str_len || len==0 || !m_str) return;
  496. //--- remove
  497. if(pos+len>m_str_len) len=m_str_len-pos;
  498. if(pos+len<m_str_len)
  499. for(UINT i=pos;i<m_str_len-len;i++)
  500. m_str[i]=m_str[i+len];
  501. m_str_len-=len;
  502. m_str[m_str_len]=L'\0';
  503. }
  504. //+------------------------------------------------------------------+
  505. //| Delete len symbols from pos position |
  506. //+------------------------------------------------------------------+
  507. inline void CMTStr::Delete(LPWSTR dst,UINT dstsize,UINT pos,UINT len)
  508. {
  509. UINT dstlen;
  510. //--- check
  511. if(!dst || dstsize==0) return;
  512. dstlen=Len(dst);
  513. if(pos>=dstlen-1) return;
  514. //--- remove
  515. if(pos+len>dstlen) len=dstlen-pos;
  516. if(pos+len<dstlen)
  517. for(UINT i=pos;i<dstlen-len;i++)
  518. dst[i]=dst[i+len];
  519. dst[dstlen-len]=L'\0';
  520. }
  521. //+------------------------------------------------------------------+
  522. //| Convert to lower case |
  523. //+------------------------------------------------------------------+
  524. inline void CMTStr::ToLower(LPWSTR str,UINT size)
  525. {
  526. if(str && size>0) _wcslwr_s(str,size);
  527. }
  528. //+------------------------------------------------------------------+
  529. //| Convert to upper case |
  530. //+------------------------------------------------------------------+
  531. inline void CMTStr::ToUpper(LPWSTR str,UINT size)
  532. {
  533. if(str && size>0) _wcsupr_s(str,size);
  534. }
  535. //+------------------------------------------------------------------+
  536. //| Static string format |
  537. //+------------------------------------------------------------------+
  538. template<UINT strsize>
  539. inline int CMTStr::FormatStr(wchar_t (&str)[strsize],LPCWSTR fmt,...)
  540. {
  541. int len=-1;
  542. //---
  543. if(str && strsize>1 && fmt)
  544. {
  545. va_list marker;
  546. //--- format text
  547. va_start(marker,fmt);
  548. len=_vsnwprintf_s(str,strsize,_TRUNCATE,fmt,marker);
  549. va_end(marker);
  550. //--- check
  551. if(len>0) str[len]=L'\0';
  552. }
  553. //---
  554. return(len);
  555. }
  556. //+------------------------------------------------------------------+
  557. //| Static string format |
  558. //+------------------------------------------------------------------+
  559. inline int CMTStr::FormatStr(LPWSTR str,UINT size,LPCWSTR fmt,...)
  560. {
  561. int len=-1;
  562. //---
  563. if(str && size>1 && fmt)
  564. {
  565. va_list marker;
  566. //--- format text
  567. va_start(marker,fmt);
  568. len=_vsnwprintf_s(str,size,_TRUNCATE,fmt,marker);
  569. va_end(marker);
  570. //--- check
  571. if(len>0) str[len]=L'\0';
  572. }
  573. //---
  574. return(len);
  575. }
  576. //+------------------------------------------------------------------+
  577. //| Append to end |
  578. //+------------------------------------------------------------------+
  579. inline void CMTStr::Append(LPCWSTR appstring)
  580. {
  581. UINT len;
  582. //--- check appstring
  583. if(m_str && appstring && (len=(UINT)wcslen(appstring))>0 && (len+m_str_len)<m_str_max)
  584. {
  585. memcpy(&m_str[m_str_len],appstring,len*sizeof(m_str[0]));
  586. m_str_len+=len;
  587. m_str[m_str_len]=0;
  588. }
  589. }
  590. //+------------------------------------------------------------------+
  591. //| Append to end |
  592. //+------------------------------------------------------------------+
  593. inline void CMTStr::Append(const CMTStr &appstring)
  594. {
  595. //--- check appstring
  596. if(m_str && appstring.Len()>0 && (appstring.Len()+m_str_len)<m_str_max)
  597. {
  598. memcpy(&m_str[m_str_len],appstring.Str(),appstring.Len()*sizeof(m_str[0]));
  599. m_str_len+=appstring.Len();
  600. m_str[m_str_len]=0;
  601. }
  602. }
  603. //+------------------------------------------------------------------+
  604. //| Append symbol to end |
  605. //+------------------------------------------------------------------+
  606. inline void CMTStr::Append(wchar_t appchar)
  607. {
  608. //--- check appchar
  609. if(m_str && appchar!=L'\0' && (m_str_len+1)<m_str_max)
  610. {
  611. m_str[m_str_len]=appchar;
  612. m_str[++m_str_len]=L'\0';
  613. }
  614. }
  615. //+------------------------------------------------------------------+
  616. //| Append to end |
  617. //+------------------------------------------------------------------+
  618. inline void CMTStr::Append(LPWSTR dst,UINT dstsize,LPCWSTR src)
  619. {
  620. if(dst && src)
  621. {
  622. //--- find destination and and calculate free size
  623. wchar_t* dst_it=dst;
  624. size_t available=dstsize;
  625. while(available>0 && *dst_it!=0)
  626. {
  627. ++dst_it;
  628. --available;
  629. }
  630. //--- not enough free size?
  631. if(available==0)
  632. return;
  633. //--- copy and check
  634. wchar_t* dst_end=dst_it;
  635. wchar_t const* src_it=src;
  636. while((*dst_it++=*src_it++)!=0 && --available>0)
  637. {
  638. }
  639. //--- not enough free size?
  640. if(available==0)
  641. *dst_end=0;
  642. }
  643. }
  644. //+------------------------------------------------------------------+
  645. //| Substring insert |
  646. //+------------------------------------------------------------------+
  647. inline void CMTStr::Insert(UINT pos,LPCWSTR insstring)
  648. {
  649. UINT len;
  650. //--- check insstring
  651. if(m_str && insstring && (len=(UINT)wcslen(insstring))>0 && (len+m_str_len)<m_str_max)
  652. {
  653. memmove(&m_str[pos+len],&m_str[pos],(m_str_len-pos)*sizeof(m_str[0]));
  654. memcpy(&m_str[pos],insstring,len*sizeof(m_str[0]));
  655. m_str_len+=len;
  656. m_str[m_str_len]=L'\0';
  657. }
  658. }
  659. //+------------------------------------------------------------------+
  660. //| Substring insert |
  661. //+------------------------------------------------------------------+
  662. inline void CMTStr::Insert(UINT pos,const CMTStr &insstring)
  663. {
  664. //--- check insstring
  665. if(m_str && insstring.Len()>0 && (insstring.Len()+m_str_len)<m_str_max)
  666. {
  667. memmove(&m_str[pos+insstring.Len()],&m_str[pos],(m_str_len-pos)*sizeof(m_str[0]));
  668. memcpy(&m_str[pos],insstring.Str(),insstring.Len()*sizeof(m_str[0]));
  669. m_str_len+=insstring.Len();
  670. m_str[m_str_len]=L'\0';
  671. }
  672. }
  673. //+------------------------------------------------------------------+
  674. //| Symbol insert |
  675. //+------------------------------------------------------------------+
  676. inline void CMTStr::Insert(UINT pos,wchar_t inschar)
  677. {
  678. //--- check inschar
  679. if(m_str && inschar!=L'\0' && (m_str_len+1)<m_str_max)
  680. {
  681. memmove(&m_str[pos+1],&m_str[pos],(m_str_len-pos)*sizeof(m_str[0]));
  682. m_str[pos]=inschar;
  683. m_str[++m_str_len]=L'\0';
  684. }
  685. }
  686. //+------------------------------------------------------------------+
  687. //| Compare |
  688. //+------------------------------------------------------------------+
  689. inline int CMTStr::Compare(LPCWSTR str) const
  690. {
  691. if(m_str && str) return wcscmp(m_str,str);
  692. return(m_str_len<1 ? 0 : 1);
  693. }
  694. //+------------------------------------------------------------------+
  695. //| Compare |
  696. //+------------------------------------------------------------------+
  697. inline int CMTStr::Compare(LPCWSTR str,UINT count) const
  698. {
  699. if(m_str && str) return wcsncmp(m_str,str,count);
  700. return(m_str_len<1 ? 0 : 1);
  701. }
  702. //+------------------------------------------------------------------+
  703. //| Compare |
  704. //+------------------------------------------------------------------+
  705. inline int CMTStr::Compare(const CMTStr& str) const
  706. {
  707. return(m_str ? wcscmp(m_str,str.Str()) : -1);
  708. }
  709. //+------------------------------------------------------------------+
  710. //| Compare |
  711. //+------------------------------------------------------------------+
  712. inline int CMTStr::Compare(LPCWSTR str1,LPCWSTR str2)
  713. {
  714. return wcscmp(str1,str2);
  715. }
  716. //+------------------------------------------------------------------+
  717. //| Compare |
  718. //+------------------------------------------------------------------+
  719. inline int CMTStr::Compare(LPCWSTR str1,LPCWSTR str2,UINT count)
  720. {
  721. return wcsncmp(str1,str2,count);
  722. }
  723. //+------------------------------------------------------------------+
  724. //| Compare no case |
  725. //+------------------------------------------------------------------+
  726. inline int CMTStr::CompareNoCase(LPCWSTR str) const
  727. {
  728. if(m_str && str) return _wcsicmp(m_str,str);
  729. return(m_str_len<1 ? 0 : 1);
  730. }
  731. //+------------------------------------------------------------------+
  732. //| Compare no case |
  733. //+------------------------------------------------------------------+
  734. inline int CMTStr::CompareNoCase(LPCWSTR str,UINT count) const
  735. {
  736. if(m_str && str) return _wcsnicmp(m_str,str,count);
  737. return(m_str_len<1 ? 0 : 1);
  738. }
  739. //+------------------------------------------------------------------+
  740. //| Compare no case |
  741. //+------------------------------------------------------------------+
  742. inline int CMTStr::CompareNoCase(const CMTStr& str) const
  743. {
  744. if(m_str && str.m_str) return _wcsicmp(m_str,str.m_str);
  745. return(m_str_len<1 ? 0 : 1);
  746. }
  747. //+------------------------------------------------------------------+
  748. //| Compare no case |
  749. //+------------------------------------------------------------------+
  750. inline int CMTStr::CompareNoCase(LPCWSTR str1,LPCWSTR str2)
  751. {
  752. return _wcsicmp(str1,str2);
  753. }
  754. //+------------------------------------------------------------------+
  755. //| Compare no case |
  756. //+------------------------------------------------------------------+
  757. inline int CMTStr::CompareNoCase(LPCWSTR str1,LPCWSTR str2,UINT count)
  758. {
  759. return _wcsnicmp(str1,str2,count);
  760. }
  761. //+------------------------------------------------------------------+
  762. //| Check group correspondence to groups mask list |
  763. //+------------------------------------------------------------------+
  764. inline bool CMTStr::CheckGroupMask(LPCWSTR groupsmask,LPCWSTR group)
  765. {
  766. const wchar_t *tok_start;
  767. wchar_t mask[256]={0};
  768. bool found=false;
  769. int pos;
  770. //--- check
  771. if(!groupsmask || !group) return(false);
  772. //--- look through groupmask
  773. for(tok_start=groupsmask;*tok_start;tok_start++)
  774. {
  775. //--- skip spaces and commas
  776. if(*tok_start==L' ' || *tok_start==L',') continue;
  777. //--- copy mask
  778. for(pos=0; *tok_start && *tok_start!=L',' && pos<255; tok_start++,pos++) mask[pos]=*tok_start;
  779. //--- skip spaces and commas
  780. while(pos>0 && (mask[pos-1]==L' ' || mask[pos-1]==L',')) pos--;
  781. mask[pos]=0;
  782. //--- check
  783. if(mask[0]=='!' && CheckGroupTemplate(mask,group)) return(false);
  784. else
  785. if(CheckGroupTemplate(mask,group)) found=true;
  786. //--- template over
  787. if(!*tok_start) break;
  788. }
  789. //--- return result
  790. return(found);
  791. }
  792. //+------------------------------------------------------------------+
  793. //| Find substring |
  794. //+------------------------------------------------------------------+
  795. inline int CMTStr::Find(LPCWSTR substring,UINT startpos) const
  796. {
  797. if(substring && m_str && m_str_len>0)
  798. if(startpos<m_str_len)
  799. {
  800. wchar_t *position=wcsstr(m_str+startpos,substring);
  801. if(position) return int(position-m_str);
  802. }
  803. return(-1);
  804. }
  805. //+------------------------------------------------------------------+
  806. //| Find substring |
  807. //+------------------------------------------------------------------+
  808. inline int CMTStr::Find(LPCWSTR substring) const
  809. {
  810. if(substring && m_str && m_str_len>0)
  811. {
  812. wchar_t *position=wcsstr(m_str,substring);
  813. if(position)
  814. {
  815. return int(position-m_str);
  816. }
  817. }
  818. return(-1);
  819. }
  820. //+------------------------------------------------------------------+
  821. //| Find substring no case |
  822. //+------------------------------------------------------------------+
  823. inline int CMTStr::FindNoCase(LPCWSTR substring,UINT startpos) const
  824. {
  825. UINT sublen=0;
  826. //---
  827. if(substring && (sublen=(UINT)wcslen(substring))>0 && m_str && m_str_len>0)
  828. if(startpos<m_str_len)
  829. for(UINT pos=startpos;m_str_len-pos>=sublen;pos++)
  830. if(_wcsnicmp(m_str+pos,substring,sublen)==0)
  831. return int(pos);
  832. return(-1);
  833. }
  834. //+------------------------------------------------------------------+
  835. //| Find substring reverse |
  836. //+------------------------------------------------------------------+
  837. inline int CMTStr::FindR(LPCWSTR substring) const
  838. {
  839. int pos=0,end=0,beg=-1;
  840. //--- check
  841. if(substring && m_str && m_str_len>0 && Len(substring)>0)
  842. {
  843. //--- find from end
  844. while((pos=CMTStr::Find(&m_str[end],substring))>=0)
  845. {
  846. beg=end+pos;
  847. end+=pos+1;
  848. }
  849. }
  850. //--- result
  851. return(beg);
  852. }
  853. //+------------------------------------------------------------------+
  854. //| Find symbol |
  855. //+------------------------------------------------------------------+
  856. inline int CMTStr::FindChar(const wchar_t character) const
  857. {
  858. if(m_str && m_str_len>0)
  859. {
  860. wchar_t *ptr=wcschr(m_str,character);
  861. if(ptr) return int(ptr-m_str);
  862. }
  863. return(-1);
  864. }
  865. //+------------------------------------------------------------------+
  866. //| Find symbol reverse |
  867. //+------------------------------------------------------------------+
  868. inline int CMTStr::FindRChar(const wchar_t character) const
  869. {
  870. if(m_str && m_str_len>0)
  871. {
  872. wchar_t *ptr=wcsrchr(m_str,character);
  873. if(ptr) return int(ptr-m_str);
  874. }
  875. return(-1);
  876. }
  877. //+------------------------------------------------------------------+
  878. //| Find substring |
  879. //+------------------------------------------------------------------+
  880. inline int CMTStr::Find(LPCWSTR str,LPCWSTR substr)
  881. {
  882. if(str && substr && substr[0]!=L'\0')
  883. {
  884. LPCWSTR ptr=wcsstr(str,substr);
  885. if(ptr) return int(ptr-str);
  886. }
  887. return(-1);
  888. }
  889. //+------------------------------------------------------------------+
  890. //| Find substring no case |
  891. //+------------------------------------------------------------------+
  892. inline int CMTStr::FindNoCase(LPCWSTR str,LPCWSTR substr)
  893. {
  894. UINT len=0,sublen=0;
  895. //---
  896. if(str && substr && (len=(UINT)wcslen(str))>0 && (sublen=(UINT)wcslen(substr))>0)
  897. for(UINT pos=0;len-pos>=sublen;pos++)
  898. if(_wcsnicmp(str+pos,substr,sublen)==0)
  899. return int(pos);
  900. return(-1);
  901. }
  902. //+------------------------------------------------------------------+
  903. //| Find substring reverse |
  904. //+------------------------------------------------------------------+
  905. inline int CMTStr::FindR(LPCWSTR str,LPCWSTR substr)
  906. {
  907. int pos=0,end=0,beg=-1;
  908. //--- check
  909. if(str && substr && Len(str)>0 && Len(substr)>0)
  910. {
  911. //--- find
  912. while((pos=CMTStr::Find(&str[end],substr))>=0)
  913. {
  914. beg=end+pos;
  915. end+=pos+1;
  916. }
  917. }
  918. //--- result
  919. return(beg);
  920. }
  921. //+------------------------------------------------------------------+
  922. //| Find char |
  923. //+------------------------------------------------------------------+
  924. inline int CMTStr::FindChar(LPCWSTR str,wchar_t character)
  925. {
  926. if(str)
  927. {
  928. LPCWSTR ptr=wcschr(str,character);
  929. if(ptr) return int(ptr-str);
  930. }
  931. return(-1);
  932. }
  933. //+------------------------------------------------------------------+
  934. //| Find symbol reverse |
  935. //+------------------------------------------------------------------+
  936. inline int CMTStr::FindRChar(LPCWSTR str,wchar_t character)
  937. {
  938. if(str)
  939. {
  940. LPCWSTR ptr=wcsrchr(str,character);
  941. if(ptr) return int(ptr-str);
  942. }
  943. return(-1);
  944. }
  945. //+------------------------------------------------------------------+
  946. //| Check group by expression |
  947. //+------------------------------------------------------------------+
  948. inline bool CMTStr::CheckGroupTemplate(LPWSTR expr,LPCWSTR group)
  949. {
  950. wchar_t *mask=NULL,*mask_ast=NULL;
  951. bool ast=false;
  952. //--- check
  953. if(!expr || !group) return(false);
  954. //--- skip multiple '!'
  955. for(mask=expr; *mask=='!'; mask++){}
  956. //--- check for '*' at start
  957. for(; *mask && *mask=='*'; mask++)
  958. {
  959. ast =true;
  960. mask_ast=mask;
  961. }
  962. //--- group loop
  963. for(; *group && *mask; group++)
  964. {
  965. //--- check symbols
  966. if(*group!=*mask)
  967. {
  968. if(!ast) return(false);
  969. else continue;
  970. }
  971. //--- check word
  972. for(; *mask && *mask!='*' && *group; mask++, group++)
  973. if(*group!=*mask)
  974. {
  975. if(!ast) return(false);
  976. else
  977. {
  978. mask=mask_ast;
  979. break;
  980. }
  981. }
  982. //--- check group
  983. if(!*mask && !*group) return(true);
  984. if(!*mask)
  985. {
  986. if(!ast) return(false);
  987. else mask=mask_ast;
  988. }
  989. if(!*group)
  990. {
  991. if(*mask && *mask!='*') return(false);
  992. else
  993. {
  994. for(; *mask && *mask=='*'; mask++){}
  995. if(!*mask) return(true);
  996. return(false);
  997. }
  998. }
  999. else
  1000. {
  1001. for(; *mask && *mask=='*'; mask++)
  1002. mask_ast=mask;
  1003. if(!*mask) return(true);
  1004. ast=true;
  1005. group--;
  1006. }
  1007. }
  1008. //--- mask empty?
  1009. if(*mask) return(false);
  1010. return(true);
  1011. }
  1012. //+------------------------------------------------------------------+
  1013. //| Windows error description |
  1014. //+------------------------------------------------------------------+
  1015. inline LPCWSTR CMTStr::ErrorMsg(DWORD error)
  1016. {
  1017. CMTStrPath text;
  1018. //--- check
  1019. if(!m_str) return(m_str);
  1020. //--- get description
  1021. ::FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
  1022. NULL,error,
  1023. MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  1024. text.Buffer(),text.Max(),
  1025. NULL);
  1026. text.Refresh();
  1027. //--- remove \r & \n in last symbol
  1028. if(text.m_str_len && (text.m_str[text.m_str_len-1]==L'\r' || text.m_str[text.m_str_len-1]==L'\n'))
  1029. {
  1030. text.m_str[text.m_str_len-1]=L'\0';
  1031. text.m_str_len--;
  1032. }
  1033. //--- remove \r & \n in prelast symbol
  1034. if(text.m_str_len && (text.m_str[text.m_str_len-1]==L'\r' || text.m_str[text.m_str_len-1]==L'\n'))
  1035. {
  1036. text.m_str[text.m_str_len-1]=L'\0';
  1037. text.m_str_len--;
  1038. }
  1039. //--- format both code and description
  1040. Format(L"%s (%u)",text.Str(),error);
  1041. return(m_str);
  1042. }
  1043. //+------------------------------------------------------------------+
  1044. //| Error description macro |
  1045. //+------------------------------------------------------------------+
  1046. #define MT_ERROR_MSG() CMTStr64().ErrorMsg(GetLastError())
  1047. //+------------------------------------------------------------------+