Files
RepoMain/ZCppMain/ZMainHeadEx.H

7526 lines
275 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef __ZCPPMAIIN__MAINHEAD_EX_H__
#define __ZCPPMAIIN__MAINHEAD_EX_H__
#ifndef _NO_USE_REEDDIR_R_
/* readdir_r() 함수가 실은 thread-safe 하지 않다고
해서 폐기되었다. -- 2025-09-07 14:55
*/
#define _NO_USE_REEDDIR_R_
#endif // !_NO_USE_REEDDIR_R_
#include<ctime>
#include<fstream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include "ZCppMain/ZtCMainChars.H"
/* cf) #define OPEN_MAX 32 in <limit.h>
OPEN_MAX is max file numbers to open */
#ifdef __linux__
#include<unistd.h> // <unistd.h>(In Linux) == <direct.h> + <io.h> + ... (In Visual C++ 6.0)
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<sys/uio.h>
#include<aio.h>
#ifndef _T
#define _T(x) x
#endif
#elif defined(__sun__) // In Solaris
#include<unistd.h> // <unistd.h>(In Linux) == <direct.h> + <io.h> + ... (In Visual C++ 6.0)
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<sys/uio.h>
#ifndef _T
#define _T(x) x
#endif
#elif defined(_WIN)
#include<io.h>
#include<direct.h>
#include<windows.h> // for Win32 API
#ifndef _T
#define _T(x) TEXT(x)
#endif
#pragma comment(lib, "ws2_32") // ws2_32.lib 를 링크한다.
#else // 기본적으로 UNIX 계열이라고 간주한다.
#include<unistd.h> // <unistd.h>(In Linux) == <direct.h> + <io.h> + ... (In Visual C++ 6.0)
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<sys/uio.h>
#ifndef _T
#define _T(x) x
#endif
#endif
#ifndef _MAX_DIR
#define _MAX_DIR 512*2 // For unix.
#endif
using namespace std ;
using namespace ZNsMain;
/*/////////////////////////////////////////////////////////////////////////////
■ char* ctime ( const time_t *timer );
wchar_t* _wctime( const time_t *timer );
Routine Required Header Compatibility
ctime <time.h> ANSI, Win 95, Win NT
_wctime <time.h> or <wchar.h> Win 95, Win NT
For additional compatibility information, see Compatibility in the Introduction.
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
Return Value
Each of these functions returns a pointer to the character string result.
If time represents a date before midnight, January 1, 1970, UTC, the function returns NULL.
■ time_t mktime( struct tm *timeptr ); ***
Routine Required Header Compatibility
mktime <time.h> ANSI, Win 95, Win NT
For additional compatibility information, see Compatibility in the Introduction.
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
Return Value
mktime returns the specified calendar time encoded as a value of type time_t.
If timeptr references a date before midnight, January 1, 1970,
or if the calendar time cannot be represented, the function returns ?1 cast to type time_t.
Remarks
The mktime function converts the supplied time structure (possibly incomplete)
pointed to by timeptr into a fully defined structure with normalized values
and then converts it to a time_t calendar time value.
For description of tm structure fields, see asctime.
The converted time has the same encoding as the values returned by the time function.
The original values of the tm_wday and tm_yday components of the timeptr structure are ignored,
and the original values of the other components are not restricted to their normal ranges.
mktime handles dates in any time zone
from midnight, January 1, 1970, to January 18, 19:14:07, 2038.
If successful, mktime sets the values of tm_wday and tm_yday as appropriate
and sets the other components to represent the specified calendar time,
but with their values forced to the normal ranges;
the final value of tm_mday is not set
until tm_mon and tm_year are determined.
When specifying a tm structure time,
set the tm_isdst field to 0 to indicate that standard time is in effect,
or to a value greater than 0 to indicate that daylight savings time is in effect,
or to a value less than zero to have the C run-time library code compute
whether standard time or daylight savings time is in effect.
(The C run-time library assumes the United Statess rules for implementing the calculation of Daylight Saving Time).
tm_isdst is a required field.
If not set, its value is undefined and the return value from mktime is unpredictable.
If timeptr points to a tm structure returned by a previous call to asctime, gmtime, or localtime,
the tm_isdst field contains the correct value.
Note that gmtime and localtime use a single statically allocated buffer for the conversion.
If you supply this buffer to mktime, the previous contents are destroyed.
struct tm
{
int tm_sec ; // seconds after the minute - [0,59]
int tm_min ; // minutes after the hour - [0,59]
int tm_hour ; // hours since midnight - [0,23]
int tm_mday ; // day of the month - [1,31]
int tm_mon ; // months since January - [0,11]
int tm_year ; // years since 1900
int tm_wday ; // days since Sunday - [0,6]
int tm_yday ; // days since January 1 - [0,365]
int tm_isdst; // daylight savings time flag
};
■ --
/////////////////////////////////////////////////////////////////////////////*/
namespace ZNsMain
{
#if defined(_WIN)
/*////////////////////////////////////////////////////////////////////////////
■ AI_SleepMiliSec 초 동안 잠든다. 1 mili 초를 지정하면 실제로 1 mili 초간 잠
드는 것이 아니라 약 16 mili 초 정도 잠든다. 이것은 10 mili 초를 지정하는 것
과 비슷하다(Window 2003, zeon 3.2, Ram 1G). 비슷한 사양의 리눅스에서 1 mili
초를 지정하면 약 4 mili 초 정도를 소요한다.
////////////////////////////////////////////////////////////////////////////*/
inline void ZfSuspendExec(int AI_SleepMiliSec)
{
::Sleep(AI_SleepMiliSec);
}/*
inline void ZfSuspendExec(int AI_SleepMiliSec)*/
/*///////////////////////////////////////////////////
■ errno_t _putenv_s(
const char *name,
const char *value
);
errno_t _wputenv_s(
const wchar_t *name,
const wchar_t *value
);
※ int _putenv(const char*) 함수가 있는데 "변수명=변수값" 형태로 넘긴다.
이 함수보다 좀 더 안전한 함수가 _putenv_s() 이다.
※ The _putenv_s and _getenv_s families of functions are not thread-safe.
_getenv_s could return a string pointer
while _putenv_s is modifying the string, causing random failures.
Make sure that calls to these functions are synchronized.
_putenv_s 과 _getenv_s 류의 함수는 쓰레드에 안전하지 않다.
_putenv_s 과 _getenv_s 을 서로 다른 스레드에서 동시에 사용하는 경우
_getenv_s 는 수정중인 문자열 포인터를 반환할 수 있다.
///////////////////////////////////////////////////*/
inline bool ZfPutEnv(const char* APC_EnvName, const char* APC_Value)
{
#if __VISUAL_CPP_VER__>=200500
return ::_putenv_s(APC_EnvName, APC_Value)==0;
#else //__VISUAL_CPP_VER__<=200500
std::string VO_CStringEnv;
VO_CStringEnv+=APC_EnvName;
VO_CStringEnv+="=" ;
VO_CStringEnv+=APC_Value ;
return ::_putenv(VO_CStringEnv.data())==0;
#endif //__VISUAL_CPP_VER__<200500
}/*
inline bool ZfPutEnv(const char* APC_EnvName, const char* APC_Value)*/
inline bool ZfPutEnv(const char* APC_EnvData)
{
return ::_putenv(APC_EnvData)==0;
}/*
inline bool ZfPutEnv(const char* APC_EnvData)*/
inline long ZfWriteStdOut(LPCVOID APC_Buffer, DWORD ADW_BuffSize, LPOVERLAPPED AP_Overlapped=NULL)
{
// 표준 출력에 쓴다.
DWORD VDW_WrittenSize= 0 ;
const bool CB_IsOK = ////////////////////////////////////////
(
::WriteFile
(
::GetStdHandle(STD_OUTPUT_HANDLE), APC_Buffer
, ADW_BuffSize , &VDW_WrittenSize
, AP_Overlapped
)==TRUE
);
///////////////////////////////////////////////////////////////
if(CB_IsOK==false) return -1; return VDW_WrittenSize;
}/*
inline long ZfWriteStdOut(LPCVOID APC_Buffer, DWORD ADW_BuffSize, LPOVERLAPPED AP_Overlapped=NULL)*/
template<typename TString>
inline long ZfWriteStdOut(TString& AR_CStringOut, LPOVERLAPPED AP_Overlapped=NULL)
{
return ZfWriteStdOut(AR_CStringOut.c_str(), AR_CStringOut.size(), AP_Overlapped);
}/*
template<typename TString>
inline long ZfWriteStdOut(TString& AR_CStringOut, LPOVERLAPPED AP_Overlapped=NULL) */
inline long ZfReadStdIn(LPVOID AP_Buff, DWORD ADW_BuffSize, LPOVERLAPPED AP_Overlapped=NULL)
{
// 표준입력으로 부터 데이타를 읽는다.
// 에러이면 -1 을 그렇지 않으면 읽은 길이를 반환한다.
DWORD VDW_ReadCnt =0 ;
const bool CB_IsOK = /////////////////////////////////
(
::ReadFile
(
::GetStdHandle(STD_INPUT_HANDLE), AP_Buff,
ADW_BuffSize, &VDW_ReadCnt, AP_Overlapped
)==TRUE
);
//////////////////////////////////////////////////////
if(CB_IsOK==false) return -1; return VDW_ReadCnt;
}/*
inline long ZfReadStdIn(LPVOID AP_Buff, DWORD ADW_BuffSize, LPOVERLAPPED AP_Overlapped=NULL)*/
template<typename TString> long ZfReadStdIn(
TString& ARR_CStringRead, LPOVERLAPPED AP_Overlapped=NULL)
{
ZTycInt CI_StdBuffSize = 512 ;
if(ARR_CStringRead.size()<1)
ARR_CStringRead.resize(CI_StdBuffSize, ' ');
DWORD VDW_ReadCnt = 0 ;
const bool CB_IsOK = ///////////////////////
(
::ReadFile
(
::GetStdHandle(STD_INPUT_HANDLE)
, ARR_CStringRead.data()
, ARR_CStringRead.size()
, &VDW_ReadCnt, AP_Overlapped
)==TRUE
);
////////////////////////////////////////////
if(CB_IsOK==false)
{
ARR_CStringRead=""; return -1;
}/*
if(CB_IsOK==false)*/
ARR_CStringRead.resize(VDW_ReadCnt,' '); return VDW_ReadCnt;
}/*
template<typename TString> long ZfReadStdIn(
TString& ARR_CStringRead, LPOVERLAPPED AP_Overlapped=NULL) */
#else // !defined(_WIN)
/*/////////////////////////////////////////////////////////////////////////////////////////////
■ std::SleepExec(int) 함수가 이미 glibc 확장에 있다.
■ ZfSuspendExec() 함수는 uslee() 함수를 이용하여 쉬는데, 쉬는 시간이 너무 크면
(1 초 이상이면)오류라는 뜻에서 음수를 반환하는 경우가 있다. '(주)인트라코어'의
취약점 진단 프로젝트를 하는데, KT 의 HP-UX(115.21.49.211) 가 그랬다.
uname -a 정보는
HP-UX sechpux B.11.11 U 9000/800 1106484218 unlimited-user license
gcc -v 정보는
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/opt/hp-gcc-4.6.2/libexec/gcc/hppa1.1-hp-hpux11.11/4.6.2/lto-wrapper
Target: hppa1.1-hp-hpux11.11
Configured with: /tmp/gcc-4.6.2.tar.gz/gcc-4.6.2/configure --host=hppa1.1-hp-hpux11.11
--target=hppa1.1-hp-hpux11.11 --build=hppa1.1-hp-hpux11.11 --prefix=/opt/hp-gcc-4.6.2
--with-gnu-as --without-gnu-ld --enable-threads=posix --enable-languages=c,c++
--with-gmp=/proj/opensrc/be/hppa1.1-hp-hpux11.11
--with-mpfr=/proj/opensrc/be/hppa1.1-hp-hpux11.11 SED=/usr/bin/sed
Thread model: posix
gcc version 4.6.2 (GCC)
그래서 성공(0)을 반환하지 않으면, 500 밀리초 씩 쉬는 것으로 했다.
-- 2012-04-01 21:35:00
/////////////////////////////////////////////////////////////////////////////////////////////*/
inline void ZfSuspendExec(int AI_SleepMiliSec)
{
if(::usleep(AI_SleepMiliSec*1000)==0) return;
int VI_SleepSec =AI_SleepMiliSec/1000 ;
int VI_ExtraMili=AI_SleepMiliSec%1000 ;
for(int i=0; i<VI_SleepSec; ++i)
{
// 1 초를 500 밀리초씩 2 번 나누어 쉰다.
::usleep(1000*500);
::usleep(1000*500);
}/*
for(int i=0; i<VI_SleepSec; ++i)*/
if(VI_ExtraMili>0) ::usleep(1000*VI_ExtraMili);
}/*
inline void ZfSuspendExec(int AI_SleepMiliSec)*/
/*///////////////////////////////////////////////////
■ setenv - 환경 변수를 바꾸거나 추가시킨다.
#include <stdlib.h>
int setenv(const char *name, const char *value, int overwrite);
void unsetenv(const char *name);
setenv() 함수는만일 name이 이미 존재하지 않는다면,
값 value를 가지고 있는 환경 변수 name을 추가시킨다.
만일 name가 환경 변수에 존재한다면, overwrite가 0 이 아니라면 그 값은 value로 바뀐다.
만일 overwrite가 0 이라면, name의 값은 바뀌지 않는다.
unsetenv() 함수는 환경 변수에서 변수 name 를 지운다.
setenv() 함수는 성공시 0 을 반환하거나,
만일 환경 변수에 공간이 충분하지 않다면 -1을 반환한다.
■ 미리 정의된 파일핸들 상수
0 : 표준입력 파일핸들
1 : 표준출력 파일핸들
2 : 표준에러 파일핸들
///////////////////////////////////////////////////*/
inline bool ZfPutEnv(const char* APC_EnvName, const char* APC_Value)
{
return ::setenv(APC_EnvName, APC_Value, 1)==0;
}/*
inline bool ZfPutEnv(const char* APC_EnvName, const char* APC_Value)*/
inline bool ZfPutEnv(const char* APC_EnvData) // "변수명=변수값"
{
return ::putenv(const_cast<char*>(APC_EnvData))==0;
}/*
inline bool ZfPutEnv(const char* APC_EnvData) // "변수명=변수값"*/
inline ssize_t ZfWriteStdOut(const void* APC_Buffer, ZTypLength AI_BuffSize)
{
return ::write(1, APC_Buffer, AI_BuffSize);
}/*
inline ssize_t ZfWriteStdOut(const void* APC_Buffer, ZTypLength AI_BuffSize)*/
template<typename TString>
inline ssize_t ZfWriteStdOut(TString& AR_CStringOut)
{
return ZfWriteStdOut(AR_CStringOut.c_str(), AR_CStringOut.size());
}/*
template<typename TString>
inline ssize_t ZfWriteStdOut(TString& AR_CStringOut) */
inline ssize_t ZfReadStdIn(void* AP_Buff, size_t AI_Count)
{
return ::read(0,AP_Buff,AI_Count);
}/*
inline ssize_t ZfReadStdIn(void* AP_Buff, size_t AI_Count)*/
template<typename TString> ssize_t ZfReadStdIn(TString& ARR_CStringRead)
{
ZTycInt CI_StdBuffSize=512;
if(ARR_CStringRead.size()<1)
ARR_CStringRead.resize(CI_StdBuffSize,' ');
ssize_t VI_ReadSize = ::read
( 0, ARR_CStringRead.c_str(), ARR_CStringRead.size() );
if(VI_ReadSize<=0)
{
ARR_CStringRead=""; return VI_ReadSize;
}/*
if(VI_ReadSize<=0)*/
ARR_CStringRead.resize(VI_ReadSize,' '); return VI_ReadSize;
}/*
template<typename TString> ssize_t ZfReadStdIn(TString& ARR_CStringRead) */
#endif // !defined(_WIN)
/*////////////////////////////////////////////////////////////////////////
■ ** IN time.h **
typedef struct tm
{
int tm_hour ; // hour (0 - 23)
int tm_isdst; // daylight saving time enabled/disabled
int tm_mday ; // day of month (1 - 31)
int tm_min ; // minutes (0 - 59)
int tm_mon ; // month (0 - 11 : 0 = January), 1 을 더한 값이 월이다.
int tm_sec ; // seconds (0 - 59)
int tm_wday ; // Day of week (0 - 6 : 0 = Sunday)
int tm_yday ; // Day of year (0 - 365), 1 을 더한 값이 그 해의 이 시점의 날수다.
int tm_year ; // Year less 1900, 1900 을 더한 값이 년도다.
}
■ ** timespec IN time.h **
SYNOPSIS
-- 아래 함수를 사용하면 Linux 에서도 초 단위보다 정밀한 시간을 구할 수 있다.
#include <time.h>
int clock_getres(clockid_t clk_id, struct timespec *res);
int clock_gettime(clockid_t clk_id, struct timespec *tp);
int clock_settime(clockid_t clk_id, const struct timespec *tp);
Link with -lrt.
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
clock_getres(), clock_gettime(), clock_settime(): _POSIX_C_SOURCE >= 199309L
DESCRIPTION
The function clock_getres() finds the resolution (precision) of the specified clock
clk_id, and, if res is non-NULL, stores it in the struct timespec pointed to by res.
The resolution of clocks depends on the implementation and cannot be configured by a
particular process. If the time value pointed to by the argument tp of clock_settime()
is not a multiple of res, then it is truncated to a multiple of res.
The functions clock_gettime() and clock_settime() retrieve and set the time of the
specified clock clk_id.
The res and tp arguments are timespec structures, as specified in <time.h>:
struct timespec {
time_t tv_sec ; // seconds
long tv_nsec; // nanoseconds
};
The clk_id argument is the identifier of the particular clock on which to act. A clock
may be system-wide and hence visible for all processes, or per-process if it measures
time only within a single process.
All implementations support the system-wide real-time clock, which is identified by
CLOCK_REALTIME. Its time represents seconds and nanoseconds since the Epoch. When its
time is changed, timers for a relative interval are unaffected, but timers for an abso-
lute point in time are affected.
More clocks may be implemented. The interpretation of the corresponding time values
and the effect on timers is unspecified.
Sufficiently recent versions of glibc and the Linux kernel support the following
clocks:
-- clk_id 은 아래 값 중 하나다 --
CLOCK_REALTIME
System-wide real-time clock. Setting this clock requires appropriate privi-
leges.
CLOCK_REALTIME_COARSE (since Linux 2.6.32; Linux-specific)
A faster but less precise version of CLOCK_REALTIME. Use when you need very
fast, but not fine-grained timestamps.
CLOCK_MONOTONIC
Clock that cannot be set and represents monotonic time since some unspecified
starting point.
CLOCK_MONOTONIC_COARSE (since Linux 2.6.32; Linux-specific)
A faster but less precise version of CLOCK_MONOTONIC. Use when you need very
fast, but not fine-grained timestamps.
CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time
that is not subject to NTP adjustments.
CLOCK_PROCESS_CPUTIME_ID
High-resolution per-process timer from the CPU.
CLOCK_THREAD_CPUTIME_ID
Thread-specific CPU-time clock.
RETURN VALUE
clock_gettime(), clock_settime() and clock_getres() return 0 for success, or -1 for
failure (in which case errno is set appropriately).
ERRORS
EFAULT tp points outside the accessible address space.
EINVAL The clk_id specified is not supported on this system.
EPERM clock_settime() does not have permission to set the clock indicated.
■ ** IN LINUX **
struct timeval
{
time_t tv_sec ; // seconds
suseconds_t tv_usec; // microseconds
};
struct timezone
{
int tz_minuteswest; // minutes W of Greenwich
int tz_dsttime; // type of dst correction
};
■ ** IN Window **
typedef struct _SYSTEMTIME
{
WORD wYear ;
WORD wMonth ;
WORD wDayOfWeek;
WORD wDay ;
WORD wHour ;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
wYear
The year. The valid values for this member are 1601 through 30827.
wMonth
The month. This member can be one of the following values.Value Meaning
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
wDayOfWeek
The day of the week. This member can be one of the following values. Value Meaning
0 Sunday
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
wDay
The day of the month. The valid values for this member are 1 through 31.
wHour
The hour. The valid values for this member are 0 through 23.
wMinute
The minute. The valid values for this member are 0 through 59.
wSecond
The second. The valid values for this member are 0 through 59.
wMilliseconds
The millisecond. The valid values for this member are 0 through 999.
void GetSystemTime(LPSYSTEMTIME lpSystemTime);
■ time_t time ( time_t *timer);
__time32_t _time32(__time32_t *timer); // In Only Window
__time64_t _time64(__time64_t *timer); // In Only Window
Return the time as seconds elapsed since midnight, January 1, 1970. There is no error return.
1970 년 1월 1일 0시 이후 경과한 시간을 초로 나타낸다.
linux 64 bit 에서 time_t 는 8 바이트이다.
////////////////////////////////////////////////////////////////////////*/
/*////////////////////////////////////////////////////////////////////////
■ class ZCTime 에 시간을 더하거나 뺄 때에는, 더하거나 빼려는 시간을
초단위로 바꾼 후, 그 시간을 ZCTime::Plus() 와 Minus() 에 인수로 넘긴다.
////////////////////////////////////////////////////////////////////////*/
class ZCTime
{
public :
typedef time_t TypeIntTime;
private :
enum{ETimeBuffSize =30};
enum{ESecResolution=1 }; // 1 초를 이루는 값.
private :
char* mpc_TimeBuff;
protected:
struct tm mo_TimeObj;
time_t ml_TimeSec; // typedef long time_t;
bool mb_IsLocal;
private :
#if defined(_WIN) && defined(_REENTRANT)
static ZCMutexSmallInit& GetCMutexSmallInit()
{
static ZCMutexSmallInit SO_CMutexSmallInit; return SO_CMutexSmallInit;
}/*
static ZCMutexSmallInit& GetCMutexSmallInit()*/
#endif //defined(_WIN) && defined(_REENTRANT)
static bool SetLocalTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime)
{
#ifdef _REENTRANT
#ifdef _WIN
ZNsMain::ZCMutexSmallLock VO_CMutexSmallLock(GetCMutexSmallInit());
struct tm* VP_StTime = ::localtime(&AL_TimeSec);
if(VP_StTime==0) return false;
ARR_StTime = *VP_StTime; return true;
#else
::localtime_r(&AL_TimeSec, &ARR_StTime); return true;
#endif
#else // !_REENTRANT
struct tm* VP_StTime = ::localtime(&AL_TimeSec);
if(VP_StTime==0) return false;
ARR_StTime = *VP_StTime; return true;
#endif // !_REENTRANT
}/*
static bool SetLocalTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime)*/
bool SetLocalTimeObj()
{
return SetLocalTimeObj(ml_TimeSec, RR(mo_TimeObj));
}/*
bool SetLocalTimeObj()*/
static bool SetSystemTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime)
{
#if defined(_REENTRANT)
#ifdef _WIN
ZNsMain::ZCMutexSmallLock
VO_CMutexSmallLock( GetCMutexSmallInit() );
struct tm* VP_StTime = ::gmtime(&AL_TimeSec);
if(VP_StTime==0) return false; //////
ARR_StTime = *VP_StTime; return true;
#else
::gmtime_r(&AL_TimeSec, &ARR_StTime); return true;
#endif
#else
struct tm* VP_StTime = ::gmtime(&AL_TimeSec);
if(VP_StTime==0) return false; //////
ARR_StTime = *VP_StTime; return true;
#endif
}/*
static bool SetSystemTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime)*/
bool SetSystemTimeObj()
{
return SetSystemTimeObj(ml_TimeSec, RR(mo_TimeObj));
}/*
bool SetSystemTimeObj()*/
static bool SetTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime, bool AB_IsLocalTime=true)
{
if(AB_IsLocalTime)
return SetLocalTimeObj (AL_TimeSec, RR(ARR_StTime));
else return SetSystemTimeObj(AL_TimeSec, RR(ARR_StTime));
}/*
static bool SetTimeObj(time_t AL_TimeSec, struct tm& ARR_StTime, bool AB_IsLocalTime=true)*/
bool SetTimeObj(bool AB_IsLocalTime)
{
return SetTimeObj(ml_TimeSec, RR(mo_TimeObj), AB_IsLocalTime);
}/*
bool SetTimeObj(bool AB_IsLocalTime)*/
bool SetTimeObj()
{
return SetTimeObj(mb_IsLocal);
}/*
bool SetTimeObj()*/
/*private:*/
public :
static TypeIntTime GetSecResolution()
{
return (TypeIntTime)ESecResolution;
}/*
static TypeIntTime GetSecResolution()*/
ZCTime(bool AB_IsLocalTime=true)
{
mb_IsLocal =AB_IsLocalTime;
mpc_TimeBuff=0; ::time(&ml_TimeSec);
::memset(&mo_TimeObj, 0, sizeof(::tm));
SetTimeObj(AB_IsLocalTime);
}/*
ZCTime(bool AB_IsLocalTime=true)*/
ZCTime(time_t AI_TimeVal, bool AB_IsLocalTime=true)
{
mpc_TimeBuff=0 ;
mb_IsLocal =AB_IsLocalTime;
ml_TimeSec =AI_TimeVal ;
::memset(&mo_TimeObj, 0, sizeof(::tm));
SetTimeObj(AB_IsLocalTime);
}/*
ZCTime(time_t AI_TimeVal, bool AB_IsLocalTime=true)*/
ZCTime(const ZCTime& rhs)
{
mpc_TimeBuff=0 ;
mb_IsLocal =rhs.mb_IsLocal;
ml_TimeSec =rhs.ml_TimeSec;
::memset(&mo_TimeObj,0,sizeof(::tm));
SetTimeObj(mb_IsLocal);
}/*
ZCTime(const ZCTime& rhs)*/
~ZCTime()
{
if(mpc_TimeBuff!=0) delete mpc_TimeBuff;
}/*
~ZCTime()*/
ZCTime& operator=(const ZCTime& rhs)
{
if(this==&rhs) return *this;
if(mpc_TimeBuff!=0)
{
delete mpc_TimeBuff; mpc_TimeBuff=0;
}/*
if(mpc_TimeBuff!=0)*/
mb_IsLocal=rhs.mb_IsLocal;
ml_TimeSec=rhs.ml_TimeSec;
SetTimeObj(mb_IsLocal); return *this;
}/*
ZCTime& operator=(const ZCTime& rhs)*/
bool InitTimeObj(bool AB_IsLocalTime)
{
::time(&ml_TimeSec); return SetTimeObj(AB_IsLocalTime);
}/*
bool InitTimeObj(bool AB_IsLocalTime)*/
bool InitTimeObj(time_t AI_TimeVal, bool AB_IsLocalTime)
{
ml_TimeSec=AI_TimeVal; return SetTimeObj(AB_IsLocalTime);
}/*
bool InitTimeObj(time_t AI_TimeVal, bool AB_IsLocalTime)*/
bool InitTimeObj()
{
return InitTimeObj(mb_IsLocal);
}/*
bool InitTimeObj()*/
bool InitTimeObj(time_t AI_TimeVal)
{
return InitTimeObj(AI_TimeVal, mb_IsLocal);
}/*
bool InitTimeObj(time_t AI_TimeVal)*/
bool InitLocalTimeObj (){return InitTimeObj(true );}
bool InitSystemTimeObj (){return InitTimeObj(false);}
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0
/*//////////*/ )
{
ml_TimeSec = ZCTime::MakeTimeInt( /////////////
AI_Year, AI_Month, AI_Day,
AI_Hour, AI_Min , AI_Sec
/*/////////*/ ); //////////////////////////////
if(SetTimeObj(mb_IsLocal)==false) return false;
return AI_Year ==mo_TimeObj.tm_year+1900 &&
AI_Month==mo_TimeObj.tm_mon +1 &&
AI_Day ==mo_TimeObj.tm_mday &&
AI_Hour ==mo_TimeObj.tm_hour &&
AI_Min ==mo_TimeObj.tm_min &&
AI_Sec ==mo_TimeObj.tm_sec ;
///////
}/*
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0
////////////// ) */
tm& GetTimeObj()
{
return mo_TimeObj;
}/*
tm& GetTimeObj()*/
inline TypeIntTime GetTimeSec() const{return ml_TimeSec;}
inline TypeIntTime GetTimeInt() const{return ml_TimeSec;} // for compatibility with linux
inline TypeIntTime AddTimeIntMilli(TypeIntTime AI_AddMilli) const
{ return ml_TimeSec + (AI_AddMilli/1000) ; }
inline TypeIntTime AddTimeIntSec (TypeIntTime AI_AddSec ) const
{ return ml_TimeSec + AI_AddSec ; }
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const
{
// ESecResolution/1000 < 1 인 경우에는 1 milli 초를 표현할 수 없으니까,
// ESecResolution/1000 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
// 근데 ESecResolution/1000 < 1 인 경우가 없게 ZCStdTime 클래스를 만들어
// 서 AddTimeIntMilliRev() 이 필요없게 되었다. -- 2018-06-25 14:06:00
if(GetSecResolution()/1000 >= 1) return AddTimeIntMilli(AI_AddMilli);
// AI_AddMilli>=0 이면서 가장 가까운 1000 의 배수에 맞춘다.
TypeIntTime VI_Revised =
(AI_AddMilli/1000)*1000 + ( (AI_AddMilli%1000)>0 ? 1000 :0 ) ;
AddTimeIntMilli(VI_Revised);
}/*
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const*/
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const
{
// ESecResolution < 1 인 경우에는 1 초를 표현할 수 없으니까,
// ESecResolution 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
return AddTimeIntSec(AI_AddSec); // 특별한 처리가 필요없다.
}/*
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const*/
inline time_t MakeTimeInt()
{
return ::mktime(&mo_TimeObj);
/*////////////////////////////////////////////////////////////
■ Get a integer that is information about day, hour, sec etc
from struct tm pointer mp_TimeObj
■ mktime() 은 에러의 경우 -1 을 반환한다.
////////////////////////////////////////////////////////////*/
}/*
inline time_t MakeTimeInt()*/
static inline time_t MakeTimeInt(struct tm& AR_TimeStruct)
{
return ::mktime(&AR_TimeStruct);
}/*
static inline time_t MakeTimeInt(struct tm& AR_TimeStruct)*/
static inline time_t MakeTimeInt(int AI_Year, int AI_Month, int AI_Day, int AI_Hour=0, int AI_Min=0, int AI_Sec=0)
{
::tm VO_TimeStr; ::memset(&VO_TimeStr, 0, sizeof(::tm));
VO_TimeStr.tm_year=AI_Year-1900 ;
VO_TimeStr.tm_mon =AI_Month-1 ;
VO_TimeStr.tm_mday=AI_Day ;
VO_TimeStr.tm_hour=AI_Hour ;
VO_TimeStr.tm_min =AI_Min ;
VO_TimeStr.tm_sec =AI_Sec ;
return ::mktime(&VO_TimeStr);
/*///////////////////////////////////////////////////////////////////
■ MakeTimeInt(2010,2,32) 을 호출하면(2010 년 2월 32 일자로 호출하면)
2010-03-04 00:00:00 에 해당하는 time_t 를 리턴한다. 따라서 이 함수
를 호출할 때 정확한 인수를 주는 것이 제일 좋지만, 차선책으로 인수가
지정하는 날짜와 이 함수가 리턴한 time_t 에 대한 날짜를 비교해 보는
것도 좋을 것 같다.
-- 2010-03-01 18:21;00
///////////////////////////////////////////////////////////////////*/
}/*
static inline time_t MakeTimeInt(int AI_Year, int AI_Month, int AI_Day, int AI_Hour=0, int AI_Min=0, int AI_Sec=0)*/
static bool IsValidTime(time_t AI_Time, int AI_Year, int AI_Month, int AI_Day, int AI_Hour, int AI_Min, int AI_Sec, bool AB_IsLocalTime=true)
{
struct ::tm VO_TimeStr; const bool CB_IsOK =
SetTimeObj(AI_Time, VO_TimeStr, AB_IsLocalTime);
if(CB_IsOK==false) return false;
return AI_Year ==VO_TimeStr.tm_year+1900 &&
AI_Month==VO_TimeStr.tm_mon +1 &&
AI_Day ==VO_TimeStr.tm_mday &&
AI_Hour ==VO_TimeStr.tm_hour &&
AI_Min ==VO_TimeStr.tm_min &&
AI_Sec ==VO_TimeStr.tm_sec ;
///////
}/*
static bool IsValidTime(time_t AI_Time, int AI_Year, int AI_Month, int AI_Day, int AI_Hour, int AI_Min, int AI_Sec, bool AB_IsLocalTime=true)*/
static bool IsValidTime(int AI_Year, int AI_Month, int AI_Day, int AI_Hour, int AI_Min, int AI_Sec, bool AB_IsLocalTime=true)
{
return IsValidTime(
MakeTimeInt(AI_Year, AI_Month, AI_Day, AI_Hour, AI_Min, AI_Sec),
AI_Year ,
AI_Month,
AI_Day ,
AI_Hour ,
AI_Min ,
AI_Sec ,
AB_IsLocalTime
/*/////////*/ ); ///////////////////////////////////////////////////////////////
}/*
static bool IsValidTime(int AI_Year, int AI_Month, int AI_Day, int AI_Hour, int AI_Min, int AI_Sec, bool AB_IsLocalTime=true)*/
bool Plus (time_t AI_TimeAddVal ){ml_TimeSec+=AI_TimeAddVal ; return SetTimeObj();}
bool Minus(time_t AI_TimeMinusVal){ml_TimeSec-=AI_TimeMinusVal; return SetTimeObj();}
ZCTime& operator+=(time_t AI_TimeVal){Plus (AI_TimeVal); return *this;}
ZCTime& operator-=(time_t AI_TimeVal){Minus(AI_TimeVal); return *this;}
char* GetTimeChars()
{
return ::asctime(&mo_TimeObj);
// We can see "Mon Nov 20Sun Jun 6 12:30:34 1995\n\0 " format from the function
// A size of char array which thie function return is 26
}/*
char* GetTimeChars()*/
inline int GetSysYear () const{return mo_TimeObj.tm_year ;}
inline int GetYear () const{return mo_TimeObj.tm_year + 1900 ;}
inline int GetSysMonth() const{return mo_TimeObj.tm_mon ;}
inline int GetMonth () const{return mo_TimeObj.tm_mon + 1 ;}
inline int GetDay () const{return mo_TimeObj.tm_mday ;}
inline int GetHour () const{return mo_TimeObj.tm_hour ;}
inline int GetMinute () const{return mo_TimeObj.tm_min ;}
inline int GetMin () const{return mo_TimeObj.tm_min ;}
inline int GetSecond () const{return mo_TimeObj.tm_sec ;}
inline int GetSec () const{return mo_TimeObj.tm_sec ;}
inline int GetYDay () const{return mo_TimeObj.tm_yday + 1 ;}
inline int GetSysYDay () const
{
// int tm_yday; // Day of year (0 - 365)
return mo_TimeObj.tm_yday ;
}/*
inline int GetSysYDay() const*/
inline int GetWeekDay() const
{
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
return mo_TimeObj.tm_wday + 1 ;
}/*
inline int GetWeekDay() const*/
inline int GetSysWeekDay() const
{
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
return mo_TimeObj.tm_wday ;
}/*
inline int GetSysWeekDay() const*/
inline int GetWeekOfYear() const
{
// 그 해의 몇 번째 주인지를 판단한다.
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
if(mo_TimeObj.tm_yday<=mo_TimeObj.tm_wday) return 1;
ZTycInt CI_DayCntOfWeek= 7;
ZTycInt CI_DayCntAdded = 2;
return (mo_TimeObj.tm_yday - mo_TimeObj.tm_wday-1)/CI_DayCntOfWeek + CI_DayCntAdded ;
}/*
inline int GetWeekOfYear() const*/
inline char* GetDate(bool AB_DoHaveHypen=true)
{
// AB_DoHaveHypen=true 이면, 일자를 2007-01-01 형태로 반환한다.
// AB_DoHaveHypen=false 이면, 일자를 20070101 형태로 반환한다.
if(mpc_TimeBuff==0)
{
mpc_TimeBuff=new char[ZCTime::ETimeBuffSize+1];
if(mpc_TimeBuff==0)
{
// Add Codes For Memory Over;
return 0;
}/*
if(mpc_TimeBuff==0)*/
}/*
if(mpc_TimeBuff==0)*/
mpc_TimeBuff[0] =
mpc_TimeBuff[ZCTime::ETimeBuffSize]=0 ;
if(AB_DoHaveHypen)
{
(void)sprintf( mpc_TimeBuff ,
"%d-%02d-%02d" ,
GetYear(), GetMonth(), GetDay()
/*////////*/ );
}
else
{
(void)sprintf( mpc_TimeBuff ,
"%d%02d%02d" ,
GetYear(), GetMonth(), GetDay()
/*////////*/ );
}/*
else*/
return mpc_TimeBuff;
}/*
inline char* GetDate(bool AB_DoHaveHypen=true)*/
/*///////////////////////////////////////////////////////////////////////////
■ 일정 시간과의 차이를 초로 구한다.
일별로 로그 파일을 남길 때, 일자가 언제 바뀌는데 알고 싶을 때 사용할 수 있다.
특히 로그 쓰레드를 만들 때, 로그 쓰레드에서 어떤 신호를 받아 다른 날짜로 로그
파일명을 바꾸어야 한다면 이 로그 쓰레드의 날짜를 체크하는 타이머 쓰레드에서
이 값을 참고할 수 있다.
-- 2009-05-19 14:03:00
///////////////////////////////////////////////////////////////////////////*/
long GetDiffSec(int AI_Hour=24, int AI_Min=0, int AI_Sec=0)
{
return (AI_Hour*3600+AI_Min*60+AI_Sec) - (mo_TimeObj.tm_hour*3600 + mo_TimeObj.tm_min*60 + mo_TimeObj.tm_sec) ;
}/*
long GetDiffSec(int AI_Hour=24, int AI_Min=0, int AI_Sec=0)*/
bool GetDiffSec(time_t& ARRI_TimeGap, int AI_Year, int AI_Month, int AI_Day, int AI_Hour, int AI_Min, int AI_Sec)
{
time_t VI_TimeSec=ZNsMain::ZCTime::MakeTimeInt(AI_Year, AI_Month, AI_Day, AI_Hour, AI_Min, AI_Sec);
if(VI_TimeSec<1){return false;} *this+=VI_TimeSec; return true ;
}/*
bool GetDiffSec(time_t& ARRI_TimeGap, int AI_Year,int AI_Month,int AI_Day,int AI_Hour,int AI_Min,int AI_Sec)*/
static bool GetDiffSec(
time_t& ARRI_TimeGap,
int AI_Year1, int AI_Month1, int AI_Day1, int AI_Hour1, int AI_Min1, int AI_Sec1,
int AI_Year2 ,int AI_Month2, int AI_Day2, int AI_Hour2, int AI_Min2, int AI_Sec2
/*//////////*/ )
{
time_t VI_TimeSec1=ZNsMain::ZCTime::MakeTimeInt(AI_Year1, AI_Month1, AI_Day1, AI_Hour1, AI_Min1, AI_Sec1);
time_t VI_TimeSec2=ZNsMain::ZCTime::MakeTimeInt(AI_Year2, AI_Month2, AI_Day2, AI_Hour2, AI_Min2, AI_Sec2);
if(VI_TimeSec1<0 || VI_TimeSec2<0) return false;
ARRI_TimeGap=VI_TimeSec2-VI_TimeSec1; return true ;
}/*
static bool GetDiffSec(
time_t& ARRI_TimeGap,
int AI_Year1, int AI_Month1, int AI_Day1, int AI_Hour1, int AI_Min1, int AI_Sec1,
int AI_Year2 ,int AI_Month2, int AI_Day2, int AI_Hour2, int AI_Min2, int AI_Sec2
////////////// ) */
static inline long GetNowDiffSec(int AI_Hour=24, int AI_Min=0, int AI_Sec=0)
{
ZCTime VO_CTime; return VO_CTime.GetDiffSec(AI_Hour, AI_Min, AI_Sec);
}/*
static inline long GetNowDiffSec(int AI_Hour=24, int AI_Min=0, int AI_Sec=0)*/
inline char* GetTimeStamp()
{
if(mpc_TimeBuff==0)
{
mpc_TimeBuff=new char[ZCTime::ETimeBuffSize+1];
if(mpc_TimeBuff==0)
{
// Add Codes For Memory Over;
return 0;
}/*
if(mpc_TimeBuff==0)*/
}/*
if(mpc_TimeBuff==0)*/
mpc_TimeBuff[0] =
mpc_TimeBuff[ZCTime::ETimeBuffSize]=0 ;
(void)sprintf ///////////////////////////
(
mpc_TimeBuff,
"%d-%02d-%02d %02d:%02d:%02d" ,
GetYear(), GetMonth (), GetDay(),
GetHour(), GetMinute(), GetSec()
);
/////////////////////////////////////////
return mpc_TimeBuff;
}/*
inline char* GetTimeStamp()*/
inline char* GetTimeStamp2()
{
// GetTimeStamp() 와는 달리, 공백, '-', ':' 등을 없앤다. 2012-09-09 10:16:00
if(mpc_TimeBuff==0)
{
mpc_TimeBuff=new char[ZCTime::ETimeBuffSize+1];
if(mpc_TimeBuff==0)
{
// Add Codes For Memory Over;
return 0;
}/*
if(mpc_TimeBuff==0)*/
}/*
if(mpc_TimeBuff==0)*/
mpc_TimeBuff[0] =
mpc_TimeBuff[ZCTime::ETimeBuffSize]=0 ;
(void)sprintf /////////////////////////////////
(
mpc_TimeBuff, "%d%02d%02d%02d%02d%02d",
GetYear() , GetMonth (), GetDay() ,
GetHour() , GetMinute(), GetSec()
);
///////////////////////////////////////////////
return mpc_TimeBuff;
}/*
inline char* GetTimeStamp2()*/
static inline char* GetNowTimeStamp(bool AB_IsLoaclTime=true)
{
struct tm VO_StTime; time_t VL_Time; time(&VL_Time); /*##############*/
if(SetTimeObj(VL_Time, RR(VO_StTime), AB_IsLoaclTime)==false) return 0;
ZTycInt CI_TimeBuffSize=30; static char VCA_TimeBuff[CI_TimeBuffSize];
(void)sprintf ////////////////////////////////////////////////////////
(
VCA_TimeBuff , "%d-%02d-%02d %02d:%02d:%02d" ,
VO_StTime.tm_year+1900, VO_StTime.tm_mon+1, VO_StTime.tm_mday,
VO_StTime.tm_hour , VO_StTime.tm_min , VO_StTime.tm_sec
);
//////////////////////////////////////////////////////////////////////
return VCA_TimeBuff;
}/*
static inline char* GetNowTimeStamp(bool AB_IsLoaclTime=true)*/
inline static char* GetTimeChars(const time_t& AR_TimeVal)
{
struct tm VO_StTime;
if(SetSystemTimeObj(AR_TimeVal, RR(VO_StTime))==false) return 0;
return ::asctime(&VO_StTime); /*##############################*/
}/*
inline static char* GetTimeChars(const time_t& AR_TimeVal)*/
inline static char* GetLocalTimeChars(const time_t& AR_TimeVal)
{
struct tm VO_StTime;
if(SetLocalTimeObj(AR_TimeVal, RR(VO_StTime))==false) return 0;
return ::asctime(&VO_StTime); /*#############################*/
}/*
inline static char* GetLocalTimeChars(const time_t& AR_TimeVal)*/
static inline time_t GetNowSec()
{
return time((time_t*)0); // Get Sec Time after the standard time
}/*
static inline time_t GetNowSec()*/
static inline clock_t Clock()
{
return clock(); // _CRTIMP clock_t __cdecl clock(void);
}/*
static inline clock_t Clock()*/
static inline long GetSecFromClock(clock_t AI_ClockInt)
{
return AI_ClockInt / CLOCKS_PER_SEC ;
}/*
static inline long GetSecFromClock(clock_t AI_ClockInt)*/
#if !defined(_WIN) // Is it better not to use this function ?
/*/////////////////////////////////////////////////////////////////////////////////////////
■ gcc 2.96 에서는 strptime 이 구현되지 않았을 수도 있다.
static inline char* GetTimeChars(const char* APC_Buff, const char* APC_Format, struct tm* AP_StTime)
{
return ::strptime(APC_Buff,APC_Format,AP_StTime);
}
/////////////////////////////////////////////////////////////////////////////////////////*/
static string& GetUniqueID(string& ARR_CString)
{
static int SI_Count=0;
const char* CPC_Gap="_" ;
char VCA_Buff[60] ;
struct timeval TTimeVal ;
struct timezone TTimeZone ;
gettimeofday(&TTimeVal,&TTimeZone);
(void)::sprintf ////////////////////////////
(
VCA_Buff, "%ld%s%ld%s%ld%s%ld%s%ld",
long(TTimeVal.tv_sec ) , CPC_Gap ,
long(TTimeVal.tv_usec) , CPC_Gap ,
long(getpid()) , CPC_Gap ,
long(getppid()) , CPC_Gap ,
long(++SI_Count)
);
////////////////////////////////////////////
return ARR_CString=VCA_Buff ;
}/*
static string& GetUniqueID(string& ARR_CString)*/
template<typename TTypString> static TTypString& GetUniqueIDObj(TTypString& ARR_CString)
{
static int SI_Count = 0 ;
const char* CPC_Gap="_" ;
char VCA_Buff[60] ;
struct timeval TTimeVal ;
struct timezone TTimeZone ;
gettimeofday(&TTimeVal,&TTimeZone);
(void)sprintf /////////////////////
(
VCA_Buff ,
"%ld%s%ld%s%ld%s%ld%s%ld" ,
TTimeVal.tv_sec , CPC_Gap ,
TTimeVal.tv_usec, CPC_Gap ,
getpid() , CPC_Gap ,
getppid() , CPC_Gap , ++SI_Count
);
///////////////////////////////////
return ARR_CString=VCA_Buff ;
}/*
template<typename TTypString> static TTypString& GetUniqueIDObj(TTypString& ARR_CString)*/
#else // deinfed(_WIN)
static string& GetUniqueID(string& ARR_CString)
{
const int CI_BuffSize=100 ;
static long SI_Count =0 ;
const char* CPC_Gap ="_" ;
char VCA_Buff[CI_BuffSize] ;
::sprintf( VCA_Buff,
"%ld%s%ld%s%ld" ,
(long)GetNowSec(), // (long) 가 없으면 메모리 오류가 난다.
CPC_Gap , (long)GetTickCount() ,
CPC_Gap , (++SI_Count)+long(::GetCurrentProcessId())
/*////*/ );
return ARR_CString = VCA_Buff ;
/*//////////////////////////////////////////////////////////////
■ sprintf
※ http://msdn.microsoft.com/en-us/library/ybk95axf.aspx In MSDN
// crt_sprintf.c
// compile with: /W3
// This program uses sprintf to format various
// data and place them in the string named buffer.
#include <stdio.h>
int main( void )
{
char buffer[200], s[] = "computer", c = 'l';
int i = 35, j;
float fp = 1.7320534f;
// Format and print various data:
j = sprintf( buffer, " String: %s\n", s ); // C4996
j += sprintf( buffer + j, " Character: %c\n", c ); // C4996
j += sprintf( buffer + j, " Integer: %d\n", i ); // C4996
j += sprintf( buffer + j, " Real: %f\n", fp );// C4996
// Note: sprintf is deprecated; consider using sprintf_s instead
printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
}
■ Windows C++ Safe String Functions
※ http://www.lingoport.com/gi/help/gihelp/unsafeMethod/winstrsafe.htm
Strsafe.h function Replaces
StringCchCat, StringCchCatEx strcat, wcscat, lstrcat, strcat, StrCatBuff, _tcscat, _ftcscat
StringCchCatN, StringCchCatNEx strncat, StrNCat
StringCchCopy, StringCchCopyEx strcpy, wcscpy, lstrcpy, strcpy, _tcscpy, _ftcscpy
StringCchCopyN, StringCchCopyNEx strncpy
StringCchGets, StringCchGetsEx gets, _getws, _getts
StringCchPrintf, StringCchPrintfEx sprintf, swprintf, wsprintf, wnsprintf, _stprintf, _snprintf, _snwprintf, _sntprintf
StringCchVPrintf, StringCchVPrintfEx vsprintf, vswprintf, wvsprintf, wvnsprintf, _vstprintf, _vsnprintf, _vsnwprintf, _vsntprintf
StringCchLength, strlen, lstrlen
■ GetTickCount()
Windows 가 부팅된 이후의 시간을 구하는데, 이전 GetTickCount()
호출과의 시간 간격은 약 49.7 일 동안은 유효하다.
//////////////////////////////////////////////////////////////*/
}/*
static string& GetUniqueID(string& ARR_CString)*/
template<typename TTypString>
static TTypString& GetUniqueIDObj(TTypString& ARR_CString)
{
static int SI_Count =0 ;
const int CI_BuffSize=100 ;
ZTypChar VC_Buff[CI_BuffSize];
ZTypCPCCh VP_GAP ="-" ;
(void)::sprintf
(
VC_Buff , "%d%s%d%s%d",
(long)GetNowSec() , VP_GAP ,
::GetTickCount() , VP_GAP ,
(++SI_Count) + ::GetCurrentProcessId()
);
/*###########*/
/*//////////////////////////////////////////////////////////
■ (long) 를 제거하면 VC++ 2008 에서 메모리 오류가 발생한다.
-- 2008-09-07 02:27:00
//////////////////////////////////////////////////////////*/
return ARR_CString=VC_Buff ;
}/*
template<typename TTypString>
static TTypString& GetUniqueIDObj(TTypString& ARR_CString) */
#endif //deinfed(_WIN)
static string& GetUniqueID()
{
static string VO_CStringObj; VO_CStringObj=""; return GetUniqueID(VO_CStringObj);
}/*
static string& GetUniqueID()*/
template<typename TTypString> static TTypString& GetUniqueIDObj()
{
static TTypString VO_CStringObj; VO_CStringObj="";
return GetUniqueIDObj<TTypString>(RR(VO_CStringObj));
}/*
template<typename TTypString> static TTypString& GetUniqueIDObj()*/
/*////////////////////////////////////////////////////////
clock
Calculates the wall-clock time used by the calling process.
clock_t clock( void );
Return Value
The elapsed wall-clock time since the start of the process (elapsed time in seconds times CLOCKS_PER_SEC). If the amount of elapsed time is unavailable, the function returns ?1, cast as a clock_t.
Remarks
The clock function tells how much time the calling process has used. A timer tick is approximately equal to 1/CLOCKS_PER_SEC second. In versions of Microsoft C before 6.0, the CLOCKS_PER_SEC constant was called CLK_TCK.
Requirements
Routine Required header Compatibility
clock <time.h> ANSI, Win 98, Win Me, Win NT, Win 2000, Win XP
For additional compatibility information, see Compatibility in the Introduction.
Libraries
All versions of the C run-time libraries.
Example
CLOCK.C: This example prompts for how long
the program is to run and then continuously
displays the elapsed time for that period.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void sleep( clock_t wait );
void main( void )
{
long i = 600000L;
clock_t start, finish;
double duration;
// Delay for a specified time.
printf( "Delay for three seconds\n" );
sleep( (clock_t)3 * CLOCKS_PER_SEC );
printf( "Done!\n" );
// Measure the duration of an event.
printf( "Time to do %ld empty loops is ", i );
start = clock();
while( i-- )
{
};
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%2.1f seconds\n", duration );
}
// Pauses for a specified number of milliseconds.
void sleep( clock_t wait )
{
clock_t goal;
goal = wait + clock();
while( goal > clock() )
;
}
Output
Delay for three seconds
Done!
Time to do 600000 empty loops is 0.1 seconds
//////////////////////////////////////////////*/
public:
};/*
class ZCTime*/
#if defined(_WIN)
/*///////////////////////////////////////////////////////////
■ class ZCStdTime 클래스는 해당 OS 에 고유한 함수를 사용하여,
좀 더 multi-thread 에 안전하게 구현한다.
-- 2012-03-23 14:42:00
리눅스에서는 ZCTime 을 ZCStdTime 으로 typedef 해도 되는데, 현재
gettimeofday() 를 이용해 좀 더 최적화되었다. -- 2018-06-25 09:38:00
■ 현재 아래 멤버가 Unix 랑 호환되는 것으로 정했다.
ZCStdTime::TypeIntTime : 시간을 표현하는 정수 자료형.
ZCStdTime(bool AB_IsLocal=true)
void InitLocalTimeObj ()
void InitSystemTimeObj()
GetSecResolution()
GetTimeInt() : return os-dependent time value
GetTimeSec()
AddTimeIntMilli()
AddTimeIntSec ()
int GetYear ()
int GetMonth ()
int GetDay ()
int GetDayOfWeek() // sunday 가 0, monday 가 1.
int GetHour ()
int GetMinute ()
int GetSecond ()
int GetMin ()
int GetSec ()
int GetMilliSec ()
int GetMilli ()
-- 2012-04-02 17:25:00
■ -- In WinBase.h
typedef struct _SYSTEMTIME {
WORD wYear ;
WORD wMonth ;
WORD wDayOfWeek ;
WORD wDay ;
WORD wHour ;
WORD wMinute ;
WORD wSecond ;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME
-- In WinDef.h
typedef struct _FILETIME {
DWORD dwLowDateTime ;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
#define _FILETIME_
□ 1601 년 1월 1일 0시가 기준이다.
time() 은 1970 년 1월 1일 0시가 기준이다.
□ FILETIME 타입은 그냥 간단하게 64비트 정수형으로 보면 되
는데 1601년 1월 1일 0시 0분 0초를 0으로 지정하며 1초에
10,000,000 이 늘어난다. 이를 두고 100 나노초의 해상도를
가진다고 이야기하는 것이다. 경과시간을 구할 때는 32비트
정수형 두개를 사용하지 않고 ULARGE_INTEGER 형에 대입한
후 QuadPart를 64비트 정수 연산을 이용한다. -- 2016-10-05
☞ http://blog.naver.com/mysticodoi/140043721556
아래 예제도 참고 -- 2018-06-21 17:08:00
☞ https://support.microsoft.com/ko-kr/help/188768/info-working-with-the-filetime-structure
#define _SECOND ((int64) 10000000)
#define _MINUTE (60 * _SECOND)
#define _HOUR (60 * _MINUTE)
#define _DAY (24 * _HOUR)
ULONGLONG qwResult;
// Copy the time into a quadword.
qwResult = (((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
// Add 30 days.
qwResult += 30 * _DAY;
// Copy the result back into the FILETIME structure.
ft.dwLowDateTime = (DWORD) (qwResult & 0xFFFFFFFF );
ft.dwHighDateTime = (DWORD) (qwResult >> 32 );
□ --
///////////////////////////////////////////////////////////*/
class ZCStdTime
{
public :
typedef ZTypUInt64 TypeIntTime;
private:
enum{ETimeBuffSize =30 };
enum{ESecResolution=1000*10000}; // 1 초를 이루는 값으로 1000 만.
private:
char mca_TimeBuff[ETimeBuffSize];
private:
bool mb_IsLocal ;
FILETIME mo_FILETIME ;
SYSTEMTIME mo_SYSTEMTIME;
public :
static TypeIntTime GetSecResolution()
{
return (TypeIntTime)ESecResolution;
}/*
static TypeIntTime GetSecResolution()*/
public :
ZCStdTime(bool AB_IsLoaclTime=true)
{
mb_IsLocal=AB_IsLoaclTime;
if(AB_IsLoaclTime)
InitLocalTimeObj ();
else InitSystemTimeObj();
}/*
ZCStdTime(bool AB_IsLoaclTime=true)*/
ZCStdTime(const ZCStdTime& rhs)
{
if(this==&rhs)
{
mb_IsLocal = true; return;
}
mb_IsLocal =rhs.mb_IsLocal ;
mo_FILETIME =rhs.mo_FILETIME ;
mo_SYSTEMTIME=rhs.mo_SYSTEMTIME;
}/*
ZCStdTime(const ZCStdTime& rhs)*/
~ZCStdTime()
{
}/*
~ZCStdTime()*/
ZCStdTime& operator=(const ZCStdTime& rhs)
{
if(this==&rhs) return *this;
mb_IsLocal =rhs.mb_IsLocal ;
mo_FILETIME =rhs.mo_FILETIME ;
mo_SYSTEMTIME=rhs.mo_SYSTEMTIME;
return *this;
}/*
ZCStdTime& operator=(const ZCStdTime& rhs)*/
bool InitLocalTimeObj()
{
::GetLocalTime (&mo_SYSTEMTIME); return
::SystemTimeToFileTime(&mo_SYSTEMTIME, &mo_FILETIME)==TRUE;
}/*
bool InitLocalTimeObj()*/
bool InitSystemTimeObj()
{
::GetSystemTime (&mo_SYSTEMTIME); return
::SystemTimeToFileTime(&mo_SYSTEMTIME, &mo_FILETIME)==TRUE;
}/*
bool InitSystemTimeObj()*/
bool InitTimeObj(bool AB_IsLoaclTime)
{
if(AB_IsLoaclTime)
return InitLocalTimeObj();
else
return InitSystemTimeObj();
//else
}/*
bool InitTimeObj(bool AB_IsLoaclTime)*/
bool InitTimeObj()
{
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
■ Windows 에서 CLogData.H 에서, 자꾸 mb_IsLocal 이 false 로 바뀌어 버린다.
그래서 __USE_LOCAL_TIME_BY_FORCE__ 이 정의되어 있으면, 무조건 InitTimeObj
에 false 를 전달한다. -- 2018-02-26 11:28:00
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
#ifdef __USE_LOCAL_TIME_BY_FORCE__
return InitTimeObj(true );
#else
return InitTimeObj(mb_IsLocal);
#endif
}/*
bool InitTimeObj()*/
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day ,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0)
{
mo_SYSTEMTIME.wYear =AI_Year ;
mo_SYSTEMTIME.wMonth =AI_Month ;
mo_SYSTEMTIME.wDay =AI_Day ;
mo_SYSTEMTIME.wHour =AI_Hour ;
mo_SYSTEMTIME.wMinute =AI_Min ;
mo_SYSTEMTIME.wSecond =AI_Sec ;
mo_SYSTEMTIME.wMilliseconds=AI_MiliSec;
mo_SYSTEMTIME.wDayOfWeek =0 ;
if(::SystemTimeToFileTime(&mo_SYSTEMTIME, &mo_FILETIME)==TRUE)
{
// to set mo_SYSTEMTIME.wDayOfWeek to correct value
::FileTimeToSystemTime(&mo_FILETIME, &mo_SYSTEMTIME); return true;
}/*
if(::SystemTimeToFileTime(&mo_SYSTEMTIME, &mo_FILETIME)==TRUE)*/
return false;
}/*
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day ,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0)*/
TypeIntTime GetTimeInt() const
{
return (((TypeIntTime)mo_FILETIME.dwHighDateTime)<<32) + mo_FILETIME.dwLowDateTime ;
}/*
TypeIntTime GetTimeInt() const*/
TypeIntTime GetTimeSec() const
{
return GetTimeInt()/ESecResolution;
}/*
TypeIntTime GetTimeSec() const*/
TypeIntTime AddTimeIntMilli(TypeIntTime AI_AddMilli) const{
return GetTimeInt() + ( AI_AddMilli*(ESecResolution/1000) ) ;}
TypeIntTime AddTimeIntSec (TypeIntTime AI_AddSec ) const{
return GetTimeInt() + ( AI_AddSec * ESecResolution ) ;}
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const
{
// ESecResolution/1000 < 1 인 경우에는 1 milli 초를 표현할 수 없으니까,
// ESecResolution/1000 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
// ZCStdTime 에는 ESecResolution/1000 < 1 인 경우가 없어서, 사실상 이 함
// 수는 사용되지 않는다.
return AddTimeIntMilli(AI_AddMilli); // 특별한 처리가 필요없다.
}/*
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const*/
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const
{
// ESecResolution < 1 인 경우에는 1 초를 표현할 수 없으니까,
// ESecResolution 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
return AddTimeIntSec(AI_AddSec); // 특별한 처리가 필요없다.
}/*
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const*/
int GetYear () const{return mo_SYSTEMTIME.wYear ;}
int GetMonth () const{return mo_SYSTEMTIME.wMonth ;}
int GetDay () const{return mo_SYSTEMTIME.wDay ;}
int GetDayOfWeek() const{return mo_SYSTEMTIME.wDayOfWeek ;} // sunday 가 0, monday 가 1.
int GetHour () const{return mo_SYSTEMTIME.wHour ;}
int GetMinute () const{return mo_SYSTEMTIME.wMinute ;}
int GetMin () const{return mo_SYSTEMTIME.wMinute ;}
int GetSecond () const{return mo_SYSTEMTIME.wSecond ;}
int GetSec () const{return mo_SYSTEMTIME.wSecond ;}
int GetMilliSec () const{return mo_SYSTEMTIME.wMilliseconds ;}
int GetMilli () const{return mo_SYSTEMTIME.wMilliseconds ;}
bool Plus(TypeIntTime AL_TimeSec)
{
TypeIntTime VL_TimeInt=GetTimeInt()+AL_TimeSec*ESecResolution;
mo_FILETIME.dwHighDateTime=(DWORD)(VL_TimeInt>>32 );
mo_FILETIME.dwLowDateTime =(DWORD)(VL_TimeInt & 0xFFFFFFFF);
return ::FileTimeToSystemTime(&mo_FILETIME, &mo_SYSTEMTIME)==TRUE;
}/*
bool Plus(TypeIntTime AL_TimeSec)*/
bool Minus(TypeIntTime AL_TimeSec)
{
TypeIntTime VL_TimeInt=GetTimeInt()-AL_TimeSec*ESecResolution;
mo_FILETIME.dwHighDateTime=(DWORD)(VL_TimeInt>>32 );
mo_FILETIME.dwLowDateTime =(DWORD)(VL_TimeInt & 0xFFFFFFFF);
return ::FileTimeToSystemTime(&mo_FILETIME, &mo_SYSTEMTIME)==TRUE;
}/*
bool Minus(TypeIntTime AL_TimeSec)*/
char* GetDate(bool AB_DoIncludeSpace=true)
{
// AB_DoIncludeSpace==true 이면 일자를 2007-01-01 형태로 반환한다.
// AB_DoIncludeSpace==false 이면 일자를 20070101 형태로 반환한다.
mca_TimeBuff[0] =
mca_TimeBuff[ZCStdTime::ETimeBuffSize]=0 ;
if(AB_DoIncludeSpace==true)
{
(void)::sprintf(mca_TimeBuff ,
"%d-%02d-%02d" ,
GetYear(), GetMonth(), GetDay()
/*//////////*/ );
}
else
{
(void)::sprintf(mca_TimeBuff ,
"%d%02d%02d" ,
GetYear(), GetMonth(), GetDay()
/*//////////*/ );
}/*
else*/
return mca_TimeBuff;
}/*
char* GetDate(bool AB_DoIncludeSpace=true)*/
char* GetTimeStamp()
{
mca_TimeBuff[0] =
mca_TimeBuff[ZCStdTime::ETimeBuffSize]=0 ;
(void)::sprintf(mca_TimeBuff,
"%d-%02d-%02d %02d:%02d:%02d",
GetYear(), GetMonth (), GetDay (),
GetHour(), GetMinute(), GetSecond()
/*//////////*/ );
return mca_TimeBuff;
}/*
char* GetTimeStamp()*/
public:
};/*
class ZCStdTime*/
/*///////////////////////////////////////////////////////////////////////////////////////////
■ class ZCTimeElapse
걸린 시간을 측정하는데, GetTickCount() 를 사용하고 있다. 좀 더 정확한 시간은 timeGetTime()
이나 아래 함수를 사용해야 한다.
QueryPerformanceCounter(StartTick);
QueryPerformanceFrequency(Freq);
또한 GetTickCount64() 하는 함수도 있는데, 게임 서버 같이, 장시간에 결쳐 운영되는 프로그램
에서 쓸 수 있겠다.
ULONGLONG WINAPI GetTickCount64(void);
-- 2013-08-11 01:17:00
■ http://cafe446.daum.net/_c21_/bbs_search_read?grpid=1EeeD&fldid=5AuH&contentval=0000bzzzzzzzzzzzzzzzzzzzzzzzzz&q=
[C언어 씨언어 알고니즘 정보보안전문가] - GetTickCount() - clock()보다 더 정확한 시간 재기.
>저도 GetTickCount가 어떤건지, 며칠전에 알았습니다.
>저처럼 모르고있었던분들도 있을것 같아서, 한번 올립니다.
>
>GetTickCount가 뭔 CPU클럭인가 먼가 .. 여튼 그런걸 이용한다던데요..
>여튼, 0.001초마다 이 카운트가 1씩 오르는건 정확합니다.
정확하지 않습니다.
카운트가 1ms(0.001sec) 라는건 값을 반환할 때 사용하는 단위가 밀리세컨드라는 뜻일 뿐입니다.
실제로 사용해보면 resolution(정밀도)은 15ms 정도에 불과합니다. (windows 2000 이상 기준)
winmm.lib 에 들어있는 (헤더는 mmsystem.h) timeGetTime() 함수가 좀 더 정확합니다.
대신 timeBeginPeriod() 와 timeEndPeriod() 함수로 정밀도를 수동조절해야 그나마 높은 정밀도
가 나옵니다. 문제는 그렇게 해놓아도 종종 10ms 이상의 점핑현상이 나타난다는거..
1ms 이상의 정밀도가 나오는 함수는 QueryPerformanceCounter() 이거 하나 뿐입니다. (수백만분
의 1초 수준의 정밀도가 나온다는군요)
이 함수의 문제는 하드웨어 사양에 따라 지원이 안되거나, 이상한 결과가 나올 수도 있다는 점..
결론을 말하자면, 윈도우즈에서 1ms 정밀도에 안정성까지 있는 함수는 존재하지 않습니다.
저는 라이브러리 로딩할 때 QueryPerformanceCounter() 가 지원되는지를 한번 확인하고, 지원 안
된다면 그냥 GetTickCount()를 쓰되 오차를 적절히 보정해서 씁니다.
그러나 1/100초 정도의 정밀도로 충분하다면 GetTickCount() 를 쓰는게 좋습니다
-- 2013-08-11 01:17:00
///////////////////////////////////////////////////////////////////////////////////////////*/
class ZCTimeElapse
{
public :
typedef ZTypInt64 TypeIntTime;
private:
TypeIntTime ml_InitMiliTime ;
public :
ZCTimeElapse()
{
ml_InitMiliTime = ::GetTickCount();
}/*
ZCTimeElapse()*/
void Init()
{
ml_InitMiliTime = ::GetTickCount();
}/*
void Init()*/
TypeIntTime GetElapse() const
{
return ::GetTickCount()-ml_InitMiliTime;
}/*
TypeIntTime GetElapse() const*/
TypeIntTime GetElapseInit() // 시간 간격을 구하면서 동시에 초기화를 한다.
{
long VL_PrevTime=ml_InitMiliTime;
ml_InitMiliTime = ::GetTickCount();
return ml_InitMiliTime-VL_PrevTime;
}/*
TypeIntTime GetElapseInit()*/
TypeIntTime GetTimeInt () const{return ml_InitMiliTime;}
TypeIntTime GetTimeMilli() const{return ml_InitMiliTime;}
static TypeIntTime GetTimeIntNow () { return ::GetTickCount(); }
static TypeIntTime GetTimeMilliNow() { return ::GetTickCount(); }
public:
};/*
class ZCTimeElapse*/
#else // !defined(_WIN)
/*//////////////////////////////////////////////////////////////
■ ZCTime 에 동기화 처리가 되었기 때문에, Unix 에서는 ZCTime 을
ZCStdTime 으로 typedef 해서 사용한다.
-- 2012-04-03 12:45:00
이제는 Unix 에서 gettimeofday() 를 이용한 좀 더 최적화된 ZCStdTime
을 만들었다. -- 2018-06-22 14:47:00
■ HP-UX 에서는 localtime_r, gmtime_r 을 사용하기 위해서는
_REENTRANT 을 정의해야 하는 경우가 있다.
-- 2012-04-08 18:43:00
//////////////////////////////////////////////////////////////*/
class ZCStdTime
{
public :
typedef ZTypInt64 TypeIntTime;
private:
enum{ETimeBuffSize =30 };
enum{ESecResolution=1000*1000 }; // 1 초를 이루는 값으로 100 만.
private:
char mca_TimeBuff[ETimeBuffSize];
private:
bool mb_IsLocal; struct
timeval mo_TimeVal; struct
tm mo_TimeObj;
TypeIntTime mi_TimeSec;
public :
static TypeIntTime GetSecResolution()
{
return (TypeIntTime)ESecResolution;
}/*
static TypeIntTime GetSecResolution()*/
public :
ZCStdTime(bool AB_IsLoaclTime=true)
{
mb_IsLocal=AB_IsLoaclTime;
mi_TimeSec=0 ;
if(AB_IsLoaclTime)
InitLocalTimeObj ();
else InitSystemTimeObj();
}/*
ZCStdTime(bool AB_IsLoaclTime=true)*/
ZCStdTime(const ZCStdTime& rhs)
{
mb_IsLocal=rhs.mb_IsLocal;
mo_TimeVal=rhs.mo_TimeVal;
mo_TimeObj=rhs.mo_TimeObj;
mi_TimeSec=rhs.mi_TimeSec;
}/*
ZCStdTime(const ZCStdTime& rhs)*/
~ZCStdTime()
{
}/*
~ZCStdTime()*/
ZCStdTime& operator=(const ZCStdTime& rhs)
{
if(this==&rhs) return *this;
mb_IsLocal=rhs.mb_IsLocal;
mo_TimeVal=rhs.mo_TimeVal;
mo_TimeObj=rhs.mo_TimeObj;
mi_TimeSec=rhs.mi_TimeSec;
return *this;
}/*
ZCStdTime& operator=(const ZCStdTime& rhs)*/
bool InitLocalTimeObj()
{
::gettimeofday(&mo_TimeVal, NULL );
::localtime_r (&mo_TimeVal.tv_sec, &mo_TimeObj); return true;
}/*
bool InitLocalTimeObj()*/
bool InitSystemTimeObj()
{
::gettimeofday(&mo_TimeVal, NULL );
::gmtime_r (&mo_TimeVal.tv_sec, &mo_TimeObj); return true;
}/*
bool InitSystemTimeObj()*/
bool InitTimeObj(bool AB_IsLoaclTime)
{
if(AB_IsLoaclTime)
return InitLocalTimeObj ();
else return InitSystemTimeObj();
}/*
bool InitTimeObj(bool AB_IsLoaclTime)*/
bool InitTimeObj()
{
return InitTimeObj(mb_IsLocal);
}/*
bool InitTimeObj()*/
bool InitLocalTimeObj(TypeIntTime AI_TimeInt)
{
if(::localtime_r(&AI_TimeInt, &mo_TimeObj)==0)
return false;
/*##########################################*/
mi_TimeSec = AI_TimeInt;
mo_TimeVal.tv_sec = AI_TimeInt;
mo_TimeVal.tv_usec= 0 ; return true;
}/*
bool InitLocalTimeObj()*/
bool InitSystemTimeObj(TypeIntTime AI_TimeInt)
{
if(::gmtime_r(&AI_TimeInt, &mo_TimeObj)==0)
return false;
/*#######################################*/
mi_TimeSec = AI_TimeInt;
mo_TimeVal.tv_sec = AI_TimeInt;
mo_TimeVal.tv_usec= 0 ; return true;
}/*
bool InitSystemTimeObj(TypeIntTime AI_TimeInt)*/
bool InitTimeObj(bool AB_IsLoaclTime, TypeIntTime AI_TimeInt)
{
if(AB_IsLoaclTime)
return InitLocalTimeObj (AI_TimeInt);
else return InitSystemTimeObj(AI_TimeInt);
}/*
bool InitTimeObj(bool AB_IsLoaclTime, TypeIntTime AI_TimeInt)*/
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day ,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0)
{
::memset(&mo_TimeVal, 0, sizeof(::tm));
mo_TimeObj.tm_year=AI_Year-1900 ;
mo_TimeObj.tm_mon =AI_Month-1 ;
mo_TimeObj.tm_mday=AI_Day ;
mo_TimeObj.tm_hour=AI_Hour ;
mo_TimeObj.tm_min =AI_Min ;
mo_TimeObj.tm_sec =AI_Sec ;
mi_TimeSec = ::mktime(&mo_TimeObj);
if(mi_TimeSec<=0) return false;
mo_TimeVal.tv_sec = mi_TimeSec ;
mo_TimeVal.tv_usec = AI_MiliSec*1000;
return true;
}/*
bool InitTimeObjFromDate(
int AI_Year , int AI_Month, int AI_Day ,
int AI_Hour=0, int AI_Min=0, int AI_Sec=0, int AI_MiliSec=0)*/
TypeIntTime GetTimeInt() const
{
return (((TypeIntTime)mo_TimeVal.tv_sec)<<32) + mo_TimeVal.tv_usec ;
}/*
TypeIntTime GetTimeInt() const*/
TypeIntTime GetTimeSec() const
{
return mo_TimeVal.tv_sec ;
}/*
TypeIntTime GetTimeSec() const*/
TypeIntTime AddTimeIntMilli(TypeIntTime AI_AddMilli) const{
return GetTimeInt() + ( AI_AddMilli*(ESecResolution/1000) ) ;}
TypeIntTime AddTimeIntSec (TypeIntTime AI_AddSec ) const{
return GetTimeInt() + ( AI_AddSec * ESecResolution ) ;}
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const
{
// ESecResolution/1000 < 1 인 경우에는 1 milli 초를 표현할 수 없으니까,
// ESecResolution/1000 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
return AddTimeIntMilli(AI_AddMilli); // 특별한 처리가 필요없다.
}/*
inline TypeIntTime AddTimeIntMilliRev(TypeIntTime AI_AddMilli) const*/
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const
{
// ESecResolution < 1 인 경우에는 1 초를 표현할 수 없으니까,
// ESecResolution 이상이면서 가장 가까운 배수로 보정(revise)하는
// 것이다. 스케줄러에서 예약 시간을 등록할 때 필요하다.
return AddTimeIntSec(AI_AddSec); // 특별한 처리가 필요없다.
}/*
inline TypeIntTime AddTimeIntSecRev(TypeIntTime AI_AddSec) const*/
inline int GetSysYear () const{return mo_TimeObj.tm_year ;}
inline int GetYear () const{return mo_TimeObj.tm_year + 1900 ;}
inline int GetSysMonth() const{return mo_TimeObj.tm_mon ;}
inline int GetMonth () const{return mo_TimeObj.tm_mon + 1 ;}
inline int GetDay () const{return mo_TimeObj.tm_mday ;}
inline int GetHour () const{return mo_TimeObj.tm_hour ;}
inline int GetMinute () const{return mo_TimeObj.tm_min ;}
inline int GetMin () const{return mo_TimeObj.tm_min ;}
inline int GetSecond () const{return mo_TimeObj.tm_sec ;}
inline int GetSec () const{return mo_TimeObj.tm_sec ;}
inline int GetYDay () const{return mo_TimeObj.tm_yday + 1 ;}
inline int GetSysYDay () const
{
// int tm_yday; // Day of year (0 - 365)
return mo_TimeObj.tm_yday ;
}/*
inline int GetSysYDay() const*/
inline int GetWeekDay() const
{
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
return mo_TimeObj.tm_wday + 1 ;
}/*
inline int GetWeekDay() const*/
inline int GetSysWeekDay() const
{
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
return mo_TimeObj.tm_wday ;
}/*
inline int GetSysWeekDay() const*/
inline int GetWeekOfYear() const
{
// 그 해의 몇 번째 주인지를 판단한다.
// int tm_wday; // Day of week (0 - 6 : 0 = Sunday)
if(mo_TimeObj.tm_yday<=mo_TimeObj.tm_wday) return 1;
ZTycInt CI_DayCntOfWeek=7;
ZTycInt CI_DayCntAdded =2;
return (mo_TimeObj.tm_yday - mo_TimeObj.tm_wday-1)/CI_DayCntOfWeek + CI_DayCntAdded ;
}/*
inline int GetWeekOfYear() const*/
int GetMilliSec() const{return mo_TimeVal.tv_usec/1000;}
int GetMilli () const{return mo_TimeVal.tv_usec/1000;}
int GetMicroSec() const{return mo_TimeVal.tv_usec ;}
bool Plus(TypeIntTime AL_TimeSec)
{
return InitTimeObj(mb_IsLocal, mo_TimeVal.tv_sec+AL_TimeSec);
}/*
bool Plus(TypeIntTime AL_TimeSec)*/
bool Minus(TypeIntTime AL_TimeSec)
{
return InitTimeObj(mb_IsLocal, mo_TimeVal.tv_sec-AL_TimeSec);
}/*
bool Minus(TypeIntTime AL_TimeSec)*/
char* GetDate(bool AB_DoIncludeSpace=true)
{
// AB_DoIncludeSpace==true 이면 일자를 2007-01-01 형태로 반환한다.
// AB_DoIncludeSpace==false 이면 일자를 20070101 형태로 반환한다.
mca_TimeBuff[0] =
mca_TimeBuff[ZCStdTime::ETimeBuffSize]=0 ;
if(AB_DoIncludeSpace==true)
{
(void)::sprintf(mca_TimeBuff ,
"%d-%02d-%02d" ,
GetYear(),GetMonth(),GetDay()
/*//////////*/ );
}
else
{
(void)::sprintf(mca_TimeBuff ,
"%d%02d%02d" ,
GetYear(),GetMonth(),GetDay()
/*//////////*/ );
}/*
else*/
return mca_TimeBuff;
}/*
char* GetDate(bool AB_DoIncludeSpace=true)*/
char* GetTimeStamp()
{
mca_TimeBuff[0] =
mca_TimeBuff[ZCStdTime::ETimeBuffSize]=0 ;
(void)::sprintf(mca_TimeBuff,
"%d-%02d-%02d %02d:%02d:%02d",
GetYear(), GetMonth (), GetDay (),
GetHour(), GetMinute(), GetSecond()
/*//////////*/ );
return mca_TimeBuff;
}/*
char* GetTimeStamp()*/
public:
};/*
class ZCStdTime*/
/*//////////////////////////////////////////////////////////////
■ struct timeval
{
time_t tv_sec ; // seconds
suseconds_t tv_usec; // microseconds
};
//////////////////////////////////////////////////////////////*/
class ZCTimeElapse
{
public :
typedef ZTypInt64 TypeIntTime ;
private:
struct timeval mo_InitTimeVal;
public :
ZCTimeElapse()
{
::gettimeofday(&mo_InitTimeVal, NULL);
}/*
ZCTimeElapse()*/
void Init()
{
::gettimeofday(&mo_InitTimeVal, NULL);
}/*
void Init()*/
ZTypInt64 GetElapse() const // 밀리 초로 반환한다.
{
struct timeval VO_TimeVal; ::gettimeofday(&VO_TimeVal, NULL);
return
(VO_TimeVal.tv_sec - mo_InitTimeVal.tv_sec )*1000 +
(VO_TimeVal.tv_usec- mo_InitTimeVal.tv_usec)/1000 ;
}/*
ZTypInt64 GetElapse() const*/
ZTypInt64 GetElapseInit() // 시간 간격을 구하면서 동시에 초기화를 한다.
{
struct timeval VO_TimeVal; ::gettimeofday(&VO_TimeVal, NULL);
long VL_MiliTime =
(VO_TimeVal.tv_sec - mo_InitTimeVal.tv_sec )*1000 +
(VO_TimeVal.tv_usec- mo_InitTimeVal.tv_usec)/1000 ;
mo_InitTimeVal=VO_TimeVal; return VL_MiliTime; ////////
}/*
ZTypInt64 GetElapseInit()*/
TypeIntTime GetTimeInt() const
{
return (TypeIntTime)(mo_InitTimeVal.tv_sec<<32) + mo_InitTimeVal.tv_usec;
}/*
TypeIntTime GetTimeInt() const*/
TypeIntTime GetTimeMilli() const
{
return (TypeIntTime)(mo_InitTimeVal.tv_sec*1000) + mo_InitTimeVal.tv_usec/1000;
}/*
TypeIntTime GetTimeMilli() const*/
static TypeIntTime GetTimeIntNow()
{
struct timeval VO_TimeVal; ::gettimeofday(&VO_TimeVal, NULL);
return (TypeIntTime)(VO_TimeVal.tv_sec<<32) + VO_TimeVal.tv_usec;
}/*
static TypeIntTime GetTimeIntNow()*/
static TypeIntTime GetTimeMilliNow()
{
// GetTimeIntNow() 을 milli 초로 환산한 것.
struct timeval VO_TimeVal; ::gettimeofday(&VO_TimeVal, NULL);
return (TypeIntTime)(VO_TimeVal.tv_sec )*1000 + (VO_TimeVal.tv_usec)/1000 ;
}/*
static TypeIntTime GetTimeMilliNow()*/
public:
};/*
class ZCTimeElapse*/
#endif // !defined(_WIN)
/*/////////////////////////////////////////////////////
Open a file.
int _open(
const char *filename,
int oflag [,
int pmode]
);
int _wopen(
const wchar_t *filename,
int oflag [,
int pmode]
);
Parameters
filename
Filename.
oflag
Type of operations allowed.
pmode
Permission mode.
Return Value
Each of these functions returns a file handle for the opened file.
A return value of ?1 indicates an error,
in which case errno is set to one of the following values:
EACCES
Tried to open read-only file for writing,
or file's sharing mode does not allow specified operations, or given path is directory.
EEXIST
_O_CREAT and _O_EXCL flags specified, but filename already exists.
EINVAL
Invalid oflag or pmode argument.
EMFILE
No more file handles available (too many open files).
ENOENT
File or path not found.
See _doserrno, errno, _sys_errlist, and _sys_nerr for more information on these,
and other, return codes.
Remarks
The _open function opens the file specified by filename and prepares the file
for reading or writing,
as specified by oflag. _wopen is a wide-character version of _open;
the filename argument to _wopen is a wide-character string.
_wopen and _open behave identically otherwise.
Generic-Text Routine Mappings
TCHAR.H routine _UNICODE & _MBCS not defined _MBCS defined _UNICODE defined
_topen _open _open _wopen
oflag is an integer expression formed
from one or more of the following manifest constants or constant combinations
defined in FCNTL.H:
_O_APPEND
Moves file pointer to end of file before every write operation.
_O_BINARY
Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
_O_CREAT
Creates and opens new file for writing. Has no effect if file specified by filename exists. pmode argument is required when _O_CREAT is specified.
_O_CREAT | _O_SHORT_LIVED
Create file as temporary and if possible do not flush to disk. pmode argument is required when _O_CREAT is specified.
_O_CREAT | _O_TEMPORARY
Create file as temporary; file is deleted when last file handle is closed. pmode argument is required when _O_CREAT is specified.
_O_CREAT | _O_EXCL
Returns error value if file specified by filename exists. Applies only when used with _O_CREAT.
_O_RANDOM
Specifies that caching is optimized for, but not restricted to, random access from disk.
_O_RDONLY
Opens file for reading only; cannot be specified with _O_RDWR or _O_WRONLY.
_O_RDWR
Opens file for both reading and writing; you cannot specify this flag with _O_RDONLY or _O_WRONLY.
_O_SEQUENTIAL
Specifies that caching is optimized for, but not restricted to, sequential access from disk.
_O_TEXT
Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
_O_TRUNC
Opens file and truncates it to zero length; file must have write permission. You cannot specify this flag with _O_RDONLY. _O_TRUNC used with _O_CREAT opens an existing file or creates a new file.
Note The _O_TRUNC flag destroys the contents of the specified file.
_O_WRONLY
Opens file for writing only; cannot be specified with _O_RDONLY or _O_RDWR.
To specify the file access mode,
you must specify either _O_RDONLY, _O_RDWR, or _O_WRONLY.
There is no default value for the access mode.
When two or more manifest constants are used to form the oflag argument,
the constants are combined with the bitwise-OR operator ( | ).
See Text and Binary Mode File I/O for a discussion of binary and text modes.
The pmode argument is required only when _O_CREAT is specified.
If the file already exists, pmode is ignored.
Otherwise, pmode specifies the file permission settings,
which are set when the new file is closed the first time.
_open applies the current file-permission mask to pmode before setting the permissions
(for more information, see _umask).
pmode is an integer expression containing one or both of the following manifest constants,
defined in SYS\STAT.H:
#define _S_IREAD 0000400 // read permission, owner
#define _S_IWRITE 0000200 // write permission, owner
_S_IREAD
Reading only permitted.
_S_IWRITE
Writing permitted (effectively permits reading and writing).
_S_IREAD | _S_IWRITE
Reading and writing permitted.
When both constants are given, they are joined with the bitwise-OR operator ( | ).
In Windows NT, all files are readable, so write-only permission is not available;
thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.
Requirements
Routine Required header Optional headers Compatibility
_open <io.h> <fcntl.h>, <sys/types.h>, <sys/stat.h> Win 98, Win Me, Win NT, Win 2000, Win XP
_wopen <io.h> or <wchar.h> <fcntl.h>, <sys/types.h>, <sys/stat.h> Win NT, Win 2000, Win XP
For additional compatibility information, see Compatibility in the Introduction.
Libraries
All versions of the C run-time libraries.
Example
OPEN.C: This program uses _open to open a file
named OPEN.C for input and a file named OPEN.OUT
for output. The files are then closed.
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
void main( void )
{
int fh1, fh2;
fh1 = _open( "OPEN.C", _O_RDONLY );
if( fh1 == -1 )
perror( "open failed on input file" );
else
{
printf( "open succeeded on input file\n" );
_close( fh1 );
}
fh2 = _open( "OPEN.OUT", _O_WRONLY | _O_CREAT, _S_IREAD |
_S_IWRITE );
if( fh2 == -1 )
perror( "Open failed on output file" );
else
{
printf( "Open succeeded on output file\n" );
_close( fh2 );
}
}
Output
Open succeeded on input file
Open succeeded on output file
///////////////////////////*/
namespace ZNsConst
{
namespace ZNsCFileMode
{
// These values are second parameters of CCFile::Open() function
const char* const Read = "r" ;
const char* const ReadWrite = "r+";
const char* const RWAppend = "a+";
const char* const RWCut = "w" ;
const char* const WriteAppend= "a" ;
const char* const WriteCut = "w+";
const char* const Binary = "b" ;
const char* const WriteBinany= "wb";
}/*
namespace ZNsCFileMode*/
namespace ZNsCppFileMode
{
// These vales are used to be a second parmeter in fstream::open() function
const unsigned int Read =std::ios::in ;
const unsigned int WriteCut =std::ios::out; // == std::ios::out | std::ios::trunc
const unsigned int Append =std::ios::out | std::ios::app ;
const unsigned int ReadWrite=std::ios::in | std::ios::out ;
const unsigned int RWCut =std::ios::in | std::ios::out | std::ios::trunc ;
const unsigned int EndPos =std::ios::ate ;
// std::ios::ate mode move file pointer to file end
// Use this value with other mode value
}/*
namespace ZNsCppFileMode*/
namespace ZNsLlioMode // Low Level Input Output
{
const unsigned long Read =O_RDONLY;
const unsigned long Write =O_WRONLY;
const unsigned long ReadWrite=O_RDWR ;
const unsigned long RWMake =O_RDWR | O_CREAT ;
const unsigned long Append =O_APPEND | O_WRONLY;
const unsigned long Trunc =O_TRUNC ;
const unsigned long Create =O_CREAT ;
const unsigned long OnlyExist =O_EXCL | O_CREAT ;
const unsigned long WriteMakeCut=O_WRONLY | O_CREAT | O_TRUNC ;
const unsigned long AppendMake =O_APPEND | O_WRONLY | O_CREAT ;
// AppendMake : 덧붙이되 파일이 없으면 새로 만든다.
// O_EXCL : open only if file doesn't already exist
// O_EXCL is used with O_CREAT
}/*
namespace ZNsLlioMode*/
}/*
namespace ZNsConst*/
/*/////////////////////////
struct stat
{
_dev_t st_dev;
_ino_t st_ino;
unsigned short st_mode;
short st_nlink;
short st_uid;
short st_gid;
_dev_t st_rdev;
_off_t st_size;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
/////////////////////////*/
class CFile
{
protected:
FILE* mp_HFile;
public :
CFile()
{
mp_HFile=0;
}/*
CFile()*/
const FILE* GetFilePtr()
{
return mp_HFile;
}/*
const FILE* GetFilePtr()*/
bool Open(const char* APC_FileName, const char* APC_Mode=ZNsConst::ZNsCFileMode::ReadWrite)
{
return (mp_HFile=::fopen(APC_FileName, APC_Mode))!=0;
}/*
bool Open(const char* APC_FileName,const char* APC_Mode=ZNsConst::ZNsCFileMode::ReadWrite)*/
bool Close()
{
bool VB_IsOK=(::fclose(mp_HFile)==0); mp_HFile=0; return VB_IsOK;
}/*
bool Close()*/
size_t Read(void* AP_Buff, size_t AI_BlockSize, size_t AI_BlockCnt)
{
return ::fread(AP_Buff, AI_BlockSize, AI_BlockCnt, mp_HFile);
}/*
size_t Read(void* AP_Buff, size_t AI_BlockSize, size_t AI_BlockCnt)*/
size_t Read(void* AP_ReadBuff, size_t AI_ReadByte)
{
return ::fread(AP_ReadBuff, 1, AI_ReadByte, mp_HFile);
}/*
size_t Read(void* AP_ReadBuff, size_t AI_ReadByte)*/
size_t Write(const void* AP_Buff, size_t AI_BlockSize, size_t AI_BlockCnt)
{
return ::fwrite(AP_Buff, AI_BlockSize, AI_BlockCnt, mp_HFile);
}/*
size_t Write(const void* AP_Buff, size_t AI_BlockSize, size_t AI_BlockCnt)*/
size_t Write(const void* AP_WriteBuff, size_t AI_WriteByte)
{
return ::fwrite(AP_WriteBuff, 1, AI_WriteByte, mp_HFile);
}/*
size_t Write(const void* AP_WriteBuff, size_t AI_WriteByte)*/
size_t Write(const char* AP_Buff)
{
return ::fwrite(AP_Buff, 1, strlen(AP_Buff), mp_HFile);
}/*
size_t Write(const char* AP_Buff)*/
bool Flush() // 파일스트림의 모든 데이타를 즉시 저장한다.
{
return ::fflush(mp_HFile)==0;
}/*
bool Flush()*/
int Seek(long AL_Offset, int AI_Whence=SEEK_SET) // AI_Whence 는 SEEK_SET, SEEK_CUR, SEEK_END 중의 한 값
{
return ::fseek(mp_HFile, AL_Offset, AI_Whence);
}/*
int Seek(long AL_Offset, int AI_Whence=SEEK_SET)*/
long Tell()
{
return ::ftell(mp_HFile);
}/*
long Tell()*/
int GetC()
{
return ::fgetc(mp_HFile);
}/*
int GetC()*/
int PutC(int AI_Char)
{
return ::fputc(AI_Char,mp_HFile);
}/*
int PutC(int AI_Char)*/
int PrintF(const char* APC_Format, ...)
{
va_list VP_VarParam; va_start( VP_VarParam, APC_Format);
return vfprintf(mp_HFile, APC_Format, VP_VarParam);
}/*
int PrintF(const char* APC_Format, ...)*/
bool IsError()
{
return ::ferror(mp_HFile)!=0;
}/*
bool IsError()*/
bool IsEOF()
{
return ::feof(mp_HFile)!=0;
}/*
bool IsEOF()*/
public:
};/*
class CFile*/
class ZCLLIO // Low Level Input Output
{
protected:
int mi_Handle;
public :
ZCLLIO()
{
mi_Handle=-1;
}/*
ZCLLIO()*/
bool IsValid() const
{
return mi_Handle>=0;
}/*
bool IsValid() const*/
bool Open(ZTypCPCCh APC_Path, int AI_Mode=ZNsConst::ZNsLlioMode::Read, int AI_Perm=0)
{
// Mode value is one of many variables in namespace NsCLLio
// return -1 if it fails;
return (mi_Handle= ::open(APC_Path, AI_Mode, AI_Perm)) != -1 ;
/*////////////////////////////////////////////////////////////////////////////////////////////////////////
■ cf)
fflush() returns 0 if the buffer was successfully flushed.
The value 0 is also returned in cases
in which the specified stream has no buffer or is open for reading only.
A return value of EOF indicates an error.
Note If fflush returns EOF, data may have been lost due to a write failure.
When setting up a critical error handler,
it is safest to turn buffering off with the setvbuf() function
or to use low-level I/O routines such as _open, _close, and _write instead of the stream I/O functions.
■ --
////////////////////////////////////////////////////////////////////////////////////////////////////////*/
}/*
bool Open(ZTypCPCCh APC_Path, int AI_Mode=ZNsConst::ZNsLlioMode::Read, int AI_Perm=0)*/
bool OpenRead (ZTypCPCCh APC_Path , int AI_Perm=0) // 읽기
{ return (mi_Handle= ::open( APC_Path , ZNsConst::ZNsLlioMode::Read , AI_Perm)) != -1 ; }
bool OpenWrite(ZTypCPCCh APC_Path , int AI_Perm=0) // 쓰기
{ return (mi_Handle= ::open( APC_Path , ZNsConst::ZNsLlioMode::Write , AI_Perm)) != -1 ; }
bool OpenRW (ZTypCPCCh APC_Path , int AI_Perm=0) // 읽기/쓰기
{ return (mi_Handle= ::open( APC_Path , ZNsConst::ZNsLlioMode::ReadWrite, AI_Perm)) != -1 ; }
bool OpenApp (ZTypCPCCh APC_Path , int AI_Perm=0) // 덧붙이기
{ return (mi_Handle= ::open( APC_Path , ZNsConst::ZNsLlioMode::Append , AI_Perm)) != -1 ; }
#ifndef S_IRWXU
#define S_IRWXU 0
#endif
#ifndef S_IRUSR
#define S_IRUSR 0
#endif
#ifndef S_IWUSR
#define S_IWUSR 0
#endif
#ifndef S_IXUSR
#define S_IXUSR 0
#endif
#ifndef S_IRWXG
#define S_IRWXG 0
#endif
#ifndef S_IRGRP
#define S_IRGRP 0
#endif
#ifndef S_IWGRP
#define S_IWGRP 0
#endif
#ifndef S_IXGRP
#define S_IXGRP 0
#endif
#ifndef S_IRWXO
#define S_IRWXO 0
#endif
#ifndef S_IROTH
#define S_IROTH 0
#endif
#ifndef S_IWOTH
#define S_IWOTH 0
#endif
#ifndef S_IXOTH
#define S_IXOTH 0
#endif
/*##############################################################################
□ unix open 함수의 주요 상수.
S_IRWXU 00700 user (file owner) has read, write and execute permission
S_IRUSR 00400 user has read permission
S_IWUSR 00200 user has write permission
S_IXUSR 00100 user has execute permission
S_IRWXG 00070 group has read, write and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others have read, write and execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
##############################################################################*/
bool MakeCut(ZTypCPCCh APC_Path, int AI_Perm=(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
{ return Open(APC_Path, ZNsConst::ZNsLlioMode::WriteMakeCut, AI_Perm); }
bool MakeRW (ZTypCPCCh APC_Path, int AI_Perm=(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
{ return Open(APC_Path, ZNsConst::ZNsLlioMode::RWMake , AI_Perm); }
bool MakeApp(ZTypCPCCh APC_Path, int AI_Perm=(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
{ return Open(APC_Path, ZNsConst::ZNsLlioMode::AppendMake , AI_Perm); } // 덧붙이되 없으면 새로 만듦.
inline int GetHandle() const
{
return mi_Handle;
}/*
inline int GetHandle() const*/
off_t GetFileSize()
{
// typedef long _off_t; IN Windows
// typedef long off_t; IN Linux
struct stat VO_FileStatus;
if(fstat(mi_Handle, &VO_FileStatus)<0)
{ return -1; }
return VO_FileStatus.st_size;
}/*
off_t GetFileSize()*/
size_t Read(void* AP_Buffer, size_t AI_ByteSize)
{
return read(mi_Handle,AP_Buffer,AI_ByteSize);
// typedef unsigned int size_t;
}/*
size_t Read(void* AP_Buffer, size_t AI_ByteSize)*/
size_t Write(const void* AP_Buffer, size_t AI_ByteSize)
{
// _CRTIMP int __cdecl write(int, const void *, unsigned int); // In Visual C++ 6.0
return write(mi_Handle,AP_Buffer,AI_ByteSize);
}/*
size_t Write(const void* AP_Buffer, size_t AI_ByteSize)*/
off_t Seek(off_t AI_Offset,int AI_Whence=SEEK_SET) const
{
// typedef long off_t;
// AI_Whence is one of SEEK_SET, SEEK_CUR, SEEK_END
return ::lseek(mi_Handle,AI_Offset,AI_Whence);
/* MSDN : _lseek() returns the offset, in bytes, of the new position from the beginning of the file.
_lseeki64 returns the offset in a 64-bit integer.
The function returns ?1L to indicate an error
and sets errno either to EBADF, meaning the file handle is invalid,
or to EINVAL, meaning the value for origin is invalid or the position specified by offset
is before the beginning of the file.
On devices incapable of seeking (such as terminals and printers),
the return value is undefined. */
}/*
off_t Seek(off_t AI_Offset,int AI_Whence=SEEK_SET) const*/
/*//////////////////////////////////////////////////////////////////////////////////
■ int _fstat ( int handle, struct _stat *buffer );
__int64 _fstati64( int handle, struct _stat *buffer );
Function Required Header Compatibility
_fstat <sys/stat.h> and <sys/types.h> Win 95, Win NT
_fstati64 <sys/stat.h> and <sys/types.h> Win 95, Win NT
Return Value
_fstat and _fstati64 return 0 if the file-status information is obtained.
A return value of ?1 indicates an error, in which case errno is set to EBADF,
indicating an invalid file handle.
When you declear struct stat even in a C++ file, To use struct keyword is better
//////////////////////////////////////////////////////////////////////////////////*/
bool GetFStat(struct stat& ARR_StatBuf)
{
return fstat(mi_Handle, &ARR_StatBuf)==0;
}/*
bool GetFStat(struct stat& ARR_StatBuf)*/
static bool GetFStat(ZTypCPCCh APC_Path, struct stat& ARR_StatBuf)
{
return stat(APC_Path, &ARR_StatBuf)==0;
}/*
static bool GetFStat(ZTypCPCCh APC_Path, struct stat& ARR_StatBuf)*/
#if !defined(_WIN)
static bool GetLStat(ZTypCPCCh APC_Path, struct stat& ARR_StatBuf)
{
return lstat(APC_Path, &ARR_StatBuf)==0;
// lstat() return information of link itself if Path is a link
}/*
static bool GetLStat(ZTypCPCCh Path, struct stat& ARR_StatBuf)*/
/*/////////////////////////////////////////
#define S_ISBLK(m) (((m)&_IFMT) == _IFBLK)
#define S_ISCHR(m) (((m)&_IFMT) == _IFCHR)
#define S_ISDIR(m) (((m)&_IFMT) == _IFDIR)
#define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO)
#define S_ISREG(m) (((m)&_IFMT) == _IFREG)
#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
#define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK)
/////////////////////////////////////////*/
#endif //!defined(_WIN)
bool Close()
{
if(mi_Handle<0) return true;
bool VB_Result=(::close(mi_Handle)==0);
mi_Handle = -1; return VB_Result;
// close() returns -1 if it fail
// close() returns 0 if it succeed
}/*
bool Close()*/
int SetDefaultMask(int AI_Mode)
{
/*///////////////////////////////////
int _umask(
int pmode
);
Sets the default file-permission mask.
Parameter
pmode
Default permission setting.
Return Value
_umask returns the previous value of pmode. There is no error return.
///////////////////////////////////*/
return umask(AI_Mode);
}/*
int SetDefaultMask(int AI_Mode)*/
public:
};/*
class ZCLLIO*/
//////////////// class ZCFileInfo ////////////////
class ZCFileInfo
{
protected:
struct stat mo_FileStatus;
public :
bool GetStatus(ZTypCPCCh AP_File)
{
return stat(AP_File, &mo_FileStatus) != -1 ;
/* Each of these functions returns 0 if the file-status information is obtained.
A return value of ?1 indicates an error,
in which case errno is set to ENOENT,
indicating that the filename or path could not be found. */
}/*
bool GetStatus(ZTypCPCCh APC_Path)*/
bool GetStatus(int AI_FileHandle)
{
return fstat(AI_FileHandle, &mo_FileStatus) != -1;
}/*
bool GetStatus(int AI_FileHandle)*/
struct stat& GetStatusObj(){ return mo_FileStatus; }
public:
};/*
class ZCFileInfo*/
/*////////////////////////////////////////////////////////////////////////////
_fstat, _fstati64
Get information about an open file.
int _fstat( int handle, struct _stat *buffer );
__int64 _fstati64( int handle, struct _stat *buffer );
Function Required Header Compatibility
_fstat <sys/stat.h> and <sys/types.h> Win 95, Win NT
_fstati64 <sys/stat.h> and <sys/types.h> Win 95, Win NT
For additional compatibility information, see Compatibility in the Introduction.
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
Return Value
_fstat and _fstati64 return 0 if the file-status information is obtained.
A return value of ?1 indicates an error, in which case errno is set to EBADF,
indicating an invalid file handle.
Parameters
handle
Handle of open file
buffer
Pointer to structure to store results
Remarks
The _fstat function obtains information about the open file associated with handle and
stores it in the structure pointed to by buffer.
The _stat structure, defined in SYS\STAT.H, contains the following fields:
// typedef long time_t;
st_atime
Time of last file access.
st_ctime
Time of creation of file.
st_dev
If a device, handle; otherwise 0.
st_mode
Bit mask for file-mode information. The _S_IFCHR bit is set if handle refers to a device. The _S_IFREG bit is set if handle refers to an ordinary file. The read/write bits are set according to the files permission mode. _S_IFCHR and other constants are defined in SYS\STAT.H.
st_mtime
Time of last modification of file.
st_nlink
Always 1 on non-NTFS file systems.
st_rdev
If a device, handle; otherwise 0.
st_size
Size of the file in bytes.
If handle refers to a device, the st_atime,
st_ctime, and st_mtime and st_size fields are not meaningful.
Because STAT.H uses the _dev_t type, which is defined in TYPES.H,
you must include TYPES.H before STAT.H in your code.
Example
FSTAT.C: This program uses _fstat to report
the size of a file named F_STAT.OUT.
#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main( void )
{
struct _stat iov_base;
int fh, result;
char buffer[] = "A line to output";
if( (fh = _open( "f_stat.out", _O_CREAT | _O_WRONLY |
_O_TRUNC )) == -1 )
_write( fh, buffer, strlen( buffer ) );
// Get data associated with "fh":
result = _fstat( fh, &iov_base );
// Check if statistics are valid:
if( result != 0 )
{
printf( "Bad file handle\n" );
}
else
{
printf( "File size : %ld\n", iov_base.st_size );
printf( "Time modified : %s", ctime( &iov_base.st_ctime ) );
}
_close( fh );
}
Output
File size : 0
Time modified : Tue Mar 21 15:23:08 1995
/////////////////////////////////////////////////////////////////*/
/*/////////////////////////////////////////////////////////////////
#define _S_IREAD 0000400 // read permission, owner
#define _S_IWRITE 0000200 // write permission, owner
#define _S_IFMT 0170000 // file type mask
#define _S_IFDIR 0040000 // directory
#define _S_IFCHR 0020000 // character special
#define _S_IFIFO 0010000 // pipe
#define _S_IFREG 0100000 // regular
#define _S_IEXEC 0000100 // execute/search permission, owner
#define S_IFMT _S_IFMT
#define S_IFDIR _S_IFDIR
#define S_IFCHR _S_IFCHR
#define S_IFREG _S_IFREG
/////////////////////////////////////////////////////////////////*/
namespace ZNsFileStatMode
{
#ifndef S_IFIFO
#define S_IFIFO _S_IFIFO
#endif
const unsigned int File =S_IFMT ;
const unsigned int Directory =S_IFDIR;
const unsigned int CharDevice =S_IFCHR;
const unsigned int DefaultFile=S_IFREG;
const unsigned int Fifo =S_IFIFO;
//const unsigned int Execute =S_IEXEC;
}/*
namespace ZNsFileStatMode*/
/*////////////////////////////////////////////////////////////////////////////////////
■ WIN32_FIND_DATA
typedef struct _WIN32_FIND_DATAA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
_Field_z_ CHAR cFileName[ MAX_PATH ];
_Field_z_ CHAR cAlternateFileName[ 14 ];
#ifdef _MAC
DWORD dwFileType;
DWORD dwCreatorType;
WORD wFinderFlags;
#endif
} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA;
typedef struct _WIN32_FIND_DATAW {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
_Field_z_ WCHAR cFileName[ MAX_PATH ];
_Field_z_ WCHAR cAlternateFileName[ 14 ];
#ifdef _MAC
DWORD dwFileType;
DWORD dwCreatorType;
WORD wFinderFlags;
#endif
} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
#ifdef UNICODE
typedef WIN32_FIND_DATAW WIN32_FIND_DATA;
typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA;
typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA;
#else
typedef WIN32_FIND_DATAA WIN32_FIND_DATA;
typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA;
typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA;
#endif // UNICODE
typedef struct _WIN32_FIND_DATA
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwOID;
TCHAR cFileName[MAX_PATH];
} WIN32_FIND_DATA;
Members
dwFileAttributes
File attributes of the file found.
The following table shows the possible values for dwFileAttribute. Value Description
FILE_ATTRIBUTE_ARCHIVE
Indicates that the file or directory is an archive file or directory.
Applications use this attribute to mark files for backup or removal.
FILE_ATTRIBUTE_COMPRESSED
Indicates that the file or directory is compressed.
For a file, this means that all of the data in the file is compressed.
For a directory, this means that compression is the default
for newly created files and subdirectories.
FILE_ATTRIBUTE_DIRECTORY
Indicates that the handle identifies a directory.
FILE_ATTRIBUTE_ENCRYPTED
Indicates that the file or directory is encrypted.
For a file, this means that all data streams are encrypted. For a directory, this means that encryption is the default for newly created files and subdirectories.
FILE_ATTRIBUTE_HIDDEN
Indicates that the file or directory is hidden.
It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_INROM
Indicates that this file is an operating system file stored in ROM.
These files are read-only; they cannot be modified.
FILE_ATTRIBUTE_NORMAL
Indicates that the file or directory has no other attributes set.
This attribute is valid only if used alone.
FILE_ATTRIBUTE_READONLY
Indicates that the file or directory is read-only.
Applications can read the file but cannot write to it or delete it.
In the case of a directory, applications cannot delete it.
FILE_ATTRIBUTE_REPARSE_POINT
Indicates that the file has an associated reparse point.
FILE_ATTRIBUTE_ROMMODULE
Indicates that this file is an operating system file stored in ROM and executed directly from ROM,
rather than being first copied to RAM.
The CreateFile function cannot be used to access this file,
instead the LoadLibrary and CreateProcess functions must be used.
FILE_ATTRIBUTE_ROMSTATICREF
Indicates that the file is a DLL module that has an implicit reference
from at least one other file that is in the modules section of the image.
A file having this attribute cannot replace the functionality of the DLL with a RAM copy of the same DLL.
A file having this attribute must also have the FILE_ATTRIBUTE_INROM and FILE_ATTRIBUTE_ROMMODULE attributes.
FILE_ATTRIBUTE_SPARSE_FILE
Indicates that the file is a sparse file.
FILE_ATTRIBUTE_SYSTEM
Indicates that the file or directory is part of the operating system
or is used exclusively by the operating system.
FILE_ATTRIBUTE_TEMPORARY
Indicates that the file is being used for temporary storage.
File systems attempt to keep all of the data in memory for quicker access,
rather than flushing it back to mass storage.
A temporary file should be deleted by the application as soon as it is no longer needed.
ftCreationTime
FILETIME structure containing the time the file was created.
FindFirstFile and FindNextFile report file times in Coordinated Universal Time (UTC) format.
These functions set the FILETIME members to zero
if the file system containing the file does not support this time member.
You can use the FileTimeToLocalFileTime function to convert from UTC to local time,
and then use the FileTimeToSystemTime function
to convert the local time to a SYSTEMTIME structure containing individual members
for the month, day, year, weekday, hour, minute, second, and millisecond.
ftLastAccessTime
FILETIME structure containing the time that the file was last accessed.
The time is in UTC format; the FILETIME members are zero
if the file system does not support this time member.
ftLastWriteTime
FILETIME structure containing the time that the file was last written to.
The time is in UTC format; the FILETIME members are zero
if the file system does not support this time member.
nFileSizeHigh
High-order DWORD value of the file size, in bytes.
This value is zero unless the file size is greater than MAXDWORD.
The size of the file is equal to (nFileSizeHigh * MAXDWORD) + nFileSizeLow.
nFileSizeLow
Low-order DWORD value of the file size, in bytes.
dwOID
Object identifier of the file.
cFileName
Null-terminated string that is the name of the file.
////////////////////////////////////////////////////////////////////////////////////*/
#ifndef MAX_PATH
#define MAX_PATH 512*2
#endif
#define _MAX_PATH2 MAX_PATH*3
#ifdef _WIN
typedef HANDLE TypeDirID;
#elif defined(__unix__)
typedef DIR* TypeDirID;
#else
typedef DIR* TypeDirID;
#endif
#if defined(_WIN)
class ZCFileData : public WIN32_FIND_DATAA
{
public:
bool IsDir() const
{
return (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==FILE_ATTRIBUTE_DIRECTORY;
// #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
}/*
bool IsDir() const*/
ZTypCPCh GetFileName() const
{
return this->cFileName;
}/*
ZTypCPCh GetFileName() const*/
public:
};/*
class ZCFileData*/
#else //!defined(_WIN)
class ZCFileData : public stat
{
public:
char cFileName[_MAX_PATH2];
inline bool IsDir() const
{ return S_ISDIR(this->st_mode); }
inline ZTypCPChar GetFileName() const
{ return cFileName ; }
public:
};/*
class ZCFileData*/
#endif //!defined(_WIN)
/*//////////////////////////////////////////////////////////////////////////////////////////////////////
HANDLE FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
#define MAX_PATH 260
Parameters
lpFileName
[in] Pointer to a null-terminated string that specifies a valid directory or path and file name,
which can contain wildcard characters (* and ?).
If the string ends with a wildcard, a period, or a directory name,
the user must have access to the root and all subdirectories on the path.
In the ANSI version of this function, the name is limited to MAX_PATH characters.
To extend this limit to 32,767 wide characters,
call the Unicode version of the function and prepend "\\?\" to the path.
For more information, see Naming a File.
Windows Me/98/95: This string must not exceed MAX_PATH characters.
lpFindFileData
[out] Pointer to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory.
Return Values
If the function succeeds,
the return value is a search handle used in a subsequent call to FindNextFile or FindClose.
If the function fails,
the return value is INVALID_HANDLE_VALUE.
To get extended error information, call GetLastError.
Remarks
The FindFirstFile function opens a search handle
and returns information about the first file whose name matches the specified pattern.
It searches both the long and short file names.
After the search handle has been established,
use the FindNextFile function to search for other files that match the same pattern.
When the search handle is no longer needed, close it by using the FindClose function.
In rare cases,
file attribute information on NTFS file systems may not be current at the time you call this function.
To obtain the current NTFS file attributes, call GetFileInformationByHandle.
This function searches for files by name only;
it cannot be used for attribute-based searches.
You cannot use root directories as the lpFileName input string for FindFirstFile,
with or without a trailing backslash.
To examine files in a root directory,
use something like "C:\*" and step through the directory with FindNextFile.
To get the attributes of a root directory, use GetFileAttributes.
Prepending the string "\\?\" does not allow access to the root directory.
Similarly, on network shares, you can use an lpFileName of the form "\\server\service\*"
but you cannot use an lpFileName that points to the share itself, such as "\\server\service".
To examine any directory other than a root directory,
use an appropriate path to that directory, with no trailing backslash.
For example, an argument of "C:\windows" will return information about the directory "C:\windows",
not about any directory or file in "C:\windows".
An attempt to open a search with a trailing backslash will always fail.
trail [treil] 【L 「(배를) 끌다」의 뜻에서】 n.
1 a 끌고 간 자국, 지나간 자국, 흔적; 선적(船跡), 항적(航跡)
the ~ of a slug 달팽이의 지나간 자국
hot[hard] on the ~ (of ···) (···의) 바로 뒤에
b 냄새 자국 ((짐승의)), 실마리, 단서 ((수사상의))
2 《미캐나다》 (황야 등의) 밟아 다져진 길, (산속의) 작은 길, 오솔길, 산길
3 꼬리 ((유성의)); 길게 늘어진 자락 ((구름연기 등의)); 긴 옷자락; 늘어진 술머리카락 ((등)); (사람차 등의) 줄, 열; (땅을) 기는 덩굴[가지]; 예망(曳網)(=~ net)
4 【군사】 세워총(의 자세)
5 (사고재해 등의) 결과, 여파, 후유증
at the ~ 【군사】 세워총의 자세로
blaze a ~ to ···을 개척하다, 창시하다(pioneer)
hit the ~ 《속어》 여행 떠나다; 가버리다, 떠나다
off the ~ (짐승의) 냄새 자국을 잃고; 실마리를 잃고
on the ~ (of) ···을 추적하여; 냄새 자국[실마리]을 찾아내어
vt.
1 끌다; <옷자락 등을> 질질 끌다, 끌며 가다; <그물 등을> 끌다
~ one's skirt 치마를 질질 끌다
《~+목+전+명》 ~ a toy cart by[on] a piece of string 장난감 수레를 끈으로 끌다
《~+목+부》 He ~ed along his wounded leg. 그는 다친 다리를 끌며 걸었다
2 <구름연기 등을> 길게 나부끼게 하다; <노를> 젓지 않고 놓아 두다
3 <사람동물 등을> 추적하다, 미행하다
《~+목+전+명》 ~ a person to his house 집까지 ···을 뒤쫓다
4 《미구어》 (경주 등에서) ···의 뒤를 달리다; <가축을> 뒤쫓다; (긴 열을 지어) 뒤에 붙어서 가다; (시합에서) 지고 있다
5 《미》 <풀 등을> 밟아 길을 내다
6 <이야기 등을> 질질 끌다; 길게 발음하다
7 【군사】 세워총을 하다
T~ arms! 세워총!
~ one's coat 일부러 반발을 유발하다; 싸움을 걸다
vi.
1 끌다; <옷자락 등이> 질질 끌리다, <머리카락 등이> 늘어지다
《~+전+명》 Her long bridal gown was ~ing on[over] the church floor. 그녀의 긴 신부 의상이 교회의 마루에 질질 끌리고 있었다
2 <덩굴이> 기다
《~+전+명》 Ivy ~s over the house. 담쟁이덩굴이 집에 기어 오르고 있다
3 <구름연기가> 길게 나부끼다
《~+전+명》 Smoke ~ed from the chimney. 연기가 굴뚝에서 길게 나부꼈다
4 발을 질질 끌며 걷다 ((along)), 힘없이[느릿느릿] 걷다, 낙오하다
5 <소리가> 점점 사라지다[약해지다] ((off, away))
《~+부》 《~+전+명》 Her voice ~ed off[wy] into silence. 그녀의 목소리는 서서히 사라져 갔다
6 <이야기 등이> 질질 계속되다 ((on))
7 마지막으로 도착하다 ((in))
~ on <싫은 시간행사 등이> 길어지다( vi. 6)
BOOL RemoveDirectory(LPCTSTR lpPathName);
Parameters
lpPathName
[in] Pointer to a null-terminated string that specifies the path of the directory to be removed.
The path must specify an empty directory,
and the calling process must have delete access to the directory.
In the ANSI version of this function, the name is limited to MAX_PATH characters.
To extend this limit to 32,767 wide characters,
call the Unicode version of the function and prepend "\\?\" to the path.
For more information, see Naming a File.
Windows Me/98/95: This string must not exceed MAX_PATH characters.
Return Values
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
BOOL DeleteFile( LPCTSTR lpFileName );
Parameters
lpFileName
[in] Pointer to a null-terminated string that specifies the file to be deleted.
In the ANSI version of this function, the name is limited to MAX_PATH characters.
To extend this limit to 32,767 wide characters,
call the Unicode version of the function and prepend "\\?\" to the path.
For more information, see Naming a File.
Windows Me/98/95: This string must not exceed MAX_PATH characters.
Return Values
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero.
To get extended error information, call GetLastError.
int _rmdir (const char *dirname );
int _wrmdir (const wchar_t *dirname );
Parameters
dirname
Path of directory to be removed.
Return Value
Each of these functions returns 0
if the directory is successfully deleted.
A return value of ?1 indicates an error, and errno is set to one of the following values:
ENOTEMPTY
Given path is not a directory; directory is not empty;
or directory is either current working directory or root directory.
ENOENT
Path is invalid.
EACCESS
A program has an open handle to the directory.
//////////////////////////////////////////////////////////////////////////////////////////////////////*/
namespace ZNsIFace
{
class ZCViewDir
{
private:
int mi_Depth;
private:
void PrintDepth()
{
for(int i=1; i<=mi_Depth; ++i) ::printf(" ");
}/*
void PrintDepth()*/
/*private:*/
public :
ZCViewDir()
{
mi_Depth=0;
}/*
ZCViewDir()*/
ZNsMain::ZNsEnum::ZERun OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
{
printf(""); PrintDepth();
printf("OnFile:APC_NowPath=\"%s\", File=\"%s\"\n", APC_NowPath, AR_CFileData.GetFileName());
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
ZNsMain::ZNsEnum::ZERun OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)*/
ZNsMain::ZNsEnum::ZERun OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
{
printf("◆ OnDir:Dir=\"%s\"\n", AR_CFileData.GetFileName()); return ZNsMain::ZNsEnum::ZERun_OK;
}/*
ZNsMain::ZNsEnum::ZERun OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)*/
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
{
printf(""); PrintDepth();
printf("OnFile:APC_NowPath=\"%s\", File=\"%s\"\n", APC_NowPath, AR_CFileData.GetFileName());
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp) */
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun
OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
{
printf("◆ OnDir:Dir=\"%s\"\n", AR_CFileData.GetFileName()); return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun
OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp) */
ZNsMain::ZNsEnum::ZERun OnIntoDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
{
printf(""); PrintDepth();
printf("OnIntoDir:APC_NowPath=\"%s\", cFileName=\"%s\"\n", APC_NowPath, AR_CFileData.GetFileName());
++mi_Depth; return ZNsMain::ZNsEnum::ZERun_OK;
}/*
ZNsMain::ZNsEnum::ZERun OnIntoDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)*/
ZNsMain::ZNsEnum::ZERun OnOutOfDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
{
--mi_Depth;
printf(""); PrintDepth();
printf("OnOutOfDir:APC_NowPath=\"%s\", cFileName=\"%s\"\n", APC_NowPath, AR_CFileData.GetFileName());
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
ZNsMain::ZNsEnum::ZERun OnOutOfDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)*/
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun OnIntoDir(
ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp )
{
printf(""); PrintDepth();
printf("OnIntoDir:APC_NowPath=\"%s\", cFileName=\"%s\"\n", APC_NowPath,AR_CFileData.GetFileName());
++mi_Depth; return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun OnIntoDir
(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp) */
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun OnOutOfDir(
ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
{
--mi_Depth;
printf(""); PrintDepth();
printf("OnOutOfDir:APC_NowPath=\"%s\", cFileName=\"%s\"\n", APC_NowPath, AR_CFileData.GetFileName());
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TTypeHelp> ZNsMain::ZNsEnum::ZERun OnOutOfDir(
ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp) */
public:
};/*
class ZCViewDir*/
class ZCViewDirOfFileList
{
public :
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList)
{
ARR_CFileDataList.push_back(AR_CFileData); return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList) */
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnIntoDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList)
{
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnIntoDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList) */
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnOutOfDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList)
{
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnOutOfDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileDataList) */
public:
};/*
class ZCViewDirOfFileList*/
/*/////////////////////////////////////////////////////////////////////////////
■ class ZCViewFileOfDir 는 특정 디렉토리에서 첫번째 깊이의 디렉토리만 저장한다.
-- 2012-10-21 16:53:00
/////////////////////////////////////////////////////////////////////////////*/
class ZCViewFileOfDir
{
public:
template<typename TDirNameListRef> ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TDirNameListRef ARR_CDirNameList)
{
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TDirNameListRef> ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TDirNameListRef ARR_CDirNameList) */
template<typename TDirNameListRef> ZNsMain::ZNsEnum::ZERun OnDir(
ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TDirNameListRef ARR_CDirNameList)
{
typedef typename ZNsMain::ZtCTypeData
<TDirNameListRef>::TypeData::TypeData CStringData;
CStringData VO_CStringPath; VO_CStringPath(APC_NowPath)
(ZNsMain::ZNsConst::CPC_DirDelimiter)(AR_CFileData.GetFileName()); ///////
ARR_CDirNameList.push_back(VO_CStringPath); return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TDirNameListRef> ZNsMain::ZNsEnum::ZERun OnDir(
ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TDirNameListRef ARR_CDirNameList) */
public:
};/*
class ZCViewFileOfDir*/
class ZCViewFileDataList
{
public:
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileList)
{
ARR_CFileList.push_back(AR_CFileData); return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileList) */
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileList)
{
return ZNsMain::ZNsEnum::ZERun_OK;
}/*
template<typename TFileDataListRef> _NP_ ZNsMain::ZNsEnum::ZERun
OnDir(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TFileDataListRef ARR_CFileList) */
public:
};/*
class ZCViewFileDataList*/
}/*
namespace ZNsIFace*/
class ZCDir
{
public:
class ZCExceptDir : public ZCExceptBase
{
protected:
std::string mo_CStrFileName;
std::string mo_CStrMessage ;
public :
ZCExceptDir(const char* AP_FileName, const char* AP_Message=0)
{
if(AP_FileName!=0) mo_CStrFileName=AP_FileName;
if(AP_Message !=0) mo_CStrMessage =AP_Message ;
}/*
ZCExceptDir(const char* AP_FileName, const char* AP_Message=0)*/
std::string& GetFileName(){return mo_CStrFileName;}
std::string& GetMessage (){return mo_CStrMessage ;}
public:
};/*
class ZCExceptDir
public:*/
public:
inline static bool DoExist(const char* AP_FileName, int AI_Mode=0)
{
/* AI_Mode 가 0 이면 파일의 존재를 조사하며,
2 이면 읽기, 4면 쓰기, 6 이면 읽기 쓰기 모두 가능한지 조사한다.
요청한 액세스 타입이 맞으면 0, 그렇지 않으면 -1 을 리턴. */
return ::access(AP_FileName, AI_Mode)==0 ;
}/*
inline static bool DoExist(const char* AP_FileName, int AI_Mode=0)*/
inline static bool DoExist(const wchar_t* AP_FileName, int AI_Mode=0)
{
/* AI_Mode 가 0 이면 파일의 존재를 조사하며,
2 이면 읽기, 4면 쓰기, 6 이면 읽기 쓰기 모두 가능한지 조사한다.
요청한 액세스 타입이 맞으면 0, 그렇지 않으면 -1 을 리턴. */
char VCA_TempBuf[_MAX_PATH2];
::wcstombs(
VCA_TempBuf, AP_FileName, ZNsMain::ZftLength(AP_FileName));
return ::access(VCA_TempBuf,AI_Mode)==0 ;
}/*
inline static bool DoExist(const wchar_t* AP_FileName, int AI_Mode=0)*/
template<typename TTypChar> static const TTypChar*
GetExtName(const TTypChar* APC_FileName, ZTypLength AI_Length)
{
// 파일의 확장자를 가져온다.
if(AI_Length<1) return 0;
for(int VI_Index=AI_Length-1; VI_Index>=0; --VI_Index)
{
if(APC_FileName[VI_Index]=='.') return APC_FileName+VI_Index+1 ;
}/*
for(int VI_Index=AI_Length-1; VI_Index>=0; --VI_Index)*/
return 0;
}/*
template<typename TTypChar> static const TTypChar*
GetExtName(const TTypChar* APC_FileName, ZTypLength AI_Length)*/
template<typename TTypChar> static const TTypChar* GetExtName
(
const TTypChar* APC_FileName,
ZTypLength AI_Length ,
ZTypLength& ARRI_LenExt
)
/////////////////////////////////////////////////////////////
{
if(AI_Length<1) return 0;
for(int VI_Index=AI_Length-1; VI_Index>=0; --VI_Index)
{
if(APC_FileName[VI_Index]=='.')
{
ARRI_LenExt=AI_Length-(VI_Index+1); return APC_FileName+VI_Index+1 ;
}/*
if(APC_FileName[VI_Index]=='.')*/
}/*
for(int VI_Index=AI_Length-1; VI_Index>=0; --VI_Index)*/
ARRI_LenExt=0; return 0;
}/*
template<typename TTypChar> static const TTypChar* GetExtName
(
const TTypChar* APC_FileName,
ZTypLength AI_Length ,
ZTypLength& ARRI_LenExt
)
///////////////////////////////////////////////////////////*/
template<typename TString, typename TTypChar> ///////////////
static TString& GetExtName
(
const TTypChar* APC_FileName ,
ZTypLength AI_Length ,
TString& ARR_CStringExt
)
/////////////////////////////////////////////////////////////
{
if(AI_Length<1) return ARR_CStringExt;
int VI_Index=AI_Length-1;
for(; VI_Index>=0; --VI_Index)
{
if(APC_FileName[VI_Index]=='.') break;
}/*
for(; VI_Index>=0; --VI_Index)*/
if(VI_Index<0) return ARR_CStringExt;
return ARR_CStringExt
( APC_FileName+VI_Index+1, AI_Length-(VI_Index+1) );
}/*
template<typename TString, typename TTypChar> ///////////////
static TString& GetExtName
(
const TTypChar* APC_FileName ,
ZTypLength AI_Length ,
TString& ARR_CStringExt
)
///////////////////////////////////////////////////////////*/
template<typename TString, typename TTypChar> static bool SetExtName
(
const TTypChar* APC_FileName, ZTypLength AI_FileLen ,
const TTypChar* APC_FileExt , ZTypLength AI_ExtLength,
TString& ARR_CStringFileNew
)
/*################################################################*/
{
// APC_FileName 의 확장자를 APC_FileExt 으로 바꾼
// 새로운 파일명을 ARR_CStringFileNew 에 전달한다.
ZTypLength VL_ExtPos=ZCMainChars::FindPosFromEnd
(
APC_FileName, TTypChar(".") ,
AI_FileLen , (ZTypLength)1
);
/**********************************************/
if(VL_ExtPos<0 || VL_ExtPos==AI_FileLen-1)
{
ARR_CStringFileNew.append(APC_FileName, AI_FileLen); return false;
}
else if(VL_ExtPos==0)
{
ARR_CStringFileNew+=".";
ARR_CStringFileNew.append(APC_FileExt, AI_ExtLength);
return true;
}/*
else if(VL_ExtPos==0)*/
ARR_CStringFileNew.append(APC_FileName , VL_ExtPos );
ARR_CStringFileNew.append(TTypChar('.') );
ARR_CStringFileNew.append(APC_FileExt , AI_ExtLength );
return true;
}/*
template<typename TString, typename TTypChar> static bool SetExtName
(
const TTypChar* APC_FileName, ZTypLength AI_FileLen ,
const TTypChar* APC_FileExt , ZTypLength AI_ExtLength,
TString& ARR_CStringFileNew
)
##################################################################*/
template<typename TString> static bool SetExtName(
const TString& AR_CStringFileNow, const TString& AR_CStringNewExt, TString& ARR_CStringFileNew)
{
return SetExtName /**************/
(
AR_CStringFileNow.data() ,
AR_CStringFileNow.size() ,
AR_CStringNewExt .data() ,
AR_CStringNewExt .size() ,
RR(ARR_CStringFileNew)
);
/********************************/
}/*
template<typename TString> static bool SetExtName(
const TString& AR_CStringFileNow, const TString& AR_CStringNewExt, TString& ARR_CStringFileNew) */
template<typename TString, typename TCharView> static bool SetExtName
(
const TCharView& AR_FileName, const TCharView& AR_FileExt, TString& ARR_CStringFileNew
)
/*#################################################################*/
{
return SetExtName /***************************/
(
AR_FileName.data(), AR_FileName.size(),
AR_FileExt .data(), AR_FileExt .size()
);
/*********************************************/
}
/*#################################################################*/
template<typename TString, typename TTypChar> static bool SetFileName
(
const TTypChar* APC_FileNow, ZTypLength AI_FileNowLen,
const TTypChar* APC_FileNew, ZTypLength AI_FileNewLen,
TString& ARR_CStringFileNew
)
/////////////////////////////////////////////////////////////////////
{
/* 파일 APC_FileNow 의 확장자를 뺀 부분을 APC_FileNew 으로 바꾼,
새로운 파일명을 ARR_CStringFileNew 에 전달한다. */
ZTypLength VL_ExtPos=ZCMainChars::FindPos
(
APC_FileNow , ".", AI_FileNowLen, 1
);
/***************************************/
if(VL_ExtPos<0)
{ ARR_CStringFileNew.append(APC_FileNew, AI_FileNewLen); return false; }
else if(VL_ExtPos==0)
{ ARR_CStringFileNew.append(APC_FileNow, AI_FileNowLen); return true ; }
/*else if(VL_ExtPos==0)*/
ARR_CStringFileNew.append(APC_FileNew, AI_FileNewLen);
ARR_CStringFileNew.append('.');
if(VL_ExtPos<AI_FileNowLen-1)
{
ARR_CStringFileNew.append
(
APC_FileNow+VL_ExtPos+1, AI_FileNowLen-VL_ExtPos-1
);
}
return true; /**************/
}/*
template<typename TString, typename TTypChar> static bool SetFileName
(
const TTypChar* APC_FileNow, ZTypLength AI_FileNowLen,
const TTypChar* APC_FileNew, ZTypLength AI_FileNewLen,
TString& ARR_CStringFileNew
)
///////////////////////////////////////////////////////////////////*/
template<typename TString> static bool SetFileName(
const TString& AR_CStringFileNow, const TString& AR_CStringNewExt, TString& ARR_CStringFileNew)
{
return SetFileName /**************************************/
(
AR_CStringFileNow.data(), AR_CStringFileNow.size(),
AR_CStringNewExt .data(), AR_CStringNewExt .size(),
RR(ARR_CStringFileNew)
);
/*********************************************************/
}/*
template<typename TString> static bool SetFileName(
const TString& AR_CStringFileNow, const TString& AR_CStringNewExt, TString& ARR_CStringFileNew) */
template<typename TTypChar> static const TTypChar* GetFileNameInPath
(
const TTypChar* APC_PathName,
ZTypLength AI_Length ,
ZTypLength& ARRI_FileName
)
////////////////////////////////////////////////////////////////////
{
// 디렉토리명을 포함한 파일명 APC_PathName 에서 파일명 부분만 추출한다.
if(AI_Length<1) return 0;
using namespace ZNsMain::ZNsChars ;
using ZNsMain::ZNsConst::CPC_DirDelimiter ;
typedef ZNsChars::ZNsType::
ZtCTypeChars<TTypChar> ZCTypeChars ;
ZTypLength VL_FindPos = ZCTypeChars::FindPosFromEnd
( APC_PathName, CPC_DirDelimiter, AI_Length, 1 ) ;
if(VL_FindPos<0)
{
ARRI_FileName=AI_Length; return APC_PathName;
}
ARRI_FileName=AI_Length-(VL_FindPos+1);
return APC_PathName+VL_FindPos+1;
}/*
template<typename TTypChar> static const TTypChar* GetFileNameInPath
(
const TTypChar* APC_PathName,
ZTypLength AI_Length ,
ZTypLength& ARRI_FileName
)
//////////////////////////////////////////////////////////////////*/
template<typename TString, typename TTypChar>
static TString& GetFileNameInPath
(const TTypChar* APC_PathName, ZTypLength AI_Length, TString& ARR_FileNameCStr)
{
ZTypLength VL_Length= 0 ;
const char* VPC_File = GetFileNameInPath
( APC_PathName, AI_Length, RR(VL_Length) );
if(VL_Length>0)
ARR_FileNameCStr(VPC_File, VL_Length);
return ARR_FileNameCStr;
}/*
template<typename TString, typename TTypChar>
static TString& GetFileNameInPath
(const TTypChar* APC_PathName, ZTypLength AI_Length, TString& ARR_FileNameCStr)*/
template<typename TChars,typename TString>
static TString& GetFileNameInPath(const TChars& AR_PathName, TString& ARR_FileNameCStr)
{
return GetFileNameInPath(AR_PathName.data(), AR_PathName.size(), RR(ARR_FileNameCStr));
}/*
template<typename TChars,typename TString>
static TString& GetFileNameInPath(const TChars& AR_PathName, TString& ARR_FileNameCStr) */
static bool RmAnyDir ///////////////////////////////////////////////////////////////////
( ZTypCPCh AP_DirName, void (*APF_ExceptHandle)
(
ZTypCPCh AP_FileName, ZCFileData& AR_CFileData, ZTypCPCCh AP_Message
)
)
/*####################################################################################*/
{
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={_T('0')};
::strcpy(VCA_Search, AP_DirName );
::strcat(VCA_Search, "\\*.*" );
BOOL VB_IsSearched=TRUE ;
bool VB_RemoveFail=false;
ZCFileData VO_CFileData ; HANDLE VH_File =
::FindFirstFileA( VCA_Search, &VO_CFileData ) ;
if(VH_File==INVALID_HANDLE_VALUE){ return false; }
do //////
{
// If the attribute of the file is FILE_ATTRIBUTE_READONLY,
// change the file attribute to FILE_ATTRIBUTE_NORNAL
if( ::strcmp("." , VO_CFileData.cFileName)==0 ||
::strcmp("..", VO_CFileData.cFileName)==0 )
{
continue;
}
/*
if( ::strcmp("." , VO_CFileData.cFileName)==0 ||
::strcmp("..", VO_CFileData.cFileName)==0 )
*/
strcpy(VCA_Search, AP_DirName);
strcat(VCA_Search, "\\" );
strcat(VCA_Search, VO_CFileData.cFileName);
if(VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{ ::SetFileAttributesA(VCA_Search, FILE_ATTRIBUTE_NORMAL); }
if(VO_CFileData.IsDir()) // VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if(RmAnyDir(VCA_Search, APF_ExceptHandle)==false)
{
APF_ExceptHandle(
VCA_Search, VO_CFileData, "RmAnyDir() return false");
VB_RemoveFail=true; break;
}/*
if(RmAnyDir(VCA_Search,APF_ExceptHandle)==false)*/
}
else if(::DeleteFileA(VCA_Search)==FALSE)
{
APF_ExceptHandle(
VCA_Search, VO_CFileData, "DeleteFile() return false");
VB_RemoveFail=true; break;
}/*
else if(::DeleteFileA(VCA_Search)==FALSE)*/
VB_RemoveFail=false;
}
while((VB_IsSearched = ::FindNextFileA(VH_File, &VO_CFileData))==TRUE);
::FindClose(VH_File);
if(VB_RemoveFail==true)
{
return false;
}
if(::RemoveDirectoryA(AP_DirName)==FALSE)
{
if(APF_ExceptHandle!=0)
APF_ExceptHandle(AP_DirName, VO_CFileData, "Fail to RemoveDirectory");
return false;
}
else
{
return true;
}/*
else*/
#elif defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_) // && !defined(_WIN)
ZCFileData VO_CFileData;
dirent VO_DirEnt ;
dirent* VP_DirEnt=0 ;
TypeDirID VH_File = ::opendir(AP_DirName);
bool VB_RemoveFail= false ;
if(VH_File==NULL)
{ return false; }
::chdir(AP_DirName);
/*//////////////////////////////////////////////////////////////////
■ In dirent.h
#ifndef __USE_FILE_OFFSET64
extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
#else
# ifdef __REDIRECT
extern struct dirent *__REDIRECT (readdir, (DIR *__dirp), readdir64)
__nonnull ((1));
# else
# define readdir readdir64
# endif
#endif
-- 2009-12-21 23:41:00
■ 아래는 naver 에서 Visual C++ __REDIRECT 로 검색한 것.
Visual C++의 __REDIRECT 매크로는 특정 함수 호출을 다른 함수로 리디렉션
(재지정)하는 역할을 하며, 주로 Windows API에서 사용됩니다. 이 매크로는
함수 포인터를 통해 원래 함수의 동작을 다른 함수로 대체할 수 있도록 해
줍니다.
__REDIRECT의 주요 특징
함수 리디렉션: __REDIRECT는 호출되는 함수를 다른 함수로 변경할 수 있도
록 하여, 디버그/릴리즈 모드나 특정 플랫폼에서의 동작을 제어할 수 있습니
다.
Windows API 호환성: 주로 Windows API에서 사용되며, 함수 포인터를 통해
원본 함수의 인자 변환 규칙을 유지하면서 다른 함수로 연결할 수 있습니다.
컴파일러 옵션: Visual C++ 컴파일러의 특정 옵션을 통해 정의되며, 함수의
반환 타입과 인자 변환 규칙을 지정할 수 있습니다.
사용 예시 및 유의점
디버그/릴리즈 모드 차이: __REDIRECT는 컴파일러 옵션에 따라 동작 방식이
달라질 수 있으므로, 개발 환경에 맞는 설정이 필요합니다.
호환성: 오래된 Windows 버전이나 타겟 플랫폼에서는 지원되지 않을 수 있
으니, 사용 전 호환성을 반드시 확인해야 합니다.
__REDIRECT는 Windows API 개발에서 함수 우회, 디버그/릴리즈 모드 최적화
등에 널리 활용되는 매크로입니다
-- 2025-08-15 14:27
//////////////////////////////////////////////////////////////////*/
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
{
const bool CB_IsNotValid = ////////////////////
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0 ||
VO_DirEnt.d_ino==0
);
///////////////////////////////////////////////
if(CB_IsNotValid) continue;
if(::lstat(VP_DirEnt->d_name, &VO_CFileData)<0)
{
APF_ExceptHandle(
VP_DirEnt->d_name, VO_CFileData, "lstat Error");
VB_RemoveFail=true; break;
}/*
if(::lstat(VP_DirEnt->d_name, &VO_CFileData)<0)*/
if(VO_CFileData.IsDir()) // S_ISDIR(VO_CFileData.st_mode))
{
if(RmAnyDir(VP_DirEnt->d_name, APF_ExceptHandle)==false)
{
APF_ExceptHandle(
VP_DirEnt->d_name, VO_CFileData, "RmAnyDir() return false");
VB_RemoveFail=true; break;
}/*
if(RmAnyDir(VP_DirEnt->d_name, APF_ExceptHandle)==false)*/
}
else
{
if(::unlink(VP_DirEnt->d_name)!=0)
{
APF_ExceptHandle(
VP_DirEnt->d_name, VO_CFileData, "DeleteFile() return false");
VB_RemoveFail=true; break;
}/*
if(::unlink(VP_DirEnt->d_name)!=0)*/
}/*
else*/
VB_RemoveFail=false;
}/*
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)*/
::chdir(".."); ::closedir(VH_File);
if(VP_DirEnt ==0 ) {return false;}
if(VB_RemoveFail==true) {return false;}
::rmdir(AP_DirName); return true ;
//#elif defined(_REENTRANT) // && !defined(_WIN)
#else // !defined(_WIN) && !defined(_REENTRANT) || defined(_NO_USE_REEDDIR_R_)
ZCFileData VO_CFileData;
dirent* VP_DirEnt ;
TypeDirID VH_File = ::opendir(AP_DirName) ;
bool VB_RemoveFail= false ;
if(VH_File==NULL) return false;
::chdir(AP_DirName);
/*//////////////////////////////////////////////////////////////////
■ In dirent.h
#ifndef __USE_FILE_OFFSET64
extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
#else
# ifdef __REDIRECT
extern struct dirent *__REDIRECT (readdir, (DIR *__dirp), readdir64)
__nonnull ((1));
# else
# define readdir readdir64
# endif
#endif
-- 2009-12-21 23:41:00
//////////////////////////////////////////////////////////////////*/
while((VP_DirEnt = ::readdir(VH_File))!=0)
{
const bool CB_IsNotValid = ////////////////////
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0 ||
VP_DirEnt->d_ino==0
);
///////////////////////////////////////////////
if(CB_IsNotValid) continue;
if(lstat(VP_DirEnt->d_name, &VO_CFileData)<0)
{
APF_ExceptHandle(VP_DirEnt->d_name, VO_CFileData, "lstat Error");
VB_RemoveFail=true; break; /*##################################*/
}/*
if(lstat(VP_DirEnt->d_name, &VO_CFileData)<0)*/
if(VO_CFileData.IsDir()) // S_ISDIR(VO_CFileData.st_mode))
{
if(RmAnyDir(VP_DirEnt->d_name, APF_ExceptHandle)==false)
{
APF_ExceptHandle(VP_DirEnt->d_name, VO_CFileData, "RmAnyDir return false");
VB_RemoveFail=true; break; /*############################################*/
}/*
if(RmAnyDir(VP_DirEnt->d_name, APF_ExceptHandle)==false)*/
}
else
{
::unlink(VP_DirEnt->d_name);
}/*
else*/
VB_RemoveFail=false;
}/*
while((VP_DirEnt = ::readdir(VH_File))!=0)*/
::chdir(".."); ::closedir(VH_File);
if(VP_DirEnt ==0 ) return false;
if(VB_RemoveFail==true) return false;
::rmdir(AP_DirName); return true ;
#endif //!defined(_WIN) && !defined(_REENTRANT)
}/*
static bool RmAnyDir //////////////////////////////////////////////////////////////////
(
ZTypCPCh AP_DirName ,
void (*APF_ExceptHandle)
(ZTypCPCh AP_FileName, ZCFileData& AR_CFileData, ZTypCPCCh AP_Message)
)
######################################################################################*/
/*//////////////////////////////////////////////////////////////////////////////////////
■ int _mkdir (const char *dirname);
int _wmkdir (const wchar_t *dirname);
Parameter
dirname
Path for new directory.
Return Value
Each of these functions returns the value 0 if the new directory was created. On an error the function returns ?1 and sets errno as follows:
EEXIST
Directory was not created because dirname is the name of an existing file, directory, or device.
ENOENT
Path was not found.
int _rmdir (const char *dirname );
int _wrmdir (const wchar_t *dirname );
Parameters
dirname
Path of directory to be removed.
Return Value
Each of these functions returns 0 if the directory is successfully deleted. A return value of ?1 indicates an error, and errno is set to one of the following values:
ENOTEMPTY
Given path is not a directory; directory is not empty; or directory is either current working directory or root directory.
ENOENT
Path is invalid.
EACCESS
A program has an open handle to the directory.
See _doserrno, errno, _sys_errlist, and _sys_nerr for more information on these and other return codes.
int _unlink( const char *filename );
int _wunlink( const wchar_t *filename );
Routine Required Header Compatibility
_unlink <io.h> and <stdio.h> Win 95, Win NT
_wunlink <io.h> or <wchar.h> Win NT
For additional compatibility information,
see Compatibility in the Introduction.
Libraries
LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version
Return Value
Each of these functions returns 0 if successful.
Otherwise, the function returns ?1 and sets errno to EACCES,
which means the path specifies a read-only file, or to ENOENT,
which means the file or path is not found or the path specified a directory.
//////////////////////////////////////////////////////////////////////////////////////*/
// APC_DirPath 는 디렉토리 구분자로 끝나지 않게 하자.
static ZNsMain::ZNsEnum::ZERun IterDirectory
(
ZTypCPCh APC_DirPath, void* APC_VoidKey,
ZNsMain::ZNsEnum::ZERun (*APF_EachFile)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey),
ZNsMain::ZNsEnum::ZERun (*APF_IntoDir )(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0,
ZNsMain::ZNsEnum::ZERun (*APF_OutOfDir)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0
)
////////////////////////////////////////////
{
ZNsMain::ZNsEnum::ZERun VE_ERun = ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={'0'};
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\*.*" );
ZCFileData VO_CFileData ;
BOOL VB_IsSearched= TRUE ;
HANDLE VH_File =
::FindFirstFileA(VCA_Search, &VO_CFileData);
if(VH_File==INVALID_HANDLE_VALUE) return ZNsMain::ZNsEnum::ZERun_OK;
while(VB_IsSearched)
{
if( VO_CFileData.IsDir() ) // VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
const bool CB_IsTrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
) ;
//////////////////////
if(CB_IsTrue)
{
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\" );
::strcat(VCA_Search, VO_CFileData.cFileName);
// VCA_Search is a directory name
if(APF_IntoDir!=0)
{
if(APF_IntoDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_IntoDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(APF_IntoDir!=0)*/
if(IterDirectory(VCA_Search, APC_VoidKey, APF_EachFile, APF_IntoDir, APF_OutOfDir)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(IterDirectory(VCA_Search, APC_VoidKey, APF_EachFile, APF_IntoDir, APF_OutOfDir)==ZNsMain::ZNsEnum::ZERun_NO)*/
if(APF_OutOfDir!=0)
{
if(APF_OutOfDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_OutOfDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(APF_OutOfDir!=0)*/
}/*
if(CB_IsTrue)*/
}
else // !VO_CFileData.IsDir()
{
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else // !VO_CFileData.IsDir()*/
VB_IsSearched = ::FindNextFileA(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else //!defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File = ::opendir(APC_DirPath);
char VCA_Search[_MAX_PATH2+1]={'0'} ;
if(VH_File==NULL)
return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid =
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
);
//////////////////////////
if(CB_IsNotValid) continue;
::strcpy(VCA_Search, APC_DirPath);
if(::strcmp(APC_DirPath, "/")!=0)
{ ::strcat(VCA_Search, "/"); } // Not to append "/" at the tail of root directory name
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search, &VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error In "
"ZCDir::IterDirectory() : Can't know the file info"
);
/////////////////
return ZNsMain::ZNsEnum::ZERun_NO;
}/*
if(::lstat(VCA_Search, &VO_CFileData)<0)*/
if(VO_CFileData.IsDir()) // S_ISDIR(VO_CFileData.st_mode))
{
if(APF_IntoDir!=0)
{
if(APF_IntoDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_IntoDir(VCA_Search, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(APF_IntoDir!=0)*/
if(IterDirectory(VCA_Search, APC_VoidKey, APF_EachFile, APF_IntoDir, APF_OutOfDir)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(IterDirectory(VCA_Search, APC_VoidKey, APF_EachFile, APF_IntoDir, APF_OutOfDir)==ZNsMain::ZNsEnum::ZERun_NO)*/
if(APF_OutOfDir!=0)
{
if(APF_OutOfDir(VCA_Search,VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_OutOfDir(VCA_Search,VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(APF_OutOfDir!=0)*/
}
else // !VO_CFileData.IsDir()
{
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else // !VO_CFileData.IsDir()*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
*/
::closedir(VH_File);
if(VP_DirEnt==0)
return ZNsMain::ZNsEnum::ZERun_NO;
#endif //!defined(_WIN)
return VE_ERun;
}/*
static ZNsMain::ZNsEnum::ZERun IterDirectory
(
ZTypCPCh APC_DirPath, void* APC_VoidKey,
ZNsMain::ZNsEnum::ZERun (*APF_EachFile)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey),
ZNsMain::ZNsEnum::ZERun (*APF_IntoDir )(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0,
ZNsMain::ZNsEnum::ZERun (*APF_OutOfDir)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0
)
//////////////////////////////////////////*/
/*/////////////////////////////////////////////////////////////////////
■ AR_CViewDir 는 ZNsMain::ZNsEnum::ZERun 을 리턴하는 아래 3 벰버를 가져야 한다.
AR_CViewDir.OnFile (ZTypCPCh APC_NowPath,ZCFileData& AR_CFileData)
AR_CViewDir.OnIntoDir (ZTypCPCh APC_NowPath,ZCFileData& AR_CFileData)
AR_CViewDir.OnOutOfDir(ZTypCPCh APC_NowPath,ZCFileData& AR_CFileData)
TViewDir 은 ZNsMain::ZNsIFace::ZCViewDir 형.
■ APC_DirPath 는 디렉토리 구분자로 끝나지 않게 하자.
■ IterDirEx(~) 함수가 디렉토리와 파일을 찾아내는 Logic 을 담당한다면
TViewDir 은 찾아낸 데이타에 대한 일종의 View 를 담당한다.
■ 예제 -- 2025-08-11 10:19
#include <iostream>
#include "ZCppMain/ZMainHeadEx.H"
int main()
{
ZNsMain::ZNsIFace::ZCViewDir VO_CViewDir;
ZNsMain::ZCDir::IterDirEx("..", VO_CViewDir);
return 0;
}
/////////////////////////////////////////////////////////////////////*/
template<typename TViewDir> static ZNsMain::ZNsEnum::ZERun
IterDirEx(ZTypCPCh APC_DirPath, TViewDir AR_CViewDir)
{
typedef typename ZNsMain::
ZtCTypeData<TViewDir>::TypeData TypeViewDir ;
TypeViewDir& VR_CViewDir = ZNsMain::
ZtCTypeData<TViewDir>::GetObjRef(AR_CViewDir);
ZNsMain::ZNsEnum::ZERun VE_ERun = ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={'0'};
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\*.*" );
ZCFileData VO_CFileData ;
BOOL VB_IsSearched= TRUE ;
HANDLE VH_File =
::FindFirstFileA(VCA_Search, &VO_CFileData);
if(VH_File==INVALID_HANDLE_VALUE)
{ return ZNsMain::ZNsEnum::ZERun_OK; }
while(VB_IsSearched)
{
if( VO_CFileData.IsDir() ) // VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
const bool CB_IsTrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
);
//////////////////////
if(CB_IsTrue)
{
strcpy(VCA_Search, APC_DirPath);
strcat(VCA_Search, "\\" );
strcat(VCA_Search, VO_CFileData.cFileName);
// VCA_Search is a directory name
if(VR_CViewDir.OnIntoDir (VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}
if(IterDirEx<TViewDir> (VCA_Search, AR_CViewDir )==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}
if(VR_CViewDir.OnOutOfDir(VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewDir.OnOutOfDir(VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(CB_IsTrue)*/
}
else
{
if(VR_CViewDir.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewDir.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
VB_IsSearched=::FindNextFile(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else //!defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File = ::opendir(APC_DirPath);
char VCA_Search[_MAX_PATH2+1]={'0'} ;
if(VH_File==NULL)
return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid =
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
);
//////////////////////////
if(CB_IsNotValid) continue;
::strcpy(VCA_Search, APC_DirPath);
if(::strcmp(APC_DirPath, "/")!=0)
{ ::strcat(VCA_Search, "/"); } // Not to append "/" at the tail of root directory name
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search,&VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error In "
"ZCDir::IterDirEx() : Can't know the file info"
);
/////////////////
return ZNsMain::ZNsEnum::ZERun_NO;
}/*
if(::lstat(VCA_Search,&VO_CFileData)<0)*/
if(VO_CFileData.IsDir()) // S_ISDIR(VO_CFileData.st_mode))
{
if(VR_CViewDir.OnIntoDir (VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}
if(IterDirEx<TViewDir> (VCA_Search, AR_CViewDir )==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}
if(VR_CViewDir.OnOutOfDir(VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewDir.OnOutOfDir(VCA_Search, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}
else
{
if(VR_CViewDir.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewDir.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
*/
::closedir(VH_File);
if(VP_DirEnt==0)
return ZNsMain::ZNsEnum::ZERun_NO ;
#endif //!defined(_WIN)
return VE_ERun;
}/*
template<typename TViewDir> static ZNsMain::ZNsEnum::ZERun
IterDirEx(ZTypCPCh APC_DirPath, TViewDir AR_CViewDir) */
/*//////////////////////////////////////////////////////////////////////////////////////////////////////
■ AR_CViewDir 는 ZNsMain::ZNsEnum::ZERun 을 리턴하는 아래 3 벰버를 가져야 한다.
AR_CViewDir.OnFile <TTypeHelp>(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
AR_CViewDir.OnIntoDir <TTypeHelp>(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
AR_CViewDir.OnOutOfDir<TTypeHelp>(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, TTypeHelp AR_CTypeHelp)
-- 2012-05-23 02:24:00
//////////////////////////////////////////////////////////////////////////////////////////////////////*/
template
<typename TViewDir, typename TTypeHelp>
static ZNsMain::ZNsEnum::ZERun IterDirEx
( ZTypCPCh APC_DirPath, TViewDir AR_CViewDir, TTypeHelp AR_CTypeHelp )
{
using ZNsMain::ZNsEnum::ZERun ;
using ZNsMain::ZNsEnum::ZERun_OK;
using ZNsMain::ZNsEnum::ZERun_NO;
typedef typename ZNsMain::
ZtCTypeData<TViewDir>::TypeData TypeViewDir ;
TypeViewDir& VR_CViewDir = ZNsMain::
ZtCTypeData<TViewDir>::GetObjRef(AR_CViewDir);
ZERun VE_ERun = ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={'0'};
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\*.*" );
ZCFileData VO_CFileData ;
BOOL VB_IsSearched= TRUE ;
HANDLE VH_File =
::FindFirstFileA(VCA_Search, &VO_CFileData);
if(VH_File==INVALID_HANDLE_VALUE) return ZERun_OK;
while(VB_IsSearched)
{
if( VO_CFileData.IsDir() ) // VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
const bool CB_IsTrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
) ;
//////////////////////
if(CB_IsTrue)
{
strcpy(VCA_Search, APC_DirPath);
strcat(VCA_Search, "\\" );
strcat(VCA_Search, VO_CFileData.cFileName);
// VCA_Search is a directory name
if(VR_CViewDir.template OnIntoDir <TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }
if(IterDirEx<TViewDir, TTypeHelp> (VCA_Search, AR_CViewDir , AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }
if(VR_CViewDir.template OnOutOfDir<TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }/*
if(VR_CViewDir.template OnOutOfDir<TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)*/
}/*
if(CB_IsTrue)*/
}
else
{
if(AR_CViewDir.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{
VE_ERun=ZERun_NO; break;
}/*
if(AR_CViewDir.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZERun_NO)*/
}/*
else*/
VB_IsSearched = ::FindNextFile(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else //!defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt ;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File= ::opendir(APC_DirPath);
char VCA_Search[_MAX_PATH2+1]={'0'} ;
if(VH_File==NULL) return ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid =
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
);
//////////////////////////
if(CB_IsNotValid) continue;
::strcpy(VCA_Search, APC_DirPath);
if(::strcmp(APC_DirPath,"/")!=0)
{ ::strcat(VCA_Search, "/"); } // Not to append "/" at the tail of root directory name
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search,&VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error In "
"ZCDir::IterDirEx() : Can't know the file info"
);
/////////////////
return ZERun_NO ;
}/*
if(::lstat(VCA_Search,&VO_CFileData)<0)*/
if(VO_CFileData.IsDir()) // S_ISDIR(VO_CFileData.st_mode))
{
if(VR_CViewDir.template OnIntoDir <TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }
if(IterDirEx<TViewDir, TTypeHelp> (VCA_Search, AR_CViewDir , AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }
if(VR_CViewDir.template OnOutOfDir<TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{ VE_ERun=ZERun_NO; break; }/*
if(VR_CViewDir.template OnOutOfDir<TTypeHelp>(VCA_Search, VO_CFileData, AR_CTypeHelp)==ZERun_NO)*/
}
else
{
if(VR_CViewDir.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZERun_NO)
{
VE_ERun=ZERun_NO; break;
}/*
if(VR_CViewDir.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZERun_NO)*/
}/*
else*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif
*/
::closedir(VH_File); if(VP_DirEnt==0) return ZERun_NO;
#endif //!defined(_WIN)
return VE_ERun;
}/*
template
<typename TViewDir, typename TTypeHelp>
static ZNsMain::ZNsEnum::ZERun IterDirEx
( ZTypCPCh APC_DirPath, TViewDir AR_CViewDir, TTypeHelp AR_CTypeHelp ) */
// APC_DirPath 는 디렉토리 구분자로 끝나지 않게 하자.
static ZNsMain::ZNsEnum::ZERun IterFile /*#################################*/
(
ZTypCPCh APC_DirPath, void* APC_VoidKey,
ZNsMain::ZNsEnum::ZERun (*APF_EachFile)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey),
ZNsMain::ZNsEnum::ZERun (*APF_EachDir )(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0
)
/*##########################################################################*/
{
ZNsMain::ZNsEnum::ZERun VE_ERun=ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={'0'};
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\*.*" );
ZCFileData VO_CFileData ;
BOOL VB_IsSearched = TRUE ;
HANDLE VH_File =
::FindFirstFileA(VCA_Search, &VO_CFileData);
if(VH_File==INVALID_HANDLE_VALUE)
return ZNsMain::ZNsEnum::ZERun_OK;
while(VB_IsSearched)
{
if(VO_CFileData.IsDir()) // (VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
const bool CB_Istrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
);
//////////////////////
if(CB_Istrue)
{
if(APF_EachDir!=0)
{
if(APF_EachDir(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachDir(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(APF_EachDir!=0)*/
}/*
if(CB_Istrue)*/
}
else // !VO_CFileData.IsDir()
{
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else // !VO_CFileData.IsDir()*/
VB_IsSearched = ::FindNextFileA(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else // !defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File = ::opendir(APC_DirPath) ;
char VCA_Search[_MAX_PATH2+1]={_T('0')};
if(VH_File==NULL)
return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid =
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
);
//////////////////////////
if(CB_IsNotValid) continue;
::strcpy(VCA_Search,APC_DirPath);
if(::strcmp(APC_DirPath, "/")!=0)
{ ::strcat(VCA_Search, "/"); }
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search,&VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error "
"In ZCDir::IterFile() : Can't know the file info"
);
/////////////////
return ZNsMain::ZNsEnum::ZERun_NO;
}/*
if(::lstat(VCA_Search,&VO_CFileData)<0)*/
if( VO_CFileData.IsDir() )
{
if(APF_EachDir(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachDir(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}
else
{
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(APF_EachFile(APC_DirPath, VO_CFileData, APC_VoidKey)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif*/
::closedir(VH_File);
if(VP_DirEnt==0)
return ZNsMain::ZNsEnum::ZERun_NO ;
#endif // !defined(_WIN)
return VE_ERun;
}/*
static ZNsMain::ZNsEnum::ZERun IterFile ####################################
(
ZTypCPCh APC_DirPath, void* APC_VoidKey,
ZNsMain::ZNsEnum::ZERun (*APF_EachFile)(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey),
ZNsMain::ZNsEnum::ZERun (*APF_EachDir )(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData, void* APC_VoidKey)=0
)
############################################################################*/
/*////////////////////////////////////////////////////
■ TViewFile 은 ZNsMain::ZNsEnum::ZERun 을 리턴하는 아래 멤버를 갖는다.
OnDir (ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
OnFile(ZTypCPCh APC_NowPath, ZCFileData& AR_CFileData)
■ APC_DirPath 는 디렉토리 구분자로 끝나지 않게 하자.
////////////////////////////////////////////////////*/
template<typename TViewFile> static ZNsMain::ZNsEnum::
ZERun IterFileEx(ZTypCPCh APC_DirPath, TViewFile AR_CViewFile)
{
typedef typename ZNsMain::
ZtCTypeData<TViewFile>::TypeData TypeViewFile ;
TypeViewFile& VR_CViewFile = ZNsMain::
ZtCTypeData<TViewFile>::GetObjRef(AR_CViewFile);
ZNsMain::ZNsEnum::ZERun VE_ERun=ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={'0'};
::strcpy(VCA_Search, APC_DirPath) ;
::strcat(VCA_Search, "\\*.*" ) ;
ZCFileData VO_CFileData ;
BOOL VB_IsSearched = TRUE ;
HANDLE VH_File =
::FindFirstFileA(VCA_Search, &VO_CFileData);
if(VH_File==INVALID_HANDLE_VALUE) return ZNsMain::ZNsEnum::ZERun_OK;
while(VB_IsSearched)
{
if(VO_CFileData.IsDir()) // (VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
const bool CB_IsTrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
);
//////////////////////
if(CB_IsTrue)
{
if(VR_CViewFile.OnDir(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.OnDir(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(CB_IsTrue)*/
}
else // !VO_CFileData.IsDir()
{
if(VR_CViewFile.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else // !VO_CFileData.IsDir()*/
VB_IsSearched = ::FindNextFile(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else // !defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File= ::opendir(APC_DirPath);
char VCA_Search[_MAX_PATH2+1]={_T('0')};
if(VH_File==NULL)
return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid=(
::strcmp("." , VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
/*//////////*/ );
if(CB_IsNotValid) continue;
::strcpy(VCA_Search,APC_DirPath);
if(::strcmp(APC_DirPath, "/")!=0)
{ ::strcat(VCA_Search, "/"); }
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search,&VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error In "
"ZCDir::IterFile() : Can't know the file info"
);
/////////////////
return ZNsMain::ZNsEnum::ZERun_NO;
}/*
if(::lstat(VCA_Search,&VO_CFileData)<0)*/
if( VO_CFileData.IsDir() )
{
if(VR_CViewFile.OnDir (APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.OnDir (APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}
else
{
if(VR_CViewFile.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.OnFile(APC_DirPath, VO_CFileData)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt= ::readdir(VH_File))!=0)
#endif
*/
::closedir(VH_File);
if(VP_DirEnt==0)
return ZNsMain::ZNsEnum::ZERun_NO ;
#endif //!defined(_WIN)
return VE_ERun;
}/*
template<typename TViewFile> static ZNsMain::ZNsEnum::
ZERun IterFileEx(ZTypCPCh APC_DirPath, TViewFile AR_CViewFile) */
template<typename TViewFile, typename TTypeHelp>
static ZNsMain::ZNsEnum::ZERun IterFileEx
(ZTypCPCh APC_DirPath, TViewFile AR_CViewFile, TTypeHelp AR_CTypeHelp)
{
typedef typename ZNsMain::
ZtCTypeData<TViewFile>::TypeData TypeViewFile;
TypeViewFile& VR_CViewFile =
ZNsMain::ZtCTypeData<TViewFile>::GetObjRef(AR_CViewFile);
ZNsMain::ZNsEnum::ZERun VE_ERun= ZNsMain::ZNsEnum::ZERun_OK ;
if(APC_DirPath==0) return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_WIN)
ZTypChar VCA_Search[_MAX_PATH2+1]={_T('0')};
::strcpy(VCA_Search, APC_DirPath);
::strcat(VCA_Search, "\\*.*" );
ZCFileData VO_CFileData ;
HANDLE VH_File =
::FindFirstFile(VCA_Search, &VO_CFileData);
BOOL VB_IsSearched = TRUE ;
if(VH_File==INVALID_HANDLE_VALUE)
return ZNsMain::ZNsEnum::ZERun_OK ;
while(VB_IsSearched)
{
if(VO_CFileData.IsDir()) // (VO_CFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
const bool CB_IsTrue =
(
::strcmp("." , VO_CFileData.cFileName)!=0 &&
::strcmp("..", VO_CFileData.cFileName)!=0
);
//////////////////////
if(CB_IsTrue)
{
if(VR_CViewFile.template OnDir<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.template OnDir<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
if(CB_IsTrue)*/
}
else
{
if(VR_CViewFile.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
VB_IsSearched = ::FindNextFile(VH_File, &VO_CFileData);
}/*
while(VB_IsSearched)*/
::FindClose(VH_File);
#else // !defined(_WIN)
ZCFileData VO_CFileData;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
dirent VO_DirEnt;
#endif
dirent* VP_DirEnt;
TypeDirID VH_File= ::opendir(APC_DirPath);
char VCA_Search[_MAX_PATH2+1]={_T('0')};
if(VH_File==NULL) return ZNsMain::ZNsEnum::ZERun_OK;
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
{
const bool CB_IsNotValid =
(
::strcmp(".", VP_DirEnt->d_name)==0 ||
::strcmp("..", VP_DirEnt->d_name)==0
);
//////////////////////////
if(CB_IsNotValid) continue;
::strcpy(VCA_Search,APC_DirPath);
if(::strcmp(APC_DirPath, "/")!=0)
{ ::strcat(VCA_Search, "/"); }
::strcat(VCA_Search , VP_DirEnt->d_name);
::strcpy(VO_CFileData.cFileName, VP_DirEnt->d_name);
if(::lstat(VCA_Search,&VO_CFileData)<0)
{
throw ZCExceptDir
(
VP_DirEnt->d_name, "Fatal Error In "
"ZCDir::IterFile() : Can't know the file info"
);
/////////////////
return ZNsMain::ZNsEnum::ZERun_NO;
}/*
if(::lstat(VCA_Search,&VO_CFileData)<0)*/
if( VO_CFileData.IsDir() )
{
if(VR_CViewFile.template OnDir <TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.template OnDir <TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)*/
}
else
{
if(VR_CViewFile.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)
{
VE_ERun=ZNsMain::ZNsEnum::ZERun_NO; break;
}/*
if(VR_CViewFile.template OnFile<TTypeHelp>
(APC_DirPath, VO_CFileData, AR_CTypeHelp)==ZNsMain::ZNsEnum::ZERun_NO)*/
}/*
else*/
}/*
#if defined(_REENTRANT) && !defined(_NO_USE_REEDDIR_R_)
while(::readdir_r(VH_File, &VO_DirEnt, &VP_DirEnt)==0 && VP_DirEnt!=0)
#else
while((VP_DirEnt = ::readdir(VH_File))!=0)
#endif
*/
::closedir(VH_File);
if(VP_DirEnt==0)
return ZNsMain::ZNsEnum::ZERun_NO ;
#endif // !defined(_WIN)
return VE_ERun;
}/*
template<typename TViewFile, typename TTypeHelp>
static ZNsMain::ZNsEnum::ZERun IterFileEx
(ZTypCPCh APC_DirPath, TViewFile AR_CViewFile, TTypeHelp AR_CTypeHelp)*/
template<typename TFileDataList> // TFileDataList 은 std::ZCFileData 의 리스트.
static void GetCFileDataList(ZTypCPCh APC_DirPath, TFileDataList& AR_TFileDataList)
{
/* APC_DirPath 디렉토리에 있는 파일만을 AR_TFileDataList 에 저장한다. 즉
APC_DirPath 의 하위 디렉토리로 찾아 들어가지 않는다. */
typedef ZNsMain::ZNsIFace::ZCViewFileDataList ZCViewFileDataList;
ZCViewFileDataList VO_CViewFileDataList; ////////////////////////
IterFileEx<ZCViewFileDataList, TFileDataList&>( /////////////////
APC_DirPath ,
VO_CViewFileDataList,
AR_TFileDataList
/*/////////*/ ); ////////////////////////////////////////////////
}/*
template<typename TFileDataList>
static void GetCFileDataList(ZTypCPCh APC_DirPath, TFileDataList& AR_TFileDataList) */
template<typename TFileDataList> // TFileDataList 은 ZCFileData 의 리스트.
static void GetCFileDataListRecur(ZTypCPCh APC_DirPath, TFileDataList& AR_TFileDataList)
{
/* APC_DirPath 디렉토리와 그 하위 디렉토리에 있는
모든 파일을 AR_TFileDataList 에 저장한다. */
typedef ZNsMain::ZNsIFace::ZCViewDirOfFileList ZCViewDirOfFileList;
ZCViewDirOfFileList VO_CViewDirOfFileList; ////////////////////////
IterDirEx<ZCViewDirOfFileList, TFileDataList&>( ///////////////////
APC_DirPath ,
VO_CViewDirOfFileList,
AR_TFileDataList
/*/////////*/ ); //////////////////////////////////////////////////
}/*
template<typename TFileDataList>
static void GetCFileDataListRecur(ZTypCPCh APC_DirPath, TFileDataList& AR_TFileDataList) */
template<typename TDirNameList> // TDirNameList 은 문자열 리스트.
static void GetDirNameList(ZTypCPCh APC_DirPath, TDirNameList& ARR_CDirNameList)
{
/* APC_DirPath 의 바로 밑에 있는 하위 디렉토리만 찾는다.
즉 재귀적으로 하위 디렉토리를 찾지 않는다. */
typedef ZNsMain::ZNsIFace::ZCViewFileOfDir ZCViewFileOfDir;
ZCViewFileOfDir VO_CViewDirList; //////////////////////////
IterFileEx<ZCViewFileOfDir, TDirNameList&>( ///////////////
APC_DirPath ,
VO_CViewDirList,
ARR_CDirNameList
/*/////////*/ ); //////////////////////////////////////////
}/*
template<typename TDirNameList>
static void GetDirNameList(ZTypCPCh APC_DirPath, TDirNameList& ARR_CDirNameList) */
#ifdef _WIN
// 비어있는 디렉토리를 삭제
static bool RemoveEmptyDir(ZTypCPCh APC_PathName)
{
return ::RemoveDirectoryA(APC_PathName)==TRUE ;
}/*
static bool RemoveEmptyDir(ZTypCPCh APC_PathName)*/
static bool MakeDir(ZTypCPCh APC_PathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes=NULL)
{
return ::CreateDirectoryA(APC_PathName, lpSecurityAttributes)==TRUE ;
}/*
static bool MakeDir(ZTypCPCh APC_PathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes=NULL)*/
template<typename TString> static bool
GetNowDir(TString& ARR_CStringDir, bool AB_DoKeepPrev=false)
{
// 디렉토리명이 _MAX_DIR 을 넘을 수 있다. 그래서 넉넉하게 곱하기 4 를 한다.
if(false==AB_DoKeepPrev)
{
ZTycInt CI_BuffSize = _MAX_DIR*4 ;
ARR_CStringDir.resize(CI_BuffSize+1, ' ');
// ::GetCurrentDirectory() 는 완전 경로를 얻고 그 길이를 반환한다.
long VL_Length = ::GetCurrentDirectoryA
( CI_BuffSize, (ZTypPCh)ARR_CStringDir.data() );
if(VL_Length<1){ return false; } //////
ARR_CStringDir.resize(VL_Length, ' '); return true ;
}/*
if(false==AB_DoKeepPrev)*/
ZTypLength VL_PrevSize = ARR_CStringDir.size() ;
ZTycInt CI_BuffSize = VL_PrevSize+_MAX_DIR*4 ;
ARR_CStringDir.resize(CI_BuffSize+1, ' ') ;
ZTypPChar VP_CopyStart =
(ZTypPChar)ARR_CStringDir.data()+VL_PrevSize ;
// ::GetCurrentDirectory() 는 완전 경로를 얻고 그 길이를 반환한다.
long VL_Length =
::GetCurrentDirectoryA(CI_BuffSize, VP_CopyStart);
if(VL_Length<1) return false; //////////
ARR_CStringDir.
resize(VL_PrevSize+VL_Length, ' ' );
return true ;
}/*
template<typename TString> static bool
GetNowDir(TString& ARR_CStringDir, bool AB_DoKeepPrev=false) */
static bool ChangeDir(ZTypCPCh APC_DirName)
{
return ::SetCurrentDirectoryA(APC_DirName)==TRUE ;
}/*
static bool ChangeDir(ZTypCPCh APC_DirName)*/
#else //!defined(_WIN)
static bool RemoveEmptyDir(const char* APC_PathName)
{
return ::rmdir(APC_PathName)==0 ; // 비어있는 디렉토리를 삭제
}/*
static bool RemoveEmptyDir(const char* APC_PathName)*/
static bool MakeDir(const char* APC_PathName, mode_t mode=0744)
{
return ::mkdir(APC_PathName, mode)==0 ;
}/*
static bool MakeDir(const char* APC_PathName, mode_t mode=0744)*/
template<typename TString> static bool
GetNowDir(TString& ARR_CStringDir, bool AB_DoKeepPrev=false)
{
if(false==AB_DoKeepPrev)
{
ZTycInt CI_BuffSize = _MAX_DIR*4 ;
ARR_CStringDir.resize(CI_BuffSize+1, ' ');
char* VP_NowDir = ::getcwd
((char*)ARR_CStringDir.data(), CI_BuffSize);
if(VP_NowDir==0){return false;} ARR_CStringDir.
resize(ZNsMain::ZftLength(VP_NowDir), ' ') ;
return true; /*********************************/
}/*
if(false==AB_DoKeepPrev)*/
ZTypLength VL_PrevSize = ARR_CStringDir.size() ;
ZTycInt CI_BuffSize = VL_PrevSize+_MAX_DIR*4 ;
ARR_CStringDir.resize(CI_BuffSize+1, ' ') ;
ZTypPChar VP_CopyStart =
(ZTypPChar)ARR_CStringDir.data()+VL_PrevSize ;
char* VP_NowDir = ::getcwd(VP_CopyStart, CI_BuffSize);
if(VP_NowDir==0) return false; ////////////////////
ARR_CStringDir.
resize( VL_PrevSize+ZftLength(VP_NowDir), ' ');
return true ;
}/*
template<typename TString> static bool
GetNowDir(TString& ARR_CStringDir, bool AB_DoKeepPrev=false) */
static bool ChangeDir(const char* APC_DirName)
{
return ::chdir(APC_DirName)==0 ;
}/*
static bool ChangeDir(const char* APC_DirName)*/
#endif //!defined(_WIN)
/*/////////////////////////////////////////////////////////////////////////////////////
■ 절대 경로 AP_AbsPath 에 대해서, 기준 경로 AP_StdPath 에 로부터의 상대 경로를 구한다.
즉 현재 디렉토리 위치가 기준 경로 AP_StdPath 라 가정했을 때, 이 경로에서 절대 경로
AP_AbsPath 에 이르는 상대 경로를 구하는 것이다.
두 경로 모두 디렉토리 구분자로 끝나는 것이 일관성이 있어서 좋을 것 같다. 이렇게 하면
AP_StdPath 와 GetRelativePath() 함수로 얻어진 상대 경로를 더하면, 바로 AP_AbsPath 경
로에 이를 수 있다.
■ 기준경로 AP_StdPath 도 절대경로로 입력받는다.
■ 반환 경로에는 디렉토리 구분자가 붙는다.
■ 경로명에 디렉토리 구분자가 연이어 존재해서는 안된다.
이에 대한 에러 처리는 넣지 않았다.
■ 예제 코드
const char* CPC_AbsPath="C:\\Windows\\A\\B\\";
const char* CPC_StdPath="C:\\Windows\\A\\C\\D\\";
std::string VO_CStringRelativePath;
std::ZCDir::GetRelativePath
(
CPC_AbsPath, strlen(CPC_AbsPath),
CPC_StdPath, strlen(CPC_StdPath), RR(VO_CStringRelativePath)
);
cout<<"RelativePath="<<VO_CStringRelativePath.c_str()<<endl;
■ 예제 코드의 결과 값은 RelativePath=..\..\B\ 이어야 한다.
/////////////////////////////////////////////////////////////////////////////////////*/
template<typename TString, typename TTypChar> static TString& GetRelativePath
(
const TTypChar* AP_AbsPath, ZTypLength AI_AbsPathLen,
const TTypChar* AP_StdPath, ZTypLength AI_StdPathLen,
TString& ARR_CStrRelativePath
)
/*#########################################################################*/
{
/* 맨 끝에 디렉토리 구분자가 있다면, 길이를 1 줄이는 것으로 무효화시킨다. */
const bool CB_IsTrue = ( /*###########################*/
AI_AbsPathLen>0 &&
(
AP_AbsPath[AI_AbsPathLen-1]=='\\' ||
AP_AbsPath[AI_AbsPathLen-1]=='/'
)
/*########*/ ); /*####################################*/
if(CB_IsTrue){ --AI_AbsPathLen; }
const bool CB_IsTrue2 = ( /*##########################*/
AI_StdPathLen>0 &&
(
AP_StdPath[AI_StdPathLen-1]=='\\' ||
AP_StdPath[AI_StdPathLen-1]=='/'
)
/*#########*/); /*####################################*/
if(CB_IsTrue2){ --AI_StdPathLen; }
if(AI_AbsPathLen<1)
{
return ARR_CStrRelativePath="" ;
}
if(AI_StdPathLen<1)
{
ARR_CStrRelativePath="";
ARR_CStrRelativePath.append(AP_AbsPath, AI_AbsPathLen);
#ifdef _WIN
ARR_CStrRelativePath+="\\";
#else
ARR_CStrRelativePath+="/";
#endif
return ARR_CStrRelativePath;
}/*
if(AI_StdPathLen<1)*/
ZTypLength VI_MinLoop =
( AI_AbsPathLen>=AI_StdPathLen ? AI_StdPathLen : AI_AbsPathLen ) ;
const char* VP_AbsPath=AP_AbsPath ;
const char* VP_StdPath=AP_StdPath ;
char VC_Temp = char(0) ;
ZTypLength VI_EqualCnt = 0; // 앞에서부터 일치하는 문자열 갯수
ZTypLength VI_LastDirPos=-1; // 앞에서부터 일치하는 문자열 중 마지막 디렉토리 구분자의 위치
while(VI_EqualCnt<VI_MinLoop)
{
if((VC_Temp= *VP_AbsPath)!= *VP_StdPath) break;
if(VC_Temp=='\\' || VC_Temp=='/')
{
VI_LastDirPos=VI_EqualCnt;
}/*
if(VC_Temp=='\\' || VC_Temp=='/')*/
++VP_AbsPath ;
++VP_StdPath ;
++VI_EqualCnt;
}/*
while(VI_EqualCnt<VI_MinLoop)*/
if(VI_EqualCnt==VI_MinLoop)
{
VI_LastDirPos=VI_EqualCnt;
}
if(VI_EqualCnt<1 || VI_LastDirPos<1)
{
ARR_CStrRelativePath="";
ARR_CStrRelativePath.append(AP_AbsPath,AI_AbsPathLen);
#ifdef _WIN
ARR_CStrRelativePath+="\\";
#else
ARR_CStrRelativePath+="/";
#endif
return ARR_CStrRelativePath;
}/*
if(VI_EqualCnt<1 || VI_LastDirPos<1)*/
VP_AbsPath=AP_AbsPath+VI_LastDirPos+1;
VP_StdPath=AP_StdPath+VI_LastDirPos+1;
AI_AbsPathLen-=VI_LastDirPos+1;
AI_StdPathLen-=VI_LastDirPos+1;
if(AI_AbsPathLen<1 && AI_StdPathLen<1)
{
return ARR_CStrRelativePath="";
}
else if(AI_AbsPathLen<1)
{
ARR_CStrRelativePath="";
ZTypLength VI_DirCnt=1; ZTypLength i=0;
const char* VP_Temp=VP_StdPath;
for(; i<AI_StdPathLen; ++i)
{
if((VC_Temp=*VP_Temp++)=='\\' || VC_Temp=='/') ++VI_DirCnt;
}/*
for(; i<AI_StdPathLen; ++i)*/
for(i=0; i<VI_DirCnt; ++i)
{
#ifdef _WIN
ARR_CStrRelativePath+="..\\";
#else
ARR_CStrRelativePath+="../";
#endif
}/*
for(i=0; i<VI_DirCnt; ++i)*/
return ARR_CStrRelativePath;
}/*
else if(AI_AbsPathLen<1)*/
else if(AI_StdPathLen<1)
{
ARR_CStrRelativePath="";
ARR_CStrRelativePath.append(VP_AbsPath, AI_AbsPathLen);
#ifdef _WIN
ARR_CStrRelativePath+="\\";
#else
ARR_CStrRelativePath+="/";
#endif
return ARR_CStrRelativePath;
}/*
else if(AI_StdPathLen<1)*/
ARR_CStrRelativePath="";
ZTypLength VI_DirCnt =1 ;
ZTypLength i =0 ;
const char* VP_Temp =VP_StdPath;
for(; i<AI_StdPathLen; ++i)
{
if((VC_Temp=*VP_Temp++)=='\\' || VC_Temp=='/') ++VI_DirCnt;
}/*
for(; i<AI_StdPathLen; ++i)*/
for(i=0; i<VI_DirCnt; ++i)
{
#ifdef _WIN
ARR_CStrRelativePath+="..\\";
#else
ARR_CStrRelativePath+="../";
#endif
}/*
for(i=0; i<VI_DirCnt; ++i)*/
ARR_CStrRelativePath.append(VP_AbsPath, AI_AbsPathLen);
#ifdef _WIN
ARR_CStrRelativePath+="\\";
#else
ARR_CStrRelativePath+="/";
#endif
return ARR_CStrRelativePath;
}/*
template<typename TString, typename TTypChar> static TString& GetRelativePath
(
const TTypChar* AP_AbsPath, ZTypLength AI_AbsPathLen,
const TTypChar* AP_StdPath, ZTypLength AI_StdPathLen,
TString& ARR_CStrRelativePath
)
###########################################################################*/
template<typename TString, typename TTypChar> /*###########################*/
static TString& GetRelativePath
(
const TTypChar* AP_AbsPath,
const TTypChar* AP_StdPath,
TString& ARR_CStrRelativePath
)
/*#########################################################################*/
{
using ZNsMain::ZftLength ;
return GetRelativePath( ///////////////////////////
AP_AbsPath ,
ZftLength(AP_AbsPath) ,
AP_StdPath ,
ZftLength(AP_StdPath) ,
RR(ARR_CStrRelativePath)
/*/////////*/ ); //////////////////////////////////
}/*
template<typename TString, typename TTypChar> ###############################
static TString& GetRelativePath
(
const TTypChar* AP_AbsPath,
const TTypChar* AP_StdPath,
TString& ARR_CStrRelativePath
)
###########################################################################*/
static std::string GetRelativePath(
const char* AP_AbsPath, ZTypLength AI_AbsPathLen, const char* AP_StdPath, ZTypLength AI_StdPathLen)
{
static std::string SO_CStrRelativePath;
return GetRelativePath( ///////////////////////////
AP_AbsPath , AI_AbsPathLen ,
AP_StdPath , AI_StdPathLen ,
RR(SO_CStrRelativePath)
/*/////////*/ ); //////////////////////////////////
}/*
static std::string GetRelativePath(
const char* AP_AbsPath, ZTypLength AI_AbsPathLen, const char* AP_StdPath, ZTypLength AI_StdPathLen) */
static std::string GetRelativePath(const char* AP_AbsPath, const char* AP_StdPath)
{
using ZNsMain::ZftLength; static std::string SO_CStrRelativePath;
return GetRelativePath ///////////////////////////////
(
AP_AbsPath , ZftLength(AP_AbsPath) ,
AP_StdPath , ZftLength(AP_StdPath) ,
RR(SO_CStrRelativePath)
);
///////////////////////////////////////////////////////
}/*
static std::string GetRelativePath(const char* AP_AbsPath, const char* AP_StdPath) */
#if defined(_WIN)
static bool DeleteFile(ZTypCPCh APC_FileName)
{
return ::DeleteFileA(APC_FileName)==TRUE;
}/*
static bool DeleteFile(ZTypCPCh APC_FileName)*/
static bool MoveFile(ZTypCPCh APC_FileNow, ZTypCPCh APC_FileNew)
{
return ::MoveFileA(APC_FileNow, APC_FileNew)==TRUE;
}/*
static bool MoveFile(ZTypCPCh APC_FileNow, ZTypCPCh APC_FileNew)*/
#else //!defined(_WIN)
static bool DeleteFile(const char* APC_FileName)
{
return ::unlink(APC_FileName)==0;
}/*
static bool DeleteFile(const char* APC_FileName)*/
static bool MoveFile(const char* APC_FileNow, const char* APC_FileNew)
{
return ::rename(APC_FileNow, APC_FileNew)==0;
}/*
static bool MoveFile(const char* APC_FileNow, const char* APC_FileNew)*/
#endif // !defined(_WIN)
public:
};/*
class ZCDir*/
#ifdef _WIN
static int GetLastErrorNo(){return ::WSAGetLastError();}
#else
static int GetLastErrorNo(){return errno ;}
#endif
#ifdef __linux__
/* 비동기 입출력은 완료시 콜백할 수 있는 윈도우 쪽이 편한 듯 하다.
리눅스도 signal 을 등록하면 물론 가능하다. cf) lio_listio() */
/*//////////////////////////////////////////////////////////////
struct aiocb
{
int aio_fildes; // File desriptor.
int aio_lio_opcode; // Operation to be performed.
int aio_reqprio; // Request priority offset.
volatile void *aio_buf; // Location of buffer.
size_t aio_nbytes; // Length of transfer.
struct sigevent aio_sigevent; // Signal number and value.
Internal members.
struct aiocb *__next_prio;
int __abs_prio;
int __policy;
int __error_code;
__ssize_t __return_value;
#ifndef __USE_FILE_OFFSET64
__off_t aio_offset; // File offset.
char __pad[sizeof (__off64_t) - sizeof (__off_t)];
#else
__off64_t aio_offset; // File offset.
#endif
char __unused[32];
};
//////////////////////////////////////////////////////////////*/
class ZCAsynIO : public aiocb
{
public :
ZCAsynIO()
{
::memset(this, 0, sizeof(aiocb));
}/*
ZCAsynIO()*/
void SetHandle(int AI_FileHandle)
{
this->aio_fildes=AI_FileHandle;
}/*
void SetHandle(int AI_FileHandle)*/
void Init(int AI_FileHandle, ZNsMain::ZTypLong ALL_Offset=0)
{
this->aio_fildes=AI_FileHandle;
this->aio_offset=ALL_Offset ;
}/*
void Init(int AI_FileHandle, ZNsMain::ZTypLong ALL_Offset=0)*/
int Read(volatile char* AP_Buffer, int AI_BufSize)
{
this->aio_buf =AP_Buffer ;
this->aio_nbytes=AI_BufSize ;
return ::aio_read(this);
}/*
int Read(volatile char* AP_Buffer, int AI_BufSize)*/
int Write(volatile char* AP_Buffer, int AI_BufSize)
{
this->aio_buf =AP_Buffer ;
this->aio_nbytes=AI_BufSize ;
return ::aio_write(this);
}/*
int Write(volatile char* AP_Buffer, int AI_BufSize)*/
int GetErrCode()
{
return ::aio_error(this);
}/*
int GetErrCode()*/
/*/////////////////////////////////////////////////////////////////////
■ aio_return(struct aiocb*)
RETURN VALUE
If the asynchronous I/O operation has completed, this function returns
the value that would have been returned in case of a synchronous read,
write, or fsync request. Otherwise the return value is undefined. On
error, the error value is returned.
/////////////////////////////////////////////////////////////////////*/
ssize_t GetFinishResult()
{
return ::aio_return(this) ;
}/*
ssize_t GetFinishResult()*/
// Windows 와 호환을 위해...
void GetFinishResult(ssize_t& ARRI_FinishCode)
{
ARRI_FinishCode = ::aio_return(this) ;
}/*
void GetFinishResult(ssize_t& ARRI_FinishCode)*/
/*/////////////////////////////////////////////////////////////////////////
■ aio_cancel(int fd,struct aiocb*)
RETURN VALUE
This function returns AIO_CANCELED if all requests were successfully
cancelled. It returns AIO_NOTCANCELED when at least one of the requests
specified was not cancelled because it was in progress. In this case
one may check the status of individual requests using aio_error(3).
This function returns AIO_ALLDONE when all requests had been completed
already before this call. When some error occurs, -1 is returned, and
errno is set appropriately.
■ Return values of cancelation function.
enum
{
AIO_CANCELED,
#define AIO_CANCELED AIO_CANCELED
AIO_NOTCANCELED,
#define AIO_NOTCANCELED AIO_NOTCANCELED
AIO_ALLDONE
#define AIO_ALLDONE AIO_ALLDONE
};
/////////////////////////////////////////////////////////////////////////*/
int Cancel()
{
return ::aio_cancel(this->aio_fildes, this) ;
}/*
int Cancel()*/
int Cancel(int AI_FileDesc)
{
return ::aio_cancel(AI_FileDesc, this) ;
}/*
int Cancel(int AI_FileDesc)*/
/*/////////////////////////////////////////////////////////////////////////
■ aio_fsync(int op,struct aiocb*);
** DESCRIPTION
The aio_fsync function does a sync on all outstanding asynchronous I/O
operations associated with aiocbp->aio_fildes.
More precisely, if op is O_SYNC, then all currently queued I/O opera-
tions shall be completed as if by a call of fsync(2), and if op is
O_DSYNC, this call is the asynchronous analog of fdatasync(2). Note
that this is a request only - this call does not wait for I/O comple-
tion.
Apart from aio_fildes the only field in the structure pointed to by
aiocbp that is used by this call is the aio_sigevent field (a struct
sigevent) that indicates the desired type of asynchronous notification
at completion. All other fields are ignored.
** RETURN VALUE
On success (the sync request was successfully queued) this function
returns 0. On error -1 is returned, and errno is set appropriately.
** Operation codes for `aio_lio_opcode'.
enum
{
LIO_READ,
#define LIO_READ LIO_READ
LIO_WRITE,
#define LIO_WRITE LIO_WRITE
LIO_NOP
#define LIO_NOP LIO_NOP
};
/////////////////////////////////////////////////////////////////////////*/
bool FSync(int AI_Operation)
{
return ::aio_fsync(AI_Operation, this)==0 ;
}/*
bool FSync(int AI_Operation)*/
/*/////////////////////////////////////////////////////////////////////////
■ int aio_suspend(const struct aiocb * const cblist[],int n, const struct timespec *timeout);
** DESCRIPTION
The aio_suspend function suspends the calling process until at least
one of the asynchronous I/O requests in the list cblist of length n
have completed, a signal is delivered, or timeout is not NULL and the
time interval it indicates has passed.
Each item in the list must either be NULL (and then is ignored), or a
pointer to a control block on which I/O was initiated using
aio_read(3), aio_write(3), or lio_listio(3).
If CLOCK_MONOTONIC is supported, this clock is used to measure the
timeout interval.
** RETURN VALUE
If this function returns after completion of one of the indicated
requests, it returns 0. Otherwise it returns -1 and sets errno appro-
priately.
/////////////////////////////////////////////////////////////////////////*/
bool Suspend(const struct timespec* AP_TimeOut)
{
aiocb* VP_AIOCB[1]; VP_AIOCB[0]=this;
return ::aio_suspend(VP_AIOCB, 1/*VP_AIOCB 원소수*/, AP_TimeOut)==0 ;
}/*
bool Suspend(const struct timespec* AP_TimeOut)*/
static bool Suspend(const struct aiocb* const APA_AIOCB[], int AI_Size, const struct timespec* AP_TimeOut)
{
return ::aio_suspend(APA_AIOCB, AI_Size, AP_TimeOut)==0 ;
}/*
static bool Suspend(const struct aiocb* const APA_AIOCB[], int AI_Size, const struct timespec* AP_TimeOut)*/
/*////////////////////////////////////////////////////////////////////////////
■ 윈도우의 WaitForMultipleObjects() 과 비슷한 POSIX 함수는 lio_listio() 이다.
DWORD WaitForMultipleObjects
(
DWORD nCount,
CONST HANDLE* lpHandles,
BOOL fWaitAll,
DWORD dwMilliseconds
);
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
enum
{
LIO_WAIT,
#define LIO_WAIT LIO_WAIT
LIO_NOWAIT
#define LIO_NOWAIT LIO_NOWAIT
};
int lio_listio
(
int mode,
struct aiocb *restrict const list[restrict],
int nent,
struct sigevent *restrict sig
);
////////////////////////////////////////////////////////////////////////////*/
public:
};/*
class ZCAsynIO : public aiocb*/
#elif defined(_WIN)
/*//////////////////////////////////////////////////////////////////////////////
typedef struct _OVERLAPPED
{
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union
{
struct
{
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
}; HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
Internal
Reserved for operating system use.
This member, which specifies a system-dependent status,
is valid when the GetOverlappedResult function returns
without setting the extended error information to ERROR_IO_PENDING.
InternalHigh
Reserved for operating system use.
This member, which specifies the length of the data transferred,
is valid when the GetOverlappedResult function returns TRUE.
Offset
File position at which to start the transfer.
The file position is a byte offset from the start of the file.
The calling process must set this member before calling the ReadFile or WriteFile function.
This member is used only when the device is a file. Otherwise, this member must be zero.
OffsetHigh
High-order word of the file position at which to start the transfer.
This member is used only when the device is a file.
Otherwise, this member must be zero.
Pointer
Reserved for system use; do not use.
hEvent
Handle to an event that will be set to the signaled state
when the operation has been completed.
The calling process must set this member either to zero or a valid event handle
before calling any overlapped functions.
To create an event object,
use the CreateEvent function.
This function returns a handle that can be used to synchronize simultaneous I/O requests for a device.
Functions such as ReadFile and WriteFile set this handle to the nonsignaled state
before they begin an I/O operation.
When the operation has completed, the handle is set to the signaled state.
Functions such as GetOverlappedResult and the wait functions reset auto-reset events to the nonsignaled state.
Therefore, if you use an auto-reset event,
your application can hang if you wait for the operation to complete then call GetOverlappedResult
BOOL ReadFileEx
(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine
);
BOOL WriteFileEx
(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine
);
VOID CALLBACK FileIOCompletionRoutine
(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
);
//////////////////////////////////////////////////////////////////////////////*/
class ZCAsynIO : public OVERLAPPED
{
private:
HANDLE mh_Handle;
public :
ZCAsynIO(HANDLE AH_FileHandle=INVALID_HANDLE_VALUE, DWORD AI_Offset=0, DWORD AI_OffseHigh=0, HANDLE AH_Event=NULL)
{
this->mh_Handle =AH_FileHandle;
this->Offset =AI_Offset ;
this->OffsetHigh=AI_OffseHigh ;
this->hEvent =AH_Event ;
}/*
ZCAsynIO(HANDLE AH_FileHandle=INVALID_HANDLE_VALUE, DWORD AI_Offset=0, DWORD AI_OffseHigh=0, HANDLE AH_Event=NULL)*/
void SetHandle(HANDLE AH_FileHandle)
{
mh_Handle=AH_FileHandle ;
}/*
void SetHandle(AH_FileHandle)*/
void Init(HANDLE AH_FileHandle, DWORD AI_Offset=0, DWORD AI_OffseHigh=0, HANDLE AH_Event=NULL)
{
this->mh_Handle =AH_FileHandle;
this->Offset =AI_Offset ;
this->OffsetHigh=AI_OffseHigh ;
this->hEvent =AH_Event ;
}/*
void Init(HANDLE AH_FileHandle, DWORD AI_Offset=0, DWORD AI_OffseHigh=0, HANDLE AH_Event=NULL)*/
DWORD Read(LPVOID AP_Buffer, DWORD AI_BufferSize)
{
DWORD VDW_ReadSize=0; ::ReadFile( //////////
mh_Handle ,
AP_Buffer ,
AI_BufferSize ,
&VDW_ReadSize ,
this
/*/////////*/ ); ///////////////////////////
return VDW_ReadSize;
}/*
DWORD Read(LPVOID AP_Buffer, DWORD AI_BufferSize)*/
BOOL Read(LPVOID AP_Buffer, DWORD AI_BufferSize, DWORD& ARR_ReadSize)
{
return ::ReadFile(mh_Handle, AP_Buffer, AI_BufferSize, &ARR_ReadSize, this);
}/*
BOOL Read(LPVOID AP_Buffer, DWORD AI_BufferSize, DWORD& ARR_ReadSize)*/
BOOL Read(LPVOID AP_Buffer, DWORD AI_BufferSize, LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine)
{
return ::ReadFileEx(mh_Handle,AP_Buffer, AI_BufferSize, this, APF_CompletionRoutine);
}/*
BOOL Read(LPVOID AP_Buffer, DWORD AI_BufferSize, LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine)*/
DWORD Write(LPVOID AP_Buffer, DWORD AI_BufferSize)
{
DWORD VDW_WriteSize=0; ::WriteFile(
mh_Handle ,
AP_Buffer ,
AI_BufferSize ,
&VDW_WriteSize ,
this
/*/////////*/ ); //////////////////
return VDW_WriteSize;
}/*
DWORD Write(LPVOID AP_Buffer, DWORD AI_BufferSize)*/
BOOL Write(LPVOID AP_Buffer, DWORD AI_BufferSize, DWORD& ARR_WriteSize)
{
return ::WriteFile(mh_Handle,AP_Buffer, AI_BufferSize, &ARR_WriteSize,this);
}/*
BOOL Write(LPVOID AP_Buffer, DWORD AI_BufferSize, DWORD& ARR_WriteSize)*/
BOOL Write(LPVOID AP_Buffer, DWORD AI_BufferSize, LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine)
{
return ::WriteFileEx(mh_Handle, AP_Buffer, AI_BufferSize, this, APF_CompletionRoutine);
}/*
BOOL Write(LPVOID AP_Buffer, DWORD AI_BufferSize, LPOVERLAPPED_COMPLETION_ROUTINE APF_CompletionRoutine)*/
BOOL Cancel()
{
return ::CancelIo(mh_Handle);
}/*
BOOL Cancel()*/
BOOL GetFinishResult(DWORD& ARRI_FinishCode, BOOL AB_Wait=FALSE)
{
return ::GetOverlappedResult(mh_Handle, this, &ARRI_FinishCode, AB_Wait);
}/*
BOOL GetFinishResult(DWORD& ARRI_FinishCode, BOOL AB_Wait=FALSE)*/
DWORD GetFinishResult(BOOL AB_Wait=FALSE)
{
/*//////////////////////////////////////////////////////////////////////////////
■ 이 object 로 비동기 입출력을 한 상태에서 현재 입출력 상태를 알기 위해
이 멤버를 호출하면 물론 안된다. 그때는
DWORD GetFinishResult(OVERLAPPED& ARR_OverLapped,BOOL AB_Wait=FALSE)
을 호출해야 한다. 즉 다른 OVERLAPPED object 로 입출력 상태를 통보받아야 한다.
//////////////////////////////////////////////////////////////////////////////*/
DWORD VDW_FinishCode; ::GetOverlappedResult(
mh_Handle ,
this ,
&VDW_FinishCode ,
AB_Wait
/*//////////*/ ); //////////////////////////
return VDW_FinishCode;
}/*
DWORD GetFinishResult(BOOL AB_Wait=FALSE)*/
DWORD GetFinishResult(OVERLAPPED& ARR_OverLapped, BOOL AB_Wait=FALSE)
{
DWORD VDW_FinishCode; ::GetOverlappedResult(
mh_Handle ,
&ARR_OverLapped ,
&VDW_FinishCode ,
AB_Wait
/*/////////*/ ); ///////////////////////////
return VDW_FinishCode;
}/*
DWORD GetFinishResult(OVERLAPPED& ARR_OverLapped, BOOL AB_Wait=FALSE)*/
public:
};/*
class ZCAsynIO : public OVERLAPPED*/
/*////////////////////////////////////////////////////////////////////////////////////////////////////
■ IOCP 지원정보
Client : Requires Windows Vista, Windows XP, or Windows 2000 Professional.
Server : Requires Windows Server 2008, Windows Server 2003, or Windows 2000 Server.
Header : Declared in WinBase.h; include Windows.h.
Library Use Kernel32.lib.
DLL Requires Kernel32.dll.
※ window95, window98 에서는 지원되지 않는다.
■ 관련함수
HANDLE CreateIoCompletionPort
(
HANDLE FileHandle ,
HANDLE ExistingCompletionPort ,
ULONG_PTR CompletionKey ,
DWORD NumberOfConcurrentThreads
);
□ 인수
※ FileHandle
[in] Handle to a file opened for overlapped I/O completion.
You must specify the FILE_FLAG_OVERLAPPED flag
when using the CreateFile function to obtain the handle.
If FileHandle specifies INVALID_HANDLE_VALUE,
CreateIoCompletionPort creates an I/O completion port
without associating it with a file. In this case,
the ExistingCompletionPort parameter must be NULL and the CompletionKey parameter is ignored.
※ ExistingCompletionPort
[in] Handle to the I/O completion port.
If this parameter specifies an existing completion port,
the function associates it with the file specified by the FileHandle parameter.
The function returns the handle of the existing completion port;
it does not create a new I/O completion port.
If this parameter is NULL,
the function creates a new I/O completion port and associates it with the file specified by FileHandle.
The function returns the handle to the new I/O completion port.
-- 이 인수가 NULL 이면 새로운 완료 포트를 만든다.
※ CompletionKey
[in] Per-file completion key that is included in every I/O completion packet for the specified file.
※ NumberOfConcurrentThreads
[in] Maximum number of threads that the operating system can allow
to concurrently process I/O completion packets for the I/O completion port.
This parameter is ignored if the ExistingCompletionPort parameter is not NULL.
If this parameter is zero, the system allows as many concurrently running threads
as there are processors in the system.
□ Return Values
If the function succeeds,
the return value is the handle to the I/O completion port
that is associated with the specified file.
If the function fails, the return value is NULL.
To get extended error information, call GetLastError.
BOOL GetQueuedCompletionStatus
(
HANDLE CompletionPort ,
LPDWORD lpNumberOfBytes ,
PULONG_PTR lpCompletionKey ,
LPOVERLAPPED* lpOverlapped ,
DWORD dwMilliseconds
);
□ Return Value
If the function dequeues a completion packet for a successful I/O operation
from the completion port, the return value is nonzero.
The function stores information in the variables pointed to
by the lpNumberOfBytes, lpCompletionKey, and lpOverlapped parameters.
If *lpOverlapped is NULL and the function does not dequeue a completion packet
from the completion port, the return value is zero.
The function does not store information in the variables pointed to
by the lpNumberOfBytes and lpCompletionKey parameters.
To get extended error information, call GetLastError.
If the function did not dequeue a completion packet because the wait timed out,
GetLastError returns WAIT_TIMEOUT.
-- *lpOverlapped 가 NULL 이고 즉 OVERLAPPED* 형 인수가 NULL 로 설정되고 완료 포트로부터 완료패
-- 킷을 가져오지 않는다면 반환값은 zero 이다. 이때 lpNumberOfBytes 와 lpCompletionKey 인수에
-- 값이 설정되지 않는다. 상세한 에러 정보는 GetLastError() 를 호출할 것. 이 함수가 타임아웃으로
-- 인해 완료패킷을 가져오지 않았다면 GetLastError() 은 WAIT_TIMEOUT 을 반환한다.
If *lpOverlapped is not NULL and the function dequeues a completion packet
for a failed I/O operation from the completion port, the return value is zero.
The function stores information in the variables pointed to
by lpNumberOfBytes, lpCompletionKey, and lpOverlapped.
To get extended error information, call GetLastError
-- *lpOverlapped 가 NULL 이 아니고 즉 OVERLAPPED* 형 인수가 NULL 이 아닌 값으로 설정되고 완료 포
-- 트로부터 완료패킷을 가져왔다면 반환값은 zero 이다. 이때 lpNumberOfBytes, lpCompletionKey,
-- lpOverlapped 인수에 유효한 값이 설정된다.
BOOL PostQueuedCompletionStatus(
HANDLE CompletionPort,
DWORD dwNumberOfBytesTransferred, // can be 0
ULONG_PTR dwCompletionKey,
LPOVERLAPPED lpOverlapped // can be null
);
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
The PostQueuedCompletionStatus function posts an I/O completion packet to an I/O completion port.
-- 완료된 입출력 정보를 IOCP Queue 에 직접 전달하기 위해 사용하는 API. 이 함수를 호출하면
-- GetQueuedCompletionStatus 함수에서 받게 된다. IOCP가 반드시 파일이나, 네트웍의 전송으로만 사용
-- 되어야 할 필요는 없다. 스레드간의 통신에서도 CompletionKey 값을 주고받는 것으로 대체할 수도 있
-- 다
□ Parameters
CompletionPort
[in] Handle to an I/O completion port to which the I/O completion packet is to be posted.
dwNumberOfBytesTransferred
[in] Value to be returned through the lpNumberOfBytesTransferred parameter
of the GetQueuedCompletionStatus function.
dwCompletionKey
[in] Value to be returned through the lpCompletionKey parameter
of the GetQueuedCompletionStatus function.
lpOverlapped
[in] Value to be returned through the lpOverlapped parameter
of the GetQueuedCompletionStatus function.
※ dwNumberOfBytesTransferred can be 0
※ lpOverlapped can be null
□ Return Value
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero.
To get extended error information, call GetLastError.
□ Remarks
The I/O completion packet will satisfy an outstanding call
to the GetQueuedCompletionStatus function.
This function returns with the three values passed as the second, third, and fourth parameters
of the call to PostQueuedCompletionStatus.
The system does not use or validate these values.
In particular, the lpOverlapped parameter need not point to an OVERLAPPED structure.
■ --
////////////////////////////////////////////////////////////////////////////////////////////////////*/
class CWinIOCP
{
protected:
HANDLE mh_IOCP;
public :
CWinIOCP()
{
mh_IOCP=0;
}/*
CWinIOCP()*/
~CWinIOCP(){Close();}
bool Create(DWORD AI_ThreadCnt=0)
{
return (mh_IOCP=::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, AI_ThreadCnt))!=NULL;
}/*
bool Create(DWORD AI_ThreadCnt=0)*/
bool AddHandle(HANDLE AH_FileHandle, ULONG_PTR APL_Key, DWORD AI_ThreadCnt=0)
{
return ::CreateIoCompletionPort(AH_FileHandle, mh_IOCP, APL_Key, AI_ThreadCnt)!=NULL;
}/*
bool AddHandle(HANDLE AH_FileHandle,ULONG_PTR APL_Key, DWORD AI_ThreadCnt=0)*/
bool GetStatus(LPDWORD APL_NumberOfBytes, PULONG_PTR APL_CompletionKey, LPOVERLAPPED* APP_Overlapped, DWORD AI_Milliseconds=INFINITE)
{
return ::GetQueuedCompletionStatus(mh_IOCP, APL_NumberOfBytes, APL_CompletionKey, APP_Overlapped, AI_Milliseconds)==TRUE;
}/*
bool GetStatus(LPDWORD APL_NumberOfBytes, PULONG_PTR APL_CompletionKey, LPOVERLAPPED* APP_Overlapped, DWORD AI_Milliseconds=INFINITE)*/
bool GetStatus(LPDWORD APL_NumberOfBytes, PULONG_PTR APL_CompletionKey, LPOVERLAPPED& APRR_Overlapped, DWORD AI_Milliseconds=INFINITE)
{
return ::GetQueuedCompletionStatus(mh_IOCP, APL_NumberOfBytes, APL_CompletionKey, &APRR_Overlapped, AI_Milliseconds)==TRUE;
}/*
bool GetStatus(LPDWORD APL_NumberOfBytes, PULONG_PTR APL_CompletionKey, LPOVERLAPPED& APRR_Overlapped, DWORD AI_Milliseconds=INFINITE)*/
#if defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__>=200800
bool GetStatusEx(OVERLAPPED_ENTRY* AP_OvlpEntry, ULONG AI_EntryCnt, ULONG& ALRR_FetchEntry, DWORD AI_Milliseconds=INFINITE, BOOL AB_Alertable=TRUE)
{
return ::GetQueuedCompletionStatusEx(mh_IOCP, AP_OvlpEntry, AI_EntryCnt, &ALRR_FetchEntry, AI_Milliseconds, AB_Alertable)==TRUE;
}/*
bool GetStatusEx(OVERLAPPED_ENTRY* AP_OvlpEntry, ULONG AI_EntryCnt, ULONG& ALRR_FetchEntry, DWORD AI_Milliseconds=INFINITE, BOOL AB_Alertable=TRUE)*/
#endif //defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__>=200800
bool PostStatus(DWORD ADW_NumberOfBytes, ULONG_PTR APL_CompletionKey, LPOVERLAPPED AP_Overlapped=NULL)
{
return ::PostQueuedCompletionStatus(mh_IOCP, ADW_NumberOfBytes, APL_CompletionKey, AP_Overlapped)==TRUE;
}/*
bool PostStatus(DWORD ADW_NumberOfBytes, ULONG_PTR APL_CompletionKey, LPOVERLAPPED AP_Overlapped=NULL)*/
bool Close()
{
if(mh_IOCP==0) return true;
bool VB_IsOK =
::CloseHandle(mh_IOCP)==TRUE ;
mh_IOCP=0; return VB_IsOK;
}/*
bool Close()*/
HANDLE GetHandle()
{
return mh_IOCP;
}/*
HANDLE GetHandle()*/
public:
};/*
class CWinIOCP*/
#endif //defined(_WIN)
#ifndef _WIN
/*////////////////////////////////////////////////////////
■ RLIMIT_CPU // 초 단위의 CPU 시간
RLIMIT_FSIZE // 최대 파일 크기
RLIMIT_DATA // 최대 데이타 크기
RLIMIT_STACK // 최대 스택 크기
RLIMIT_CORE // 최대 코어 파일 크기
RLIMIT_RSS // 최대 거주 집합 크기
RLIMIT_NPROC // 최대 프로세스 수
RLIMIT_NOFILE // 최대 열 수 있는 파일의 수
RLIMIT_MEMLOCK // 최대 잠긴 기억 장소 주소 공간
RLIMIT_AS // 주소 공간(가상 메모리) 제한값
만일 RLIM_INFINITY 로 설정되었다면 자원은 무제한이다.
RLIMIT_OFILE는 RLIMIT_NOFILE에대한 BSD 이름이다.
■ rlimit 구조체는 다음과 같다:
struct rlimit
{
rlim_t rlim_cur;
rlim_t rlim_max;
};
■ -- 2010-02-10 22:43:00
■ http://carenam.egloos.com/9515070
ulimit -c 해서 core file size가 0 으로 되어 있다면 core file 이 생성되지 않음(linux 최초 기본값).
Core file size 변경 방법입니다.
방법1: ulimit -c unlimited <-- 한시적인 적용 (rebooting 후 해제 됨)
방법2: /etc/profile 파일 변경 <-- rebooting 후에도 설정 유지 됨
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1 부분을 아래와 같이 수정
ulimit -S -c unlimited > /dev/null 2>&1
# source /etc/profile <-- /etc/profile을 수정 하였으므로 설정 값 적용.
/etc/security/limits.conf 파일 변경
* soft core -1 추가
* hard core -1 추가 ( -1은 무한 의미 )
ulimit -a 또는 ulimit -c 로 확인 <-- core file 생성 적용 여부 확인 (unlimited 또는 설정파일 크기)
-- 2010-05-19 23:12:00
////////////////////////////////////////////////////////*/
template<typename TLimitSize=rlim_t> class CResrcLimit_T : public rlimit
{
public:
TLimitSize GetCurSize() const
{
return this->rlim_cur;
}/*
TLimitSize GetCurSize() const*/
TLimitSize GetMaxSize() const
{
return this->rlim_max;
}/*
TLimitSize GetMaxSize() const*/
void SetCurSize(TLimitSize AI_LimitSize)
{
this->rlim_cur=AI_LimitSize;
}/*
void SetCurSize(TLimitSize AI_LimitSize)*/
void SetMaxSize(TLimitSize AI_LimitSize)
{
this->rlim_max=AI_LimitSize;
}/*
void SetMaxSize(TLimitSize AI_LimitSize)*/
void SetSize(TLimitSize AI_CurSize, TLimitSize AI_MaxSize)
{
this->rlim_cur=AI_CurSize;
this->rlim_max=AI_MaxSize;
}/*
void SetSize(TLimitSize AI_CurSize, TLimitSize AI_MaxSize)*/
bool GetInfo(int AI_Resource)
{
return ::getrlimit(AI_Resource, this)==0;
}/*
bool GetInfo(int AI_Resource)*/
void SetInfo(int AI_Resource)
{
return ::setrlimit(AI_Resource, this)==0;
}/*
void SetInfo(int AI_Resource)*/
public:
};/*
template<typename TLimitSize=rlim_t> class CResrcLimit_T : public rlimit */
/*///////////////////////////////////////
■ struct iovec
{
void* iov_base; // Starting address
size_t iov_len ; // Number of bytes
};
■ -- 2010-04-17 20:15:00
///////////////////////////////////////*/
template<int TVecSize=10> class ZtCIOBuffVec
{
public :
enum{EInvalidPos=-1 };
enum{EVecSize =TVecSize};
public :
typedef ::iovec StIOBuff;
protected:
::iovec mo_IOBuff[TVecSize];
ZTypLength mi_HeadPos ; // TVecSize 에서 유효한 처음 위치
ZTypLength mi_TailPos ; // TVecSize 에서 유효한 마지막 위치
ZTypLength ml_AllLen ; // 전체 버퍼 길이
public :
static char* GetCharsInVec ( StIOBuff& AR_StIOBuff){return (char*) AR_StIOBuff.iov_base;}
static const char* GetCharsInVec (const StIOBuff& AR_StIOBuff){return (const char*)AR_StIOBuff.iov_base;}
static size_t GetLengthInVec(const StIOBuff& AR_StIOBuff){return AR_StIOBuff.iov_len ;}
static void InitStIOBuff(StIOBuff& ARR_StIOBuff)
{
ARR_StIOBuff.iov_base=0;
ARR_StIOBuff.iov_len =0;
}/*
static void InitStIOBuff(StIOBuff& ARR_StIOBuff)*/
/*public:*/
public:
ZtCIOBuffVec()
{
Init();
}/*
ZtCIOBuffVec()*/
void Init()
{
mi_HeadPos=EInvalidPos;
mi_TailPos=EInvalidPos;
ml_AllLen =0 ;
}/*
void Init()*/
ZTypLength GetSize() const
{
return mi_HeadPos<=EInvalidPos ? 0 : (mi_TailPos-mi_HeadPos+1) ;
}/*
ZTypLength GetSize() const*/
ZTypLength GetAllLength() const
{
return ml_AllLen;
}/*
ZTypLength GetAllLength() const*/
bool IsFull() const
{
return GetSize()==EVecSize;
}/*
bool IsFull() const*/
StIOBuff& operator[](ZTypLength AI_Index)
{
return mo_IOBuff[AI_Index];
}/*
StIOBuff& operator[](ZTypLength AI_Index)*/
const StIOBuff& operator[](ZTypLength AI_Index) const
{
return mo_IOBuff[AI_Index];
}/*
const StIOBuff& operator[](ZTypLength AI_Index) const*/
bool IsEqual(ZTypLength AI_BuffIndex, char* APC_Buff, ZTypLength AI_Length)
{
// AI_BuffIndex 번 원소가 APC_Buff, AI_Length 인지 확인하는 함수.
// 주로 DEBUG 목적으로 설계한 함수이다.
if(AI_BuffIndex<0 || AI_BuffIndex>=EVecSize)
{ return false; }
return GetCharsInVec (mo_IOBuff[AI_BuffIndex])==APC_Buff &&
GetLengthInVec(mo_IOBuff[AI_BuffIndex])==AI_Length ;
//////
}/*
bool IsEqual(ZTypLength AI_BuffIndex, char* APC_Buff, ZTypLength AI_Length)*/
bool AddBuff(char* APC_Buff, ZTypLength AI_Length)
{
if(AI_Length<1 || mi_TailPos+1>=TVecSize)
{ return false; }
if(mi_HeadPos<=EInvalidPos)
{ mi_HeadPos=0; }
mo_IOBuff[++mi_TailPos].iov_base=APC_Buff ;
mo_IOBuff[ mi_TailPos].iov_len =AI_Length;
ml_AllLen+=AI_Length; return true;
}/*
bool AddBuff(char* APC_Buff, ZTypLength AI_Length)*/
template<typename TString> bool AddBuffCStr(TString& AR_CString)
{
return AddBuff(AR_CString.data(), AR_CString.size());
}/*
template<typename TString> bool AddBuffCStr(TString& AR_CString)*/
int MinusLength(ZTypLength AL_Length, ZTypLength* APL_LastInvalidByte=0)
{
/*//////////////////////////////////////////////////////////////////////
■ mo_WSABuff 의 유효버퍼에서 AL_Length 만큼 처리가 된 것으로 셋팅한다.
■ int VI_EmptyBuffCnt(처리 후 비어 있게 되는 버퍼 갯수)를 반환한다.
■ long* APL_LastInvalidByte 에 유효한 mo_IOBuff 중 마지막 원소에서 무효
화되는 바이트 길이를 전달한다.
//////////////////////////////////////////////////////////////////////*/
if(AL_Length<1 ) return 0 ;
if(ml_AllLen<AL_Length) AL_Length=ml_AllLen ;
// 이때 mi_HeadPos, mi_TailPos 에 유효한 값이 들어있다.
int VI_EmptyBuffCnt= 0 ;
::iovec* VP_IOBuff = mo_IOBuff+mi_HeadPos;
for(int i=mi_HeadPos; i<=mi_TailPos; ++i)
{
if(AL_Length>=ZNsMain::ZTypInt(VP_IOBuff->iov_len))
{
AL_Length -= VP_IOBuff->iov_len;
ml_AllLen -= VP_IOBuff->iov_len;
++VI_EmptyBuffCnt;
if(++mi_HeadPos>mi_TailPos)
{
Init(); return VI_EmptyBuffCnt;
}
if(AL_Length<=0)
{
return VI_EmptyBuffCnt;
}
}
else // AL_Length<ZNsMain::ZTypInt(VP_IOBuff->iov_len)
{
if(APL_LastInvalidByte!=0)
*APL_LastInvalidByte=AL_Length;
VP_IOBuff->iov_base = (char*)(VP_IOBuff->iov_base)+AL_Length;
VP_IOBuff->iov_len -= AL_Length;
ml_AllLen -= AL_Length;
return VI_EmptyBuffCnt;
}/*
else // AL_Length<ZNsMain::ZTypInt(VP_IOBuff->iov_len)*/
++VP_IOBuff;
}/*
for(int i=mi_HeadPos; i<=mi_TailPos; ++i)*/
return VI_EmptyBuffCnt;
}/*
int MinusLength(ZTypLength AL_Length, ZTypLength* APL_LastInvalidByte=0)*/
StIOBuff* GetHeadBuffPtr()
{
return mi_HeadPos<=EInvalidPos ? 0 : mo_IOBuff+mi_HeadPos ;
}/*
StIOBuff* GetHeadBuffPtr()*/
void MoveFirst()
{
if(mi_HeadPos<1) return ;
int VI_Index= 0, i = mi_HeadPos;
int VI_ValidBuffCnt = GetSize() ;
for(; i<=mi_TailPos; ++i)
{
mo_IOBuff[VI_Index++]=mo_IOBuff[i];
}/*
for(; i<=mi_TailPos; ++i)*/
// mi_HeadPos 개 만큼을 앞으로 이동시켰으므로
// 이 다음 유효하지 않은 mi_HeadPos 개 StIOBuff 버퍼를 초기화한다.
for(i=0; i<mi_HeadPos; ++i)
{
InitStIOBuff(RR(mo_IOBuff[VI_Index++]));
}/*
for(i=0; i<mi_HeadPos; ++i)*/
mi_HeadPos= 0 ; mi_TailPos= VI_ValidBuffCnt-1;
}/*
void MoveFirst()*/
template<typename TString> void SetInfoCStr(
TString& ARR_CStringInfo, const char* APC_Indent="")
{
// 이 함수는 주로 DEBUG 를 위해 설계하였다.
ARR_CStringInfo(APC_Indent)("All Buffer Cnt=")(EVecSize) ("\r\n");
ARR_CStringInfo(APC_Indent)("Use Buffer Cnt=")(GetSize()) ("\r\n");
ARR_CStringInfo(APC_Indent)("All Byte Cnt=")(GetAllLength())("\r\n");
ARR_CStringInfo(APC_Indent)("HeadPos=")(mi_HeadPos)(", TailPos=")(mi_TailPos)("\r\n");
if(mi_HeadPos<=EInvalidPos) return;
for(int i=mi_HeadPos; i<=mi_TailPos; ++i)
{
ARR_CStringInfo(APC_Indent)("i=")(i)(" : Length=")(GetLengthInVec(mo_IOBuff[i]))("\r\n");
ARR_CStringInfo(APC_Indent)(" Data=\"")(GetCharsInVec(mo_IOBuff[i]),GetLengthInVec(mo_IOBuff[i]))("\"\r\n");
}/*
for(int i=mi_HeadPos; i<=mi_TailPos; ++i)*/
}/*
template<typename TString> void SetInfoCStr(
TString& ARR_CStringInfo, const char* APC_Indent="") */
public:
};/*
template<int TVecSize=10> class ZtCIOBuffVec*/
template<> class ZtCIOBuffVec<0>
{
public:
enum{EInvalidPos=-1};
enum{EVecSize = 0};
public:
typedef ::iovec StIOBuff;
public:
ZtCIOBuffVec(){}
void Init(){}
int GetSize() const {return 0;}
bool AddBuff(
char* APC_Buff, ZTypLength AI_Length){return false;}
void MinusLength(long AL_Length){}
StIOBuff* GetHeadBuffPtr(){return 0;}
void MoveFirst(){}
public:
};/*
template<> class ZtCIOBuffVec<0>*/
#endif //!_WIN
/*#######################################################################################################
■ 아래 WriteFileRaw() 함수는 원래, ZtCStringBase<> 의 멤버 함수로 WriteFile() 라는 정적 멤버 함수였으나
이미 같은 이름의 비정적 멤버 함수가 있다 보니, 두 개 함수를 사용했을 때, g++ 4.4.7 에서 경고가 발생했
었다.
[sauron@localhost Donut_CPP]$ g++ -g -D_DEBUG -D_REENTRANT DonutTopCheck.cpp -o DonutTopCheck_D.exe -lpthread -I../../../my_CPP/CPP_Std/ -I../../../my_CPP/CPP_Net/ -I../../../my_CPP/CPP_Main/
DonutTopCheck.cpp: In static member function 'static void std::CSngtChecker::Exec()::HandleLine::Exec(CStringData&)':
DonutTopCheck.cpp:235: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
Donut.H:23376: note: candidate 1: static bool std::ZtCStringBase<TTypCh, TAlloc, TAllocSize, TTypeString>::WriteFile(const TTypCh*, const typename TTypeString::ZCTypeChars::TypeChar*, typename TTypeString::ZCTypeChars::TypeLength, bool, int) [with TTypCh = char, TAlloc = std::ZtCAllocClass<char>, TAllocSize = std::ZtCAllocMemSize<char>, TTypeString = std::ZNsType::ZtCTypeStringBase<char, std::ZtCAllocClass<char>, std::ZtCAllocMemSize<char>, long int>]
Donut.H:23318: note: candidate 2: bool std::ZtCStringBase<TTypCh, TAlloc, TAllocSize, TTypeString>::WriteFile(const TTypCh*, bool, int) const [with TTypCh = char, TAlloc = std::ZtCAllocClass<char>, TAllocSize = std::ZtCAllocMemSize<char>, TTypeString = std::ZNsType::ZtCTypeStringBase<char, std::ZtCAllocClass<char>, std::ZtCAllocMemSize<char>, long int>]
DonutTopCheck.cpp:235: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
Donut.H:23376: note: candidate 1: static bool std::ZtCStringBase<TTypCh, TAlloc, TAllocSize, TTypeString>::WriteFile(const TTypCh*, const typename TTypeString::ZCTypeChars::TypeChar*, typename TTypeString::ZCTypeChars::TypeLength, bool, int) [with TTypCh = char, TAlloc = std::ZtCAllocClass<char>, TAllocSize = std::ZtCAllocMemSize<char>, TTypeString = std::ZNsType::ZtCTypeStringBase<char, std::ZtCAllocClass<char>, std::ZtCAllocMemSize<char>, long int>]
Donut.H:23318: note: candidate 2: bool std::ZtCStringBase<TTypCh, TAlloc, TAllocSize, TTypeString>::WriteFile(const TTypCh*, bool, int) const [with TTypCh = char, TAlloc = std::ZtCAllocClass<char>, TAllocSize = std::ZtCAllocMemSize<char>, TTypeString = std::ZNsType::ZtCTypeStringBase<char, std::ZtCAllocClass<char>, std::ZtCAllocMemSize<char>, long int>]
그래서 WriteFileRaw() 로 이름을 바꾸고, std 의 전역 함수로 뺀 것이다. -- 2015-09-25 20:15:00
■ ZfWriteFileRaw() 로 이름을 바꾸었다. -- 2025-08-11 10:52
#######################################################################################################*/
static bool ZfWriteFileRaw /*//////////////////////////////////////////////////////////////////////////*/
(
ZTypCPCh APC_FileName , ZTypCPCh APC_Content ,
ZTypLength AL_ContentLen, bool AB_DoAppend=true, int AI_RightMode=-1
)
/*#####################################################################################################*/
{
// int AI_RightMode = -1 은 리눅스에서만 쓴다.
#ifdef _WIN
HANDLE VH_File = ::CreateFileA(
APC_FileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
if(VH_File==INVALID_HANDLE_VALUE) return false;
if(AB_DoAppend==true)
::SetFilePointer(VH_File, 0, NULL, FILE_END); // 덧붙이는 경우라면 파일 포인터를 맨 끝으로 옮긴다.
else ::SetEndOfFile (VH_File ); // 덧붙이는 경우가 아니면 기존 내용을 지운다.
DWORD NumberOfBytesWritten = 0 ;
if(::WriteFile(VH_File, APC_Content, AL_ContentLen, &NumberOfBytesWritten, NULL)==FALSE)
{
::CloseHandle(VH_File); return false;
}/*
if(::WriteFile(VH_File, APC_Content, AL_ContentLen, &NumberOfBytesWritten, NULL)==FALSE)*/
return ::CloseHandle(VH_File)==TRUE ;
#else // !defined(_WIN)
// 리눅스의 경우
using ZNsConst::ZNsLlioMode::AppendMake ;
using ZNsConst::ZNsLlioMode::WriteMakeCut;
ZTycInt CI_FileOpenErr = -1 ;
ZTycInt CI_FileOpenTag =
(
AI_RightMode<0 ?
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP :
AI_RightMode
) ;
//////////////////////////////////
int AH_FileDesc = CI_FileOpenErr ;
if(AB_DoAppend==true)
{
const bool CB_IsError = ////////////////////////////////////
(
(
AH_FileDesc = ::open
( APC_FileName, AppendMake, CI_FileOpenTag )
)==CI_FileOpenErr
);
////////////////////////////////////////////////////////////
if(CB_IsError) return false; ///////////////////////////////
}
else
{
const bool CB_IsError = ////////////////////////////////////
(
(
AH_FileDesc = ::open
( APC_FileName, WriteMakeCut, CI_FileOpenTag )
)==CI_FileOpenErr
);
//////////////////////////////////////////////////////////////
if(CB_IsError) return false; /////////////////////////////////
}/*
else*/
if(::write(AH_FileDesc, APC_Content, AL_ContentLen)<AL_ContentLen)
{
::close(AH_FileDesc); return false;
}/*
if(::write(AH_FileDesc, APC_Content, AL_ContentLen)<AL_ContentLen)*/
return ::close(AH_FileDesc)==0 ;
#endif //!defined(_WIN)
}/*
static bool ZfWriteFileRaw( /////////////////////////////////////////////////////////////////////////////
(
ZTypCPCh APC_FileName , ZTypCPCh APC_Content ,
ZTypLength AL_ContentLen, bool AB_DoAppend=true, int AI_RightMode=-1
)
#######################################################################################################*/
template<typename TStringData> bool ZftLoadFile /*////////////////////////////*/
(
TStringData& ARR_SaveCStr , ZTypCPCChar APC_FileName ,
ZTypLength AL_LoadSize=0 , ZTypLength AL_Offset =0,
bool AB_DoAppend=true
)
/*#############################################################################*/
{
// window 에서 _open() 함수는 \r\n 을 한 문자로 입력받음에 주의.
if(AL_Offset<0) AL_Offset=0;
typedef ZtCCharType<TStringData> ZCCharType;
typedef typename ZCCharType::TypeChar Typechar ;
#ifndef _WIN
int AH_FileDesc = ::open
(APC_FileName, ZNsConst::ZNsLlioMode::Read);
if(AH_FileDesc == -1) return false;
// 파일 기술자를 파일의 맨 끝으로 이동시켜 파일 크기를 구한다.
off_t VL_LastPos = ::lseek
(AH_FileDesc, 0/*Offset*/, SEEK_END); // 실패시 -1
if(VL_LastPos == -1 || VL_LastPos<=AL_Offset)
{ ::close(AH_FileDesc); return false; }
/*******************************************/
VL_LastPos -= AL_Offset;
if(AL_LoadSize>0 && VL_LastPos>AL_LoadSize)
{ VL_LastPos=AL_LoadSize; }
/*=======================================*/
::lseek(AH_FileDesc, AL_Offset, SEEK_SET);
ZTypLength VL_PrevSize =
(AB_DoAppend ? ARR_SaveCStr.size() : 0);
ARR_SaveCStr.resize //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(
VL_PrevSize+VL_LastPos-AL_Offset, ' '
);
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// 윈도우에서 read() 함수는 \r\n 을 한 문자로 읽어들이므로 주의
ZTypLength VL_ReadSize = 0 ;
ZTypCPChar VP_CopyStart =
const_cast<ZTypPChar>(ARR_SaveCStr.data())+VL_PrevSize ;
if((VL_ReadSize = ::read(AH_FileDesc, VP_CopyStart, VL_LastPos))<0)
{
ARR_SaveCStr.resize(VL_PrevSize, Typechar(0));
::close(AH_FileDesc); return true; /*********/
}
/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
ARR_SaveCStr.resize(VL_PrevSize+VL_ReadSize, Typechar(0));
::close(AH_FileDesc); return true; /*********************/
#else //defined(_WIN)
ZTypLength VL_PrevSize = (AB_DoAppend ? ARR_SaveCStr.size() : 0) ;
HANDLE VH_File = ::CreateFileA /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
(
APC_FileName ,
GENERIC_READ ,
FILE_SHARE_READ , // 공유모드: 이미 열려 있는 파일을 열 수 있게 한다.
NULL ,
OPEN_EXISTING ,
FILE_ATTRIBUTE_NORMAL, // 반드시 단독으로 사용되는 플래그
NULL
);
/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
if(INVALID_HANDLE_VALUE==VH_File) return false;
DWORD dwRead2 = 0 ;
DWORD dwRead =
::SetFilePointer(VH_File, 0, NULL, FILE_END);
dwRead -= AL_Offset;
if(AL_LoadSize>0 && dwRead>AL_LoadSize)
{ dwRead=AL_LoadSize; }
ARR_SaveCStr.resize //>>>>>>>>>>>>>>>>>>>>>>>>>>>>
(
VL_PrevSize + dwRead, ' '
);
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
::SetFilePointer(VH_File, AL_Offset, NULL, FILE_BEGIN);
ZTypCPChar VP_CopyStart =
const_cast<ZTypPChar>(ARR_SaveCStr.data())+VL_PrevSize ;
if(::ReadFile(VH_File, (LPVOID)VP_CopyStart, dwRead, &dwRead2, NULL)==FALSE)
{
ARR_SaveCStr.resize(VL_PrevSize+dwRead2, Typechar(0));
::CloseHandle(VH_File); return false; /**************/
}
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
::CloseHandle(VH_File);
if(dwRead2>0)
ARR_SaveCStr.resize(VL_PrevSize+dwRead2, Typechar(0));
else ARR_SaveCStr.resize(VL_PrevSize , Typechar(0));
return true;
#endif //defined(_WIN)
}/*
template<typename TStringData> bool ZftLoadFile ////////////////////////////////
(
TStringData& ARR_SaveCStr , ZTypCPCChar APC_FileName ,
ZTypLength AL_LoadSize=0 , ZTypLength AL_Offset =0,
bool AB_DoAppend=true
)
###############################################################################*/
}/*
namespace ZNsMain*/
/*///////////////////////////////////////////////////////////////////////////////////////
■ ZCDir 클래스에서 사용된 readdir() 함수를 _REENTRANT 매크로가 정의되어 있는 경우,
readdir_r() 을 사용하는 것으로 바꾸었다. man 페이지에서는 readdir_r() 대신에
getdents() 을 사용할 것을 권고하고 있으나, freebsd 에서는 인수가 약간 다르고,
실제 테스트에 자꾸 core dump 가 발생하여 readdir_r() 을 사용하는 것으로 하였다.
int getdents(unsigned int fd, struct dirent* dirp, unsigned int count ); // In Linux
int getdents(int fd , char *buf , int nbytes); // In FreeBSD
int getdents(int fildes , struct dirent *buf , size_t nbyte ); // In solaris
OS 별로 선언이 다른 것이 지저분해 보인다.
-- 2012-05-07 01:19:00
그리고 getdents() 보다 readdir_r() 을 사용한 것이 결국 좋았다. AIX(115.21.49.210)에서
확인 결과, getdents() 는 없어도 readdir_r() 은 있었다. 즉 readdir_r() 이 좀 더 많은 OS
에서 지원된다고 봐도 된다. (2012-05-07 01:27:00)
///////////////////////////////////////////////////////////////////////////////////////*/
#endif //__ZCPPMAIIN__MAINHEAD_EX_H__