spShareMemoryBase.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. #include "precompile.h"
  2. #include "spShareMemoryBase.h"
  3. #include <strstream>
  4. #include <memory>
  5. #ifdef RVC_OS_WIN
  6. #include <Shlwapi.h>
  7. #else
  8. #include <sys/types.h>
  9. #include <sys/ipc.h>
  10. #include <sys/shm.h>
  11. #include <sys/user.h>
  12. #include <mutex>
  13. #endif
  14. #include "sp_dir.h"
  15. #include <winpr/tchar.h>
  16. #include <winpr/synch.h>
  17. #include <winpr/file.h>
  18. #include <winpr/sysinfo.h>
  19. #include <winpr/library.h>
  20. #include "toolkit.h"
  21. #include "fileutil.h"
  22. #define MAX_ENTITY_NUM 20
  23. #define ENTITY_LOCK_NAME "Entity_Connect_Lock"
  24. #define LOG_LOCK_NAME "Entity_Log_Lock"
  25. #ifdef RVC_OS_WIN
  26. #pragma data_seg("CONNECT_INFO")
  27. ENTITY_CONNECT_INFO m_connectInfo[MAX_ENTITY_NUM] = { ENTITY_CONNECT_INFO() };
  28. int m_priorLink = -1;
  29. int m_infoInit = 0;
  30. #pragma data_seg()
  31. #pragma comment(linker,"/section:CONNECT_INFO,rws")
  32. #else
  33. std::mutex g_mutex_4_connctrl;
  34. std::mutex g_mutex_4_log;
  35. static toolkit_once_t once = TOOLKIT_ONCE_INIT;
  36. static char* shm_ptr = NULL;
  37. ENTITY_CONNECT_INFO* m_connectInfo = NULL;
  38. int* m_priorLinkPtr = NULL;
  39. int* m_infoInitPtr = NULL;
  40. #define SHM_SIZE (sizeof(ENTITY_CONNECT_INFO)*MAX_ENTITY_NUM+sizeof(int)+sizeof(int))
  41. #define SHM_MODE 0666
  42. static void share_memory_global_init(void)
  43. {
  44. int shm_id = -1;
  45. key_t key = ftok(".", 20);
  46. shm_id = shmget(key, SHM_SIZE, IPC_CREAT | SHM_MODE);
  47. if (shm_id == -1) {
  48. printf("shmget failed, errorno: %d\n", errno);
  49. }
  50. else {
  51. shm_ptr = (char*)shmat(shm_id, NULL, 0);
  52. if ((void*)shm_ptr == (void*)-1) {
  53. printf("shmat failed, errorno: %d\n", errno);
  54. }
  55. else {
  56. printf("shmat attached from %p\n", (void*)shm_ptr);
  57. m_connectInfo = (ENTITY_CONNECT_INFO*)shm_ptr;
  58. m_priorLinkPtr = (int*)(shm_ptr + sizeof(ENTITY_CONNECT_INFO) * MAX_ENTITY_NUM);
  59. m_infoInitPtr = (int*)(shm_ptr + sizeof(ENTITY_CONNECT_INFO) * MAX_ENTITY_NUM + sizeof(int));
  60. *m_priorLinkPtr = -1;
  61. *m_infoInitPtr = 0;
  62. }
  63. }
  64. }
  65. #endif
  66. CMyLogFile m_log;
  67. BOOL connectControl::Lock(DWORD dwTime)
  68. {
  69. #ifdef RVC_OS_WIN
  70. if (!m_hLock) {
  71. std::string strLockName = ENTITY_LOCK_NAME;
  72. m_hLock = ::CreateMutex(NULL, FALSE, strLockName.c_str());
  73. if (!m_hLock)
  74. return FALSE;
  75. }
  76. // whose priority is higher, when occupies this lock.
  77. DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime);
  78. return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED);
  79. #else
  80. g_mutex_4_connctrl.lock();
  81. #endif // RVC_OS_WIN
  82. }
  83. void connectControl::Unlock()
  84. {
  85. #ifdef RVC_OS_WIN
  86. if (m_hLock)
  87. ::ReleaseMutex(m_hLock);
  88. #else
  89. g_mutex_4_connctrl.unlock();
  90. #endif // RVC_OS_WIN
  91. }
  92. connectControl::connectControl()
  93. :m_hLock(NULL)
  94. {
  95. #ifdef RVC_OS_WIN
  96. if (!m_infoInit) {
  97. for (int i = 0; i < MAX_ENTITY_NUM; i++)
  98. m_connectInfo[i].clear();
  99. m_infoInit = 1;
  100. }
  101. #else
  102. if (m_infoInitPtr != NULL && *m_infoInitPtr == 0) {
  103. for (int i = 0; i < MAX_ENTITY_NUM; i++)
  104. m_connectInfo[i].clear();
  105. *m_infoInitPtr = 1;
  106. }
  107. #endif // RVC_OS_WIN
  108. }
  109. connectControl::~connectControl()
  110. {
  111. #ifdef RVC_OS_WIN
  112. if (m_hLock != NULL)
  113. CloseHandle(m_hLock);
  114. #endif // RVC_OS_WIN
  115. }
  116. connectControl* connectControl::getInstance()
  117. {
  118. static connectControl* Instance = NULL;
  119. #ifdef RVC_OS_LINUX
  120. toolkit_once(&once, share_memory_global_init);
  121. #endif
  122. if (NULL == Instance)
  123. Instance = new connectControl();
  124. return Instance;
  125. }
  126. int connectControl::getEntityNum()
  127. {
  128. int entityNum = 0;
  129. #ifdef RVC_OS_LINUX
  130. if (m_connectInfo == NULL)
  131. return 0;
  132. #endif
  133. for (int i = 0; i < MAX_ENTITY_NUM; i++)
  134. {
  135. if (0 != strlen(m_connectInfo[i].m_EntityName))
  136. entityNum++;
  137. else
  138. break;
  139. }
  140. return entityNum;
  141. }
  142. int connectControl::getPriorLink(int lastLink)
  143. {
  144. static int diffTimes = 0;
  145. #ifdef RVC_OS_LINUX
  146. if (m_priorLinkPtr != NULL) {
  147. const int m_priorLink = *m_priorLinkPtr;
  148. #endif
  149. if (-1 == lastLink)
  150. return m_priorLink;
  151. else if (lastLink != m_priorLink) {
  152. int tempLink = (0 == ++diffTimes % 5) ? m_priorLink : lastLink;
  153. return tempLink;
  154. }
  155. #ifdef RVC_OS_LINUX
  156. }
  157. #endif
  158. return lastLink;
  159. }
  160. void connectControl::setLastLink(int link)
  161. {
  162. #ifdef RVC_OS_WIN
  163. if (-1 == link || -1 == m_priorLink) {
  164. m_priorLink = link;
  165. return;
  166. }
  167. else if (link != m_priorLink) {
  168. int entityNum = getEntityNum();
  169. int diffNum = 0;
  170. for (int i = 0; i < entityNum; i++) {
  171. if (m_priorLink != m_connectInfo[i].m_lastLink)
  172. diffNum++;
  173. }
  174. if (diffNum > (entityNum / 2))
  175. m_priorLink = link;//change prior Link when half of the connection links to another connection
  176. }
  177. #else
  178. if (m_priorLinkPtr != NULL) {
  179. if (-1 == link || -1 == *m_priorLinkPtr) {
  180. *m_priorLinkPtr = link;
  181. return;
  182. }
  183. else if (link != *m_priorLinkPtr) {
  184. int entityNum = getEntityNum();
  185. int diffNum = 0;
  186. for (int i = 0; i < entityNum; i++) {
  187. if (*m_priorLinkPtr != m_connectInfo[i].m_lastLink)
  188. diffNum++;
  189. }
  190. if (diffNum > (entityNum / 2))
  191. *m_priorLinkPtr = link;//change prior Link when half of the connection links to another connection
  192. }
  193. }
  194. #endif
  195. }
  196. bool connectControl::getSuccessDual(ENTITY_CONNECT_INFO *entityInfo)
  197. {
  198. if (NULL == entityInfo)
  199. return false;
  200. #ifdef RVC_OS_LINUX
  201. if (m_connectInfo == NULL)
  202. return false;
  203. #endif
  204. int entityNum = getEntityNum();
  205. for (int i = 0; i < entityNum; i++)
  206. {
  207. if (1 == m_connectInfo[i].m_DualActive && -1 != m_connectInfo[i].m_currentLink)
  208. {
  209. memcpy(entityInfo, &(m_connectInfo[i]), sizeof(ENTITY_CONNECT_INFO));
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. bool connectControl::getEntityInfo(const char *entityName, ENTITY_CONNECT_INFO *entityInfo)
  216. {
  217. #ifdef RVC_OS_LINUX
  218. if (m_connectInfo == NULL)
  219. return false;
  220. #endif
  221. if (NULL == entityName || NULL == entityInfo)
  222. return false;
  223. int entityNum = getEntityNum();
  224. for (int i = 0; i < entityNum; i++)
  225. {
  226. if (!strcmp(entityName, m_connectInfo[i].m_EntityName))
  227. {
  228. memcpy(entityInfo, &(m_connectInfo[i]), sizeof(ENTITY_CONNECT_INFO));
  229. return true;
  230. }
  231. }
  232. return false;
  233. }
  234. bool connectControl::setEntityInfo(const ENTITY_CONNECT_INFO *entityInfo)
  235. {
  236. bool result = false;
  237. if (NULL == entityInfo)
  238. return result;
  239. #ifdef RVC_OS_LINUX
  240. std::lock_guard<std::mutex> guard(g_mutex_4_connctrl);
  241. do
  242. {
  243. if (m_connectInfo == NULL)
  244. break;
  245. int entityNum = getEntityNum();
  246. for (int i = 0; i < entityNum; i++) {
  247. if (!strcmp(entityInfo->m_EntityName, m_connectInfo[i].m_EntityName)) {
  248. m_connectInfo[i].setParam(entityInfo->m_EntityName
  249. , entityInfo->m_ServerIP, entityInfo->m_ServerPort,
  250. entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort,
  251. entityInfo->m_DualActive, entityInfo->m_currentLink);
  252. result = true;
  253. break;
  254. }
  255. }
  256. if (MAX_ENTITY_NUM == entityNum) {
  257. break;
  258. }
  259. m_connectInfo[entityNum].setParam(entityInfo->m_EntityName
  260. , entityInfo->m_ServerIP, entityInfo->m_ServerPort
  261. , entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort
  262. , entityInfo->m_DualActive, entityInfo->m_currentLink);
  263. result = true;
  264. } while (false);
  265. #else
  266. Lock(INFINITE);
  267. std::shared_ptr<void> delLockFun((void*)0, [&](void*) {
  268. Unlock();
  269. });
  270. int entityNum = getEntityNum();
  271. for (int i = 0; i < entityNum; i++)
  272. {
  273. if (!strcmp(entityInfo->m_EntityName, m_connectInfo[i].m_EntityName))
  274. {
  275. m_connectInfo[i].setParam(entityInfo->m_EntityName, entityInfo->m_ServerIP, entityInfo->m_ServerPort,
  276. entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort, entityInfo->m_DualActive, entityInfo->m_currentLink);
  277. return true;
  278. }
  279. }
  280. if (MAX_ENTITY_NUM == entityNum)
  281. return false;
  282. m_connectInfo[entityNum].setParam(entityInfo->m_EntityName, entityInfo->m_ServerIP, entityInfo->m_ServerPort,
  283. entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort, entityInfo->m_DualActive, entityInfo->m_currentLink);
  284. result = true;
  285. #endif
  286. return result;
  287. }
  288. CMyLogFile::CMyLogFile()
  289. : m_cOutFile(NULL), m_hLock(nullptr)
  290. {
  291. }
  292. CMyLogFile::~CMyLogFile()
  293. {
  294. }
  295. void CMyLogFile::Output(const TCHAR *data)
  296. {
  297. if (NULL != m_cOutFile)
  298. m_cOutFile->write(data, strlen(data));
  299. }
  300. bool checkDirExist(char *filePath)
  301. {
  302. if (!ExistsDirA(filePath)) {
  303. return CreateDirA(filePath, TRUE);
  304. }
  305. return true;
  306. //bool b = CreateDirectoryA(filePath, NULL);
  307. //if (b || (GetLastError() == ERROR_ALREADY_EXISTS))
  308. // return true;
  309. //return false;
  310. }
  311. void CMyLogFile::Init()
  312. {
  313. if (!m_cOutFile)
  314. {
  315. char m_dirPath[_MAX_PATH] = "";
  316. char tmp[MAX_PATH];
  317. GetModuleFileNameA(NULL, tmp, MAX_PATH);
  318. *strrchr(tmp, SPLIT_SLASH) = 0;
  319. *strrchr(tmp, SPLIT_SLASH) = 0;
  320. *strrchr(tmp, SPLIT_SLASH) = 0;
  321. *strrchr(tmp, SPLIT_SLASH) = 0;
  322. *strrchr(tmp, SPLIT_SLASH) = 0;
  323. sprintf_s(m_dirPath, _MAX_PATH, "%s" SPLIT_SLASH_STR "rvc" SPLIT_SLASH_STR "dbg" SPLIT_SLASH_STR "DualActive", tmp);
  324. if (!checkDirExist(m_dirPath))
  325. return;
  326. SYSTEMTIME cur;
  327. GetSystemTime(&cur);
  328. sprintf(m_dirPath, "%s" SPLIT_SLASH_STR "%4d%.2d%.2d.log", m_dirPath, cur.wYear, cur.wMonth,
  329. cur.wDay);
  330. m_cOutFile = new ofstream(m_dirPath, ios_base::app);
  331. if (m_cOutFile->is_open())
  332. return;
  333. delete m_cOutFile;
  334. m_cOutFile = NULL;
  335. }
  336. }
  337. void CMyLogFile::Release()
  338. {
  339. if (NULL != m_cOutFile)
  340. {
  341. m_cOutFile->close();
  342. delete m_cOutFile;
  343. m_cOutFile = NULL;
  344. }
  345. }
  346. BOOL CMyLogFile::Lock(DWORD dwTime)
  347. {
  348. #ifdef RVC_OS_WIN
  349. if (!m_hLock) {
  350. std::string strLockName = LOG_LOCK_NAME;
  351. m_hLock = ::CreateMutex(NULL, FALSE, strLockName.c_str());
  352. if (!m_hLock)
  353. return FALSE;
  354. }
  355. DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime);
  356. return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED);
  357. #else
  358. g_mutex_4_log.lock();
  359. #endif // RVC_OS_WIN
  360. }
  361. void CMyLogFile::Unlock()
  362. {
  363. #ifdef RVC_OS_WIN
  364. if (m_hLock)
  365. ::ReleaseMutex(m_hLock);
  366. #else
  367. g_mutex_4_log.unlock();
  368. #endif
  369. }
  370. bool CMyLogFile::GetRootDir(char *dirPath)
  371. {
  372. char pathbuf[1024] = "";
  373. int pathlen = ::GetModuleFileNameA(NULL, pathbuf, 1024);
  374. int times = 0;
  375. while (pathlen > 0)
  376. {
  377. if (pathbuf[pathlen--] == SPLIT_SLASH)
  378. times++;
  379. if (2 == times)
  380. break;
  381. }
  382. pathbuf[++pathlen] = '\0';
  383. memcpy(dirPath, pathbuf, (pathlen + 1 > 1024 ? 1024 : pathlen + 1));
  384. return pathlen;
  385. }
  386. void CMyLogFile::PrintCurTime()
  387. {
  388. TCHAR dateString[256];
  389. SYSTEMTIME cur;
  390. GetLocalTime(&cur);
  391. sprintf(dateString, "[%4d-%.2d-%.2d,%.2d:%.2d:%.2d][%u][%u] ", cur.wYear, cur.wMonth,
  392. cur.wDay, cur.wHour, cur.wMinute, cur.wSecond, GetCurrentProcessId(),
  393. #if defined(RVC_OS_WIN)
  394. GetCurrentThreadId());
  395. #else
  396. GetCurrentThreadIdFromSys());
  397. #endif //RVC_OS_WIN
  398. Output(dateString);
  399. }
  400. CMyLogFile& CMyLogFile::operator <<(unsigned int unVal)
  401. {
  402. strstream tmp;
  403. tmp << unVal;
  404. tmp << '\0';
  405. TCHAR* output = tmp.str();
  406. Output(output);
  407. tmp.freeze(false);
  408. return *this;
  409. }
  410. CMyLogFile& CMyLogFile::operator <<(long lVal)
  411. {
  412. strstream tmp;
  413. tmp << lVal;
  414. tmp << '\0';
  415. TCHAR* output = tmp.str();
  416. Output(output);
  417. tmp.freeze(false);
  418. return *this;
  419. }
  420. CMyLogFile& CMyLogFile::operator <<(const TCHAR* str)
  421. {
  422. Output(str);
  423. return *this;
  424. }
  425. CMyLogFile& CMyLogFile::operator <<(TCHAR tch)
  426. {
  427. TCHAR szCh[2];
  428. szCh[0] = tch;
  429. szCh[1] = '\0';
  430. Output(szCh);
  431. return *this;
  432. }
  433. CMyLogFile& CMyLogFile::operator <<(int nVal)
  434. {
  435. strstream tmp;
  436. tmp << nVal;
  437. tmp << '\0';
  438. TCHAR* output = tmp.str();
  439. Output(output);
  440. tmp.freeze(false);
  441. return *this;
  442. }
  443. CMyLogFile& CMyLogFile::operator <<(unsigned long ulVal)
  444. {
  445. strstream tmp;
  446. tmp << ulVal;
  447. tmp << '\0';
  448. TCHAR* output = tmp.str();
  449. Output(output);
  450. tmp.freeze(false);
  451. return *this;
  452. }
  453. CMyLogFile& CMyLogFile::operator <<(double dVal)
  454. {
  455. strstream tmp;
  456. tmp << dVal;
  457. tmp << '\0';
  458. TCHAR* output = tmp.str();
  459. Output(output);
  460. tmp.freeze(false);
  461. return *this;
  462. }
  463. #ifdef _WIN32
  464. CMyLogFile& CMyLogFile::operator <<(u__int64_t unllVal)
  465. {
  466. strstream tmp;
  467. tmp << unllVal;
  468. tmp << '\0';
  469. TCHAR* output = tmp.str();
  470. Output(output);
  471. tmp.freeze(false);
  472. return *this;
  473. }
  474. #endif
  475. void CMyLogFile::LOGERROR(TCHAR* formatString, ...)
  476. {
  477. #ifdef RVC_OS_WIN
  478. Lock(INFINITE);
  479. Init();
  480. __try {
  481. if (NULL != m_cOutFile && !m_cOutFile->is_open())
  482. return;
  483. /*
  484. ** Insert the current time..
  485. */
  486. PrintCurTime();
  487. /*
  488. ** Parse the format string and write to the file
  489. */
  490. if (formatString == NULL) {
  491. /*
  492. ** No point in continuiing
  493. */
  494. return;
  495. }
  496. va_list argList;
  497. /*
  498. ** Set va_list to the beginning of optional arguments
  499. */
  500. va_start(argList, formatString);
  501. TCHAR* ptr = formatString;
  502. while (*ptr != '\0') {
  503. TCHAR* str = NULL;
  504. int nInteger = 0;
  505. unsigned int unInt = 0;
  506. long lLong = 0;
  507. unsigned long ulLong = 0;
  508. double dDoub = 0;
  509. u__int64_t ullLong = 0;
  510. if (*ptr == '%') {
  511. switch (*(ptr + 1)) {
  512. case 's':
  513. str = va_arg(argList, TCHAR*);
  514. if (NULL == str)
  515. break;
  516. *this << str;
  517. ptr++;
  518. break;
  519. case 'd':
  520. nInteger = va_arg(argList, int);
  521. *this << nInteger;
  522. ptr++;
  523. break;
  524. case 'u':
  525. unInt = va_arg(argList, unsigned int);
  526. *this << unInt;
  527. ptr++;
  528. break;
  529. case 'l':
  530. ptr++;
  531. if (*(ptr + 1) == 'd') {
  532. lLong = va_arg(argList, long);
  533. *this << lLong;
  534. ptr++;
  535. }
  536. else if (*(ptr + 1) == 'u') {
  537. ulLong = va_arg(argList, unsigned long);
  538. *this << ulLong;
  539. ptr++;
  540. }
  541. else if (*(ptr + 1) == 'q') {
  542. ullLong = va_arg(argList, u__int64_t);
  543. *this << ullLong;
  544. ptr++;
  545. }
  546. break;
  547. case 'f':
  548. dDoub = va_arg(argList, double);
  549. *this << dDoub;
  550. ptr++;
  551. break;
  552. default:
  553. *this << *ptr;
  554. }
  555. } // if(*ptr == '%')
  556. else {
  557. *this << *ptr;
  558. }
  559. /*
  560. ** Increment pointer..
  561. */
  562. ptr++;
  563. }
  564. va_end(argList); //va_end missing.
  565. *this << '\n';
  566. }
  567. __finally {
  568. Release();
  569. Unlock();
  570. }
  571. #else
  572. std::lock_guard<std::mutex> guard(g_mutex_4_log);
  573. Init();
  574. do
  575. {
  576. if (NULL != m_cOutFile && !m_cOutFile->is_open())
  577. break;
  578. PrintCurTime();
  579. if (formatString == NULL) {
  580. break;
  581. }
  582. va_list argList;
  583. va_start(argList, formatString);
  584. TCHAR* ptr = formatString;
  585. while (*ptr != '\0') {
  586. TCHAR* str = NULL;
  587. int nInteger = 0;
  588. unsigned int unInt = 0;
  589. long lLong = 0;
  590. unsigned long ulLong = 0;
  591. double dDoub = 0;
  592. u__int64_t ullLong = 0;
  593. if (*ptr == '%') {
  594. switch (*(ptr + 1)) {
  595. case 's':
  596. str = va_arg(argList, TCHAR*);
  597. if (NULL == str)
  598. break;
  599. *this << str;
  600. ptr++;
  601. break;
  602. case 'd':
  603. nInteger = va_arg(argList, int);
  604. *this << nInteger;
  605. ptr++;
  606. break;
  607. case 'u':
  608. unInt = va_arg(argList, unsigned int);
  609. *this << unInt;
  610. ptr++;
  611. break;
  612. case 'l':
  613. ptr++;
  614. if (*(ptr + 1) == 'd') {
  615. lLong = va_arg(argList, long);
  616. *this << lLong;
  617. ptr++;
  618. }
  619. else if (*(ptr + 1) == 'u') {
  620. ulLong = va_arg(argList, unsigned long);
  621. *this << ulLong;
  622. ptr++;
  623. }
  624. else if (*(ptr + 1) == 'q') {
  625. ullLong = va_arg(argList, u__int64_t);
  626. *this << ullLong;
  627. ptr++;
  628. }
  629. break;
  630. case 'f':
  631. dDoub = va_arg(argList, double);
  632. *this << dDoub;
  633. ptr++;
  634. break;
  635. default:
  636. *this << *ptr;
  637. }
  638. } // if(*ptr == '%')
  639. else {
  640. *this << *ptr;
  641. }
  642. /*
  643. ** Increment pointer..
  644. */
  645. ptr++;
  646. }
  647. va_end(argList); //va_end missing.
  648. *this << '\n';
  649. } while (false);
  650. Release();
  651. #endif // RVC_OS_WIN
  652. }