0x001 Programming/01. C | C++

[Example] 디렉터리 내용 출력

KimSangLab 2017. 12. 29. 15:00

특정 디렉터리 내에 있는 내용을 출력하는 프로그램입니다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <io.h>

#define TYPE_FILE 1  
#define TYPE_DIR 2
#define TYPE_DOT 3

#define MAX_OPTIONS 20 
#define MAX_ARG 1000 
#define MAX_COMMAND_LINE MAX_PATH+50 
#define MAX_PATH_LONG 32767 
#define MAX_NAME 256    

#ifdef _UNICODE 
#define _tstrrchr wcsrchr
#else
#define _tstrrchr strrchr
#endif

#ifdef _UNICODE 
#define _tstrstr wcsstr
#else
#define _tstrstr strstr
#endif

#ifdef _UNICODE 
#define _memtchr wmemchr
#else
#define _memtchr memchr
#endif

BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);
DWORD FileType( LPWIN32_FIND_DATA);
BOOL ProcessItem( LPWIN32_FIND_DATA, DWORD, LPBOOL);
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

int _tmain(int argc, LPTSTR argv[])
{
 BOOL flags[MAX_OPTIONS], ok = TRUE;
 TCHAR pathName[MAX_PATH + 1] , currPath[MAX_PATH + 1], tempPath[MAX_PATH + 1];
 LPTSTR pSlash, pFileName;
 int i, fileIndex;

 fileIndex = Options(argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);

 GetCurrentDirectory(MAX_PATH, currPath);

 if( argc < fileIndex + 1)
 {
  ok = TraverseDirectory(_T("*"), MAX_OPTIONS, flags);
 }
 else 
 {
  for( i = fileIndex; i < argc; i++)
  {
   _tcscpy(pathName, argv[i]);
   _tcscpy(tempPath, argv[i]);
  
   pSlash = _tstrrchr(tempPath, '\\');

   if( pSlash != NULL )
   {
    *pSlash = '\0';
    _tcscat(tempPath, _T("\\"));
    SetCurrentDirectory(tempPath);
    pSlash = _tstrrchr(pathName, '\\');
    pFileName = pSlash + 1;
   }
   else 
   {
    pFileName = pathName;
   }

   ok = TraverseDirectory(pFileName, MAX_OPTIONS, flags) && ok;

   SetCurrentDirectory(currPath);
  }
 }
}

static BOOL TraverseDirectory(LPCTSTR pathName, DWORD numFlags, LPBOOL flags)
{
 HANDLE searchHandle;
 WIN32_FIND_DATA findData;
 BOOL recursive = flags[0];
 DWORD fType, iPass;
 TCHAR currPath[MAX_PATH + 1];

 GetCurrentDirectory(MAX_PATH, currPath);

 for( iPass = 1; iPass <= 2; iPass++)
 {
  searchHandle = FindFirstFile(pathName, &findData);

  do
  {
   fType = FileType(&findData);
   if( iPass == 1 )
   {
    ProcessItem(&findData, MAX_OPTIONS, flags);
   }

   if( fType == TYPE_DIR && iPass == 2 && recursive)
   {
    _tprintf(_T("\n%s\\%s:"), currPath, findData.cFileName);

    SetCurrentDirectory(findData.cFileName);
    TraverseDirectory(_T("*"), numFlags, flags);
    SetCurrentDirectory(_T(".."));
   }
  
  }while( FindNextFile(searchHandle, &findData));

  FindClose(searchHandle);
 }

 return TRUE;

}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)
{
 BOOL isDir;
 DWORD fType;
 fType = TYPE_FILE;
 isDir =(pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 if (isDir)
  if (lstrcmp(pFileData->cFileName, _T(".")) == 0
    || lstrcmp(pFileData->cFileName, _T("..")) == 0)
   fType = TYPE_DOT;
  else fType = TYPE_DIR;
 return fType;
}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD numFlags, LPBOOL flags)
{
 const TCHAR fileTypeChar[] = {_T(' '), _T('d')};
 DWORD fType = FileType(pFileData);
 BOOL longList = flags[1];
 SYSTEMTIME lastWrite;

 if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

 _tprintf(_T("\n"));
 if (longList) {
  _tprintf(_T("%c"), fileTypeChar[fType - 1]);
  _tprintf(_T("%10d"), pFileData->nFileSizeLow);
  FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &lastWrite);
  _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
    lastWrite.wMonth, lastWrite.wDay,
    lastWrite.wYear, lastWrite.wHour,
    lastWrite.wMinute, lastWrite.wSecond);
 }
 _tprintf(_T(" %s"), pFileData->cFileName);
 return TRUE;
}

DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
{
 va_list pFlagList;
 LPBOOL pFlag;
 int iFlag = 0, iArg;

 va_start (pFlagList, OptStr);

 while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
    && iFlag < (int)_tcslen (OptStr)) {
  *pFlag = FALSE;
  for (iArg = 1; !(*pFlag) && iArg < argc && argv [iArg] [0] == _T('-'); iArg++)
   *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
     _tcslen (argv [iArg])) != NULL;
  iFlag++;
 }

 va_end (pFlagList);

 for (iArg = 1; iArg < argc && argv [iArg] [0] == _T('-'); iArg++);

 return iArg;
}
출처 : Windows 시스템 프로그래밍 윈도우즈 API 핵심 바이블​