새해 기념으로 올립니다.
플렛폼 독립적인 심플 String , TStringList 클래스와 함수입니다.
모든 C++ 컴파일러에서 쓸수 있습니다.
#ifndef __BCSysClass
#define __BCSysClass
//---------------------------------------------------------------------------
// 시스템 유틸리티 클래스
// --------------------------------------------------------------------------
// 제작목적:
// 이미 익숙한 String 과 TStringList 등의 빌더 클래스와 함수를 이용하여 프로그램하고 싶은데,
// 지원되지 않은 환경에서 사용하기 위해 만듦.
// 또한, 기존 소스를 수정하는 노력을 취소로하여 옮기기 위해.
// 윈도우 환경에서 만든 기능을 순수도스용 프로그램으로 바꿀려니.. 거의 쓸수 있는 클래스/함수가 없어 허걱 했음. 그래서 만듦.
//
// 구현 클래스/함수:
// AnsiString, String
// TStringList
// ExtractFileName
// ExtractFilePath
// FileExists
//
// Written by 김태성(jsdkts@korea.com), Open Source.
//
// 날짜 설명 (update history)
// --------------------------------------------------------------------------
// 2006-01-01 첫버전 제작. 메모리 누수없음. 더 필요한 기능은 추가해서 쓰세요. ^^;
//---------------------------------------------------------------------------
namespace BCSysClass
{
typedef char byte;
#define ZeroMemory(a,b) memset(a, 0, b)
// 순수 도스에서 사용하기 위한 String 클래스
// 원래 C++Builder에 있는 AnsiString을 순수 도스나 VC++에서 이용하기 위해 몇가지 기능만 구현함.
// 일부 동작이 표준 AnsiString과는 약간 틀리나 대략 비슷하게 사용할수 있음.
class String
{
enum { BUFFER_SIZE = 4097 }; // 4k 문자열 임시 버퍼.
private:
char *Data;
public:
String()
{
Data = NULL;
}
String(char *str)
{
if (*str == 0 || str == NULL)
Data = NULL;
else
{
Data = new char[strlen(str)+1];
strcpy(Data, str);
}
}
String(String& str)
{
if (str.Length() == 0)
Data = NULL;
else
{
Data = new char[str.Length()+1];
strcpy(Data, str.c_str());
}
}
String(char ch, int len) // 원래 AnsiString에는 없으나, 문자열공간 선확보 목적으로 신설.
{
if (len > 0)
{
Data = new char[len+1];
memset(Data, ch, len+1);
}
else
Data = NULL;
}
~String()
{
if (Data)
{
delete[] Data; Data = NULL;
}
}
int Length()
{
if (Data == NULL) return 0;
return strlen(Data);
}
char *c_str()
{
return Data;
}
String& operator=(char *str)
{
if (Data)
{
delete[] Data; Data = NULL;
}
if (strlen(str) > 0)
{
Data = new char[strlen(str) + 1];
strcpy(Data, str);
}
return *this;
}
String& operator=(String str)
{
if (Data)
{
delete[] Data; Data = NULL;
}
if (str.Length() > 0)
{
Data = new char[str.Length() + 1];
strcpy(Data, str.c_str());
}
return *this;
}
String& SubString(int pos, int len)
{
if (pos == 0) return *this; // 위치 인덱스는 1부터
String *ps = new String(0, len);
strncpy(ps->c_str(), Data + pos - 1, len); // 끝에 자동초기화된 0가 있으므로.
return *ps;
}
// String().sprintf("%d %s", a, b); 식으로도 사용가능하게 하기 위해.
String& sprintf(const char* format, ...)
{
char buffer[BUFFER_SIZE];
va_list args;
va_start(args, format);
int len = vsprintf(buffer, format, args);
va_end(args);
if (len == EOF)
len = 0; // throw "vsprintf의 변환 에러";
String *ps = new String(0, len);
strcpy(ps->c_str(), buffer);
return *ps;
}
int printf(const char* format, ...)
{
char buffer[BUFFER_SIZE];
va_list args;
va_start(args, format);
int len = vsprintf(buffer, format, args);
va_end(args);
if (len == EOF)
return 0;
if (Data)
{
delete Data; Data = NULL;
}
if (len > 0)
{
Data = new char[len + 1];
strcpy(Data, buffer);
}
return len;
}
};
typedef String AnsiString;
// 순수 도스에서 사용하기 위해 TStringList를 간편하게 새롭게 만들었다.
// 원래 TObject를 상속한 VCL스타일 클래스이나 이것은 아무것도 상속하지 않았다.
// 간편하게 사용할 목적이므로 에러 체크를 안한다.
class TStringList
{
// MAX_LINE * 4 만큼 스트링 포인트 테이블로 소요.
// 원래 한줄당 인스턴스용 메모리를 할당받아야 하나, 간편하게 구현하기 위해.
enum { MAX_LINE = 10000 };
private:
int Max;
public:
int Count;
String *Strings;
public:
TStringList(int max = MAX_LINE)
{
ZeroMemory(this, sizeof(*this));
Max = max;
Strings = new String[max]; // 생성자에서 자동 0로 모두 초기화된다.
}
~TStringList()
{
delete[] Strings;
}
int Add(String str)
{
if (Count + 1 >= Max)
throw "TStringList 인덱스값 초과"; // over
Strings[Count] = str;
return Count++;
}
void Delete(int index)
{
if (index >= Count)
return;
if (Strings[index].Length() > 0)
delete (Strings + index);
memcpy(Strings + index, Strings + index + 1, sizeof(String) * (Max - index - 1));
ZeroMemory(Strings + Max-1, sizeof(String));
Count--;
}
String& operator[](int index)
{
return Strings[index];
}
};
String ExtractFilePath(String filename)
{
int len = filename.Length();
char *p = filename.c_str();
for(int c = 0; c < len; c++)
{
char ch = p[len-c-1];
if (ch == '\\' || ch == ':')
{
return filename.SubString(1, len - c);
}
}
return "";
}
String ExtractFileName(String filename)
{
int len = filename.Length();
char *p = filename.c_str();
for(int c = 0; c < len; c++)
{
char ch = p[len-c-1];
if (ch == '\\' || ch == ':')
{
String name = (p + len - c);
return name;
}
}
return filename;
}
bool FileExists(String filename)
{
FILE *fp = fopen(filename.c_str(), "rb");
bool b = fp;
if (fp)
fclose(fp);
return b;
}
}; // name space BCSysClass
#endif
사용할 때는
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dir.h>
대략 이정도는 해주시고..
//---------------------------------------------------------------------------
// 유닛
//---------------------------------------------------------------------------
using namespace BCSysClass;
로 네임스페이스 참조를 해줘야 합니다.
일단, 제가 만든 도스 프로그램을 이 헤더만 포함해서 아무런 컨버팅없이 돌려보니, 잘 되는군요.
메모리 누수가 발생하는지 체크해봤는데 누수없이 잘 돌아갑니다.
너무 간단하게 만들었기 때문에, 구현하지 않은 기능이 많습니다. 필요한 기능을 추가하는 것은 별로 어려운 일이 아니라 생각됩니다.
혹시 모를 버그도 있을수 있으니 그건 리플을 달아주시면 좋겠습니다.
소스를 공개하므로 알아서 개선해 쓰셔도 좋을것 같군요.
참고로 원래 빌더에서 지원하는 String 클래스나 TStringList 등의 클래스는 콘솔프로그램에서도 사용할 수 있습니다.
하지만, 콘솔일뿐 win32 응용프로그램의 일부이며, 순수한 도스용 프로그램 제작을 지원하지 않습니다.
|
파일명을 SysClass.h 로 고치고
namespace 는 제거하고
typedef int bool;
enum { false, true };
를 해줘야 합니다. 오래된 C++ 규정이라서 제한이 좀 있습니다.
소스중에 bool b = fp 는
bool b = fp ? true: false;
로 조금 고쳐야 합니다.