2015. 11. 24. 17:35

Linux/gcc에서 CStringA MFC Class 사용하기

LinuxCStringA.zip

CStringA는 MFC/ATL Class로, gcc를 사용하는 Linux에서는 컴파일할 수 없습니다. 그래서 만일, CStringA 기반으로 작성된 코드를 Linux에서 compile하려면, 추가 - 작업 - 이 필요할 수 있습니다. 이러한 불편을 줄이고자, LinuxCStringA.h를 공유(GPL 3.0, No commercial)로 공유합니다. (상업적 용도로 사용시, 댓글로 요청 바람. 큰 이견 없다면 사용 허락 부여함)


현재 CStringA, 즉, char만 허용되는데, wchar_t 즉, WCHAR에 해당되는 CString은 지원하지 않았습니다. 왜냐하면, wchar_t가 Windows/Linux의 크기가 달라, 자칫 one-source로 compile은 되더라도, 혹시나 모를 실행시의 이슈가 발생할 소지가 있기 때문입니다. 그래서, one-source로 CString을 사용하려면, ANSI만 사용하라, 라고 강제화 시킨 겁니다(사실, Windows에서는 MBCS, Linux에서는 UTF-8이 사용되겠지만서도요...).


std string으로 CStringA를 흉내낸 것인데, 주로 사용하는 CStringA 함수만 추가하였습니다. 혹시나, AppendFormat등을 사용하셨다면, 직접 구현하셔야 할 겁니다. 미리 만들어놓은 틀이 있으니, 수정하는데에는 큰 어려움은 없을 것으로 보여집니다.


std string으로 흉내낸 것이라 했는데, 이는, Windows에서도 사용 가능하다라는 말도 됩니다. LinuxCStringA에서 _MSC_VER를 체크하여, Windows라면 <atlstr.h>를 include하고 종료하는데, 만일, ATL/MFC를 사용하지 않고, std만 가지고 코딩하시는 경우에는, 해당 line을 주석처리하면 해결되리라 봅니다.


LinuxCStringA.zip은 Visual Studio Project인데, linux에서는,

$ g++ stl_string.cpp

와 같이 compile하면 되며,

$ ./a.out
<BASIC>
0: ABCD
1: 1
2: 0
3: 1
4: ABCD_1234
5: 0
6: 1
7: 4

<Delete>
8: 4
9: ABCD
10: 3
11: BCD
12: 1
13: D

<Find>
14: 4
15: 4
16: 4
17: -1
18: -1
19: 4
20: 4
21: 4
22: -1
23: -1
24: -1

<Insert>
25: 11
26: *_ ABCD RRR
27: 12
28: *_ ABCD RRR$
29: 5

<Mid>
30:  ABCD RRR$
31:
32:  AB
33:

<Replace>
34: 1
35: *_ aBCD RRR$
36: 1
37: *_ aBcd RRR$
38: 0
39: *_ aBcd RRR$
40: 3
41: *_ aBcd rrr$

<Format>
42: 04d2>>>>>01234>>>>>hello,world
43: ABCD RRR
44: _ ABCD
$
 

와 같이 Windows(ATL의 CStringA), Linux(LinuxCStringA.h) 모두 동일한 결과가 나왔음을 확인하였습니다.

사용은,

#include "LinuxCStringA.h"

...

CStringA strTmp;

... 

와 같이 사용하면 되며, Windows/Linux 관련없이 CStringA를 사용할 수 있습니다.

앞서 얘기한바대로, 해당 .h은 GPL 3.0 with no commercial이니, 주의하시기 바랍니다.


Source

#pragma once

/*
http://www.gnu.org/licenses/gpl-3.0.html

LinuxCStringA, LinuxCStringA.h
Copyright (C) 2015-11-24  greenfish @ gmail.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

And,
No Commercial only,
If you want to use it commercially, contact to author.
*/

#ifdef _MSC_VER
// VC로 compile하는 경우에는 CAtlStringA, 즉, CStringA를 사용하도록 한다.
#include <atlstr.h>
#else
// gcc로 compile하는 경우에는 아래 Class를 참고하도록 한다.
#include <string>
#include <vector>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

class CStringA
{
public:
	CStringA(void) { };
	~CStringA(void) { };

public:
	CStringA(const CStringA& obj)		{m_str = obj.m_str;}
	void operator=(const CStringA& obj)	{m_str = obj.m_str;}
	void operator=(const char* p)		{if (NULL != p) m_str = p;}
	CStringA& operator+=(const char* p)	{if (NULL != p) m_str += p; return (*this);}
	friend CStringA operator+(const CStringA& str1, const char* psz2 )
	{CStringA r; r.m_str=str1.m_str; if (NULL != psz2) {r.m_str = r.m_str + psz2;} return r;}
	bool operator==(const char* p)		{return (m_str.compare(p) == 0);}
	operator const char*()			{return m_str.c_str();}
	int GetLength(void)			{return m_str.length();}
	bool IsEmpty()				{return(GetLength()==0);}
	int Find(const char* pszSub, int iStart=0)	{if (NULL == pszSub) return -1; return m_str.find(pszSub, iStart);}
	int Find(const char ch, int iStart=0)	{return m_str.find(ch, iStart);}

	CStringA Mid(int iFirst, int nCount)
	{
		CStringA r; 
		try
		{
			r.m_str = m_str.substr(iFirst, nCount); 
		}
		catch(...)
		{
		}
		return r;
	}

	CStringA Mid(int iFirst)
	{
		CStringA r; 
		try
		{
			r.m_str = m_str.substr(iFirst); 
		}
		catch(...)
		{
		}
		return r;
	}
	
	int Delete(int iIndex, int nCount = 1)
	{
		try
		{
			m_str.erase(iIndex, nCount); 
		}
		catch(...)
		{
		}
		return m_str.length();
	}

	int Insert(int iIndex, const char* psz)
	{
		try
		{
			if (NULL != psz) m_str.insert(iIndex, psz); 
		}
		catch(...)
		{
			m_str += psz;
		}

		return m_str.length();
	}

	int Insert(int iIndex, char ch)
	{
		try
		{
			m_str.insert(iIndex, 1, ch); 
		}
		catch(...)
		{
			m_str += ch;
		}
		return m_str.length();
	}

	CStringA& TrimRight(char chTarget)
	{
		size_t l = 0;
		l = m_str.length();

		for (;;)
		{
			if (0 == l) break;

			if (m_str[l-1] != chTarget)
			{
				break;
			}
			else
			{
				m_str.erase(l-1, 1);
				l--;
			}
		}

		return (*this);
	}

	CStringA& TrimRight(const char* pszTargets)
	{
		size_t l = 0;

		if (NULL == pszTargets) return (*this);

		l = m_str.length();

		for (;;)
		{
			if (0 == l) break;

			if (NULL == strchr(pszTargets, m_str[l-1]))
			{
				break;
			}
			else
			{
				m_str.erase(l-1, 1);
				l--;
			}
		}

		return (*this);
	}

	CStringA& TrimLeft(char chTarget)
	{
		for (;;)
		{
			if (m_str[0] != chTarget)
			{
				break;
			}
			else
			{
				m_str.erase(0, 1);
			}
		}

		return (*this);
	}

	CStringA& TrimLeft(const char* pszTargets)
	{
		if (NULL == pszTargets) return (*this);

		for (;;)
		{
			if (NULL == strchr(pszTargets, m_str[0]))
			{
				break;
			}
			else
			{
				m_str.erase(0, 1);
			}
		}

		return (*this);
	}

	int Replace(const char* pszOld, const char* pszNew)
	{
		int r = 0;
		size_t l = 0;
		std::string::size_type offset = 0;

		if ((NULL == pszOld) || (NULL == pszNew)) return 0; 

		for (;;)
		{
			offset = m_str.find(pszOld, offset);

			if (std::string::npos == offset) 
			{
				break;
			}
			else
			{
				if (0 == l)
				{
					l = strlen(pszOld);
					if (0 == l) return 0;
				}
				m_str.replace(offset, l, pszNew);
				offset += l;
				r++;
			}
		}
		return r;
	}

	void Format(const char* pszFormat, ...)
	{
		int		len	= 0;
		va_list	vl;

		va_start(vl, pszFormat);

		// 포맷의 길이를 구한다.
#if (_MSC_VER >= 1400)	// Visual studio 2005 이상
		len = _vscprintf(pszFormat, vl) + 1;
#else
		len = vsnprintf(NULL, 0, pszFormat, vl) + 1;
#endif

		// 버퍼의 크기를 조정한다.
		m_str.resize(len, '\0');

		// 포맷을 적용한다.
		va_start(vl, pszFormat);
#if (_MSC_VER >= 1400)	// Visual studio 2005 이상
		if (vsnprintf_s(&m_str[0], len, _TRUNCATE, pszFormat, vl) > len)
#else
		if (vsnprintf(&m_str[0], len, pszFormat, vl) > len)
#endif
		{
			// Error
		}
		va_end(vl);
	}

protected:
	std::string m_str;
};
#endif