

#include <vcl.h>
#pragma hdrstop


//[BuildTool 정의]
//{
    //[2022.09.14.수][추가]{------------------------------------------------------------------
    //[맷돌-IDE] 제작도구가 <TC++2006> 인지 <ECB/CE> 인지 구분하는 정의값이 들어 있다.
    //
    //이 <BuildToolDefine.h> 는 아래와 같이 내용이 다르므로 <TC++2006> 으로 빌드하는 묶음과
    //<ECB/CE> 로 빌드하는 묶음에서 각각 고유하게 가지고 있어야 한다.
    //
    //#define  d_BuildTool_TC2006    true   <=== <TC++2006> 으로 빌드되는 묶음안의 정의 내용.
    //#define  d_BuildTool_TC2006    false  <=== <ECB/CE> 로 빌드되는 묶음안의 정의 내용.
    //
    //
    //[참고]----------------------------------------------------------------------------------
    //<TC++2006> : Turbo C++ 2006 Explorer
    //<ECB/CE>   : Embarcadero C++Builder/Community Edition
    //}---------------------------------------------------------------------------------------

    #include "BuildToolDefine.h"

//}

#include  "ide_main.h"

//[다른 폼]
//{
    #include  "main.h"
    #include  "ide_caption.h"
    #include  "ide_menu.h"
    #include  "ide_submenu.h"

    #include  "ide_mbutton.h"
    #include  "ide_buttons.h"
    #include  "ide_tree.h"
    #include  "ide_editor.h"
    #include  "ide_msg.h"
    #include  "ide_vsplit.h"
    #include  "ide_hsplit.h"
    #include  "ide_msgbox.h"

    #include  "editor_edit.h"
    #include  "editor_top.h"
    #include  "msg_msg.h"
    #include  "tree_tree.h"

    #include  "file.h"
    #include  "ide_library.h"

    #include  "compiler.h"
    #include  "parser.h"
    #include  "asmencoder.h"
    #include  "object1st.h"
    #include  "object.h"
    #include  "link.h"
    #include  "gvmx.h"

    //[2009.03.12.목][추가!!!]
    #include  "vmos.h"

    //[2009.04.05.일][추가!!!]
    #include  "debug.h"

    //[2009.04.07.화][추가!!!]
    #include  "vdebug.h"

    //[2009.04.14.화][추가!!!]
    #include  "gxcom.h"

    //[2009.04.21.화][추가!!!]
    #include  "comport.h"

    //[2009.05.30.토][추가!!!]
    #include  "project_Wizard.h"

    //[2009.07.07.화][추가!!!]
    #include  "flash.h"

    #include  "matdol.h"

    //[2009.07.24.금][추가!!!]
    #include  "combus.h"

    //[2009.11.20.금][추가!!!]
    #include  "servoZero_DialogBox.h"

    //[2009.11.24.화][추가!!!]
    #include  "gmrcbasic_DialogBox.h"

    //[2009.12.05.토][추가!!!]
    #include  "gmrcbasicMake_DialogBox.h"


    //[2010.12.06.화][추가!!!]
    #include  "file_ginf.h"

    //[2010.12.10.금][추가!!!]
    #include  "vmos_info.h"

    //[2011.04.28.목][추가!!!]
    #include  "buildStatus.h"

    //[2011.06.08.수][추가!!!]
    #include  "debug_view.h"

    //[2012.02.26.일][추가!!!]
    #include  "bookMark_DialogBox.h"

    //[2012.04.09.월][추가!!!]
    #include  "info_tree.h"

    //[2012.05.17.목][추가!!!]
    #include  "str_conf.h"

    //[]2012.05.16+2.금][추가!!!]
    #include  "gui.h"

    //[2012.05.19.토][추가!!!]
    #include  "ide_hint.h"


    //[2018.03.06.화][추가!!!]
    #include  "optionIde_DialogBox.h"
    #include  "gmrcbasicMake_DialogBox.h"
    #include  "gmrcbasic_DialogBox.h"
    #include  "servoZero_DialogBox.h"
    #include  "find_DialogBox.h"
    #include  "bookMark_DialogBox.h"

    //[2022.06.05.일][추가]
    #include  "VClass\VStrBuf\VStrBuf.h"

    //[2022.06.08.수][추가]
    #include  "library.h"

    //[2023.01.02.월][추가]
    #include  "GImageBox.h"

//}


//[환경 변수]
//{
    //환경 변수는 전역으로 설정한다.
    struct  IDE_OPTION    _ide_Option;


//}


void __fastcall IDE_Get_Option(struct  IDE_OPTION  **pOption)
{
  //[2007.10.02.화][생성!!!]{-----------
  ///환경변수 집합의 포인터를 돌려준다.
  //}-----------------------------------

  (*pOption) = &_ide_Option;

  return;

}

void __fastcall Ide_Option_Init(void)
{
  //[2010.07.05.월][생성!!!]{-----------------------------------------------------
  //전역변수인 [환경변수] 를 초기화 한다.
  //실제 대부분의 내용은 [문서] 도 자동 초기화 되므로 여기서는 [문서] 로 저장되지
  //않고, 내부적으로 사용되는 것들만 초기화 한다.
  //
  //[2012.05.29.화][수정!!!]------------------------------------------------------
  //[2012.05.30.수][수정!!!]------------------------------------------------------
  //[2018.05.05.토][수정!!!]------------------------------------------------------
  //[2019.02.26.화][추가]---------------------------------------------------------
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      //[2019.02.26.화][추가]
      int  color;

  //}

  _ide_Option.gvmMode = false;

  //[2012.04.14.토][추가!!!]
  //[편집기] 실시간 선언정보판 설정.
  _ide_Option.editorInfoTree_AlphaBlend       = false;
  _ide_Option.editorInfoTree_AlphaBlendValue  = 225;
  _ide_Option.editorInfoTree_Brightness       = 225;

  //[2012.05.24.목][추가!!!]
  _ide_Option.editorInfoTree_BottomHint       = true;

  //[2012.05.29.화][추가!!!]
  _ide_Option.editorInfoTree_BottomTitleHint  = false;

  //[2012.05.26.토][추가!!!]
  _ide_Option.editorInfoTree_ItemHint         = true;

  //[2012.05.30.수][추가!!!]
  _ide_Option.editorInfoTree_ClosedWord       = false;

  //[자동 저장 관련]
  //{
      //[2018.05.05.토][추가!!!]

      //저장 주기는 기본 2분.
      _ide_Option.autoSavePeriod = 2;

      //자동 저장 기능은 사용.
      _ide_Option.autoSaveUse = true;

  //}

  //[메뉴 관련]
  //{
      //[2018.05.06.일][추가!!!]
      _ide_Option.tabToSpaceX = 1;

  //}

  //[풍선도움말 관련]
  //{
      //[2018.05.09.수][추가!!!]
      _ide_Option.balloonChangeNotSaveUse = true;

  //}

  //[전체찾기:Tree <빠른목록> 관련]
  //{
      //[2019.02.26.화][추가]
      _ide_Option.findTree_FontStyle = d_FONTSTYLE_bold;

      BMP_Get_Bright_Color(clBlack, 75, &color);
      _ide_Option.findTree_FontColor = color;

      //[형광색] 지정 유/무.
      _ide_Option.findTree_FontBackUse = true;

      //[형광색] 값.
      _ide_Option.findTree_FontBackColor = clLime;

  //}

}

void __fastcall IDE_CreateForms(void)
{
  //[2006.10.14.토][생성!!!]{---------------------------------------
  //IDE 에 사용되는 각각의 컨트롤에 해당하는 Form 을 생성해 준다.
  //실제 생성만 하면 각각의 Form 의 생성함수에서 모든것을 그려준다.
  //
  //[2012.05.28.월][수정!!!]----------------------------------------
  //[2012.06.09.토][수정!!!]----------------------------------------
  //[2018.05.09.수][수정!!!]----------------------------------------
  //}---------------------------------------------------------------

  //[VAR]
  //{
      //[2012.02.26.일][추가!!!]
      class  BookMark_DialogBox  *_bookMark_DialogBox;

      //[2012.05.28.월][추가!!!]
      //긴 [문자열] 을 출력시 포인터로 받아서 사용한다.
      char  *str_ = "";

  //}

  //[주의!!!]{---------------------
  //반드시 순서대로 처리해야 한다.
  //}------------------------------

  //[ide_caption]
  //{
      ide_caption_Form          = new Tide_caption_Form(main_Form);
      ide_caption_Form->Parent  = main_Form;
      ide_caption_Form->Visible = true;
  //}

  //[ide_menu]
  //{
      ide_menu_Form          = new Tide_menu_Form(main_Form);
      ide_menu_Form->Parent  = main_Form;
      ide_menu_Form->Visible = true;
  //}

  //[ide_mbutton]
  //{
      ide_mbutton_Form          = new Tide_mbutton_Form(main_Form);
      ide_mbutton_Form->Parent  = main_Form;
      ide_mbutton_Form->Visible = true;
  //}

  //[ide_buttons]
  //{
      ide_buttons_Form          = new Tide_buttons_Form(main_Form);
      ide_buttons_Form->Parent  = main_Form;
      ide_buttons_Form->Visible = true;

      //[2009.04.04.토][추가!!!]
      //버튼에 따른 기본 [활성상태] 를 처리한다.
      ide_buttons_Form->_Enable_Init();

  //}

  //[ide_msg]
  //{
      ide_msg_Form          = new Tide_msg_Form(main_Form);
      ide_msg_Form->Parent  = main_Form;
      ide_msg_Form->Visible = true;
  //}

  //[ide_hsplit]
  //{
      ide_hsplit_Form          = new Tide_hsplit_Form(main_Form);
      ide_hsplit_Form->Parent  = main_Form;
      ide_hsplit_Form->Visible = true;
  //}

  //[ide_tree]
  //{
      ide_tree_Form          = new Tide_tree_Form(main_Form);
      ide_tree_Form->Parent  = main_Form;
      ide_tree_Form->Visible = true;
  //}

  //[ide_vsplit]
  //{
      ide_vsplit_Form          = new Tide_vsplit_Form(main_Form);
      ide_vsplit_Form->Parent  = main_Form;
      ide_vsplit_Form->Visible = true;
  //}

  //[ide_editor]
  //{
      ide_editor_Form          = new Tide_editor_Form(main_Form);
      ide_editor_Form->Parent  = main_Form;
      ide_editor_Form->Visible = true;
  //}


  //[info_tree]
  //{
      //[2012.04.09.월][추가!!!]
      info_tree_Form          = new Tinfo_tree_Form(main_Form);
      //전체화면을 대상으로 위치.
      info_tree_Form->Parent  = NULL;

      info_tree_Form->Visible = false;

      info_tree_Form->_Tree_Init(&(info_tree_Form->_tree),
                                //항목수 250 개로 초기 생성.
                                250);

      //[<ECB/CE> 관련][2022.09.12.월]{********************************
      //<ECB/CE> 계열에서는 왼쪽 아래 모서리 잘라내기가 [생성시] 에
      //처리 되지 못하므로, 반드시 여기서 한번 다시 그려주어 처리한다.
      //모서리 잘라내기 처리-----------v
      info_tree_Form->_TreeView(false, true);
      //}**************************************************************

  //}

  //[Z-order 조정]
  //{
      ide_tree_Form->BringToFront();
      ide_editor_Form->BringToFront();

      ide_hsplit_Form->BringToFront();
      ide_vsplit_Form->BringToFront();

      //[2012.06.05.화][수정!!!]{-------------------------------------
      //<ide_editor_Form> 과 처리 순서를 바꾼다.
      //이는 [전체 크기 조정] 시 [편집기] 가 [출력창] 위로 잠깐씩
      //올라오는 것을 막기 위한것.
      //
      //더불어 [수직/수평:분할자] 도 크기 조정시 [출력창] 위로 나올수
      //있으므로 아예 이들보다도 위에오게 한다.
      //확인 결과 [전체 크기 조정] 시에도 매끄럽게 처리된다.
      ide_msg_Form->BringToFront();
      //}-------------------------------------------------------------

      ide_menu_Form->BringToFront();
      ide_mbutton_Form->BringToFront();
      ide_buttons_Form->BringToFront();
      ide_caption_Form->BringToFront();
  //}

  //[2007.03.30.금][추가!!!]
  //{
      //처음에는 [편집기] 에 [촛점] 이 없는 것이 좋으므로 보이지 않게 만든다.
      //자체적으로 [촛점] 잃으면 [입력지정자] 가 사라지므로 일단 [촛점] 을 주고
      //다시 다른 것에 [촛점] 을 이동하여 해제시키면 자동으로 처리된다.
      editor_edit_Form->SetFocus();
      ide_menu_Form->SetFocus();

      //[편집기 비활성화]
      //{
          //일단 처음에는 아무 문서도 없으므로 [편집기능] 관련이 동작되지 않게 만든다.
          ide_editor_Form->_Enable(false);

          //[2009.04.25.토][추가!!!]
          editor_top_Form->_close_bmpbtns->_Enable(false);
          editor_top_Form->_list_bmpbtns->_Enable(false);

      //}

  //}


  //[설정 복구 처리]
  //{
      //------------------------------------
      //[2007.12.11.화][추가!!!]

      //[편집기 열었던 문서 다시열기]
      //{
          //IDE_OptionFile_RestoreEditor();

      //}
      //------------------------------------
  //}


  //[통신포트 생성]
  //{
      //[23009.10.01.목][추가!!!]{-------------------------------
      //통신을 위한 두개의 별도 통신포트의 기본 설정을 수행한다.
      //}--------------------------------------------------------

      //맷돌과 통신하기 위한 기본 통신포트.
      COMPORT_Create();

      //알림창에 수신문자열을 출력하기 위한 검증용 부가적인 통신포트.
      ComPortDebug_Create();

  //}

  //[찾기목록(책갈피) 대화상자 생성]
  //{
      //[2012.02.26.일][추가!!!]{----------------------------------------
      //[책갈피 대화상자] 는 <bookMark_DialogBox.cpp> 안에 [전역변수] 로
      //한개 선언돼 있다.
      //새로운 방식을 사용하는 것.
      //
      //[2012.03.03.토][중요주의!!!]-------------------------------------
      //위에서 생성된 것과 [생성 순서] 를 바꿔도 [책갈피 대화상자] 안의
      //동적 생성된 [그림부품] 들이 먼저 삭제된다는 것에 주의한다.
      //}----------------------------------------------------------------

      //[전역변수] 로 선언된 [책갈피 대화상자] 위치 얻기.
      BookMark_DialogBox_GetPtr(&_bookMark_DialogBox);

      //모양 만들기(이때 내부 그림부품이 동적 생성).
      _bookMark_DialogBox->_Create();

  //}

  //[개발환경 기타 초기화]
  //{
      //[2012.05.28.월][추가!!!]{----------------------
      //[맷돌-통합개발환경] 의 부가적인 초기화를 수행.
      //}----------------------------------------------

      //[편집용 중요 단축키 설명]
      //{
          //[2012.05.28.월][추가!!!]{-----------------------------------------
          //반드시 알아야 하는 [단축키] 와 해당 설명을 [출력창] 에 출력.
          //원래 [편집기] 배경에 [문서가 열려 있지 않은 경우] 출력하려 했으나
          //[추력창] 이 더 단순하고 효과적이다.
          //초기에 한번만 출력하면 되는 [잠깐설명] 같은 것이다.
          //
          //[2018.06.05.화][수정!!!]------------------------------------------
          //전체적인 문자열 재 조정이 있음.
          //}-----------------------------------------------------------------
          
          str_ = "[편집기] 에서 사용할수 있는 중요 [단축키] 조합.\r\n"
                 "- <Ctrl+Space 키> : 현재 편집중인 문서의 [선언정보] 만 수집 후 [실시간 선언 정보판] 보이기.\r\n"
                 //[2018.05.09.수][주석처리!!!]{-------------------------------------------------------------
                 //[Linux:wine] 에서는 F9 등 기능키가 동작하지 않으므로 제거.
                 //"<Ctrl+F9>    : [가상기계(GVMS/GVMX)] 까지 완성.\r\n\r\n"
                 //"<Alt+F9>     : 현재 편집중인 문서만 문법검사 후 [정보창:설계정보] 에 정보 정리.\r\n\r\n"
                 //}-----------------------------------------------------------------------------------------
                 //[2012.06.09.토][추가!!!]
                 "- <Ctrl+G 키>     : 세로줄 보조선 보이기(문서에 개별적으로 적용).\r\n"
                 //[2018.06.05.화][추가!!!]
                 "- <Ctrl+수평방향키> : 선택영역에 포함된 행 전체 수평 이동({ 메뉴 : 편집 -> 수평이동 } 참고).\r\n"
                 "- <Ctrl+P 키>     : 현재 단어 API 검색.\r\n\r\n"

                 //[2018.06.04.월][수정/추가!!!]
                 //일반적인 단축키는 제거하고 [Linux:wine] 구동 관련 정보를 대신 추가.
                 //"<Ctrl+S>     : 현재 편집중인 문서 저장.\r\n";
                 "Linux/FreeBSD 에서 [Wine] 으로 구동하는 경우는 반드시 해당 설정 필요.\r\n"
                 "- { 메뉴 : 설정 -> 통합 개발환경 설정 -> [wine 구동 설정] } 의 항목에 반드시 [v].\r\n"
                 "- \"[v] FreeBSD/Linux 에서 wine 으로 구동.\"\r\n"
                 "- XFCE 에서 가장 완벽하게 구동됨(Linux/FreeBSD 모두 동일).\r\n";


          msg_msg_Form->_Print(0, str_);

      //}

  //}

  //[<ECB/CE> 관련][2022.09.12.월]{***********************************************
  //<ECB/CE> 이후 부터는 <Parent> 를 지정하면 생성시 적용된 크기가 무시되고 다시
  //[폼디자인(Object Inspector)] 상의 크기로 되돌아가는 문제가 있는데 이를 죽이기
  //위하여 [모양만들기] 를 모두 끝낸 후 한번 전체 크기를 조율해 준다.
  IDE_ResizeForms();
  //}*****************************************************************************

}

void __fastcall IDE_DeleteForms(void)
{
  //[2006.11.25.토][생성!!!]{--
  //생성된 모든 폼을 삭제한다.
  //
  //[2012.04.29.일][수정!!!]---
  //생성된 역순으로 처리.
  //}--------------------------

  //[통신포트 삭제]
  //{
      //[2009.10.01.목][추가!!!]

      COMPORT_Delete();

      ComPortDebug_Delete();

  //}

  if(ide_editor_Form != NULL) { delete ide_editor_Form; ide_editor_Form = NULL; }

  if(ide_vsplit_Form != NULL) { delete ide_vsplit_Form; ide_vsplit_Form = NULL; }

  if(ide_tree_Form != NULL) { delete ide_tree_Form; ide_tree_Form = NULL; }

  if(ide_hsplit_Form != NULL) { delete ide_hsplit_Form; ide_hsplit_Form = NULL; }

  if(ide_msg_Form != NULL) { delete ide_msg_Form; ide_msg_Form = NULL; }

  if(ide_buttons_Form != NULL) { delete ide_buttons_Form; ide_buttons_Form = NULL; }

  if(ide_mbutton_Form != NULL) { delete ide_mbutton_Form; ide_mbutton_Form = NULL; }

  if(ide_menu_Form != NULL) { delete ide_menu_Form; ide_menu_Form = NULL; }

  if(ide_caption_Form != NULL) { delete ide_caption_Form; ide_caption_Form = NULL; }

}

void __fastcall IDE_ResizeForms(void)
{
  //[2006.10.15.일][생성!!!]{---------------------------------------------------------
  //IDE Form 의 크기가 변경되는 경우는 내부의 모든 Form 도 전부 크기가 바뀌어야
  //하는데 각 [컨트롤] 의 크기 변경 함수를 호출해 주면 된다.
  //해당 Form 이 생성되지 않은 경우는 처리해서는 안된다.
  //
  //[2012.06.05.화][수정!!!]----------------------------------------------------------
  //[수직분할자] 가 [출력창] 보다 위에 있으나 크기 조정시 크기 조정은 나중에 되기
  //때문에 위로 조정하는 경우는 [출력창] 위로 세로로
  //[수직분할자] 가 잠깐 보여 눈에 거슬린다.
  //따라서, 크기 조정시에는 먼저 [수직분할자] 를 감추고 크기 조정이 된 뒤에 보여준다.
  //}---------------------------------------------------------------------------------

  //[주의!!!]{---------------------
  //반드시 순서대로 처리해야 한다.
  //}------------------------------
  
  if(ide_caption_Form != NULL) { ide_caption_Form->_Resize(); }
  if(ide_menu_Form    != NULL) { ide_menu_Form->_Resize();    }

  //아래는 고정 크기로 크기를 바꾸지 않는다.
  if(ide_mbutton_Form != NULL) {                              }

  if(ide_buttons_Form != NULL) { ide_buttons_Form->_Resize(); }


  //[수직분할자:감추기][2012.06.05.화][추가!!!]{----------------------
  //[출력창] 을 [수직/수평:분할자] 보다 위에오게 배치하는것으로 처리.
  //이 부분은 주석으로 처리한다.
  //if(ide_vsplit_Form != NULL) { ide_vsplit_Form->Visible = false; }
  //}-----------------------------------------------------------------


  if(ide_msg_Form     != NULL) { ide_msg_Form->_Resize();     }
  if(ide_hsplit_Form  != NULL) { ide_hsplit_Form->_Resize();  }
  if(ide_tree_Form    != NULL) { ide_tree_Form->_Resize();    }
  if(ide_vsplit_Form  != NULL) { ide_vsplit_Form->_Resize();  }


  //[수직분할자:감추기][2012.06.05.화][추가!!!]{----------------------
  //[출력창] 을 [수직/수평:분할자] 보다 위에오게 배치하는것으로 처리.
  //이 부분은 주석으로 처리한다.
  //if(ide_vsplit_Form != NULL) { ide_vsplit_Form->Visible = true; }
  //}-----------------------------------------------------------------


  if(ide_editor_Form  != NULL) { ide_editor_Form->_Resize();  }

  return;

}

void __fastcall IDE_StartUp_Etc(void)
{
  //[2022.06.07.화][생성]{-----------------------------
  //[맷돌-IDE] 시작시 사용할 기본 정보, 문서를 만든다.
  //}--------------------------------------------------

  //<IDE\glib\def_file.glist> 를 생성.
  API_Make_DefFile();

}

void __fastcall IDE_OnShow(void)
{
  //[2022.07.15.금][생성]{-------------------------------------------------
  //[맷돌-IDE] 가 실제로 보이는 시점에 처리할 내요을 기술한다.
  //이 함수는 실제로 <main_Form::FormShow()> 에서 호출되며
  //[맷돌-IDE] 구성 GUI 가 완전히 완성된 상태 직후가 된다.
  //
  //<Tmain_Form::Tmain_Form()> 생성자 부분이나, <IDE_CreateForms()> 에서는
  //실제 GUI 가 완전히 완성되지 않는다.
  //실제 GUI 가 완전히 완성되어 제 기능을 수행할수 있는 초기상태는 바로
  //<main_Form::FormShow()> 시점이 되므로 여기서 [맷돌-IDE] 초기 GUI 관련
  //처리를 수행해야 한다.
  //}----------------------------------------------------------------------

  //[VAR]
  //{
      //[2022.07.15.금][추가]
      char  filePathNameExt[1024];

  //}

  //[<읽어보기.gtxt> 열기]
  //{
      //[!]{---------------------------------------------------------------------------------------------------
      //[첨단기술의 병사 양성] 의 구체적 내용이 담겨있는 [맷돌-IDE] 의 개요인 <읽어보기.gtxt> 문서를 열어준다.
      //}------------------------------------------------------------------------------------------------------

      STR_Add_AB(filePathNameExt,
                 ((AnsiString)ExtractFilePath(Application->ExeName)).c_str(),
                 "txt\\읽어보기.gtxt");

      //문서 열기.
      editor_top_Form->_List_Add((AnsiString)filePathNameExt);

      //[읽기전용] 설정.
      editor_edit_Form->_readOnly = true;

  //}

  //[풍선도움말]
  //{
      //촛점을 잃으면 사라지도록 설정.
      editor_top_Form->_balloonBox->_KillFocusUse(true);

      //"첨단기술의병사양성" 단어를 찾고 해당 단어 위치에 [풍선도움말] 출력.
      editor_top_Form->_BalloonBox_Print_At_FindStr
                       ("첨단기술의병사양성",
                        0,
                        "\"첨단기술의병사\" 는 \"프로그램을 통한 하드웨어 제어\" 를 할수 있는 존재를 의미.");

  //}                      

}

void __fastcall IDE_OptionFile_Open(void)
{
  //[2007.10.02.화][생성!!!]{-----------------------------------
  //환경 변수문서를 읽어 들여서 환경변수를 설정한다.
  //
  //[2007.11.21.수][수정!!!]------------------------------------
  //보다 환경 변수가 많아 졌으므로 서로를 구분할 제목을 만들고
  //모두 행단위로 기록하는 방식으로 바뀌었으므로 이를 반영한다.
  //
  //[2012.04.14.토][수정!!!]------------------------------------
  //[편집기:실시간 선언정보판] 관련 추가.
  //
  //[2012.05.24.목][수정!!!]------------------------------------
  //[2012.05.29.화][수정!!!]------------------------------------
  //[2012.05.30.수][수정!!!]------------------------------------
  //[2018.05.05.토][수정!!!]------------------------------------
  //[2018.05.09.수][수정!!!]------------------------------------
  //[2019.02.26.화][추가]---------------------------------------
  //}-----------------------------------------------------------


  //[VAR]
  //{
      int         fileSize;

      AnsiString  fileName = "";

      char       *fileBuf = NULL;

      char        tempStr[1024];

      //[2007.11.21.수][추가!!!]

      //문서의 총행수.
      int         fileLineCount = 0;

      int         searchLineNumber = -1;

  //}


  //[문서 경로 얻기]
  //{
      fileName = ExtractFilePath(Application->ExeName) + "opt\\opt.opt";

  //}

  //[문서 열기]
  //{
      FILE_Open(fileName, (unsigned char **)(&fileBuf), &fileSize);

  //}

  //[전체 행수 얻기]
  //{
      fileLineCount = STR_Get_LineCount(fileBuf);

  //}

  //[구조체에 저장]
  //{
      //구조체 설정정보에 각각의 정보를 저장한다.
      //<제목> 을 먼저 찾고 해당 값을 추출하여 처리한다.

      //[전체색]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전체색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_0));

            _ide_Option.color_0_save = _ide_Option.color_0;

          }

      //}

      //[행지정사각형색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<행지정사각형색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_linebox));

          }

      //}

      //[행지정화살표색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<행지정화살표색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_run_arrow));

          }

      //}

      //[정지점색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<정지점색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_breakpoint));

          }

      //}

      //[명령어색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<명령어색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_Keyword));

          }

      //}

      //[주석문색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<주석문색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_Comment));

          }

      //}

      //[16진수색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<16진수색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_HexWord));

          }

      //}

      //[2진수색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<2진수색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_BinWord));

          }

      //}

      //[의사명령어색]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<의사명령어색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_Directive));

          }

      //}

      //[문자열색]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<문자열색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_String));

          }

      //}

      //[문자색]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<문자색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.color_Char));

          }

      //}

      //[전체배경사용유무]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전체배경사용유무>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.ideBackPictureEntire)));

          }

      //}

      //[전체배경그림경로]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전체배경그림경로>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 경로 할당.
            STR_Assign(_ide_Option.ideBackpicturePath, tempStr);

          }

      //}

      /*
      //[편집기배경그림경로]
      //{
          //[2007.12.02.일][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기배경그림경로>", &searchLineNumber);

          //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
          STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

          //환경변수에 경로 할당.
          STR_Assign(_ide_Option.editorBackPicturePath, tempStr);

      //}

      //[정보창배경그림경로]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<정보창배경그림경로>", &searchLineNumber);

          //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
          STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

          //환경변수에 경로 할당.
          STR_Assign(_ide_Option.treeBackPicturePath, tempStr);

      //}

      //[알림창배경그림경로]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<알림창배경그림경로>", &searchLineNumber);

          //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
          STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

          //환경변수에 경로 할당.
          STR_Assign(_ide_Option.msgBackPicturePath, tempStr);

      //}
      */

      //[편집기바탕밝기]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기바탕밝기>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.edit_back_brightness));

          }

      //}

      //[정보창바탕밝기]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<정보창바탕밝기>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.tree_back_brightness));

          }

      //}

      //[알림창바탕밝기]
      //{
          //[2007.12.13.목][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<알림창바탕밝기>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.msg_back_brightness));

          }

      //}

      //[통신포트번호]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<통신포트번호>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.portnumber));

            //[내부 저장]
            //{
                //[2010.04.01.목][추가!!!]{----------------------------
                //현재 포트를 항상 저장해 놓는다(해당 변수 설명 참고).
                //}----------------------------------------------------

                _ide_Option.portNumber_Backup = _ide_Option.portnumber;

            //}

          }

      //}

      //[통신포트2번호]
      //{
          //[2009.10.02.금][추가!!!]
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<통신포트2번호>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.port2_Num));

          }

      //}

      //[통신포트2 전송율]
      //{
          //[2009.10.02.금][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<통신포트2전송율>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.port2_Baud));

          }

      //}

      //[알파블렌드설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<알파블렌드설정>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.alphaBlendUse));

          }

      //}

      //[알파블렌드값]
      //{
          //[2009.04.20.월][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<알파블렌드값>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.alphaBlendValue));

          }

      //}

      //[풍선도움말설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<풍선도움말설정>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.balloonHelpUse));

          }

      //}

      //[풍선도움말투명설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<풍선도움말투명설정>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.balloonHelpAlphaBlend));

          }

      //}

      //[문서수정알림사용]
      //{
          //[2018.05.09.수][추가!!!]

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<문서수정알림사용>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.balloonChangeNotSaveUse)));

          }

      //}

      //[전광판사용]
      //{
          //[2010.02.22.월][추가!!!]{-------------
          //[전광판] 을 사용할지 말지를 결정한다.
          //}-------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전광판사용>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.dotmatrixUse)));

          }

      //}

      //[전광판문자열]
      //{
          //[2010.02.22.월][추가!!!]{------------------
          //[전광판] 에 표시되는 [문자열] 을 관리한다.
          //}------------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전광판문자열>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 경로 할당.
            STR_Assign(_ide_Option.dotmatrixStr, tempStr);

          }

      //}

      //[전광판문자색]
      //{
          //[2010.02.22.월][추가!!!]{---------
          //[전광판] 의 [문자색] 을 설정한다.
          //}---------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전광판문자색>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.dotmatrixColor));

            //[2018.02.17.토][수정!!!]{------------------------
            //[전광판:색] 은 기본 [테마색] 으로 고정 지정한다.
            _ide_Option.dotmatrixColor = _ide_Option.color_0;
            //}------------------------------------------------

          }

      //}

      //[전광판문자열회전]
      //{
          //[2010.02.22.월][추가!!!]{---------------
          //[전광판 문자열] 의 회전여부를 관리한다.
          //}---------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전광판문자열회전>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.dotmatrixRotate)));

          }

      //}

      //[전광판문자열회전시간간격]
      //{
          //[2018.02.19.월][추가!!!]{----------------
          //[전광판 문자열 회전 시간 간격(ms)] 관리.
          //}----------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<전광판문자열회전시간간격>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.dotmatrixRotateTime));

          }

      //}

      //[자동저장주기]
      //{
          //[2018.05.05.토][추가!!!]{-------------------------------------------                                          
          //[주기] 를 먼저 설정하고 해당 [타이머] 를 구동해야 하므로 먼저 처리.
          //}-------------------------------------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<자동저장주기>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, &(_ide_Option.autoSavePeriod));

            //[자동 저장 타이머:주기]
            //{
                //[주기] 설정.
                Ide_AutoSave_Period(_ide_Option.autoSavePeriod);

            //}

          }

      //}
      
      //[자동저장사용]
      //{
          //[2018.05.05.토][추가!!!]{------------
          //[자동 저장 기능] 의 사용 유/무 설정.
          //}------------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<자동저장사용>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.autoSaveUse)));

            //[자동 저장 타이머:사용여부]
            //{
                Ide_AutoSave_Use(_ide_Option.autoSaveUse);

            //}

          }


      //}

      //[wine구동설정]
      //{
          //[2018.02.16.금][추가!!!]{---------
          //linux:wine 에서 구동 여부를 관리.
          //}---------------------------------

          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<wine구동설정>", &searchLineNumber);

          if(searchLineNumber >= 0)
          {
            //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
            STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

            //환경변수에 할당.
            CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.wine)));

          }

      //}

      //[편집기:실시간 선언정보판]
      //{
          //[2012.04.14.토][추가!!!]

          //[투명 유/무]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:투명유무>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_AlphaBlend)));

              }

          //}

          //[투명 정도]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:투명정도>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_AlphaBlendValue)));

              }

          //}

          //[밝기 정도]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:밝기정도>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_Brightness)));

              }

          //}

          //[항목 귀뜸말 사용 유/무]
          //{
              //[2012.05.26.토][추가!!!]

              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:항목귀뜸말사용유무>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_ItemHint)));

              }

          //}

          //[아래 귀뜸말 사용 유/무]
          //{
              //[2012.05.24.목][추가!!!]

              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:아래귀뜸말사용유무>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_BottomHint)));

              }

          //}

          //[아래 귀뜸말 <제목줄> 사용 유/무]
          //{
              //[2012.05.29.화][추가!!!]

              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:아래귀뜸말제목줄사용유무>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_BottomTitleHint)));

              }

          //}

          //[<근접 단어 정렬> 기능 사용 유/무]
          //{
              //[2012.05.30.수][추가!!!]

              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집기:선언정보판:근접단어정렬사용유무>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.editorInfoTree_ClosedWord)));

              }

          //}

      //}

      //[전체찾기:Tree 관련]
      //{
          //[2019.02.26.화][추가]

          //[<찾기:tree:문자형식>]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<찾기:tree:문자형식>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.findTree_FontStyle)));

              }

          //}

          //[<찾기:tree:문자색>]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<찾기:tree:문자색>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.findTree_FontColor));

              }

          //}

          //[<찾기:tree:형광색사용>]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<찾기:tree:형광색사용>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_DecStr_To_IntVal(tempStr, (int *)(&(_ide_Option.findTree_FontBackUse)));

              }

          //}

          //[<찾기:tree:형광색>]
          //{
              //제목줄을 찾는다.
              STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<찾기:tree:형광색>", &searchLineNumber);

              if(searchLineNumber >= 0)
              {
                //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

                //환경변수에 할당.
                CONV_HexStr_To_IntVal(tempStr, &(_ide_Option.findTree_FontBackColor));

              }

          //}

      //}

  //}

  //[공간 삭제]
  //{
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }

  //}

}

void __fastcall IDE_OptionFile_Save(void)
{
  //[2007.10.02.화][생성!!!]{-----------------------------------
  //현재 환경변수를 해당 파일에 저장한다.
  //
  //[2007.11.21.수][수정!!!]------------------------------------
  //보다 환경 변수가 많아 졌으므로 서로를 구분할 제목을 만들고
  //모두 행단위로 기록하는 방식으로 바뀌었으므로 이를 반영한다.
  //
  //[2012.04.14.토][수정!!!]------------------------------------
  //[편집기:실시간 선언정보판] 관련 정보 추가.
  //
  //[2012.05.24.목][수정!!!]------------------------------------
  //[2012.05.29.화][수정!!!]------------------------------------
  //[2012.05.30.수][수정!!!]------------------------------------
  //[2018.05.05.토][수정!!!]------------------------------------
  //[2019.02.26.화][추가]---------------------------------------
  //}-----------------------------------------------------------

  //[VAR]
  //{
      int         fileSize;

      AnsiString  fileName = "";

      //설정문서는 10K byte 정도면 충분하다.
      char        optionFile[1024*10] = {""};

      //기본 문자열 조합등에 사용되는 문자열.
      char        tempStr[1024];

      int         i;

  //}

  //[문서 경로 얻기]
  //{
      fileName =  ExtractFilePath(Application->ExeName) + "opt\\opt.opt";

  //}

  //[문서 만들기]
  //{
      //[전체색 정보]
      //{
          //제목 추가.
          STR_Add(optionFile, "<전체색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_0_save, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[행지정사각형색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<행지정사각형색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_linebox, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[행지정화살표색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<행지정화살표색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_run_arrow, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[정지점색]
      //{
          //[2007.11.22.목][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<정지점색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_breakpoint, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[명령어색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<명령어색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_Keyword, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[주석문색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<주석문색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_Comment, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[16진수색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<16진수색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_HexWord, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[2진수색]
      //{
          //[2007.12.02.일][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<2진수색>\r\n");

          //값 추가.
          STR_Add(optionFile, "0x");

          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_BinWord, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[의사명령어색]
      //{
          //제목 추가.
          STR_Add(optionFile, "<의사명령어색>\r\n");
          //값 추가.
          STR_Add(optionFile, "0x");
          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_Directive, tempStr);
          STR_Add(optionFile, tempStr);
          STR_Add(optionFile, "\r\n");

      //}

      //[문자열색]
      //{
          //제목 추가.
          STR_Add(optionFile, "<문자열색>\r\n");
          //값 추가.
          STR_Add(optionFile, "0x");
          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_String, tempStr);
          STR_Add(optionFile, tempStr);
          STR_Add(optionFile, "\r\n");

      //}

      //[문자색]
      //{
          //제목 추가.
          STR_Add(optionFile, "<문자색>\r\n");
          //값 추가.
          STR_Add(optionFile, "0x");
          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.color_Char, tempStr);
          STR_Add(optionFile, tempStr);
          STR_Add(optionFile, "\r\n");

      //}

      //[전체배경사용유무]
      //{
          //제목 추가.
          STR_Add(optionFile, "<전체배경사용유무>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.ideBackPictureEntire, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[편집기배경그림경로]
      //{
          //제목 추가.
          STR_Add(optionFile, "<전체배경그림경로>\r\n");

          //경로 저장.
          STR_Add(optionFile, _ide_Option.ideBackpicturePath);

          STR_Add(optionFile, "\r\n");

      //}

      //[편집기 바탕 밝기]
      //{
          //제목 추가.
          STR_Add(optionFile, "<편집기바탕밝기>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.edit_back_brightness, 3, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[정보창바탕밝기]
      //{
          //제목 추가.
          STR_Add(optionFile, "<정보창바탕밝기>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.tree_back_brightness, 3, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[알림창바탕밝기]
      //{
          //제목 추가.
          STR_Add(optionFile, "<알림창바탕밝기>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.msg_back_brightness, 3, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[통신포트 번호]
      //{
          //제목 추가.
          STR_Add(optionFile, "<통신포트번호>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.portnumber, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[통신포트2 번호]
      //{
          //[2009.10.02.금][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<통신포트2번호>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.port2_Num, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[통신포트2 전송율]
      //{
          //[2009.10.02.금][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<통신포트2전송율>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.port2_Baud, 8, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[알파블렌드설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<알파블렌드설정>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.alphaBlendUse, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[알파블렌드값]
      //{
          //[2009.04.20.월][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<알파블렌드값>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.alphaBlendValue, 3, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[풍선도움말설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<풍선도움말설정>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.balloonHelpUse, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[풍선도움말투명설정]
      //{
          //[2009.04.20.월][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<풍선도움말투명설정>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.balloonHelpAlphaBlend, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[문서수정알림사용]
      //{
          //[2018.05.09.수][추가!!!]

          //제목 추가.
          STR_Add(optionFile, "<문서수정알림사용>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.balloonChangeNotSaveUse, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[전광판사용]
      //{
          //[2010.02.22.월][추가!!!]{------
          //[전광판] 사용 유무를 저장한다.
          //}------------------------------

          //제목 추가.
          STR_Add(optionFile, "<전광판사용>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.dotmatrixUse, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[전광판문자열]
      //{
          //[2010.02.22.월][추가!!!]{----
          //[전광판 문자열] 을 저장한다.
          //}----------------------------

          //제목 추가.
          STR_Add(optionFile, "<전광판문자열>\r\n");

          //경로 저장.
          STR_Add(optionFile, _ide_Option.dotmatrixStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[전광판문자색]
      //{
          //[2010.02.22.월][추가!!!]{----
          //[전광판 문자색] 을 저장한다.
          //}----------------------------

          //제목 추가.
          STR_Add(optionFile, "<전광판문자색>\r\n");
          //값 추가.
          STR_Add(optionFile, "0x");
          //값을 16진수 최소표기로 변환.
          CONV_LongVal_To_Hex2(_ide_Option.dotmatrixColor, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[전광판문자열회전]
      //{
          //[2010.02.22.월][추가!!!]{---------------------
          //[전광판 문자열] 을 회전 시킬지 여부를 가진다.
          //}---------------------------------------------

          //제목 추가.
          STR_Add(optionFile, "<전광판문자열회전>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.dotmatrixRotate, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[전광판문자열회전시간간격]
      //{
          //[2018.02.19.월][추가!!!]{----------------
          //[전광판 회전 문자열 시간 간격(ms)] 관리.
          //}----------------------------------------

          //제목 추가.
          STR_Add(optionFile, "<전광판문자열회전시간간격>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.dotmatrixRotateTime, 4, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[자동저장주기]
      //{
          //[2018.05.05.토][추가!!!]{-------------------------------------------
          //[주기] 를 먼저 설정하고 해당 [타이머] 를 구동해야 하므로 먼저 처리.
          //}-------------------------------------------------------------------

          //제목 추가.
          STR_Add(optionFile, "<자동저장주기>\r\n");

          //값 추가.
          //1-60 분 사이의 값이므로 2 자리수로 지정-------v
          CONV_LongVal_To_Str(_ide_Option.autoSavePeriod, 2, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[자동저장사용]
      //{
          //[2018.05.05.토][추가!!!]{------------
          //[자동 저장 기능] 의 사용 유/무 설정.
          //}------------------------------------

          //제목 추가.
          STR_Add(optionFile, "<자동저장사용>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.autoSaveUse, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[wine구동설정]
      //{
          //[2018.02.16.금][추가!!!]{---------
          //linux:wine 에서 구동 여부를 관리.
          //}---------------------------------

          //제목 추가.
          STR_Add(optionFile, "<wine구동설정>\r\n");

          //값 추가.
          CONV_LongVal_To_Str(_ide_Option.wine, 1, false, tempStr);

          STR_Add(optionFile, tempStr);

          STR_Add(optionFile, "\r\n");

      //}

      //[편집기:실시간 선어정보판]
      //{
          //[2012.04.14.토][추가!!!]

          //[투명 유/무]
          //{
              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:투명유무>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_AlphaBlend, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[투명 유/무]
          //{
              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:투명정도>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.alphaBlendValue, 3, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[투명 유/무]
          //{
              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:밝기정도>\r\n");

              //값 추가.
              //[2012.05.08.화][수정!!!]
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_Brightness, 3, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[항목 귀뜸말 사용 유/무]
          //{
              //[2012.05.26.토][추가!!!]

              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:항목귀뜸말사용유무>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_ItemHint, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[아래 귀뜸말 사용 유/무]
          //{
              //[2012.05.24.목][추가!!!]

              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:아래귀뜸말사용유무>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_BottomHint, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[아래 귀뜸말 <제목줄> 사용 유/무]
          //{
              //[2012.05.29.화][추가!!!]

              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:아래귀뜸말제목줄사용유무>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_BottomTitleHint, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[<근접 단어 정렬> 기능 사용 유/무]
          //{
              //[2012.05.30.수][추가!!!]

              //제목 추가.
              STR_Add(optionFile, "<편집기:선언정보판:근접단어정렬사용유무>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.editorInfoTree_ClosedWord, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

      //}

      //[전체찾기:Tree 관련]
      //{
          //[2019.02.26.화][추가]

          //[<찾기:tree:문자형식>]
          //{
              //제목 추가.
              STR_Add(optionFile, "<찾기:tree:문자형식>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.findTree_FontStyle, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[<찾기:tree:문자색>]
          //{
              //제목 추가.
              STR_Add(optionFile, "<찾기:tree:문자색>\r\n");
              //값 추가.
              STR_Add(optionFile, "0x");
              //값을 16진수 최소표기로 변환.
              CONV_LongVal_To_Hex2(_ide_Option.findTree_FontColor, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[<찾기:tree:형광색사용>]
          //{
              //제목 추가.
              STR_Add(optionFile, "<찾기:tree:형광색사용>\r\n");

              //값 추가.
              CONV_LongVal_To_Str(_ide_Option.findTree_FontBackUse, 1, false, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

          //[<찾기:tree:형광색>]
          //{
              //제목 추가.
              STR_Add(optionFile, "<찾기:tree:형광색>\r\n");
              //값 추가.
              STR_Add(optionFile, "0x");
              //값을 16진수 최소표기로 변환.
              CONV_LongVal_To_Hex2(_ide_Option.findTree_FontBackColor, tempStr);

              STR_Add(optionFile, tempStr);

              STR_Add(optionFile, "\r\n");

          //}

      //}

      //[설정 끝]
      //{
          //제목 추가.
          STR_Add(optionFile, "<끝>\r\n");

      //}

  //}

  //[문서 크기 얻기]
  //{
      fileSize = STR_Length(optionFile);

  //}

  //[문서 저장]
  //{
      //임시문서저장.
      FILE_Save(fileName, optionFile, fileSize);

  //}

  return;

}

void __fastcall IDE_OptionFile_RestoreEditor(void)
{
  //[2007.11.21.수][생성!!!]{------------------------------------------------------
  //환경 변수파일안의 정보를 읽어서 편집기에서 이전에 열었던 문서를 다시 열어준다.
  //단, 경로가 바뀌거나 삭제됬을수 있으므로 반드시 해당 문서가 있는지 확인하고
  //문서가 없는 경우는 Null 을 할당해 주어야 한다.
  //}------------------------------------------------------------------------------


  //[VAR]
  //{
      int         fileSize;

      AnsiString  fileName = "";

      char       *fileBuf = NULL;

      char        tempStr[1024];


      //[2007.11.21.수][추가!!!]

      //문서의 총행수.
      int         fileLineCount = 0;

      int         searchLineNumber = -1;

      int         i;

      //버튼에 표시할 문자열 저장.
      AnsiString  btnFileName;

      int         editorFileCount = 0;

  //}


  //[문서 경로 얻기]
  //{
      fileName = ExtractFilePath(Application->ExeName) + "opt\\opt.opt";

  //}

  //[문서 열기]
  //{
      FILE_Open(fileName, (unsigned char **)(&fileBuf), &fileSize);

  //}

  //[전체 행수 얻기]
  //{
      fileLineCount = STR_Get_LineCount(fileBuf);

  //}

  //[편집기에서 다시 열기]
  //{
      //제목줄을 찾는다.
      STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<편집문서목록>", &searchLineNumber);

      //할당 문서가 없는 경우는 설정파일에 Null 로 기록되 있으나 그냥 두면 자동으로 처리된다.

      //[문서 개수 얻기]
      //{
          //문서 개수는 <제목> 바로 다음 행에 있는 값이다.

          //값을 얻는다.(값은 제목줄 다음에 있고 한줄 이 한개 단어이므로 단어로 보면 된다.)
          STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

          CONV_DecStr_To_IntVal(tempStr, &editorFileCount);

      //}

      for(i = 0; i < editorFileCount; i++)
      {
        //경로를 얻는다.
        STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

        //[문서 존재 확인]
        //{
            //문서가 존재하는지 확인하고 없다면 아예 열지 않는다.
            if(FileExists((AnsiString)tempStr) != true)
            {
              //문서가 존재하지 않으므로 그냥 넘긴다.
              continue;

            }

        //}

        //문서 열기.
        editor_top_Form->_List_Add((AnsiString)tempStr);

      }

  //}

  //[공간 삭제]
  //{
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }

  //}

}

//[디버그 관련]-----------------------------------------------------------------

void __fastcall DEBUG_Indicator_Show(void)
{
  //지정자를 보여준다.

  //[지정자 표시]
  //{
      //[실행지정자] 와 [실행지정상자] 를 보여준다.
      editor_edit_Form->_DEBUG_RunArrow_Show();

      //[2010.02.16.화][수정!!!]{---------------------------------------
      //<editor_linebox_Form> 을 [지정행] 으로 대체한다.
      editor_edit_Form->_FocusLineNum(editor_edit_Form->_focusLineNum);
      //}---------------------------------------------------------------

  //}

  return;

}

void __fastcall DEBUG_Indicator_Hide(void)
{
  //지정자를 감춘다.

  //[지정자 표시]
  //{
      //[실행지정자] 와 [실행지정상자] 를 보여준다.
      editor_edit_Form->_DEBUG_RunArrow_Hide();

      //[2010.02.16.화][수정!!!]{------------------------
      //<editor_linebox_Form> 을 [지정행] 으로 대체한다.
      //<-1> 이면 지정행이 없는 것으로 보이지 않게 된다.
      editor_edit_Form->_FocusLineNum(-1);
      //}------------------------------------------------

      editor_edit_Form->_DEBUG_RunArrow(editor_edit_Form->_focusLineNum, true);

  //}

  return;

}

//[문서 관련]-------------------------------------------------------------------

void __fastcall Ide_Make_TempFolder(void)
{
  //[20120.04.06.화][생성!!!]{----------------------------------------------------
  //IDE 시작시 [임시문서] 처리를 위하여 반드시 있어야 하는 "temp" 를 만들어 준다.
  //사용자가 삭제할수 있으므로 반드시 무조건 만들어 주는 것으로 한다.
  //}-----------------------------------------------------------------------------

  ForceDirectories(ExtractFilePath(Ide_TempFolderPath));

}

void __fastcall IDE_File_Open(void)
{
  //[2005.07.05.화][작성!!!]{--
  //파일을 열어준다.
  //}--------------------------

  //[확장자 설정]
  //{
      //[2009.01.27.화][추가!!!]
      //금일 새로 정의된 <Ide_FileFilter> 로 대체.
      main_Form->file_OpenDialog->Filter = Ide_FileFilter;
      /*
      main_Form->file_OpenDialog->Filter = "*.c|*.c|*.h|*.h|*.txt|*.txt|*.gtxt|*.gtxt|*.gasm|*.gasm|*.gcsm|*.gcsm|*.gobj|*.gobj|*.glib|*.glib|*.gob1|*.gob1|*.gtmp|*.gtmp|"
                                           //[2012.03.17.토][추가!!!]
                                           //[맷돌-IDE] 관련 읽을수 있는 모든문서 추가.
                                           "*.glnk|*.glnk|*.$lst|*.$lst|*.$|*.$|*.gvmi|*.gvmi";
      */

  //}

  if(main_Form->file_OpenDialog->Execute() != true) return;

  //파일을 열어준다.
  //main_Form->Caption = main_Form->file_OpenDialog->FileName;

  editor_top_Form->_List_Add(main_Form->file_OpenDialog->FileName);

  return;

}

void __fastcall IDE_File_Save(void)
{
  //[2007.03.23.금][작성!!!]{------
  //현재 열려있는 문서를 저장한다.
  //}------------------------------

  editor_edit_Form->_EDITFILE_SaveNowEditFile();

  return;

}

void __fastcall IDE_File_SaveAll(void)
{
  //[2007.03.23.금][작성!!!]{-----------
  //현재 열려있는 모든 문서를 저장한다.
  //}-----------------------------------

  editor_edit_Form->_EDITFILE_SaveAllFile();

  return;

}

void __fastcall IDE_File_SaveAs(void)
{
  //[2007.04.01.일][생성!!!]{-------
  //[다른이름으로저장] 츨 처리한다.
  //}-------------------------------

  editor_edit_Form->_EDITFILE_SaveAsNowEditFile();

}

void __fastcall IDE_File_New(void)
{
  //[2007.03.28.수][생성!!!]{-----
  //[새문서] 를 하나 만들어 준다.
  //}-----------------------------

  editor_edit_Form->_EDITFILE_NewFile();

}

void __fastcall Ide_AutoSave_Period(int  pMinute)
{
  //[2018.05.05.토][생성!!!]{---------------------------------------------
  //[자동 저장:타이머] 저장 [주기] 설정.
  //[주기] 는 [분:단위] 이므로 타이머 시간에 맞게 밀리초(ms) 단위로 변경.
  //}---------------------------------------------------------------------

  main_Form->autoSave_Timer->Interval = pMinute * (60*1000);

}

void __fastcall Ide_AutoSave_Use(bool  pUse)
{
  //[2018.05.05.토][생성!!!]{-----------
  //[자동 저장:타이머] 사용 유/무 설정.
  //}-----------------------------------

  main_Form->autoSave_Timer->Enabled = pUse;

}

//[설계묶음 관련 함수]----------------------------------------------------------

bool __fastcall IDE_Project_New(bool  pNewOnly,
                                //[2009.05.30.토][추가!!!]
                                //[설계묶음 마법사] 를 보이는 경우는 true.
                                bool  pWizardShow)
{
  //[2009.01.26.월][생성!!!]{-------------------------------------------------
  //현재 모든 [설계묶음] 관련 [문서] 를 전부 닫아 주고 초기화 한다.
  //단, 이전에 작업 중인 것은 전부 자동 저장하고 종료해야 하고 수정된 것은
  //사용자에게 저장여부를 묻는 대화 상자를 호출해 주어야 한다.
  //이는 이미 만들어 놓은 [문서] 관련 함수를 사용하여 간단하게 처리 가능하다.
  //
  //최종적으로 IDE 초기 구동시 항목으로 간단하게 초기화 해 놓는다.
  //
  //[2012.03.27.화][수정!!!]--------------------------------------------------
  //[마법사] 보이기시 [모달] 적용하지 않고 일반 보이기로 수정.
  //[마법사:대화상자] 의 [미리보기] 기능을 지원하기 위한것.
  //[미리보기] 는 <main.c> 을 [편집기] 에 열어주는 것으로 처리되며 사용자가
  //이 문서를 살펴볼수 있어야 하기 때문에 [모달] 이어서는 안된다.
  //
  //[2012.05.13.일][수정!!!]--------------------------------------------------
  //[2018.10.21.일][수정!!!]--------------------------------------------------
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      //[2009.02.02.월][추가!!!]{--
      //보여줄 문자열을 저장한다.
      //
      //[2018.10.21.일][수정!!!]---
      //포인터 형식으로 변경.
      //}--------------------------

      char  *msgStr;

  //}

  //[현재 작업중인 <*.gprj> 를 닫을지 확인]
  //{
      //[2018.10.21.일][추가!!!]{-----------------------------------------------------
      //현재 작업중인 [설계묶음] 이 존재한다면 [종료] 할지 묻는다.
      //이 과정이 없으면 [새설계묶음/열기] 시에 무조건 현재 [설계묶음] 을 닫기 때문에
      //작업중 곤란할때가 있으므로 항상 먼저 확인시킨다.
      //}-----------------------------------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") != true)
      {
        //현재 작업 중인 <*.gprj> 에 대한 처리를 먼저 수행해 준다.

        msgStr = "현재 작업 중인 [설계묶음] 을 종료합니다.";

        if(ide_msgbox_Form->_MsgBox_Ok_Cancle(d_MSGBOX_info, msgStr) != true) return(false);

      }

  //}

  //[출력 문자열 설정]
  //{
      //[2009.02.02.월][추가!!!]{------------------------------------------------------
      //이 함수는 [새설계묶음] 을 만드는데 뿐만 아니라 [설계묶음 종료] 나 [IDE 종료]
      //등에도 사용되므로 이를 구분하여 해당동작과 관련된 문자열을 출력해 주어야 한다.
      //}------------------------------------------------------------------------------

      if(pNewOnly == true)
      {
        //순수하게 [새설계묶음] 인 경우.

        //STR_Assign(msgStr,
          msgStr = "현재 작업 중인 [설계묶음] 이 존재 합니다.\r\n"
                   "작업 중인 [설계묶음] 을 자동으로 저장하려면 [확인] 을 누르시고\r\n"
                   "저장하지 않고 새로운 [설계묶음] 을 열려면 [취소] 를 눌러 주세요.";//);

      }
      else
      {
        //STR_Assign(msgStr,
          msgStr = "현재 작업 중인 [설계묶음] 이 존재 합니다.\r\n"
                   "작업 중인 [설계묶음] 을 자동으로 저장한 다음에 종료하려면 [확인] 을 누르시고\r\n"
                   "저장하지 않고 그냥 끝내려면 [취소] 를 눌러 주세요.";//);

      }

  //}

  //[현재 작업중인 <*.gprj> 가 있나?]
  //{
      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") != true)
      {
        //현재 작업 중인 <*.gprj> 에 대한 처리를 먼저 수행해 준다.

        if(ide_msgbox_Form->_MsgBox_Ok_Cancle(d_MSGBOX_info, msgStr) == true)
        {
          //[현재 설계묶음 저장]
          //{
              //[!]{-----------------------------------
              //현재 작업 중인 [설계묶음] 을 저장한다.
              //전용 함수로 간단하게 처리한다.
              //}--------------------------------------

              IDE_Project_Save(false);

          //}

        }
        else
        {
          //[취소] 가 눌린 경우는 [설계묶음] 을 저장하지 않는다.

        }

      }

  //}

  //[현재 설계묶음 관련 문서 닫기]
  //{
      //[!]{--------------------------------------------------------------------
      //현재 [편집기] 에 열려 있는 모든 문서를 저장 확인후 닫아 준다.
      //전용 함수가 있으므로 순서대로 닫아주기만 하면 아직 저장되지 않은 문서는
      //자동으로 확인을 위한 [대화상자] 가 출력된다.
      //}-----------------------------------------------------------------------

      //만일 현재 저장되지 않음 문서가 있어서 [닫기] 시에 [대화상자] 가 나온
      //경우는 더이상 처리하지 않고 종료 해야 한다.
      //자세한 내용은 _List_DeleteAll() 함수의 설명을 참고 한다.
      if(editor_top_Form->_List_DeleteAll() != true) return(false);

  //}

  //[<infoTree> 초기화]
  //{
      //[2012.05.13.일][추가!!!]{------------------------------------
      //이 경우 크기는 <0> 이라 생성되지 않으면서 기존것은 삭제된다.
      //즉, 틀은 그대로 두고 공간은 완전히 [삭제] 된다.
      //존재하지만 공간과 크기가 없는 상태인것.
      //이는 최대한 메모리를 점유하지 않기 위한것.
      //}------------------------------------------------------------

      info_tree_Form->_Tree_Init(&(info_tree_Form->_tree), 0);

      //[참고!!!][2012.05.13.일]{----------------------------------------
      //[설계묶음] 을 닫을때 [편집기:줄이동자] 관련 [이벤트] 처리 부에서
      //자동적으로 <infoTree> 를 감춰주기 때문에, 위에서 [삭제] 한 뒤에
      //내용이 보일 가능성은 없다.
      //}----------------------------------------------------------------

  //}

  //[새설계묶음으로 초기화]
  //{
      //[!]{---------------------------------------------------------
      //일단 [새설계묶음] 으로 초기화 해준다.
      //이는 <*.gprj> 를 열어 주기전 항목을 준비해 놓기 위한 것이다.
      //}------------------------------------------------------------

      //[설계묶음] 과 관련된 2개 [정보창] 만 초기화 한다.

      //[2009.05.30.토][수정!!!]
      //각각의 비트 조합을 사용하는 것으로 수정한다.
      //
      //[2019.02.22.금][추가]
      //[찾기:Tree] 초기화-------------------------------------------------------v
      //
      //[2011.07.13.수][수정!!!]
      //[검증식 보기창] 도 전부 초기화 한다---------------------------v
      ide_tree_Form->_Tree_All_Init(d_Tree_Prj | d_Tree_Info | d_Tree_DbgExp | d_Tree_Find, true);

  //}

  //[설계묶음 마법사 열기]
  //{
      //[2009.05.30.토][추가!!!]{--------------------------------------------------
      //이전과 달리 [설계묶음] 을 새로 생성하는 경우는 반드시 [설계묶음 마법사] 를
      //사용하도록 한다.
      //}--------------------------------------------------------------------------

      if(pWizardShow == true)
      {
        //[2012.03.27.화][수정!!!]{----------------------------------------------------
        //[마법사] 에서도 [운영체제 설치] 와 마찬가지로 [내용보기] 가 지원되는데
        //[운영체제 설치] 와 달리 [풍선도움말] 이 아니라 직접 <main.c> 를
        //[편집기] 에 열어주는 방식을 사용한다.
        //이 경우 [편집기] 에 나온 문서를 사용자가 살펴볼수 있어야 하므로
        //<ShowModal()> 을 적용하지 말고 그냥 대화상자를 보여준다.
        //
        //[주의!!!]--------------------------------------------------------------------
        //[마법사] 로 [설계묶음] 을 생성하는 경우 [미리보기] 로 열었던 <main.c> 문서를
        //닫아주는 것은 <Ide_Project_Wizard()> 에서 자동 처리한다.
        //[미리보기] 문서는 한개만 열리도록 돼 있다.
        //<projectWizard_Form.cpp:_EVENT_MouseEnter_vmos_Btns()> 함수 설명 참고.
        //}----------------------------------------------------------------------------

        projectWizard_Form->_Show();
        //projectWizard_Form->ShowModal();

      }

  //}

  return(true);

}

void __fastcall IDE_Project_Open(//[2009.05.28.목][추가!!!]
                                 //NULL인 경우는 대화상자를 열어주고 이미 경로가 있는 경우는 바로 열어준다.
                                 //이는 [설계묶음 마법사] 기능으로 이미 만들어 진 것을 자동으로 열어 주어야 하기 때문이다.
                                 char  *pGprjName)
{
  //[2009.01.26.월][생성!!!]{-------------------------------------------------------------
  //<*.gprj> 문서를 읽어서 해당 항목을 해당 [정보창] 에 정리하고, 관련 처리를 수행한다.
  //
  //[2009.01.31.토][추가!!!]--------------------------------------------------------------
  //
  //1) 현재 "새설계묶음" 인 경우는 바로 열어 준다.
  //
  //2) 현재 <*.gprj> 가 작업 중인 경우는
  //
  //   (가) 현재 작업 중인 <*.gprj> 를 저장하고 닫을지 묻는 대화 상자를 출력한다.
  //   (나) 열기를 선택한 경우는, 현재 <*.gprj> 를 저장하고, 현재 편집기에 열려 있는
  //        관련 문서를 전부 닫아 준다.
  //        이 경우 해당 문서를 닫아 주는 함수에서 자동으로 저장되지 않은 문서에 대한
  //        확인을 하게 된다.
  //   (다) 일단, [새설계묶음] 으로 완전히 초기화 한다.
  //   (라) 지정된 <*.gprj> 를 열어 준다.
  //
  //[2009.05.28.목][추가!!!]--------------------------------------------------------------
  //[설계묶음 마법사] 를 사용하여 생성된 [설계묶음] 을 여는 경우는 이미 문서위치를 알고
  //있으므로 [열기 대화상자] 를 보여주지 않고 바로 열어주면 된다.
  //
  //[2009.09.05.토][추가!!!]
  //사용되는 기본 API 는 모두 <IDE경로\glib> 폴더 안에 있는 것을 사용하는 것이므로
  //[설계묶음] 을 열때 자동으로 다시 해당 API 를 복사하여 <[설계묶음]\glib> 에 덮어쓰기로
  //복사해준다.
  //<[설계묶음]\glib> 에 있는것은 모든 것을 설계묶음 단위로 관리 하기 위하여 편의상으로
  //원본을 복사해 놓은 것이므로 실제 적용시에는 항상 원본 API 를 사용해야 하기 때문이다.
  //[설계묶음] 을 열때 일괄적으로 자동 처리하는 것이 가장 간단한 방법이다.
  //
  //[2012.03.17.토][추가!!!]--------------------------------------------------------------
  //[가상기계] 부분 처리 추가.
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      int    fileSize;

      char   fileName[OPT_lineStrSize];

      char  *fileBuf = NULL;

      char   tempStr[OPT_lineStrSize];
      char   itemFileName[OPT_lineStrSize];

      //문서의 총행수.
      int    fileLineCount = 0;

      int    searchLineNumber = -1;

      int    itemCount;
      int    i;

      //[가상기계 관련]
      //{
          //[2012.03.17.토][추가!!!]
          //[가상기계] 부분을 처리하면서 가장 최후에 추가된 [GVMS/GVMX] 의
          //[Tree:절대위치] 를 기록/관리.
          //[GVMS/GVMX] 에 등록되는 [하위항목] 을 위하여 필요하고
          //항상 [GVMS/GVMX] 가 먼저 등록되어 반드시 위치가 먼저 설정된다.
          //기본적으로 <gvmNodeIndex> 을 구할때 같은 위치로 초기화.
          int     lastGvmIndex;

          //추가할 [옹이:가상기계] 위치.
          int     gvmNodeIndex;

          //긴 이름을 간단하게 사용하기 위하여.
          struct  TREE  *tree;

      //}

  //}

  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //
  //[Tree 치환]-----------------------------------------------------------
  //[2012.03.17.토][추가!!!]
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------

  //[현재 작업중인 <*.gprj> 가 있나?]
  //{
      //모든 과정은 [새설계묶음] 을 만드는 함수로 완전히 처리 가능하다.
      if(IDE_Project_New(true, false) != true) return;

  //}
  
  //[<*.gprj> 문서 열기]
  //{
      //[2009.05.28.목][수정!!!]{----------------------------------------------------------
      //[설계묶음 마법사] 로 생성된 [설계묶음] 을 여는 경우는 [대화상자] 를 보이지 않는다.
      //}----------------------------------------------------------------------------------

      if(pGprjName[0] == '\0')
      {
        //이 경우는 사용자가 직접 여는 경우로 [대화상자] 를 보여주어야 한다.

        //[확장자 설정]
        //{
            //[2009.01.27.화][추가!!!]
            main_Form->file_OpenDialog->Filter = "*.gprj|*.gprj";

        //}

        if(main_Form->file_OpenDialog->Execute() != true) return;

        STR_Assign(fileName, ((AnsiString)(main_Form->file_OpenDialog->FileName)).c_str());

      }
      else
      {
        //이 경우는 [대화상자] 를 보이지 않고 전달받은 [설계묶음] 을 바로 열어준다.
        STR_Assign(fileName, pGprjName);

      }

      //[<*.gprj> 인지 확인]
      //{
          STR_GetFileExt(fileName, tempStr);

          if(STR_Match_NoCase(tempStr, "gprj") != true)
          {
            //확장자가 [설계묶음] 에 해당하지 않으므로 열수 없다!

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 문서만 열수 있습니다.");

            return;

          }

      //}

      //[설계묶음 이름 추가]
      //{
          //[2009.01.30.금][추가!!!]{--------------------------------------------------------------
          //현재 연 <*.gprj> [이름] 을 <name>:"root" 에 등록한다.
          //기본적으로 "새설계묶음" 으로 되 있으므로 새로 연 <*.gprj> 이름으로 교체해 주는 것이다.
          //}--------------------------------------------------------------------------------------

          //[순수이름만 추출]
          //{
              STR_GetFileNameOnly(fileName, tempStr);

          //}

          //<name>:"root" 는 무조건 itemindex:0 이 된다.
          //[2012.04.20.금][수정!!!]
          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                    &(tree_tree_Form->_tree[d_TREE_project].items[0]),
                                    tempStr);

      //}

  //}

  //[문서 열기]
  //{
      FILE_Open(fileName, (unsigned char **)(&fileBuf), &fileSize);

  //}

  //[경로 기록]
  //{
      //{DATABASE} 의 해당 정보에 경로를 기록해 준다.
      //관련 정보도 같이 처리해 준다.

      //[project 경로 저장]
      STR_Assign(database->projectname, fileName);

      //[project path 저장]
      STR_GetFilePathOnly(database->projectname, database->projectpath);

      //[2009.07.24.금][추가!!!]{---------------------------------------
      //[build] 폴더는 항상 <*.gprj> 와 같은 위치에 있는 것으로 한다.
      //이 경로에 [build] 폴더가 없는 경우는 자동으로 하나 생성해 준다.
      STR_Assign(database->buildpath, database->projectpath);
      STR_Add_AB(database->buildpath, database->buildpath, "build\\");
      //}---------------------------------------------------------------

  //}

  //[전체 행수 얻기]
  //{
      fileLineCount = STR_Get_LineCount(fileBuf);

  //}

  //[내용 처리]
  //{
      //내용을 읽어서 해당 [정보창] 에 정리해 준다.

      //[설계문서]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<설계문서>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_C(itemFileName);

                //}

              }

          //}

      //}

      //[함수묶음]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<함수묶음>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.

                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[2012.03.17.토][수정!!!]
                //이전에 넣은것 같으나 넣은 이유가 감감하고, 무의미 하므로 일단 주석 처리.
                /*if(STR_Match_NoCase(tempStr, "glib\\기계닉스전용\\GUI\\GUI_GTabs\\_GTabs_X_.glib") == true)
                {
                   i = i;
                }
                */

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[API 다시 복사]
                //{
                    //[2009.09.05.토][추가!!!]{----------------------------------------------------------------------
                    //API 의 경우는 항상 새로운 것이 적용되야 하므로, 현재 읽어들일 [함수묶음] 이
                    //API 경로에 존재하는 것이라면 자동으로 다시 [설계묶음] 안의 해당 경로에 덮어쓰기로 복사한다.
                    //사용자의 [설계묶음]->[glib] 에 있는 것은 편의상 관리를 위하여 복사한 것으로, 실제 사용되는것은
                    //현재 IDE->[glib] 안에 있는 API 이다. 따라서, 항상 IDE->[glib] 가 사용되도록 해야 한다.
                    //}----------------------------------------------------------------------------------------------

                    //항상 새로운 OS 의 API 원본을 다시 복사한다.
                    Ide_Project_Api_ReCopy(tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_Glib(itemFileName);

                //}

              }

          //}

      //}

      //[참고자료]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<참고자료>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_Etc(itemFileName);

                //}

              }

          //}

      //}

      //[가상기계]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<가상기계>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록돼 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              //[추가 항목 구분]{------------------------------------------------
              //
              //1) [GVMS/GVMX] 인 경우.
              //   [옹이:가상기계] 를 대상으로 추가.
              //
              //2) 1) 이외의 문서.
              //   가장 나중에 처리한 [GVMS/GVMX] 를 대상으로 추가.
              //
              //<pPathNameExt> 에 [전체경로] 가 전달 되므로 [확장자] 를 검사하여
              //<*.gvms>, <*.gvmx> 인지 쉽게 구분 처리가능.
              //}----------------------------------------------------------------

              //[<가상기계> 옹이 위치 얻기]
              //{
                  //[!]{------------------------------
                  //[옹이:가상기계] 의 절대위치 얻기.
                  //}---------------------------------

                  tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "gvm", &gvmNodeIndex);

                  //기본적으로 같은 위치로 초기화.
                  lastGvmIndex = gvmNodeIndex;

              //}

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[추가]
                //{
                    //[확장자 추출]
                    //{
                        STR_GetFileExt(itemFileName, tempStr);

                    //}

                    if((STR_Match_NoCase(tempStr, "gvms") == true) ||
                       (STR_Match_NoCase(tempStr, "gvmx") == true))
                    {
                      //[옹이:가상기계] 에 등록.
                      if(Ide_Project_Add_Gvm_Item(gvmNodeIndex, itemFileName, &lastGvmIndex) != true) return;

                    }
                    else
                    {
                      //가장 마지막에 처리한 [GVMS/GVMX] 에 등록.
                      if(Ide_Project_Add_Gvm_SubItem(lastGvmIndex, itemFileName, NULL) != true) return;

                    }

                //}

              }

          //}

      //}

      //[표시]
      //{
          //tree 를 한번 그려준다.
          tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

      //}

  //}

  //[공간 삭제]
  //{
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }

  //}

  //[버튼 활성화]
  //{
      //[2009.01.28.수][추가!!!]{-------------------------------------
      //한개의 [설계묶음] 을 열었으므로 관련 [버튼] 을 활성화 해준다.
      //}-------------------------------------------------------------

      //if(ide_buttons_Form->Enabled != true) { ide_buttons_Form->Enabled = true; }

  //}

}

/*
void __fastcall IDE_Project_Open(void)
{
  //[2009.01.26.월][생성!!!]{-----------------------------------------------------------
  //<*.gprj> 문서를 읽어서 해당 항목을 해당 [정보창] 에 정리하고, 관련 처리를 수행한다.
  //
  //[2009.01.31.토][추가!!!]------------------------------------------------------------
  //
  //1) 현재 "새설계묶음" 인 경우는 바로 열어 준다.
  //
  //2) 현재 <*.gprj> 가 작업 중인 경우는
  //
  //   (가) 현재 작업 중인 <*.gprj> 를 저장하고 닫을지 묻는 대화 상자를 출력한다.
  //   (나) 열기를 선택한 경우는, 현재 <*.gprj> 를 저장하고, 현재 편집기에 열려 있는
  //        관련 문서를 전부 닫아 준다.
  //        이 경우 해당 문서를 닫아 주는 함수에서 자동으로 저장되지 않은 문서에 대한
  //        확인을 하게 된다.
  //   (다) 일단, [새설계묶음] 으로 완전히 초기화 한다.
  //   (라) 지정된 <*.gprj> 를 열어 준다.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      int    fileSize;

      char   fileName[OPT_lineStrSize];

      char  *fileBuf = NULL;

      char   tempStr[OPT_lineStrSize];
      char   itemFileName[OPT_lineStrSize];

      //문서의 총행수.
      int    fileLineCount = 0;

      int    searchLineNumber = -1;

      int    itemCount;
      int    i;

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[현재 작업중인 <*.gprj> 가 있나?]
  //{
      //모든 과정은 [새설계묶음] 을 만드는 함수로 완전히 처리 가능하다.
      if(IDE_Project_New(true) != true) return;

  //}

  //[<*.gprj> 문서 열기]
  //{
      //[확장자 설정]
      //{
          //[2009.01.27.화][추가!!!]
          main_Form->file_OpenDialog->Filter = "*.gprj|*.gprj";

      //}

      if(main_Form->file_OpenDialog->Execute() != true) return;

      STR_Assign(fileName, main_Form->file_OpenDialog->FileName.c_str());

      //[<*.gprj> 인지 확인]
      //{
          STR_GetFileExt(fileName, tempStr);

          if(STR_Match_NoCase(tempStr, "gprj") != true)
          {
            //확장자가 [설계묶음] 에 해당하지 않으므로 열수 없다!

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 문서만 열수 있습니다.");

            return;

          }

      //}

      //[설계묶음 이름 추가]
      //{
          //[2009.01.30.금][추가!!!]{--------------------------------------------------------------
          //현재 연 <*.gprj> [이름] 을 <name>:"root" 에 등록한다.
          //기본적으로 "새설계묶음" 으로 되 있으므로 새로 연 <*.gprj> 이름으로 교체해 주는 것이다.
          //}--------------------------------------------------------------------------------------

          //[순수이름만 추출]
          //{
              STR_GetFileNameOnly(fileName, tempStr);

          //}

          //<name>:"root" 는 무조건 itemindex:0 이 된다.
          STR_Assign(tree_tree_Form->_tree[d_TREE_project].items[0].text, tempStr);

      //}

  //}

  //[문서 열기]
  //{
      FILE_Open(fileName, (unsigned char **)(&fileBuf), &fileSize);

  //}

  //[경로 기록]
  //{
      //{DATABASE} 의 해당 정보에 경로를 기록해 준다.
      //관련 정보도 같이 처리해 준다.

      //[project 경로 저장]
      STR_Assign(database->projectname, fileName);

      //[project path 저장]
      STR_GetFilePathOnly(database->projectname, database->projectpath);

  //}

  //[전체 행수 얻기]
  //{
      fileLineCount = STR_Get_LineCount(fileBuf);

  //}

  //[내용 처리]
  //{
      //내용을 읽어서 해당 [정보창] 에 정리해 준다.

      //[설계문서]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<설계문서>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_C(itemFileName);

                //}

              }

          //}

      //}

      //[함수묶음]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<함수묶음>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.

                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_Glib(itemFileName);

                //}

              }

          //}

      //}

      //[참고자료]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(fileBuf, fileLineCount, "<참고자료>", &searchLineNumber);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록되 있다.
              STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

          //[항목 처리]
          //{
              //[!]{------------------------------------------------------------
              //이 경로는 <*.gprj> 의 경로는 제외한 경로가 된다.
              //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.
              //}---------------------------------------------------------------

              for(i = 0; i < itemCount; i++)
              {
                //[문서 이름] 얻기.
                STR_Get_LineStr_withLineNumber(fileBuf, searchLineNumber + 2 + i, tempStr);

                //[전체 이름으로 합성]
                //{
                    STR_Assign(itemFileName, database->projectpath);

                    STR_Add_AB(itemFileName, itemFileName, tempStr);

                //}

                //[열기]
                //{
                    IDE_Project_Add_Etc(itemFileName);

                //}

              }

          //}

      //}

      //[표시]
      //{
          //tree 를 한번 그려준다.
          tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

      //}

  //}

  //[공간 삭제]
  //{
      delete [] fileBuf; fileBuf = NULL;

  //}

  //[버튼 활성화]
  //{
      //[2009.01.28.수][추가!!!]{-------------------------------------
      //한개의 [설계묶음] 을 열었으므로 관련 [버튼] 을 활성화 해준다.
      //}-------------------------------------------------------------

      //if(ide_buttons_Form->Enabled != true) { ide_buttons_Form->Enabled = true; }

  //}

  return;

}
*/

void __fastcall IDE_Project_Save(//[다른이름으로 저장] 인 경우는 무조건 [대화상자] 를 열어 주어야 한다.
                                 bool  pSaveAs)
{
  //[2009.01.26.월][생성!!!]{-----------------------------------------------------------------
  //현재 열려 있는 <*.gprj> 을 저장한다.
  //
  //1) 현재 [설계묶음] 이름이 "새설계묶음" 인 경우는 아직 한번도 저장되지 않은 것이므로
  //   이름을 지정하여 저장할 [대화 상자] 를 보여 주어야 한다.
  //   [새설계묶음] 인 경우는 어떤 항목도 추가 할수 없으므로 현재 비어있는 상태이다.
  //   즉, 무조건 <*.gprj> 로 저장된 상태에서만 이 경로를 참고로 항목을 추가 할수 있다.
  //
  //2) 현재 이미 <*.gprj> 로 저장되 있는 상태라면 다시 이 경로대로 저장한다.
  //
  //[2011.05.09.월][중요수정!!!]--------------------------------------------------------------
  //[Tree:함수묶음] 의 표현 구조가 기존의 [경로] 방식에서 [Tree 구조] 방식으로 변경되었으므로
  //저장시 바로 저장하면 안되고, 이전처럼 [경로] 를 추출하여 저장해야 한다.
  //즉, [저장] 자체는 기존의 방식대로 저장한다.
  //
  //[2012.03.17.토][추가!!!]------------------------------------------------------------------
  //[가상기계] 부분 처리 추가.
  //}-----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      int   fileSize;

      char  fileName[OPT_lineStrSize];

      char  fileBuf[OPT_ProjectFileBuf_Size];

      char  tempStr[OPT_lineStrSize];

      int   nodeIndex;
      int   nodeItemLevel;
      int   nodeItemCount;
      int   i;

      //[2011.05.09.월][추가!!!]
      struct  TREE   *tree;

      int     nodeLastItemIndex;

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[<*.gprj> 가 존재하는가?]
  //{
      //[!]{---------------------------------------------------------------------------
      //현재 "새설계묶음" 인 경우는 새로 저장하기 위한 [대화상자] 를 보여 주어야 한다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}------------------------------------------------------------------------------

      //[2012.04.20.금][수정!!!]
      if((STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true) ||
         //[다른 이름으로 저장] 인 경우는 무조건 [대화상자] 를 보여 주어야 한다.
         (pSaveAs == true))
      {
        //현재 [새설계묶음] 상태이므로 <*.gprj> 로 저장 할수 있도록 [저장 대화 상자] 를 보여 준다.

        //[확장자 설정]
        //{
            //[2009.01.27.화][추가!!!]
            main_Form->file_SaveDialog->Filter = "*.gprj|*.gprj";

        //}

        if(main_Form->file_SaveDialog->Execute() != true) return;

        STR_Assign(fileName, ((AnsiString)main_Form->file_SaveDialog->FileName).c_str());

      }
      else
      {
        //이미 <*.gprj> 가 존재 하는 것이므로 전체 경로로 합성한다.

        //[전체 이름으로 합성]
        //{
            STR_Assign(fileName, database->projectpath);

            //[2012.04.20.금][수정!!!]
            STR_Add_AB(fileName, fileName, tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0));

        //}

      }

  //}

  //[<*.gprj> 인지 확인]
  //{
      //[설계묶음] 은 반드시 <*.gprj> 확장자를 가지고 있어야 한다.

      //[<*.gprj> 인지 확인]
      //{
          STR_GetFileExt(fileName, tempStr);

          if(STR_Match_NoCase(tempStr, "gprj") != true)
          {
            //확장자가 [설계묶음] 에 해당하지 않으므로 저장 할수 없다.

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 문서로만 저장 할수 있습니다.");

            return;

          }

      //}

      //[설계묶음 이름 추가]
      //{
          //[!]{----------------------------------------------------------------------------------
          //현재 연 <*.gprj> [이름] 을 <name>:"root" 에 등록한다.
          //기본적으로 "새설계묶음" 으로 되 있으므로 새로 저장하는 <*.gprj> 이름으로 교체해 준다.
          //}-------------------------------------------------------------------------------------

          //[순수이름만 추출]
          //{
              STR_GetFileNameOnly(fileName, tempStr);

          //}

          //<name>:"root" 는 무조건 itemindex:0 이 된다.
          //[2012.04.20.금][수정!!!]
          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                    &(tree_tree_Form->_tree[d_TREE_project].items[0]),
                                    tempStr);

      //}

  //}

  //[저장소 초기화]
  //{
      STR_Assign(fileBuf, "");

  //}

  //[경로 기록]
  //{
      //{DATABASE} 의 해당 정보에 경로를 기록해 준다.
      //관련 정보도 같이 처리해 준다.

      //[project 경로 저장]
      STR_Assign(database->projectname, fileName);

      //[project path 저장]
      STR_GetFilePathOnly(database->projectname, database->projectpath);

  //}

  //[내용 처리]
  //{
      //내용을 읽어서 해당 [정보창] 에 정리해 준다.

      //[설계문서]
      //{
          //제목을 추가한다.
          STR_Add(fileBuf, "<설계문서>\r\n");

          //[직계 항목수 구하기]
          //{
              //[설계문서] 의 [직계 가지] 수 를 구한다.
              tree_tree_Form->_Tree_Get_Node_ItemCount(&(tree_tree_Form->_tree[d_TREE_project]),
                                                       "c", &nodeIndex, &nodeItemCount);

          //}

          //[항목 수 기록]
          //{
              CONV_LongVal_To_Str(nodeItemCount, 8, false, tempStr);

              STR_Add(fileBuf, tempStr);
              STR_Add(fileBuf, "\r\n");

          //}

          //[항목 추가]
          //{
              //[2010.03.24.수][중요추가!!!]{----------------------------------------
              //추가된 항목이 없는 경우는 처리하지 않는다.
              //[그림부품] 의 이벤트를 확인하는 예제를 실행하다가 발견하고 수정한다.
              //어떻게 이제까지 그냥 처리하게 두었는지...
              //}--------------------------------------------------------------------

              if(nodeItemCount > 0)
              {
                //[옹이] 의 [직계가지] 의 <level> 은 [옹이] <level> + 1 이 된다.
                nodeItemLevel = tree_tree_Form->_tree[d_TREE_project].items[nodeIndex].level + 1;

                for(//[직계가지] 는 [옹이] 바로 다음 부터 시작된다.
                    i = (nodeIndex + 1);
                    ;
                    i++)
                {
                  if     (nodeItemLevel == tree_tree_Form->_tree[d_TREE_project].items[i].level)
                  {
                    //[직계가지] 에 해당한다.

                    //<text> 가 문서이름에 해당한다.
                    //[2012.04.20.금][수정!!!]
                    STR_Add(fileBuf, tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, i));
                    STR_Add(fileBuf, "\r\n");

                  }
                  else if(nodeItemLevel > tree_tree_Form->_tree[d_TREE_project].items[i].level)
                  {
                    //범위를 벗어난 것으로 더이상 처리 하지 않는다.
                    break;

                  }
                  else
                  {
                    //[직계가지] 만 처리 하므로 보다 하위 가지는 처리하지 않는다.

                  }

                }

              }

          //}

      //}

      //[함수묶음]
      //{
          //[2011.05.09.월][중요수정!!!]{-----------------------------------------
          //[Tree:함수묶음] 의 구조가 이전의 [경로] 방식에서 [Tree 구조] 방식으로
          //변경되었으므로 이에 대응하여 전부 수정한다.
          //}---------------------------------------------------------------------

          //제목을 추가한다.
          STR_Add(fileBuf, "<함수묶음>\r\n");


          //[<Tree:함수묶음> 옹이 정보 얻기]
          //{
              //현재 [옹이] 의 [하위항목] 관련 정보를 수집한다.
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2
                              (tree,
                               "glib",
                               //이 옹이의 [절대위치].
                               &nodeIndex,
                               NULL,
                               //지정 [옹이] 의 가장 마지막 가지의 item-index.
                               &nodeLastItemIndex);

          //}

          //[항목수 처리]
          //{
              //[<*.glib> 항목 수 얻기]
              //{
                  //[!]{----------------------------------------------------------
                  //기존의 [경로] 방식과 달리 [Tree 구조] 방식으로 변경되었으므로
                  //<*.glib> 항목의 수를 직접 검사하여 얻어야 한다.
                  //}-------------------------------------------------------------

                  for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
                      i = nodeIndex + 1,
                      nodeItemCount = 0;
                      //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
                      i <= nodeLastItemIndex;
                      i++)
                  {
                    //[<txt> 가 <*.glib> 인가?]
                    //{
                        //[!]{----------------------------------------------------------------------------
                        //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
                        //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
                        //}-------------------------------------------------------------------------------

                        //[항목] 의 <txt> 에서 [확장자] 추출.
                        //[2012.04.20.금][수정!!!]
                        STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, i), tempStr);

                        //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
                        if(STR_Match_NoCase(tempStr, "glib") != true) continue;

                    //}

                    nodeItemCount++;

                  }

              //}

              //[항목 수 기록]
              //{
                  CONV_LongVal_To_Str(nodeItemCount, 8, false, tempStr);

                  STR_Add(fileBuf, tempStr);
                  STR_Add(fileBuf, "\r\n");

              //}

          //}

          //[항목 추가]
          //{
              //[2010.03.24.수][중요추가!!!]{-------------------------------------------
              //추가된 항목이 없는 경우는 처리하지 않는다.
              //[그림부품] 의 이벤트를 확인하는 예제를 실행하다가 발견하고 수정한다.
              //어떻게 이제까지 그냥 처리하게 두었는지...
              //
              //[2011.05.09.월][중요수정!!!]--------------------------------------------
              //[Tree:함수묶음] 의 표현방식이 [경로] 방식이 아니라 [Tree 구조] 방식으로
              //변경되었으므로 전용함수로 [경로] 를 추출하여, 저장할때는 기존 방식처럼
              //[경로] 방식으로 저장한다.
              //}-----------------------------------------------------------------------

              //<*.glib> 가 한개라도 존재하는 경우만 처리해야 한다.
              if(nodeItemCount > 0)
              {
                //[!]{----------------------------------------------------
                //1) 먼저 <*.glib> 항목을 찾는다.
                //2) [설계묶음] 내부 경로를 합성한다.
                //3) 저장한다.
                //
                //[함수묶음] 의 끝까지 전부 검사하여 1) - 3) 을 반복한다.
                //}-------------------------------------------------------

                for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
                    i = nodeIndex + 1;
                    //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
                    i <= nodeLastItemIndex;
                    i++)
                {
                  //[<txt> 가 <*.glib> 인가?]
                  //{
                      //[!]{----------------------------------------------------------------------------
                      //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
                      //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
                      //}-------------------------------------------------------------------------------

                      //[항목] 의 <txt> 에서 [확장자] 추출.
                      //[2012.04.20.금][수정!!!]
                      STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, i), tempStr);

                      //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
                      if(STR_Match_NoCase(tempStr, "glib") != true) continue;

                  //}

                  //[경로추출]
                  //{
                      //현재 <*.glib> 항목의 [설계묶음 내부 경로] 를 합성한다.
                      Ide_Project_Glib_Make_InFileName(tree, i, tempStr);

                  //}

                  //[저장문자열에 추가]
                  //{
                      STR_Add(fileBuf, tempStr);
                      STR_Add(fileBuf, "\r\n");

                  //}

                }

              }

          //}

      //}

      //[참고자료]
      //{
          //제목을 추가한다.
          STR_Add(fileBuf, "<참고자료>\r\n");

          //[직계 항목수 구하기]
          //{
              //[참고자료] 의 [직계 가지] 수 를 구한다.
              tree_tree_Form->_Tree_Get_Node_ItemCount(&(tree_tree_Form->_tree[d_TREE_project]),
                                                       "etc", &nodeIndex, &nodeItemCount);

          //}

          //[항목 수 기록]
          //{
              CONV_LongVal_To_Str(nodeItemCount, 8, false, tempStr);

              STR_Add(fileBuf, tempStr);
              STR_Add(fileBuf, "\r\n");

          //}

          //[항목 추가]
          //{
              //[2010.03.24.수][중요추가!!!]{----------------------------------------
              //추가된 항목이 없는 경우는 처리하지 않는다.
              //[그림부품] 의 이벤트를 확인하는 예제를 실행하다가 발견하고 수정한다.
              //어떻게 이제까지 그냥 처리하게 두었는지...
              //}--------------------------------------------------------------------

              if(nodeItemCount > 0)
              {
                //[옹이] 의 [직계가지] 의 <level> 은 [옹이] <level> + 1 이 된다.
                nodeItemLevel = tree_tree_Form->_tree[d_TREE_project].items[nodeIndex].level + 1;

                for(//[직계가지] 는 [옹이] 바로 다음 부터 시작된다.
                    i = (nodeIndex + 1);
                    ;
                    i++)
                {
                  if     (nodeItemLevel == tree_tree_Form->_tree[d_TREE_project].items[i].level)
                  {
                    //[직계가지] 에 해당한다.

                    //<text> 가 문서이름에 해당한다.
                    //[2012.04.20.금][수정!!!]
                    STR_Add(fileBuf, tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, i));
                    STR_Add(fileBuf, "\r\n");

                  }
                  else if(nodeItemLevel > tree_tree_Form->_tree[d_TREE_project].items[i].level)
                  {
                    //범위를 벗어난 것으로 더이상 처리 하지 않는다.
                    break;

                  }
                  else
                  {
                    //[직계가지] 만 처리 하므로 보다 하위 가지는 처리하지 않는다.

                  }

                }

              }

          //}

      //}

      //[가상기계]
      //{
          //[2012.03.16.금][중요수정!!!]{--------------------
          //[함수묶음] 과 달리 모든 항목을 다 기록해야 한다.
          //}------------------------------------------------

          //제목을 추가한다.
          STR_Add(fileBuf, "<가상기계>\r\n");


          //[<Tree:가상기계> 옹이 정보 얻기]
          //{
              //현재 [옹이] 의 [하위항목] 관련 정보를 수집한다.
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2
                              (tree,
                               "gvm",
                               //이 옹이의 [절대위치].
                               &nodeIndex,
                               NULL,
                               //지정 [옹이] 의 가장 마지막 가지의 item-index.
                               &nodeLastItemIndex);

          //}

          //[항목수 처리]
          //{
              //[항목 수 얻기]
              //{
                  //[!]{------------------------------------------------------
                  //[경로(폴더)] 를 제외한 모든 항목은 다 유효한 것으로 본다.
                  //<bmpindex:d_ITEMBMP_folder> 인 것으로 쉽게 구별 가능.
                  //}---------------------------------------------------------

                  for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
                      i = nodeIndex + 1,
                      nodeItemCount = 0;
                      //[Tree:가상기계] 의 가장 마지막 항목까지 전부 검사.
                      i <= nodeLastItemIndex;
                      i++)
                  {
                    //[경로(폴더)] 가 아닌 모든 항목이 대상.
                    if(tree->items[i].bmpindex != d_ITEMBMP_folder) nodeItemCount++;

                  }

              //}

              //[항목 수 기록]
              //{
                  CONV_LongVal_To_Str(nodeItemCount, 8, false, tempStr);

                  STR_Add(fileBuf, tempStr);
                  STR_Add(fileBuf, "\r\n");

              //}

          //}

          //[항목 추가]
          //{
              //[!]{------------------------------------------------------------------
              //[옹이:가상기계] 에 추가된 [항목] 이 없는 경우는 처리하지 않는다.
              //추가시 [경로] 만 추가할수 없으므로 [경로(폴더)] 만 존재할수는 없다.
              //
              //[항목] 을 저장시 전용함수로 [설계묶음] 내부 [경로이름확장자] 로 저장.
              //}---------------------------------------------------------------------

              //항목이 한개라도 있는 경우만 처리.
              if(nodeItemCount > 0)
              {
                //[!]{-------------------------------------------------
                //1) 먼저 [경로(폴더)] 가 아닌 [항목] 찾기.
                //2) [설계묶음] 내부 경로를 합성한다.
                //3) 저장한다.
                //
                //[가상기계] 끝까지 전부 검사하여 1) - 3) 을 반복한다.
                //}----------------------------------------------------

                for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
                    i = nodeIndex + 1;
                    //[Tree:가상기계] 의 가장 마지막 항목까지 전부 처리.
                    i <= nodeLastItemIndex;
                    i++)
                {
                  //[경로(폴더)] 가 아닌 모든 항목이 대상.
                  if(tree->items[i].bmpindex != d_ITEMBMP_folder)
                  {
                    //[경로추출]
                    //{
                        //현재 [항목] 의 [설계묶음] 내부 [경로이름확장자] 합성.
                        Ide_Project_Gvm_Make_InFileName(tree, i, tempStr);

                    //}

                    //[저장문자열에 추가]
                    //{
                        STR_Add(fileBuf, tempStr);
                        STR_Add(fileBuf, "\r\n");

                    //}

                  }

                }

              }

          //}

      //}

      //[마무리]
      //{
          STR_Add(fileBuf, "<끝>\r\n");

      //}

      //[표시]
      //{
          //tree 를 한번 그려준다.
          tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

      //}

  //}

  //[문서 저장]
  //{
      //[문서 크기] 얻기.
      fileSize = STR_Length(fileBuf);

      //임시문서저장.
      FILE_Save(fileName, fileBuf, fileSize);

  //}

  //[열려있는 모든 문서 저장]
  //{
      //[2009.04.01.수][추가!!!]
      //현재 열려 있는 전체 문서를 다시 저장한다.
      IDE_File_SaveAll();

  //}

  //[버튼 활성화]
  //{
      //[2009.01.28.수][추가!!!]{-------------------------------------
      //한개의 [설계묶음] 을 열었으므로 관련 [버튼] 을 활성화 해준다.
      //}-------------------------------------------------------------

      //if(ide_buttons_Form->Enabled != true) { ide_buttons_Form->Enabled = true; }

  //}

  return;

}

void __fastcall IDE_Project_SaveAs(void)
{
  //[2009.01.26.월][생성!!!]{--------------------------
  //<*.gprj> 의 [다른이름으로저장] 인 경우를 처리한다.
  //}--------------------------------------------------

  //[다른 이름으로 저장] 조건으로 실행한다.
  IDE_Project_Save(true);

  return;

}

void __fastcall IDE_Project_Close(void)
{
   //[2009.01.26.월][생성!!!]{------------------------------------------------------------------
   //IDE_Project_New() 를 하면 어차피 모든 현재 <*.gprj> 관련 문서는 닫히게 된다.
   //다라서, 이 함수는 사실상 아무 의미가 없다.
   //즉, 현재 [설계묶음] 을 닫는 경우는 IDE_Project_New() 함수를 사용하여 새로운 것을 생성한다.
   //어차피 창이 하나 있으므로 항상 기본 항목을 보여 주어야 하므로...
   //
   //[2012.05.13.일][수정!!!]-------------------------------------------------------------------
   //}------------------------------------------------------------------------------------------

   //[닫기] 는 [새설계묶음] 으로 초기화 하는 것과 완전히 같다.
   IDE_Project_New(false, false);

   //[<infoTree> 초기화]
   //{
       //[2012.05.13.일][추가!!!]{------------------------------------
       //이 경우 크기는 <0> 이라 생성되지 않으면서 기존것은 삭제된다.
       //즉, 틀은 그대로 두고 공간은 완전히 [삭제] 된다.
       //존재하지만 공간과 크기가 없는 상태인것.
       //이는 최대한 메모리를 점유하지 않기 위한것.
       //}------------------------------------------------------------

       //[2012.05.13.일][수정!!!]{--------------------------------------------------
       //[설계묶음] 의 [열기/닫기] 의 모든 경우 반드시 <IDE_Project_New()>
       //함수를 사용하게 되므로 모든 경우에 적용하기 위하여 <IDE_Project_New()>
       //함수에서 현재 작업중인 [설계묶음] 문서를 모두 닫을때 처리하는 것으로 수정.
       //이 부분의 처리는 [주석] 으로 처리한다.
       //info_tree_Form->_Tree_Init(&(info_tree_Form->_tree), 0);
       //}--------------------------------------------------------------------------

   //}

   //[참고!!!][2012.05.13.일]{----------------------------------------
   //[설계묶음] 을 닫을때 [편집기:줄이동자] 관련 [이벤트] 처리 부에서
   //자동적으로 <infoTree> 를 감춰주기 때문에, 위에서 [삭제] 한 뒤에
   //내용이 보일 가능성은 없다.
   //}----------------------------------------------------------------

}

void __fastcall IDE_Project_Add_C(char  *pFileName)
{
  //[2009.01.29.목][생성!!!]{-------------------------------
  //[설계문서] [옹이] 의 항목에 <*.c> 를 추가한다.
  //단, 현재 <*.gprj> 가 위치한 폴더 안에 있는 문서만 된다.
  //모든 작업은 <*.gprj> 를 기준으로 관리 되어야 하므로.
  //
  //[2009.01.31.토][추가!!!]--------------------------------
  //"새설계묶음" 인 경우는 아무것도 추가할수 없다.
  //아직 담을 그릇이 없는 것과 같으므로.
  //}-------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];
      char  hexStr[OPT_wordStrSize];

      int   nodeItemIndex;
      int   tempVal;

      //[tree 관련]
      //{
          struct TREEITEM  item;

      //}

  //}

  //[<*.gprj> 가 존재하는가?]
  //{
      //[2009.01.31.토][추가!!!]{--------------------
      //현재 "새설계묶음" 인 경우는 추가하지 않는다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}--------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        //비어있는 상태이므로 아무것도 추가 할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 항목을 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        return;

      }

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[<*.c> 문서 열기]
  //{
      if(pFileName == NULL)
      {
        //[확장자 설정]
        //{
            //[설계문서] 는 <*.c> 만을 대상으로 한다.
            main_Form->file_OpenDialog->Filter = "*.c|*.c";

        //}

        //[문서 열기 대화상자] 보여주기.
        if(main_Form->file_OpenDialog->Execute() != true) return;

		STR_Assign(fileName, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

      }
      else
      {
        STR_Assign(fileName, pFileName);

      }

      //[<*.c> 인지 확인]
	  //{
          STR_GetFileExt(fileName, tempStr);

          if(STR_Match_NoCase(tempStr, "c") != true)
          {
            //확장자가 [설계문서] 에 해당하지 않으므로 추가할수 없다.

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.c> 문서만 추가할수 있습니다.");

            return;

          }

      //}

  //}

  //[경로 확인]
  //{
      //현재 [문서] 가 <*.gprj> 가 위치한 [폴더] 안에 있는지 확인한다.

      if(STR_BaseDirectory_Match(database->projectpath, fileName) != true)
      {
        //<*.gprj> 가 있는 폴더 안에 존재하지 않으므로 추가할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 가 위치한 [폴더] 안의 문서만 추가할수 있습니다.");

        return;

      }

  //}

  //[항목 추가]
  //{
       //[항목 초기화][2012.04.18.수]{-------------------------------------
       //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
       tree_tree_Form->_Item_Init(&item);
       //}-----------------------------------------------------------------

      //[name 만들기]
      //{
          //[[옹이] 항목 수 구하기]
          //{
              //현재 추가할 [옹이] 의 항목 수가 지금 추가할 [항목] index 가 된다.
              tree_tree_Form->_Tree_Get_Node_ItemCount(&(tree_tree_Form->_tree[d_TREE_project]),
                                                       "c", //<---[설계문서] 옹이의 <name> 이다.
                                                       &nodeItemIndex,
                                                       &tempVal);

          //}

          //"c.[번호]" 형식으로 만들어 준다(이름만 다르면 되므로).
          STR_Assign(item.name, "c.");
          CONV_LongVal_To_Hex2(tempVal, hexStr);
          STR_Add_AB(item.name, item.name, hexStr);

      //}

      //[항목 문자열 만들기]
      //{
          //경로는 <*.gprj> 의 경로는 제외 하고 기록해야 한다.
          //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.

          //[설계묶음 경로 제거]
          //{
              //순수한 <*.gprj> 존재하는 폴더 안의 경로만 추출한다.
              STR_GetFileName_Except_BaseDirectory(database->projectpath, fileName, tempStr);

          //}

          //[2012.04.20.금][수정!!!]
          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                    &item,
                                    tempStr);

      //}

      //[기타 설정]
      //{                                        
          item.kind = '.';
          item.bmpindex = d_ITEMBMP_file_c;

      //}

      //[추가]
      //{
          //[중북확인]
          //{
              //표시되는 <text> 가 일치하는 경우(즉, 같은 문서의 경우)는 추가하지 않아야 한다.
              tree_tree_Form->_Tree_Get_Node_ItemIndex_withText(&(tree_tree_Form->_tree[d_TREE_project]),
                                                                "c",
                                                                //[2012.04.20.금][수정!!!]
                                                                tree_tree_Form->_Item_Txt_StrPtr2(d_TREE_project, item.txt),
                                                                false,
                                                                NULL,
                                                                &tempVal);

              if(tempVal >= 0)
              {
                //중복되는 것이 있는 경우이며, 중복 되는 문서는 추가 할수 없다!

                ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "이미 존재하는 문서입니다.");

                return;

              }

          //}

          //추가한다.
          tree_tree_Form->_Tree_Add_NodeItem(&(tree_tree_Form->_tree[d_TREE_project]), "c", &item, NULL);

      //}

      //[표시]
      //{
          if(pFileName == NULL)
          {
            //tree 를 한번 그려준다.
            tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

          }

      //}

  //}

  return;

}

int __fastcall IDE_Project_Delete_C(void)
{
  //[2009.02.01.일][생성!!!]{----------------------------------------------------
  //[설계문서] 에 추가된 <*.c> 를 삭제 한다.
  //단, [직계가지] 인 <*.c> 만 대상으로 하고 <Build> 후에 <*.c> 의 하위 항목으로
  //등록되는 <*.h> 는 대상으로 하지 않는다.
  //즉, <*.c> 가 삭제 되는 경우는 무조건 하위에 등록되 있는 모든 <*.h> 로 같이
  //삭제해 주어야 한다(tree_tree_Form->_Tree_Delete_Item() 함수에서 자동 처리).
  //
  //[2011.05.10.화][수정!!!]-----------------------------------------------------
  //[Tree:설계문서] 의 경우도 [삭제 대상] 으로 넣고, 이 경우는 [항목 초기화] 로
  //하위 모든 항목을 지운다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      int     nodeIndex;
      int     nodeLastItemIndex;

      char    tempStr[OPT_wordStrSize];
      char    hexStr[OPT_wordStrSize];

      int     i;
      int     x, y;

      //[2011.05.10.화][추가!!!]
      int     delItemIndex;
      int     itemCount;
      int     itemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree_tree_Form->_tree[d_TREE_project].select_itemindex < 0) return(no);

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[범위 확인]
  //{
      //[설계문서] [옹이] 에 등록된 것이 맞는지 먼저 확인한다.

      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

      //[2011.05.10.화][중요수정!!!]{---------------------------------------------
      //[삭제] 의 경우 [Tree:설계문서] 로 일단 대상이 되므로 이것도 포함 시킨다.
      //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
      //즉, [Tree:설계묶음] 을 완전히 비워주는 기능이다.
      //}-------------------------------------------------------------------------
      //---------------v
      if(!((nodeIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex)))
      {
        //[설계문서] [범위] 에 해당하지 않으므로 이 함수처리 대상이 아니다.

        return(no);

      }

  //}

  //[문서 확인]
  //{
      //[방법]{----------------------------------------------------------------------
      //[설계문서] 에서는 반드시 [직계가지] 에 해당하는 <*.c> 만 삭제 가능하다.
      //<*.c> 에 등록되 있는 <*.h> 는 삭제 할수 없다.
      //
      //1) 간단하게 [직계가지] 인지 확인하기만 하면 된다.

      //[2011.05.10.화][수정!!!]-----------------------------------------------------
      //전부다 삭제 대상이 되고, 단지 <*.h> 만 대상이 되지 않으므로 이것만 확인한다.
      //}----------------------------------------------------------------------------

      //[현재 항목의 [확장자] 가 <*.h> 인가?]
      //{
          //[확장자 추출]
          //{
              //[2012.04.20.금][수정!!!]
              STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, tree->select_itemindex), tempStr);

          //}

          if(STR_Match_NoCase(tempStr, "h") == true)
          {
            //<*.h> 는 삭제 할수 없다.
            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "<*.h> 문서는 삭제 대상이 아닙니다.\r\n"
                                     "<*.c> 문서에 등록된 하위 문서는 자동으로 추가 되는 정보이며\r\n"
                                     "<*.c> 문서가 삭제 될때 자동으로 같이 삭제 됩니다."
                                    );

            //삭제 할수 없는 [항목] 이다.
            return(error);

          }

      //}

  //}

  //[항목 삭제]
  //{
      //[2011.05.10.화][수정!!!]{-----------------------------------------------------
      //[Tree:설계문서] 가 [삭제대상] 인 경우는 모든 하위 항목을 제거하고 비워준다.
      //이 경우는 하예 하위 항목이 하나도 없으므로 <name> 을 [재생성] 할 필요가 없다.
      //}-----------------------------------------------------------------------------

      //[초기화]
      //{
          //기본적인 삭제 위치는 현재 [선택된 항목] 이다.
          delItemIndex = tree->select_itemindex;

      //}

      //[<Tree:설계문서> 항목인가?]
      //{
          //[!]{-------------------------------------------------------------------
          //[Tree:함수묶음] 인 경우와 다른 항목의 경우를 구분하여 처리해야 한다.
          //<*.h> 의 경우는 이미 위에서 [삭제 대상이 아닌 것] 으로 막아 놓았으므로
          //여기서는 고려하지 않는다.
          //}----------------------------------------------------------------------

          if(STR_Match(tree->items[delItemIndex].name, "c") == true)
          {
            //[!]{---------------------------------------------------------------------
            //이 경우는 [삭제 대상] 이 [Tree:설계문서] 인 경우다.
            //
            //[직계가지] 를 하나씩 삭제해 주기만 하면 된다.
            //
            //아예 내부 항목이 다 없어지는 것이므로 [<name> 재생성] 을 할 필요도 없다.
            //}------------------------------------------------------------------------

            //[<Tree:설계문서> 직계가지 수 얻기]
            //{
                tree_tree_Form->_Tree_Get_Node_ItemCount2
                                  (tree,
                                   //지정 [옹이] 의 [절대위치].
                                   delItemIndex,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

            //}

            for(i = 0,
                //현재 옹이 다음부터 검사한다.
                itemIndex = delItemIndex + 1;
                //[직계가지] 개수 만큼 삭제한다.
                i < itemCount;
                i++)
            {
              //[직계가지] 는 현재 <[옹이].level> 보다 <+1> 된 값을 갖는다.
              if((tree->items[delItemIndex].level + 1) == tree->items[itemIndex].level)
              {
                //[직계가지] 에 해당하므로 [삭제] 한다(모든 하위 항목도 자동 삭제된다).
                tree_tree_Form->_Tree_Delete_Item(tree, itemIndex);

                //현재 항목이 삭제 되었으므로 [현재 위치] 부터 계속 검사 처리한다.

              }
              else
              {
                //다음 위치로 이동한다.
                itemIndex++;

              }

            }

            //마무리 부분으로 이동한다.
            goto lbEnd;

          }

      //}

      //[!]{---------------------------------------------------------------
      //여기까지 온 경우는 <*.c> 가 대상인 경우다.
      //위에서 <*.h> 인 경우는 이미 차단되었으므로 <*.c> 만 처리하면 된다.
      //}------------------------------------------------------------------

      //[삭제]
      //{
          //현재 선택된 것을 삭제 한다.
          tree_tree_Form->_Tree_Delete_Item(tree, tree->select_itemindex);

      //}

      //[정보 구하기]
      //{
          //항목이 삭제 되었으므로 다시 정보를 얻는다.
          tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

      //}

      //[<name> 재생성]
      //{
          //[방법]{--------------------------------------------------------------------------------
          //각각의 항목의 <name> 을 다시 index 순번으로 만들어 주어야 한다.
          //이는 계속 생성/삭제를 반복하는 경우 우연히 <name> 이 겹치는 것을 방지하기 위한 것이다.
          //
          //<*.c>.name = "c.x"
          //<*.h>.name = "c.x.h.y"
          //
          //}--------------------------------------------------------------------------------------

          //[옹이] 다음 부터 하위 항목이 된다.
          for(i = (nodeIndex + 1), x = 0, y = 0; i <= nodeLastItemIndex; i++)
          {
            if     (tree->items[i].level == (tree->items[nodeIndex].level + 1))
            {
              //<*.c> 문서인 경우.

              STR_Assign(tree->items[i].name, "c.");

              //[번호얻기]
              //{
                  CONV_LongVal_To_Hex2(x, hexStr);
                  STR_Add(tree->items[i].name, hexStr);

              //}

              //[후처리]
              //{
                  x++;

                  //<*.h> 는 <*.c> 의 하위 가지가 되므로 반드시 0 부터 다시 시작해야 한다.
                  y = 0;

                  //[임시저장]
                  //{
                      //<*.h> 의 <name> 을 만들기 위하여 <*.c> <name> 을 기본으로 덧붙여 만들게 되므로
                      //일단 <*.c> 의 <name> 을 저장해 놓는다.
                      STR_Assign(tempStr, tree->items[i].name);

                  //}

              //}

            }
            else if(tree->items[i].level == (tree->items[nodeIndex].level + 2))
            {
              //<*.h> 문서인 경우.

              //[방법]{---------------------------------------------------------------
              //"c.x" 부분은 이미 tempStr 에 들어 있으므로 이를 바탕으로 "c.x.h.y" 로
              //<name> 을 만들어 준다.
              //}---------------------------------------------------------------------

              //"c.x" 부분을 먼저 기록해 준다.
              STR_Assign(tree->items[i].name, tempStr);

              STR_Add(tree->items[i].name, ".h.");

              //[번호얻기]
              //{
                  CONV_LongVal_To_Hex2(y, hexStr);
                  STR_Add(tree->items[i].name, hexStr);

              //}

              y++;

            }

          }

      //}

  //}

  lbEnd:

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

  //}

  return(yes);

}

bool __fastcall Ide_Project_Get_TotalFileSize(int  *rSize,
                                              //처리한 문서 개수(중복되지 않은 순수 문서 개수, NULL 이면 미사용).
                                              int  *rCount)
{
  //[2019.02.23.토][생성]{----------------------------------------------------
  //[설계묶음:설계문서] 에 등록된 모든 문서<c/h> 의 [크기]  를 합산해서 반환.
  //
  //<find_DialogBox_Form::_TreeFind_All()> 를 사용해서 만든다.
  //[전체찾기] 지원을 위한것.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      class    DATABASE  *DB_;

      struct   TREE      *treeGprj;
      
      struct   STRHEAP    strHeap;
      
      int      fileSize = 0;
      
      int      fileTotalSize = 0;
      
      char     fileStr[1024*10];

      char     filePathNameExt[1024*10];

      int      nodeIndex, nodeLastItemIndex;

      int      i;

      int      docCount = 0;
      
  //}

  //[<*.gprj> 가 존재하는가?]
  //{
      //[!]{---------------------------------------------------------
      //현재 "새설계묶음" 인 경우는 대상이 없으므로 처리하지 않는다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}------------------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      { 
        //처리 대상 문서가 하나도 없으므로 <0> 반환.
        return(0);

      }

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&DB_);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      treeGprj = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[STRHEAP:생성]
  //{
      //[!]{----------------------------------------------
      //[STRHEAP] 은 사용전 반드시 한번 초기화 해야 한다.
      //}-------------------------------------------------

      STRHEAP_Init(&strHeap);

      //일단 기본 크기로 생성.
      STRHEAP_Create(&strHeap, d_STRHEAP_Heap_addSize, d_STRHEAP_List_addSize);

  //}

  //[<설계문서> 옹이 정보 얻기]
  //{
      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(treeGprj, "c", &nodeIndex, NULL, &nodeLastItemIndex);

  //}
 
  //[문서 검색 처리]
  //{
      //[!]{--------------------------------------------------------------------------
      //각 항목마다 문서를 순서대로 등록한다.
      //이 [STRHEAP] 에 [등록] 된 [문자열] 이 겹치는 것은 [이미 처리한 문서] 로 간주.
      //}-----------------------------------------------------------------------------

      //[설계문서] 에 등록된 모든 문서를 대상으로 처리.
      for(i = nodeIndex + 1, docCount = 0, fileTotalSize = 0;
          i <= nodeLastItemIndex;
          i++)
      {
        //[문서이름 얻기]
        //{
            STR_Assign(fileStr, tree_tree_Form->_Item_Txt_StrPtr3(treeGprj, i));

        //}

        //[<전체:경로이름확장자> 로 합성]
        //{
            STR_Add_AB(filePathNameExt, DB_->projectpath, fileStr);

        //}
        
        //[!]{-----------------------------------------------------------------------------
        //<fileStr>         : 원본 문서이름(STRHEAP 에 등록할 문서이름).
        //                    중복 검사시 처리 시간을 줄이기 위하여 보다 짧은 이름을 사용.
        //<filePathNameExt> : 실제 [문서] 를 열어서 처리할때 사용할 [경로이름확장자].
        //}--------------------------------------------------------------------------------

        //[문서 등록]
        //{
            //[!]{------------------------------------------------------
            //단지 [중복검사] 를 위해서 등록하는 것으로 큰 의미는 없다.
            //}---------------------------------------------------------

            //[중복] 되는 것이 있다면 [등록] 하지 않고 계속 검사.
            if(STRHEAP_Str_Search(&strHeap, false, fileStr) >= 0) continue;

            //[문서] 등록.
            STRHEAP_Str_Add(&strHeap, fileStr);
            
            //[문서 개수 수정]
            //{
                docCount++;
            
            //}
            
        //}

        //[문서 크기 얻기]
        //{
            if(FILE_Size(filePathNameExt, &fileSize) != true) goto lbFalse;
            
            //[전체 문서 크기 합산]
            //{
                fileTotalSize += fileSize;

            //}

        //}
        
      }

  //}
  
  //[처리 정보 반환]
  //{
      if(rSize  != NULL) (*rSize)  = fileTotalSize;

      if(rCount != NULL) (*rCount) = docCount;
  
  //}
  
  lbTrue:
  //{
      //[STRHEAP:삭제]
      //{
          //[2019.02.22.금][추가]
          STRHEAP_Delete(&strHeap);

      //}
      
      return(true);
  
  //}
  
  lbFalse:
  //{
      //[STRHEAP:삭제]
      //{
          //[2019.02.22.금][추가]
          STRHEAP_Delete(&strHeap);

      //}
      
      return(false);
  
  //}
  
}

bool __fastcall IDE_Project_Add_Glib(char  *pFileName)
{
  //[2009.01.29.목][생성!!!]{------------------------------------------------------------
  //[함수묶음] [옹이] 의 항목에 <*.glib> 를 추가하고 동시에 해당 <*.h> 도 같이 추가한다.
  //이는 참고적인 의미로 반드시 두개가 짝을 이루어 사용되므로 반드시 같이 등록해야 한다.
  //단, <*.h> 는 <*.glib> 항목을 [옹이] 로 하위 항목으로 등록해야 한다.
  //<*.h> 는 직접 추가 되는 것이 아니라 자동으로 추가 된다.
  //모든 작업은 <*.gprj> 를 기준으로 관리 되어야 하므로 현재 <*.gprj> 가 위치한
  //[폴더] 안에 있는 문서만 된다.
  //
  //[2009.01.31.토][추가!!!]-------------------------------------------------------------
  //"새설계묶음" 인 경우는 아무것도 추가할수 없다.
  //아직 담을 그릇이 없는 것과 같으므로.
  //
  //[2011.05.07.토][중요수정!!!]---------------------------------------------------------
  //[함수묶음] 에 포함되는 <*glib> 가 너무 많은 경우는 서로 구분이 안되고, 원하는 것을
  //찾기가 너무 힘들게 되므로, 아예 <Tree> 상의 구조를 API 와 같이 그대로 표시하는것으로
  //수정한다.
  //
  //부가적으로 <*.gprj> 문서 저장/열기 등 관련 부분을 전부 수정해 주어야 한다.
  //
  //[항목추가] 부분을 <Ide_Project_Add_Glib_Tree()> 함수를 사용한 방법으로 수정하였다.
  //결과적으로 한눈에 [경로] 를 알수 있으므로 깔끔하고 가독성이 좋게 개선되었다.
  //}------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];
      char  hexStr[OPT_wordStrSize];

      int   nodeItemIndex;
      int   tempVal;

      //[tree 관련]
      //{
          //<*.glib> 함목을 저장.
          struct TREEITEM  item;

          //<*.h> 항목을 저장.
          struct TREEITEM  itemHeader;

          //초기화 한다.
          tree_tree_Form->_Item_Init(&item);

      //}

      //[2009.10.04.일][추가!!!]
      char    itemTxt[OPT_lineStrSize];

  //}

  //[<*.gprj> 가 존재하는가?]
  //{
      //[2009.01.31.토][추가!!!]{--------------------
      //현재 "새설계묶음" 인 경우는 추가하지 않는다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}--------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        //비어있는 상태이므로 아무것도 추가 할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 항목을 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        return(false);

      }

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[<*.glib> 문서 열기]
  //{
      if(pFileName == NULL)
      {
        //[확장자 설정]
        //{
            //[함수묶음] 은 <*.glib> 만을 대상으로 한다.
            main_Form->file_OpenDialog->Filter = "*.glib|*.glib";

        //}

        //[문서 열기 대화상자] 보여주기.
        if(main_Form->file_OpenDialog->Execute() != true) return(false);

		STR_Assign(fileName, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

      }
      else
      {
        //<fileName> 으로 문서를 열게 되므로 일단 여기에 다시 할당한다.
        STR_Assign(fileName, pFileName);

      }

      //[<*.glib> 인지 확인]
      //{
          STR_GetFileExt(fileName, tempStr);

          if(STR_Match_NoCase(tempStr, "glib") != true)
          {
            //확장자가 [함수묶음] 에 해당하지 않으므로 추가할수 없다.

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.glib> 문서만 추가할수 있습니다.");

            return(false);

          }

      //}

  //}

  //[경로 확인]
  //{
      //현재 [문서] 가 <*.gprj> 가 위치한 [폴더] 안에 있는지 확인한다.

      if(STR_BaseDirectory_Match(database->projectpath, fileName) != true)
      {
        //<*.gprj> 가 있는 폴더 안에 존재하지 않으므로 추가할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 가 위치한 [폴더] 안의 문서만 추가할수 있습니다.");

        return(false);

      }

  //}

  //[<*.h> 가 존재하는가?]
  //{
      //<*.glib> 에 해당하는 같은 이름의 <*.h> 가 같은 위치에 실제 존재하는지 확인한다.

      STR_ChangeFileExt(fileName, "h", tempStr);

      if(FileExists(tempStr) != true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.glib> 와 같은 이름의 <*.h> 가 동일한 위치에 있어야 합니다.");

        return(false);

      }

  //}

  //[항목 추가]
  //{
      if(Ide_Project_Add_Glib_Tree(fileName) != true) return(false);

  //}

  //[표시]
  //{
      if(pFileName == NULL)
      {
        //tree 를 한번 그려준다.
        tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

      }

  //}

  return(true);

}

bool __fastcall Ide_Project_Add_Glib_Tree(//<*.glib> 전체 경로를 전받 받는다.
                                          char  *pGlibFileName)
{
  //[2011.05.07.금][생성!!!]{------------------------------------------------------------
  //<*.glib> 전체 경로를 전달 받아서 [함수묶음] 에 등록해 준다.
  //단, [Tree:API] 처럼 정확한 [Tree 구조] 로 등록해 준다.
  //
  //[폴더이름] : 옹이가 된다.
  //[문서이름] : 항목이 된다.
  //
  //[주의!!!]----------------------------------------------------------------------------
  //이 함수는 <Ide_Project_Add_Glib()> 함수에서 호출된다.
  //대부분 오류점검이 된 상태에서 단지 [함수묶음] 에 [등록] 을 위한 목적으로만 사용된다.
  //
  //1) <*.glib> 가 이미 [설계묶음] 경로안에 존재할것.
  //2) <*.glib> 에 해당하는 <*.h> 가 같은 위치에 존재할것.
  //
  //이 이미 만족된 상태로 보고 처리한다.
  //
  //[<name> 생성]------------------------------------------------------------------------
  //1) 일단, [Tree] 상의 [절대위치] 를 바탕으로 생성한다.
  //2) 항목이 추가되는 경우는, 이 항목 다음의 모든 항목의 <name> 을 다시 만든다.
  //   이는 [우연히] 라도 <name> 이 겹치는 것을 막기 위한 것이다.
  //}------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];

      char  tempWord[OPT_lineStrSize];
      char  tempExt[OPT_wordStrSize];

      char  hexStr[OPT_wordStrSize];

      int   nodeIndex;
      int   itemIndex;

      int   tempVal;

      //[tree 관련]
      //{
          //<*.glib> 함목을 저장.
          struct TREEITEM  item;

      //}

      //[2009.10.04.일][추가!!!]
      char    itemTxt[OPT_lineStrSize];

      //[2011.05.07.금][추가!!!]
      int  i;

  //}


  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------


  //[<*.glib> 항목 추가]
  //{
      //[!]{-------------------------------------------------------
      //각각의 [폴더이름] 은 [옹이] 가 되므로
      //
      //1) [폴더이름] 을 '\' 문자를 기준으로 [단어 단위] 로 추출.
      //2) 이미 해당 [옹이] 가 만들어져 있는 경우는 이 아래에 추가
      //
      //[폴더이름] 순으로 한개의 [경로] 를 모두 처리하면 된다.
      //}----------------------------------------------------------

      //[설계묶음 경로 제거]
      //{
          //순수한 <*.gprj> 존재하는 폴더 안의 경로만 추출한다.
          STR_GetFileName_Except_BaseDirectory(database->projectpath, pGlibFileName, tempStr);

      //}

      //[<함수묶음> 옹이 위치 얻기]
      //{
          //[!]{-------------------------------------------------
          //[함수묶음] [옹이] 의 절대위치를 얻는다.
          //이는 이 [옹이] 가 처리의 가장 기본위치이기 때문이다.
          //}----------------------------------------------------

          tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "glib", &nodeIndex);

      //}

      for(i = 0; ; i++)
      {
        //[단어 추출]
        //{
            STR_GetWord(tempStr, '\\', i, tempWord);

            //[한개 문서 완료 인가?]
            //{
                //[단어] 가 "" 이라면 현재 [문서] 한개의 처리가 끝난 것이다.
                if(tempWord[0] == '\0') break;

            //}

        //}

        //[<폴더이름/문서이름> 인지 구분]
        //{
            //[확장자] 있는 경우는 [문서이름] 이고 없는 경우는 [폴더이름] 이다.
            //[폴더이름] 은 [옹이] 가, [문서이름] 은 [항목] 이 된다.
            //이는 [폴더:옹이] 와 [*.glib:항목] 을 조기 구분하기 위한 것이다.
            STR_GetFileExt(tempWord, tempExt);

            //[확장자] 가 없는 경우는 [옹이] 처리부로 이동한다.
            if(tempExt[0] == '\0') goto lbNode;
            //[확장자] 가 있는 경우는 [항목] 처리부로 이동한다.
            else                   goto lbItem;

        //}

        lbNode:
        //{
            //[중복 검사]
            //{
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인한다.
                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사한다.
                                 tree->items[nodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않는다.
                                 false,
                                 //이 [옹이] 의 item-index.
                                 NULL,
                                 //<text> 를 가진 itemindex.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-----------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가한다.
              //}--------------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] index 가 된다.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[nodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[nodeIndex].name); //지금 [옹이] 의 <name>
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{----------------------------------------
                  //현재 추출한 [단어] 를 그대로 사용하면 된다.
                  //}-------------------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);

              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지] 가 된다.
                  item.kind = '.';

                  //최종 [항목] 을 제외하고는 전부 [경로] 에 해당하므로 [폴더] 로 지정한다.
                  item.bmpindex = d_ITEMBMP_folder;

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[nodeIndex].name,
                                                     &item,
                                                     NULL);

              //}

              //[다음 [옹이] 위치 지정]
              //{
                  //현재 추가된 [가지] 는 [경로 구조] 상 다음 항목의 [옹이] 가 된다.
                  tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, item.name, &nodeIndex);

              //}

            }
            else
            {
              //이미 존재하는 것으로 무시한다.
              //이 경우는 현재 <항목> 이 다음 항목의 [옹이] 가 된다.

              nodeIndex = itemIndex;

            }

            continue;

        //}

        lbItem:
        //{
            //[중복 검사]
            //{
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인한다.
                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사한다.
                                 tree->items[nodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않는다.
                                 false,
                                 //이 [옹이] 의 item-index.
                                 NULL,
                                 //<text> 를 가진 itemindex.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-----------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가한다.
              //}--------------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] index 가 된다.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[nodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[nodeIndex].name); //지금 [옹이] 의 <name>
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{----------------------------------------
                  //현재 추출한 [단어] 를 그대로 사용하면 된다.
                  //}-------------------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);

              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지] 가 된다.
                  item.kind = '.';

                  //최종 [항목] 은 [API] 가 된다.
                  item.bmpindex = d_ITEMBMP_api;

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[nodeIndex].name,
                                                     &item,
                                                     //추가된 <*.glib> 의 [절대위치] 를 얻는다.
                                                     //이는 아래의 <*.h> 를 추가하는데 <nodeIndex> 정보가 된다.
                                                     &itemIndex);

              //}


              //[<*.h> 문서 등록]
              //{
                  //[!]{----------------------------------------------------------------
                  //<*.glib> 는 항상 같은 이름의 <*.h> 문서와 같이 있으므로 이 <*.h> 를
                  //<*.glib> 에 [직계가지] 로 등록해 주어야 한다.
                  //이미 이 함수가 호출되었을때 <*.h> 의 존재는 확인되었으므로 간단하게
                  //[항목] 을 만들어 등록하면 된다.
                  //}-------------------------------------------------------------------

                  //[<*.glib> 절대 위치 얻기]
                  //{
                      //바로 위에서 구한 <*.glib> 추가 위치가 <*.h> 의 [옹이] 가 된다.
                      nodeIndex = itemIndex;

                  //}

                  //[항목 초기화][2012.04.18.수]{-------------------------------------
                  //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                  tree_tree_Form->_Item_Init(&item);
                  //}-----------------------------------------------------------------

                  //[<name> 만들기]
                  //{
                      //"[옹이이름].[번호]" 형식으로 만든다.
                      STR_Assign(item.name, tree->items[nodeIndex].name); //지금 [옹이] 의 <name>
                      STR_Add(item.name, ".");
                      //<*.glib> 와는 1:1 대응으로 항상 <*.glib> 를 [옹이] 로 0번째 [가지] 가 된다.
                      CONV_LongVal_To_Hex2(0, hexStr);
                      STR_Add(item.name, hexStr);

                  //}

                  //[<text> 만들기]
                  //{
                      //[!]{----------------------------------------------------
                      //현재 추출한 [단어] 의 [확장자] 만 <*.h> 로 바꾸면 된다.
                      //}-------------------------------------------------------

                      //[확장자] 를 바꾼다.
                      STR_ChangeFileExt(tempWord, "h", tempStr);

                      //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                      //[2012.04.20.금][수정!!!]
                      tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                                &item,
                                                tempStr);

                  //}

                  //[기타 설정]
                  //{
                      //추가되는 것은 기본적으로 [가지] 가 된다.
                      item.kind = '.';

                      //최종 [항목] 은 [*.h] 가 된다.
                      item.bmpindex = d_ITEMBMP_file_h;

                  //}

                  //[추가]
                  //{
                      //현재 [옹이] 위치의 [직계가지] 로 추가한다.
                      tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                         tree->items[nodeIndex].name,
                                                         &item,
                                                         NULL);

                  //}

              //}

            }
            else
            {
              //[!]{----------------------------------------------------
              //[옹이] 는 중복 될수 있으나, 항목은 중복되어서는 안된다.
              //이미 추가된 것임을 알려준다.
              //}-------------------------------------------------------

              ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "이미 존재하는 문서입니다.");

              return(false);

            }

            continue;

        //}

      }

  //}

  return(true);

}

int __fastcall IDE_Project_Delete_Glib(void)
{
  //[2009.02.02.월][생성!!!]{-------------------------------------------------------
  //[함수묶음] 에 추가된 <*.glib> 를 삭제 한다.
  //단, [직계가지] 인 <*.glib> 만 대상으로 하고 하위 항목으로 자동 등록되는
  //<*.h> 는 대상으로 하지 않는다.
  //즉, <*.glib> 가 삭제 되는 경우는 무조건 하위에 등록되 있는 <*.h> 로 같이
  //삭제해 주어야 한다(tree_tree_Form->_Tree_Delete_Item() 함수에서 자동 처리).
  //
  //[2011.05.07.토][중요수정!!!]----------------------------------------------------
  //[Tree:함수묶음] 을 기존의 [경로방식] 에서, 완전한 [Tree 구조] 로 수정하였으므로
  //역시 [삭제] 도 같이 수정해 주어야 한다.
  //[경로] 의 [폴더이름] 이 하나의 [옹이] 가 되므로 [항목] 까지 모든 <txt> 를
  //결합하면 [전체 경로] 가 완성된다.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      int     nodeIndex;
      int     nodeLastItemIndex;

      char    tempStr[OPT_wordStrSize];
      char    hexStr[OPT_wordStrSize];

      int     i;
      int     x, y;

      //[2011.05.08.일][추가!!!]
      int     delItemIndex;
      int     itemCount;

      //[2011.05.10.화][추가!!!]
      int     itemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree_tree_Form->_tree[d_TREE_project].select_itemindex < 0) return(no);

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[범위 확인]
  //{
      //[함수묶음] [옹이] 에 등록된 것이 맞는지 먼저 확인한다.

      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "glib", &nodeIndex, NULL, &nodeLastItemIndex);

      //[2011.05.10.화][중요수정!!!]{---------------------------------------------
      //[삭제] 의 경우 [Tree:함수묶음] 로 일단 대상이 되므로 이것도 포함 시킨다.
      //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
      //즉, [Tree:함수묶음] 을 완전히 비워주는 기능이다.
      //}-------------------------------------------------------------------------
      //---------------v
      if(!((nodeIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex)))
      {
        //[함수묶음] [범위] 에 해당하지 않으므로 이 함수처리 대상이 아니다.

        return(no);

      }

  //}

  //[<삭제> 가능한 문서 인가?]
  //{
      //[2011.05.10.화][중요수정!!!]{-----------------------------------------------------
      //<*.h> 를 제외하고는 [Tree:함수묶음], [옹이], <*.glib> 모두 [삭제] 의 대상이되므로
      //<*.h> 만 걸러내는 부분으로 수정한다.
      //}---------------------------------------------------------------------------------

      //[방법]{------------------------------------------------------------------------------
      //[함수묶음] 에서는 반드시 [직계가지] 에 해당하는 <*.glib> 만 삭제 가능하다.
      //<*.glib> 에 등록되 있는 <*.h> 는 직접 삭제 할수 없다.
      //
      //1) 간단하게 [직계가지] 인지 확인하기만 하면 된다.
      //
      //[2011.05.08.일][중요수정!!!]---------------------------------------------------------
      //<*.glib> 만 삭제가능 하며, 이제는 [항목] 의 경우는 [확장자] 까지 <txt> 에 저장하므로
      //간단하게 [확장자] 만 검사하면 된다.
      //즉, [확장자] 가 <*.glib> 인 [항목] 만 [삭제] 가능한 대상이 된다.
      //
      //이전의 위의 방법은 [확장자] 없이 [이름] 만 기록했을때의 방법으로, 새롭게 만들어진
      //[Tree 구조] 인 [함수묶음] 에서는 사용할수 없는 방법이다.
      //
      //[2011.05.10.화][수정!!!]-------------------------------------------------------------
      //전부다 삭제 대상이 되고, 단지 <*.h> 만 대상이 되지 않으므로 이것만 확인한다.
      //}------------------------------------------------------------------------------------

      //[현재 항목의 [확장자] 가 <*.h> 인가?]
      //{
          //[확장자 추출]
          //{
              //[2012.04.20.금][수정!!!]
              STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, tree->select_itemindex), tempStr);

          //}

          if(STR_Match_NoCase(tempStr, "h") == true)
          {
            //<*.h> 는 삭제 할수 없다.
            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "<*.h> 문서는 삭제 대상이 아닙니다.\r\n"
                                     "<*.glib> 문서에 등록된 하위 문서는 자동으로 추가 되는 정보이며\r\n"
                                     "<*.glib> 문서가 삭제 될때 자동으로 같이 삭제 됩니다."
                                    );

            //삭제 할수 없는 [항목] 이다.
            return(error);

          }

      //}

  //}

  //[항목 삭제]
  //{
      //[2011.05.08.일][중요수정!!!]{-------------------------------------------------------
      //이전과 달리 [함수묶음] 부분이 [Tree 구조] 로 표시되므로, 만일 [항목] 을 삭제한뒤
      //이 항목이 등록돼 있던 [옹이] 에 [항목] 이 아무것도 없는 경우는 이 [옹이] 도 전부
      //삭제해 주어야 한다.
      //
      //1) 먼저 해당 [항목] 을 삭제한다.
      //
      //2) 거꾸로 [옹이] 를 거슬러 올라가면서 [하위항목] 이 하나도 없는 [옹이] 를 삭제한다.
      //
      //단, [함수묶음<name:"glib">] 자체 [옹이] 는 항상 존재해야 하므로 <name> 확인후
      //<name:"glib"> 인 [옹이] 이전까지만 처리해야 한다.
      //
      //[2011.05.10.화][중요수정!!!]--------------------------------------------------------
      //이전과 달리, [Tree:함수묶음], [옹이] 도 삭제 대상이 된다.
      //이는 다수의 <*.glib> 를 추가한 경우 일일히 삭제하는것이 너무 번거롭기 때문이다.
      //
      //[Tree:함수묶음] : 모든 하위 항목을 삭제하나 자신을 남겨둔다(<Tree 제목> 이므로).
      //[옹이]          : 자신을 삭제하고 후처리를 수행한다.
      //<*.glib>        : 자신을 삭제하고 추처리를 수행한다.
      //<*.h>           : 삭제 대상이 아니다.
      //}-----------------------------------------------------------------------------------

      //[초기화]
      //{
          //기본적인 삭제 위치는 현재 [선택된 항목] 이다.
          delItemIndex = tree->select_itemindex;

      //}

      //[삭제]
      //{
          //[!]{-------------------------------------------------------------------
          //[Tree:함수묶음] 인 경우와 다른 항목의 경우를 구분하여 처리해야 한다.
          //<*.h> 의 경우는 이미 위에서 [삭제 대상이 아닌 것] 으로 막아 놓았으므로
          //여기서는 고려하지 않는다.
          //}----------------------------------------------------------------------

          if(STR_Match(tree->items[delItemIndex].name, "glib") == true)
          {
            //[!]{---------------------------------------------------------------------
            //이 경우는 [삭제 대상] 이 [Tree:함수묶음] 인 경우다.
            //
            //[직계가지] 를 하나씩 삭제해 주기만 하면 된다.
            //
            //아예 내부 항목이 다 없어지는 것이므로 [<name> 재생성] 을 할 필요도 없다.
            //}------------------------------------------------------------------------

            //[<Tree:함수묶음> 직계가지 수 얻기]
            //{
                tree_tree_Form->_Tree_Get_Node_ItemCount2
                                  (tree,
                                   //지정 [옹이] 의 [절대위치].
                                   delItemIndex,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

            //}

            for(i = 0,
                //현재 옹이 다음부터 검사한다.
                itemIndex = delItemIndex + 1;
                //[직계가지] 개수 만큼 삭제한다.
                i < itemCount;
                i++)
            {
              //[직계가지] 는 현재 <[옹이].level> 보다 <+1> 된 값을 갖는다.
              if((tree->items[delItemIndex].level + 1) == tree->items[itemIndex].level)
              {
                //[직계가지] 에 해당하므로 [삭제] 한다(모든 하위 항목도 자동 삭제된다).
                tree_tree_Form->_Tree_Delete_Item(tree, itemIndex);

                //현재 항목이 삭제 되었으므로 [현재 위치] 부터 계속 검사 처리한다.

              }
              else
              {
                //다음 위치로 이동한다.
                itemIndex++;

              }

            }

            //마무리 부분으로 이동한다.
            goto lbEnd;

          }

          //[!]{------------------------------------------------------
          //여기 까지 온것은 [옹이], <*.glib> 를 [삭제]  하는 경우다.
          //}---------------------------------------------------------

          lbItemDel:

          //[<옹이> 정보 얻기]
          //{
              //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 를 구한다.
              tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                              (tree,
                               //현재 삭제(선택된것) 할 항목의 [절대위치].
                               delItemIndex,
                               //직계 [옹이] 의 [절대위치].
                               &nodeIndex);

          //}

          //[항목 삭제]
          //{
              //현재 선택된 것을 삭제 한다.
              tree_tree_Form->_Tree_Delete_Item(tree, delItemIndex);

          //}

          //[직계 [옹이] 가 [함수묶음] 제목인가?]
          //{
              //[!]{-------------------------------------------------------------
              //현재 삭제된 [항목] 의 [직계옹이] 가 [Tree 구조] 상 [제목항목] 인
              //[함수묶음] 인 경우는 삭제해서는 안되므로 더이상 처리하지 않는다.
              //이 경우는 <name:"glib"> 로 쉽게 구분할수 있다.
              //}----------------------------------------------------------------

              if(STR_Match(tree->items[nodeIndex].name, "glib") == true) goto lbItemDelEnd;

          //}

          //[<옹이> 가 비었나?]
          //{
              //[!]{----------------------------------------------------------------------
              //이 항목을 가지는 [옹이] 를 거꾸로 거슬러 올라가면서, 비어있는 [옹이] 라면
              //역시 전부 삭제해야 한다.
              //}-------------------------------------------------------------------------

              //[<옹이> 의 [직계가지] 수 얻기]
              //{
                  tree_tree_Form->_Tree_Get_Node_ItemCount
                                  (tree,
                                   //지정 [옹이] 의 [이름].
                                   tree->items[nodeIndex].name,
                                   NULL,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

              //}

              if(itemCount == 0)
              {
                //[!]{--------------------------------------------------------
                //이 경우는 현재 [항목] 의 삭제로 직계 [옹이] 가 텅빈것이므로
                //이 [옹이] 도 역시 삭제해 주어야 한다.
                //}-----------------------------------------------------------

                //[삭제 위치 지정]{-----------------------------------
                //현재 이 [옹이] 위치가 삭제할 [항목] 의 위치가 된다.
                delItemIndex = nodeIndex;
                //}---------------------------------------------------

                goto lbItemDel;

              }

          //}

          lbItemDelEnd:

      //}

      //[<name> 재생성]
      //{
          //[방법]{-----------------------------------------------------------------------------------
          //각각의 항목의 <name> 을 다시 index 순번으로 만들어 주어야 한다.
          //이는 계속 [생성/삭제] 를 반복하는 경우 우연히 <name> 이 겹치는 것을 방지하기 위한 것이다.
          //
          //<*.glib>.name = "glib.x"
          //<*.h>.name = "glib.x.h.y"
          //
          //[2011.05.08.일][중요수정!!!]--------------------------------------------------------------
          //[함수묶음] 항목의 표시가 [Tree 구조] 로 변경되었으며, <name> 의 형식이 변경되었으므로
          //새로운 방식으로 전부 다시 생성해 준다.
          //
          // <name> = [옹이의 <name>].[옹이에 등록된 순번]
          //
          //으로 생성한다.
          //
          //가장 마지막에 [삭제] 된 항목의 [직계옹이] 에 해당하는 [모든 하위 항목] 을 대상으로 한다.
          //
          //모든 하위 항목을 전부 처리하는데 있어 [동일한 형식] 이 되므로 아예 [전용함수] 의
          //[재귀호출] 로 처리한다.
          //}-----------------------------------------------------------------------------------------

          //[!]{--------------------------------------------------------------------
          //원래는 [최종 삭제된 위치] 부터 처리해야 하지만, [Tree 구조] 가 복잡하고
          //[옹이] 단위로 처리하는 것이 [재귀호출] 로 일괄 처리 하기 좋으므로
          //[최종 삭제된 항목] 을 가지는 [옹이] 를 넘겨준다.
          //}-----------------------------------------------------------------------

          Ide_Project_Delete_Glib_ReName(tree, nodeIndex);

      //}

  //}

  lbEnd:

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

  //}

  return(yes);

}

void __fastcall Ide_Project_Delete_Glib_ReName(struct TREE  *pTree,
                                               //처리할 [옹이] 의 [절대위치].
                                               int           pNodeIndex)
{
  //[2011.05.08.일][생성!!!]{-------------------------------------------------
  //<IDE_Project_Delete_Glib()> 함수에서 <*.glib> 항목이 [삭제] 된경우
  //[함수묶음] 한의 모든 항목의 <name> 을 겹치지 않게 재 생성해준다.
  //
  //1) [옹이] 의 정보를 추출.
  //2) [직계가지] 의 <name> 을 새로 만든다.
  //
  //이 함수는 [직계가지] 만을 대상으로 하고, [직계가지] 자체가 다시 [옹이] 가
  //되는 경우는 이 함수를 [재귀호출] 하여 처리한다.
  //
  //<name> = [옹이의 <name>].[직계가지순번]
  //
  //으로 설정된다.
  //이는 절대로 서로 <name> 이 겹치지 않도록 하기 위함이다.
  //
  //[주의!!!]-----------------------------------------------------------------
  //이 함수는 <IDE_Project_Delete_Glib()> 만을 대상으로 하며, 반드시
  //[함수묶음<name:"glib">] 내부만을 대상으로 처리해야 한다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      int     nodeEndItemIndex;
      int     nodeLastItemIndex;

      int     nodeLevel;

      int     itemCount;

      char    tempStr[OPT_lineStrSize];
      char    hexStr[OPT_wordStrSize];

      int     i, count;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[<옹이> 정보 얻기]
  //{
      //현재 [옹이] 의 [하위항목] 관련 정보를 수집한다.
      tree_tree_Form->_Tree_Get_Node_LastItemIndex
                      (pTree,
                       //지정 [옹이] 의 index.
                       pNodeIndex,
                       //가장 마지막 [직계가지] 의 [절대위치].
                       &nodeEndItemIndex,
                       //이 [옹이] 의 가장 마지막 항목의 [절대위치].
                       &nodeLastItemIndex);

      //현재 [옹이] 의 [직계가지] 수를 얻는다.
      tree_tree_Form->_Tree_Get_Node_ItemCount2
                      (pTree,
                       //지정 [옹이] 의 [절대위치].
                       pNodeIndex,
                       //지정 [옹이] 의 직계 가지 수.
                       &itemCount);

      //현재 [옹이] 의 <level> 정보를 얻는다.
      nodeLevel = pTree->items[pNodeIndex].level;

  //}

//[검증]{----------------------------------------------------
//msg_msg_Form->_PrintAddLine(0, "[옹이]");
//msg_msg_Form->_PrintAddLine(0, "txt:");
//msg_msg_Form->_PrintAdd(0, pTree->items[pNodeIndex].txt);
//msg_msg_Form->_PrintAdd(0, " / name:");
//msg_msg_Form->_PrintAdd(0, pTree->items[pNodeIndex].name);
//}----------------------------------------------------------

  //[<직계가지> 의 <name> 재설정]
  //{
      //[!]{------------------------------------------------------------
      //이 [옹이] 에 포함돼 있는 [직계가지] 의 <name> 을 다시 설정한다.
      //단, 이 [직계가지] 가 다시 [옹이] 인 경우는, 다시 이 함수를
      //[재귀호출] 하여 처리해 준다.
      //}---------------------------------------------------------------

      for(//[옹이] 다음 위치 부터 [직계가지] 가 시작된다.
          i = (pNodeIndex + 1),
          //처음에는 처리한 [직계가지] 수는 0 이다.
          count = 0;
          //[옹이] 가 가진 하위가지 전체 까지 검사한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //[!]{---------------------------------------------------------------------------------
        //[직계가지] 만을 대상으로 하며, [직계가지] 는 [옹이<level> + 1] 의 <level> 을 갖는다.
        //}------------------------------------------------------------------------------------

        if     (pTree->items[i].level == (nodeLevel + 1))
        {
          //[!]{--------------------------------------------------------------
          //이 경우는 [직계가지] 에 해당하는 것이다.
          //
          //1) [직계가지] 의 <name> 을 새로 만든다.
          //
          //2) 이 [직계가지] 가 [옹이] 가 되는 경우는 [재귀호출] 로 처리한다.
          //}-----------------------------------------------------------------

          //[<name> 만들기]
          //{
              //[!]{-----------------------------
              //<name> = [옹이<name>].[직계번호]
              //}--------------------------------

              //[<name>]{-------------------------------------------------
              //[옹이] 의 <name> 이 기본이 된다.
              STR_Assign(tempStr, pTree->items[pNodeIndex].name);
              STR_Add(tempStr, ".");

              //[직계가지] 순번을 16진수 최소표기로 변환한다.
              CONV_LongVal_To_Hex2(count, hexStr);

              //함성하여 <name> 에 바로 할당한다.
              STR_Add_AB(pTree->items[i].name, tempStr, hexStr);
              //}---------------------------------------------------------

              //일단 [직계가지] 한개는 처리한 것으로 기록한다.
              count++;

//[검증]{-------------------------------------------
//msg_msg_Form->_PrintAddLine(0, "txt:");
//msg_msg_Form->_PrintAdd(0, pTree->items[i].txt);
//msg_msg_Form->_PrintAdd(0, " / name:");
//msg_msg_Form->_PrintAdd(0, pTree->items[i].name);
//}-------------------------------------------------

          //}

          //[이 [직계가지] 가 [옹이] 인가?]
          //{
              //이 <가지> 에 하위 항목이 있는지 [하위 항목수] 를 얻는다.
              tree_tree_Form->_Tree_Get_Node_ItemCount2
                              (pTree,
                               //지금 [가지] 의 [절대위치].
                               i,
                               //지금 [가지] 의 [하위 항목] 수.
                               &itemCount);

              if(itemCount > 0)
              {
                //[!][----------------------------------------------------
                //이 경우는 지금 [가지] 가 [옹이] 가 되므로 [재귀호출] 로
                //다시 [하위 항목] 의 <name> 을 만들어준다.
                //}-------------------------------------------------------

                Ide_Project_Delete_Glib_ReName(pTree,
                                               //지금 이 [가지] 가 [옹이] 가 된다.
                                               i);

              }

          //}

        }

      }

  //}

}

void __fastcall Ide_Project_Glib_Make_InFileName(struct TREE  *pTree,
                                                 //<*.glib> 항목의 [절대위치].
                                                 int           pGlibItemIndex,
                                                 //합성된 [설계묶음] 내부 경로.
                                                 char         *rInFileName)
{
  //[2011.05.08.일][생성!!!]{-----------------------------------------------------------
  //<*.glib> [항목] 의 [절대위치] 를 넘겨 받아서, [설계묶음 내부 경로] 를 함성하여
  //반환한다.
  //
  //[함수묶음] 의 [Tree 구조] 자체가 원래 [설계묶음 내부 경로] 를 그대로 [Tree 구조] 로
  //만들어 놓은 것이므로 거꾸로 합성해 가면 간단하게 [경로] 를 만들수 있다.
  //즉, <txt> 속성을 전부 거꾸로 합성하면 [경로] 가 된다.
  //
  //[주의!!!]---------------------------------------------------------------------------
  //[전체 경로] 가 아니라, [설계묶음 내부 경로] 라는 것에 주의한다.
  //
  //<pGlibItemIndex> 위치에는 이미 <*.glib> 가 존재해야 한다.
  //
  //반드시, [Tree:함수묶음] 처리에만 사용해야 한다.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      char   tempStr[2][OPT_lineStrSize];

      //[문자열 위치 관리]{---------------------------------------------------------------------
      char  *inFileName, //합성결과 저장위치.
            *bfFileName; //이전 합성된 문자열 위치.
      char  *tempPtr;
      //inFileName = <txt> + "\\" + bfFileName;
      //형식으로 사용되므로 계속 두 [위치] 를 바꾸면 된다.
      //간단하게 [매크로] 로 만들어 사용한다.
      #define  m_StrPtrChange    tempPtr=inFileName; inFileName=bfFileName; bfFileName=tempPtr;
      //}---------------------------------------------------------------------------------------

      int    nodeIndex, itemIndex;

  //}

  //[경로 합성]
  //{
      //[초기화]
      //{
          itemIndex = pGlibItemIndex;

          //[문자열 위치 관리자]
          //{
              //같은 크기의 저장소 각각의 위치로 설정해 준다(저장소 순번은 무관).
              inFileName = tempStr[0];
              bfFileName = tempStr[1];

          //}

          //일단, 이 <*.glib> 항목의 <txt> 를 먼저 합성한다.
          //[2012.04.20.금][수정!!!]
          STR_Assign(inFileName, tree_tree_Form->_Item_Txt_StrPtr3(pTree, itemIndex));

          //[문자열 저장 위치 교환]{----------------------------------------------------------
          //거꾸로 합성하기 때문에 지금 <inFileName> 은 다음에는 <bfFileName> 이 되어야 한다.
          m_StrPtrChange;
          //}---------------------------------------------------------------------------------

      //}

      lbInFileNameMake:
      {
        //[<옹이> 찾기]
        //{
            //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 를 구한다.
            tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                            (pTree,
                             //현재 삭제(선택된것) 할 항목의 [절대위치].
                             itemIndex,
                             //직계 [옹이] 의 [절대위치].
                             &nodeIndex);

        //}

        //[내부경로 끝인가?]
        //{
            //[!]{---------------------------------------------------------------------
            //위에서 찾은 [옹이] 가 [경로끝] 인 [Tree:함수묶음<name:"glib">] 인 경우는
            //모든 [문서이름] 합성이 완료된 것이다.
            //}------------------------------------------------------------------------

            if(STR_Match(pTree->items[nodeIndex].name, "glib") == true) goto lbInFileNameMakeEnd;

        //}

        //[경로합성]
        //{
            //[!]{------------------------------------
            //inFileName = <txt> + "\\" + bfFileName;
            //
            //형식으로 합성해 준다.
            //}---------------------------------------

            STR_Add_AB(inFileName, "\\", bfFileName); m_StrPtrChange;

            //[2012.04.20.금][수정!!!]
            STR_Add_AB(inFileName, tree_tree_Form->_Item_Txt_StrPtr3(pTree, nodeIndex), bfFileName); m_StrPtrChange;

        //}

        //지금 합성한 [옹이] 가 다음 검사시 [직계가지] 항목이 된다.
        itemIndex = nodeIndex;

        //계속 처리한다.
        goto lbInFileNameMake;

      }
      lbInFileNameMakeEnd:

      //[후처리]
      //{
          //[!]{------------------------------------------------------------------------------------
          //처리 완료 상태에서는 <m_StrPtrChange> 로 <bfFileName> 에 [합성] 된 결과가 들어 있으므로
          //기준이 되는 <inFileName> 에 다시 결과 문자열 위치를 넘져준다.
          //큰 의미는 없으나, [변수이름] 을 직관적으로 사용하기 위한 것이다.
          //}---------------------------------------------------------------------------------------

          inFileName = bfFileName;

      //}

  //}

  //[합성된 경로 반환]
  //{
      //[!]{------------------------------------------
      //모두 합성된 [설계묶음 내부 경로] 를 반환한다.
      //}---------------------------------------------

      if(rInFileName != NULL) { STR_Assign(rInFileName, inFileName); }

  //}

//[검증]{-----------------------------------
//msg_msg_Form->_PrintAddLine(0, inFileName);
//}-----------------------------------------

}

void __fastcall IDE_Project_Add_Etc(char  *pFileName)
{
  //[2009.01.29.목][생성!!!]{---------------------------------------
  //[참고자료] [옹이] 의 항목에 <*.x> 를 추가한다.
  //단, 현재 <*.gprj> 가 위치한 폴더 안에 있는 문서만 된다.
  //모든 작업은 <*.gprj> 를 기준으로 관리 되어야 하므로.
  //어떤 문서인지 종류는 상관 없다(문서, 그림, *.pdf 등 상관 없음).
  //
  //[2009.01.31.토][추가!!!]----------------------------------------
  //"새설계묶음" 인 경우는 아무것도 추가할수 없다.
  //아직 담을 그릇이 없는 것과 같으므로.
  //}---------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];
      char  hexStr[OPT_wordStrSize];

      int   nodeItemIndex;
      int   tempVal;

      //[tree 관련]
      //{
          struct TREEITEM  item;

      //}

  //}

  //[<*.gprj> 가 존재하는가?]
  //{
      //[2009.01.31.토][추가!!!]{--------------------
      //현재 "새설계묶음" 인 경우는 추가하지 않는다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}--------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        //비어있는 상태이므로 아무것도 추가 할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 항목을 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        return;

      }

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[<*.*> 문서 열기]
  //{
      if(pFileName == NULL)
      {
        //[확장자 설정]
        //{
            //[설계문서] 는 모든 문서를 전부 대상으로 한다.
            main_Form->file_OpenDialog->Filter = "*.*|*.*";

        //}

        //[문서 열기 대화상자] 보여주기.
        if(main_Form->file_OpenDialog->Execute() != true) return;

		STR_Assign(fileName, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

      }
      else
      {
        STR_Assign(fileName, pFileName);

      }

  //}

  //[경로 확인]
  //{
      //현재 [문서] 가 <*.gprj> 가 위치한 [폴더] 안에 있는지 확인한다.

      if(STR_BaseDirectory_Match(database->projectpath, fileName) != true)
      {
        //<*.gprj> 가 있는 폴더 안에 존재하지 않으므로 추가할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "<*.gprj> 가 위치한 [폴더] 안의 문서만 추가할수 있습니다.");

        return;

      }

  //}

  //[항목 추가]
  //{
      //[항목 초기화][2012.04.18.수]{-------------------------------------
      //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
      tree_tree_Form->_Item_Init(&item);
      //}-----------------------------------------------------------------

      //[name 만들기]
      //{
          //[[옹이] 항목 수 구하기]
          //{
              //현재 추가할 [옹이] 의 항목 수가 지금 추가할 [항목] index 가 된다.
              tree_tree_Form->_Tree_Get_Node_ItemCount(&(tree_tree_Form->_tree[d_TREE_project]),
                                                       "etc",
                                                       &nodeItemIndex,
                                                       &tempVal);

          //}

          //"c.[번호]" 형식으로 만들어 준다(이름만 다르면 되므로).
          STR_Assign(item.name, "etc.");
          CONV_LongVal_To_Hex2(tempVal, hexStr);
          STR_Add_AB(item.name, item.name, hexStr);

      //}

      //[항목 문자열 만들기]
      //{
          //경로는 <*.gprj> 의 경로는 제외 하고 기록해야 한다.
          //모든 문서는 <*.gprj> 의 경로안에 있어야 한다는 가정에 있으므로.

          //[설계묶음 경로 제거]
          //{
              //순수한 <*.gprj> 존재하는 폴더 안의 경로만 추출한다.
              STR_GetFileName_Except_BaseDirectory(database->projectpath, fileName, tempStr);

          //}

          //[2012.04.20.금][수정!!!]
          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                    &item,
                                    tempStr);

      //}

      //[기타 설정]
      //{
          item.kind = '.';
          item.bmpindex = d_ITEMBMP_file_x;

      //}

      //[추가]
      //{
          //[중북확인]
          //{
              //표시되는 <text> 가 일치하는 경우(즉, 같은 문서의 경우)는 추가하지 않아야 한다.
              tree_tree_Form->_Tree_Get_Node_ItemIndex_withText(&(tree_tree_Form->_tree[d_TREE_project]),
                                                                "etc",
                                                                //[2012.04.20.금][수정!!!]
                                                                tree_tree_Form->_Item_Txt_StrPtr2(d_TREE_project, item.txt),
                                                                false,
                                                                NULL,
                                                                &tempVal);

              if(tempVal >= 0)
              {
                //중복되는 것이 있는 경우이며, 중복 되는 문서는 추가 할수 없다!

                ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "이미 존재하는 문서입니다.");

                return;

              }

          //}

          //추가한다.
          tree_tree_Form->_Tree_Add_NodeItem(&(tree_tree_Form->_tree[d_TREE_project]), "etc", &item, NULL);

      //}

      //[표시]
      //{
          if(pFileName == NULL)
          {
            //tree 를 한번 그려준다.
            tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

          }

      //}

  //}

  return;

}

int __fastcall IDE_Project_Delete_Etc(void)
{
  //[2009.02.02.월][생성!!!]{----------------------------------------------------------------
  //[참고자료] 에 추가된 <*.*> 를 삭제 한다.
  //[참고자료] 는 오직 한개의 [직계가지] 단위로만 등록되므로 지정 항목 한개만 삭제하면 된다.
  //
  //[2011.05.10.화][수정!!!]-----------------------------------------------------------------
  //[Tree:참고자료] 의 경우도 [삭제 대상] 으로 넣고, 이 경우는 [항목 초기화] 로
  //하위 모든 항목을 지운다.
  //}----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      int     nodeIndex;
      int     nodeLastItemIndex;

      char    tempStr[OPT_wordStrSize];
      char    hexStr[OPT_wordStrSize];

      int     i;
      int     x;

      //[2011.05.10.화][추가!!!]
      int     delItemIndex;
      int     itemCount;
      int     itemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree_tree_Form->_tree[d_TREE_project].select_itemindex < 0) return(no);

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[범위 확인]
  //{
      //[함수묶음] [옹이] 에 등록된 것이 맞는지 먼저 확인한다.

      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "etc", &nodeIndex, NULL, &nodeLastItemIndex);

      //[2011.05.10.화][중요수정!!!]{---------------------------------------------
      //[삭제] 의 경우 [Tree:참고자료] 로 일단 대상이 되므로 이것도 포함 시킨다.
      //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
      //즉, [Tree:참고자료] 를 완전히 비워주는 기능이다.
      //}-------------------------------------------------------------------------
      //---------------v
      if(!((nodeIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex)))
      {
        //[참고자료] [범위] 에 해당하지 않으므로 이 함수처리 대상이 아니다.

        return(no);

      }

  //}

  //[문서 확인]
  //{
      //[방법]{---------------------------------------------------------------
      //[참고자료] 에서는 항상 [직계가지] 로만 사용되므로 확인할 필요는 없다.
      //}---------------------------------------------------------------------

  //}

  //[항목 삭제]
  //{
      //[2011.05.10.화][수정!!!]{-----------------------------------------------------
      //[Tree:참고자료] 가 [삭제대상] 인 경우는 모든 하위 항목을 제거하고 비워준다.
      //이 경우는 하예 하위 항목이 하나도 없으므로 <name> 을 [재생성] 할 필요가 없다.
      //}-----------------------------------------------------------------------------

      //[초기화]
      //{
          //기본적인 삭제 위치는 현재 [선택된 항목] 이다.
          delItemIndex = tree->select_itemindex;

      //}

      //[<Tree:참고자료> 항목인가?]
      //{
          //[!]{-----------------------------------------------------------------
          //[Tree:참고자료] 인 경우는 하위 모든 항목을 삭제하고 완전히 비워준다.
          //}--------------------------------------------------------------------

          if(STR_Match(tree->items[delItemIndex].name, "etc") == true)
          {
            //[!]{---------------------------------------------------------------------
            //이 경우는 [삭제 대상] 이 [Tree:참고자료] 인 경우다.
            //
            //[직계가지] 를 하나씩 삭제해 주기만 하면 된다.
            //
            //아예 내부 항목이 다 없어지는 것이므로 [<name> 재생성] 을 할 필요도 없다.
            //}------------------------------------------------------------------------

            //[<Tree:참고자료> 직계가지 수 얻기]
            //{
                tree_tree_Form->_Tree_Get_Node_ItemCount2
                                  (tree,
                                   //지정 [옹이] 의 [절대위치].
                                   delItemIndex,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

            //}

            for(i = 0,
                //현재 옹이 다음부터 검사한다.
                itemIndex = delItemIndex + 1;
                //[직계가지] 개수 만큼 삭제한다.
                i < itemCount;
                i++)
            {
              //[직계가지] 는 현재 <[옹이].level> 보다 <+1> 된 값을 갖는다.
              if((tree->items[delItemIndex].level + 1) == tree->items[itemIndex].level)
              {
                //[직계가지] 에 해당하므로 [삭제] 한다(모든 하위 항목도 자동 삭제된다).
                tree_tree_Form->_Tree_Delete_Item(tree, itemIndex);

                //현재 항목이 삭제 되었으므로 [현재 위치] 부터 계속 검사 처리한다.

              }
              else
              {
                //다음 위치로 이동한다.
                itemIndex++;

              }

            }

            //마무리 부분으로 이동한다.
            goto lbEnd;

          }

      //}

      //[!]{-----------------------------------------------------
      //여기까지 온 경우는 일반적인 항목이 [삭제대상] 인 경우다.
      //}--------------------------------------------------------

      //[삭제]
      //{
          //현재 선택된 것을 삭제 한다.
          tree_tree_Form->_Tree_Delete_Item(tree, tree->select_itemindex);

      //}

      //[정보 구하기]
      //{
          //항목이 삭제 되었으므로 다시 정보를 얻는다.
          tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "etc", &nodeIndex, NULL, &nodeLastItemIndex);

      //}

      //[<name> 재생성]
      //{
          //[방법]{--------------------------------------------------------------------------------
          //각각의 항목의 <name> 을 다시 index 순번으로 만들어 주어야 한다.
          //이는 계속 생성/삭제를 반복하는 경우 우연히 <name> 이 겹치는 것을 방지하기 위한 것이다.
          //
          //<*.etc>.name = "etc.x"
          //
          //}--------------------------------------------------------------------------------------

          //[옹이] 다음 부터 하위 항목이 된다.
          for(i = (nodeIndex + 1), x = 0; i <= nodeLastItemIndex; i++)
          {
            //모두 <*.etc> 문서에 해당하는 것이다.

            STR_Assign(tree->items[i].name, "etc.");

            //[번호얻기]
            //{
                CONV_LongVal_To_Hex2(x, hexStr);
                STR_Add(tree->items[i].name, hexStr);

            //}

            //[후처리]
            //{
                x++;

            //}

          }

      //}

  //}

  lbEnd:

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

  //}

  return(yes);

}

bool __fastcall Ide_Project_Add_Gvm(//대화상자를 열어 추가하는 경우는 NULL.
                                    char  *pFileName)
{
  //[2012.03.14.수][생성!!!]{---------------------------------------------------
  //[옹이:가상기계] 에 [GVMS/GVMX] 를 추가하고 관련 문서를 등록.
  //[함수묶음] 과 처리 방식은 거의 동일하나 보다 [추가/삭제] 가 자유롭다.
  //
  //[참고!!!]-------------------------------------------------------------------
  //모든 작업은 <*.gprj> 를 기준으로 관리 되어야 하므로 현재 <*.gprj> 가 위치한
  //[폴더] 안에 있는 문서만 된다.
  //
  //"새설계묶음" 인 경우는 아무것도 추가할수 없다.
  //아직 담을 그릇이 없는 것과 같으므로.
  //}---------------------------------------------------------------------------

  //[처리대상]{------------------------------------------------
  //
  //1) [가상기계] [옹이] 의 항목에 <*.gvms>, <*.gvmx> 를 추가.
  //   이 두개 종류만 [직계가지] 로 등록할수 있다.
  //
  //2) <*.gvms>, <*.gvmx> 에 해당 하위 문서 개별 추가.
  //   <*.gtxt>, <*.pdf>, <*.jpg> 등 참고 문서가 해당.
  //
  //의 두가지를 처리.
  //
  //}----------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE  *tree;

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];

      int   nodeIndex;

  //}


  //[<*.gprj> 가 존재하는가?]
  //{
      //[2009.01.31.토][추가!!!]{--------------------
      //현재 "새설계묶음" 인 경우는 추가하지 않는다.
      //item.name:"root" 는 itemindex:0 에 해당한다.
      //}--------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        //비어있는 상태이므로 아무것도 추가 할수 없다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 항목을 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        return(false);

      }

  //}


  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------


  //[문서등록]
  //{
      //[!]{------------------------------------------------------------------
      //[옹이:가상기계] 의 [직계가지] 로는 <*.gvms/*.gvmx> 두종류만 등록가능.
      //따라서, 현재 [등록대상] 이 [옹이:가상기계] 인지 구분 처리.
      //
      //1) 선택된 항목이 [옹이:가상기계] 인 경우.
      //2) 선택된 항목이 [GVMS/GVMX] 인 경우.
      //두가지만 등록 대상이 될수 있고 각각 등록할수 있는 대상이 다르다.
      //}---------------------------------------------------------------------

      //[<가상기계> 옹이 위치 얻기]
      //{
          //[!]{------------------------------
          //[옹이:가상기계] 의 절대위치 얻기.
          //}---------------------------------

          tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "gvm", &nodeIndex);

      //}

      if     (nodeIndex == tree->select_itemindex)
      {
        //[2012.03.15.목][추가!!!]{---
        //[옹이:가상기계] 에 추가.
        //}---------------------------

        if(pFileName == NULL)
        {
          //[!]{----------------------------------------------------
          //이 경우는 직접 항목 추가를 위한 [대화상자] 를 보여준다.
          //}-------------------------------------------------------

          //[확장자 설정]
          //{
              //[가상기계(GVMS/GVMX)] 만 가능.
              main_Form->file_OpenDialog->Filter = "PC 구동(*.gvms)|*.gvms|맷돌(G.MTDL.X) 구동(*.gvmx)|*.gvmx";

          //}

          //[문서 열기 대화상자] 보여주기.
		  if(main_Form->file_OpenDialog->Execute() != true) return(false);

		  STR_Assign(fileName, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

        }
        else
        {
          //[!]{-----------------------
          //직접 대상을 추가하는 경우.
          //}--------------------------

          //<fileName> 으로 문서를 열게 되므로 일단 여기에 다시 할당.
          STR_Assign(fileName, pFileName);

        }

        //[<GVMS/GVMX> 인지 확인]
        //{
            STR_GetFileExt(fileName, tempStr);

            if(!((STR_Match_NoCase(tempStr, "gvms") == true) ||
                 (STR_Match_NoCase(tempStr, "gvmx") == true)))
            {
              //[가상기계(GVMS/GVNX)] 만 추가 가능.
              ide_msgbox_Form->_MsgBox
              (d_MSGBOX_error,
               "[가상기계(GVMS/GVMX)] 만 추가할수 있습니다."
              );

              return(false);

            }

        //}

        //[항목 추가]
        //{
            //처리 과정이 복잡하므로 전용 함수를 사용.
            if(Ide_Project_Add_Gvm_Item(tree->select_itemindex, fileName, NULL) != true) return(false);

        //}

      }
      //[중요!!!]{-----------------------------------------------
      //[GVMS/GVMX] 항목인지는 <bmpindex> 로 구분하는 것이 간단.
      //<옹이:가상기계> 부터 <d_ITEMBMP_gvms/d_ITEMBMP_gvmx> 는
      //[GVMS/GVMX] 항목에만 사용되므로 확실하게 구분가능.
      //}--------------------------------------------------------
      else if((tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_gvms) ||
              (tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_gvmx))
      {
        //[2012.03.15.목][추가!!!]{----------------------
        //[가상기계(GVMS/GVMX)] 에 [하위항목] 으로 추가.
        //}----------------------------------------------

        if(pFileName == NULL)
        {
          //[!]{----------------------------------------------------
          //이 경우는 직접 항목 추가를 위한 [대화상자] 를 보여준다.
          //}-------------------------------------------------------

          //[확장자 설정]
          //{
              //모든 문서를 다 등록할수 있다.
              main_Form->file_OpenDialog->Filter = "*.*|*.*";

          //}

          //[문서 열기 대화상자] 보여주기.
          if(main_Form->file_OpenDialog->Execute() != true) return(false);

          STR_Assign(fileName, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

        }
        else
        {
          //[!]{-----------------------
          //직접 대상을 추가하는 경우.
          //}--------------------------

          //<fileName> 으로 문서를 열게 되므로 일단 여기에 다시 할당.
          STR_Assign(fileName, pFileName);

        }

        //[<GVMS/GVMX> 인지 확인]
        //{
            //[!]{---------------------------------------------
            //[GVMS/GVMX] 항목에 [GVMS/GVMX] 를 등록할수 없다.
            //}------------------------------------------------

            STR_GetFileExt(fileName, tempStr);

            if((STR_Match_NoCase(tempStr, "gvms") == true) ||
               (STR_Match_NoCase(tempStr, "gvmx") == true))
            {
              //[가상기계(GVMS/GVNX)] 는 하위 항목으로 등록할수 없다.
              ide_msgbox_Form->_MsgBox
              (d_MSGBOX_error,
               "[가상기계(GVMS/GVMX)] 항목에 [가상기계(GVMS/GVMX)] 는 추가할수 없습니다."
              );

              return(false);

            }

        //}

        //[항목 추가]
        //{
            //처리 과정이 복잡하므로 전용 함수를 사용.
            if(Ide_Project_Add_Gvm_SubItem(tree->select_itemindex, fileName, NULL) != true) return(false);

        //}

      }
      else
      {
        //[!]{-------------------------------------------------------------
        //[옹이:가상기계] 나 [직계가지] 인 [GVMS/GVMX] 에만 등록할수 있다.
        //}----------------------------------------------------------------

        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "[항목] 추가는\r\n\r\n"
         "1) [가상기계] 항목.\r\n"
         "2) [GVMS/GVMX] 항목.\r\n\r\n"
         "두 종류를 대상으로만 가능합니다."
        );

        return(false);

      }

  //}

  //[표시]
  //{
      if(pFileName == NULL)
      {
        //tree 를 한번 그려준다.
        tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

      }

  //}

  return(true);

}

bool __fastcall Ide_Project_Add_Gvm_Item(//추가할 [옹이] 절대위치.
                                         int    pNodeIndex,
                                         //<*.gvmx/*.gvmx> 의 [경로이름확장자].
                                         char  *pGvmFileName,
                                         //[2012.03.17.토][추가!!!]
                                         //추가된 항목의 [절대위치] 반환(NULL 인 경우는 무효).
                                         int   *rAddItemIndex)
{
  //[2012.03.15.목][생성!!!]{-----------------------------------
  //[옹이:가상기계] 에 [GVMS/GVMX] 항목 추가.
  //
  //이 함수는 <Ide_Project_Add_Glib_Tree()> 를 바탕으로 만든다.
  //
  //[2012.03.17.토][추가!!!]------------------------------------
  //<rAddItemIndex> 로 추가된 항목의 실제 위치를 반환.
  //경로가 있는 경우는 가장 마지막에 추가된 항목위치가 된다.
  //}-----------------------------------------------------------

  //[방법]{------------------------------------------------------------------------
  //[경로] 가 그대로 [tree] 에 반영되도록 처리.
  //[폴더이름] : 옹이가 된다.
  //[문서이름] : 항목이 된다.
  //
  //[주의!!!]----------------------------------------------------------------------
  //이 함수는 <Ide_Project_Add_Gvm()> 함수에서 [항목 등록] 의 목적으로만 사용된다.
  //
  //[<name> 생성]------------------------------------------------------------------
  //1) 일단, [Tree] 상의 [절대위치] 를 바탕으로 생성한다.
  //2) 항목이 추가되는 경우는, 이 항목 다음의 모든 항목의 <name> 을 다시 만든다.
  //   이는 [우연히] 라도 <name> 이 겹치는 것을 막기 위한 것이다.
  //}------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      char  tempStr[OPT_lineStrSize];

      char  tempWord[OPT_lineStrSize];
      char  tempExt[OPT_wordStrSize];
      char  hexStr[OPT_wordStrSize];

      int   itemIndex;

      //[tree 관련]
      //{
          //<*.glib> 함목을 저장.
          struct TREEITEM  item;

      //}

      //[2011.05.07.금][추가!!!]
      int  i;

  //}


  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------


  //[<*.gvms/*.gvmx> 항목 추가]
  //{
      //[!]{-------------------------------------------------------
      //각각의 [폴더이름] 은 [옹이] 가 되므로
      //
      //1) [폴더이름] 을 '\' 문자를 기준으로 [단어 단위] 로 추출.
      //2) 이미 해당 [옹이] 가 만들어져 있는 경우는 이 아래에 추가
      //
      //[폴더이름] 순으로 한개의 [경로] 를 모두 처리.
      //}----------------------------------------------------------

      //[설계묶음 경로 제거]
      //{
          //순수한 <*.gprj> 존재하는 폴더 안의 경로만 추출한다.
          STR_GetFileName_Except_BaseDirectory(database->projectpath, pGvmFileName, tempStr);

      //}

      for(i = 0; ; i++)
      {
        //[단어 추출]
        //{
            STR_GetWord(tempStr, '\\', i, tempWord);

            //[한개 문서 완료 인가?]
            //{
                //[단어] 가 "" 이라면 현재 [문서] 한개의 처리가 끝난 것.
                if(tempWord[0] == '\0') break;

            //}

        //}

        //[<폴더이름/문서이름> 인지 구분]
        //{
            //[!]{----------------------------------------------------------
            //[확장자] 있는 경우는 [문서이름] 이고 없는 경우는 [폴더이름].
            //[폴더이름] 은 [옹이] 가, [문서이름] 은 [항목] 이 된다.
            //이는 [폴더:옹이] 와 [*.gvm*:항목] 을 조기에 구분하기 위한 것.
            //}-------------------------------------------------------------

            STR_GetFileExt(tempWord, tempExt);

            //[확장자] 가 없는 경우는 [옹이] 처리부로 이동.
            if(tempExt[0] == '\0') goto lbNode;
            //[확장자] 가 있는 경우는 [항목] 처리부로 이동.
            else                   goto lbItem;

        //}

        lbNode:
        //{
            //[중복 검사]
            //{
                //[!]{-------------------------------------------
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인.
                //}----------------------------------------------

                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사.
                                 tree->items[pNodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않음.
                                 false,
                                 //이 [옹이] 의 <item-index>.
                                 NULL,
                                 //<text> 를 가진 <itemindex>.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가.
              //}----------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] <index>.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[pNodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[pNodeIndex].name); //지금 [옹이] 의 <name>.
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{-------------------------------
                  //현재 추출한 [단어] 를 그대로 사용.
                  //}----------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);

              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지].
                  item.kind = '.';

                  //최종 [항목] 을 제외하고는 전부 [경로] 에 해당하므로 [폴더] 로 지정.
                  item.bmpindex = d_ITEMBMP_folder;

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[pNodeIndex].name,
                                                     &item,
                                                     NULL);

              //}

              //[다음 [옹이] 위치 지정]
              //{
                  //현재 추가된 [가지] 는 [경로 구조] 상 다음 항목의 [옹이] 가 된다.
                  tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, item.name, &pNodeIndex);

              //}

            }
            else
            {
              //[!]{-------------------------------------------------
              //[중복] 이므로 무시.
              //이 경우는 현재 <항목> 이 다음 항목의 [옹이] 가 된다.
              //}----------------------------------------------------

              pNodeIndex = itemIndex;

            }

            continue;

        //}

        lbItem:
        //{
            //[중복 검사]
            //{
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인.
                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사.
                                 tree->items[pNodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않음.
                                 false,
                                 //이 [옹이] 의 <item-index>.
                                 NULL,
                                 //<text> 를 가진 <itemindex>.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가.
              //}----------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] <index>.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[pNodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[pNodeIndex].name); //지금 [옹이] 의 <name>.
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{-------------------------------
                  //현재 추출한 [단어] 를 그대로 사용.
                  //}----------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);

              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지] 가 된다.
                  item.kind = '.';

                  //[<GVMS/GVMX> 를 구분하여 처리]
                  //{
                      //적용하는 [엄지그림] 이 다르므로 [확장자] 를 추출하여 구분.
                      STR_GetFileExt(pGvmFileName, tempStr);

                      if     (STR_Match_NoCase(tempStr, "gvms") == true)
                      {
                        item.bmpindex = d_ITEMBMP_gvms;

                      }
                      else if(STR_Match_NoCase(tempStr, "gvmx") == true)
                      {
                        item.bmpindex = d_ITEMBMP_gvmx;

                      }
                      else
                      {
                        //[가상기계(GVMS/GVNX)] 만 추가 가능.
                        ide_msgbox_Form->_MsgBox
                        (d_MSGBOX_error,
                         "[가상기계(GVMS/GVMX)] 만 추가할수 있습니다."
                        );

                        return(false);

                      }

                  //}

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[pNodeIndex].name,
                                                     &item,
                                                     //추가된 [항목] 의 [절대위치] 얻기.
                                                     &itemIndex);

                  //[추가 위치 반환]
                  //{
                      //[2012.03.17.토][추가!!!]{----------
                      //최종 추가된 실제 항목 위치를 반환.
                      //}----------------------------------

                      if(rAddItemIndex != NULL) { (*rAddItemIndex) = itemIndex; }

                  //}

              //}

            }
            else
            {
              //[!]{----------------------------------------------------
              //[옹이] 는 중복 될수 있으나, 항목은 중복되어서는 안된다.
              //이미 추가된 것임을 알려준다.
              //}-------------------------------------------------------

              ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "이미 존재하는 [항목] 입니다.");

              return(false);

            }

            continue;

        //}

      }

  //}

  return(true);

}

bool __fastcall Ide_Project_Add_Gvm_SubItem(//추가할 [옹이] 절대위치.
                                            int    pNodeIndex,
                                            //<*.*> 의 [경로이름확장자].
                                            char  *pFileName,
                                            //[2012.03.17.토][추가!!!]
                                            //추가된 항목의 [절대위치] 반환(NULL 인 경우는 무효).
                                            int   *rAddItemIndex)
{
  //[2012.03.15.목][생성!!!]{----------------------------------------------------
  //[GVMS/GVMX] 항목에 해당 [하위 항목] 추가.
  //
  //이 함수는 <Ide_Project_Add_Gvm_Item()> 를 바탕으로 만든다.
  //
  //[2012.03.16.금][중요수정!!!]-------------------------------------------------
  //[추가] 시 추가 대상인 [GVMS/GVMX] 의 경로까지는 제거한 경로만 사용해야 한다.
  //그렇지 않은 경우 [설계묶음] 내의 모든 경로까지 등록된다.
  //
  //[2012.03.17.토][추가!!!]-----------------------------------------------------
  //<rAddItemIndex> 로 추가된 항목의 실제 위치를 반환.
  //경로가 있는 경우는 가장 마지막에 추가된 항목위치가 된다.
  //}----------------------------------------------------------------------------

  //[방법]{------------------------------------------------------------------------
  //[경로] 가 그대로 [tree] 에 반영되도록 처리.
  //[폴더이름] : 옹이가 된다.
  //[문서이름] : 항목이 된다.
  //
  //[주의!!!]----------------------------------------------------------------------
  //이 함수는 <Ide_Project_Add_Gvm()> 함수에서 [항목 등록] 의 목적으로만 사용되고
  //[GVMS/GVMX] 항목에 [하위항목] 을 등록할때만 사용된다.
  //
  //1) [GVMS/GVMX] 에 [GVMS/GVMX] 는 다시 추가할수 없는데 이는 이미 검사된 상태로
  //   이 함수를 사용해야 한다.
  //
  //2) 등록되는 하위 항목은 반드시 대상이 되는 [GVMS/GVMX] 가 있는 위치 안에 존재.
  //
  //[<name> 생성]------------------------------------------------------------------
  //1) 일단, [Tree] 상의 [절대위치] 를 바탕으로 생성한다.
  //2) 항목이 추가되는 경우는, 이 항목 다음의 모든 항목의 <name> 을 다시 만든다.
  //   이는 [우연히] 라도 <name> 이 겹치는 것을 막기 위한 것이다.
  //}------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      char  tempStr[OPT_lineStrSize];

      char  tempWord[OPT_lineStrSize];
      char  tempExt[OPT_wordStrSize];
      char  hexStr[OPT_wordStrSize];

      int   itemIndex;

      //[tree 관련]
      //{
          //<*.glib> 함목을 저장.
          struct TREEITEM  item;

      //}

      int  i;

      //[2012.03.16.금][추가!!!]
      //이미 존재하는 저장소를 다른이름으로 사용하기 위한것.
      char  *tempStr0 = tempStr;
      char  *tempStr1 = tempWord;

  //}


  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------


  //[<GVMS/GVMX> 경로 안인가?]
  //{
      //[2012.03.16.금][중요추가!!!]{-------------------------------------
      //[GVMS/GVMX] 에는 [GVMS/GVMX] 와 같거나 내부 경로안의 문서만 가능.
      //
      //확인시에는 [설계묶음 내부 경로] 를 사용.
      //}-----------------------------------------------------------------

      //[<GVMS/GVMX> [설계묶음] 내부 경로 얻기]
      //{
          Ide_Project_Gvm_Make_InFileName(tree, pNodeIndex, tempStr1);

          //[비교경로] 만 추출.
          STR_GetFilePathOnly(tempStr1,tempStr0);

      //}

      //[추가 항목의 [설계묶음] 내부 경로 얻기]
      //{
          STR_GetFileName_Except_BaseDirectory(database->projectpath, pFileName, tempStr1);

      //}

      //[비교 확인]
      //{
          //추가 항목이 [GVMS/GVMX] 와 같거나 내부에 존재하나?
          if(STR_BaseDirectory_Match(tempStr0, tempStr1) != true)
          {
            ide_msgbox_Form->_MsgBox
            (d_MSGBOX_error,
             "[가상기계(GVMS/GVMX)] 에 추가되는 [항목] 은\r\n"
             "[가상기계(GVMS/GVMX)] 와 같거나 하위 경로에\r\n"
             "존재해야 합니다."
            );

            return(false);

          }

      //}

  //}


  //[<*.*> 항목 추가]
  //{
      //[!]{-------------------------------------------------------------------
      //각각의 [폴더이름] 은 [옹이] 가 되므로
      //
      //1) [폴더이름] 을 '\' 문자를 기준으로 [단어 단위] 로 추출.
      //2) 이미 해당 [옹이] 가 만들어져 있는 경우는 이 아래에 추가
      //
      //[폴더이름] 순으로 한개의 [경로] 를 모두 처리.
      //
      //[2012.03.16.금][중요수정!!!]-------------------------------------------
      //[GVMS/GVMX] 를 [옹이] 로 하위에 추가하므로 같은 경로가 중복되지 않도록
      //[GVMS/GVMX] 가 있는 [경로] 까지는 제거한 경로를 사용해야 한다.
      //}----------------------------------------------------------------------

      //[<GVMS/GVMX> [설계묶음] 내부 경로 얻기]
      //{
          Ide_Project_Gvm_Make_InFileName(tree, pNodeIndex, tempStr1);

          //전체 경로 합성.
          STR_Add_AB(tempStr0, database->projectpath, tempStr1);

          //[비교경로] 만 추출.
          STR_GetFilePathOnly(tempStr0, tempStr1);

          //여기까지 [GVMS/GVMX] 가 위치한 경로가 <tempStr1> 에 들어있다.

      //}

      //[<GVMS/GVMX> 경로 제거]
      //{
          //순수한 <GVMS/GVMX> 가 존재하는 폴더 안의 경로만 추출한다.
          STR_GetFileName_Except_BaseDirectory(tempStr1, pFileName, tempStr);

      //}

      for(i = 0; ; i++)
      {
        //[단어 추출]
        //{
            STR_GetWord(tempStr, '\\', i, tempWord);

            //[한개 문서 완료 인가?]
            //{
                //[단어] 가 "" 이라면 현재 [문서] 한개의 처리가 끝난 것.
                if(tempWord[0] == '\0')
                {
                  //[2012.03.16.금][중요추가!!!]{-------------------------------
                  //[하위항목] 이 [GVMS/GVMX] 와 같은 위치에 있는 경우는 '\' 이
                  //하나도 없이 [이름.확장자] 만 있을수 있다.
                  //이 경우는 처리할 단어가 한개 있으므로 항상 처리해야 된다.
                  //}-----------------------------------------------------------

                  if((i == 0) && (tempStr[0] != '\0'))
                  {
                    //[!]{----------------------------------------------------------------
                    //이 경우는 <tempStr> 자체가 '\' 를 기준으로 추출한 한개 단어가 된다.
                    //처리는 <tempWord> 를 대상으로 하므로 <tempWord> 에 할당.
                    //}-------------------------------------------------------------------

                    STR_Assign(tempWord, tempStr);

                  }
                  else
                  {
                    //위의 조건에 해당하지 않는 경우는 종료.
                    break;

                  }

                }

            //}

        //}

        //[<폴더이름/문서이름> 인지 구분]
        //{
            //[!]{----------------------------------------------------------
            //[확장자] 있는 경우는 [문서이름] 이고 없는 경우는 [폴더이름].
            //[폴더이름] 은 [옹이] 가, [문서이름] 은 [항목] 이 된다.
            //이는 [폴더:옹이] 와 [*.*:항목] 을 조기에 구분하기 위한 것.
            //}-------------------------------------------------------------

            STR_GetFileExt(tempWord, tempExt);

            //[확장자] 가 없는 경우는 [옹이] 처리부로 이동.
            if(tempExt[0] == '\0') goto lbNode;
            //[확장자] 가 있는 경우는 [항목] 처리부로 이동.
            else                   goto lbItem;

        //}

        lbNode:
        //{
            //[중복 검사]
            //{
                //[!]{-------------------------------------------
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인.
                //}----------------------------------------------

                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사.
                                 tree->items[pNodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않음.
                                 false,
                                 //이 [옹이] 의 <item-index>.
                                 NULL,
                                 //<text> 를 가진 <itemindex>.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가.
              //}----------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] <index>.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[pNodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[pNodeIndex].name); //지금 [옹이] 의 <name>.
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{-------------------------------
                  //현재 추출한 [단어] 를 그대로 사용.
                  //}----------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);
                                            
              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지].
                  item.kind = '.';

                  //최종 [항목] 을 제외하고는 전부 [경로] 에 해당하므로 [폴더] 로 지정.
                  item.bmpindex = d_ITEMBMP_folder;

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[pNodeIndex].name,
                                                     &item,
                                                     NULL);

              //}

              //[다음 [옹이] 위치 지정]
              //{
                  //현재 추가된 [가지] 는 [경로 구조] 상 다음 항목의 [옹이] 가 된다.
                  tree_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, item.name, &pNodeIndex);

              //}

            }
            else
            {
              //[!]{-------------------------------------------------
              //[중복] 이므로 무시.
              //이 경우는 현재 <항목> 이 다음 항목의 [옹이] 가 된다.
              //}----------------------------------------------------

              pNodeIndex = itemIndex;

            }

            continue;

        //}

        lbItem:
        //{
            //[중복 검사]
            //{
                //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인.
                tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                                (tree,
                                 //이전 [옹이] 의 <name> 안에서 검사.
                                 tree->items[pNodeIndex].name,
                                 //검사할 <text> 항목.
                                 tempWord,
                                 //[대/소] 문자 구분 여부(true:구분).
                                 //[폴더이름] 으로 구분하지 않음.
                                 false,
                                 //이 [옹이] 의 <item-index>.
                                 NULL,
                                 //<text> 를 가진 <itemindex>.
                                 &itemIndex);

            //}

            if(itemIndex < 0)
            {
              //[!]{-------------------------------------------
              //[중복] 되지 않는 것이므로 현재 [옹이] 에 추가.
              //}----------------------------------------------

              //[항목 초기화][2012.04.18.수]{-------------------------------------
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //[<name> 만들기]
              //{
                  //[<옹이> 항목 수 구하기]
                  //{
                      //현재 [항목] 의 추가 대상이 되는 [옹이] 의 현재 항목 수가 지금 추가할 [항목] <index>.
                      tree_tree_Form->_Tree_Get_Node_ItemCount(tree,
                                                               tree->items[pNodeIndex].name,
                                                               NULL,
                                                               &itemIndex);

                  //}

                  //"[옹이이름].[번호]" 형식으로 만든다.
                  STR_Assign(item.name, tree->items[pNodeIndex].name); //지금 [옹이] 의 <name>.
                  STR_Add(item.name, ".");
                  CONV_LongVal_To_Hex2(itemIndex, hexStr);
                  STR_Add(item.name, hexStr);

              //}

              //[<text> 만들기]
              //{
                  //[!]{-------------------------------
                  //현재 추출한 [단어] 를 그대로 사용.
                  //}----------------------------------

                  //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
                  //[2012.04.20.금][수정!!!]
                  tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                            &item,
                                            tempWord);

              //}

              //[기타 설정]
              //{
                  //추가되는 것은 기본적으로 [가지] 가 된다.
                  item.kind = '.';

                  //종류에 무관하므로 일반 문서로 등록.
                  item.bmpindex = d_ITEMBMP_file_x;

              //}

              //[추가]
              //{
                  //현재 [옹이] 위치의 [직계가지] 로 추가.
                  tree_tree_Form->_Tree_Add_NodeItem(tree,
                                                     tree->items[pNodeIndex].name,
                                                     &item,
                                                     //추가된 [항목] 의 [절대위치] 얻기.
                                                     &itemIndex);

                  //[추가 위치 반환]
                  //{
                      //[2012.03.17.토][추가!!!]{------------
                      //최종 추가된 실제 항목의 위치를 반환.
                      //}------------------------------------

                      if(rAddItemIndex != NULL) { (*rAddItemIndex) = itemIndex; }

                  //}

              //}

            }
            else
            {
              //[!]{----------------------------------------------------
              //[옹이] 는 중복 될수 있으나, 항목은 중복되어서는 안된다.
              //이미 추가된 것임을 알려준다.
              //}-------------------------------------------------------

              ide_msgbox_Form->_MsgBox(d_MSGBOX_error, "이미 존재하는 [항목] 입니다.");

              return(false);

            }

            continue;

        //}

      }

  //}

  return(true);

}

int __fastcall IDE_Project_Delete_Gvm(void)
{
  //[2012.03.16.금][생성!!!]{-------------------------
  //[옹이:가상기계] 에 추가된 <*.glib> 를 삭제 한다.
  //
  //<IDE_Project_Delete_Glib()> 함수를 바탕으로 제작.
  //}-------------------------------------------------

  //[대상 구분 처리]{------------------------------------------------------------------
  //
  //1) [옹이:가상기계] 항목.
  //   [옹이:가상기계] 에 등록된 모든 항목을 삭제(자신은 남긴다).
  //
  //2) [GVMS/GVMX] 항목.
  //   항목을 삭제하고 하위항목도 전부 삭제.
  //
  //3) [GVMS/GVMX] 등록된 하위 항목.
  //   자신만 삭제.
  //
  //4) [폴더] 항목.
  //   자신을 비롯한 하위 모두 삭제.
  //   단, 자신이 속한 [옹이] 가 비워지는 경우는 계속 거슬러 올라가며 삭제.
  //
  //항목의 [하위항목 삭제] 는 <tree_tree_Form->_Tree_Delete_Item() 함수에서 자동 처리.
  //
  //[주의!!!]--------------------------------------------------------------------------
  //[GVMS/GVMX] 에도 하위 항목을 등록할수 있지만, [GVMS/GVMX] 의 하위 항목을 모두
  //삭제한 경우라도 [GVMS/GVMX] 항목자체는 삭제되어서는 안된다.
  //[하위항목] 이 하나도 없을경우 삭제되는 [옹이] 는 [경로] 에 한정된다.
  //}----------------------------------------------------------------------------------

  //[VAR]
  //{
      struct  TREE   *tree;

      int     nodeIndex;
      int     nodeLastItemIndex;

      int     i;

      int     delItemIndex;
      int     itemCount;

      int     itemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree_tree_Form->_tree[d_TREE_project].select_itemindex < 0) return(no);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[범위 확인]
  //{
      //[옹이:가상기계] 범위의 항목인지 확인.
      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "gvm", &nodeIndex, NULL, &nodeLastItemIndex);

      //[!]{----------------------------------------------------------------------
      //[삭제] 의 경우 [Tree:가상기계] 로 일단 대상이 되므로 이것도 포함 시킨다.
      //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
      //즉, [Tree:가상기계] 을 완전히 비워주는 기능.
      //}-------------------------------------------------------------------------
      //---------------v
      if(!((nodeIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex)))
      {
        //[가상기계] [범위] 에 해당하지 않으므로 처리하지 않는다.
        return(no);

      }

  //}

  //[<삭제> 가능한 문서 인가?]
  //{
      //[!]{-----------------------------------
      //[함수묶음] 과 달리 모두 삭제 가능하다.
      //}--------------------------------------

  //}

  //[항목 삭제]
  //{
      //[삭제 대상]{----------------------------------------------
      //1) [옹이:가상기계] 항목.
      //2) [GVMS/GVMX] 항목.
      //3) [GVMS/GVMX] 등록된 하위 항목.
      //4) [폴더] 항목.
      //
      //모든 항목은 삭제 가능하지만 각 항목에 따라 처리가 다르다.
      //}---------------------------------------------------------

      //[!]{--------------------------------------------------------------------------------
      //만일 [항목] 을 삭제한뒤 이 항목이 등록돼 있던 [옹이] 에 [항목] 이 아무것도 없는
      //경우는 이 [옹이] 도 전부 삭제해 주어야 한다.
      //
      //1) 먼저 해당 [항목] 을 삭제한다.
      //
      //2) 거꾸로 [옹이] 를 거슬러 올라가면서 [하위항목] 이 하나도 없는 [옹이] 를 삭제한다.
      //
      //단, [가상기계<name:"gvm">] 자체 [옹이] 는 항상 존재해야 하므로 <name> 확인후
      //<name:"gvm"> 인 [옹이] 이전까지만 처리해야 한다.
      //
      //[!]---------------------------------------------------------------------------------
      //[Tree:가상기계] [옹이] 도 삭제 대상이 된다.
      //이는 다수의 <GVMS/GVMX> 를 추가한 경우 일일히 삭제하는것이 너무 번거롭기 때문.
      //
      //[Tree:가상기계] : 모든 하위 항목을 삭제하나 자신을 남겨둔다(<Tree 제목> 이므로).
      //[항목]          : 자신을 삭제하고 후처리를 수행한다.
      //                  모든 항목이 포함된다.
      //}-----------------------------------------------------------------------------------

      //[초기화]
      //{
          //기본적인 삭제 위치는 현재 [선택된 항목].
          delItemIndex = tree->select_itemindex;

      //}

      //[삭제]
      //{
          //[!]{--------------------------------------------------------
          //[Tree:가상기계] 인 경우와 다른 항목의 경우를 구분하여 처리.
          //}-----------------------------------------------------------

          if(STR_Match(tree->items[delItemIndex].name, "gvm") == true)
          {
            //[!]{---------------------------------------------------------------------
            //이 경우는 [삭제 대상] 이 [Tree:가상기계] 인 경우다.
            //
            //[직계가지] 를 하나씩 삭제해 주기만 하면 된다.
            //
            //아예 내부 항목이 다 없어지는 것이므로 [<name> 재생성] 을 할 필요도 없다.
            //}------------------------------------------------------------------------

            //[<Tree:가상기계> 직계가지 수 얻기]
            //{
                tree_tree_Form->_Tree_Get_Node_ItemCount2
                                  (tree,
                                   //지정 [옹이] 의 [절대위치].
                                   delItemIndex,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

            //}

            for(i = 0,
                //현재 [옹이] 다음부터 검사.
                itemIndex = delItemIndex + 1;
                //[직계가지] 개수 만큼 삭제.
                i < itemCount;
                i++)
            {
              //[직계가지] 는 현재 <[옹이].level> 보다 <+1> 된 값을 갖는다.
              if((tree->items[delItemIndex].level + 1) == tree->items[itemIndex].level)
              {
                //[직계가지] 에 해당하므로 [삭제](모든 하위 항목도 자동 삭제된다).
                tree_tree_Form->_Tree_Delete_Item(tree, itemIndex);

                //현재 [항목] 이 삭제 되었으므로 [현재 위치] 부터 계속 검사 처리.

              }
              else
              {
                //다음 위치로 이동.
                itemIndex++;

              }

            }

            //마무리 부분으로 이동한다.
            goto lbEnd;

          }

          //[!]{-------------------------------------------
          //여기 까지 온것은 [항목] 을 개별 삭제하는 경우.
          //}----------------------------------------------

          lbItemDel:

          //[<옹이> 정보 얻기]
          //{
              //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 를 구한다.
              tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                              (tree,
                               //현재 삭제(선택된것) 할 항목의 [절대위치].
                               delItemIndex,
                               //직계 [옹이] 의 [절대위치].
                               &nodeIndex);

          //}

          //[항목 삭제]
          //{
              //현재 선택된 것을 삭제 한다.
              tree_tree_Form->_Tree_Delete_Item(tree, delItemIndex);

          //}

          //[<옹이> 삭제 예외 처리]
          //{
              //[직계 [옹이] 가 [가상기계] 제목인가?]
              //{
                  //[!]{-------------------------------------------------------------
                  //현재 삭제된 [항목] 의 [직계옹이] 가 [Tree 구조] 상 [제목항목] 인
                  //[가상기계] 인 경우는 삭제해서는 안되므로 더이상 처리하지 않는다.
                  //이 경우는 <name:"gvm"> 로 쉽게 구분할수 있다.
                  //}----------------------------------------------------------------

                  if(STR_Match(tree->items[nodeIndex].name, "gvm") == true) goto lbItemDelEnd;

              //}

              //[직계 [옹이] 가 [GVMS/GVMX] 인가?]
              //{
                  //[!]{--------------------------------------------------------------
                  //현재 삭제된 [항목] 의 [직계옹이] 가 [Tree 구조] 상 [GVMS/GVMX] 인
                  //경우는 삭제해서는 안된다.
                  //
                  //[GVMS/GVMX] 는 직접 삭제하는 경우 외에는 삭제될수 없다.
                  //
                  //이 경우는 <bmpindex:d_ITEMBMP_gvms/d_ITEMBMP_gvmx> 로 쉽게 구분.
                  //}-----------------------------------------------------------------

                  if((tree->items[nodeIndex].bmpindex == d_ITEMBMP_gvms) ||
                     (tree->items[nodeIndex].bmpindex == d_ITEMBMP_gvmx))
                  {
                    //더이상 처리하지 않는다.
                    goto lbItemDelEnd;

                  }

              //}

          //}

          //[<옹이> 가 비었나?]
          //{
              //[!]{----------------------------------------------------------------------
              //이 항목을 가지는 [옹이] 를 거꾸로 거슬러 올라가면서, 비어있는 [옹이] 라면
              //역시 전부 삭제해야 한다.
              //}-------------------------------------------------------------------------

              //[<옹이> 의 [직계가지] 수 얻기]
              //{
                  tree_tree_Form->_Tree_Get_Node_ItemCount
                                  (tree,
                                   //지정 [옹이] 의 [이름].
                                   tree->items[nodeIndex].name,
                                   NULL,
                                   //지정 [옹이] 의 직계 가지 수.
                                   &itemCount);

              //}

              if(itemCount == 0)
              {
                //[!]{--------------------------------------------------------
                //이 경우는 현재 [항목] 의 삭제로 직계 [옹이] 가 텅빈것이므로
                //이 [옹이] 도 역시 삭제해 주어야 한다.
                //}-----------------------------------------------------------

                //[삭제 위치 지정]{-----------------------------------
                //현재 이 [옹이] 위치가 삭제할 [항목] 의 위치가 된다.
                delItemIndex = nodeIndex;
                //}---------------------------------------------------

                goto lbItemDel;

              }

          //}

          lbItemDelEnd:

      //}

      //[<name> 재생성]
      //{
          //[방법]{-----------------------------------------------------------------------------------
          //각각의 항목의 <name> 을 다시 <index> 순번으로 만들어 준다.
          //이는 계속 [생성/삭제] 를 반복하는 경우 우연히 <name> 이 겹치는 것을 방지하기 위한 것이다.
          //
          // <name> = [옹이의 <name>].[옹이에 등록된 순번]
          //
          //으로 생성한다.
          //
          //가장 마지막에 [삭제] 된 항목의 [직계옹이] 에 해당하는 [모든 하위 항목] 을 대상으로 한다.
          //
          //모든 하위 항목을 전부 처리하는데 있어 [동일한 형식] 이 되므로 아예 [전용함수] 의
          //[재귀호출] 로 처리한다.
          //}-----------------------------------------------------------------------------------------

          //[!]{--------------------------------------------------------------------
          //원래는 [최종 삭제된 위치] 부터 처리해야 하지만, [Tree 구조] 가 복잡하고
          //[옹이] 단위로 처리하는 것이 [재귀호출] 로 일괄 처리 하기 좋으므로
          //[최종 삭제된 항목] 을 가지는 [옹이] 를 넘겨준다.
          //}-----------------------------------------------------------------------

          Ide_Project_Delete_Gvm_ReName(tree, nodeIndex);

      //}

  //}

  lbEnd:

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

  //}

  return(yes);

}

void __fastcall Ide_Project_Delete_Gvm_ReName(struct TREE  *pTree,
                                              //처리할 [옹이] 의 [절대위치].
                                              int           pNodeIndex)
{
  //[2012.03.16.금][생성!!!]{-------------------------------------------------
  //<IDE_Project_Delete_Gvm()> 함수에서 [항목] 이 [삭제] 된경우
  //[삭제위치] 다음 모든 항목의 <name> 을 겹치지 않게 [재생성] 한다.
  //
  //1) [옹이] 의 정보를 추출.
  //2) [직계가지] 의 <name> 을 새로 만든다.
  //
  //이 함수는 [직계가지] 만을 대상으로 하고, [직계가지] 자체가 다시 [옹이] 가
  //되는 경우는 이 함수를 [재귀호출] 하여 처리한다.
  //
  //<name> = [옹이의 <name>].[직계가지순번]
  //
  //으로 설정된다.
  //이는 절대로 서로 <name> 이 겹치지 않도록 하기 위한것.
  //
  //[주의!!!]-----------------------------------------------------------------
  //이 함수는 <IDE_Project_Delete_Gvm()> 만을 대상으로 한다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      int     nodeEndItemIndex;
      int     nodeLastItemIndex;

      int     nodeLevel;

      int     itemCount;

      char    tempStr[OPT_lineStrSize];
      char    hexStr[OPT_wordStrSize];

      int     i, count;

  //}

  //[<옹이> 정보 얻기]
  //{
      //현재 [옹이] 의 [하위항목] 관련 정보를 수집한다.
      tree_tree_Form->_Tree_Get_Node_LastItemIndex
                      (pTree,
                       //지정 [옹이] 의 index.
                       pNodeIndex,
                       //가장 마지막 [직계가지] 의 [절대위치].
                       &nodeEndItemIndex,
                       //이 [옹이] 의 가장 마지막 항목의 [절대위치].
                       &nodeLastItemIndex);

      //현재 [옹이] 의 [직계가지] 수를 얻는다.
      tree_tree_Form->_Tree_Get_Node_ItemCount2
                      (pTree,
                       //지정 [옹이] 의 [절대위치].
                       pNodeIndex,
                       //지정 [옹이] 의 직계 가지 수.
                       &itemCount);

      //현재 [옹이] 의 <level> 정보를 얻는다.
      nodeLevel = pTree->items[pNodeIndex].level;

  //}

  //[<직계가지> 의 <name> 재설정]
  //{
      //[!]{------------------------------------------------------------
      //이 [옹이] 에 포함돼 있는 [직계가지] 의 <name> 을 다시 설정한다.
      //단, 이 [직계가지] 가 다시 [옹이] 인 경우는, 다시 이 함수를
      //[재귀호출] 하여 처리해 준다.
      //}---------------------------------------------------------------

      for(//[옹이] 다음 위치 부터 [직계가지] 가 시작된다.
          i = (pNodeIndex + 1),
          //처음에는 처리한 [직계가지] 수는 0 이다.
          count = 0;
          //[옹이] 가 가진 하위가지 전체 까지 검사한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //[!]{---------------------------------------------------------------------------------
        //[직계가지] 만을 대상으로 하며, [직계가지] 는 [옹이<level> + 1] 의 <level> 을 갖는다.
        //}------------------------------------------------------------------------------------

        if     (pTree->items[i].level == (nodeLevel + 1))
        {
          //[!]{--------------------------------------------------------------
          //이 경우는 [직계가지] 에 해당하는 것이다.
          //
          //1) [직계가지] 의 <name> 을 새로 만든다.
          //
          //2) 이 [직계가지] 가 [옹이] 가 되는 경우는 [재귀호출] 로 처리한다.
          //}-----------------------------------------------------------------

          //[<name> 만들기]
          //{
              //[!]{-----------------------------
              //<name> = [옹이<name>].[직계번호]
              //}--------------------------------

              //[<name>]{-------------------------------------------------
              //[옹이] 의 <name> 이 기본이 된다.
              STR_Assign(tempStr, pTree->items[pNodeIndex].name);
              STR_Add(tempStr, ".");

              //[직계가지] 순번을 16진수 최소표기로 변환한다.
              CONV_LongVal_To_Hex2(count, hexStr);

              //함성하여 <name> 에 바로 할당한다.
              STR_Add_AB(pTree->items[i].name, tempStr, hexStr);
              //}---------------------------------------------------------

              //일단 [직계가지] 한개는 처리한 것으로 기록한다.
              count++;

          //}

          //[이 [직계가지] 가 [옹이] 인가?]
          //{
              //이 <가지> 에 하위 항목이 있는지 [하위 항목수] 를 얻는다.
              tree_tree_Form->_Tree_Get_Node_ItemCount2
                              (pTree,
                               //지금 [가지] 의 [절대위치].
                               i,
                               //지금 [가지] 의 [하위 항목] 수.
                               &itemCount);

              if(itemCount > 0)
              {
                //[!][----------------------------------------------------
                //이 경우는 지금 [가지] 가 [옹이] 가 되므로 [재귀호출] 로
                //다시 [하위 항목] 의 <name> 을 만들어준다.
                //}-------------------------------------------------------

                Ide_Project_Delete_Glib_ReName(pTree,
                                               //지금 이 [가지] 가 [옹이] 가 된다.
                                               i);

              }

          //}

        }

      }

  //}

}

void __fastcall Ide_Project_Gvm_Make_InFileName(struct TREE  *pTree,
                                                //<*.gvms/*.gvmx> 항목의 [절대위치].
                                                int           pGvmItemIndex,
                                                //합성된 [설계묶음] 내부 경로.
                                                char         *rInFileName)
{
  //[2012.03.16.금][생성!!!]{--------------------------------------------------------------
  //<GVMS/GVMX> [항목] 의 [절대위치] 를 넘겨 받아 [설계묶음 내부 경로] 를 함성하여 반환.
  //
  //이 함수는 <Ide_Project_Glib_Make_InFileName()> 를 사용하여 만든것.
  //
  //[주의!!!]------------------------------------------------------------------------------
  //[전체 경로] 가 아니라, [설계묶음 내부 경로] 라는 것에 주의.
  //
  //반드시, [Tree: 가상기계] 처리에만 사용해야 한다.
  //
  //[2012.03.17.토][중요수정!!!]-----------------------------------------------------------
  //[GVMS/GVMX] 하위에도 임의로 [항목] 을 등록할수 있기 때문에,
  //[GVMS/GVMX] 의 하위 항목 경로를 이전 방식대로 합성하는 경우 [경로(폴더)] 뿐만 아니라
  //[GVMS/GVMX] 의 [이름] 까지 [경로] 에 포함 돼버리고 만다.
  //따라서, 거슬러 올라가면서 나오는 [GVMS/GVMX] 이름은 무시되어야 한다.
  //
  //금일 <IDE_Project_Save()> 함수에 [가상기계] 항목을 추가한뒤 확인하는 과정에서 발견하고
  //수정한다.
  //}--------------------------------------------------------------------------------------

  //[VAR]
  //{
      char   tempStr[2][OPT_lineStrSize];

      //[문자열 위치 관리]{---------------------------------------------------------------------
      char  *inFileName, //합성결과 저장위치.
            *bfFileName; //이전 합성된 문자열 위치.
      char  *tempPtr;
      //inFileName = <txt> + "\\" + bfFileName;
      //형식으로 사용되므로 계속 두 [위치] 를 바꾸면 된다.
      //간단하게 [매크로] 로 만들어 사용한다.
      #define  m_StrPtrChange    tempPtr=inFileName; inFileName=bfFileName; bfFileName=tempPtr;
      //}---------------------------------------------------------------------------------------

      int    nodeIndex, itemIndex;

  //}

  //[경로 합성]
  //{
      //[초기화]
      //{
          itemIndex = pGvmItemIndex;

          //[문자열 위치 관리자]
          //{
              //같은 크기의 저장소 각각의 위치로 설정해 준다(저장소 순번은 무관).
              inFileName = tempStr[0];
              bfFileName = tempStr[1];

          //}

          //일단, 이 [항목] 의 <txt> 를 먼저 합성한다.
          //[2012.04.20.금][수정!!!]
          STR_Assign(inFileName, tree_tree_Form->_Item_Txt_StrPtr3(pTree, itemIndex));

          //[문자열 저장 위치 교환]{----------------------------------------------------------
          //거꾸로 합성하기 때문에 지금 <inFileName> 은 다음에는 <bfFileName> 이 되어야 한다.
          m_StrPtrChange;
          //}---------------------------------------------------------------------------------

      //}

      //[!]{------------------------------------------
      //일단 이 위치까지 [이름확장자] 는 처리된 상태.
      //이 후 부터는 [경로(폴더)] 만 추가하면 된다.
      //}---------------------------------------------

      lbInFileNameMake:
      {
        //[<옹이> 찾기]
        //{
            //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 를 구한다.
            tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                            (pTree,
                             //현재 삭제(선택된것) 할 항목의 [절대위치].
                             itemIndex,
                             //직계 [옹이] 의 [절대위치].
                             &nodeIndex);

        //}

        //[내부경로 끝인가?]
        //{
            //[!]{--------------------------------------------------------------------
            //위에서 찾은 [옹이] 가 [경로끝] 인 [Tree:함수묶음<name:"gvm">] 인 경우는
            //모든 [문서이름] 합성이 완료된 것이다.
            //}-----------------------------------------------------------------------

            if(STR_Match(pTree->items[nodeIndex].name, "gvm") == true) goto lbInFileNameMakeEnd;

        //}

        //[경로합성]
        //{
            //[!]{-----------------------------------------------------------
            //inFileName = <txt> + "\\" + bfFileName;
            //
            //형식으로 합성해 준다.
            //
            //[2012.03.17.토][중요수정!!!]-----------------------------------
            //[GVMS/GVMX] 하위에도 <*.*> 항목을 마음대로 추가할수 있기때문에
            //[경로] 에 [폴더] 외에 [GVMS/GVMX] 가 추가될수 있다.
            //반드시, [경로] 는 [폴더] 만 가능하도록 수정.
            //
            //이 함수 시작 부분에서 [항목:이름확장자] 는 이미 추가되었으므로
            //여기서는 [경로(폴더)] 만 대상으로 처리하면 된다.
            //}--------------------------------------------------------------

            if(pTree->items[nodeIndex].bmpindex == d_ITEMBMP_folder)
            {
              STR_Add_AB(inFileName, "\\", bfFileName); m_StrPtrChange;

              //[2012.04.20.금][수정!!!]
              STR_Add_AB(inFileName, tree_tree_Form->_Item_Txt_StrPtr3(pTree, nodeIndex), bfFileName); m_StrPtrChange;

            }

        //}

        //지금 합성한 [옹이] 가 다음 검사시 [직계가지] 항목이 된다.
        itemIndex = nodeIndex;

        //계속 처리한다.
        goto lbInFileNameMake;

      }
      lbInFileNameMakeEnd:

      //[후처리]
      //{
          //[!]{------------------------------------------------------------------------------------
          //처리 완료 상태에서는 <m_StrPtrChange> 로 <bfFileName> 에 [합성] 된 결과가 들어 있으므로
          //기준이 되는 <inFileName> 에 다시 결과 문자열 위치를 넘져준다.
          //큰 의미는 없으나, [변수이름] 을 직관적으로 사용하기 위한 것이다.
          //}---------------------------------------------------------------------------------------

          inFileName = bfFileName;

      //}

  //}

  //[합성된 경로 반환]
  //{
      //[!]{------------------------------------------
      //모두 합성된 [설계묶음 내부 경로] 를 반환한다.
      //}---------------------------------------------

      if(rInFileName != NULL) { STR_Assign(rInFileName, inFileName); }

  //}

}

int __fastcall Ide_Project_All_Delete_C_Include_H(void)
{
  //[2009.04.01.수][생성!!!]{----------------------------------------------------------
  //현재 [설계묶음] 안에 포함된 모든 <*.c> 에 등록되 있는 하위 <*.h> 를 전부 삭제한다.
  //}----------------------------------------------------------------------------------

  //[VAR]
  //{
      struct  TREE   *tree;

      int     nodeIndex;
      int     nodeLastItemIndex;

      int     i;

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[설계문서 옹이 정보 얻기]
  //{
      //현재 [설계문서] 의 정보를 얻는다.
      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

  //}

  //[모두 삭제]
  //{
      //<*.c> 에 등록된 <*.h> 문서만 전부 삭제한다.

      for(//현재 옹이 다음부터 검색처리 한다.
          i = nodeIndex + 1;
          //현재 옹이의 가장 마지막 하위 항목의 위치까지 검색한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //<*.c> 의 항목인지 확인한다.
        if(tree->items[i].level == (tree->items[nodeIndex].level + 1))
        {
          //<*.c> 문서 [옹이] 이므로 이 하위 항목을 전부 삭제한다.
          tree_tree_Form->_Tree_Delete_AllSubItem(tree, i);

          //[설계문서 옹이 정보 얻기]
          //{
              //항목이 삭제 되었으므로 현재 [설계문서] 의 정보를 다시 얻는다.
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

          //}

        }

      }  

  //}

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

  //}

  return(yes);

}

void __fastcall Ide_Project_C_IncludeFile(void)
{
  //[2009.04.01.수][생성!!!]{--------------------------------------------------------------
  //Parser() 처리후 {DATABASE} 의 filelist[] 를 검색하여 현재 <*.c> 문서에서 <include> 한
  //<*.h> 문서를 해당 <*.c> 의 하위 항목으로 정리해 준다.
  //
  //[방법]---------------------------------------------------------------------------------
  //(1) 먼저 <*.c> 항목의 모든 하위 항목을 삭제한다.
  //(2) <*.c> 에서 <include> 한 <*.h> 문서를 <*.c> 항목의 하위 항목으로 등록한다.
  //(3) 해당 [Tree] 를 대로 그려준다.
  //}--------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE      *tree;
      struct  TREEITEM   item;

      int     nodeIndex;
      int     nodeLastItemIndex;

      int     i;

      int     fileListIndex;

      char    fileName[OPT_filepath_length];
      char    hexStr[OPT_wordStrSize];

      int     incX;
      int     hFileListIndex;

      //[2009.10.04.일][추가!!!]
      char    itemTxt[OPT_lineStrSize];

  //}

  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------

  //[<*.c> 하위 항목 삭제]
  //{
      //[!]{-----------------------------------------------------------------------------------
      //일단 <*.c> 항목에 등록된 모든 <*.h> 를 삭제한다.
      //이는 복잡한 처리를 하지 않고 간단하게 비워진 상태에서  <*.h> 를 추가 하기 위한 것이다.
      //이렇게 하면 <name> 속성을 간단하게 지정할수 있게 된다.
      //}--------------------------------------------------------------------------------------

      Ide_Project_All_Delete_C_Include_H();

  //}

  //[<*.h> 추가]
  //{
      //[!]{-------------------------------------------------------------------
      //<*.c> 항목에 해당 <*.c> 에 <include> 된 모든 <*.h> 문서를 등록해 준다.
      //}----------------------------------------------------------------------

      //[설계문서 옹이 정보 얻기]
      //{
          //현재 [설계문서] 의 정보를 얻는다.
          tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

      //}

      //[<*.h> 추가]
      //{
          //<*.c> 의 위치를 찾아서 이 위치에 <include> 된 모든 <*.h> 를 추가한다.

          for(//현재 옹이 다음부터 검색처리 한다.
              i = nodeIndex + 1;
              //현재 옹이의 가장 마지막 하위 항목의 위치까지 검색한다.
              i <= nodeLastItemIndex;
              i++)
          {
            //<*.c> 의 항목인지 확인한다.
            if(tree->items[i].level == (tree->items[nodeIndex].level + 1))
            {
              //<*.c> 문서 [옹이] 이므로 {DATABASE} 의 filelist[] 를 검색하여 <include> 된
              //문서가 있다면 전부 등록한다.

              //현재 문서 전체 이름 만들기.
              //[2012.04.20.금][수정!!!]
              STR_Add_AB(fileName, database->projectpath, tree_tree_Form->_Item_Txt_StrPtr3(tree, i));

              //해당 문서 찾기.
              database->FILELIST_GetIndex_WithName(fileName, &fileListIndex);

              for(incX = 0; incX < database->filelist[fileListIndex].include_list_count; incX++)
              {
                //<*.h> 문서이름 얻기.
                hFileListIndex = database->filelist[fileListIndex].include_list[incX];

                //[항목 정보 정리]
                //{
                    //[항목 초기화]{------------------------------------------------------------------
                    //[2012.04.17.화][참고!!!]
                    //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                    tree_tree_Form->_Item_Init(&item);
                    //[<name> 만들기]-----------------------------------------------------------------
                    //"c.x.h.x" 형식으로 만들어 준다.
                    //이는 {DATABASE} 항목의 recordindex 와 겹치는 겻을 방지하기 위한 것이다.
                    //"c.x" 부분을 먼저 기록해 준다.
                    STR_Assign(item.name, tree->items[i].name);
                    STR_Add(item.name, ".h.");
                    //번호얻기.
                    CONV_LongVal_To_Hex2(incX, hexStr);
                    STR_Add(item.name, hexStr);
                    //[<text> 만들기]-------------------------------------------------------------
                    STR_GetFileName_Except_BaseDirectory(database->projectpath,
                                                         database->filelist[hFileListIndex].name,
                                                         itemTxt);

                    //[2012.04.20.금][수정!!!]
                    tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_project]),
                                              &item,
                                              itemTxt);

                    //[기타 설정]-----------------------------------------------------------------
                    item.kind = '.';
                    item.bmpindex = d_ITEMBMP_file_h;
                    //[<recindex> 기록]-----------------------------------------------------------
                    //필요하지 않으므로 기본 값을 할당한다.
                    item.info1 = -1;
                    //[추가]----------------------------------------------------------------------
                    tree_tree_Form->_Tree_Add_NodeItem(tree, tree->items[i].name, &item, NULL);
                    //}---------------------------------------------------------------------------

                //}

              }

              //[설계문서 옹이 정보 얻기]
              //{
                  //항목이 추가 되었으므로 현재 [설계문서] 의 정보를 다시 얻는다.
                  tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeIndex, NULL, &nodeLastItemIndex);

              //}

            }

          }

      //}

  //}

  //[표시]
  //{
      //수정된 내용을 반영하기 위하여 tree 를 한번 다시 그려준다.
      tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);
                               //지정 item-index 를 가진 [옹이] 의 가장 마지막 item-index 를 구해서 반환한다.
  //
  //[2009.02.02.월][수정!!!]-----------------------------------------------------
  //반환 통로가 NULL 인 경우는 반환하지 않는다.
  //이는 _Tree_Get_Node_LastItemIndex() 함수에서 자동 처리 된다.

  //}

  return;

}

bool __fastcall Ide_Project_Api_Vmos_Match(char  *pVmosGinfName)
{
  //[2010.12.16.목][생성!!!]{----------------------------------------------
  //현재 [설계묶음] 안에 포함돼 있는 [명령형 API] 가 현재 맷돌의 VMOS 에서
  //지원하는 것인지 확인하여 그 결과를 알려 준다.
  //
  //이 함수는 [맷돌모듈] 에 생성된 <*.gvmx> 를 설치할때 사용된다.
  //
  //<matdol.cpp> 안의 <Matdol_Gvmx_Install()> 함수에서 사용된다.
  //}----------------------------------------------------------------------

  //[방법!!!]{------------------------------------------------------------------
  //각 [내장형 API] 에는 이 API 관리 폴더 안에 폴더 이름과 같은 이름의 <*.ginf>
  //문서가 존재한다.
  //이 <*.ginf> 안의 <명령API분류이름> 항목의 문자열을 추출하고,
  //[운영체제] 관리 위치의 <운영체제.ginf> 문서안의 <지원API> 항목의 목록을
  //추출하여 비교하면 간단하게 이 API 가 현재 맷돌안의 VMOS 가 지원하는 것인지
  //알수있다.
  //
  //지원 API 목록은 "Com Pwm " 처럼 쉽게 알수 있는 [단어] 로 공백을 구분자로
  //나열돼 있으므로 쉽게 처리가능하다.
  //}---------------------------------------------------------------------------

  //[주의!!!]{-----------------------------------------------------------------
  //이전처럼 [설계묶음:Tree] 안의 내용을 바탕으로 처리하지 않고, 모든 처리에서
  //<IDE_Build()> 안에서 먼저 [설계묶음] 을 저장하고 시작하므로, 이 [설계묶음]
  //안의 <함수묶음> 항목의 목록 정보를 바탕으로 처리한다.
  //이 편이 헐씬 빠르고 간단하다.
  //}--------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      //[설계묶음 관련]
      //{
          char  *gprjFileBuf = NULL;
          int    gprjLineCount;

          int    srchLineNum;

      //}

      //[목록 관련]
      //{
          char  apiListStr[OPT_lineStrSize*5];
          int   apiListWordCount;

      //}

      char  fileName[OPT_lineStrSize];
      char  lastFolderName[OPT_lineStrSize];
      char  tempStr[OPT_lineStrSize];
      int   i, itemCount;

      //"_Math_Cos_" 처럼 수수 API 이름만 가진다.
      char  apiName[OPT_lineStrSize];

      //오류 문자열 합성.
      char  errorStr[OPT_lineStrSize*10];

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[<지원API> 목록 얻기]
  //{
      //[!]{-------------------------------------------------------------------
      //찾은 <운영체제.ginf> 문서에서 <지원API> 목록을 1 행의 문자열로 얻는다.
      //더불어 목록의 단어수도 얻는다.
      //이미 [공백 한개] 단위로 정리된 단어 조합 문자열이다.
      //"Com Pwm Math ..."  와 같은 형식이다.
      //}----------------------------------------------------------------------

      if(Ginf_Get_ApiListStr_InFile(pVmosGinfName, apiListStr, &apiListWordCount) != true) goto lbError;

  //}

  //[설계묶음<*.gprj> 문서 열기]
  //{
      //[!]{----------------------------------------------------------------------------
      //<Tree> 상에서 직접 읽어들이지 않고(복잡하다) 항상 이 함수가 처리되기 전에
      //[설계묶음<*.gprj>] 가 먼저 [저장] 되므로 [설계묶음<*.gprj>] 를 열어서 처리한다.
      //이 문서에는 이미 <함수묶음> 항목으로 포함된 모든 [함수묶음] 이 정리돼 있으므로
      //이 부분을 추출하여 직접 처리하는 것이 훨씬 간단하고 처리 속도도 빠르다.
      //}-------------------------------------------------------------------------------

      //[[설계묶음<*.gprj>] 열기]
      //{
          //원래 <*.ginf> 문서를 여는 함수지만, 차이가 없으므로 이 함수로 읽어들인다.
          if(Ginf_Open(database->projectname, (unsigned char **)(&gprjFileBuf), NULL) != true) return(false);

          //전체 행수 얻기.
          gprjLineCount = STR_Get_LineCount(gprjFileBuf);

      //}

      //[함수묶음 정보 얻기]
      //{
          //제목줄을 찾는다.
          STR_Search_LineStr_knowLineCount(gprjFileBuf, gprjLineCount, "<함수묶음>", &srchLineNum);

          //[문서 개수 얻기]
          //{
              //[제목행] 바로 다음행이 문서 개수가 10진수로 기록돼 있다.
              STR_Get_LineStr_withLineNumber(gprjFileBuf, srchLineNum + 1, tempStr);

              //값으로 변환.
              CONV_DecStr_To_IntVal(tempStr, &itemCount);

          //}

      //}

  //}

  //[지원 API 여부 확인]
  //{
      //[!]{---------------------------------------------------------------------------------
      //"glib\맷돌\API_Math\_Math_Cos_.glib"
      //와 같이 경로가 기록돼 있으므로, 이를 [원본 glib] 가 있는 폴더위치로 합성하여
      //실제 [원본] 과 비교한다.
      //이는 [명령API분류이름] 정보를 가진 <*.ginf> 는 [원본] 폴더안에만 존재하기 때문이다.
      //또한, VMOS 계열의 내장 명령형 API 는 반드시 [원본 gib] 폴더안에만 존재하기 때문이다.
      //}------------------------------------------------------------------------------------

      //[방법!!!]{------------------------------------------------------------------------------------
      //1) 원본 [glib] 폴더의 경로로 합성한다.
      //2) <*.glib> 가 존재하는 폴더안에 <*.ginf> 가 존재하는지 확인한다.
      //3) <*.ginf> 안의 <명령API이름> 항목 정보를 추출한다.
      //4) 3) 의 정보(단어) 와 이미 위에서 구한 [API 지원 목록] 을 단어단위로 비교한다.
      //5) 4) 에서 일치하는 것이 하나도 없다면 [현재 맷돌의 VMOS 에서 지원하지 않는 API] 로 확정한다.
      //6) 2)- 5) 까지 과정을 [함수묶음] 안의 모든 항목에 대하여 처리한다.
      //7) 결과 보고.
      //}---------------------------------------------------------------------------------------------

      for(i = 0; i < itemCount; i++)
      {
        //[<함수묶음> 목록 추출]
        //{
            STR_Get_LineStr_withLineNumber(gprjFileBuf, srchLineNum + 2 + i, tempStr);

        //}

        //[<*.glib> 이름 합성]
        //{
			//실제 원본의 위치로 합성한다.
			STR_Add_AB(fileName, ((AnsiString)Ide_Root_Path).c_str(), tempStr);

            //[순수 API 이름만 추출]
            //{
                //[!]{--------------------------------------------------------------
                //경로등을 전부 제거하고 "_Math_Cos_" 처럼 [이름] 만 추출해 놓는다.
                //}-----------------------------------------------------------------

                STR_GetFileNameOnly_ExceptExt(fileName, apiName);

            //}

        //}

        //[최종 폴더이름 추출]
        //{
            //[!]{-------------------------------------------------------
            //<최종 폴더이름.ginf> 에 [명령API분류이름] 정보가 들어있다.
            //이 문서가 없는 경우는 VMOS 에 아예 내장되지 않는 것이므로
            //검사대상에서 제외시킨다.
            //}----------------------------------------------------------

            STR_Get_FileFullName_LastFolderName(fileName, lastFolderName);

        //}

        //[경로만 추출]
        //{
            //<*.glib> 부분을 빼고 순수한 경로만 추출한다.
            STR_GetFilePathOnly(fileName, tempStr);

        //}

        //[<최종 폴더이름.ginf> 문서 이름 만들기]
        //{
            STR_Add_AB(fileName, tempStr, lastFolderName);

            //확장자 붙이기.
            STR_Add(fileName, ".ginf");

        //}

        //[문서존재 검사]
        //{
            //[!]{------------------------------------------------------------------------
            //<*.ginf> 문서가 존재하지 않는다면 현재 검사하는 [함수묶음] 은
            //아예 VMOS 에 내장되는 API 에 해당하지 않으므로 그냥 다음 항목으로 넘어간다.
            //}---------------------------------------------------------------------------

            //계속 다음 항목으로 진행.
            if(FileExists(fileName) != true) continue;

        //}

        //[<명령API분류이름> 정보 얻기]
        //{
            //[!]{----------------------------------------------------
            //<*.ginf> 문서에서 직접 <명령API분류이름> 정보를 얻는다.
            //이는 한개의 [단어] 로 된 문자열 정보다.
            //직접 해당 함수를 사용하여 바로 추출한다.
            //}-------------------------------------------------------

            if(Ginf_Get_ApiClassName_InFile(fileName, tempStr) != true) goto lbError;

        //}

        //[지원 목록에 해당하나?]
        //{
            //[!]{--------------------------------------------------------
            //이미 구한 현재 맷돌의 VMOS 에서 지원하는 API 인지 검사한다.
            //단, [대/소 문자] 는 구분하지 않는다.
            //}-----------------------------------------------------------

            if(STR_Search_MatchWord_inLineStr(apiListStr, tempStr, true) == -1)
            {
              //[!]{-------------------------------------------------------------
              //이 경우는 해당하는 것이 없는 것으로 현재 맷돌에 설치된 VMOS 에서
              //지원하지 않는 API 라는 것이다.
              //}----------------------------------------------------------------

              STR_Assign(errorStr, "");

              //<apiName> 에 현재 검사한 API 이름이 들어있다. 
              STR_Add(errorStr, "[ "); STR_Add(errorStr, apiName); STR_Add(errorStr, " ]\r\n\r\n");
              STR_Add(errorStr, "이 API 는 현재 맷돌에 설치돼 있는 [운영체제] 에서 지원하지 않는 API 인데\r\n"
                                "[함수묶음] 안에 포함돼 있습니다.\r\n\r\n"

                                "먼저 맷돌에 해당 API 를 지원하는 [운영체제] 를 설치하시기 바랍니다.\r\n"
                                "{ 메뉴 : 설정->맷돌 [운영체제] 설치 }\r\n\r\n"

                                "사용되지 않는 API 라면 [함수묶음] 에서 삭제하십시요.");

              ide_msgbox_Form->_MsgBox2(d_MSGBOX_error, false, errorStr);

              goto lbError;

            }

        //}

      }

      //[!]{-----------------------------------
      //여기까지 온 것은 모두 이상없는 것이다.
      //}--------------------------------------

  //}

  lbOk:
  {
    //[동적 삭제]
    //{
        if(gprjFileBuf != NULL) { delete [] gprjFileBuf; gprjFileBuf = NULL; }

    //}

    return(true);

  }

  lbError:
  {
    //[동적 삭제]
    //{
        if(gprjFileBuf != NULL) { delete [] gprjFileBuf; gprjFileBuf = NULL; }

    //}

    return(false);

  }

}

bool __fastcall Ide_Mtdl_Get_VmosGinfFileName(char  *rVmosGinfFileName)
{
  //[2011.11.13.일][생성!!!]{----------------------------------
  //현재 연결돼 있는 맷돌(G.MTDL.X) 에 설치된 VMOS 에 대응되는
  //<*.ginf> 문서 [경로이름확장자] 를 찾아서 반환한다.
  //}----------------------------------------------------------

  //[VAR]
  //{
      DTU8  osID;

  //}

  //[VMOSINFO 위치 얻기]
  //{
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}

  //[초기화]
  //{
      rVmosGinfFileName[0] = '\0'; 

  //}

  //[식별자 읽기]
  //{
      //운영체제 정보를 읽어들인다.
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_OS_ID, (DTU1 *)(&osID)) != true) return(false);

  //}

  //[<운영체제.ginf> 문서 찾기]
  //{
      //[!]{---------------------------------------------------------------------------------
      //맷돌에 설치된 [운영체제] 정보를 알기 위하여 <식별자> 를 가진 <*.ginf> 문서를 찾는다.
      //과정이 복잡하므로 전용함수를 사용한다.
      //}------------------------------------------------------------------------------------

      if(Ginf_Get_OsGinfFileName_withID(osID, rVmosGinfFileName) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mtdl_Vmos_Api_Match(//한행 단어나열로 된 API 목록.
                                        //예) "Spi I2c Math"
                                        char  *pApiClassList)
{
  //[2010.12.16.목][생성!!!]{-----------------------------------------------------------
  //<Ide_Project_Api_Vmos_Match()> 함수를 바탕으로 만든 것이다.
  //
  //<맷돌C:API> 와 일반적인 경우 <GVMX> 를 [설계묶음] 없이 바로 맷돌에 설치할때는
  //[설계묶음] 이 열려 있어야 동작하는 <Ide_Project_Api_Vmos_Match()> 함수는
  //사용할수 없다.
  //
  //따라서, 이 경우는 직접 "Spi I2c Math" 처럼 직접 [문자열] 형태로
  //[API 목록] 을 전달 받아서 직접 일치 여부를 확인해야 한다.
  //
  //<Ide_Project_Api_Vmos_Match()> 함수와는 달리 직접 맷돌에 설치된 현재
  //VMOS 의 종류를 판별하고 관련 <*.ginf> 문서를 찾는 것까지 전부다 처리해야 한다.
  //
  //[주의!!!]---------------------------------------------------------------------------
  //이 함수는 [확인] 용도이고, <맷돌C:;API> 에서 사용하기 위하여 만든 것이므로
  //내부적으로 [알림창] 을 보여주지 않고 <true/false> 만 전달한다.
  //
  //[중요!!!]---------------------------------------------------------------------------
  //<pApiClassList == ""> 인 경우등 비교할 단어가 없는 경우는 [이상없음] 으로 처리한다.
  //}-----------------------------------------------------------------------------------

  //[방법!!!]{------------------------------------------------------------------
  //"Spi I2c Math" 의 형식으로 [API 목록] 을 각각 단어로 전달 받는데, 이 목록과
  //[운영체제] 관리 위치의 <운영체제.ginf> 문서안의 <지원API> 항목의 목록을
  //추출하여 비교하여 처리한다.
  //
  //지원 API 목록은 "Com Pwm " 처럼 쉽게 알수 있는 [단어] 로 공백을 구분자로
  //나열돼 있으므로 쉽게 처리가능하다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      //[목록 관련]
      //{
          char  apiListStr[OPT_lineStrSize*5];
          int   apiListWordCount;

      //}

      char  tempStr[OPT_lineStrSize];
      int   i;

      char  vmosGinfName[OPT_lineStrSize];

  //}

  //[처리할 내용이 있나?]
  //{
      //처리할 내용이 없는 경우는 [이상없음] 으로 간주.
      if(pApiClassList[0] == '\0') goto lbOk;

  //}

  //[VMOS 해당 <*.ginf> [경로이름확장자] 얻기]
  //{
      //현재 맷돌에 설치돼 있는 VMOS 에 해당하는 <*.ginf> 의 [경로이름확장자] 를 얻는다.
      if(Ide_Mtdl_Get_VmosGinfFileName(vmosGinfName) != true) goto lbError;

  //}

  //[<지원API> 목록 얻기]
  //{
      //[!]{-------------------------------------------------------------------
      //찾은 <운영체제.ginf> 문서에서 <지원API> 목록을 1 행의 문자열로 얻는다.
      //더불어 목록의 단어수도 얻는다.
      //이미 [공백 한개] 단위로 정리된 단어 조합 문자열이다.
      //"Com Pwm Math ..."  와 같은 형식이다.
      //}----------------------------------------------------------------------

      if(Ginf_Get_ApiListStr_InFile(vmosGinfName, apiListStr, &apiListWordCount) != true) goto lbError;

  //}

  //[지원 API 여부 확인]
  //{
      //[2011.11.14.화][추가!!!]{---------------------------------------------------
      //<pApiClassList> 문자열에서 순번대로 <명령API분류이름> 을 하나씩 추출하여
      //현재 맷돌에 설치돼 있는 VMOS 에서 지원하는 <명령API분류이름> 인지 확인한다.
      //즉, 현재 <API 계열> 이 VMOS 에서 지원하는 것인지 확인하고자 하는것.
      //}---------------------------------------------------------------------------

      for(i = 0; ; i++)
      {
        //[<명령API분류이름> 정보 얻기]
        //{
            //<API 목록:pApiClassList> 에서 지정 순번 단어추출.
            STR_Get_LineWord_withSpace(pApiClassList, i, tempStr);

            //더이상 비교할 단어가 없다면 이상없는 것으로 종료.
            if(tempStr[0] == '\0') break;

        //}

        //[지원 목록에 해당하나?]
        //{
            //[!]{----------------------------------------------------------------------
            //이미 구한 현재 맷돌의 VMOS 에서 지원하는 API 에 해당하는 것인지 검사한다.
            //단, [대/소 문자] 는 구분하지 않는다.
            //}-------------------------------------------------------------------------

            if(STR_Search_MatchWord_inLineStr(apiListStr, tempStr, true) == -1)
            {
              //[!]{---------------------------------------------------------------
              //이 경우는 해당하는 것이 없는 것으로 현재 맷돌에 설치된 VMOS 에서
              //지원하지 않는 API 인것.
              //단, 이 함수 자체가 <맷돌C:API> 를 위한 것이므로 여기서 [알림참] 을
              //보이지 않고 이 처리는 이 함수를 사용하는 쪽에서 처리하도록 한다.
              //}------------------------------------------------------------------

              goto lbError;

            }

        //}

      }

      //[!]{-----------------------------------
      //여기까지 온 것은 모두 이상없는 것이다.
      //}--------------------------------------

  //}

  lbOk:
  {
    return(true);

  }

  lbError:
  {
    return(false);

  }

}

void __fastcall Ide_Project_Api_ReCopy(char  *pApiTreeText)
{
  //[2009.09.05.토][생성!!!]{-----------------------------------------------------------------
  //현재 [함수묶음] 에 등록된 API 의 <tree> 상의 문자열을 전달받아서, 해당 API 를
  //IDE->[build] 경로에서 다시 복사해 덮어쓴다.
  //이는 항상 IDE->[build] 폴던안의 API 가 사용되어야 하기 때문이다.
  //이렇게 하지 않으면, 기존의 [설계묶음] 의 경우 향상된 API 를 적용받지 못하여
  //해로운 배포본과 호환되지 않게 된다.
  //
  //<pApiTreeText> 는 [설계묶음] 경로안의 위치이므로, 이 문자열을 이용하여 [출발지],
  //[도착지] 경로를 합성한 뒤 File_Copy() 함수로 간단하게 처리한다.
  //
  //만일 경로가 다르거나 해당 경로에 문서가 존재하지 않는 경우는 아무 처리도 수행되지 않는다.
  //
  //[주의!!!]---------------------------------------------------------------------------------
  //복사시에는 반드시 <*.glib>, <*.h>, <*.gtxt> 3개의 문서를 같이 복사해야 한다.
  //API 사용시는 항상 이 3 개의 문서가 같이 있어야 하기 때문이다.
  //}-----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      char    dstPath[OPT_filepath_length];
      char    srcPath[OPT_filepath_length];

      char    tempPath[OPT_filepath_length];

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[출발지 경로 합성]
  //{
      //출발지 경로 합성.
      STR_Add_AB(srcPath, database->programpath, pApiTreeText);

  //}

  //[도착지 경로 합성]
  //{
      //사용자 [설계묶음] 경로안으로 하면된다(출발지 경로에 "glib" 가 있으므로).
      STR_Add_AB(dstPath, database->projectpath, pApiTreeText);

  //}

  //[출발지에 문서가 존재하나?]
  //{
      //[!]{-----------------------------------------------------------
      //출발지 문서가 존재하는 경우만 복사할수 있으므로 이를 확인한다.
      //}--------------------------------------------------------------

      //복사하지 않고 바로 종료한다.
      if(FileExists(srcPath) != true) return;

  //}

  //[복사]
  //{
      //[!]{----------------------------------------------------------------------
      //File_Copy() 함수는 도착지에 같은 문서가 이미 있는 경우, 이전것을 삭제하고
      //새로운 것으로 덮어쓰는 것 까지 수행한다.
      //}-------------------------------------------------------------------------

      //[<*.h> 복사]
      //{
          STR_ChangeFileExt(dstPath, "h", tempPath); STR_Assign(dstPath, tempPath);
          STR_ChangeFileExt(srcPath, "h", tempPath); STR_Assign(srcPath, tempPath);
          File_Copy(dstPath, srcPath);

      //}

      //[<*.gtxt> 복사]
      //{
          STR_ChangeFileExt(dstPath, "gtxt", tempPath); STR_Assign(dstPath, tempPath);
          STR_ChangeFileExt(srcPath, "gtxt", tempPath); STR_Assign(srcPath, tempPath);
          File_Copy(dstPath, srcPath);

      //}

      //[<*.glib> 복사]
      //{
          STR_ChangeFileExt(dstPath, "glib", tempPath); STR_Assign(dstPath, tempPath);
          STR_ChangeFileExt(srcPath, "glib", tempPath); STR_Assign(srcPath, tempPath);
          File_Copy(dstPath, srcPath);

      //}

  //}

  return;

}

//------------------------------------------------------------------------------
//[<*.gprj> 문서 관련]----------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_GprjFile_Get_PathNameExt(char  *rPathNameExt,
                                             char  *rPath,
                                             char  *rNameExt,
                                             char  *rName)
{
  //[2018.10.09.화][생성!!!]{-----------------------------------------------------
  //현재 [맷돌-IDE] 에 열려있는 [설계묶음<*.gprj>] 의 [경로/이름/확장자] 를 반환.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      class DATABASE  *db_;

  //}

  //[DataBase 주소 얻기]
  //{
      DATABASE_GetPtr(&db_);

  //}

  //[경로이름확장자:반환]
  //{
      if(rPathNameExt != NULL)
      {
        STR_Assign(rPathNameExt, db_->projectname);

      }

  //}

  //[경로:반환]
  //{
      if(rPath != NULL)
      {
        STR_Assign(rPath, db_->projectpath);

      }

  //}

  //[이름확장자:반환]
  //{
      if(rNameExt != NULL)
      {
        //[이름확장자] 만 추출.
        STR_GetFileNameOnly(db_->projectname, rNameExt);

     
      }

  //}

  //[이름:반환]
  //{
      if(rName != NULL)
      {
        //[이름] 만 추출.
        STR_GetFileNameOnly_ExceptExt(db_->projectname, rName);
        
      }

  //}

}

bool __fastcall Ide_GprjFile_Add_C(char  *pGprj_PathNameExt,
                                   //[2018.10.15.월][추가!!!]{----------------------------------------------------
                                   //<pInsertPosStr> 문자열을 찾아 이 위치에 <pC_PathNameExt_List> 를 끼워넣는다.
                                   //찾는 문자열이 없는 경우는 그냥 <설계문서> 마지막에 추가.
                                   //""  인 경우는 사용하지 않는다.
                                   char  *pInsertPosStr,
                                   //}----------------------------------------------------------------------------
                                   //반드시 [설계묶음] 내부 경로에 존재해야 함.
                                   char  *pC_PathNameExt_List)
{
  //[2018.10.09.화][생성!!!]{----------------------------------------
  //[설계묶음<*.gprj> 문서 자체에 <*.c> 추가.
  //
  //1) 문서열기.
  //2) <설계문서> 목록에 <*.c> 끼워넣기.
  //3) 개수 수정.
  //
  //[2018.10.11.목][수정!!!]-----------------------------------------
  //[중복] 되는 경우는 추가하지 않는다.
  //
  //[2018.10.12.금][중요수정!!!]-------------------------------------
  //내부 적으로 물리적인 하드디스크를 대상으로 [열기/저장] 을 하므로
  //연속적으로 사용시 하드디스크 접근 오류가 발생한다.
  //따라서, 목록을 전달받아서 한번에 처리하는 것으로 수정.
  //
  //[2018.10.14.일][수정!!!]*****************************************
  //[폼디자이너] 지원을 위하여 [설계문서] 안에 <__Main.c> 가 있다면
  //이 항목 자리에 끼워 넣는다.
  //즉, <__Main.c> 가 가장 마지막에 위치하도록.
  //}----------------------------------------------------------------

  //[설계묶음:구조]{-----------------------------------------
  //
  //<설계문서>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  //main.c
  // ...
  //
  //<함수묶음>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  //glib\IDE\API_Ide_Gvms\_Ide_가상기계_실행이름확장자_.glib
  // ...
  //
  //<참고자료>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  // ...
  //
  //<가상기계>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  // ...
  //
  //<끝>
  //}--------------------------------------------------------

  //[VAR]
  //{
      char  *fileBuf = NULL;

      int    fileSize;

      char   tempStr[1024];

      int    lineNumber_C    = -1; //<설계문서> 행번호.
      int    lineNumber_Glib = -1; //<함수묶음> 행번호.

      //[2018.10.15.월][추가!!!]{----
      int    lineNumber_Insert = -1;
      //}----------------------------

      int    searchLineNumber = -1;

      //[설계묶음<*.gprj>] 의 [경로].
      char   gprjPath[1024];

      //[설계묶음] 내부 [경로이름확장자].
      char   innerPathNameExt[1024];

      int    count;

      //[2018.10.12.금][추가!!!]
      char   lineStr[1024];
      int    lineCount;
      int    i;

      //[2018.10.13.토][추가!!!]
      //순수하게 추가된 항목수.
      int    addItemCount = 0;

  //}

  //[<*.gprj> 확인]
  //{
      //[문서 존재 확인]
      //{
          if(FileExists(pGprj_PathNameExt) != true) { return(false); }

      //}

      //[<*.gprj> 인지 확인]
      //{
          STR_GetFileExt(pGprj_PathNameExt, tempStr);

          if(STR_Match_NoCase(tempStr, "gprj") != true)
          {
            //[설계묶음] 에 해당하지 않는 것이므로 오류.
            return(false);

          }

      //}

  //}

  //[문서 열기]
  //{
      if(FILE_Open(pGprj_PathNameExt, (unsigned char **)(&fileBuf), &fileSize) != true) goto lbError;

      //[참고!!!]{************************************************************************
      //여기서는 [설계묶음] 문서 크기만큼 <fileBuf> 가 생성되지만 추가하는데 문제가 없다.
      //<STR_InsertLineStr()> 에서 추가시 <fileBuf> 를 자동적으로 화장하고 포인터를
      //[재설정] 하기 때문.
      //}*********************************************************************************

  //}

  //[행번호 얻기]
  //{
      //[!]{---------------------------------------------------------------------
      //<설계문서>, <함수묶음> 의 행번호를 미리 구한다.
      //여기서 미리 구해도 [개수] 부분 위치는 추가후에도 변경되지 않으므로 무관.
      //}------------------------------------------------------------------------

      //["<설계문서>" 찾기]
      //{
          STR_Search_LineStr_knowLineCount(fileBuf, 0, "<설계문서>", &lineNumber_C);

      //}

      //["<함수묶음>" 찾기]
      //{
          STR_Search_LineStr_knowLineCount(fileBuf, 0, "<함수묶음>", &lineNumber_Glib);

      //}

  //}

  //[끼워넣을 위치 찾기]
  //{
      //[2018.10.15.월][추가!!]{----------------------------
      //<pC_PathNameExt_List> 를 끼워넣을 위치 찾기.
      //
      //1) <pInsertPosStr> 문자열 찾기.
      //
      //2) <설계문서> - <함수묶음> 사이가 아닌 경우는 무시.
      //
      //}----------------------------------------------------

      //지정 문자열이 있는 경우만 처리.
      if(STR_Match_NoCase(pInsertPosStr, "") != true)
      {
        STR_Search_LineStr_knowLineCount(fileBuf, 0, pInsertPosStr, &lineNumber_Insert);

        //[범위 검사]
        //{
            //<설계문서> - <함수묶음> 사이에 위치하는 경우만 유효.
            if(!((lineNumber_C < lineNumber_Insert) && (lineNumber_Insert < lineNumber_Glib)))
            {
              //[범위] 밖이라면 무효.
              lineNumber_Insert = -1;

            }

        //}

        //[!]{-------------------------------------------------------------------------
        //찾는 문자열이 없는 경우는 <lineNumber_Insert:-1> 이 되나, 이 의미를 구분하여
        //처리하는 것은 [끼워넣기] 부분에서 처리한다.
        //}----------------------------------------------------------------------------

      }

  //}
  
  //[C 문서 추가]
  //{
      //[2018.10.12.금][수정!!!]{--------------
      //[목록] 을 전달 받아서 한번에 처리한다.
      //[목록] 은 [행:단위] 로 정리돼 있다.
      //}--------------------------------------
      
      //[설계묶음] 경로 추출.
      STR_GetFilePathOnly(pGprj_PathNameExt, gprjPath);
      
      //[목록] 의 총행수 얻기.
      lineCount = STR_Get_LineCount(pC_PathNameExt_List);
      
      for(i = 0, addItemCount = 0; i < lineCount; i++)
      {
        //[행 추출]
        //{
            //한개 행은 <*.c> 문서의 [경로이름확장자] 가 된다.
            STR_Get_LineStr_withLineNumber(pC_PathNameExt_List, i, lineStr);

            //[주의!!!]{-----------------------------------------------------------------
            //<pGlib_Name_List> 의 끝에 "\r\n" 만 있는 NULL 행인 경우가 있을수 있으므로.
            //이 경우는 무시하고 계속 검사.
            //단, 다음에 비교하는 부분에 닿으면 오류가 되므로 이 부분에서 넘긴다.
            //절대 <continue> 를 사용시 그대로 for 를 종료하여 결국 [일치하지않음:오류]
            //로 인식되므로 아예 [추가] 부분 까지 건너뛰도록 한다.
            if(STR_Match_NoCase(lineStr, "") == true) goto lbContinue;
            //}--------------------------------------------------------------------------

        //}

        //[<*.c> 확인]
        //{
            //[2018.10.11.목][추가!!!]{---
            //
            //1) <*.c> 존재 확인.
            //
            //2) [확장자:"c"] 인지 확인.
            //
            //}---------------------------

            //[문서 존재 확인]
            //{
                //해당하지 않는 경우는 오류.
                if(FileExists(lineStr) != true) goto lbError;

            //}

            //[<*.c> 인지 확인]
            //{
                STR_GetFileExt(lineStr, tempStr);

                if(STR_Match_NoCase(tempStr, "c") != true)
                {
                  //<*.c> 에 해당하지 않는 것이므로 오류.
                  goto lbError;

                }

            //}

        //}
  
        //[내부경로 얻기]
        //{
            //[설계묶음] 안의 경로만 추가되므로 [내부경로] 만 추출.
            STR_GetFileName_Except_BaseDirectory(gprjPath, lineStr, innerPathNameExt);

        //}

        //[중복 검사]
        //{
            //[2018.10.11.목][추가!!!]{----------------------------------------------------
            //
            //1) 전체를 대상으로 일치하는 문자열 찾기.
            //
            //2) 찾은 행이 <설계문서>/<함수묶음> 사이라면 [중복] 으로 보고 추가하지 않는다.
            //   아니라면 [추가].
            //
            //}-----------------------------------------------------------------------------

            STR_Search_LineStr_knowLineCount(fileBuf, 0, innerPathNameExt, &searchLineNumber);

            //이 경우는 중복으로 보고 추가하지 않는다.
            if((lineNumber_C <= searchLineNumber) && (searchLineNumber <= lineNumber_Glib)) continue;

        //}

        //[추가]
        //{
            //[2018.10.15.월][수정!!!]{------------------------------------------------------------------
            //
            //1) [끼워넣을 위치<lineNumber_Insert>] 가 존재한다면(<-1> 이 아닌 경우) 이 위치에 끼워넣기.
            //
            //2) 존재하지 않는(<-1> 인 경우)다면 <설계문서> 제일 뒤에 추가.
            //
            //}------------------------------------------------------------------------------------------

            if((lineNumber_C < lineNumber_Insert) && (lineNumber_Insert < lineNumber_Glib))
            {
              //끼워넣을 위치가 있으므로 여기에 끼워넣기.
              STR_InsertLineStr(&fileBuf, lineNumber_Insert, innerPathNameExt, NULL, NULL, NULL);

            }
            else
            {
              //끼워넣을 위치가 없으므로 <설계문서> 마지막에 추가.

              //"<함수묶음>" 위치가 [설계문서:끝] 이 되므로 이 위치에 끼워넣는다.
              STR_InsertLineStr(&fileBuf, lineNumber_Glib, innerPathNameExt, NULL, NULL, NULL);
            }

            //해당 위치에 한개를 끼워 넣었으므로 행 위치 수정.
            lineNumber_Glib++;

            //[추가 항목수 기록]
            //{
                //[2018.10.13.토][추가!!!]{------------------------------------------------------
                //<i> 값의 경우는 위에서 [중복] 되는 경우 [추가] 되지 않아서 정확한 값이 아니다.
                //따라서, [중복] 된 경우는 제외하고 반드시 [추가] 된 경우만 [추가:개수] 로 기록.
                //}------------------------------------------------------------------------------

                addItemCount++;

            //}

        //}

        lbContinue:
        
      }
      
  //}
  
  //[<설계문서> 개수 수정]
  //{
      //[문서 개수 얻기]
      //{
          //"<설계문서>" 다음 행의  8자리 10진수로 된 [문서개수] 문자열 얻기.
          STR_Get_LineStr_withLineNumber(fileBuf, lineNumber_C + 1, tempStr);

          //값으로 변환.
          CONV_DecStr_To_IntVal(tempStr, &count);

          //순수하게 추가한 항목수(중복된 것은 포함되지 않음)만 더해서 개수 수정.
          count += addItemCount;
          
      //}

      //[개수 수정/문자열 변환]
      //{
          CONV_LongVal_To_Str(count, 8, false, tempStr);

      //}

      //[문서개수 수정]
      //{
          STR_ReplaceLineStr(&fileBuf, lineNumber_C + 1, tempStr, NULL, NULL, NULL);

      //}

  //}

  //[설계묶음:저장]
  //{
      //내용이 수정된 [설계묶음] 을 다시 저장.
      FILE_Save(pGprj_PathNameExt,(unsigned char *)fileBuf, STR_Length(fileBuf));

  //}

  lbOk:
  //{
      //저장 공간 삭제.
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }
      
      return(true);
      
  //}
  
  lbError:
  //{
      //저장 공간 삭제.
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }
      
      return(false);
      
  //}  

}

bool __fastcall Ide_GprjFile_Add_Glib(char  *pGprj_PathNameExt,
                                      //[함수묶음] 은 단지 [이름] 만 사용(확장자도 불필요).
                                      char  *pGlib_Name_List)
{
  //[2018.10.09.화][생성!!!]{----------------------------------------
  //[설계묶음<*.gprj> 문서 자체에 <*.c> 추가.
  //
  //1) 문서열기.
  //2) <함수묶음> 목록에 <*.glib> 끼워넣기.
  //3) 개수 수정.
  //
  //[2018.10.12.금][중요수정!!!]-------------------------------------
  //내부 적으로 물리적인 하드디스크를 대상으로 [열기/저장] 을 하므로
  //연속적으로 사용시 하드디스크 접근 오류가 발생한다.
  //따라서, 목록을 전달받아서 한번에 처리하는 것으로 수정.
  //}----------------------------------------------------------------

  //[설계묶음:구조]{-----------------------------------------
  //
  //<설계문서>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  //main.c
  // ...
  //
  //<함수묶음>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  //glib\IDE\API_Ide_Gvms\_Ide_가상기계_실행이름확장자_.glib
  // ...
  //
  //<참고자료>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  // ...
  //
  //<가상기계>
  //xxxxxxxx  //문서 개수(8자리 10진수 표기).
  // ...
  //
  //<끝>
  //}--------------------------------------------------------

  //[VAR]
  //{
      char  *fileBuf = NULL;

      int    fileSize;

      char   tempStr[1024];

      int    lineNumber_Glib = -1;
      int    lineNumber_Etc  = -1;

      int    searchLineNumber = -1;

      //[설계묶음<*.gprj>] 의 [경로].
      char   gprjPath[1024];

      //[설계묶음] 내부 [경로이름확장자].
      char   glibPathNameExt[1024];

      //[2018.10.12.금][추가!!!]
      char   list_Name[1024];
      char   searchPath[1024];
      char   lineStr[1024];
      int    lineCount;
      int    count;
      int    i;
      int    m;

      TStringList  *list = NULL;

      class  DATABASE  *db_;

      //[2018.10.13.토][추가!!!]
      //순수하게 추가된 항목수.
      int    addItemCount = 0;

  //}

  //[<*.gprj> 문서 열기]
  //{
      //[문서 존재 확인]
      //{
          if(FileExists(pGprj_PathNameExt) != true) { return(false); }

      //}

      //[<*.gprj> 인지 확인]
      //{
          STR_GetFileExt(pGprj_PathNameExt, tempStr);

          if(STR_Match_NoCase(tempStr, "gprj") != true)
          {
            //[설계묶음] 에 해당하지 않는 것이므로 오류.
            return(false);

          }

      //}

  //}

  //[문서 열기]
  //{
      if(FILE_Open(pGprj_PathNameExt, (unsigned char **)(&fileBuf), &fileSize) != true) goto lbError;

      //[참고!!!]{************************************************************************
      //여기서는 [설계묶음] 문서 크기만큼 <fileBuf> 가 생성되지만 추가하는데 문제가 없다.
      //<STR_InsertLineStr()> 에서 추가시 <fileBuf> 를 자동적으로 화장하고 포인터를
      //[재설정] 하기 때문.
      //}*********************************************************************************

  //}

  //[행번호 얻기]
  //{
      //[!]{---------------------------------------------------------------------
      //<함수묶음>, <참고자료> 의 행번호를 미리 구한다.
      //여기서 미리 구해도 [개수] 부분 위치는 추가후에도 변경되지 않으므로 무관.
      //}------------------------------------------------------------------------

      //["<함수묶음>" 찿기]
      //{
          STR_Search_LineStr_knowLineCount(fileBuf, 0, "<함수묶음>", &lineNumber_Glib);

      //}

      //["<참고자료>" 찾기]
      //{
          STR_Search_LineStr_knowLineCount(fileBuf, 0, "<참고자료>", &lineNumber_Etc);

      //}

  //}

  //[<*.glib> 문서 추가]
  //{
      //[2018.10.12.금][수정!!!]{--------------
      //[목록] 을 전달 받아서 한번에 처리한다.
      //[목록] 은 [행:단위] 로 정리돼 있다.
      //}--------------------------------------

      DATABASE_GetPtr(&db_);

      list = new TStringList;

      //[목록] 의 총행수 얻기.
      lineCount = STR_Get_LineCount(pGlib_Name_List);

      //[<*.glib> 목록 수집]
      //{
          //[중요!!!][2018.10.12.금][수정!!!]{----------------------------
          //디스크에 직접 접근하는 <Dir_Search_File()> 등의 함수는
          //논리적으로 연속적인 빠른 접근시 I/O 오류가 발생한다.
          //따라서, 디스크에 접근하는 <Dir_Search_File()> 는 여기서
          //[한번] 만 사용해서 <*.glib> 목록 전체를 수집하고
          //다음에서 [수집된 목록] 을 기준으로 검색 처리하는 것으로 수정.
          //}-------------------------------------------------------------

          //<*.glib> 검사경로 합성.
          //"[맷돌-IDE]\glib\..."  가 검사 대상.
          STR_Add_AB(searchPath, db_->programpath, "glib\\");

          //초기화.
          list->Clear();

          //<*.glib> 에 해당하는 모든 항목이 대상.
          Dir_Search_File(searchPath, "*", "glib",
                          false,               //모든 하위 폴더까지 검사.
                          false,               //[폴더] 는 대상으로 하지 않는다.
                          true,                //[파일] 대상.
                          false, false, false, //전체 [경로이름확장자] 다 수집.
                          list);

      //}

      for(i = 0, addItemCount = 0; i < lineCount; i++)
      { 
        //[행 추출]
        //{
            //한개 행은[함수묶음] 의 [이름] 이 된다.
            STR_Get_LineStr_withLineNumber(pGlib_Name_List, i, lineStr);

        //}

        //[<list> 에서 검색]
        //{
            //[2018.10.12.금][추가!!!]{---------------------------------------------------
            //<*.glib> 수집목록에서 검색.
            //<lineStr> : [이름] 만 들어 있음.
            //<list>    : "[맷돌-IDE]\glib\...\...\이름.glib" 까지 전체 [경로이름확장자].
            //
            //[함수묶음:이름] 은 절대 [중복] 되지 않는다.
            //
            //[방법!!!]-------------------------------------------------------------------
            //1) <list> 행 추출.
            //2) [이름] 만 추출.
            //3) <lineStr> 과 [이름] 비교.
            //4) 3) 이 일치하는 경우 <list> 행 설계묶음에 추가.
            //}---------------------------------------------------------------------------

			for(m = 0; m < list->Count; m++)
			{
			  //<list> 행(경로이름확장자) 에서 [이름] 추출.
			  STR_GetFileNameOnly_ExceptExt(((AnsiString)(list->Strings[m])).c_str(), list_Name);

              //[주의!!!]{-----------------------------------------------------------------
              //<pGlib_Name_List> 의 끝에 "\r\n" 만 있는 NULL 행인 경우가 있을수 있으므로.
              //이 경우는 무시하고 계속 검사.
              //단, 다음에 비교하는 부분에 닿으면 오류가 되므로 이 부분에서 넘긴다.
              //절대 <continue> 를 사용시 그대로 for 를 종료하여 결국 [일치하지않음:오류]
              //로 인식되므로 아예 [추가] 부분 까지 건너뛰도록 한다.
              if(STR_Match_NoCase(lineStr, "") == true) goto lbContinue;
              //}--------------------------------------------------------------------------

              //<lineStr> 과 [이름] 일치 확인.
              if(STR_Match_NoCase(lineStr, list_Name) == true)
              {
                //[!]{--------------------------------------------
                //[일치] 하는 것을 찾았다면 기록후 다음으로 진행.
                //}-----------------------------------------------

                //[추가할 문자열로 변경]
                //{
                    //[!]{-----------------------------------------------
                    //<list> 에는 전체 [경로이름확장자] 가 들어 있으므로
                    //"glib\...\...\이름.glib" 와 같은 형식으로 변경.
                    //[맷돌-IDE] 경로를 제외시킨다.
                    //}--------------------------------------------------
                    
                    STR_GetFileName_Except_BaseDirectory(db_->programpath,
                                                         ((AnsiString)(list->Strings[m])).c_str(),
                                                         glibPathNameExt);

                //}
                
                goto lbAdd;

              }

            }

            //여기까지 온것은 찾지 못한 것으로 오류.
            goto lbError;

        //}

        lbAdd:

        //[중복 검사]
        //{
            //[2018.10.11.목][추가!!!]{----------------------------------------------------
            //
            //1) 전체를 대상으로 일치하는 문자열 찾기.
            //
            //2) 찾은 행이 <함수묶음>/<참고자료> 사이라면 [중복] 으로 보고 추가하지 않는다.
            //   아니라면 [추가].
            //
            //}-----------------------------------------------------------------------------

            STR_Search_LineStr_knowLineCount(fileBuf, 0, glibPathNameExt, &searchLineNumber);

            //이 경우는 중복으로 보고 추가하지 않는다.
            if((lineNumber_Glib <= searchLineNumber) && (searchLineNumber <= lineNumber_Etc)) continue;

        //}

        //[추가]
        //{
            //"<참고자료>" 위치가 [함수묶음:끝] 이 되므로, 이 위치에 끼워넣는다.
            STR_InsertLineStr(&fileBuf, lineNumber_Etc, glibPathNameExt, NULL, NULL, NULL);

            //해당 위치에 한개를 끼워 넣었으므로 행 위치 수정.
            lineNumber_Etc++;

            //[추가 항목수 기록]
            //{
                //[2018.10.13.토][추가!!!]{------------------------------------------------------
                //<i> 값의 경우는 위에서 [중복] 되는 경우 [추가] 되지 않아서 정확한 값이 아니다.
                //따라서, [중복] 된 경우는 제외하고 반드시 [추가] 된 경우만 [추가:개수] 로 기록.
                //}------------------------------------------------------------------------------

                addItemCount++;

            //}

        //}

        lbContinue:

      }

  //}
  
  //[<함수묶음> 개수 수정]
  //{
      //[문서 개수 얻기]
      //{
          //"<함수묶음>" 다음 행의  8자리 10진수로 된 [문서개수] 문자열 얻기.
          STR_Get_LineStr_withLineNumber(fileBuf, lineNumber_Glib + 1, tempStr);

          //값으로 변환.
          CONV_DecStr_To_IntVal(tempStr, &count);
          
          //순수하게 추가한 항목수(중복된 것은 포함되지 않음)만 더해서 개수 수정.
          count += addItemCount;
          
      //}

      //[개수 수정/문자열 변환]
      //{
          CONV_LongVal_To_Str(count, 8, false, tempStr);

      //}

      //[문서개수 수정]
      //{
          STR_ReplaceLineStr(&fileBuf, lineNumber_Glib + 1, tempStr, NULL, NULL, NULL);

      //}

  //}

  //[설계묶음:저장]
  //{
      //내용이 수정된 [설계묶음] 을 다시 저장.
      FILE_Save(pGprj_PathNameExt,(unsigned char *)fileBuf, STR_Length(fileBuf));

  //}
  
  lbOk:
  //{
      //저장 공간 삭제.
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }
      if(list != NULL)    { delete list;       list    = NULL; }

      return(true);

  //}

  lbError:
  //{
      //저장 공간 삭제.
      if(fileBuf != NULL) { delete [] fileBuf; fileBuf = NULL; }
      if(list != NULL)    { delete list;       list    = NULL; }

      return(false);
      
  //}

}

//------------------------------------------------------------------------------
//[설계묶음 마법사 관련]--------------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_Project_Wizard(//[설계묶음 마법사] 에서 생성할 [설계묶음] 이름(경로가 없는 순수 이름).
                                   char   *pWizardName)
{
  //[2009.05.27.수][생성!!!]{----------------------------------------------------
  //이 함수는 [설계묶음 마법사] 에서 생성할 [설계묶음] 을 선택한 경우 호출된다.
  //대화상자를 보여주고 사용자가 지정한 위치에 생성해 준다.
  //
  //[2012.03.27.화][추가!!!]-----------------------------------------------------
  //[마법사:대화상자] 의 [미리보기] 기능을 지원하기 위한것.
  //
  //[2018.05.02.수][수정!!!]-----------------------------------------------------
  //[마법사] 에 GUI 관련 부분이 추가 됐는데 GUI 의 경우는 <__Main.c> 에서 사용자
  //GUI 구현이 시작되므로 <main.c> 대신에 <__Main.c> 를 열어 준다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      //전체 경로를 가진다.
      char   fileFullName[OPT_lineStrSize];

      //[2018.05.02.수][추가!!!]{--------------
      char   fileFullNameGui[OPT_lineStrSize];
      //}--------------------------------------

      //사용자가 지정한 <*.gprj> 의 실제 생성된 [폴더] 까지의 위치를 갖는다.
      char   gprjPath[OPT_lineStrSize];

      //순수한 <*.gprj> 의 [확장자] 를 제외한 순수한 [이름] 만 갖는다.
      char   gprjNameOnly[OPT_wordStrSize];

      //생성된 [설계묶음] 폴더 안에 <*.gprj> 이름을 추출한다.
      TStringList  *fileList = new TStringList;

  //}


  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[현재 열려있는 문서 다시 한번 닫기]
  //{
      //[2012.03.27.화][추가!!!]{---------------------------------------
      //[마법사:대화상자] 가 [모달] 이 아닌 일반 보이기로 열리기 때문에
      //[마법사:대화상자] 에 새로 적용된 [<main.c> 미리보기] 기능으로
      //해당 <main.c> 가 [편집기] 에 열려있을수 있다.
      //여기서 다시 한번 [편집기] 에 열려있는 문서를 닫아준다.
      //
      //이는 [안전] 상 조치.
      //}---------------------------------------------------------------

      editor_top_Form->_List_DeleteAll();

  //}

  //[저장 대화 상자 보이기]
  //{
      //[2009.05.28.목][추가!!!]{----------------------------------------------------------------
      //현재 [새설계묶음] 상태이므로 <*.gprj> 로 저장 할수 있도록 [저장 대화 상자] 를 보여 준다.
      //[마법사] 로 [설계묶음] 을 새로 생성하는 것이므로 대화상자를 열어준다.
      //}----------------------------------------------------------------------------------------

      //[확장자 설정]{--------------------------------------
      main_Form->file_SaveDialog->Filter = "*.gprj|*.gprj";
      //}---------------------------------------------------

      if(main_Form->file_SaveDialog->Execute() != true)
      {
        if(fileList != NULL) { delete fileList; fileList = NULL; }

        return(false);

      }

      //[설계묶음] 경로를 얻는다.
	  STR_Assign(fileFullName, ((AnsiString)main_Form->file_SaveDialog->FileName).c_str());

  //}

  //[경로 만들기]
  //{
      //[!]{----------------------------------------------------------------------------
      //현재 얻는 [설계묶음] 의 경로는 바로 사용할수 없는 것으로 이는 이 위치에 일단
      //사용자가 지정한 [설계묶음 이름] 에 해당하는 폴더를 먼저 생성해야 하기 때문이다.
      //실제 사용자가 지정한 [설계묶음] 은 이 이름과 같은 폴더안에 위치하게 된다.
      //}-------------------------------------------------------------------------------

      //[문서 이름 분리]
      //{
          //[!]{---------------------------------------------------------------------------
          //일단 "...\설계묶음이름.gprj" 에서 "...\" 와 "설계묶음이름.gprj" 를 분리시킨다.
          //이는 사용자가 지정한 [설계묶음] 에 해당하는 폴더를 만들어 주기 위한 것이다.
          //[폴더] 를 생성하기 위하여 순수한 [설계묶음이름] 만 얻는다.
          //}------------------------------------------------------------------------------

          //"...\" 부분 추출.
          STR_GetFilePathOnly(fileFullName, gprjPath);

          //"설계묶음이름" 만 부분 추출(순수한 [이름] 만 얻는다).
          STR_GetFileNameOnly_ExceptExt(fileFullName, gprjNameOnly);

      //}

      //[생성할 폴더 경로 만들기]
      //{
          //위에서 구한 정보를 바탕으로 생성할 [폴더] 의 경로를 만든다.
          //이미 구한 위치에 현재 [설계묶음 이름] 에 해당하는 [디렉토리 이름] 를 추가하면 된다.
          STR_Add(gprjPath, gprjNameOnly);

          //반드시 붙여 주어야 한다.
          STR_Add(gprjPath, "\\");

      //}

  //}

  //[폴더생성]
  //{
      //[설계묶음] 을 저장할 [폴더] 를 생성한다.
      File_CreateDirectory(gprjPath);

  //}

  //[마법사 설계묶음 복사]
  //{
      //생성된 폴더로 사용자가 선택한 마법사 [설계묶음] 을 [복사] 한다.
      Dir_Copy(gprjPath, Ide_WizardFolderPath + (AnsiString)pWizardName + "\\");

  //}

  //[<*.gprj> 문서 이름 얻기]
  //{
      //복사된 사용자 지정 [설계묶음] 폴더안의 <*.gprj> 의 목록을 얻는다.
      //[마법사] 의 [설계묶음] 은 꼭 [마법사 폴더] 이름과 같지 않으므로 일단 안의 <*.gprj> 문서 목록을 얻어야 한다.
      //항상 사용자 지정 이름으로 폴더를 먼저 생성하므로 한개밖에는 있을수가 없다.
      Dir_Get_FileList_BoundDir(gprjPath, "gprj", true, d_File, fileList);

  //}

  //[빈묶음인 경우]
  //{
      //[2009.06.06.토][추가!!!]{-------------------------------------------------------------
      //[설계묶음 마법사] 의 [빈묶음] 인 경우는 안에 아무것도 없으므로 다음의
      //RenameFile() 함수에서 오류가 발생한다.
      //따라서, [빈묶음] 인 경우는 여기서 종료하고 [설계묶음] 경로는 "" 로 초기화한다.
      //어차피 <*.gprj> 로 사용자가 저장할때 자동으로 다시 확정되므로 여기서는 초기화 시킨다.
      //}-------------------------------------------------------------------------------------

      if(fileList->Count <= 0)
      {
        //이 경우는 <*.gprj> 가 존재하지 않는 것이다.

        //[project 경로 저장]
        STR_Assign(database->projectname, "");

        //[project path 저장]
        STR_Assign(database->projectpath, "");

        goto END;

      }

  //}

  //[<*.gprj> 를 사용자 지정이름으로 수정]
  //{
      //[지정 이름 만들기]{----------------
      STR_Assign(fileFullName, gprjPath);
      STR_Add(fileFullName, gprjNameOnly);
      STR_Add(fileFullName, ".gprj");
      //}----------------------------------

      //복사된 [설계묶음] 의 이름을 사용자가 지정한 이름으로 바꾼다.
      RenameFile(fileList->Strings[0], fileFullName);

  //}

  //[경로 저장]
  //{
      //{DATABASE} 의 해당 정보에 경로를 기록해 준다.
      //관련 정보도 같이 처리해 준다.

      //[project 경로 저장]
      STR_Assign(database->projectname, fileFullName);

      //[project path 저장]
      STR_GetFilePathOnly(database->projectname, database->projectpath);

  //}

  //[설계묶음 열기]
  //{
      //[2018.05.02.수][수정!!!]{------------------------------------------------------
      //[마법사] 에 GUI 관련 추가됐음. GUI 는 <__Main.c> 부터 사용자 구현이 시작되므로
      //<main.c> 대신에 <__Main.c> 를 열어 준다.
      //
      //<__Main.c> 는 [설계묶음] 과 같은 위치에 있으므로 <__Main.c> 가 존재하는 경우는
      //이 문서를 열어준다.
      //}------------------------------------------------------------------------------

      //사용자 지정 위치에 [마법사] 로 생성된 [설계묶음] 을 사용하기 위하여 열어준다.
      IDE_Project_Open(fileFullName);

      //[기본/GUI 구분 처리]
      //{
          //[방법]{-------------------------------------------------------------------------
          //
          //1) [설계묵음] 위치에 <__Main.c> 가 있다면 GUI 로 보고 <__Main.c> 를 열어 준다.
          //
          //2) 1) 의 경우가 아니라면 <main.c> 를 열어 준다.
          //
          //}-------------------------------------------------------------------------------

          //[지정 이름 만들기]{------------------
          STR_Assign(fileFullNameGui, gprjPath);
          STR_Add(fileFullNameGui, "__Main.c");
          //}------------------------------------

          //파일 존재 확인.
          if(FileExists(fileFullNameGui) == true)
          {
            //<__Main.c> 열기.

            editor_top_Form->_List_Add(fileFullNameGui);
            
          }
          else
          {
            //<main.c> 열기.

            //[!]{----------------------------------------------------------
            //[설계묶음 마법사] 로 생성된 모든 것은 다 <main.c> 를 갖으므로
            //기본적으로 <main.c> 는 기본으로 열어준다.
            //이는 사용자의 편의를 위한 것이다.
            //}-------------------------------------------------------------

            //[지정 이름 만들기]{----------------
            STR_Assign(fileFullName, gprjPath);
            STR_Add(fileFullName, "main.c");
            //}----------------------------------

            editor_top_Form->_List_Add(fileFullName);

          }

      //}      

  //}

  END:

  //[삭제]
  //{
      if(fileList != NULL) { delete fileList; fileList = NULL; }

  //}

  return(true);

}

//------------------------------------------------------------------------------
//[기타 문서 관리]--------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_File_Close_DebugFiles(void)
{
  //[2009.05.15.금][생성!!!]{---------------------------------------------------------------
  //현재 열려있는 <*.gasm>, <*.gcsm> 문서를 전부 닫아준다.
  //이 함수는 [가상기계개발] => [개발검증] 로 전환시 자동 호출되며, 이렇게 하는 이유는
  //현재 문서 열기 체계가, 이미 열려있는 문서는 다시 열지 않으므로 수정된
  //<*.gasm>, <*gcsm> 이 다시 열리지 않아 수정/반영 된 문서가 열리지 않는 것을 방지하기
  //위한것이다.
  //문서 편집기에서 이미 [열기] 로 <*.gasm>, <*gcsm> 문서를 열었을수도 있으므로 반드시
  //[가상기계개발] => [개발검증] 으로 전환시 처리해 주어야 한다.
  //이는 항상 수정/반영된 새로운 <*.gasm>, <*gcsm> 문서를 [검증] 시에 사용하기 위한 것이다.
  //
  //[2011.05.31.화][중요수정!!!]------------------------------------------------------------
  //<*.glib> 문서도 자동으로 닫아 주어야 한다.
  //
  //함수 이름을 <Ide_File_Close_Gasm_Gcsm => Ide_File_Close_DebugFiles> 로 바꾼다.
  //}---------------------------------------------------------------------------------------

  //[VAR]
  //{
      char  fileExt[OPT_wordStrSize];

      int   i;

  //}

  for(i = 0; i < editor_edit_Form->_textinfo_count; )
  {
    //[확장자 얻기]{----------------------------------------------------------
    STR_GetFileExt(editor_edit_Form->_textinfo[i].filename.c_str(), fileExt);
    //}-----------------------------------------------------------------------

    if(STR_Match_NoCase(fileExt, "gasm") ||
       STR_Match_NoCase(fileExt, "gcsm") ||
       //[2011.05.31.화][추가!!!]
       STR_Match_NoCase(fileExt, "glib"))
    {
      //[주의!!!]{-----------------------------------------------------------
      //항상 눈에 보이는 문서만 삭제가능하므로 일단 다시 눈에 보이게 만든다.
      //이렇게 하지 않으면 현재 체계상 오류가 발생한다.
      editor_top_Form->_List_Add(editor_edit_Form->_textinfo[i].filename);
      //}--------------------------------------------------------------------

      //현재 문서를 삭제한다.
      editor_top_Form->_List_Delete(i);

    }
    else
    {
      i++;

    }

  }

  return;

}

void __fastcall Ide_File_Close_GlibSysHeader(void)
{
  //[2009.05.28.목][생성!!!]{------------------------------------------------------------
  //현재 열려있는 <함수묶음.h> 를 닫아 준다.
  //이 함수는 Ide_Glib_MakeHeader() 함수에서 호출되며, 새로운 <함수묶음.h> 문서가 만들어
  //지기 전에 항상 호출되어야 한다.
  //이는 이미 열려 있는 문서의 내용은 수정된 내용이 반영되지 않은 이전 것이기 때문이다.
  //이 상태에서 저장하는 경우는 새로 생성된 내용이 이전 내용으로 바뀌므로 안된다.
  //}------------------------------------------------------------------------------------

  //[VAR]
  //{
      char  fileNameOnly[OPT_wordStrSize];

      int   i;

  //}

  for(i = 0; i < editor_edit_Form->_textinfo_count; )
  {
    //[이름 얻기]{----------------------------------------------------------------------
    STR_GetFileNameOnly(editor_edit_Form->_textinfo[i].filename.c_str(), fileNameOnly);
    //}---------------------------------------------------------------------------------

    if(STR_Match_NoCase(fileNameOnly, "함수묶음.h"))
    {
      //[주의!!!]{-----------------------------------------------------------
      //항상 눈에 보이는 문서만 삭제가능하므로 일단 다시 눈에 보이게 만든다.
      //이렇게 하지 않으면 현재 체계상 오류가 발생한다.
      editor_top_Form->_List_Add(editor_edit_Form->_textinfo[i].filename);
      //}--------------------------------------------------------------------

      //현재 문서를 삭제한다.
      editor_top_Form->_List_Delete(i);

      //이 문서는 한개밖에 없으므로 여기서 종료한다.
      return;

    }
    else
    {
      i++;

    }

  }

  return;

}

void __fastcall Ide_File_Close_GlibGtxt(//[2011.05.09.월][추가!!!]
                                        //닫아줄 문서전체이름.
                                        char  *pCloseFilelName)
{
  //[2009.05.30.토][생성!!!]{--------------------------------------------------------------
  //현재 열려있는 <함수묶음.gtxt> 를 닫아 준다.
  //이 함수는 Ide_Glib_MakeGtxt() 함수에서 호출되며, 새로운 <함수묶음.gtxt> 문서가 만들어
  //지기 전에 항상 호출되어야 한다.
  //이는 이미 열려 있는 문서의 내용은 수정된 내용이 반영되지 않은 이전 것이기 때문이다.
  //이 상태에서 저장하는 경우는 새로 생성된 내용이 이전 내용으로 바뀌므로 안된다.
  //
  //[2011.05.09.월][중요수정!!!]-----------------------------------------------------------
  //[Tree:함수묶음] 이 이전의 [경로] 방식에서 [Tree 구조] 방식으로 변경되었으므로
  //이에 맞게 수정한다.
  //지정한 [문서] 을 닫아주는 것으로 수정한다.
  //단, [전체 문서 경로] 를 대상으로 일치해야 한다.
  //자세한 내용은 <Ide_Glib_MakeGtxt()> 함수의 설명을 참고한다.
  //}--------------------------------------------------------------------------------------

  //[VAR]
  //{
      int   i;

  //}

  for(i = 0; i < editor_edit_Form->_textinfo_count; )
  {
    if(STR_Match_NoCase(editor_edit_Form->_textinfo[i].filename.c_str(), pCloseFilelName))
    {
      //[주의!!!]{-----------------------------------------------------------
      //항상 눈에 보이는 문서만 삭제가능하므로 일단 다시 눈에 보이게 만든다.
      //이렇게 하지 않으면 현재 체계상 오류가 발생한다.
      editor_top_Form->_List_Add(editor_edit_Form->_textinfo[i].filename);
      //}--------------------------------------------------------------------

      //현재 문서를 삭제한다.
      editor_top_Form->_List_Delete(i);

      //이 문서는 한개밖에 없으므로 여기서 종료한다.
      return;

    }
    else
    {
      i++;

    }

  }

  return;

}

//------------------------------------------------------------------------------
//[정보창 처리 관련]------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall IDE_Tree_Item_DoubleClick(void)
{
  //[2009.01.30.금][생성]{--------------------------------------------------------
  //정보창의 선택 항목의 [더블클릭] 의 경우를 처리한다.
  //이 함수는 <tree_tree.cpp> 안의 [더블클릭] [동작함수] 에서 호출되어 처리된다.
  //
  //[2009.05.28.목][수정!!!]------------------------------------------------------
  //[함수묶음] 이 대상인 경우는 같은 위치/이름의 <*.gtxt> 문서를 열어준다.
  //이 문서는 해당 <*.glib> 의 설명을 담고 있는 문서이며 <*.c> 와 같은 [색동문자]
  //기능을 가진다.
  //
  //[2011.05.06.금][중요수정!!!]--------------------------------------------------
  //[설계묶음] 안의 [함수묶음] 의 경우도 [API] 처럼, <*.gtxt> 문서가 없는 경우는
  //무조건 <*.h> 문서를 보여주도록 만든다.
  //
  //[2012.03.18.일][추가!!!]------------------------------------------------------
  //[Tree:설계묶음:가상기계] 항목 처리 추가.
  //
  //[2019.02.17.일][추가]---------------------------------------------------------
  //[Tree:전체찾기] 관련 추가.
  //
  //[2022.06.24.금][추가]---------------------------------------------------------
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      struct TREE   *tree;

      int    nodeItemIndex;
      int    nodeLastItemIndex;

      char   fileName[OPT_filepath_length];
      char   tempStr[OPT_lineStrSize];
      char   fileExt[OPT_wordStrSize];

      //[2011.05.09.월][추가!!!]
      int    nodeIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 아예 처리 하지 않아야 한다.
      if(tree_tree_Form->_tree[tree_tree_Form->_tree_select_index].select_itemindex < 0) return;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[선택된 것의 처리]
  //{
      switch(tree_tree_Form->_tree_select_index)
      {
        case  d_TREE_project : //[설계묶음]
        {
          //[!]{------------------------------------------------------------------
          //선택된 항목이 속한 [옹이] 를 판별하여 각각 다른 처리를 해주어야 한다.
          //}---------------------------------------------------------------------

          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_project]);

          //}

          //[[설계문서] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex < tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                //<*.c> 와 <*.h> 만 해당하므로 바로 [편집기] 에서 열어 준다.

                //[문서 경로 합성]
                //{
                    //전체 [문서 경로] 를 만들어 준다.
                    STR_Add_AB(fileName, database->projectpath,
                               //[2012.04.20.금][수정!!!]
                               tree_tree_Form->_Item_Txt_StrPtr3(tree, tree->select_itemindex));

                //}

                //[편집기에 열어주기]
                //{
                    //파일을 열어준다.
                    editor_top_Form->_List_Add((AnsiString)fileName);

                //}

                break;

              }

          //}

          //[<Tree:함수묶음> 에 해당하는가?]
          //{
              //[2011.05.09.월][중요수정!!!]{-----------------------------------------------------
              //[Tree:함수묶음] 이 이전의 [경로] 방식에서 [Tree 구조] 방식으로 변환되었으므로
              //이에 맞게 전부다 수정한다.
              //더불어, [Tree:API] 와 같이 [옹이] 의 경우는 하위 모든 항목의 <*.gtxt> 를 합성하여
              //새로운 문서를 만들고 이를 열어서 보여주는 방식으로 변환한다.
              //}---------------------------------------------------------------------------------

              //[<옹이> 정보 얻기]
              //{
                  tree_tree_Form->_Tree_Get_Node_LastItemIndex2
                                  (tree,
                                   //[Tree:함수묶음] 의 <name>.
                                   "glib",
                                   &nodeItemIndex,
                                   NULL,
                                   //이 [옹이] 의 가장 마지막 하위항목의 [절대위치].
                                   &nodeLastItemIndex);

              //}

              //[Tree:함수묶음] 영역안만을 대상으로 처리한다
              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                //[!]{------------------------------------------------------------------------------------------------
                //[옹이,<*.glib>, <*.h> 인 경우 3가지로 구분하여 처리한다.
                //
                //[옹이]   : <Ide_Tree_Api_Glib_MakeGtxt()> 함수로 하위 모든 항목의 <*.gtxt> 를
                //           합성하여 [옹이<txt>.gtxt] 문서를 만들어 주고 이 문서의 [전체 경로] 를 전달받아 열어준다.
                //
                //<*.glib> : 대응하는 <*.gtxt> 문서를 열어준다.
                //           단, 대응하는 <*.gtxt> 가 존재하지 않는 경우는 해당 <*.h> 를 열어준다.
                //
                //<*.h>    : 반드시 <*.glib> 의 하위 항목으로 등록돼 있으므로 <*glib> 의 경로를 합성후
                //           확장자를 <*.h> 로 만들고 이 문서를 열어준다.
                //}---------------------------------------------------------------------------------------------------

                //[확장자 추출]
                //{
                    //3종류를 구분하기 위하여 [항목<txt>] 의 [확장자] 를 추출한다.
                    //[2012.04.20.금][수정!!!]
                    STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, tree->select_itemindex), tempStr);

                //}

                //[확장자] 에 따라 처리한다.
                if     (STR_Match_NoCase(tempStr, "glib") == true)
                {
                  //[!]{----------------------------------------------------
                  //<*.glib> 인 경우이다.
                  //1) 해당하는 <*.gtxt> 가 존재한다면 이 문서를 열어준다.
                  //2) <*.gtxt> 가 존재하지 않는다면 <*.h> 문서를 열어준다.
                  //}-------------------------------------------------------

                  //[설계묶음 내부 경로추출]
                  //{
                      //현재 <*.glib> 항목의 [설계묶음 내부 경로] 를 합성한다.
                      Ide_Project_Glib_Make_InFileName(tree, tree->select_itemindex, fileName);

                  //}

                  //[<*.gtxt> 로 확장자 변환]
                  //{
                      STR_ChangeFileExt(fileName, "gtxt", tempStr);

                  //}

                  //[전체 문서 경로 합성]
                  //{
                      //전체 [문서 경로] 를 만들어 준다.
                      STR_Add_AB(fileName, database->projectpath, tempStr);

                  //}

                  //[<*.gtxt>] 문서가 존재하나?]
                  //{
                      //<*.gtxt> 문서가 존재하지 않는 경우는 대응하는 <*.h> 를 열어야 한다.
                      //<*.h> 문서는 <*.glib> 와 항상 같이 존재한다.

                      if(FileExists(fileName) != true)
                      {
                        //<*.h> 로 [확장자] 를 바꿔준다.
                        STR_ChangeFileExt(fileName, "h", tempStr);

                        //<fileName> 으로 문서를 열기 때문에 다시 여기에 할당한다.
                        STR_Assign(fileName, tempStr);

                      }

                  //}

                  //[편집기에 열어주기]
                  //{
                      editor_top_Form->_List_Add((AnsiString)fileName);

                  //}

                }
                else if(STR_Match_NoCase(tempStr, "h") == true)
                {
                  //[!]{-------------------------------------------------------------------
                  //<*.h> 인 경우다.
                  //그냥 해당 문서를 열어주면 된다.
                  //단, <*.glib> 문서의 경로를 바탕으로 [경로] 를 얻은뒤 다시 <*.h> 로
                  //[확장자] 를 변환하여 이 문서를 열어야 한다.
                  //이는 <*.glib> 항목으로 [경로] 를 추출하는 함수를 활용하기 위한 것이다.
                  //}----------------------------------------------------------------------

                  //[<*.glib> 위치 얻기]
                  //{
                      //<*.glib> 문서는 항상 <*.h> 에 1:1 로 대응하고 바로 [직계옹이] 가 된다.
                      //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 를 구한다.
                      tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                                      (tree,
                                       //현재 항목의 [절대위치].
                                       tree->select_itemindex,
                                       //직계 [옹이] 의 [절대위치].
                                       &nodeIndex);

                  //}

                  //[설계묶음 내부 경로추출]
                  //{
                      //현재 <*.glib> 항목의 [설계묶음 내부 경로] 를 합성한다.
                      Ide_Project_Glib_Make_InFileName(tree, nodeIndex, fileName);

                  //}

                  //[<*.h> 로 확장자 변환]
                  //{
                      STR_ChangeFileExt(fileName, "h", tempStr);

                  //}

                  //[전체 문서 경로 합성]
                  //{
                      //전체 [문서 경로] 를 만들어 준다.
                      STR_Add_AB(fileName, database->projectpath, tempStr);

                  //}

                  //[편집기에 열어주기]
                  //{
                      editor_top_Form->_List_Add((AnsiString)fileName);

                  //}

                }
                else if(tempStr[0] == '\0')
                {
                  //[!]{------------------------------------------------------------------
                  //[옹이] 에 해당하는 경우다.
                  //<Ide_Tree_Api_Glib_MakeGtxt()> 함수로 하위 모든 항목의 <*.gtxt> 를
                  //합성하여 [옹이<txt>.gtxt] 문서를 만들어 주고 이 문서의 [전체 경로] 를
                  //전달받아 열어준다.
                  //}---------------------------------------------------------------------

                  //<*.gtxt> 문서를 생성하고 이 문서의 [전체경로] 를 반환한다.
                  Ide_Glib_MakeGtxt(tree->select_itemindex, fileName);

                  //[편집기에 열어주기]
                  //{
                      editor_top_Form->_List_Add((AnsiString)fileName);

                  //}

                }
                else
                {
                  //해당하지 않는 경우는 바로 종료한다.
                  return;

                }

              }

          //}

          //[[Tree:참고문서] 에 해당하는가?]
          //{
              //[2012.03.17.토][수정!!!]{-------------------------------------
              //[맷돌-IDE] 에서 열수 있는 종류의 문서는 [맷돌-IDE] 에서 열기.
              //나머지는 <ShellExecute()> API 를 사용하여 처리.
              //}-------------------------------------------------------------

              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "etc", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex < tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                //[문서 경로 합성]
                //{
                    //전체 [문서 경로] 를 만들어 준다.
                    //[2012.04.20.금][수정!!!]
                    STR_Add_AB(fileName, database->projectpath,
                               tree_tree_Form->_Item_Txt_StrPtr3(tree, tree->select_itemindex));

                //}

                //[문서 종류 구분 처리]
                //{
                    //[2012.03.17.토][수정!!!]{--------------------------------
                    //1) [맷돌-IDE] 에서 열수 있는 문서.
                    //   [맷돌-IDE] 에서 직접 열어준다.
                    //
                    //2) 1) 에 해당하지 않는 모든 문서는 [외부실행] 으로 연다.
                    //
                    //[확장자] 로 간단하게 구분.
                    //}--------------------------------------------------------

                    //[확장자 추출]
                    //{
                        STR_GetFileExt(fileName, tempStr);

                    //}

                    //[!]{-----------------------------------------------------------
                    //[확장자 목록 문자열] 에서 [확장자] 를 찾을수 있다면 처리 가능.
                    //}--------------------------------------------------------------

                    if(STR_Search_MatchWord_inLineStr(Ide_FileExtList, tempStr, true) > 0)
                    {
                      //[!]{---------------------------------
                      //[맷돌-IDE] 에서 직접 열수 있는 문서.
                      //}------------------------------------

                      editor_top_Form->_List_Add(fileName);

                    }
                    else
                    {
                      //[!]{------------------------------------------------
                      //[맷돌-IDE] 에서 열수 없으므로 [외부실행] 으로 열기.
                      //}---------------------------------------------------

                      //[확장자 연결로 열기]
                      //{
                          //어떤 문서이든 해당 확장자에 연결된 프로그램으로 자동적으로 열어준다.
                          //이것은 직접 해당 문서를 마우스로 더블클릭하여 열어 주는 것과 같다.
                          ShellExecute(0, "open", fileName, "", "", SW_NORMAL);

                      //}

                    }

                //}

                break;

              }

          //}

          //[<Tree:가상기계> 에 해당하는가?]
          //{
              //[2012.03.17.토][추가!!!]{------------------------------------
              //[<*.gvms>/<*.gvmx>] 인 경우와 [일반항목] 의 경우를 구분처리.
              //
              //[맷돌-IDE] 에서 열수 있는 종류의 문서는 [맷돌-IDE] 에서 열기.
              //}-------------------------------------------------------------

              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "gvm", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex < tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                //[구분!!!]{-----------------------------------------------------
                //1) <*.gvms> : [가상기계 전용 환경] 으로 실행.
                //
                //2) <*.gvmx> : [가상기계 전용 환경] 으로 맷돌(G.MTDL.X)에 설치.
                //
                //3) [맷돌-IDE] 에서 열수 있는 항목은 [맷돌-IDE] 에서 열기.
                //
                //4) 1)-3) 까지 해당하지 않는다면 [외부실행] 으로 열기.
                //
                //[확장자] 에 따라 경로 합성이 달라지므로 구분처리.
                //}--------------------------------------------------------------

                //[확장자 추출]
                //{
                    //[2012.04.20.금][수정!!!]
                    STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, tree->select_itemindex), fileExt);

                //}

                //[문서 종류 구분 처리]
                //{
                    if     (STR_Match_NoCase(fileExt, "gvms") == true)
                    {
                      //[!]{---------------------------------
                      //[가상기계 전용 환경] 으로 바로 실행.
                      //}------------------------------------

                      //[경로합성]
                      //{
                          //[설계묶음] 내부 [경로이름확장자] 얻기.
                          Ide_Project_Gvm_Make_InFileName(tree, tree->select_itemindex, tempStr);

                          //전체 [경로이름확장자] 합성.
                          STR_Add_AB(fileName, database->projectpath, tempStr);

                      //}

                      //[가상기계 실행]
                      //{
                          //<GVMS> 설치후 정지------------v
                          Ide_Menu_GVMS_Install(fileName, false);

                      //}

                    }
                    else if(STR_Match_NoCase(fileExt, "gvmx") == true)
                    {
                      //[!]{--------------------------------------------------
                      //[가상기계 전용 환경] 에서 맷돌(G.MTDL.X)에 바로 설치.
                      //}-----------------------------------------------------

                      //[경로합성]
                      //{
                          //[설계묶음] 내부 [경로이름확장자] 얻기.
                          Ide_Project_Gvm_Make_InFileName(tree, tree->select_itemindex, tempStr);

                          //전체 [경로이름확장자] 합성.
                          STR_Add_AB(fileName, database->projectpath, tempStr);

                      //}

                      //[가상기계 실행]
                      //{
                          //<GVMS> 설치후 정지----------------v
                          Ide_Tree_Gvm_GVMX_Install(fileName, false);

                      //}

                    }
                    else if(STR_Search_MatchWord_inLineStr(Ide_FileExtList, fileExt, true) > 0)
                    {
                      //[!]{----------------------------------------------------------------
                      //[확장자 목록 문자열] 에서 [확장자] 를 찾을수 있다면 [맷돌-IDE] 에서
                      //직접 열수 있는 문서.
                      //}-------------------------------------------------------------------

                      //[경로합성]
                      //{
                          //[설계묶음] 내부 [경로이름확장자] 얻기.
                          Ide_Project_Gvm_Make_InFileName(tree, tree->select_itemindex, tempStr);

                          //전체 [경로이름확장자] 합성.
                          STR_Add_AB(fileName, database->projectpath, tempStr);

                      //}

                      editor_top_Form->_List_Add(fileName);

                    }
                    else
                    {
                      //[!]{------------------------------------------------
                      //[맷돌-IDE] 에서 열수 없으므로 [외부실행] 으로 열기.
                      //단, [확장자] 가 없는 경우([경로(폴더)])는 제외.
                      //}---------------------------------------------------

                      if(STR_Match_NoCase(fileExt, "") != true)
                      {
                        //[경로합성]
                        //{
                            //[설계묶음] 내부 [경로이름확장자] 얻기.
                            Ide_Project_Gvm_Make_InFileName(tree, tree->select_itemindex, tempStr);

                            //전체 [경로이름확장자] 합성.
                            STR_Add_AB(fileName, database->projectpath, tempStr);

                        //}

                        //[확장자 연결로 열기]
                        //{
                            //어떤 문서이든 해당 확장자에 연결된 프로그램으로 자동적으로 열어준다.
                            //이것은 직접 해당 문서를 마우스로 더블클릭하여 열어 주는 것과 같다.
                            ShellExecute(0, "open", fileName, "", "", SW_NORMAL);

                        //}

                      }

                    }

                //}

                break;

              }

          //}
          
        } break;

        case  d_TREE_info : //[설계정보]
        {
          //[2009.02.14.토][추가!!!]{----------------
          //처리가 복잡 하므로 전용 함수로 처리한다.
          //}----------------------------------------

          Ide_TreeInfo_DoubleClick();

        } break;

        case  d_TREE_api : //[API]
        {
          //[2009.06.01.월][추가!!!]{---
          //해당 전용 함수로 처리한다.
          //}---------------------------

          Ide_Tree_Api_DoubleClick(d_TREE_api);

        } break;

        case  d_TREE_apiSrch : //[API]
        {
          //[2022.06.24.금][추가]{------
          //해당 전용 함수로 처리한다.
          //}---------------------------

          Ide_Tree_Api_DoubleClick(d_TREE_apiSrch);

        } break;

        case  d_TREE_find : //[전체찾기]
        {
          //[2019.02.17.일][추가]{---
          //해당 전용 함수로 처리.
          //}------------------------

          Ide_Tree_Find_DoubleClick();

        } break;

        case  d_TREE_system :
        {
          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_system]);

          //}

        } break;

        //[2011.07.19.화][추가!!!]
        case  d_TREE_dbgExp :
        {
          //[2011.07.19.화][추가!!!]{-----------------------------------------------------
          //[검증식 보기창] 의 기능을 처리한다.
          //
          //[2011.07.21.목][수정!!!]------------------------------------------------------
          //[자동검증] 시에는 [맷돌] 에 접근할때 <ACK> 를 인식 못하여 통신오류가
          //발생할수 있으므로 <Ide_Tree_DbgExp_DoubleClick()> 함수를 바로 사용하지 않고
          //<tree_tree.cpp> 에 정의된 <_DbgExp_DoubleClick()> 함수를 사용하여 처리한다.
          //이 <_DbgExp_DoubleClick()> 함수 안에서 <Ide_Tree_DbgExp_DoubleClick()> 함수를
          //호출하여 처리하게 된다.
          //}-----------------------------------------------------------------------------
          
          tree_tree_Form->_DbgExp_DoubleClick();

        } break;

      }

  //}

  return;

}

void __fastcall IDE_Tree_Item_Add(void)
{
  //[2009.02.02.월][생성]{-----------------------------
  //[정보창] 의 선택 항목의 [추가] 의 경우를 처리한다.
  //선택 항목의 [종류] 를 구분하여 처리해야 한다.
  //}--------------------------------------------------

  //[VAR]
  //{
      struct TREE   *tree;

      int    nodeItemIndex;
      int    nodeLastItemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 아예 처리 하지 않아야 한다.
      if(tree_tree_Form->_tree[tree_tree_Form->_tree_select_index].select_itemindex < 0) return;

  //}

  //[선택된 것의 처리]
  //{
      switch(tree_tree_Form->_tree_select_index)
      {
        case  d_TREE_project : //[설계묶음]
        {
          //[!]{------------------------------------------------------------------
          //선택된 항목이 속한 [옹이] 를 판별하여 각각 다른 처리를 해주어야 한다.
          //단, 다른 경우와 달리 해당 [옹이] 도 범위에 넣어야 한다.
          //원래는 [옹이] 를 선택하고 해당 [옹이] 의 항목을 추가 하는 것이므로.
          //}---------------------------------------------------------------------

          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_project]);

          //}

          //[[설계문서] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Add_C(NULL);

                break;

              }

          //}

          //[[함수묶음] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "glib", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Add_Glib(NULL);

                break;

              }

          //}

          //[[참고자료] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "etc", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Add_Etc(NULL);

                break;

              }

          //}

          //[[가상기계] 에 해당하는가?]
          //{
              //[2012.03.14.수][추가!!!]{------------------------------
              //[가상기계(GVMS/GVMX)] 를 바로 실행할수 있는 항목 추가.
              //}------------------------------------------------------

              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "gvm", &nodeItemIndex, NULL, &nodeLastItemIndex);

              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                Ide_Project_Add_Gvm(NULL);

                break;

              }

          //}

        } break;

        case  d_TREE_info : //[설계정보]
        {
          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_info]);

          //}

        } break;

        case  d_TREE_system : //[상태정보]
        {
          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_system]);

          //}

        } break;

      }

  //}

  return;

}

void __fastcall IDE_Tree_Item_Delete(void)
{
  //[2009.02.02.월][생성]{-----------------------------
  //[정보창] 의 선택 항목의 [삭제] 의 경우를 처리한다.
  //선택 항목의 [종류] 를 구분하여 처리해야 한다.
  //
  //[2012.03.16.금][추가!!!]---------------------------
  //[옹이:가상기계] 항목에 대한 처리 추가.
  //}--------------------------------------------------

  //[VAR]
  //{
      struct TREE   *tree;

      int    nodeItemIndex;
      int    nodeLastItemIndex;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 아예 처리 하지 않아야 한다.
      if(tree_tree_Form->_tree[tree_tree_Form->_tree_select_index].select_itemindex < 0) return;

  //}
  
  //[선택된 것의 처리]
  //{
      switch(tree_tree_Form->_tree_select_index)
      {
        case  d_TREE_project : //[설계묶음]
        {
          //[!]{------------------------------------------------------------------
          //선택된 항목이 속한 [옹이] 를 판별하여 각각 다른 처리를 해주어야 한다.
          //}---------------------------------------------------------------------

          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_project]);

          //}

          //[[설계문서] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "c", &nodeItemIndex, NULL, &nodeLastItemIndex);

              //[2011.05.10.화][중요수정!!!]{---------------------------------------------
              //[삭제] 의 경우 [Tree:설계문서] 도 일단 대상이 되므로 이것도 포함 시킨다.
              //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
              //즉, [Tree:설계문서] 을 완전히 비워주는 기능이다.
              //}-------------------------------------------------------------------------
              //-----------------v
              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Delete_C();

                break;

              }

          //}

          //[[함수묶음] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "glib", &nodeItemIndex, NULL, &nodeLastItemIndex);

              //[2011.05.10.화][중요수정!!!]{---------------------------------------------
              //[삭제] 의 경우 [Tree:함수묶음] 로 일단 대상이 되므로 이것도 포함 시킨다.
              //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
              //즉, [Tree:함수묶음] 을 완전히 비워주는 기능이다.
              //}-------------------------------------------------------------------------
              //-----------------v
              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Delete_Glib();

                break;

              }

          //}

          //[[참고문서] 에 해당하는가?]
          //{
              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "etc", &nodeItemIndex, NULL, &nodeLastItemIndex);

              //[2011.05.10.화][중요수정!!!]{---------------------------------------------
              //[삭제] 의 경우 [Tree:설계문서] 도 일단 대상이 되므로 이것도 포함 시킨다.
              //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
              //즉, [Tree:설계문서] 을 완전히 비워주는 기능이다.
              //}-------------------------------------------------------------------------
              //-----------------v
              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Delete_Etc();

                break;

              }

          //}

          //[<가상기계> 에 해당하는가?]
          //{
              //[2012.03.16.금][추가!!!]{--------------
              //[옹이:가상기계] 하위 항목의 삭제 처리.
              //}--------------------------------------

              tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "gvm", &nodeItemIndex, NULL, &nodeLastItemIndex);

              //[!]{----------------------------------------------------------------------
              //[삭제] 의 경우 [Tree:함수묶음] 로 일단 대상이 되므로 이것도 포함 시킨다.
              //이 경우는 [삭제] 시 [자신] 은 삭제되지 않으나, 하위 모든 항목을 삭제한다.
              //즉, [Tree:함수묶음] 을 완전히 비워주는 기능이다.
              //}-------------------------------------------------------------------------
              //-----------------v
              if((nodeItemIndex <= tree->select_itemindex) && (tree->select_itemindex <= nodeLastItemIndex))
              {
                IDE_Project_Delete_Gvm();

                break;

              }

          //}

        } break;

        case  d_TREE_info : //[설계정보]
        {
          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_info]);

          //}


        } break;

        case  d_TREE_system : //[상태정보]
        {
          //[Tree 치환]
          //{
              //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
              tree = &(tree_tree_Form->_tree[d_TREE_system]);

          //}


        } break;

      }

  //}

  return;

}

//---------------------------------------------------------------------------------------------
//[전체 찾기창]--------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------

bool __fastcall Ide_Tree_Find_Add_Doc(char  *pPathNameExt,
                                      //[다시그리기] 로 즉시 반영하는 경우는 <true>.
                                      bool   pShape,
                                      //[2019.02.21.목][추가]
                                      //항목이 추가된 경우 이 항목의 <index> 반환.
                                      //단, 이상없이 등록된 경우만 유효.
                                      int   *rItemIndex)
{
  //[2019.02.16.토][생성]{--------------------------------------------
  //[정보창:전체찾기:Tree] 의 <node:root> 에 <pPathNameExt> 등록.
  //
  //[문서:엄지그림]---------------------------------------------------
  //<*.c>, <*.h>, <*.gtxt> 는 전용 [엄지그림] 을 적용하고 나머지는
  //일반 항목(*)을 적용한다.
  //
  //[2019.02.21.목][중요수정]*****************************************
  //[등록] 시 [처리속도 향상] 을 위하여 [문서/찾은항목].<name> 을
  //동일한 형식 "item.xxxx" 으로 처리하고, "xxxx" 부분은 일괄적으로
  //<Tree->items_count> 를 "16진수표기" 로 적용한다.
  //<name> 은 서로 구분만 하면 되므로 무관.
  //
  //[전체찾기] 의 결과의 경우 { [문서] -> [항목] -> [문서] ...} 로
  //전부 순서대로 등록하므로 [옹이] 를 찾아서 등록하는 함수를 사용
  //하지 않고, 단순하게 [Tree] 끝에 추가하는 <_Tree_Add_Item()> 을
  //사용하여 처리한다.
  //
  //<_Tree_Add_NodeItem()> 함수는 [옹이] 의 정보를 추적하고 결과를
  //얻는데 상당히 많은 시간이 소요되므로 [찾은 결과:10만개] 정도만
  //되도 [추가속도] 가 느려진다.
  //
  //단, <_Tree_Add_Ietem()> 함수를 사용하는 경우는 <lastItem, level,
  //kind, name> 을 완전히 정리한뒤 [항목] 을 추가해야 한다.
  //
  //[주의!!!]*********************************************************
  //이 함수 내부에서는 <lastItem:false> 로 기본 설정하고, 실제 마지막
  //항목의 설정은 이 함수를 사용한 부분에서 처리해야 한다.
  //}-----------------------------------------------------------------

  //[VAR]
  //{
      char  extStr[OPT_lineStrSize];

      char  hexStr[OPT_wordStrSize];

      int   tempVal;

      //[tree 관련]
      //{
          struct TREE      *tree;

          struct TREEITEM   item;

      //}

  //}

  //[Tree 치환]
  //{
      //간결한 기술을 위하여 [Tree] 를 [포인터] 로 받아서 사용.
      tree = &(tree_tree_Form->_tree[d_TREE_find]);

  //}

  //[항목 추가]
  //{
      //[항목 초기화]{----------------------------------------------------
      //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
      tree_tree_Form->_Item_Init(&item);
      //}-----------------------------------------------------------------

      //[name]
      //{
          //[2019.02.21.목][수정]{---------------------------------------
          //[문서항목/찾은항목] 구분없이 "item.xxxx" 형식으로 일괄적용.
          //
          //"xxxx" : <Tree->Tree->items_count> 를 사용(16진수 최소표기).
          //}------------------------------------------------------------

          STR_Assign(item.name, "item.");
          CONV_LongVal_To_Hex2(tree->items_count, hexStr);
          STR_Add_AB(item.name, item.name, hexStr);

      //}

      //[txt]
      //{
          //[!]{----------------------------------------
          //<pPathNameExt> 자체가 [항목문자열] 에 해당.
          //}-------------------------------------------

          tree_tree_Form->_Item_Txt(tree,
                                    &item,
                                    pPathNameExt);
                
      //}

      //[level]
      //{
          //[2019.02.21.목][추가]{---
          //[root]      : 0
          //[문서:항목] : 1
          //[찾은:항목] : 2
          //}------------------------

          //[문서:항목] 이므로 <1> 에 해당.
          item.level = 1;

      //}

      //[항목:종류]
      //{
          //[!]{---------------------------------------------------------------
          //'.' 로 [일반항목] 으로 설정해도 [하위항목] 이 추가되면, 내부적으로
          //'+' 로 자동 전환 된다.
          //
          //[2019.02.21.목][추가]
          //<_Tree_Add_NodeItem()> 이 아니라 <_Tree_Add_Item()> 을 사용하므로
          //내부적으로 자동 전환되지 않는다.
          //}------------------------------------------------------------------
          
          item.kind = '+';

      //}

      //[항목:엄지그림]
      //{
          //[!]{-----------------------------------------------------------
          //<*.c>, <*.h>, <*.gtxt> 는 전용 [엄지그림] 을 적용하고 나머지는
          //일반 항목(*)을 적용한다.
          //}--------------------------------------------------------------

          //[확장자 추출]
          //{
              STR_GetFileExt(pPathNameExt, extStr);

          //}

          if     (STR_Match_NoCase(extStr, "c") == true)
          {
            item.bmpindex = d_ITEMBMP_file_c;

          }
          else if(STR_Match_NoCase(extStr, "h") == true)
          {
            item.bmpindex = d_ITEMBMP_file_h;

          }
          else if(STR_Match_NoCase(extStr, "gtxt") == true)
          {
            item.bmpindex = d_ITEMBMP_file_x;

          }
          else
          {
            //"*" 모양의 [엄지그림:API] 사용.
            item.bmpindex = d_ITEMBMP_api;

          }

      //}

      //[lastItem]
      //{
          //[2019.02.21.목][추가]{----------------------------------------------------
          //이 설정은 이 함수를 사용하는 곳에서 설정하므로 여기서는 <false> 로 설정.
          //<_Tree_Search_Before_Item()> 로 현재 항목을 기준으로 같은 [단계] 의
          //이전 항목을 알수 있으나 [항목수] 가 [10만개] 이상인 경우 [반복] 으로 인한
          //[처리시간 증가] 를 막기 위하 여기서는 사용하지 않는다.
          //}-------------------------------------------------------------------------

          item.lastItem = false;

      //}

      //[추가]
      //{
          //[중북확인]
          //{
              //<txt> 가 일치하는 경우(이미 처리한 [문서] 의 경우)는 추가하지 않는다.
              tempVal = tree_tree_Form->_Tree_Search_Item_with_Txt(tree,
                                                                   //현재 추가하는 [문서:항목] 과 같은 <level> 만 대상으로 검색.
                                                                   item.level,
                                                                   //[문서:경로이름확장자] 이므로 [대/소] 구분 없이 검색.
                                                                   false,
                                                                   pPathNameExt);

              //이미 추가된 문서라면 추가하지 않는다(문서는 중복 추가 금지).
              if(tempVal >= 0) return(false);

          //}

          //[추가]
          //{
              //[!]{------------------------------------------------------------
              //[전체찾기] 결과는 [순서대로] 처리되므로 [node] 에 등록하지 않고
              //[Tree] 를 대상으로 직접 추가한다.
              //}---------------------------------------------------------------
              
              tree_tree_Form->_Tree_Add_Item(tree, &item);

          //}

      //}

      //[등록 위치 반환]
      //{
          //[2019.02.21.목][추가]{--------------------------------------
          //[항목] 이 등록된 <intemIndex> 반환.
          //
          //이 함수를 사용하는 곳에서 <item.lastItem> 설정 하는데 필요.
          //}-----------------------------------------------------------

          //현재 위에서 추가된 상태이므로 [개수 - 1] 이 등록된 위치가 된다.
          if(rItemIndex != NULL) (*rItemIndex) = tree->items_count - 1;

      //}

      //[모양 출력]
      //{
          //[변경] 내용 출력.
          if(pShape == true)
          {
            tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

          }
          
      //}

  //}

  //추가된것.
  return(true);

}

void __fastcall Ide_Tree_Find_Add_Item(//추가할 1행 문자열([찾을문자열] 이 있는 행전체).   
                                       char  *pLineStr,
                                       //[2019.02.17.일][추가]{----------------------
                                       //[찾은문자열] 의 [문서] 상의 [시작/끝:위치].
                                       //나중에 [찾기지정] 시에 필요.
                                       int    pStartIndex,
                                       int    pEndIndex,
                                       //[2019.02.26.화][추가]
                                       //[찾은문자열] 이 위치한 행의 [시작:위치].
                                       int    pLineStartIndex,
                                       //}-------------------------------------------
                                       //[다시그리기] 로 즉시 반영하는 경우는 <true>.
                                       bool   pShape,
                                       //[2019.02.21.목][추가]
                                       //항목이 추가된 경우 이 항목의 <index> 반환.
                                       //단, 이상없이 등록된 경우만 유효.
                                       int   *rItemIndex)
{
  //[2019.02.16.토][생성]{--------------------------------------------------------
  //[2019.02.21.목][대폭수정]-----------------------------------------------------
  //[정보창:전체찾기:Tree] 에 [찾은:항목] 을 단순하게 등록한다.
  //[문서:옹이] 를 찾아서 등록하는 것이 아니 그냥 등록한다.
  //이는 [전체찾기] 에서만 사용되고 { [문서] -> [항목] -> [문서] ... } 순으로
  //단순하게 처리하므로 [문서] 위치를 찾을 필요가 없다.
  //
  //[항목:엄지그림]---------------------------------------------------------------
  //<d_ITEMBMP_item> 을 사용.
  //
  //[2019.02.17.일][중요수정]-----------------------------------------------------
  //
  //1) 같은행에 여러개의 [찾은문자열] 이 있는 경우도 전부 추가.
  //
  //2) [찾은문자열] 이 있는 [행문자열] 이 동일한 경우도 전부 추가.
  //
  //[2019.02.21.목][중요수정]*****************************************************
  //[등록] 시 [처리속도 향상] 을 위하여 [문서/찾은항목].<name> 을 동일한 형식
  //"item.xxxx" 으로 처리하고, "xxxx" 부분은 일괄적으로
  //<Tree->items_count> 를 "16진수표기" 로 적용한다.
  //<name> 은 서로 구분만 하면 되므로 무관.
  //
  //[전체찾기] 의 결과의 경우 { [문서] -> [항목] -> [문서] ...} 로 전부 순서대로
  //등록하므로 [옹이] 를 찾아서 등록하는 함수를 사용
  //하지 않고, 단순하게 [Tree] 끝에 추가하는 <_Tree_Add_Item()> 을 사용하여 처리.
  //
  //<_Tree_Add_NodeItem()> 함수는 [옹이] 의 정보를 추적하고 결과를 얻는데 상당히
  //많은 시간이 소요되므로 [찾은 결과:10만개] 정도만 되도 [추가속도] 가 느려진다.
  //
  //단, <_Tree_Add_Ietem()> 함수를 사용하는 경우는 <lastItem, level, kind, name>
  //을 완전히 정리한뒤 [항목] 을 추가해야 한다.
  //
  //[주의!!!]*********************************************************************
  //이 함수 내부에서는 <lastItem:false> 로 기본 설정하고, 실제 마지막
  //항목의 설정은 이 함수를 사용한 부분에서 처리해야 한다.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      char  hexStr[OPT_wordStrSize];

      int   tempVal;

      //[tree 관련]
      //{
          struct TREE      *tree;

          struct TREEITEM   item;

      //}

  //}

  //[Tree 치환]
  //{
      //간결한 기술을 위하여 [Tree] 를 [포인터] 로 받아서 사용.
      tree = &(tree_tree_Form->_tree[d_TREE_find]);

  //}

  //[항목 추가]
  //{
      //[항목 초기화]{----------------------------------------------------
      //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
      tree_tree_Form->_Item_Init(&item);
      //}-----------------------------------------------------------------

      //[name]
      //{
          //[2019.02.21.목][수정]{---------------------------------------
          //[문서항목/찾은항목] 구분없이 "item.xxxx" 형식으로 일괄적용.
          //
          //"xxxx" : <Tree->Tree->items_count> 를 사용(16진수 최소표기).
          //}------------------------------------------------------------

          STR_Assign(item.name, "item.");
          CONV_LongVal_To_Hex2(tree->items_count, hexStr);
          STR_Add_AB(item.name, item.name, hexStr);

      //}

      //[항목 문자열]
      //{
          //[!]{----------------------------------------
          //<pPathNameExt> 자체가 [항목문자열] 에 해당.
          //}-------------------------------------------

          tree_tree_Form->_Item_Txt(tree,
                                    &item,
                                    pLineStr);
          
      //}

      //[level]
      //{
          //[2019.02.21.목][추가]{---
          //[root]      : 0
          //[문서:항목] : 1
          //[찾은:항목] : 2
          //}------------------------

          //[찾은:항목] 이므로 <2> 에 해당.
          item.level = 2;

      //}

      //[항목:종류]
      //{
          //[!]{---------------------------------------------------------------
          //'.' 로 [일반항목] 으로 설정해도 [하위항목] 이 추가되면, 내부적으로
          //'+' 로 자동 전환 된다.
          //}------------------------------------------------------------------
          
          item.kind = '.';

      //}

      //[항목:엄지그림]
      //{
          //"[=>" 모양의 [엄지그림:항목] 사용.
          item.bmpindex = d_ITEMBMP_item;

      //}

      //[lastItem]
      //{
          //[2019.02.21.목][추가]{----------------------------------------------------
          //이 설정은 이 함수를 사용하는 곳에서 설정하므로 여기서는 <false> 로 설정.
          //<_Tree_Search_Before_Item()> 로 현재 항목을 기준으로 같은 [단계] 의
          //이전 항목을 알수 있으나 [항목수] 가 [10만개] 이상인 경우 [반복] 으로 인한
          //[처리시간 증가] 를 막기 위하 여기서는 사용하지 않는다.
          //}-------------------------------------------------------------------------

          item.lastItem = false;

      //}

      //[시작/끝 위치 정보]
      //{
          //[2019.02.17.일][추가]{-------------------------------
          //[시작위치:<item.info1>], [끝위치:<item.info2>] 기록.
          //
          //[2019.02.26.화][추가]--------------------------------
          //[행시작위치:<item.info3>] 기록.
          //}----------------------------------------------------

          item.info1 = pStartIndex;

          item.info2 = pEndIndex;

          //[2019.02.26.화][추가]
          item.info3 = pLineStartIndex;

      //}

      //[추가]
      //{
          //[2019.02.17.일][수정]{------------------------------------------
          //1) 같은행에 여러개의 [찾은문자열] 이 있는 경우도 전부 추가.
          //
          //2) [찾은문자열] 이 있는 [행문자열] 이 동일한 경우도 전부 추가.
          //
          //따라서, 여기서 [중복검사] 는 하지 않는다.
          //
          //[2019.02.21.목][중요수정]{--------------------------------------
          //[전체찾기] 결과는 [순서대로] 처리되므로 [node] 에 등록하지 않고
          //[Tree] 를 대상으로 직접 추가한다.
          //}---------------------------------------------------------------

          tree_tree_Form->_Tree_Add_Item(tree, &item);

      //}

      //[등록 위치 반환]
      //{
          //[2019.02.21.목][추가]{--------------------------------------
          //[항목] 이 등록된 <intemIndex> 반환.
          //
          //이 함수를 사용하는 곳에서 <item.lastItem> 설정 하는데 필요.
          //}-----------------------------------------------------------

          //현재 위에서 추가된 상태이므로 [개수 - 1] 이 등록된 위치가 된다.
          if(rItemIndex != NULL) (*rItemIndex) = tree->items_count - 1;

      //}

      //[모양 출력]
      //{
          //[변경] 내용 출력.
          if(pShape == true)
          {
            tree_tree_Form->_TreeView(tree_tree_Form->_tree_select_index, false);

          }
          
      //}

  //}

}

void __fastcall Ide_Tree_Find_DoubleClick(void)
{
  //[2019.02.17.일][생성]{--------------------------------------------
  //[Tree:전체찾기] 의 항목의 [2중선택] 처리.
  //
  //[Tree:전체찾기] 는 { [문서], [찾은항목] } 두개 항목만 존재.
  //
  //[방법]************************************************************
  //
  //[항목:구분] 은 해당 [항목] 의 <item.bmpindex> 를 사용한다.
  //
  //[항목:문서]
  //
  //1) 해당 [문서] 를 열어준다.
  //
  //   가) <*.gprj> 안에 들어있는 경우는 [내부:경로이름확장자] 만 표시하고
  //
  //   나) 그렇지 않은 경우는 [전체:경로이름확장자] 로 표시.
  //
  //   다) "새문서.xxx" 인 경우는 나) 의 경우로 처리.
  //
  //   [경로이름확장자] 는 <item.txt> 에 들어 있음.
  //
  //[항목:찾은항목]
  //
  //1) 이 [항목] 을 갖는 [항목:문서] 를 찾고, 이 [문서] 를 연다.
  //
  //2) 이 항목의 item.info1/2> 정보를 사용하여 1) 에서 연 [문서] 에서
  //   [찾은 문자열] 을 [선택영역] 으로 지정한다.
  //
  //   <editor_edit_Form->History_SelectX()> 로 간단하게 처리 가능.
  //   [선택영역] 은 자동적으로 [편집기:보이는 영역] 에 나오게 된다.
  //
  //}-----------------------------------------------------------------

  //[VAR]
  //{
      class   DATABASE  *DB_;

      struct  TREE  *tree;

      char    fileStr[OPT_lineStrSize];

      char    itemTxt[1024*10];

      char    tempStr[1024];

      int     nodeIndex;

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&DB_);

      //기술을 단순화 하게 위하여 포인터로 받아서 처리.
      tree = &(tree_tree_Form->_tree[d_TREE_find]);

  //}

  //[항목 문자열 얻기]
  //{
      //현재 선택된 항목의 [항목:문자열] 을 추출.
      STR_Assign(itemTxt, tree_tree_Form->_Item_Txt_StrPtr3(tree, tree->select_itemindex));

  //}

  //[항목 구분]
  //{
      //[!]{---------------------------------------------------------------------
      //[항목:구분] 은 <item.bmpindex> 로 간단 구분.
      //[문서] 는 여러종류를 사용하지만, [찾은항목] 은 <d_ITEMBMP_item> 만 사용.
      //}------------------------------------------------------------------------

      if     (tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_root)
      {
        //[root] 의 경우는 처리하지 않는다.

      }
      else if(tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_item)
      {
        //[찾은:항목] 에 해당.

        //[방법]{*****************************************************************
        //
        //1) 이 항목에 해당하는 문서열기.
        //
        //2) <item.info1/2> 정보를 사용해서 [찾은문자열] 을 [선택영역] 으로 지정.
        //
        //}***********************************************************************

        //[항목 [옹이] 찾기]
        //{
            //[!]{------------------------------------
            //현재 [항목] 을 가지는 [문서:옹이] 를 찾는다.
            //}---------------------------------------

            //이 [항목] 을 [직계가지] 로 가지는 [옹이] 의 [절대위치] 얻기.
            tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem
                            (tree,
                             //현재 선택 항목의 [절대위치].
                             tree->select_itemindex,
                             //직계 [옹이] 의 [절대위치].
                             &nodeIndex);

        //}

        //[문서 열기]
        //{
            //이 [찾은항목] 을 가지는 [문서] 의 [문서이름] 얻기.
            //여기 [문서이름]  은 [전체이름/내부경로/새문서] 중 하나일수 있다.
            STR_Assign(fileStr, tree_tree_Form->_Item_Txt_StrPtr3(tree, nodeIndex));

            //[문서] 열기(내부적으로 [전체이름/내부경로/새문서] 를 구분하여 자동 처리 됨).
            //문서 열기시 오류가 있다면 더이상 처리하지 않는다.
            if(Ide_Tree_Find_FileOpen(fileStr) != true) return;

        //}

        //[찾은 문자열 [선택영역] 으로 지정]
        //{
            //[!]{---------------------------------------------------------------
            //이 항목에 해당하는 [찾은 문자열] 을 [선택영역] 으로 지정.
            //
            //<item.info1(시작위치)/2(끝위치)> 의 정보를 사용하여 선택영역 지정.
            //[선택영역지정] 은 <editor_edit_Form->History_SelectX()> 함수 사용.
            //
            //<History_SelectX()> 는 [입력지정자:위치] 를 기준으로 처리하므로
            //[수평줄이동] 까지 처리되지만 [선택영역] 의 앞부분만 나오게 된다.
            //[선택영역] 때문이 아니라 [입력지정자] 가 [선택영역:시작] 위치에
            //있으므로.
            //}------------------------------------------------------------------

            editor_edit_Form->History_SelectX(tree->items[tree->select_itemindex].info1,
                                              tree->items[tree->select_itemindex].info2,
                                              //[선택영역] 을 항상 보이는 위치에.
                                              true,
                                              NULL,
                                              //다시 그려준다.
                                              true,
                                              false,
                                              true);

        //}

      }
      else
      {
        //[!]{---------------------------------------------------------------
        //[문서:항목] 에 해당.
        //
        //모든 기능을 가진 <Ide_Tree_Find_FileOpen()> 로 처리.
        //
        //[문서:항목] 에는 [하위항목] 이 있으므로 [+] => [-] 로 전환 시킨다.
        //}------------------------------------------------------------------

        //[문서열기]
        //{
            Ide_Tree_Find_FileOpen(itemTxt);

        //}

        //[펼치기]
        //{
            tree_tree_Form->_Tree_ThisItemExpandAll(d_TREE_find, tree->select_itemindex, false);

        //}

      }

  //}

}

bool __fastcall Ide_Tree_Find_FileOpen(char  *pStr)
{
  //[2019.02.17.일][생성]{-----------------------------------------
  //
  //<Ide_Tree_Find_DoubleClick()> 에서 [항목:문서] 를 여는데 사용.
  //처리 과정이 복잡하므로 별도 함수로 분리한다.
  //}--------------------------------------------------------------

  //[항목:문서]{***********************************************************
  //
  //1) 해당 [문서] 를 열어준다.
  //
  //   가) <*.gprj> 안에 들어있는 경우는 [내부:경로이름확장자] 만 표시하고
  //
  //   나) 그렇지 않은 경우는 [전체:경로이름확장자] 로 표시.
  //
  //   다) "새문서.xxx" 인 경우는 나) 의 경우로 처리.
  //
  //   [경로이름확장자] 는 <item.txt> 에 들어 있음.
  //
  //}**********************************************************************

  //[VAR]
  //{
      class   DATABASE  *DB_;

      char    filePathNameExt[OPT_lineStrSize];

      char    tempStr[1024*10];

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&DB_);

  //}

  //[문서 구분 처리]
  //{ 
      //[방법]{*********************************************************************
      //
      //가) <*.gprj> 안에 들어있는 경우는 [내부:경로이름확장자] 만 표시하고
      //
      //나) 그렇지 않은 경우는 [전체:경로이름확장자] 로 표시.
      //
      //다) "새문서.xxx" 인 경우는 나) 의 경우로 처리.
      //
      //[경로이름확장자] 는 <item.txt> 에 들어 있음.
      //
      //1) [문서이름] 으로 존재가 확인된다면 => (나) 에 해당.
      //   => 문서를 연다.
      //
      //2) 1) 에 해당하지 않는다면 일단 (가) 로 보고 [전체:경로이름확장자] 로 합성.
      //   [문서존재] 확인된다면 (가) 에 확실하게 해당하므로 그대로 사용.
      //   => 문서를 연다.
      //
      //3) 1), 2) 에 해당하지 않는다면 (다) [새문서] 에 해당하는것으로 본다.
      //   => 문서를 열수 없으므로 그대로 둔다.
      //
      //}***************************************************************************

      if(Str_Is_FullFileName(pStr) == true)
      {
        //[!]{--------------------------------------------------------------------
        //[전체:경로이름확장자] 에 해당하므로 바로 문서를 열어준다.
        //
        //단, [드라이브문자] 가 있는 [전체:경로이름확장자] 인지 확인.
        //이는 "__Main.c" 인 경우도 [문서] 가 존재하는 경우는 <존재:true> 가 되어
        //여기서 처리되는 것을 막기 위한것.
        //
        //이를 위하여 오늘 <Str_Is_FullFileName()> 을 새로 만들었다.
        //}-----------------------------------------------------------------------

        if(FileExists((AnsiString)pStr) != true) return(false);

        //[편집기에 열어주기]
        //{
            editor_top_Form->_List_Add((AnsiString)pStr);

        //}

        //이상없이 문서를 열었음.
        return(true);
        
      }
      else
      {
        //[!]{--------------------------------------------------
        //[전체:경로이름확장자] 가 아닌 경우.
        //
        //"새문서.xxx" 와 [내부:경로이름확장자] 문서 구분 처리.
        //
        //이를 위하여 오늘 만든 <Str_Is_NewFileName()> 사용.
        //}-----------------------------------------------------

        if(Str_Is_NewFileName(pStr) == true)
        {
          //[!]{--------------------------------------------------------------
          //[새문서] 인 경우.
          //
          //단, 이미 문서가 닫힌 상태일수 있으므로, 현재 [편집기] 에 열려있는
          //문서가 [새문서] 인지 확인필요.
          //
          //이는 [문서] 가 열려있지 않은 경우 [찾은항목] 을 [선택영역] 으로
          //지정하다가 오류가 발생할수 있기 때문.
          //}-----------------------------------------------------------------

          //[현재 열려있는 문서에 존재하는지 확인]
          //{
              //[!]{----------------------------------------------------------
              //[새문서] 인 경우는 현재 열려있는 문서인 경우만 대상으로 처리.
              //[새문서] 가 이미 [닫힌] 경우는 더이상 처리하지 않아야 한다.
              //이미 존재하지 않으므로.
              //
              //여기서 걸러주지 않으면 존재하지 않은 [새문서.xxx] 를 아래 
              //<editor_top_Form->_List_Add()> 에서 다시 만들게 된다.
              //}-------------------------------------------------------------

              //현재 [새문서] 가 이미 존재하지 않으면 여기서 종료.
              if(editor_edit_Form->_TEXTINFO_GetIndex_withFILEname((AnsiString)pStr) < 0) return(false);

          //}

          //[새문서 열기]
          //{
              //[!]{--------------------------------------------------------------
              //[새문서] 는 열려있으나 다른 [문서] 때문에 가려져 있을수 있으므로
              //일단 열어 준다.
              //
              //1) 만일 해당하는 [새문서.xxx] 가 있다면 보이는 위치로 나오게 되고
              //
              //2) 없다면 현재 보이는 [문서이름] 은 [새문서.xxx] 가 아니다.
              //}-----------------------------------------------------------------

              editor_top_Form->_List_Add((AnsiString)pStr);

          //}

          //[지정한 문서가 열려있는지 확인]
          //{
              tempStr[0] = '\0';

              //현재 [편집기] 에 열려있는 문서이름 얻기.
              editor_top_Form->_Get_TitleStr(tempStr);

              //지정한 문서이름과 같다면 해당 문서가 열려있는것.
              if(STR_Match_NoCase(pStr, tempStr) == true) return(true);
              else                                        return(false);

          //}

        }
        else
        {
          //[!]{-----------------------------------------------------
          //이 경우는 [내부:경로이름확장자] 에 해당하는 것으로 본다.
          //}--------------------------------------------------------

          //[문서 경로 합성]
          //{
              //[전체:경로이름확장자] 를 합성.
              STR_Add_AB(filePathNameExt, DB_->projectpath, pStr);

          //}

          //[존재 확인]
          //{
              if(FileExists((AnsiString)filePathNameExt) != true) return(false);

          //}

          //[편집기에 열어주기]
          //{
              editor_top_Form->_List_Add((AnsiString)filePathNameExt);

          //}

          //이상없이 문서를 열었음.
          return(true);

        }

      }

  //}

}


//---------------------------------------------------------------------------------------------
//[검증식 보기창]------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------

bool __fastcall Ide_Tree_DbgExp_Add(struct DBGEXP_TREE_INFO  *pInfo,
                                    //[2011.07.18.월][추가!!!]
                                    //추가된 [검증식] 위치를 반환한다.
                                    int                      *rExpIndex)
{
  //[2011.07.12.화][생성!!!]{----------------------------------------------------------
  //[검증식] 한개 정보를 전달 받아서 [검증식 보기창] 의 가장 마지막 항목으로 등록한다.
  //단, 정해진 형식으로 등록해야 한다.
  //
  //[2011.07.18.월][추가!!!]-----------------------------------------------------------
  //추가된 [검증식] 위치를 반환한다.
  //이는 [검증식] 을 추가한뒤 바로 [계산] 을 하여 해당 정보를 보여주기 위한 것이다.
  //
  //이 함수는 [Tree] 를 다시 그리지 않는 것으로 한다.
  //이 함수를 사용하는 부분에서 처리하는 것으로 수정한다.
  //이는 중복 그리기를 막기 위한 것이다.
  //
  //[2012.05.21.월][수정!!!]-----------------------------------------------------------
  //}----------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      //긴 이름을 간단하게 사용하기 위하여.
      struct TREE      *tree;

      //[tree 관련]
      //{
          //한개 [항목] 을 저장.
          struct TREEITEM  item;

      //}

      char  lineStr[OPT_lineStrSize];
      int   lineStartIndex;

      char  tempStr[OPT_lineStrSize];

      int   itemIndex;

  //}

  //[초기화]
  //{
      //[2011.07.18.월][추가!!!]
      //추가된 위치는 일단 <-1> 로 초기화한다.
      if(rExpIndex != NULL) { (*rExpIndex) = -1; }

  //}

  //[검사]
  //{
      //[!]{---------------------------------------
      //처리할 [문자열] 이 없다면 여기서 종료한다.
      //}------------------------------------------

      if(pInfo->infoStr == NULL) return(false);

  //}

  //[Database 의 주소를 얻기]{--------------------------------------------
  DATABASE_GetPtr(&database);
  //
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[정보정리/추가]
  //{
      //[!]{--------------------------------------------------------------------------
      //사실상 [문자열] 안에 모든 정보가 들어있으므로 [한 행] 단위로 읽어서
      //정의된 정보를 [항목] 으로 지정된 형식으로 추가한다.
      //이미 출력할 모든 정보가 정리돼 있으므로 [행단위] 로 추출하여 그대로 처리한다.
      //
      //<name> 은 특별한 의미가 없으므로 [중복] 되지 않도록만 하면 된다.
      //}-----------------------------------------------------------------------------

      //[검증식]
      //{
          //[문자열 추출:0행]
          //{
              //첫행은 0 부터 시작한다.
              lineStartIndex = 0;

              //행 문자열 추출.
              STR_Get_ThisLineStr(pInfo->infoStr, lineStartIndex, lineStr);

              //다음행 시작위치 지정.
              STR_Get_NextLineStartIndex(pInfo->infoStr, lineStartIndex, &lineStartIndex);

          //}

          //[항목 정리]
          //{
              //[항목 초기화}{----------------------------------------------------
              //[2012.04.17.화][참고!!!]
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //하위 항목이 추가되는 경우 자동으로 '+' 로 변경되므로 기본적으로 [가지] 인 '.' 로 지정한다.
              item.kind = '-';

              //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
              CONV_LongVal_To_Hex2(tree->items_count, item.name);

              //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
              //[2012.04.20.금][수정!!!]
              tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_dbgExp]),
                                        &item,
                                        lineStr);

              item.bmpindex = d_ITEMBMP_dbgExp;

              //[부가정보 정리]
              //{
                  //기타정보를 정리한다.
                  //[2011.07.17.일][주의!!!]
                  //함수정보가 먼저라는 것에 주의한다.

                  //[2011.07.19.화][개념정리!!!}{-------------------------------------
                  //이 [함수정보] 는 [검증식 계산] 에서는 사용되지 않으며 [검증식] 이
                  //존재하는 [함수이름] 을 얻는 용도로만 사용된다.
                  item.info1 = pInfo->funcRecIndex;
                  //}-----------------------------------------------------------------

                  item.info2 = pInfo->fileListIndex;
                  item.info3 = pInfo->expStartIndex;
                  item.info4 = pInfo->expEndIndex;
                  //[2011.07.18.월][추가!!!]
                  //기본 [16진수] 로 표기한다.
                  //[2011.07.21.목][수정!!!]
                  //[정의이름] 으로 변경한다.
                  item.info5 = Opt_Ide_DbgExpView_Mode;

              //}

              //[추가]
              //{
                  //[검증식] 은 항상 [뿌리] 에 추가된다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, &itemIndex);

                  //[검증식 추가위치 반환]
                  //{
                      //[2011.07.18.월][추가!!!]{-----------
                      //[검증식] 자체 항목 위치를 반환한다.
                      //}-----------------------------------

                      if(rExpIndex != NULL) { (*rExpIndex) = itemIndex; }

                  //}

              //}

          //}

      //}

      //[값]
      //{
          //[문자열 추출:1행]
          //{
              //행 문자열 추출.
              STR_Get_ThisLineStr(pInfo->infoStr, lineStartIndex, lineStr);

              //다음행 시작위치 지정.
              STR_Get_NextLineStartIndex(pInfo->infoStr, lineStartIndex, &lineStartIndex);

          //}

          //[항목 정리]
          //{
              //[항목 초기화}{----------------------------------------------------
              //[2012.04.17.화][참고!!!]
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //하위 항목이 추가되는 경우 자동으로 '+' 로 변경되므로 기본적으로 [가지] 인 '.' 로 지정한다.
              item.kind = '+';

              //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
              CONV_LongVal_To_Hex2(tree->items_count, item.name);

              //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
              //[2012.04.20.금][수정!!!]
              tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_dbgExp]),
                                        &item,
                                        lineStr);

              item.bmpindex = d_ITEMBMP_dbgValue;

              //[부가정보 정리]
              //{
                  //기타정보를 정리한다.
                  //[2011.07.19.화][주의!!!]
                  //함수정보가 먼저라는 것에 주의한다.

                  //[2011.07.19.화][개념정리!!!}{-------------------------------------
                  //이 [함수정보] 는 [검증식 계산] 에서는 사용되지 않으며 [검증식] 이
                  //존재하는 [함수이름] 을 얻는 용도로만 사용된다.
                  item.info1 = pInfo->funcRecIndex;
                  //}-----------------------------------------------------------------

                  item.info2 = pInfo->fileListIndex;
                  item.info3 = pInfo->expStartIndex;
                  item.info4 = pInfo->expEndIndex;
                  //[2011.07.18.월][추가!!!]
                  //기본 [16진수] 로 표기한다.
                  //[2011.07.21.목][수정!!!]
                  //[정의이름] 으로 변경한다.
                  item.info5 = Opt_Ide_DbgExpView_Mode;

              //}

              //[추가]
              //{
                  //[값] 은 바로 전 [검증식] 의 [가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree, tree->items[itemIndex].name, &item, &itemIndex);

              //}

          //}

      //}

      //[함수영역]
      //{
          //[문자열 추출:2행]
          //{
              //행 문자열 추출.
              STR_Get_ThisLineStr(pInfo->infoStr, lineStartIndex, lineStr);

              //다음행 시작위치 지정.
              STR_Get_NextLineStartIndex(pInfo->infoStr, lineStartIndex, &lineStartIndex);

          //}

          //[항목 정리]
          //{
              //[항목 초기화}{----------------------------------------------------
              //[2012.04.17.화][참고!!!]
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //하위 항목이 추가되는 경우 자동으로 '+' 로 변경되므로 기본적으로 [가지] 인 '.' 로 지정한다.
              item.kind = '.';

              //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
              CONV_LongVal_To_Hex2(tree->items_count, item.name);

              //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
              //[2012.04.20.금][수정!!!]
              tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_dbgExp]),
                                        &item,
                                        lineStr);

              item.bmpindex = d_ITEMBMP_function;

              //[부가정보 정리]
              //{
                  //기타정보를 정리한다.
                  //[2011.07.19.화][주의!!!]
                  //함수정보가 먼저라는 것에 주의한다.

                  //[2011.07.19.화][개념정리!!!}{-------------------------------------
                  //이 [함수정보] 는 [검증식 계산] 에서는 사용되지 않으며 [검증식] 이
                  //존재하는 [함수이름] 을 얻는 용도로만 사용된다.
                  item.info1 = pInfo->funcRecIndex;
                  //}-----------------------------------------------------------------

                  item.info2 = pInfo->fileListIndex;
                  item.info3 = pInfo->expStartIndex;
                  item.info4 = pInfo->expEndIndex;
                  //[2011.07.18.월][추가!!!]
                  //기본 [16진수] 로 표기한다.
                  //[2011.07.21.목][수정!!!]
                  //[정의이름] 으로 변경한다.
                  item.info5 = Opt_Ide_DbgExpView_Mode;

              //}

              //[추가]
              //{
                  //바로 [값] 의 [가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree, tree->items[itemIndex].name, &item, NULL);

              //}

          //}

      //}

      //[기반주소]
      //{
          //[문자열 추출:3행]
          //{
              //행 문자열 추출.
              STR_Get_ThisLineStr(pInfo->infoStr, lineStartIndex, lineStr);

              //다음행 시작위치 지정.
              STR_Get_NextLineStartIndex(pInfo->infoStr, lineStartIndex, &lineStartIndex);

          //}

          //[항목 정리]
          //{
              //[항목 초기화}{----------------------------------------------------
              //[2012.04.17.화][참고!!!]
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //하위 항목이 추가되는 경우 자동으로 '+' 로 변경되므로 기본적으로 [가지] 인 '.' 로 지정한다.
              item.kind = '.';

              //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
              CONV_LongVal_To_Hex2(tree->items_count, item.name);

              //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
              //[2012.04.20.금][수정!!!]
              tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_dbgExp]),
                                        &item,
                                        lineStr);

              //[2012.05.21.월][수정!!!]
              item.bmpindex = d_ITEMBMP_api;
              //item.bmpindex = d_ITEMBMP_item;

              //[부가정보 정리]
              //{
                  //기타정보를 정리한다.
                  //[2011.07.19.화][주의!!!]
                  //함수정보가 먼저라는 것에 주의한다.

                  //[2011.07.19.화][개념정리!!!}{-------------------------------------
                  //이 [함수정보] 는 [검증식 계산] 에서는 사용되지 않으며 [검증식] 이
                  //존재하는 [함수이름] 을 얻는 용도로만 사용된다.
                  item.info1 = pInfo->funcRecIndex;
                  //}-----------------------------------------------------------------

                  item.info2 = pInfo->fileListIndex;
                  item.info3 = pInfo->expStartIndex;
                  item.info4 = pInfo->expEndIndex;
                  //[2011.07.18.월][추가!!!]
                  //기본 [16진수] 로 표기한다.
                  //[2011.07.21.목][수정!!!]
                  //[정의이름] 으로 변경한다.
                  item.info5 = Opt_Ide_DbgExpView_Mode;

              //}

              //[추가]
              //{
                  //바로 [값] 의 [가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree, tree->items[itemIndex].name, &item, NULL);

              //}

          //}

      //}

      //[자료유형]
      //{
          //[문자열 추출:3행]
          //{
              //행 문자열 추출.
              STR_Get_ThisLineStr(pInfo->infoStr, lineStartIndex, lineStr);

              //다음행 시작위치 지정.
              STR_Get_NextLineStartIndex(pInfo->infoStr, lineStartIndex, &lineStartIndex);

          //}

          //[항목 정리]
          //{
              //[항목 초기화}{----------------------------------------------------
              //[2012.04.17.화][참고!!!]
              //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
              tree_tree_Form->_Item_Init(&item);
              //}-----------------------------------------------------------------

              //하위 항목이 추가되는 경우 자동으로 '+' 로 변경되므로 기본적으로 [가지] 인 '.' 로 지정한다.
              item.kind = '.';

              //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
              CONV_LongVal_To_Hex2(tree->items_count, item.name);

              //반드시 이 함수로 할당해야 한다(이 함수 안의 설명 참조).
              //[2012.04.20.금][수정!!!]
              tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_dbgExp]),
                                        &item,
                                        lineStr);

              item.bmpindex = d_ITEMBMP_item;

              //[부가정보 정리]
              //{
                  //기타정보를 정리한다.
                  //[2011.07.19.화][주의!!!]
                  //함수정보가 먼저라는 것에 주의한다.

                  //[2011.07.19.화][개념정리!!!}{-------------------------------------
                  //이 [함수정보] 는 [검증식 계산] 에서는 사용되지 않으며 [검증식] 이
                  //존재하는 [함수이름] 을 얻는 용도로만 사용된다.
                  item.info1 = pInfo->funcRecIndex;
                  //}-----------------------------------------------------------------

                  item.info2 = pInfo->fileListIndex;
                  item.info3 = pInfo->expStartIndex;
                  item.info4 = pInfo->expEndIndex;
                  //[2011.07.18.월][추가!!!]
                  //기본 [16진수] 로 표기한다.
                  //[2011.07.21.목][수정!!!]
                  //[정의이름] 으로 변경한다.
                  item.info5 = Opt_Ide_DbgExpView_Mode;

              //}

              //[추가]
              //{
                  //바로 [값] 의 [가지] 로 추가한다.
                  tree_tree_Form->_Tree_Add_NodeItem(tree, tree->items[itemIndex].name, &item, NULL);

              //}

          //}

      //}

  //}

  //[<뿌리> 열기]
  //{
      //[!]{-----------------------------------------------------------------
      //[뿌리] 에 한개라도 [항목] 이 있는 경우는 [검증식 보기] 가 목적이므로
      //반드시 [-] 로 바꾸어 열어준다.
      //}--------------------------------------------------------------------

      //[뿌리] 는 반드시 0 번 항목이다.
      tree->items[0].kind = '-';

  //}

  //[표시]
  //{
      //tree 를 한번 그려준다.
      //if(tree_tree_Form->_tree_select_index == d_TREE_dbgExp)
      //{
          //[2011.07.22.금][추가!!!]{----------------------------------------------
          //반드시, [검증식 보기창] 이 보이는 경우만 처리한다.
          //이는 [동작대기열] 에 등록된 경우는 이미 다른 [Tree] 가 보이는 상태에서
          //[검증식 보기창] 이 그려질수 있기 때문이다.
          //}----------------------------------------------------------------------

          //tree_tree_Form->_TreeView(d_TREE_dbgExp, false);

      //}    

      //강제로 [검증식 보기창] 으로 전환하면 자연스럽게 다시 그려져 반영된다.

      //[2011.07.18.월][수정!!!]{------------------------------------------------
      //여기서 다시 그리지 않고 추가하는 전체 기능 함수에서 한번 그린다.
      //<editor_edit.cpp:_Event_dbgView_bmp_AddBtn()> 함수에서 한번 그리게 된다.
      //ide_tree_Form->_tabs_Form->_TabIndex(d_TREE_dbgExp);
      //}------------------------------------------------------------------------

  //}

  return(true);

}

bool __fastcall Ide_Tree_DbgExp_Delete(void)
{
  //[2011.07.13.수][생성!!!]{-------
  //현재 선택된 [항목] 을 삭제한다.
  //}-------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      int  dbgExpItemIndex;

      int  i;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return(false);

  //}

  //[<검증식> 위치 찾기]
  //{
      //[!]{-------------------------------------------------------
      //[검증식] 은 하위 항목중 어떤 것을 삭제하더라도 [검증식] 과
      //하위 [항목] 을 모두 삭제해야 한다.
      //}----------------------------------------------------------

      //현재 위치에서 거꾸로 올라가면서 <엄지그림:d_ITEMBMP_dbgExp> 의 항목을 찾는다.
      for(i = tree->select_itemindex; 0 <= i; i--)
      {
        if(tree->items[i].bmpindex == d_ITEMBMP_dbgExp)
        {
          //[검증식] 항목을 찾았다.
          dbgExpItemIndex = i;

          goto lbDelete;

        }

      }

      //여기까지 온것은 찾는 것이 없으므로 여기서 종료한다.
      return(false);

  //}

  lbDelete:

  //[항목 삭제]
  //{
      //[2011.07.14.목][추가!!!]{---------------------
      //[검증식 항목] 부터 하위 모든 항목을 삭제한다.
      //}---------------------------------------------

      //함수자체적으로 지정 항목의 하위 항목까지 모두 자동 삭제된다.
      tree_tree_Form->_Tree_Delete_Item(tree, dbgExpItemIndex);

  //}

  //[<name> 재정의]
  //{
      //[2011.07.14.목][추가!!!]{------------------------------------
      //삭제된 것이 있다면, 전체 <name> 을 재정의 해야 한다.
      //단, <name> 이 [항목번호] 를 [16진수 최소표기] 를 한 것이므로
      //삭제된 위치부터만 재정의하면 된다.
      //}------------------------------------------------------------

      for(i = dbgExpItemIndex; i < tree->items_count; i++)
      {
        //<name> 은 [현재 항목 번호] 의 16진수 최소표기로 한다(큰 의미가 없음).
        CONV_LongVal_To_Hex2(i, tree->items[i].name);

      }

  //}

  //[표시]
  //{
      //[2011.07.14.목][추가!!!]
      //tree 를 한번 그려준다.
      if(tree_tree_Form->_tree_select_index == d_TREE_dbgExp)
      {
        //[2011.07.22.금][추가!!!]{----------------------------------------------
        //반드시, [검증식 보기창] 이 보이는 경우만 처리한다.
        //이는 [동작대기열] 에 등록된 경우는 이미 다른 [Tree] 가 보이는 상태에서
        //[검증식 보기창] 이 그려질수 있기 때문이다.
        //}----------------------------------------------------------------------

        tree_tree_Form->_TreeView(d_TREE_dbgExp, false);

      }

  //}

  return(true);

}

void __fastcall Ide_Tree_DbgExp_DeleteAll(void)
{
  //[2011.07.13.수][생성!!!]{---
  //모든 [항목] 을 삭제한다.
  //[Tree] 를 초기화 하면된다.
  //}---------------------------

  //[검증식 보기창] 을 초기화 한다.
  ide_tree_Form->_Tree_All_Init(d_Tree_DbgExp, true);

}

void __fastcall Ide_Tree_DbgExp_ModeChange(//<10, 16, 2> 의 [값] 으로 직접 형식을 지정한다.
                                           int  pViewMode)
{
  //[2011.07.18.월][생성!!!]{-------------------------------------
  //현재 선택된 [검증식] 의 [보기형식] 을 지정 형식으로 바꿔준다.
  //}-------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      int  dbgExpItemIndex;

      int  i;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[<검증식> 위치 찾기]
  //{
      //[!]{----------------------------------------------------
      //[검증식] 위치는 [기준] 이 되므로 이 위치를 먼저 찾는다.
      //}-------------------------------------------------------

      //현재 위치에서 거꾸로 올라가면서 <엄지그림:d_ITEMBMP_dbgExp> 의 항목을 찾는다.
      for(i = tree->select_itemindex; 0 <= i; i--)
      {
        if(tree->items[i].bmpindex == d_ITEMBMP_dbgExp)
        {
          //[검증식] 항목을 찾았다.
          dbgExpItemIndex = i;

          goto lbModeChange;

        }

      }

      //여기까지 온것은 찾는 것이 없으므로 여기서 종료한다.
      return;

  //}

  lbModeChange:

  //[<값> 보기 형식 변경]
  //{
      //[!]{----------------------------------------------------------
      //지정 형식으로 [값] 보기 형식을 바꾼다.
      //<[항목:값].info5> 를 수정하고 다시 [검증식] 을 계산하면 된다.
      //}-------------------------------------------------------------

      //새로운 형식으로 변경해 준다.
      //[값] 은 [검증식] 의 바로 다음 항목이다.
      tree->items[dbgExpItemIndex + 1].info5 = pViewMode;

      //다시 [검증식] 을 계산하면 자동으로 [값] 이 지정 형식으로 다시 변경된다.
      if(DbgExpTree_View(dbgExpItemIndex) != true) return;

  //}

  //[표시]
  //{
      //tree 를 한번 그려준다.

      if(tree_tree_Form->_tree_select_index == d_TREE_dbgExp)
      {
        //[2011.07.22.금][추가!!!]{----------------------------------------------
        //반드시, [검증식 보기창] 이 보이는 경우만 처리한다.
        //이는 [동작대기열] 에 등록된 경우는 이미 다른 [Tree] 가 보이는 상태에서
        //[검증식 보기창] 이 그려질수 있기 때문이다.
        //}----------------------------------------------------------------------

        tree_tree_Form->_TreeView(d_TREE_dbgExp, false);

      }

  //}

  return;

}

void __fastcall Ide_Tree_DbgExp_ViewSelectItem(void)
{
  //[2011.07.19.화][생성!!!]{-------------------------------------
  //현재 [선택된 검증식] 을 찾고, 이 [검증식] 한개만 계산해 준다.
  //그리고, [검증식 보기창] 을 다시 그려준다.
  //}-------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct  TREE   *tree;

      int  selExpItemIndex;

      int  i;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[<검증식> 위치 찾기]
  //{
      //[!]{----------------------------------------------------
      //[검증식] 위치는 [기준] 이 되므로 이 위치를 먼저 찾는다.
      //}-------------------------------------------------------

      //현재 위치에서 거꾸로 올라가면서 <엄지그림:d_ITEMBMP_dbgExp> 의 항목을 찾는다.
      for(i = tree->select_itemindex; 0 <= i; i--)
      {
        if(tree->items[i].bmpindex == d_ITEMBMP_dbgExp)
        {
          //[검증식] 항목을 찾았다.
          selExpItemIndex = i;

          goto lbExpView;

        }

      }

      //여기까지 온것은 찾는 것이 없으므로 여기서 종료한다.
      return;

  //}

  lbExpView:

  //[선택 검증식 계산]
  //{
      //다시 [검증식] 을 계산하면 자동으로 [값] 이 지정 형식으로 다시 변경된다.
      if(DbgExpTree_View(selExpItemIndex) != true) return;

  //}

  //[표시]
  //{
      //tree 를 한번 그려준다.

      if(tree_tree_Form->_tree_select_index == d_TREE_dbgExp)
      {
        //[2011.07.22.금][추가!!!]{----------------------------------------------
        //반드시, [검증식 보기창] 이 보이는 경우만 처리한다.
        //이는 [동작대기열] 에 등록된 경우는 이미 다른 [Tree] 가 보이는 상태에서
        //[검증식 보기창] 이 그려질수 있기 때문이다.
        //}----------------------------------------------------------------------

        tree_tree_Form->_TreeView(d_TREE_dbgExp, false);

      }

  //}

  return;
  
}

void __fastcall Ide_Tree_DbgExp_ViewAll(void)
{
  //[2011.07.19.화][생성!!!]{-----------------------------------------
  //모든 [검증식] 을 전부 계산하고, [검증식 보기창] 을 다시 그려준다.
  //}-----------------------------------------------------------------

  //[검증식 보기창 처리]
  //{
      //[주의!!!]{------------------------------------------------------------
      //이 함수는 <DbgExpTree_View()> 와는 달리 내부적으로 [검증식 보기창] 을
      //다시 그려준다는 것에 주의한다.
      //}---------------------------------------------------------------------

      if(DbgExpTree_ViewAll(true) != true) return;

  //}

}

void __fastcall Ide_Tree_DbgExp_DoubleClick(void)
{
  //[2011.07.19.화][생성!!!]{--------------------------------------------------
  //[검증식 보기창] 의 항목을 [2중선택] 하는 경우는 [검증식 계산] 을 수행하고
  //정보를 표시해 준다.
  //이는 [검증식] 이 [+] => [-] 로 전환되는 경우, [+] 일때는 계산이 안되므로
  //수동적으로 계산을 한번 해줄 필요가 있기 때문이다.
  //
  //<tree_tree.h:_EVENT_PopupMenu_DbgExpView()> 의 [빠른항목] 에 동일한 기능이
  //있으므로 이를 위하여 만든 함수를 사용하여 처리한다.
  //}--------------------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct TREE  *tree;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[선택 항목 다시 계산]
  //{
      //[2011.07.20.수][추가!!!]{--------------------------------------------------
      //[뿌리] 라면 [검증식 보기창] 에 등록됀 모든 검증식을 다시 계산해 주고,
      //다른 경우라면, 해당 [검증식] 을 먼저 찾고 이 [검증식] 을 다시 계산해 준다.
      //}--------------------------------------------------------------------------

      if(tree->select_itemindex == 0)
      {
        //[!]{---------------------
        //[뿌리] 에 해당하는 경우.
        //}------------------------

        //[주의!!!]{------------------------------------------------------------
        //이 함수는 <DbgExpTree_View()> 와는 달리 내부적으로 [검증식 보기창] 을
        //다시 그려준다는 것에 주의한다.
        //}---------------------------------------------------------------------

        //[검증식 보기창] 의 [검증식] 전체를 다시 계산해 준다.
        Ide_Tree_DbgExp_ViewAll();

      }
      else
      {
        //[!]{---------------------------------
        //일반 [검증식] 에 해당하는 경우.
        //
        //1) [검증식] 위치 찾기.
        //
        //2) [검증식] 계산후 정보 정리.
        //
        //3) [검증식 보기창] 을 다시 그려준다.
        //}------------------------------------

        //이미 해당 기능을 가진 함수가 있으므로 이것을 사용하여 처리한다.
        //내부적으로 그려주는 것까지 자동 처리한다.
        Ide_Tree_DbgExp_ViewSelectItem();

      }

  //}

}

void __fastcall Ide_Tree_DbgExp_EVENT_Item_M(//[2011.07.21.목][추가!!!]
                                             //[검증식 보기창] 을 다시 그리는 경우는 <true>.
                                             bool  pRePaint)
{
  //[2011.07.20.수][생성!!!]{------------------------------------------------------------
  //[Tree:검증식 보기창] 의 <_EVENT_Item_M()> 동작 함수가 발생하는 경우를 처리한다.
  //
  //이는 [검증식] 이 [+] => [-] 로 전환되는 경우, [+] 일때는 계산이 안되므로
  //[검증식] 이 [-] 로 열릴때 자동으로 계산하여 항상 정확한 값을 보여주기 위한 것이다.
  //
  //[방법!!!]----------------------------------------------------------------------------
  //
  //1) [-]<root>   : 전체 [검증식] 을 처리한다.
  //
  //2) [-][검증식] : 지정된 [검증식] 만 처리한다.
  //
  //단, 2) 의 경우는 반드시 [검증식] 항목인 경우만 처리한다.
  //이는 정확한 대상이 지정되는 경우만 처리해야 하기 때문이다.
  //
  //[주의!!!]----------------------------------------------------------------------------
  //여기서는 [Tree] 를 다시 그리지 않는다.
  //이는 <_EVENT_Item_M()> 함수가 [Tree] 가 그려지는 과정에서 호출되기 때문이다.
  //즉, 이 함수에서 그려지면 두번 이어서 그리는 꼴이 되므로 이의 중복을 막기 위한것이다.
  //
  //[2011.07.21.목][수정!!!]
  //}------------------------------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct TREE  *tree;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[선택 항목 다시 계산]
  //{
      //[2011.07.20.수][추가!!!]{---------------------------------------------
      //[뿌리] 라면 [검증식 보기창] 에 등록된 모든 검증식을 다시 계산해 주고,
      //다른 경우라면 반드시 [검증식] 항목인 경우만 처리한다.
      //}---------------------------------------------------------------------

      if(tree->select_itemindex == 0)
      {
        //[!]{---------------------
        //[뿌리] 에 해당하는 경우.
        //}------------------------

        //[검증식 보기창] 의 [검증식] 전체를 다시 계산해 준다.
        //여기서는 [검증식 보기창] 을 다시 그리지 않는다.
        //--------------------v
        if(DbgExpTree_ViewAll(false) != true) goto lbRePaint;

      }
      else
      {
        //[!]{---------------------------------
        //일반 [검증식] 에 해당하는 경우.
        //}------------------------------------

        //[<검증식> 항목 인가?]
        //{
            //[주의!!!]{-----------------------------------------------------------
            //반드시 현재 항목이 [검증식] 자체 인 경웅만 처리해야 한다.
            //즉, [검증식] 항목이 [+] => [-] 로 전환되는 경우라야 처리대상이 된다.
            //}--------------------------------------------------------------------

            if(tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_dbgExp)
            {
              if(DbgExpTree_View(tree->select_itemindex) != true) goto lbRePaint;

            }

        //}

      }

  //}

  lbRePaint:

  //[표시]
  //{
      //[2011.07.21.목][추가!!!]
      if(pRePaint == true)
      {
        //tree 를 한번 그려준다.

        if(tree_tree_Form->_tree_select_index == d_TREE_dbgExp)
        {
          //[2011.07.22.금][추가!!!]{----------------------------------------------
          //반드시, [검증식 보기창] 이 보이는 경우만 처리한다.
          //이는 [동작대기열] 에 등록된 경우는 이미 다른 [Tree] 가 보이는 상태에서
          //[검증식 보기창] 이 그려질수 있기 때문이다.
          //}----------------------------------------------------------------------

          tree_tree_Form->_TreeView(d_TREE_dbgExp, false);

        }

      }

  //}

}

void __fastcall Ide_Tree_DbgExp_ThisItemExpandAll(void)
{
  //[2011.07.20.수][생성!!!]{-------------------------------------------------------------
  //<tree_tree.cpp:_EVENT_PopupMenu_DbgExpView()> 함수의 [하위항목 모두열기] 을 처리한다.
  //
  //여기서는 [다시그리기] 를 하지 않고 처리만 한다.
  //이 함수를 호출하는 쪽에서 다시 그려준다.
  //
  //[방법!!!]-----------------------------------------------------------------------------
  //
  //1) [-]<root>   : 전체 [검증식] 을 처리한다.
  //
  //2) [-][검증식] : 지정된 [검증식] 만 처리한다.
  //
  //단, 2) 의 경우는 반드시 [검증식] 항목인 경우만 처리한다.
  //이는 정확한 대상이 지정되는 경우만 처리해야 하기 때문이다.
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct TREE  *tree;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[선택 항목 다시 계산]
  //{
      //[2011.07.20.수][추가!!!]{---------------------------------------------
      //[뿌리] 라면 [검증식 보기창] 에 등록된 모든 검증식을 다시 계산해 주고,
      //다른 경우라면 반드시 [검증식] 항목인 경우만 처리한다.
      //}---------------------------------------------------------------------

      if(tree->select_itemindex == 0)
      {
        //[!]{---------------------
        //[뿌리] 에 해당하는 경우.
        //}------------------------

        //[검증식 보기창] 의 [검증식] 전체를 다시 계산해 준다.
        //여기서는 [검증식 보기창] 을 다시 그리지 않는다.
        //--------------------v
        if(DbgExpTree_ViewAll(false) != true) return;

      }
      else
      {
        //[!]{---------------------------------
        //일반 [검증식] 에 해당하는 경우.
        //}------------------------------------

        //[<검증식> 항목 인가?]
        //{
            //[주의!!!]{-----------------------------------------------------------
            //반드시 현재 항목이 [검증식] 자체 인 경웅만 처리해야 한다.
            //즉, [검증식] 항목이 [+] => [-] 로 전환되는 경우라야 처리대상이 된다.
            //}--------------------------------------------------------------------
            
            if(tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_dbgExp)
            {
              if(DbgExpTree_View(tree->select_itemindex) != true) return;

            }

        //}

      }

  //}

}

void __fastcall Ide_Tree_DbgExp_ThisLevelExpandAll(void)
{
  //[2011.07.20.수][생성!!!]{-------------------------------------------------------------
  //<tree_tree.cpp:_EVENT_PopupMenu_DbgExpView()> 함수의 [같은단계 모두열기] 을 처리한다.
  //
  //여기서는 [다시그리기] 를 하지 않고 처리만 한다.
  //이 함수를 호출하는 쪽에서 다시 그려준다.
  //
  //[방법!!!]-----------------------------------------------------------------------------
  //
  //1) [-]<root>   : 전체 [검증식] 을 처리한다.
  //
  //2) [-][검증식] : 모든 [검증식] 을 다 계산한다.
  //
  //단, 2) 의 경우는 반드시 [검증식] 항목인 경우만 처리한다.
  //이는 정확한 대상이 지정되는 경우만 처리해야 하기 때문이다.
  //
  //[검증식] 과 같은 단계는 모두 [검증식] 이 되므로 전부다 계산한다.
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //긴 이름을 간단하게 사용하기 위하여.
      struct TREE  *tree;

  //}

  //[Tree 치환]{----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_dbgExp]);
  //}---------------------------------------------------------------------

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 처리하지 않는다.
      if(tree->select_itemindex < 0) return;

  //}

  //[선택 항목 다시 계산]
  //{
      //[2011.07.20.수][추가!!!]{---------------------------------------------
      //[뿌리] 라면 [검증식 보기창] 에 등록된 모든 검증식을 다시 계산해 주고,
      //다른 경우라면 반드시 [검증식] 항목인 경우만 처리한다.
      //}---------------------------------------------------------------------

      if(tree->select_itemindex == 0)
      {
        //[!]{---------------------
        //[뿌리] 에 해당하는 경우.
        //}------------------------

        //[검증식 보기창] 의 [검증식] 전체를 다시 계산해 준다.
        //여기서는 [검증식 보기창] 을 다시 그리지 않는다.
        //--------------------v
        if(DbgExpTree_ViewAll(false) != true) return;

      }
      else
      {
        //[!]{---------------------------------
        //일반 [검증식] 에 해당하는 경우.
        //}------------------------------------

        //[<검증식> 항목 인가?]
        //{
            //[주의!!!]{-----------------------------------------------------------
            //반드시 현재 항목이 [검증식] 자체 인 경웅만 처리해야 한다.
            //즉, [검증식] 항목이 [+] => [-] 로 전환되는 경우라야 처리대상이 된다.
            //}--------------------------------------------------------------------

            if(tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_dbgExp)
            {
              //[!]{----------------------------------------------------------------
              //[검증식 보기창] 의 [검증식] 전체를 다시 계산해 준다.
              //이는 [검증식] 과 [같은단계] 는 전부 같은 [검증식] 이 되기 때문이다.
              //}-------------------------------------------------------------------

              //여기서는 [검증식 보기창] 을 다시 그리지 않는다.
              //--------------------v
              if(DbgExpTree_ViewAll(false) != true) return;

            }

        //}

      }

  //}

}

void __fastcall Ide_Tree_DbgExp_ExpandAll(void)
{
  //[2011.07.20.수][생성!!!]{-----------------------------------------------------
  //<tree_tree.cpp:_EVENT_PopupMenu_DbgExpView()> 함수의 [전체 열기] 을 처리한다.
  //
  //여기서는 [다시그리기] 를 하지 않고 처리만 한다.
  //이 함수를 호출하는 쪽에서 다시 그려준다.
  //
  //[방법!!!]---------------------------------------------------------------------
  //
  //모든 항목을 전부 여는 것이므로 모든 [검증식] 을 다시 계산해 준다.
  //}-----------------------------------------------------------------------------

  //여기서는 [검증식 보기창] 을 다시 그리지 않는다.
  //--------------------v
  if(DbgExpTree_ViewAll(false) != true) return;

}

//------------------------------------------------------------------------------
//[가상머신 제작 관련 함수]-----------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_IsBuilded(void)
{
  //[2009.12.28.월][생성!!!]{-------------------------------------------------------------
  //[2009.01.26.월][수정!!!]
  //<*.gprj> 경로를 참고하여 현재 검증정보({DATABASE})가 저장된 경로를 만들고
  //이미 생성된 것과 비교하여, 현재 [설계묶음] 이 최소한 한번은 빌드된 상태인지 검사한다.
  //이는,설계묶음이 너무 큰 경우 빌드에 많은 시간이 걸릴수 있어 수정된 경우가 아는 경우는
  //[자동진행] 시 바로 다음 단계로 넘어가도록 되 있으나, 처음 [설계묶음] 을 연 경우는
  //한번도 빌드되지 않은 상태이나 수정된 것은 없은 상태가 되어 검증이 되지 않는다.
  //따라서,
  //1) 수정된 것이 있는가?
  //2) 최소한 한번은 빌드되었는가?
  //중 2) 번을 검사하기 위하여 이 함수를 만든다.
  //
  //[켄타우로스] 제어 설계묶음은 거의 100K 바이트의 가상기계가 생성되는데
  //이 경우 계속 빌드하느라 많은 시간을 낭비하게 되므로 이런 새로운 방법을 만드는 도중
  //이 함수를 만들게 되었다.
  //이미 [켄타우로스] 는 맷돌(G.MTDL.A)로 완벽하게 구동하고 있으며 후처리의 일환으로
  //정리 보완을 하는 도중 개선을 위하여 만든다.
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  tempStr[OPT_lineStrSize];

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[검증 경로 만들기]
  //{
      //[!]{---------------------------------------------------
      //<*.gprj> 문서 경로를 기준으로 다른 경로를 만들어 준다.
      //}------------------------------------------------------

      STR_Assign(tempStr, database->projectpath);
      STR_Add_AB(tempStr, tempStr, "debug\\");

  //}

  //[일치 검사]
  //{
      //[!]{-----------------------------------------------------------------
      //현재 생성되 있는 경로와 지금 만든 경로가 일치하는지 검사한다.
      //일치한다면 이미 현재 설계묶음을 최소 한번은 빌드한 것으로 볼수 있다.
      //}--------------------------------------------------------------------

      return(STR_Match_NoCase(tempStr, database->debugPath));

  //}

}

bool __fastcall IDE_Build(unsigned char  pStep)
{
  //[2005.10.05.수][생성!!!]{--------------------------------------------
  //[2009.01.26.월][수정!!!]
  //<*.gprj> 문서를 찾아서 실제 [가상머신] 을 만드는 것 까지 완료한다.
  //실제 적인 모든 처리를 수행한다.
  //
  //[2009.05.28.목][추가!!!]---------------------------------------------
  //항상 Parser() 전에 무조건 <함수묶음.h> 문서를 만들어 주는 기능 추가.
  //
  //[2012.04.02.월][추가!!!]---------------------------------------------
  //<Parser()> 함수 [해석종류] 처리부 추가.
  //
  //[2012.05.16+2.금][추가!!!]-------------------------------------------
  //[2012.05.23.수][수정!!!]---------------------------------------------
  //[2012.05.26.토][수정!!!]---------------------------------------------
  //[중복 처리 방지] 기능 추가.
  //[2012.05.27.일 [수정!!!]---------------------------------------------
  //[중복 처리 방지] 기능 [해제].
  //[2022.05.27.금][중요수정]********************************************
  //}--------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      AnsiString  msgStr = "";

      //[2008.11.26.수][추가!!!]
      char  fileName[OPT_filepath_length];
      char  fileNewName[OPT_filepath_length];
      char  fileFullName[OPT_filepath_length];
      char  filePath[OPT_filepath_length];

      //[2009.01.25.일][추가!!!]
      int  i;

      //[<설계묶음> 관련]
      //{
          //[2009.01.27.화][추가!!!]
          int  nodeItemIndex;
          int  c_Count;

          //[2009.03.29.일][추가!!!]
          //처리된 [문서수] 를 가진다.
          int  cnt;

      //}

      //[풍선도움말 API 추가 정보 문자열 관련]
      //{
          //[2022.05.30.월][추가]
          //자동 추가된 API 기본 정보를 출력하기 위하여 필요.
          char  balloonStr[1024*10];
          int   bls;

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.06.07.화][추가]
          VSTRBUF  *vStrBuf_ = NULL;
          
          char     *defFile_ApiList_ = NULL;
          int       defFile_ApiCount = 0;
          char      defFile_ApiName_[OPT_filepath_length];

          //[2022.06.08.수][추가]
          //[오류단어] 가 <struct, union> 인 경우 다음단어를 가진다.
          char      errorNextWord_[OPT_filepath_length];

          //[2022.07.14.목][추가]
          //[단어] 가 존재하지 않는 경우는 <-1>.
          int       errorWordStartIndex;

      //}

  //}

  //[Database 의 주소를 얻기]
  //{
      //[2023.01.29.일][중요추가]{*********************************************************
      //{DB} 주소 얻는 부분을 이 위치로 이동.
      //이는 [설계묶음] 이 없는 경우 아래 [새설계묶음인가?] 부분에서 오류로 처리 되어
      //<lbError:> 로 이동하게 되는데, 아직 {DB} 의 주소를 얻지 못한 상태에서 이 처리 부의
      //<API_Check()> 함수가 <DB> 에 접근하기 때문에 [포인터오류] 가 계속 발생하게 된다.
      //따라서, 어떤 경우라도 확실하게 {DB} 에 접근할수 있도록 아예 이 함수 가장 첫부분인
      //여기서 {DB} 주소를 확정한다.
      //}**********************************************************************************

      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  lbStart: //[2022.05.27.금][추가]

  //[<Parser()> 중복 처리 방지]
  //{
      //[2012.05.26.토][추가!!!]{------------------------------------------
      //<Parser()> 함수의 [중복실행] 을 [방지] 하기위한것.
      //
      //[2012.05.27.일][수정!!!]-------------------------------------------
      //<Ctrl+Space> 의 경우는 [중복] 시에도 큰 문제가 없고 완벽 동작한다.
      //<Ctrl+F9>, <Alt+F9> 의 경우는 자체적으로 [중복 방지] 된다.
      //
      //이 방식은 [예측할수 없는 오류] 등으로 종료되는 경우는 계속 값을
      //가지고 있기 때문에 [재동작] 시 [중복] 으로 간주되어 다시 함수를
      //동작 시킬수 없게 된다.
      //
      //일단, 사용하지 않는 것으로 하고 [주석] 처리한다.
      //}------------------------------------------------------------------

      //이미 처리중이라면 [이상없음] 으로 종료.
      //if(_ParserMode_Read() != d_ParserMode_NULL) return(true);

  //}

  //[API 자동 추가 관련]
  //{
      //[2022.05.30.월][추가]{--------------------------------------------------
      //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
      //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨다.
      //
      //[촛점:해제] 시에도 사라지지 않고 [알림창] 처럼 동작 시키기 위한것.
      //}-----------------------------------------------------------------------

      editor_top_Form->_balloonBox->_KillFocusUse(false);

  //}

  //[정보판:감추기]
  //{
      //[2012.05.23.수][추가!!!]{-----------------
      //잔상이 남지 않도록 반드시 가장 먼저 처리.
      //}-----------------------------------------

      if(info_tree_Form != NULL)
      {
        if(info_tree_Form->Visible == true) { info_tree_Form->Hide(); }

      }

  //}

  //[기본설정]
  //{
      //[2012.04.02.월][추가!!!]{-----------------------------------------
      //새로 추가된 <Parser()> 의 [해석종류] 를 기본으로 초기화.
      //<Build> 시에는 항상 기본 설정을 적용.
      //
      //<Parser()> 의 경우 [기본/선언만검사] 의 두경우가 존재.
      //이는 [실시간 선언정보 보이기] 기능때문으로 BCB 의 [정보상자] 와
      //유사한 것을 구현하기 위한 것이다.
      //
      //[선언만검사] 시에는 [1차번역] 관련 처리를 하지 않고, [선언정보]
      //관련만 검사하고 나머지는 기본검사만 처리하게 된다.
      //[식] 의 경우 [최소 규칙검사] 만 하고 [Match 검사] 는 하지 않는다.
      //
      //[주의!!!]---------------------------------------------------------
      //이는 <Parser()> 함수를 별도 구동하여 사용하므로 여기서는 반드시
      //기본값으로 설정해 주어야 한다.
      //}-----------------------------------------------------------------

      _ParserMode(d_ParserMode_All);

  //}

  //[단계 구분 처리]
  //{
      //[2009.02.12.목][추가!!!]{------------------
      //해당 단계 처리요청이 없다면 바로 종료한다.
      //}------------------------------------------

      if((pStep & d_Build_Parser) != d_Build_Parser)
      {
        //[2009.02.12.목][추가!!!]{-----------------------------------------------------------
        //<*.gvmx> 가 생성된 것이 아닌 경우이므로 false 로 하여 다음 처리가 되지 않게 만든다.
        //이는 "|>" 버튼으로 자동 처리 되는 경우 더이상 진행하지 못하게 하기 위한 것이다.
        //}-----------------------------------------------------------------------------------

        //return(false);
        goto lbError;

      }

  //}

  //[새설계묶음인가?]
  //{
      //[2010.12.30.목][추가!!!]{----------------------------------------------------------
      //현재 [새설계묶음] 상태인 경우는 먼저 <*.gprj> 로 저장할 것을 요구한다.
      //이전처럼 바로 [저장대화상자] 를 보여 주는 경우는, 기존 <*.gprj> 를 여는 대화상자로
      //오인하여 기존의 [설계묶음] 을 덮어써버리는 문제가 있다.
      //나도 착각하여 여러번 낭패를 보았으므로, 아예 사용자가 직접 저장할수 있도록 한다.
      //즉, [새설계묶음] 인 경우는 저장할것을 요구하고 더이상 처리하지 않고 종료한다.
      //}----------------------------------------------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "현재 [새설계묶음] 입니다.\r\n"
                                 "저장되지 않은 [설계묶음] 은 처리 할수 없습니다.\r\n"
                                 "먼저 [설계묶음] 을 <*.gprj> 로 저장해 주십시요."
                                );

        //return(false);
        goto lbError;

      }

  //}

  //[설계묶음 저장]
  //{
      //[2009.04.01.수][추가!!!]{--------------
      //현재 작업 중인 [설계묶음] 을 저장한다.
      //}--------------------------------------

      IDE_Project_Save(false);

  //}

  //[문서 저장]
  //{
      //[2009.02.09.월][추가!!!]{-----------------------------
      //[Build] 전에 먼저 현재 편집중인 모든 문서를 저장한다.
      //}-----------------------------------------------------

      IDE_File_SaveAll();

  //}

  //[Database 의 주소를 얻기]
  //{
      //[2023.01.29.일][주석처리]{**************************************
      //이부분은 이 함수의 가장 첫 위치로 이동(해당부분의 설명을 참조).
      //}***************************************************************

      //{DATABASE} 의 주소를 얻는다.
      //DATABASE_GetPtr(&database);

  //}

  //[경로 만들기]
  //{
      //[2009.01.26.월][수정!!!]{------------------------------
      //<*.gprj> 문서 경로를 기준으로 다른 경로를 만들어 준다.
      //}------------------------------------------------------

      //[Build]
      //{
          //[build] 폴더는 항상 <*.gprj> 와 같은 위치에 있는 것으로 한다.
          //이 경로에 [build] 폴더가 없는 경우는 자동으로 하나 생성해 준다.
          STR_Assign(database->buildpath, database->projectpath);
          STR_Add_AB(database->buildpath, database->buildpath, "build\\");

          //[해당 경로를 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->buildpath);

          //}

      //}

      //[Debug]
      //{
          STR_Assign(database->debugPath, database->projectpath);
          STR_Add_AB(database->debugPath, database->debugPath, "debug\\");

          //[해당 경로를 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->debugPath);

          //}

      //}

  //}

  //[DATABASE 초기화]
  //{
      //[2005.10.10.월][추가!!!]{-----------------------------------------------
      //compile 을 하기 전에는 반드시 {DATABASE} 를 먼저 초기화 해 주어야 한다.
      //}-----------------------------------------------------------------------

      database->Init();

  //}

  //[설계묶음 존재]
  //{
      //[2009.02.12.목][추가!!!]{-------------------------------------------
      //[새설계묶음] 인 경우는 아직 저장된 것이 아니므로 처리해서는 안된다.
      //}-------------------------------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "현재 [새설계묶음] 입니다.\r\n"
                                 "저장되지 않은 [설계묶음] 은 처리 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 저장해 주십시요."
                                );

        //return(false);
        goto lbError;

      }

  //}

  //[정보 얻기]
  //{
      //현재 [설계묶음] 의 <*.c> 문서의 수를 구한다.
      tree_tree_Form->_Tree_Get_Node_ItemCount(&(tree_tree_Form->_tree[d_TREE_project]),
                                               "c", &nodeItemIndex, &c_Count);

  //}

  //[<*.c> 가 존재?]
  //{
      //[2009.02.12.목][추가!!!]{----------------------
      //처리할 <*.c> 가 [설계묶음] 안에 존재해야 한다.
      //}----------------------------------------------

      if(c_Count <= 0)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "현재 [설계묶음] 에 처리할 [설계문서] 가 존재하지 않습니다.\r\n"
                                 "먼저 [설계묶음] 에 [설계문서] 를 등록해 주십시요."
                                );

        //return(false);
        goto lbError;

      }

  //}

  //[<함수묶음.h> 만들기]
  //{
      //[2009.05.28.목][추가!!!]{-----------------------------------------------------------
      //현재 [설계묶음] 에 포함된 모든 [함수묶음] 의 <*.h> 를 모아 놓은 <함수묶음.h> 문서를
      //현재 [설계묶음] 위치에 만들어 준다.
      //}-----------------------------------------------------------------------------------

      Ide_Glib_MakeHeader();

  //}


  //[진행 상태창 보이기]
  //{
      //[2011.04.29.금][추가!!!]
      buildStatus_Form->_On();

  //}


  //[Project 처리]
  //{
      //[2009.01.24.토][수정!!!]{--------------------------------------------------
      //<*.prj> 단위로 처리 되어야 하므로 <*.c> 만으로 대상으로 순서대로 처리한다.
      //}--------------------------------------------------------------------------

      //[알림창 지우기]
      //{
          //현재 처리할 문서의 경로를 보여준다.
          msg_msg_Form->_Print(d_msg_msg, "");

      //}

      C_FILE_START:

      //새로운 <*.c> 문서를 시작한다.

      //for(i = 0; i < c_Count; i ++)
      for(i = 0, cnt = 0; cnt < c_Count; i++)
      {
        //[직계가지 인가?]
        //{
             //[!]{-----------------------------------------------------
             //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
             //이는 [옹이] 의 [직계가지] 에만 해당한다.
             //}--------------------------------------------------------

             //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
             if((tree_tree_Form->_tree[d_TREE_project].items[nodeItemIndex].level + 1) !=
                 tree_tree_Form->_tree[d_TREE_project].items[i + (nodeItemIndex + 1)].level) continue;

        //}

        //[처리할 문서 경로 얻기]
        //{
            //[2009.01.27.화][추가!!!]{-------------------------------------------------------------
            //현재 열려 있는 [설계묶음] <Tree> 에서 <*.c> 문서를 하나 씩 읽어서 경로를 만들어 준다.
            //현재는 해당 항목의 <text> 에 있는 것이 <*.gprj> 가 있는 폴더 안의 경로가 된다.
            //}-------------------------------------------------------------------------------------

            STR_Assign(filePath, database->projectpath);

            STR_Add_AB(filePath,
                       filePath,
                       //[2012.04.20.금][수정!!!]
                       //실제 문서는 [옹이] 의 다음부터 시작된다.-----------------------v
                       tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, nodeItemIndex + 1 + i));

            //처리할 문서가 없는 경우는 처리하지 않는다.
            if(filePath == "") goto lbError;//return(false);

        //}

        //[경로 보여주기!!!]
        //{
            //현재 처리할 문서의 경로를 보여준다.
            msg_msg_Form->_PrintAddLine(d_msg_msg, filePath);

        //}

        //[문법검사]
        //{
            if(Parser(filePath, database) == true)
            {
              //이상없이 처리 되었다.

              //[2007.06.17.일][수정!!!]{---------------------------------------
              //계속 행이 추가 되는 경우는 구별이 분명하지 않는 경우가 있으므로
              //이전에 출력된 내용을 완전히 지우고 지금 결과만 추가한다.
              //}---------------------------------------------------------------

              msg_msg_Form->_PrintAddLine(d_msg_msg, "[문법검사] 이상없음!");

            }
            else
            {
              //[오류] 발생!!!

              //[행지정]
              //{
                  //[2009.02.18.수][추가!!!]
                  //[오류행] 전체를 [선택영역] 으로 지정해 준다.
                  Ide_ErrorLine(database->errorinfo.fileFullName,
                                database->errorinfo.line);

              //}

              //[구분처리]
              //{
                  //[2011.04.29.금][수정!!!]{-----------------------------------
                  //[사용자 처리 중지] 인 경우는 오류로 간주하지만, [오류행] 을
                  //지정하지 않으므로 이 경우를 구분하여 처리한다.
                  //이 경우는 [오류행:-1] 로 쉽게 구분 가능하다.
                  //}-----------------------------------------------------------

                  if(database->errorinfo.line < 0)
                  {
                    //[!]{---------------------------------------------------------------------------
                    //[가상기계 제작 중지] 의 경우로, [오류행] 이 존재하지 않으므로 표시하지 않는다.
                    //}------------------------------------------------------------------------------

                    msgStr = "\r\n[ " + (AnsiString)database->errorinfo.word + " ]\r\n" +
                             (AnsiString)database->errorinfo.strbuf.buf;

                  }
                  else
                  {
                    msgStr = "[ " + IntToStr(database->errorinfo.line) + " 행 ]\r\n" +
                             "[ " + (AnsiString)database->errorinfo.word + " ]\r\n" +
                             (AnsiString)database->errorinfo.strbuf.buf;

                  }

              //}

              //[2007.06.17.일][수정!!!]{---------------------------------------
              //계속 행이 추가 되는 경우는 구별이 분명하지 않는 경우가 있으므로
              //이전에 출력된 내용을 완전히 지우고 지금 결과만 추가한다.
              //}---------------------------------------------------------------

              //[2022.05.27.금][주석처리]
              //msg_msg_Form->_PrintAddLine(d_msg_msg, msgStr.c_str());

              //[2008.11.26.수][추가!!!]{-----------------------------
              //오류가 있으므로 더이상 진행하지 않고 여기서 종료한다.
              //}-----------------------------------------------------

              //[API 자동 추가 관련]
              //{
                  //[2022.06.08.수][추가]{**************************************************
                  //함수안의 선언부에서 [구조체/공용체] 선언시
                  //
                  //void 맷돌28호_각도구동확인(void)
                  //{
                  //  struct SPDXWR_3  속도목록[28];
                  //  ...
                  //
                  //여기서, <SPDXWR_3> 이 선언되있지 않은 [구조체이름] 인 경우
                  //<SPDXWR_3> 이 단어를 [오류단어] 로 지정하지 않고, <struct> 가
                  //[오류단어] 로 지정된다.
                  //
                  //이 경우 <lbError> 의 오류 처리부에서 <API_DefFile_Check()> 함수로
                  //제대로 된 <API이름> 을 찾을수 없다.
                  //
                  //따라서, 여기서 이를 위하여 <struct> 가 [오류단어] 인 경우는 [다음단어]
                  //까지 추출하여 이 [다음단어] 를 오류처리부의 <API_DefFile_Check()> 에
                  //넘겨 주어야 한다.
                  //
                  //이는 일반적인 오류 처리에는 불필요 하나, [API 자동 추가] 를 위해서는
                  //반드시 필요한 기능이다.
                  //
                  //아직 이 위치에서 <Parser()> 의 <ParserInfo> 가 유효하므로 이를 이용하여
                  //이 위치에서 다음 단어까지 추출한다.
                  //
                  //단, struct, union 인 경우만 처리하면 된다.
                  //}***********************************************************************

                  //[키워드] 와 비교하므로 대소문자를 구분해서 비교해야 한다.
                  if((STR_Match(database->errorinfo.word, "struct") == true) ||
                     (STR_Match(database->errorinfo.word, "union") == true))
                  {
                    //"struct", "union" 다음 단어를 추출한다.
                    //[2022.07.14.목][추가]
                    //<errorWordStartIndex> 로 오류 단어 시작 위치를 반환 받도록 수정.
                    errorWordStartIndex = CheckNextWord(&database->parserinfo, errorNextWord_);

                    //[중요]{*************************************************
                    //<Check_NextWord()> 는 #define 으로 선언된 이름인 경우
                    //해당문자열로 대체하므로, 구체적인 문법을 적용하지 않고,
                    //단순하게 [다음단어] 만 추출하는 <CheckNextWord()> 를
                    //사용해야 한다.
                    //}*******************************************************

                  }
                  else
                  {
                    //해당하지 않는다면 NULL 로 초기화.
                    errorNextWord_[0] = '\0';

                    //[2022.07.14.목][추가]
                    //<errorWordStartIndex> 로 오류 단어 시작 위치를 반환 받도록 수정.
                    errorWordStartIndex = database->parserinfo.wordindex;

                  }

              //}

              //return(false);
              goto lbError;

            }

            //처리한 문서수 증가.
            cnt++;

        //}

      }

      //[<*.c> 에 <include> 된 문서 추가]
      //{
          Ide_Project_C_IncludeFile();

      //}

      //[구조체/공용체 단어 정리]
      //{
          //[2012.05.16+2.금][추가!!!]{-------------------------------------------------
          //<{DB}._strHeap_Conf> 의 해당 [구간] 에 [구조체/공용체 이름] 을 정리.
          //이 정보는 <Parser()> 를 돌릴때 마다 수정될수 있으므로 <Parser()> 사용후
          //한번씩 처리해야 한다.
          //
          //[2012.05.19.토][중요!!!]----------------------------------------------------
          //<Ide_TreeInfo> 안에서 [형식 적용 문자열] 정보 정리를 위하여 [구조체/공용체]
          //정보를 사용하므로 먼저 처리해야 한다.
          //}---------------------------------------------------------------------------

          database->StrHeapConf_Type();

      //}

      //[설계정보 표시]
      //{
          //[2009.02.13.금][추가!!!]{-----------------------------
          //{DATABASE} 의 내용을 [설계정보] [Tree] 에 정리해준다.
          //Parser() 이 끝나면 바로 정리해 준다.
          //}-----------------------------------------------------

          Ide_TreeInfo();

      //}

      for(i = 0, cnt = 0; cnt < c_Count; i++)
      {
        //[직계가지 인가?]
        //{
             //[!]{-----------------------------------------------------
             //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
             //이는 [옹이] 의 [직계가지] 에만 해당한다.
             //}--------------------------------------------------------

             //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
             if((tree_tree_Form->_tree[d_TREE_project].items[nodeItemIndex].level + 1) !=
                 tree_tree_Form->_tree[d_TREE_project].items[i + (nodeItemIndex + 1)].level) continue;

        //}

        //[처리할 문서 경로 얻기]
        //{
            //[2009.01.27.화][추가!!!]{-------------------------------------------------------------
            //현재 열려 있는 [설계묶음] <Tree> 에서 <*.c> 문서를 하나 씩 읽어서 경로를 만들어 준다.
            //현재는 해당 항목의 <text> 에 있는 것이 <*.gprj> 가 있는 폴더 안의 경로가 된다.
            //}-------------------------------------------------------------------------------------

            STR_Assign(filePath, database->projectpath);

            STR_Add_AB(filePath,
                       filePath,
                       //[2012.04.20.금][수정!!!]
                       //실제 문서는 [옹이] 의 다음부터 시작된다.-----------------------v
                       tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, nodeItemIndex + 1 + i));

            //처리할 문서가 없는 경우는 처리하지 않는다.
            if(filePath == "") goto lbError;//return(false);

        //}

        //[ASM 번역]
        //{
            //[2008.11.26.수][추가!!!]{-----------
            //<*.t> 문서를 <*.asm> 으로 번역한다.
            //}-----------------------------------

            //[문서 이름 구하기]
            //{
                //먼저 순수 name 만 추출한다. ("name.ext" 형식...)
                STR_GetFileNameOnly(filePath, fileName);

                //확장자를 *.gtmp 로 바꾸어 준다.
                STR_ChangeFileExt(fileName, "gtmp", fileNewName);

                //새로운 경로를 만들어 준다.
                STR_Assign(fileFullName, database->buildpath);
                STR_Add(fileFullName, fileNewName);

            //}

            //[경로 보여주기!!!]
            //{
                //현재 처리할 문서의 경로를 보여준다.
                //msg_msg_Form->_PrintAddLine(d_msg_msg, fileFullName);

            //}

            if(AsmEncoder(fileFullName) == true)
            {
              //이상없이 처리 되었다.

            }
            else
            {
              //처리시 오류가 발생하였다(실제 오류는 있을수 없다).
              //return(false);
              goto lbError;

            }

            //처리한 문서수 증가.
            cnt++;

        //}

      }

      for(i = 0, cnt = 0; cnt < c_Count; i++)
      {
        //[직계가지 인가?]
        //{
             //[!]{-----------------------------------------------------
             //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
             //이는 [옹이] 의 [직계가지] 에만 해당한다.
             //}--------------------------------------------------------

             //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
             if((tree_tree_Form->_tree[d_TREE_project].items[nodeItemIndex].level + 1) !=
                 tree_tree_Form->_tree[d_TREE_project].items[i + (nodeItemIndex + 1)].level) continue;

        //}

        //[처리할 문서 경로 얻기]
        //{
            //[2009.01.27.화][추가!!!]{-------------------------------------------------------------
            //현재 열려 있는 [설계묶음] <Tree> 에서 <*.c> 문서를 하나 씩 읽어서 경로를 만들어 준다.
            //현재는 해당 항목의 <text> 에 있는 것이 <*.gprj> 가 있는 폴더 안의 경로가 된다.
            //}-------------------------------------------------------------------------------------

            STR_Assign(filePath, database->projectpath);

            STR_Add_AB(filePath,
                       filePath,
                       //[2012.04.20.금][수정!!!]
                       //실제 문서는 [옹이] 의 다음부터 시작된다.-----------------------v
                       tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, nodeItemIndex + 1 + i));

            //처리할 문서가 없는 경우는 처리하지 않는다.
            if(filePath == "") goto lbError;//return(false);

        //}

        //[OB1 번역]
        //{
            //[2009.01.15.목][추가!!!]{---------------
            //<*.asm> 문서를 <*.ob1> 문서로 번역한다.
            //}---------------------------------------

            //[문서 이름 구하기]
            //{
                //먼저 순수 name 만 추출한다. ("name.ext" 형식...)
                STR_GetFileNameOnly(filePath, fileName);

                //확장자를 *.asm 로 바꾸어 준다.
                STR_ChangeFileExt(fileName, "gasm", fileNewName);

                //새로운 경로를 만들어 준다.
                STR_Assign(fileFullName, database->buildpath);
                STR_Add(fileFullName, fileNewName);

            //}

            //[경로 보여주기!!!]
            //{
                //현재 처리할 문서의 경로를 보여준다.
                //msg_msg_Form->_PrintAddLine(d_msg_msg, fileFullName);

            //}

            if(Object1st(fileFullName) == true)
            {
              //이상없이 처리 되었다.

            }
            else
            {
              //처리시 오류가 발생하였다(실제 오류는 있을수 없다).
              //return(false);
              goto lbError;

            }

            //처리한 문서수 증가.
            cnt++;

        //}

      }

      //[알림글 출력]
      //{
          //[2009.02.12.목][추가!!!]
          msg_msg_Form->_PrintAddLine(d_msg_msg, "[해석] 완료!");

      //}

      //[단계 구분 처리]
      //{
          //[2009.02.12.목][추가!!!]{------------------
          //해당 단계 처리요청이 없다면 바로 종료한다.
          //}------------------------------------------

          if((pStep & d_Build_Object) != d_Build_Object)
          {
            //[2009.02.12.목][추가!!!]{-----------------------------------------------------------
            //<*.gvmx> 가 생성된 것이 아닌 경우이므로 false 로 하여 다음 처리가 되지 않게 만든다.
            //이는 "|>" 버튼으로 자동 처리 되는 경우 더이상 진행하지 못하게 하기 위한 것이다.
            //}-----------------------------------------------------------------------------------

            //return(false);
            goto lbError;

          }

      //}

      for(i = 0, cnt = 0; cnt < c_Count; i++)
      {
        //[직계가지 인가?]
        //{
             //[!]{-----------------------------------------------------
             //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
             //이는 [옹이] 의 [직계가지] 에만 해당한다.
             //}--------------------------------------------------------

             //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
             if((tree_tree_Form->_tree[d_TREE_project].items[nodeItemIndex].level + 1) !=
                 tree_tree_Form->_tree[d_TREE_project].items[i + (nodeItemIndex + 1)].level) continue;

        //}

        //[처리할 문서 경로 얻기]
        //{
            //[2009.01.27.화][추가!!!]{-------------------------------------------------------------
            //현재 열려 있는 [설계묶음] <Tree> 에서 <*.c> 문서를 하나 씩 읽어서 경로를 만들어 준다.
            //현재는 해당 항목의 <text> 에 있는 것이 <*.gprj> 가 있는 폴더 안의 경로가 된다.
            //}-------------------------------------------------------------------------------------

            STR_Assign(filePath, database->projectpath);

            STR_Add_AB(filePath,
                       filePath,
                       //[2012.04.20.금][수정!!!]
                       //실제 문서는 [옹이] 의 다음부터 시작된다.-----------------------v
                       tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, nodeItemIndex + 1 + i));

            //처리할 문서가 없는 경우는 처리하지 않는다.
            if(filePath == "") goto lbError;//return(false);

        //}

        //[OBJ 번역]
        //{
            //[2009.01.22.목][추가!!!]{---------------
            //<*.ob1> 문서를 <*.obj> 문서로 번역한다.
            //}---------------------------------------

            //[문서 이름 구하기]
            //{
                //먼저 순수 name 만 추출한다. ("name.ext" 형식...)
                STR_GetFileNameOnly(filePath, fileName);

                //확장자를 *.ob1 로 바꾸어 준다.
                STR_ChangeFileExt(fileName, "gob1", fileNewName);

                //새로운 경로를 만들어 준다.
                STR_Assign(fileFullName, database->buildpath);
                STR_Add(fileFullName, fileNewName);

            //}

            //[경로 보여주기!!!]
            //{
                //현재 처리할 문서의 경로를 보여준다.
                //msg_msg_Form->_PrintAddLine(d_msg_msg, fileFullName);

            //}

            if(Object(fileFullName) == true)
            {
              //이상없이 처리 되었다.

            }
            else
            {
              //처리시 오류가 발생하였다(실제 오류는 있을수 없다).
              //return(false);
              goto lbError;

            }

            //처리한 문서수 증가.
            cnt++;

        //}

      }

      //[알림글 출력]
      //{
          //[2009.02.12.목][추가!!!]
          msg_msg_Form->_PrintAddLine(d_msg_msg, "가상기계 [부품] 만들기 완료!");

      //}

      //[단계 구분 처리]
      //{
          //[2009.02.12.목][추가!!!]{------------------
          //해당 단계 처리요청이 없다면 바로 종료한다.
          //}------------------------------------------

          if((pStep & d_Build_Link) != d_Build_Link)
          {
            //[2009.02.12.목][추가!!!]{-----------------------------------------------------------
            //<*.gvmx> 가 생성된 것이 아닌 경우이므로 false 로 하여 다음 처리가 되지 않게 만든다.
            //이는 "|>" 버튼으로 자동 처리 되는 경우 더이상 진행하지 못하게 하기 위한 것이다.
            //}-----------------------------------------------------------------------------------

            //return(false);
            goto lbError;
            
          }

      //}

      //[LINK 처리]
      //{
          //[2009.01.22.목][추가!!!]{---------------
          //<*.ob1> 문서를 <*.obj> 문서로 번역한다.
          //}---------------------------------------

          //[문서 이름 구하기]
          //{
              //[설계묶음] 을 대상으로 하므로 [문서이름] 은 처리하지 않는다.

          //}

          //처리하면서 결과가 저장되 있는 <*.glnk> 문서의 경로를 받아 온다.
          if(Link(fileName) == true)
          {
            //이상없이 처리 되었다.

          }
          else
          {
            //오류 발생!!!

            msgStr = "\r\n< LINK > : 함수 연결 오류!!!\r\n"
                     "[ " + (AnsiString)database->errorinfo.word + " ]\r\n" +
                     (AnsiString)database->errorinfo.strbuf.buf;

            //[2022.05.27.금][주석처리]
            //msg_msg_Form->_PrintAddLine(d_msg_msg, msgStr.c_str());

            //[오류 단어 시작위치 기록]
            //{
                //[2022.07.14.목][추가]{-------------------------------------------------
                //[링크] 시의 [오류단어] 는 [편집기] 상에서 지정할수 없으므로 <-1> 처리.
                //}----------------------------------------------------------------------
                
                errorWordStartIndex = -1;

            //}

            //return(false);
            goto lbError;

          }

      //}

      //[알림글 출력]
      //{
          //[2009.02.12.목][추가!!!]
          msg_msg_Form->_PrintAddLine(d_msg_msg, "가상기계 [부품 조립] 완료!");

      //}

      //[단계 구분 처리]
      //{
          //[2009.02.12.목][추가!!!]{------------------
          //해당 단계 처리요청이 없다면 바로 종료한다.
          //}------------------------------------------

          if((pStep & d_Build_Gvmx) != d_Build_Gvmx)
          {
            //[2009.02.12.목][추가!!!]{-----------------------------------------------------------
            //<*.gvmx> 가 생성된 것이 아닌 경우이므로 false 로 하여 다음 처리가 되지 않게 만든다.
            //이는 "|>" 버튼으로 자동 처리 되는 경우 더이상 진행하지 못하게 하기 위한 것이다.
            //}-----------------------------------------------------------------------------------

            //return(false);
            goto lbError;
          }

      //}

      //[Gvmx 생성]
      //{
          //[2009.02.11.수][추가!!!]{----------------------------------------------------
          //<*.glnk> 를 가지고 실제적으로 구동가능한 가상기계 <*.gvmx> 2진문서를 만든다.
          //이미 <*.glnk> 문서의 [이름] 은 Link() 함수 처리시 자동으로 얻어 졌다.
          //}----------------------------------------------------------------------------
 
          if(Gvmx(fileName) == true)
          {
            //이상없이 처리 되었다.

          }
          else
          {
            //오류 발생!!!

            //return(false);
            goto lbError;

          }

      //}

      //[알림글 출력]
      //{
          //[2009.02.12.목][추가!!!]
          msg_msg_Form->_PrintAddLine(d_msg_msg, "가상기계 [제작] 완료!");

      //}

  //}

  //[{DATABASE} 내용 정리]
  //{
      //[2009.01.28.수][추가!!!]{------------------------------------------
      //<Build> 후에는 자동 적으로 {DATABASE} 안의 내용을 이미 만들어 놓은
      //전용 경로에 문서로 정리해 준다.
      //}------------------------------------------------------------------

      database->DEBUG_Database_View();

  //}

  lbOk:
  //{
      //[진행 상태창 감추기]
      //{
          //[2011.04.29.금][추가!!!]
          buildStatus_Form->_Off();

      //}

      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      //[편집기 선택영역 해제]
      //{
          //[2022.05.30.월][추가]{----------------------------------------
          //[이상없이] 종료된 경우는, 이전에 [오류] 등으로 존재 할수 있는
          //[선택영역] 을 해제시킨다(사용자가 오류로 착각하는 것을 방지).
          //}-------------------------------------------------------------

          editor_edit_Form->_Edit_Select_Off();

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.05.30.월][추가]{-----------------------------------------------------
          //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
          //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨 것을 기본으로 북구.
          //}--------------------------------------------------------------------------

          editor_top_Form->_balloonBox->_KillFocusUse(true);

      //}

      return(true);

  //}

  lbError:
  //{
      //[오류 내용 출력]
      //{
          //[2022.05.27.금][추가]{-----------------------------------------------------
          //위의 <Parser()>, <Link()> 에서 즉시 처리하지 않고 여기서 한번에 출력한다.
          //이는 API 자동 추가기능 추가로, 여기에 해당하는 이름의 경우는 오류가 아니라
          //[API 자동 추가 대상] 이기 때문이다.
          //
          //즉, [오류단어] 가 [API 이름] 이 아닌 경우만 순수 오류로 보고 [오류내용] 을
          //출력하기 위한것.
          //}--------------------------------------------------------------------------

          if(API_Check(database->errorinfo.word) == true)
          {
            //[중요]{**************************************************************************
            //이 경우는 [오류단어] 가 API 에 해당하는 것으로 보고(추가되지 않은 API 사용 등),
            //자동으로 API 를 [Tree:설계묶음->함수묶음] 에 추가하고 다시 이 IDE_Build() 함수를
            //처음부터 시작시킨다.
            //}********************************************************************************

            if(API_Add_To_Project(database->errorinfo.word) == true)
            {
              //[편집기 제목줄 풍선도움말에 추가한 API 표기]
              //{
                  //[2022.05.30.월][추가]

                  bls  = STR_Assign(balloonStr, "API : \"");
                  bls += STR_Assign(&(balloonStr[bls]), database->errorinfo.word);
                  bls += STR_Assign(&(balloonStr[bls]), "\" 함수가 [설계묶음] 에 자동으로 추가됐습니다.");

                  //[풍선도움말 출력]
                  //{
                      //[2022.07.14.목][추가]{---------------------------------------------------
                      //<errorWordStartIndex < 0> 으로 지정된 것이 없다면 그냥 기본 위치에 표시.
                      //지정된 것이 있다면 편집기 상의 해당 단어 위치에 출력.
                      //}------------------------------------------------------------------------
                      
                      if(errorWordStartIndex < 0)
                      {
                        editor_top_Form->_BalloonBox_Print(balloonStr);

                      }
                      else
                      {
                        editor_top_Form->_BalloonBox_Print_At_FindStr(NULL, errorWordStartIndex, balloonStr);

                      }  

                  //}    

              //}

              //자동으로 API 를 추가했으므로 다시 이 함수 처음부터 실행한다.
              goto lbStart; 

            }
            else
            { 
              //API 추가시 오류가 발생한 경우도 일반 오류로 간주하고 해당 처리부로 넘긴다.
              goto lbErrorInfoPrint;

            }

          }
          else
          {
            //[API 에 사용된 <정의/구조체/공용체이름> 인지 확인]
            //{
                //[오류단어 확인]
                //{
                    //[2022.06.08.수][수정]{-------------------------------------------------
                    //[VAR]{ ... } 안에서 [구조체/공용체] 생성 오류인 경우는 [오류단어] 가
                    //<struct>, <union> 으로 지정되어 구체적인 API 를 찾을수 없으므로,
                    //이 경우는 위의 <Parser()> 함수의 오류 처리부에서 얻은 <errorNextWord_>
                    //를 사용한다.
                    //}----------------------------------------------------------------------

                    //[키워드] 와 비교하므로 대소문자를 구분해서 비교해야 한다.
                    if((STR_Match(database->errorinfo.word, "struct") == true) ||
                       (STR_Match(database->errorinfo.word, "union") == true))
                    {
                      defFile_ApiCount = API_DefFile_Check(errorNextWord_, &defFile_ApiList_);

                    }
                    else
                    {
                      defFile_ApiCount = API_DefFile_Check(database->errorinfo.word, &defFile_ApiList_);

                    }

                //}    
            
                if(defFile_ApiCount > 0)
                {
                  //[!]{--------------------------------------------------------
                  //이 경우는 [오류단어] 가 <[API 이름.h> 에 정의된 [정의이름] 인 경우다.
                  //}-----------------------------------------------------------

                  if(defFile_ApiCount == 1)
                  {
                    //[!]{---------------------------------------------------
                    //단, 한 개의 API 라면 여기서 해당 API 를 바로 추가한다.
                    //}------------------------------------------------------

                    //[API 이름 추출]
                    //{
                        //[!]{---------------------------------------------------------------------------------
                        //[API 목록] 은 행단위 목록으로 항목이 한개라도 뒤에 [NULL 행] 이 있으므로(실제는 2행)
                        //[API 이름] 에 해당하는 첫번째 행만 추출한다.
                        //}------------------------------------------------------------------------------------

                        STR_Get_ThisLineStr(defFile_ApiList_, 0, defFile_ApiName_);                          

                    //}
                    
                    //[<def_file> 관련 저장소 초기화]
                    //{
                        //[!]{----------------------------------------------------------------------------------------
                        //<IDE_Build()> 가 API 자동 추가로 계속 반복 실행될수 있으므로, 여기서 기존에 생성/사용한 것을 삭제해주어야 한다.
                        //이미 <defFile_ApiList_> 에서 <defFile_ApiName_> 을 얻었으므로 이 시점에서 더이상 불필요
                        //}-------------------------------------------------------------------------------------------
                        
                        if(defFile_ApiList_ != NULL) { delete defFile_ApiList_; defFile_ApiList_ = NULL; }

                    //}

                    if(API_Add_To_Project(defFile_ApiName_) == true)
                    {
                      //[편집기 제목줄 풍선도움말에 추가한 API 표기]
                      //{
                          bls  = STR_Assign(balloonStr, "API : \"");
                          bls += STR_Assign(&(balloonStr[bls]), defFile_ApiName_);
                          bls += STR_Assign(&(balloonStr[bls]), "\" 함수가 [설계묶음] 에 자동으로 추가됐습니다.");

                          //[풍선도움말 출력]
                          //{
                              //[2022.07.14.목][추가]{---------------------------------------------------
                              //<errorWordStartIndex < 0> 으로 지정된 것이 없다면 그냥 기본 위치에 표시.
                              //지정된 것이 있다면 편집기 상의 해당 단어 위치에 출력.
                              //}------------------------------------------------------------------------

                              if(errorWordStartIndex < 0)
                              {
                                editor_top_Form->_BalloonBox_Print(balloonStr);

                              }
                              else
                              {
                                editor_top_Form->_BalloonBox_Print_At_FindStr(NULL, errorWordStartIndex, balloonStr);

                              }

                          //}

                      //}

                      //자동으로 API 를 추가했으므로 다시 이 함수 처음부터 실행한다.
                      goto lbStart;

                    }
                    else
                    {
                      //API 추가시 오류가 발생한 경우도 일반 오류로 간주하고 해당 처리부로 넘긴다.
                      goto lbErrorInfoPrint;

                    }

                  }
                  else
                  {
                    //[!]{-------------------------------------------------------------------------
                    //[정의이름] 을 포함하고 있는 API 가 2 개 이상이라면 이 [정의이름] 을 가진 API 목록을 보여주고
                    //사용자가 직접 해당 API 를 [설계묶음] 에 추가할수 있도록 안내한다.
                    //}----------------------------------------------------------------------------

                    //[VSTRBUF:생성]
                    //{                      
                        vStrBuf_ = new VSTRBUF;
                        
                        //내부에서 자동으로 "" 로 초기화.
                        vStrBuf_->Create();
                        
                    //}    
                    
                    //[출력 내용 합성]
                    //{
                        vStrBuf_->Add("정의되지 않은 [ ");
                        vStrBuf_->Add(database->errorinfo.word);
                        vStrBuf_->Add(" ] 사용으로 인한 오류 발견.\r\n\r\n");

                        vStrBuf_->Add("아래 API 목록중 하나를 선택하여 [설계묶음] 에 추가하는 것으로\r\n");
                        vStrBuf_->Add("이 오류를 해결할 수 있습니다.\r\n\r\n");
                        vStrBuf_->Add(defFile_ApiList_);
                    
                    //}
                    
                    //[알림문 출력]
                    //{
                        ide_msgbox_Form->_MsgBox(d_MSGBOX_info, vStrBuf_->Get_Str());
                        
                    //}
                                          
                    //[VSTRBUF:삭제]
                    //{
                        if(vStrBuf_ != NULL)
                        {
                          vStrBuf_->Delete();

                          delete vStrBuf_;

                        }

                    //}

                    //[<def_file> 관련 저장소 초기화]
                    //{
                        //[!]{----------------------------------------------------------------------------------------
                        //<IDE_Build()> 가 API 자동 추가로 계속 반복 실행될수 있으므로, 여기서 기존에 생성/사용한 것을 삭제해주어야 한다.
                        //}-------------------------------------------------------------------------------------------
                        
                        if(defFile_ApiList_ != NULL) { delete defFile_ApiList_; defFile_ApiList_ = NULL; }

                    //}

                  }
                  
                }  

            //}
          
            lbErrorInfoPrint:

            //[오류 문자열 출력]
            //{
                //[2023.01.29.일][수정]{---------------------
                //"" 인 경우는 오류문자열을 출력하지 않는다.
                //}------------------------------------------

                if(msgStr != "")
                {
                  //이 경우는 순수 오류에 해당하므로 오류 문자열을 출력.
                  msg_msg_Form->_PrintAddLine(d_msg_msg, msgStr.c_str());

                }

            //}

          }

      //}

      //[진행 상태창 감추기]
      //{
          //[2011.04.29.금][추가!!!]
          buildStatus_Form->_Off();

      //}

      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.05.30.월][추가]{-----------------------------------------------------
          //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
          //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨 것을 기본으로 북구.
          //}--------------------------------------------------------------------------

          editor_top_Form->_balloonBox->_KillFocusUse(true);

      //}

      //[오류 알림]
      //{
          //[2022.06.04.토][추가]{---------------------------------------------------------------------
          //[맷돌-IDE] 아래 [출력창] 의 출력 문자열 만으로는 이상없이 종료됐는지, [오류] 로 종료됐는지
          //직관적으로 알수 없어, [오류]  임에도 그냥 지나치는 경우가 있어 이를 방지하고자 확실하게
          //[오류] 임을 알려주는 [알림문] 을 출력한다.
          //
          //단, 오류 내용이 있는 경우에 한한다.
          //이는 <Build> 관련 오류(문법검사 등)의 경우에만 사용하기 위한것.
          //}------------------------------------------------------------------------------------------

          if((msgStr.c_str())[0] != '\0')
          {
            //[주의]{******************************************************************
            //if(msgStr != "") 로 처리하는 경우는 [최적화] 과정에서 <msgStr> 에 한번도
            //문자열 저장이 없는 경우(Build 관련 이외의 오류)에서 <msgStr> 자체가 생성
            //되지 않아 [BCB:포인터오류] 가 발생할 수 있다.
            //그러므로, 반드시 사용된 코드로 인식하도록 <msgStr.c_str()> 로 사용한다.
            //}************************************************************************

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
		     						 "오류가 발견됐습니다.\r\n\r\n"
                                     "자세한 정보는 아래 [출력창] 의 내용을 참고 바랍니다.");

          }

      //}
  
      return(false);

  //}

}

void __fastcall Ide_Glib_MakeHeader(void)
{
  //[2009.05.28.목][생성!!!]{-------------------------------------------------------------------
  //[함수묶음] 에 등록된 모든 [함수묶음] 의 <*.h> 를 전부 읽어서 <함수묶음.h> 문서로
  //만들어서 [설계묶음] 위치에 자동 저장한다.
  //이는 사용자가 일일히 [함수묶음] 의 <*.h> 를 문서에 추가하는 번거로움 없이 <함수묶음.h> 문서
  //한개만 추가하는 것으로 끝내게 하기 위한 것이다.
  //Parser() 가 구동되기 전 무조건 실행되어 정리되어야 한다.
  //
  //[2011.05.09.월][중요수정!!!]----------------------------------------------------------------
  //[Tree:함수묶음] 의 구조가 [경로] 방식에서 [Tree 구조] 방식으로 변경되었으므로 이전처럼
  //바로 <txt> 를 사용할수 없으며, [경로] 를 합성하여 사용해야 한다.
  //이와 관련된 중요 수정을 한다.
  //}-------------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  fileName[OPT_filepath_length];

      int   i;

      //[<설계묶음> 관련]
      //{
          int  nodeIndex;
          int  glib_Count;

      //}

      //[문서 관련]
      //{
          //<함수묶음.h> 을 만들 임시 저장소.
          char  *buf = NULL;

          //<함수묶음.h> 의 임시 저장소 생성 크기.
          int    bufSize;

      //}

      //[2011.05.09.월][추가!!!]
      struct  TREE   *tree;

      //[2011.05.09.월][추가!!!]
      int     nodeLastItemIndex;

      //[2011.05.09.월][추가!!!]
      char    tempStr[OPT_lineStrSize];

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[<함수묶음.h> 닫기]
  //{
      //[!]{---------------------------------------------------------------------------
      //현재 열려있는 <함수묶음.h> 문서가 있다면 닫아준다.
      //이는 새로 생성되면 현재 열려 있는 문서의 내용은 아무 의미가 없어지기 때문이다.
      //}------------------------------------------------------------------------------

      Ide_File_Close_GlibSysHeader();

  //}

  //[<Tree:함수묶음> 옹이 정보 얻기]
  //{
      //현재 [옹이] 의 [하위항목] 관련 정보를 수집한다.
      tree_tree_Form->_Tree_Get_Node_LastItemIndex2
                      (tree,
                       "glib",
                       //이 옹이의 [절대위치].
                       &nodeIndex,
                       NULL,
                       //지정 [옹이] 의 가장 마지막 가지의 item-index.
                       &nodeLastItemIndex);

  //}

  //[<*.glib> 항목 수 얻기]
  //{
      //[!]{----------------------------------------------------------
      //기존의 [경로] 방식과 달리 [Tree 구조] 방식으로 변경되었으므로
      //<*.glib> 항목의 수를 직접 검사하여 얻어야 한다.
      //}-------------------------------------------------------------

      for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
          i = nodeIndex + 1,
          glib_Count = 0;
          //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //[<txt> 가 <*.glib> 인가?]
        //{
            //[!]{----------------------------------------------------------------------------
            //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
            //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
            //}-------------------------------------------------------------------------------

            //[항목] 의 <txt> 에서 [확장자] 추출.
            //[2012.04.20.금][수정!!!]
            STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, i), tempStr);

            //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
            if(STR_Match_NoCase(tempStr, "glib") != true) continue;

        //}

        glib_Count++;

      }

  //}

  //[<함수묶음.h> 만들기]
  //{
      //[!]{-------------------------------------------------------------------------------------
      //[함수묶음] 에 등록된 모든 [함수묶음] 들을 사용할수 있는 <함수묶음.h> 문서를 만들어 준다.
      //각각의 <*.h> 는 항상 해당 [함수묶음] 과 같은 위치에 있으므로 [함수묶음] 의 현재 경로에서
      //[확장자] 만 <*.h> 로 바꾸면 된다.
      //}----------------------------------------------------------------------------------------

      //[저장소 크기 구하기]
      //{
          //[!]{------------------------------------------------------------------------
          //<함수묶음.h> 를 만들기 위하여 대략적인 문서의 크기를 구한다.
          //[함수묶음] 한개의 <#inlcude "..."> 를 256 byte 로 잡아서 처리한다.
          //단, 간단한 문서 구성을 해야 하므로 넉넉하게 설정한다.
          //
          //[2009.06.05.금][중요수정!!!]------------------------------------------------
          //아무 문서도 없는 경우라도 일단 <함수묶음.h> 를 빈문서로 생성해 주어야 한다.
          //이는 항상 이 문서가 #include 된 상태이므로 이전에 생성된 문서로 이하여 없는
          //함수묶음에 접근할수 있기 때문이다.
          //이 경우는 간단하게 1K 정도로 일단 생성한다.
          //}---------------------------------------------------------------------------

          if(glib_Count <= 0)
          {
            //처리할 <*.glib> 가 [함수묶음] 안에 하나도 없는 경우는 1K 정도로 설정해 준다.
            bufSize = 1024;

          }
          else
          {
            bufSize = OPT_Glib_IncludeStrSize * (glib_Count * 2);

          }

      //}

      //[저장소 셍성]
      //{
          //<함수묶음.h> 를 저장할 저장소를 동적 생성한다.
          //buf = new char [bufSize];
          //[동적생성단위적용][2021.01.24.일][수정]
          buf = new char [UnitX(1024, bufSize)];


      //}

      //[기본 문서 추가]
      //{
          //간단한 설명글을 추가한다.
          STR_Assign(buf, "\r\n"
                          "//이 문서는 [설계묶음] 에 등록된 [함수묶음] 을 사용하기 위한 것입니다.\r\n"
                          "//이 문서는 자동 생성되며 사용자는 이곳에 다른 내용을 추가하거나 안의 내용을 삭제해서는 안됩니다.\r\n"
                          "//[함수묶음] 안의 [함수] 를 사용하고자 하는 <*.c> 등에 아래와 같이 추가하여 사용합니다.\r\n"
                          "//\r\n"
                          "//#include  \"함수묶음.h\"\r\n"
                          "//\r\n"
                          "//기계닉스 첨단 대장장이 김 갑철."
                          "\r\n\r\n");

      //}

      //[<*.h> 문서 경로 수집/합성]
      //{
          //[!]{----------------------------------------------------------
          //기존의 [경로] 방식과 달리 [Tree 구조] 방식으로 변경되었으므로
          //<*.glib> 항목의 수를 직접 검사하여 얻어야 한다.
          //}-------------------------------------------------------------

          for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
              i = nodeIndex + 1;
              //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
              i <= nodeLastItemIndex;
              i++)
          {
            //[<txt> 가 <*.glib> 인가?]
            //{
                //[!]{----------------------------------------------------------------------------
                //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
                //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
                //}-------------------------------------------------------------------------------

                //[항목] 의 <txt> 에서 [확장자] 추출.
                //[2012.04.20.금][수정!!!]
                STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, i), tempStr);

                //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
                if(STR_Match_NoCase(tempStr, "glib") != true) continue;

            //}

            //[추가할 <*.h> 이름 얻기]
            //{
                //[!]{---------------------------------------------------------------------
                //지금 <*.glib> 항목과 <*.h> 는 항상 같은 위치에 있으므로 먼저 <*.glib> 의
                //[경로] 를 구한뒤 [확장자] 만 <*.h> 로 바꿔주면 된다.
                //}------------------------------------------------------------------------

                //[경로추출]
                //{
                    //현재 <*.glib> 항목의 [설계묶음 내부 경로] 를 합성한다.
                    Ide_Project_Glib_Make_InFileName(tree, i, tempStr);

                //}

                //[확장자 <*.h> 로 교체]
                //{
                    STR_ChangeFileExt(tempStr, "h", fileName);

                //}

            //}

            //[문서 추가]
            //{
                //[!]{------------------------------------------------------
                //<#include  "문서이름\r\n"> 의 형식으로 행단위로 추가한다.
                //}---------------------------------------------------------

                STR_Add(buf, "#include  \"");
                STR_Add(buf, fileName);
                STR_Add(buf, "\"\r\n");

            //}

          }

      //}

  //}

  //[문서 저장]
  //{
      //<함수묶음.h> 로 현재 [설계묶음] 과 같은 위치에 저장한다.

      //[문서이름 만들기]{-------------------------
      //저장경로 만들기.
      STR_Assign(fileName, database->projectpath);
      STR_Add(fileName, "함수묶음.h");
      //}------------------------------------------

      FILE_Save(fileName, (unsigned char *)buf, STR_Length(buf));

  //}

  //[저장소 삭제]
  //{
      if(buf != NULL) { delete [] buf; buf = NULL; }

  //}

}

void __fastcall Ide_Glib_MakeGtxt(//지정 [옹이] 의 [절대위치].
                                  int    pNodeIndex,
                                  //완성되어 저장된 문서의 경로.
                                  char  *rFileFullName)
{
  //[2011.05.09.월][생성!!!]{--------------------------------------------------------------
  //이전 <Ide_Glib_MakeGtxt()> 함수를 폐기하고 전부 새로 만든다.
  //
  //이는 [Tree:함수묶음] 이 이전의 [경로] 방식에서 [Tree 구조] 방식으로 변경됐기 때문이다.
  //즉, [Tree:API] 와 같은 방식이므로 <Ide_Tree_Api_Glib_MakeGtxt()> 함수를 참고하여
  //전부 새로 만든다.
  //
  //1) 지정 [옹이] 안의 모든 하위 항목의 <*.gtxt> 를 순서대로 전부 합성한다.
  //2) 지정 [옹이] 의 이름과 같은 [이름] 으로 <*.gtxt> 문서를 만들어
  //   [설계믂음\glib] 폴더 안에 생성해 준다(반드시 존재하는 폴더이므로).
  //   [옹이] 의 경로에 무관하게 [설계믂음\glib] 에 생성한다는 점에 주의한다.
  //
  //[주의!!!]------------------------------------------------------------------------------
  //반드시 대상이 [옹이] 이어야 한다.
  //}--------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      char    tempStr[OPT_lineStrSize];

      char    fileName[OPT_lineStrSize];

      char    fileGtxtName[OPT_lineStrSize];

      int     i;

      //[<*.gtxt> 문서 목록]{-----------------------------------------------------------
      //지정 [옹이] 에 포함돼 있는 모든 <*.gtxt> 의 [전체경로] 를 [행단위] 로 관리한다.
      //동적으로 문서수에 따른 크기로 생성된다.
      char  *fileList = NULL;
      //
      //<fileList[]> 상의 문자열이 추가되는 위치(이전 문자열 끝 위치).
      int    fileListSaveIndex;
      //}-------------------------------------------------------------------------------

      int    glibCount;
      int    nodeLastItemIndex;

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

      tree = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[초기화]
  //{
      //반환할 문자열을 미리 초기화 한다.
      if(rFileFullName != NULL) { rFileFullName[0] = '\0'; }

  //}

  //[<저장 문서이름> 합성]
  //{
      //[!]{---------------------------------------------
      //항상 [설계묶음\glib] 폴더안에 생성되어야 하고
      //지정 <[옹이<txt>].gtxt> 를 이름으로 가져야 한다.
      //}------------------------------------------------

      STR_Add_AB(fileGtxtName, database->projectpath, "glib\\");

      //[옹이] 이름이 문서이름이 된다.
      //[2012.04.20.금][수정!!!]
      STR_Add(fileGtxtName, tree_tree_Form->_Item_Txt_StrPtr3(tree, pNodeIndex));

      //확장자 붙이기.
      STR_Add(fileGtxtName, ".gtxt");

  //}

  //[<*.gtxt> 닫기]
  //{
      //[!]{---------------------------------------------------------------------------
      //현재 열려있는 <함수묶음.gtxt> 문서가 있다면 닫아준다.
      //이는 새로 생성되면 현재 열려 있는 문서의 내용은 아무 의미가 없어지기 때문이다.
      //}------------------------------------------------------------------------------

      Ide_File_Close_GlibGtxt(fileGtxtName);

  //}

  //[지정 [옹이] 정보 얻기]
  //{
      tree_tree_Form->_Tree_Get_Node_LastItemIndex
                      (tree,
                       pNodeIndex,
                       //[직계가지] 의 마지막 [절대위치].
                       NULL,
                       //모든 하위 항목을 대상으로 한 마지막 [가지] 의 [절대위치].
                       &nodeLastItemIndex);

  //}

  //[<*.glib> 문서 총수 얻기]
  //{
      //[!]{-----------------------------------------------------------------
      //지정 [옹이] 에 포함돼 있는(하위전부) 모든 <*.glib> 의 개수를 얻는다.
      //}--------------------------------------------------------------------

      for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
          i = pNodeIndex + 1,
          glibCount = 0;
          //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //[<txt> 가 <*.glib> 인가?]
        //{
            //[!]{----------------------------------------------------------------------------
            //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
            //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
            //}-------------------------------------------------------------------------------

            //[항목] 의 <txt> 에서 [확장자] 추출.
            //[2012.04.20.금][수정!!!]
            STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, i), tempStr);

            //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
            if(STR_Match_NoCase(tempStr, "glib") != true) continue;

        //}

        glibCount++;

      }

  //}

  //[항목이 존재하나?]
  //{
      //[!]{--------------------------------------------------------
      //처리할 <*.glib> 가 하나도 없는 경우는 처리하지 않아야 한다.
      //}-----------------------------------------------------------

      if(glibCount <= 0)
      {
        //경로를 다시 초기화 한다.
        if(rFileFullName != NULL) { rFileFullName[0] = '\0'; }

        return;

      }

  //}

  //[문서 목록 저장소 생성]
  //{
      //[!]{---------------------------------------------------------------------
      //위에서 구한 <*.glib> 개수에 대응하는 문서 목록을 저장할 공간을 생성한다.
      //}------------------------------------------------------------------------

      //fileList = new char [OPT_filepath_length * glibCount];
      //[동적생성단위적용][2021.01.24.일][수정]
      fileList = new char [UnitX(1024, OPT_filepath_length * glibCount)];

      //뒤에서는 [추가] 만 하게 되므로 여기서 반드시 초기화 해야 한다.
      fileList[0] = '\0';

      //<fileList[]> 상의 0 위치부터 문자열이 저장된다.
      fileListSaveIndex = 0;

  //}

  //[문서 목록 수집]
  //{
      //[!]{--------------------------------------------------------------------
      //지정 [옹이] 의 모든 하위 <*.glib> 에 대응하는 <*.gtxt> 의 [전체경로] 를
      //수집한다.
      //}-----------------------------------------------------------------------

      for(//[항목] 은 [옹이] 위치 다음부처 시작한다.
          i = pNodeIndex + 1;
          //[Tree:함수묶음] 의 가장 마지막 항목까지 전부 검사한다.
          i <= nodeLastItemIndex;
          i++)
      {
        //[<txt> 가 <*.glib> 인가?]
        //{
            //[!]{----------------------------------------------------------------------------
            //<*.glib> 항목인 경우만 처리하므로 <txt> 속성의 [확장자] 를 확인한다.
            //사실상, <_bmp_item> 속성으로 쉽게 구분되지만 일반적인 [문자열] 방식을 사용한다.
            //}-------------------------------------------------------------------------------

            //[항목] 의 <txt> 에서 [확장자] 추출.
            //[2012.04.20.금][수정!!!]
            STR_GetFileExt(tree_tree_Form->_Item_Txt_StrPtr3(tree, i), tempStr);

            //확장자가 <*.glib> 가 아니라면 다음 항목으로 넘긴다.
            if(STR_Match_NoCase(tempStr, "glib") != true) continue;

        //}

        //[문서 이름 합성]
        //{
            //현재 <*.glib> 항목의 [설계묶음 내부 경로] 를 합성한다.
            Ide_Project_Glib_Make_InFileName(tree, i, fileName);

            //확장자를 <*.gtxt> 로 변환한다.
            STR_ChangeFileExt(fileName, "gtxt", tempStr);

            //[설계묶음] 경로를 합성하여 [전체 경로] 를 만들어 준다.
            STR_Add_AB(fileName, database->projectpath, tempStr);

            //[<*.gtxt> 문서가 존재하나?]
            //{
                if(FileExists(fileName) != true)
                {
                  //해당 <*.gtxt> 가 없는 경우는 대신에 <*.h> 문서를 열어주어야 한다.

                  //확장자를 <*.h> 로 변환한다.
                  STR_ChangeFileExt(fileName, "h", tempStr);

                  //<fileName> 을 수집하므로 다시 여기에 할당한다.
                  STR_Assign(fileName, tempStr);

                }

            //}

        //}

        //[목록에 수집]
        //{
            //[!]{-----------------------------------------------
            //문자열을 추가 하면서 동시에 결과 크기를 얻게 되며,
            //이 [크기] 는 결국 [다음 저장 시작 위치] 가 된다.
            //이는 처리 시간을 줄이기 위한 것이다.
            //
            //반드시 [행단위] 로 저장되어야 한다.
            //}--------------------------------------------------

            //[문서 전체 경로] 를 먼저 추가한다.
            fileListSaveIndex += STR_Add(&(fileList[fileListSaveIndex]), fileName);

            //한개의 [행] 으로 마무리 한다.
            fileListSaveIndex += STR_Add(&(fileList[fileListSaveIndex]), "\r\n");

        //}

      }

  //}

  //[<*.gtxt> 합성 저장]
  //{
      //[!]{----------------------------------------------------------
      //[문서목록] 의 모든 문서를 한개 문서로 [합성] 후 처음 만들어준
      //<fileGtxtName> 위치에 [저장] 해 준다.
      //}-------------------------------------------------------------

      //[합성하기]
      //{
          //새로 만든 <File_Compose2()> 를 사용하여 [한개] 의 문서로 [합성] 한다.
          File_Compose2(fileList, fileGtxtName);

      //}

      //[<*.gtxt> 저장 문서 이름 반환]
      //{
          //합성된 <*.gtxt> [문서 전체 이름] 을 반환한다.
          if(rFileFullName != NULL) { STR_Assign(rFileFullName, fileGtxtName); }

      //}

  //}

  //[저장소 삭제]
  //{
      if(fileList != NULL) { delete fileList; fileList = NULL; }

  //}

}

//------------------------------------------------------------------------------
//[IDE 운영 관련]---------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall IDE_Close(void)
{
  //[2009.02.02.월][생성!!!]{-----------------------------------------------------------------------
  //[통합개발환경] 을 [종료] 하는 과정을 수행한다.
  //[통합개발환경] [종료] 를 수행하는 경우는 반드시 이 함수를 사용해야 한다.
  //
  //단, [종료] 전에는 무조건 다시 한번 확인한다.
  //이는 [작업중인] 것을 굳이 저장하지 않고 부조건 그대로 그냥 종료 하고 싶은 경우도 있기 때문이다.
  //즉, 수정된 내용이 있더라도 그냥 종료를 원한다면 무조건 바로 종료하게 만든다.
  //
  //[2018.02.18.일][추가!!!]------------------------------------------------------------------------
  //IDE 종료시 열려있는 모든 통신포트를 닫도록 수정.
  //[기본통신포트/검증용통신포트] 모두 해당.
  //}-----------------------------------------------------------------------------------------------

  //[무조건 확인]
  //{
      if(ide_msgbox_Form->_MsgBox_Ok_Cancle(d_MSGBOX_info,
                                            "[통합개발환경] 을 [종료] 할까요?") == true)
      {
        //현재 작업 중인 모든 [설계묶음] 과 [편집기] 의 문서를 저장하고 종료한다.

        if(IDE_Project_New(false, false) != true) return;

      }
      else
      {
        //[취소] 가 눌린 것으로 종료하지 않아야 한다.
        return;

      }

  //}

  //[IDE 종료]
  //{
      //[2010.03.08.월][중요수정!!!]{-------------------------------------------------
      //아래 두개의 함수는 <~Tmain_Form()> 에서 처리하지 않고 반드시 여기서 처리한다.
      //또한, 반드시 main_Form->Close() 이전에 먼저 처리해 주어야 한다.
      //이렇게 하지 않으면 <GVmos> 가 제대로 삭제되지 않아서 <IDE> 가 종료되지 못하는
      //문제가 발생한다.
      //}-----------------------------------------------------------------------------

      //[VMOS Thread 삭제]
      //{
          //[2009.03.16.월][추가!!!]{--------------
          //동적 생성된 [VMOS Thread] 를 삭제한다.
          //}--------------------------------------

          VMOS_ThreadDelete();

      //}

      //[VDEBUG Thread 삭제]
      //{
          //[2009.04.06.월][추가!!!]{----------------
          //동적 생성된 [VDEBUG Thread] 를 삭제한다.
          //}----------------------------------------

          VDEBUG_ThreadDelete();

      //}

      //[모든 통신포트 닫기]
      //{
          //[2018.02.18.일][추가!!!]{-------------------------------------------
          //통신포트를 닫지 않고 종료 하는 경우는 아직 열린 상태라 문제가 발생.
          //다시 사용할때 문제가 발생할수 있다.
          //<Linux:wine> 구동시 이는 문제가 된다.
          //}-------------------------------------------------------------------
          
          Ide_Comport_Close();  //IDE 메인 통신포트.
          Ide_Comport2_Close(); //검증용 통신포트.

      //}

      //[main_Form 종료]
      //{
          //[!]{--------------------------------------------------------------------
          //위의 두개 함수를 먼처 처리하여 <GVmos> 와 <VMOS> 를 완전히 삭제한다음에
          //이 함수로 <main_Form> 을 삭제해 주어야 한다.
          //}-----------------------------------------------------------------------

          main_Form->Close();

      //}

  //}

  return;

}

void __fastcall IDE_Size_Max(void)
{
  //[2018.02.26.월][생성!!!]{------------------------------------------------------
  //[Linux:wine] 지원을 위하여 [최대화/기본화] 를 각 부분에서 직접 처리하지 않고
  //함수로 만들어 처리한다.
  //[Linux:wine] 지원부분을 한곳으로 일원화 하기 위한것.
  //
  //여기서는 [최대화] 관련을 처리.
  //
  //[Linux:wine] 에서는 <main_Form->WindowState = wsMaximized;> 와 같은 방법으로는
  //[최대화] 되지 않는다.
  //
  //[방법]-------------------------------------------------------------------------
  //
  //1) 현재 [위치/크기] 정보 저장.
  //1) 직접 위치를 (0, 0) 으로 조정.
  //2) 폭, 높이를 화면 크기로 조정.
  //3) <main_Form->WindowState = wsMaximized;> 로 설정.
  //   이는 다른 곳에서 [설정값] 으로 사용하므로 반드시 필요.
  //}------------------------------------------------------------------------------

  if(_ide_Option.wine == true)
  {
    //[Linux:wine] 지원의 경우.

    //[현재 위치/크기 정보 저장]
    //{
        _ide_Option.ideRect.left   = main_Form->Left;
        _ide_Option.ideRect.top    = main_Form->Top;
        _ide_Option.ideRect.width  = main_Form->Width;
        _ide_Option.ideRect.height = main_Form->Height;

    //}

    //[위치/크기 설정]
    //{
        main_Form->Left   = 0;
        main_Form->Top    = 0;
        main_Form->Width  = Screen->Width;
        main_Form->Height = Screen->Height;

        //여기서 [전체 크기 조정] 이 이루어 지므로 <main_Form->_Resize();> 호출은 불필요.
        //아래에서 <main_Form->WindowState = wsMaximized;> 로 설정된 이후는 [크기조정] 은
        //이루어 지지 않는다.

    //}

    //[상태 설정]
    //{
        //다른 곳에서도 설정값으로 사용하므로 반드시 기록.
        main_Form->WindowState = wsMaximized;

    //}

  }
  else
  {
    //[읜도우] 기본 처리.

    main_Form->WindowState = wsMaximized;

    //여기서 [전체 크기 조정] 이 이루어 지므로 <main_Form->_Resize();> 호출은 불필요.

  }

}

void __fastcall IDE_Size_Normal(void)
{
  //[2018.02.26.월][생성!!!]{----------------------------------------------------
  //[Linux:wine] 지원을 위하여 [최대화/기본화] 를 각 부분에서 직접 처리하지 않고
  //함수로 만들어 처리한다.
  //[Linux:wine] 지원부분을 한곳으로 일원화 하기 위한것.
  //
  //여기서는 [기본화] 관련을 처리.
  //}----------------------------------------------------------------------------

  if(_ide_Option.wine == true)
  {
    //[Linux:wine] 지원의 경우.

    //[상태 설정]
    //{
        //먼저 <wsNormal> 로 돌려 놓지 않으면 [크기조정] 이 되지 않는다.
        main_Form->WindowState = wsNormal;
        Application->Restore();

    //}

    //[위치/크기 복원]
    //{
        main_Form->Left   = _ide_Option.ideRect.left;
        main_Form->Top    = _ide_Option.ideRect.top;
        main_Form->Width  = _ide_Option.ideRect.width;
        main_Form->Height = _ide_Option.ideRect.height;

        //여기서 [전체 크기 조정] 이 이루어 지므로 <main_Form->_Resize();> 호출은 불필요.

    //}

  }
  else
  {
    //[읜도우] 기본 처리.

    main_Form->WindowState = wsNormal;
    Application->Restore();
    //여기서 [전체 크기 조정] 이 이루어 지므로 <main_Form->_Resize();> 호출은 불필요.

  }

}

void __fastcall IDE_Size_Min(void)
{
  //[2018.03.04.일][생성!!!]{---------------------------------------------
  //[Linux:wine] 지원을 위하여 [최소화] 를 각 부분에서 직접 처리하지 않고
  //함수로 만들어 처리한다.
  //[Linux:wine] 지원부분을 한곳으로 일원화 하기 위한것.
  //
  //[방법]----------------------------------------------------------------
  //
  //1) 현재 [위치/크기] 정보 저장.
  //2) 최소화.
  //}---------------------------------------------------------------------

  if(_ide_Option.wine == true)
  {
    //[Linux:wine] 지원의 경우.

    //[현재 위치/크기 정보 저장]
    //{
        //[기본위치] 로 전환하기 위하여 현재 정보를 [환경변수] 에 저장.
        _ide_Option.ideRect.left   = main_Form->Left;
        _ide_Option.ideRect.top    = main_Form->Top;
        _ide_Option.ideRect.width  = main_Form->Width;
        _ide_Option.ideRect.height = main_Form->Height;

    //}

    //[위치/크기 설정]
    //{
        //[작업표시줄] 로 이동.
        Application->Minimize();

    //}

  }
  else
  {
    //[읜도우] 기본 처리.

    //[작업표시줄] 로 이동.
    Application->Minimize();

  }

}

//------------------------------------------------------------------------------
//[Linux:Wine 지원 관련]--------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall IDE_Wine_Modal(//유사모달(true)/해제(false))
                               bool  pModal)
{
  //[2018.03.06.화][생성!!!]{-------------------------------------------------------
  //[Linux:Wine] 에서 [유사모달] 을 지원하기 위한 함수.
  //<ide_msgbox_Form> 안에서나 <_MsgBox...()> 함수 안에서 처리하는 것에는 한계가
  //있으며, 이는 사용하는 곳에서 호출하는 다른 함수안에 다시 <_MsgBox...()> 를
  //호출할수 있기 때문이다.
  //따라서, <_MsgBox...()> 가 보일때 다른 모든 보이는 <Form:Enabled> 를 제어하여
  //[유사모달] 속성을 지원하도록 한다.
  //현재 [맷돌-IDE] 에서 별도 사요하는 <Form> 은 많지 않으며 추가 되는 경우는
  //여기서 별도 지원.
  //
  //[중요!!!]-----------------------------------------------------------------------
  //<ide_menu> 에서 <optionIde_DialogBox_Form> 을 [유사모달] 로 보여주는 것을 해제.
  //현재 <optionIde_DialogBox_Form> 만 유일한 [유사모달] 이다.
  //
  //이는 <_MsgBox...()> 만 유일한 [유사모달] 기능을 갖게 하기 위한것.
  //}-------------------------------------------------------------------------------

  //[대상 목록]{----------------------------------------------------------------------------
  //<optionIde_DialogBox_Form>, <gmrcbasicMake_DialogBox_Form>, <gmrcbasic_DialogBox_Form>,
  //<servoZero_DialogBox_Form>, <find_DialogBox_Form>, <class BookMark_DialogBox>
  //
  //[생성돼 있고 && 보이고] 있는 경우만 처리.
  //}---------------------------------------------------------------------------------------

  //[VAR]
  //{
      class  BookMark_DialogBox  *_bookMark_DialogBox = NULL;

  //}

  if((main_Form != NULL) && (main_Form->Visible == true))
  {
    if(pModal == true) { main_Form->Enabled = false; }
    else               { main_Form->Enabled = true;  }

  }

  if((optionIde_DialogBox_Form != NULL) && (optionIde_DialogBox_Form->Visible == true))
  {
    if(pModal == true) { optionIde_DialogBox_Form->Enabled = false; }
    else               { optionIde_DialogBox_Form->Enabled = true;  }

  }

  if((gmrcbasicMake_DialogBox_Form != NULL) && (gmrcbasicMake_DialogBox_Form->Visible == true))
  {
    if(pModal == true) { gmrcbasicMake_DialogBox_Form->Enabled = false; }
    else               { gmrcbasicMake_DialogBox_Form->Enabled = true;  }

  }

  if((gmrcbasic_DialogBox_Form != NULL) && (gmrcbasic_DialogBox_Form->Visible == true))
  {
    if(pModal == true) { gmrcbasic_DialogBox_Form->Enabled = false; }
    else               { gmrcbasic_DialogBox_Form->Enabled = true;  }

  }

  if((servoZero_DialogBox_Form != NULL) && (servoZero_DialogBox_Form->Visible == true))
  {
    if(pModal == true) { servoZero_DialogBox_Form->Enabled = false; }
    else               { servoZero_DialogBox_Form->Enabled = true;  }

  }

  if((find_DialogBox_Form != NULL) && (find_DialogBox_Form->Visible == true))
  {
    if(pModal == true) { find_DialogBox_Form->Enabled = false; }
    else               { find_DialogBox_Form->Enabled = true;  }

  }

  //[찾기목록(책갈피) 대화상자]
  //{
      //<class> 로 만든 것으로 [대화상자] 가 아니라 직접 처리.
      //[전역변수] 로 선언된 [책갈피 대화상자] 위치 얻기.
      BookMark_DialogBox_GetPtr(&_bookMark_DialogBox);

      if((_bookMark_DialogBox != NULL) && (_bookMark_DialogBox->_base->Visible == true))
      {
        if(pModal == true) { _bookMark_DialogBox->_base->Enabled = false; }
        else               { _bookMark_DialogBox->_base->Enabled = true;  }

      }

  //}

}

//------------------------------------------------------------------------------
//[설계 정보 보여주기 함수]-----------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_TreeInfo(void)
{
  //[2009.02.01.목][생성!!!]{-----------------------------------------------------
  //<Build> 후에 {DATABASE} 안의 모든 내용을 정리하여 [Tree] 상의 "설계정보" 창에
  //전부 해당 항목 별로 정리해 주어야 한다.
  //
  //단, [define] 으로 선언된 것은 {definelist[]} 로 별도 관리 되므로 역시
  //별도로 처리해 주어야 한다.
  //
  //[<name> 지정 방법]--------------------------------------------------------------------
  //
  // [일반항목]
  //
  //  <name> : 현재 {DATABASE} 상의 record-index 의 16진수 문자열을 사용한다.
  //           record-index 는 절대 서로 겹치지 않으므로 name 으로 제격이다.
  //
  // [define 정의 항목]
  //
  //  <name> : <#define> 항목은 {definelist[]} 를 별도 운영하고 있으므로 이것을 사용한다.
  //           "def.recindex" 의 형식으로 앞에 "def." 를 붙여서 구분한다.
  //
  //
  //[2012.04.20.금][수정!!!]--------------------------------------------------------------
  //[2012.05.16+2.금][수정!!!]------------------------------------------------------------
  //[2012.05.19.토][수정!!!]--------------------------------------------------------------
  //[2012.05.21.월][수정!!!]--------------------------------------------------------------
  //[2012.05.27.일][설명!!!]--------------------------------------------------------------
  //이 함수는 <Teditor_edit_Form::InfoTree_Call()> 에서도 [실시간 선언 정보판] 을 위한
  //정보 수집후 먼저 사용되어 [정보창:설계정보] 를 정리하는데 사용된다.
  //이는 두개의 처리가 모두 <Parser()> 를 거치므로 동일한 {DB} 를 사용하기 때문에
  //반드시 같은 정보를 정리해야 하기 때문이다.
  //
  //[2중선택] 으로 찾기 기능이 {DB} 정보를 사용하기 때문에 반드시 두개는 같은 정보로
  //정리돼야 한다.
  //
  //[2012.06.03.일][수정!!!]--------------------------------------------------------------
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  tempStr[OPT_lineStrSize];
      char  hexStr[OPT_wordStrSize];

      int   nodeItemIndex;

      //[tree 관련]
      //{
          struct  TREE      *tree;

          struct  TREEITEM   item;

      //}

      int   i, j;

      int   motherIndex;
      char  motherName[OPT_wordStrSize];
      int   memberCount;

      char  isStructUnion = 0;

      //[2009.10.04.일][추가!!!]
      //[2012.05.16+2.금][크기조정!!!]
      char  itemTxt[OPT_lineStrSize*4];

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [정보 Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_info]);

  //}

  //[초기화]
  //{
      //[!]{-------------------------------------------------------------
      //새로 그리기 전에 먼저 해당 [Tree] 의 내용을 초기화 한다.
      //
      //[2012.06.03.일][수정!!!]-----------------------------------------
      //[기본 목록] 을 만든 뒤에는 [다시 그리지] 않는다.
      //바로 이어서 [항목] 을 채우기 때문에 여기서는 다시 그리지 않는다.
      //[깜박임] 을 막기 위한것.
      //}----------------------------------------------------------------

      //[다시 그리기] 금지-----------------------v
      ide_tree_Form->_Tree_All_Init(d_Tree_Info, false);

  //}

  //[설계 정보 정리]
  //{
      //[지정이름]
      //{
          for(i = 0; i < database->definelist_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                //[2012.06.02.토][주석처리!!!]
                //Application->ProcessMessages();

            //}

            //[항목 초기화]
            //{
                //[2012.04.17.화][참고!!!]
                //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                tree_tree_Form->_Item_Init(&item);

            //}

            //[<name> 만들기]
            //{
                //"def.definelistindex" 형식으로 만들어 준다.
                //이는 {DATABASE} 항목의 recordindex 와 겹치는 겻을 방지하기 위한 것이다.

                STR_Assign(item.name, "def.");
                CONV_LongVal_To_Hex2(i, hexStr);
                STR_Add_AB(item.name, item.name, hexStr);

            //}

            //[<text> 만들기]
            //{
                //"[정의이름] [문자열]" 형식으로 합성한다.

                STR_Assign(itemTxt, database->definelist[i].defname);
                STR_Add(itemTxt, " ");
                STR_Add(itemTxt, database->definelist[i].defstr);
                //[2012.04.20.금][수정!!!]
                tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                          &item,
                                          itemTxt);

            //}

            //[기타 설정]
            //{
                item.kind = '.';
                item.bmpindex = d_ITEMBMP_define;

            //}

            //[<recindex> 기록]
            //{
                //{definelist[]} 상의 <recindex> 를 기록해 준다.
                item.info1 = i;

            //}

            //[추가]
            //{
                tree_tree_Form->_Tree_Add_NodeItem(tree, "define", &item, NULL);

            //}

          }

      //}

      //[구조체 선언]
      //{
          for(i = 0; i < database->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                //[2012.06.02.토][주석처리!!!]
                Application->ProcessMessages();

            //}

            //[구조체 선언 시작 찾기]
            //{
                //[구조체 선언] 이 아니라면 계속 다음을 검사한다.
                if(database->record[i].kind != _recKIND_structtype) continue;

            //}

            //[구조체 선언 자체 처리]
            //{
                //일단 [구조체 선언] 자체 항목을 추가 한다.

                //[항목 초기화]
                //{
                    //[2012.04.17.화][참고!!!]
                    //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                    tree_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[<text> 만들기]
                //{
                    //[record.name] 을 그대로 사용한다.
                    //[2012.04.20.금][수정!!!]
                    tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                              &item,
                                              database->record[i].name);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';
                    item.bmpindex = d_ITEMBMP_struct_def;

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    tree_tree_Form->_Tree_Add_NodeItem(tree, "struct", &item, NULL);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[구성원 처리]
            //{
                for(//아직 [구조체 모체] 의 위치 이므로 i++ 하고 시작한다.
                    j = i + 1, memberCount = 0;
                    j < database->record_count;
                    j++, memberCount++)
                {
                  //[영역검사]
                  //{
                      //[모체 영역 안] 인 경우만 처리하면 된다.
                      if(database->record[j].area != motherIndex) break;

                  //}

                  //[항목 초기화]
                  //{
                      //[2012.04.17.화][참고!!!]
                      //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                      tree_tree_Form->_Item_Init(&item);

                  //}

                  //[<name> 만들기]
                  //{
                      //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                      CONV_LongVal_To_Hex2(j, hexStr);
                      STR_Assign(item.name, hexStr);

                  //}

                  //[기타 설정]
                  //{
                      item.kind = '.';

                      //일단 기본 그림으로 설정한다.
                      item.bmpindex = d_ITEMBMP_item;

                  //}

                  //[<text> 만들기]
                  //{
                      //[2009.02.14.토][수정!!!]{------------------------------------
                      //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                      //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                      //}------------------------------------------------------------

                      Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                      //[2012.04.20.금][수정!!!]
                      tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                                &item,
                                                itemTxt);

                      if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                      else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                  //}

                  //[<recindex> 기록]
                  //{
                      //{definelist[]} 상의 <recindex> 를 기록해 준다.
                      item.info1 = j;

                  //}

                  //[추가]
                  //{
                      //모체에 추가 해야 한다.
                      tree_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                  //}

                }

                i += memberCount;

            //}

          }

      //}

      //[공용체 선언]
      //{
          for(i = 0; i < database->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                //[2012.06.02.토][주석처리!!!]
                Application->ProcessMessages();

            //}

            //[공용체 선언 시작 찾기]
            //{
                //[구조체 선언] 이 아니라면 계속 다음을 검사한다.
                if(database->record[i].kind != _recKIND_uniontype) continue;

            //}

            //[공용체 선언 자체 처리]
            //{
                //일단 [공용체 선언] 자체 항목을 추가 한다.

                //[항목 초기화]
                //{
                    //[2012.04.17.화][참고!!!]
                    //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                    tree_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[<text> 만들기]
                //{
                    //[record.name] 을 그대로 사용한다.
                    //[2012.04.20.금][수정!!!]
                    tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                              &item,
                                              database->record[i].name);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';
                    item.bmpindex = d_ITEMBMP_union_def;

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    tree_tree_Form->_Tree_Add_NodeItem(tree, "union", &item, NULL);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[구성원 처리]
            //{
                for(//아직 [공용체 모체] 의 위치 이므로 j = i + 1 로 시작한다.
                    j = i + 1, memberCount = 0;
                    j < database->record_count;
                    j++, memberCount++)
                {
                  //[영역검사]
                  //{
                      //[모체 영역 안] 인 경우만 처리하면 된다.
                      if(database->record[j].area != motherIndex) break;

                  //}

                  //[항목 초기화]
                  //{
                      //[2012.04.17.화][참고!!!]
                      //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                      tree_tree_Form->_Item_Init(&item);

                  //}

                  //[<name> 만들기]
                  //{
                      //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                      CONV_LongVal_To_Hex2(j, hexStr);
                      STR_Assign(item.name, hexStr);

                  //}

                  //[기타 설정]
                  //{
                      item.kind = '.';

                      //일단 기본그림으로 설정한다.
                      item.bmpindex = d_ITEMBMP_item;

                  //}

                  //[<text> 만들기]
                  //{
                      //[2009.02.14.토][수정!!!]{------------------------------------
                      //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                      //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                      //}------------------------------------------------------------

                      Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                      //[2012.04.20.금][수정!!!]
                      tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                                &item,
                                                itemTxt);

                      if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                      else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                  //}

                  //[<recindex> 기록]
                  //{
                      //{definelist[]} 상의 <recindex> 를 기록해 준다.
                      item.info1 = j;

                  //}

                  //[추가]
                  //{
                      //모체에 추가 해야 한다.
                      tree_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                  //}

                }

                i += memberCount;

            //}

          }

      //}

      //[전역변수]
      //{
          for(i = 0; i < database->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                //[2012.06.02.토][주석처리!!!]
                Application->ProcessMessages();

            //}

            //[전역변수 확인]
            //{
                //[전역영역] 에서 선언된 [구조체/공용체/변수] 등이 해당된다.
                //[전역변수] 는 [_recKIND_data] 한가지만 가진다.
                //단, 전역 영역이므로 반드시 <area>:-1 이어야 한다.
                if(!((database->record[i].kind == _recKIND_data) &&
                     (database->record[i].area == -1))) continue;

            //}

            //[항목 초기화]
            //{
                //[2012.04.17.화][참고!!!]
                //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                tree_tree_Form->_Item_Init(&item);

            //}

            //[<name> 만들기]
            //{
                //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                CONV_LongVal_To_Hex2(i, hexStr);
                STR_Assign(item.name, hexStr);

            //}

            //[기타 설정]
            //{
                item.kind = '.';

                //일단 기본그림으로 설정한다.
                item.bmpindex = d_ITEMBMP_item;

            //}

            //[<text> 만들기]
            //{
                //[!]{---------------------------------------------------------
                //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                //}------------------------------------------------------------

                Ide_TreeInfo_ItemTextMake(i, itemTxt, &isStructUnion);

                //[2012.04.20.금][수정!!!]
                tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                          &item,
                                          itemTxt);

                if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

            //}

            //[<recindex> 기록]
            //{
                //{definelist[]} 상의 <recindex> 를 기록해 준다.
                item.info1 = i;

            //}

            //[추가]
            //{
                tree_tree_Form->_Tree_Add_NodeItem(tree, "global", &item, NULL);

            //}

          }

      //}

      //[함수]
      //{
          for(i = 0; i < database->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                //[2012.06.02.토][주석처리!!!]
                Application->ProcessMessages();

            //}

            //[함수 확인]
            //{
                //[!]{--------------------------------------------------
                //[함수] 는 [선언/본체] 로 [종류] 가 구분되 있으나 <redcord> 는
                //하나 밖에 존재 할수 없으으로 이 두 경우 중 하나에 해당한다면
                //[함수] 로 본다.
                //단, 전역 영역이므로 반드시 <area>:-1 이어야 한다.

                if(!(((database->record[i].kind == _recKIND_func_def) ||
                      (database->record[i].kind == _recKIND_func_body)) &&
                      (database->record[i].area == -1))) continue;

            //}

            //[함수 자체 항목 처리]
            //{
                //[항목 초기화]
                //{
                    //[2012.04.17.화][참고!!!]
                    //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                    tree_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';

                    //일단 기본그림으로 설정한다.
                    item.bmpindex = d_ITEMBMP_function;

                //}

                //[<text> 만들기]
                //{
                    //[!]{------------------------------------------------------------
                    //[함수선언] 문자열은 이미 <record>.str_mem 에 저장돼 있으므로
                    //이것을 그대로 읽어서 사용한다.
                    //
                    //[2012.05.16+2.금][수정!!!]--------------------------------------
                    //{DB} 의 [함수 선언 정보 문자열] 은 보기 좋지 않기 때문에
                    //보기 좋게 [재정리] 한다.
                    //이를 위하여 금일 만든 <FuncDefStr_ReMake_TreeItem()> 함수 사용.
                    //}---------------------------------------------------------------

                    //[재정리]
                    //{
                        //[2012.05.16+2.금][추가!!!]
                        FuncDefStr_ReMake_TreeItem(STRHEAP_Str_Ptr(&(database->_strHeap), database->record[i].str_mem),
                                                   itemTxt);

                    //}

                    //[2012.04.20.금][수정!!!]
                    tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                              &item,
                                              itemTxt);

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    tree_tree_Form->_Tree_Add_NodeItem(tree, "function", &item, NULL);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[지역변수 처리]
            //{
                //[!]{-----------------------------------------------------------------------
                //[함수] 는 [선언] 이 먼저오고 [본체] 가 나중에 오는 경우도 있다.
                //이 경우는 [인수] 부분은 [함수선언] 부분과 붙어 있지만 내부의
                //[지역변수] 는 [함수본체] 가 오는 부분에 오므로 서로 떨어져 있게 된다.
                //따라서, 아래와 같이 처리 한다.
                //
                // 1) 먼저 [인수] 를 처리한다.
                //
                //    - [인수] 다음에 [지역변수] 가 계속된다면 바로 3) 단계를 처리하면 된다.
                //
                // 2) [함수영역] 을 찾는다(여기부터 [지역변수] 시작이 된다).
                //
                // 3) 일단 [함수영역] 은 다시 분리되지 않는다.
                //
                //}--------------------------------------------------------------------------

                //[인수 처리]
                //{
                    //[!]{-------------------------------------
                    //[인수] 는 [함수] 바로 다음부터 시작된다.
                    //먼저 [인수] 를 처리한다.
                    //}----------------------------------------

                    for(//아직 [함수] 의 위치 이므로 j = i + 1 로 시작한다.
                        j = i + 1, memberCount = 0;
                        j < database->record_count;
                        j++, memberCount++)
                    {
                      //[영역 검사]
                      //{
                          //[함수 영역] 안 이고 [인수] 에 해당하는 것만 처리한다.
                          if(!((database->record[j].area == motherIndex) &&
                               (database->record[j].kind == _recKIND_func_param))) break;

                      //}

                      //[항목 초기화]
                      //{
                          //[2012.04.17.화][참고!!!]
                          //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                          tree_tree_Form->_Item_Init(&item);

                      //}

                      //[<name> 만들기]
                      //{
                          //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                          CONV_LongVal_To_Hex2(j, hexStr);
                          STR_Assign(item.name, hexStr);

                      //}

                      //[기타 설정]
                      //{
                          item.kind = '.';

                          //일단 기본그림으로 설정한다.
                          item.bmpindex = d_ITEMBMP_item;

                      //}

                      //[<text> 만들기]
                      //{
                          //[!]{---------------------------------------------------------
                          //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                          //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                          //}------------------------------------------------------------

                          Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                          //[2012.04.20.금][수정!!!]
                          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                                    &item,
                                                    itemTxt);

                          if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                          else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                      //}

                      //[<recindex> 기록]
                      //{
                          //{definelist[]} 상의 <recindex> 를 기록해 준다.
                          item.info1 = j;

                      //}

                      //[추가]
                      //{
                          //모체에 추가 해야 한다.
                          tree_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                      //}

                    }

                    i += memberCount;

                //}

                //[순수 지역변수 처리]
                //{
                    //[함수 지역 영역 시작 찾기]
                    //{
                        for(//아직 [함수] 나 마지막 [인수] 의 위치 이므로 j = i + 1 로 시작한다.
                            j = i + 1;
                            j < database->record_count;
                            j++)
                        {
                          //[지역변수] 는 [함수영역] 시작 부터 다시 시작되므로 일단
                          //이 함수 영역이 다시 시작되는 부분을 찾는다.

                          if(database->record[j].area == motherIndex)
                          {
                            //시작 위치를 찾았으므로 계속 [진역 변수] 를 처리한다.
                            goto FUNC_LOCAL_ITEM;

                          }

                        }

                        //[다음 함수 처리 계속]
                        //{
                            //[중요 주의!!!]
                            //{
                                //다음 계속할 위치는 현재 [함수] 위치다음부터 시작되어야 한다.
                                //이는 [선언] 이 먼저 오고 [본체] 가 나중에 있는 경우는 반드시
                                //[선언] 된 순서대로 [본체] 가 온다는 보장이 없기 때문이다.
                                //따라서, 이미 처리한 [함수] 는 제외하고 다음부터 계속 검사해야 한다.
                                //항상 [함수] 를 먼저 찾으므로 다음이 [인수] 나 [지역변수] 가 되어도
                                //무시되므로 상관 없다.

                                i = motherIndex;

                            //}

                            //여기 까지 온것은 이미 이 [함수] 는 더이상 처리할 것이 없는 것이다.
                            //따라서, 계속 다음 [함수] 를 처리한다.
                            continue;

                        //}

                    //}

                    FUNC_LOCAL_ITEM:

                    for(//j 는 이미 위에서 구한 위치부터 시작하면 된다.
                        memberCount = 0;
                        j < database->record_count;
                        j++, memberCount++)
                    {
                      //[영역 검사]
                      //{
                          //[함수 영역] 안 이고 [인수] 에 해당하는 것만 처리한다.
                          if(!((database->record[j].area == motherIndex) &&
                               (database->record[j].kind == _recKIND_data))) break;

                      //}

                      //[항목 초기화]
                      //{
                          //[2012.04.17.화][참고!!!]
                          //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                          tree_tree_Form->_Item_Init(&item);

                      //}

                      //[<name> 만들기]
                      //{
                          //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                          CONV_LongVal_To_Hex2(j, hexStr);
                          STR_Assign(item.name, hexStr);

                      //}

                      //[기타 설정]
                      //{
                          item.kind = '.';

                          //일단 기본그림으로 설정한다.
                          item.bmpindex = d_ITEMBMP_item;

                      //}

                      //[<text> 만들기]
                      //{
                          //[!]{---------------------------------------------------------
                          //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                          //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                          //}------------------------------------------------------------

                          Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                          //[2012.04.20.금][수정!!!]
                          tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_info]),
                                                    &item,
                                                    itemTxt);

                          if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                          else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                      //}

                      //[<recindex> 기록]
                      //{
                          //{definelist[]} 상의 <recindex> 를 기록해 준다.
                          item.info1 = j;

                      //}

                      //[추가]
                      //{
                          //모체에 추가 해야 한다.
                          tree_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                      //}

                    }

                    //[중요 주의!!!]
                    //{
                        //다음 계속할 위치는 현재 [함수] 위치다음부터 시작되어야 한다.
                        //이는 [선언] 이 먼저 오고 [본체] 가 나중에 있는 경우는 반드시
                        //[선언] 된 순서대로 [본체] 가 온다는 보장이 없기 때문이다.
                        //따라서, 이미 처리한 [함수] 는 제외하고 다음부터 계속 검사해야 한다.
                        //항상 [함수] 를 먼저 찾으므로 다음이 [인수] 나 [지역변수] 가 되어도
                        //무시되므로 상관 없다.

                        i = motherIndex;

                    //}

                //}

            //}

          }

      //}

  //}

  //[형식 적용 문자열 정보 재정리]
  //{
      //[2012.05.19.토][추가!!!]{----------------------------------------------
      //이 함수 자체가 <Parser()> 후 [Tree:설계정보] 를 채워주는 것으로
      //[구조체/공용체] 는 계속 변화될수 있으므로 이 정보때문에 다시 정리한다.
      //
      //[2012.05.21.월][수정!!!]-----------------------------------------------
      //[귀뜸말] 뿐 아니라 <Tree:항목> 에도 [형식 적용 문자열] 을 지원하므로
      //<_TreeView()> 로 그려지기 전에 먼저 설정해야 한다.
      //}----------------------------------------------------------------------

      tree_tree_Form->_ConfStr_Info_Set();

  //}

  //[반영]
  //{
      //[!]{-------------------------------------------------------------
      //해당 [Tree] 가 보이고 있는 경우만 처리한다.
      //이는 [줄이동자] 설정 등의 혼선을 피하기 위한 것이다.
      //또한, 해당 [Tree] 가 선택되는 경우는 자동으로 다시 그려지게된다.
      //}----------------------------------------------------------------

      if(tree_tree_Form->_tree_select_index == d_TREE_info)
      {
        tree_tree_Form->_TreeView(d_TREE_info, false);

      }

  //}

}

void __fastcall Ide_TreeInfo_ItemTextMake(int    pRecIndex,
                                          char  *rItemText,
                                          //[구조체] 인 경우는 's', [공용체] 인 경우는 'u' 를 반환한다.
                                          char  *rStructUnion)
{
  //[2009.02.14.토][생성!!!]{-------------------------------------------------------
  //{DATABASE} 를 상대로 해당 <record> 의 정보를 참고하여 [설계정보 Tree] 에 표시할
  //항목의 [<text> 문자열] 을 만들어 준다.
  //[선언유형] 에 따라 [선언문자열] 자체를 만들어 주는 것이다.
  //
  //[2012.05.16+2.금][수정!!!]------------------------------------------------------
  //"***pA" 와 같은 [포인터] 선언의 경우는 "*** pA" 로 [인수] 와 구분한다.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      char  text[OPT_lineStrSize] = {""};
      char  word[OPT_wordStrSize] = {""};

      int   i;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[초기화]
  //{
      (*rStructUnion) = 0;

  //}

  //[구조체/공용체 또는 일반형 인가?]
  //{
      TYPE:

      //[구조체/공용체] 인지는  <typelistindex> 정보를 사용하여 간단하게 알수 있다.

      if     (database->TYPELIST_IS_StructType(database->record[pRecIndex].typelistindex) == true)
      {
        STR_Add(text, "struct ");

        //해당 [타입 이름] 을 합성한다.
        STR_Add(text, database->typelist[database->record[pRecIndex].typelistindex].type);
        STR_Add(text, " ");

        //[구조체] 에 해당한다는 것을 알려준다.
        (*rStructUnion) = 's';

      }
      else if(database->TYPELIST_IS_UnionType(database->record[pRecIndex].typelistindex) == true)
      {
        STR_Add(text, "union ");

        //해당 [타입 이름] 을 합성한다.
        STR_Add(text, database->typelist[database->record[pRecIndex].typelistindex].type);
        STR_Add(text, " ");

        //[공용체] 에 해당한다는 것을 알려준다.
        (*rStructUnion) = 'u';

      }
      else
      {
        //그밖의 경우는 [일반 선언] 에 해당한다.

        STR_Add(text, database->typelist[database->record[pRecIndex].typelistindex].type);
        STR_Add(text, " ");

      }

  //}

  //[포인터 인가?]
  //{
      POINTER:

      if(database->record[pRecIndex].pointer > 0)
      {
        //[포인터 차원] 에 해당하는 만큼 "*" 기호룰 공백 없이 붙여 준다.

        for(i = 0; i < database->record[pRecIndex].pointer; i++)
        {
          STR_Add(text, "*");

        }

        //[2012.05.16+2.금][추가!!!]{-----------
        //[포인터] 선언부와 [인수] 를 분리한다.
        STR_Add(text, " ");
        //}-------------------------------------

      }

  //}

  //[이름 합성]
  //{
      NAME:

      //[이름] 을 추출하여 합성한다.
      STR_Add(text, database->record[pRecIndex].name);

  //}

  //[배열 인가?]
  //{
      ARRAY:

      if(database->record[pRecIndex].arraydimension > 0)
      {
        //[배열 차원] 은 이미 관리되고 있으므로 직접 10진수 문자열로 만들어 준다.

        //[배열 차원 크기 정보]
        //{
            //arraydimension 을 참고해서 각각의 크기를 [a][b][c]...
            //처럼 문자열로 만들어 표시해 준다.

            //array 가 최소 1 차원은 되므로 각각의 size 를 문자열로 만들어 준다.
            for(i = 0; i < database->record[pRecIndex].arraydimension; i++)
            {
              STR_Add(text, "[");

              //[값 => 문자열 변환]
              //{
				  STR_Assign(word, ((AnsiString)IntToStr(database->record[pRecIndex].arraysize[i])).c_str());

              //}

              STR_Add(text, word);

              STR_Add(text, "]");

            }

        //}

      }

  //}

  //[문자열 반환]
  //{
      STR_Assign(rItemText, text);

  //}

  return;

}

void __fastcall Ide_TreeInfo_DoubleClick(void)
{
  //[2009.02.14.토][생성]{------------------------------------------------------------------
  //[설계 정보] [Tree] 선택 항목의 [더블클릭] 의 경우를 처리한다.
  //
  //이 경우는 해당 항목이 선언되 있는 [문서] 를 열어 주고 [선언위치] 를 지정해 주어야 한다.
  //이미 <tem.dbRecIndex> 에 {DATABASE} 상의 <ecord-index> 정보가 기록되 있으므로 간단하게
  //해당 정보를 추출하여 처리할수 있다.
  //}---------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      struct TREE   *tree;

      int    nodeItemIndex;
      int    nodeLastItemIndex;

      char   fileName[OPT_filepath_length];
      char   tempStr[OPT_lineStrSize];

      //[2009.02.17.화][추가!!!]
      //{
          //선택된 항목을 기록한다(표시 길이를 줄이가 위한것).
          int    selIndex;
          int    recIndex;
          int    fileListIndex;
          int    wordIndex;
          int    wordLength;

      //}

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 아예 처리 하지 않아야 한다.
      if(tree_tree_Form->_tree[tree_tree_Form->_tree_select_index].select_itemindex < 0) return;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_info]);

      //선택된 항목을 기록한다.
      selIndex = tree->select_itemindex;

  //}

  //[예외처리]
  //{
      //[2009.02.17.화][추가!!!]{---------------------------
      //<dbRecIndex> 정보가 없는 경우는 처리할 필요가 없다.
      //}---------------------------------------------------

      if(tree->items[selIndex].info1 == -1) return;

  //}

  //[종류 구분 처리]
  //{
      //[#define] 으로 선언된 것은 {definelist} 를 대상으로 해야 하므로 별도 구분하여 처리한다.

      tree_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "define", &nodeItemIndex, NULL, &nodeLastItemIndex);

      if((nodeItemIndex < selIndex) && (selIndex <= nodeLastItemIndex))
      {
        //[#define] 으로 선언된 것이므로 {definelist[]} 를 대상으로 처리해야 한다.

        //[정보수집]
        //{
            recIndex      = tree->items[selIndex].info1;

            fileListIndex = database->definelist[recIndex].filelistindex;

            wordIndex     = database->definelist[recIndex].index;

            wordLength    = STR_Length(database->definelist[recIndex].defname);

        //}

      }
      else
      {
        //일반적인 경우로 {database} 를 대상으로 처리한다.

        //[정보수집]
        //{
            recIndex      = tree->items[selIndex].info1;

            fileListIndex = database->record[recIndex].filelistindex;

            wordIndex     = database->record[recIndex].index;

            wordLength    = STR_Length(database->record[recIndex].name);

        //}

      }

  //}

  //[공통 처리]
  //{
      //이미 위에서 모든 정보를 얻었으므로 해당 항목이 있는 문서를 열어 주고 지정해준다.

      //[해당 문서 열기]
      //{
          //[2009.02.18.수][중요!!!]{-----------------------------------------------------
          //일단 문서를 열때는 깜박거림을 방지하기 위하여 [다시출력] 하지 않게 만든다.
          //이는 이전에 [선택] 된 것이 있는 경우 [깜박거림] 으로 보기 좋지 않기 때문이다.
          //여러 가지가 있으니 사용하지 않는 _edit_paste_ing 사용하여 처리한다.
          //
          //문서를 다시 출력하여 [선택영역] 을 반영하는 것은 아래 _Edit_SelectX() 함수
          //안에서 자동으로 한번만 처리 되어 [깜박거림] 이 없어 깔끔하다.
          //}-----------------------------------------------------------------------------

          editor_edit_Form->_edit_paste_ing = true;
          //{
              //파일을 열어준다.
              editor_top_Form->_List_Add(database->filelist[fileListIndex].name);

          //}
          editor_edit_Form->_edit_paste_ing = false;

      //}

      //[단어 지정]
      //{
          //[2009.02.18.수][추가!!!]{---
          //해당 단어를 지정해 준다.
          //}---------------------------

          editor_edit_Form->SetFocus();

          editor_edit_Form->_Edit_SelectX(//[선택영역] 시작 위치.
                                          wordIndex,
                                          //[선택영역] 끝 위치.
                                          wordIndex + wordLength,
                                          //자동으로 [선택영역] 이 항상 보이는 위치에 있게 만든다.
                                          true,
                                          NULL,
                                          true);

      //}

  //}

  return;

}

//------------------------------------------------------------------------------
//[API 정보창 관련]-------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_Tree_Api(void)
{
  //[2009.05.30.토][생성!!!]{------------------------------------------------------------
  //[API] 창의 기본 설정을 수행한다.
  //이는 [IDE] 폴더안의 [glib] 폴더 안 모든 항목을 읽어서 정리해 주면 되며
  //각각의 [폴더] 는 한개의 [옹이] 가 되고 한개의 <*.glib> 문서는 한개의 [항목] 이 된다.
  //
  //[폴  더] : 한개의 [옹이] 가 된다.
  //           [폴더이름] 이 표시이름이 된다.
  //
  //[*.glib] : 한개의 항목이 된다.
  //           확장자를 제외한 순수 [이름] 만 표시한다.
  //
  //[2012.04.27.금][수정!!!]-------------------------------------------------------------
  //}------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      struct TREE      *tree;
      struct TREEITEM   item, beforeItem;

      //[IDE] 경로안의 [glib] 폴더안에서 정리할 [폴더] 와 [문서] 목록을 갖는다.
      TStringList     *fileList = new TStringList;

      char  sysGlibPath[OPT_lineStrSize];

      char  tempStr[OPT_lineStrSize];
      char  tempWord[OPT_wordStrSize];
      char  tempExt[OPT_wordStrSize];
      char  hexStr[OPT_wordStrSize];

      int   i, w;

      //이전 항목의 <name> 을 갖는다.
      int   nodeIndex;
      int   itemIndex;


  //}

  //[Database 주소 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(tree_tree_Form->_tree[d_TREE_api]);

  //}

  //[문서 목록 얻기]
  //{
      //[glib] 폴더의 경로를 만든다.
      STR_Add_AB(sysGlibPath, database->programpath, "glib\\");

      //[폴더] 의 경우는 전부다 얻고, 문서의 경우는 <*.glib> 만 얻으면 된다.
      Dir_Get_FileList_BoundDir(sysGlibPath, "glib", false, d_Directory | d_File, fileList);

  //}

  //[정리]
  //{
      //[2009.05.31.일][추가!!!]{---------------------------------------------
      //[폴더]   : 한개의 [옹이] 가 된다.
      //           [순수이름] 만 표시한다.
      //
      //[*.glib] : 한개의 [항목] 이 된다.
      //           [순수이름] 만 표시한다(확장자도 제외).
      //
      //이미 위에서 [폴더] 와 안의 [*.glib] 가 전부 순서대로 정리되 있으므로
      //그대로 순서대로 처리해 주면 된다.
      //즉, [항목] 부터 거꾸로 [옹이] 를 거술러 가면 바로 한개의 경로가 된다.
      //}---------------------------------------------------------------------

      for(i = 0; i < fileList->Count; i++)
      {
        //[목록 추출]
        //{
            //[!]{------------------------------------------------------------------
            //[문서 목록] 에서 한개의 문서경로를 추출하되 전체 경로를 사용하지 않고
            //[IDE\glib\] 까지는 제외된 순수하게 [glib] 안의 경로만 추출한다.
            //}---------------------------------------------------------------------

            STR_GetFileName_Except_BaseDirectory(sysGlibPath,
												 ((AnsiString)(fileList->Strings[i])).c_str(),
                                                 tempStr);

        //}

        //[항목 정리]
        //{
            for(w = 0; ; w++)
            {
              //[단어] 추출.
              STR_GetWord(tempStr, '\\', w, tempWord);

              //[한개 문서 완료?]{-----------------------------------------
              //[단어] 가 "" 이라면 현재 [문서] 한개의 처리가 끝난 것이다.
              if(tempWord[0] == '\0') break;
              //}----------------------------------------------------------

              //[확장자가 있나?]
              //{
                  //이는 [폴더:옹이] 와 [*.glib:항목] 을 조기 구분하기 위한 것이다.
                  STR_GetFileExt(tempWord, tempExt);

                  if(tempExt[0] == '\0') goto WORD;
                  else                   goto WORD_ITEM;

              //}

              WORD:
              //{
                  //[첫번째 단어인가?]{---
                  if(w != 0) goto WORD_X;
                  //}---------------------

                  //[첫번째 단어인 경우 처리]
                  //{
                      //[존재 확인]
                      //{
                          //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인한다.
                          tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                          (tree,
                           //첫번째 단어의 경우는 무조건 "root" 가 된다.
                           "root",
                           //검사할 <text> 항목.
                           tempWord,
                           //[대/소] 문자 구분 여부(true:구분).
                           false,
                           //이 [옹이] 의 item-index.
                           &nodeIndex,
                           //<text> 를 가진 itemindex.
                           &itemIndex);

                      //}

                      if(itemIndex == -1)
                      {
                        //찾는 것이 없으므로 현재 항목을 추가한다.

                        //[항목 초기화]-------------------------------------------------------------------
                        //[2012.04.17.화][참고!!!]
                        //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                        tree_tree_Form->_Item_Init(&item);

                        //[<name> 만들기]-----------------------------------------------------------------
                        //"word.level(16진수)" 형식으로 만들어 준다.
                        //이는 [폴더] 의 특성상 동일한 <level> 에서는 절대 이름이 중복되지 않기 때문이다.
                        STR_Add_AB(item.name, tempWord, ".");

                        //"root" 다음 <level> 이 된다.
                        CONV_LongVal_To_Hex2(tree->items[0].level + 1, hexStr);
                        STR_Add(item.name, hexStr);

                        //[<text> 만들기]-----------------------------------------------------------------
                        //현재 추출한 [단어] 를 그대로 사용한다.
                        //[2012.04.20.금][수정!!!]
                        tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_api]),
                                                  &item,
                                                  tempWord);

                        //[기타 설정]---------------------------------------------------------------------
                        //일단은 [항목] 으로 추가한다.
                        item.kind = '.';
                        item.bmpindex = d_ITEMBMP_folder;

                        //[추가]--------------------------------------------------------------------------
                        //가장 기본 적인 [옹이] 이므로 반드시 "root" 아래에 등록 되어야 한다.
                        tree_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);
                        //}-------------------------------------------------------------------------------

                      }
                      else
                      {
                        //현재 [항목] 을 다음 처리를 위하여 할당해 준다.
                        item = tree->items[itemIndex]; 

                      }

                      goto WORD_END;

                  //}

              //}

              WORD_X:
              //{
                  //[일반 폴더 처리]
                  //{
                      //[존재 확인]
                      //{
                          //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인한다.
                          tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                          (tree,
                           //이전 [옹이] 의 <name> 안에서 검사한다.
                           beforeItem.name,
                           //검사할 <text> 항목.
                           tempWord,
                           //[대/소] 문자 구분 여부(true:구분).
                           false,
                           //이 [옹이] 의 item-index.
                           &nodeIndex,
                           //<text> 를 가진 itemindex.
                           &itemIndex);

                      //}

                      if(itemIndex == -1)
                      {
                        //찾는 것이 없으므로 현재 항목을 추가한다.

                        //[항목 초기화]-------------------------------------------------------------------
                        //[2012.04.17.화][참고!!!]
                        //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                        tree_tree_Form->_Item_Init(&item);

                        //[<name> 만들기]-----------------------------------------------------------------
                        //"word.level(16진수)" 형식으로 만들어 준다.
                        //이는 [폴더] 의 특성상 동일한 <level> 에서는 절대 이름이 중복되지 않기 때문이다.
                        STR_Add_AB(item.name, tempWord, ".");

                        //이전 [옹이] 다음 <level> 이 된다.
                        CONV_LongVal_To_Hex2(beforeItem.level + 1, hexStr);
                        STR_Add(item.name, hexStr);

                        //[<text> 만들기]-----------------------------------------------------------------
                        //현재 추출한 [단어] 를 그대로 사용한다.
                        //[2012.04.20.금][수정!!!]
                        tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_api]),
                                                  &item,
                                                  tempWord);

                        //[기타 설정]---------------------------------------------------------------------
                        //일단은 [항목] 으로 추가한다.
                        item.kind = '.';
                        item.bmpindex = d_ITEMBMP_folder;

                        //[추가]--------------------------------------------------------------------------
                        //경로는 계속 이어지므로 이전 [옹이] 에 추가한다.
                        tree_tree_Form->_Tree_Add_NodeItem(tree, beforeItem.name, &item, NULL);
                        //}-------------------------------------------------------------------------------

                      }
                      else
                      {
                        //현재 [항목] 을 다음 처리를 위하여 할당해 준다.
                        item = tree->items[itemIndex];

                      }

                      goto WORD_END;

                  //}

              //}

              WORD_ITEM:
              //{
                  //[일반 <*.glib> 처리]
                  //{
                      //[확장자 제거]
                      //{
                          //실제 순수한 이름만 사용해야 하므로 여기서는 [확장자] 를 제거한다.
                          //STR_Assign(tempStr, tempWord);
                          //STR_GetFileNameOnly_ExceptExt(tempStr, tempWord);

                      //}

                      //[존재 확인]
                      //{
                          //[단어] 가 지정 [옹이] 에 이미 존재하는지 확인한다.
                          tree_tree_Form->_Tree_Get_Node_ItemIndex_withText
                          (tree,
                           //이전 [옹이] 의 <name> 안에서 검사한다.
                           beforeItem.name,
                           //검사할 <text> 항목.
                           tempWord,
                           //[대/소] 문자 구분 여부(true:구분).
                           false,
                           //이 [옹이] 의 item-index.
                           &nodeIndex,
                           //<text> 를 가진 itemindex.
                           &itemIndex);

                      //}

                      if(itemIndex == -1)
                      {
                        //찾는 것이 없으므로 현재 항목을 추가한다.

                        //[항목 초기화]-------------------------------------------------------------------
                        //[2012.04.17.화][참고!!!]
                        //항목에 <txt> 등 [동적생성] 되는 것이 있으므로 반드시 초기화 필요.
                        tree_tree_Form->_Item_Init(&item);

                        //[<name> 만들기]-----------------------------------------------------------------
                        //"word.level(16진수)" 형식으로 만들어 준다.
                        //이는 [폴더] 의 특성상 동일한 <level> 에서는 절대 이름이 중복되지 않기 때문이다.
                        STR_Add_AB(item.name, tempWord, ".");

                        //이전 [옹이] 다음 <level> 이 된다.
                        CONV_LongVal_To_Hex2(beforeItem.level + 1, hexStr);
                        STR_Add(item.name, hexStr);

                        //[<text> 만들기]-----------------------------------------------------------------
                        //현재 추출한 [단어] 를 그대로 사용한다.
                        //[2012.04.20.금][수정!!!]
                        tree_tree_Form->_Item_Txt(&(tree_tree_Form->_tree[d_TREE_api]),
                                                  &item,
                                                  tempWord);

                        //[기타 설정]---------------------------------------------------------------------
                        //일단은 [항목] 으로 추가한다.
                        item.kind = '.';
                        item.bmpindex = d_ITEMBMP_api;

                        //[추가]--------------------------------------------------------------------------
                        //경로는 계속 이어지므로 이전 [옹이] 에 추가하낟.
                        tree_tree_Form->_Tree_Add_NodeItem(tree, beforeItem.name, &item, NULL);
                        //}-------------------------------------------------------------------------------

                      }
                      else
                      {
                        //현재 [항목] 을 다음 처리를 위하여 할당해 준다.
                        item = tree->items[itemIndex];

                      }

                      goto WORD_END;

                  //}

              //}

              WORD_END:
              //{
                  //후처리를 수행한다.
                  beforeItem = item;

              //}

            }

        //}

      }

  //}

  //[<root> 펼치기]
  //{
      //가장 기본이 되는 API 자체는 열어 준다.
      if(tree->items_count > 1)
      {
        tree->items[0].kind = '-';

      }

  //}

  //[다시 그리기]
  //{
      //반영하기 위하여 다시 그려준다.
      if(tree_tree_Form->_tree_select_index == d_TREE_api)
      {
        tree_tree_Form->_TreeView(d_TREE_api, false);

      }

  //}

  //[삭제]
  //{
      //[2012.04.27.금][추가!!!]
      if(fileList != NULL) { delete fileList; fileList = NULL; }

  //}

}

void __fastcall Ide_Tree_Api_Make_ItemPath(//[2022.06.24.금][추가]
                                           //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 사용.
                                           //[Tree:API 검색] 지원하기 위한것.
                                           int    pTreeIndex,
                                           //항목의 index.
                                           int    pItemIndex,
                                           //합성된 경로(경우에 따라 문서이름까지 포함된다).
                                           char  *rPath)
{
  //[2009.06.01.월][생성!!!]{----------------------------------------------------------------
  //[Tree:API] 애서 지정된 [항목] 의 <text> 를 전부 단계적으로 함성하여 실제
  //문서경로를 만들어 준다.
  //이는 애초에 이 [Tree] 의 구조가 문서 경로를 그대로 순서대로 만들어 놓은 것이기 때문이다.
  //
  //[API] 는 실제는 [IDE\glib] 폴더가 된다.
  //
  //"glib\옹이\옹이\옹이\...\항목.glib" 와 같은 형식이 된다.
  ///[옹이] 는 한개의 경로가지만 된다.
  //[항목:<*.glib>] 인 경우는 한개 문서의 경로가 된다.
  //
  //[2022.06.24.금][중요수정]----------------------------------------------------------------
  //}----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      struct TREE   *tree;

      int    nodeIndex;
      int    itemIndex;

      char   path[OPT_lineStrSize] = {""};
      char   tempStr[OPT_lineStrSize] = {""};
      char   tempWord[OPT_wordStrSize] = {""};

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

      //[Tree 확인]
      //{
          //[2022.06.24.금][추가]{-------------------------------
          //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 허용된다.
          //}----------------------------------------------------

          if(!((pTreeIndex == d_TREE_api) || (pTreeIndex == d_TREE_apiSrch)))
          {
            if(rPath != NULL) {  STR_Assign(rPath, ""); }

            return;

          }

      //}

      tree = &(tree_tree_Form->_tree[pTreeIndex]);

  //}

  //[경로 합성]
  //{
      //현재 선택된 [항목] 부터 거꾸로 올라가면서 각각 항목의 <text> 를 합성한다.

      //[현재 항목합성]
      //{
          //기본적으로 지정된 [항목] 이 가장 끝 경로가 되므로 먼저 함성한다.

          if(pItemIndex == 0)
          {
            //이 경우는 <name:root> 가 되므로 해당 경로도 대체한다.
            STR_Assign(path, "glib");

          }
          else
          {
            //[2012.04.20.금][수정!!!]
            STR_Assign(path, tree_tree_Form->_Item_Txt_StrPtr3(tree, pItemIndex));

          }

          if(tree->items[pItemIndex].bmpindex != d_ITEMBMP_api)
          {
            //이 경우는 이 항목 자체도 하나의 경로가 되므로 뒤에 "\" 를 붙여준다.
           STR_Add(path, "\\");

          }

          itemIndex = pItemIndex;

      //}

      //계속 자신을 포함하고 있는 [옹이] 의 뿌리까지 거슬러 올라가면 된다.
      while(itemIndex)
      {
        //[!]{------------------------------------------------------------------------
        //현재 [항목] 을 포함하고 있는 옹이를 찾는다.
        //이 [옹이] 가 <name:root> 인 경우는 뿌리 끝에 도달한 것으로 실제 경로 이름은
        //"glib" 가 되므로 이것으로 합성하고 종료한다.
        //}---------------------------------------------------------------------------

        //[옹이 찾기]
        //{
            //상위 [옹이] 찾기.
            tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem(tree, itemIndex, &nodeIndex);

            //현재 nodeIndex 는 다음 검사할 [항목] 이 된다.
            itemIndex = nodeIndex;

        //}

        if(nodeIndex == 0)
        {
          //[!]{--------------------------------------
          //<name:root> 가 되므로 끝에 도달한 것이다.
          //이 경우는 "glib" 를 합성해 주어야 한다.
          //}-----------------------------------------

          //뒤에 [경로 구분자] 를 붙여준다.
          STR_Add_AB(tempWord, "glib", "\\");

          //합성한다.
          STR_Add_AB(tempStr, tempWord, path);

          //결과를 저장한다.
          STR_Assign(path, tempStr);

          //더이상 검사하지 않는다.
          break;

        }
        else
        {
          //[!]{----------------------------------------
          //이 경우는 일반적인 경우이다.
          //단순하게 [옹이] 의 <text> 를 합성하면 된다.
          //}-------------------------------------------

          //뒤에 [경로 구분자] 를 붙여준다.
          //[2012.04.20.금][수정!!!]
          STR_Add_AB(tempWord, tree_tree_Form->_Item_Txt_StrPtr3(tree, itemIndex), "\\");

          //합성한다.
          STR_Add_AB(tempStr, tempWord, path);

          //결과를 저장한다.
          STR_Assign(path, tempStr);

        }

      }

  //}

  //[합성 경로 반환]
  //{
      if(rPath != NULL) {  STR_Assign(rPath, path); }

  //}

  return;

}

void __fastcall Ide_Tree_Api_File_Close_GlibGtxt(char  *pDelFileName)
{
  //[2009.06.01.월][생성!!!]{-------------------------------------------------------
  //현재 열려있는 <*.gtxt> 문서를 [문서목록] 에서 삭제한다.
  //이는 새로운 문서의 내용을 항상 반영해 주기 위한것으로 이는 동일한 이름의 문서를
  //다시 열수 없는 규칙때문이다.
  //또한, 전체 경로가 모두 일치해야 한다.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      int   i;

  //}

  for(i = 0; i < editor_edit_Form->_textinfo_count; )
  {
    if(STR_Match_NoCase(editor_edit_Form->_textinfo[i].filename.c_str(), pDelFileName))
    {
      //[주의!!!]{-----------------------------------------------------------
      //항상 눈에 보이는 문서만 삭제가능하므로 일단 다시 눈에 보이게 만든다.
      //이렇게 하지 않으면 현재 체계상 오류가 발생한다.
      editor_top_Form->_List_Add(editor_edit_Form->_textinfo[i].filename);
      //}--------------------------------------------------------------------

      //현재 문서를 삭제한다.
      editor_top_Form->_List_Delete(i);

      //이 문서는 한개밖에 없으므로 여기서 종료한다.
      return;

    }
    else
    {
      i++;

    }

  }

  return;

}

void __fastcall Ide_Tree_Api_Glib_MakeGtxt(//[2022.06.24.금][추가]{---------------------------
                                           //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 사용.
                                           //[Tree:API 검색] 지원하기 위한것.
                                           int    pTreeIndex,
                                           //}------------------------------------------------
                                           //처리 대상 항목의 index.
                                           int    pItemIndex,
                                           //완성되어 저장된 문서의 경로.
                                           char  *rFileFullName)
{
  //[2009.05.30.토][생성!!!]{-----------------------------------------------------
  //[Tree:API] 의 지정 항목의 경로안의 모든 <*.gtxt> 를 합성하여 처리하면 된다.
  //합성된 문서는 수시로 생성될수 있으므로 [IDE\glib] 폴더안에 <항목이름.gtxt> 로
  //저장하고 이 문서를 열어준다(단지 자동 생성되며 참고만 하는 문서이므로).
  //
  //단, <*.glib> 항목인 경우는 자체 <*.gtxt> 를 열어 주면 된다.
  //이 문서는 항상 <*.glib> 와 같은 경로에 위치한다.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      char    tempStr[OPT_lineStrSize];
      char    fileName[OPT_lineStrSize];
      char    fileGtxtName[OPT_lineStrSize];

      //지정 [옹이] 의 해당 폴더의 전체 경로를 갖는다.
      char    folderPath[OPT_lineStrSize];

      int     i;

      //[함수묶음] 에 등록된 모든 [함수묶음] 의 <*.gtxt> 문서 경로를 수집한다.
      TStringList  *fileList = NULL;

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

      //[Tree 확인]
      //{
          //[2022.06.24.금][추가]{-------------------------------
          //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 허용된다.
          //}----------------------------------------------------

          if(!((pTreeIndex == d_TREE_api) || (pTreeIndex == d_TREE_apiSrch)))
          {
            if(rFileFullName != NULL) { STR_Assign(rFileFullName, ""); }

            return;

          }

      //}

      tree = &(tree_tree_Form->_tree[pTreeIndex]);

  //}

  //[항목이 <*.glib> 인가?]
  //{
      //항목이 <*.glib> 인 경우는 해당 <*.gtxt> 가 있으므로 이 경로를 여기서 바로 반환화면 된다.
      if(tree->items[pItemIndex].bmpindex == d_ITEMBMP_api)
      {
        //현재 항목의 [Tree] 상의 경로를 구한다.
        Ide_Tree_Api_Make_ItemPath(pTreeIndex, pItemIndex, fileName);

        //확장자를 변환한다.
        STR_ChangeFileExt(fileName, "gtxt", fileGtxtName);

        //[전체 경로를 합성]
        //{
            if(rFileFullName != NULL) { rFileFullName[0] = '\0'; }

            if(rFileFullName != NULL) { STR_Add_AB(rFileFullName, database->programpath, fileGtxtName); }

        //}

        //더이상 처리하지 않는다.
        return;

      }
      else
      {
        //[2022.06.24.금][중요수정]{-----------------------------------------------------------
        //<Tree:API 검색> 의 경우는 [API 항목] 만 처리하면 되므로 다른 경우라면 바로 종료한다.
        //
        //<Tree:API 검색> 은 <Tree:API> 에서 해당 항목을 추려낸 것으로, [옹이] 의 모든 구조가
        //<폴더:glib> 안의 모든 폴더 내용과 완전히 일치 하지 않아 <gtxt> 묶음에 적합하지 않다.
        //따라서, <Tree:API 검색> 의 경우는 [API 항목] 만 처리한다.
        //}------------------------------------------------------------------------------------

        if(pTreeIndex == d_TREE_apiSrch)
        {
          if(rFileFullName != NULL) { STR_Assign(rFileFullName, ""); }

          return;

        }

      }

  //}

  //[일반 항목인 경우 <저장 문서이름> 합성]
  //{
      //이 경우는 일반 [폴더] 이름이 되므로 이 폴더이름(옹이이름) 으로 <옹이이름.gtxt> 를 만든다.
      STR_Add_AB(fileGtxtName, database->programpath, "glib\\");

      //[옹이] 이름이 문서이름이 된다.
      //[2012.04.20.금][수정!!!]
      STR_Add(fileGtxtName, tree_tree_Form->_Item_Txt_StrPtr3(tree, pItemIndex));

      //확장자 붙이기.
      STR_Add(fileGtxtName, ".gtxt");

  //}

  //[<*.gtxt> 닫기]
  //{
      //[!]{---------------------------------------------------------------------------
      //현재 열려있는 <함수묶음.gtxt> 문서가 있다면 닫아준다.
      //이는 새로 생성되면 현재 열려 있는 문서의 내용은 아무 의미가 없어지기 때문이다.
      //}------------------------------------------------------------------------------

      Ide_Tree_Api_File_Close_GlibGtxt(fileGtxtName);

  //}

  //[문서 목록 얻기]
  //{
      //현재 지정 [옹이] 폴더 안의 <*.glib> 문서목록을 구한다.

      //[목록 생성]{--------------
      fileList = new TStringList;
      fileList->Clear();
      //}-------------------------

      //[검사할 폴더 경로 만들기]
      //{
          //현재 [옹이] 의 [glib\\...] 경로 얻기.
          Ide_Tree_Api_Make_ItemPath(pTreeIndex, pItemIndex, tempStr);

          //전체 경로 합성.
          STR_Add_AB(folderPath, database->programpath, tempStr);

      //}

      //지정 [옹이] 에 대응하는 폴더안의 <*.glib> 문서목록을 얻는다.
      Dir_Get_FileList_BoundDir(folderPath, "glib", false, d_File, fileList);

  //}

  //[<*.glib> 가 존재?]{---------------------------------------------------------------------
  //처리할 <*.glib> 가 [옹이] 에 해당 하는 폴더안에 하나도 없는 경우는 처리하지 않아야 한다.
  if( fileList->Count <= 0) goto END;
  //}----------------------------------------------------------------------------------------

  //[<*.gtxt> 만들기]
  //{
      //[!]{-------------------------------------------------------------------------------------------
      //문서목록의 모든 <*.glib> 에 해당하는 <*.gtxt> 를 전부 한개의 <옹이이름.gtxt> 로 합성해준다.
      //[합성] 은 전용 함수로 간단하게 처리 할수 있으므로 여기서는 [문서목록] 만 만들어주면 된다.
      //}----------------------------------------------------------------------------------------------

      for(i = 0; i < fileList->Count; i++)
      {
        //현재는 <*.glib> 로 되 있으므로 확장자를 전부 <*.gtxt> 로 바꿔준다.

        STR_Assign(tempStr, ((AnsiString)(fileList->Strings[i])).c_str());

        //확장자 바꾸기.
        STR_ChangeFileExt(tempStr, "gtxt", fileName);


        //수정내용 다시 저장.
        //{
            //[2022.09.13.화][중요수정]{------------------------
            //<TC++2006> 과 <ECB/CE> 에 따라 구분 Compile 처리.
            //}-------------------------------------------------

            #if d_BuildTool_TC2006
            //{
                //[!]{---------------------------
                //<TC++2006> 으로 제작하는 경우.
                //}------------------------------

                fileList->Strings[i] = fileName;

            //}
            #else
            //{
                //[!]{-----------------------
                //<ECB/CE> 로 제작하는 경우.
                //}--------------------------

                fileList->Strings[i] = (UnicodeString)fileName;

            //}
            #endif

        //}

      }

  //}

  //[<*.gtxt> 합성 저장]
  //{
      //이미 처음부분에서 만들어진 <*.gtxt> 위치에 합성하여 저장한다.

      //[합성하기]
      //{
          File_Compose(fileList, fileGtxtName);

      //}

      //현재 문서경로 반환.
      if(rFileFullName != NULL) { STR_Assign(rFileFullName, fileGtxtName); }

  //}

  END:

  //[저장소 삭제]
  //{
      if(fileList != NULL) { delete fileList; fileList = NULL; }

  //}

}

void __fastcall Ide_Tree_Api_DoubleClick(//[2022.06.24.금][추가]
                                         //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 사용.
                                         //[Tree:API 검색] 지원하기 위한것.
                                         int  pTreeIndex)
{
  //[2009.06.01.월][생성!!!]{------------------------------------------------------
  //[Tree:API] 의 항목이 [2중선택] 된 경우를 처리한다.
  //이 경우는 해당 경로안의 모든 <*.gtxt> 를 합성하여 처리하면 된다.
  //합성된 문서는 수시로 생성될수 있으므로 [IDE\glib] 폴더안에 <항목이름.gtxt> 로
  //저장하고 이 문서를 열어준다.
  //단, <*.glib> 항목인 경우는 자체 <*.gtxt> 를 열어 주면 된다.
  //이 문서는 항상 <*.glib 와 같은 경로에 위치한다.
  //
  //[2010.06.09.수][수정!!!]-------------------------------------------------------
  //[GUI] 관련 API 는 보안상의 문제로 아직 <*.gtxt> 가 존재하지 않지만 <*.h> 는
  //존재 하므로 <*.gtxt> 가 존재하지 않는 경우는 무조건 <*.h> 를 열어준다.
  //
  //[2022.06.24.금][수정]----------------------------------------------------------
  //[2022.06.30.목][중요수정]******************************************************
  //[API] 의 경우는 더블클릭으로 열린 문서는 모두 원본이므로 [읽기전용] 으로 설정.
  //}------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE      *tree;

      char    fileName[OPT_lineStrSize];

      //[2010.06.09.수][추가!!!]
      //<*.gtxt> 문서가 없는 경우 열어줄 <*.h> 문서의 이름을 갖는다.
      char    fileHName[OPT_lineStrSize];

      //[2022.07.14.목][추가]
      char    apiName_[OPT_lineStrSize];

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

      //[Tree 확인]
      //{
          //[2022.06.24.금][추가]{-------------------------------
          //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 허용된다.
          //}----------------------------------------------------

          if(!((pTreeIndex == d_TREE_api) || (pTreeIndex == d_TREE_apiSrch))) return;

      //}

      tree = &(tree_tree_Form->_tree[pTreeIndex]);

  //}

  //[<순간보기> 문서가 있다면 닫기]
  //{
      //[2022.06.27.월][추가]{------------------------------------------------------
      //현재 열려 있는 [순간보기] 문서가 있다면 무조건 닫아 준다.
      //
      //[Tree:API/API 검색] 에서 [화면지정자] 가 위치한 항목은 이미 API 항목의 경우
      //해당 API 의 <gtxt/h> 가 [순간보기] 로 열려있는 상태 일수 있으나, 다시 열게
      //되더라도 일단 닫는다.
      //}---------------------------------------------------------------------------

      //깜박임 방지 처리 사용------------------------v
      tree_tree_Form->_Tree_ApiInfo_Hide(pTreeIndex, true);

  //}

  //[지정 문서 열기]
  //{
      Ide_Tree_Api_Glib_MakeGtxt(pTreeIndex, tree->select_itemindex, fileName);

      //[자동 감추기 설정 및 촛점 해제 설정]
      //{
          //[2022.06.28.화][추가]{-----------------------------------------------------
          //일정 시간 뒤에 자동으로 사라지도록 [자동감추기] 기능 설정 및 [문서열기] 시
          //촛점이 [편집기] 로 이동하여 [풍선도움말] 이 사라지는 것을 방지하기 위하여
          //[촛점사용] 을 해제 시킨다.
          //}--------------------------------------------------------------------------

          //촛점을 잃더라도 사라지지 않도록 설정.
          editor_top_Form->_balloonBox->_KillFocusUse(false);

          //[픙선도움말] 이 보여진뒤 1 초뒤 자동으로 사라진다.
          editor_top_Form->_balloonBox->_HideTime(1000);

      //}

      //[<*.gtxt> 문서가 존재하나?]
      //{
          //[2010.06.09.수][추가!!!]{-----------------------------------------
          //<*.gtxt> 가 존재하는 경우는 이 문서를 열어주고, 존재하지 않는다면
          //<*.h> 를 열어준다.
          //}-----------------------------------------------------------------

          if(FileExists(fileName) == true)
          {
            //<*.gtxt> 문서를 열어준다.
            editor_top_Form->_List_Add((AnsiString)fileName);

            //[읽기전용 설정]
            //{
                //[2022.06.30.목][추가]{*********************************
                //여기서 여는 문서는 [원본] 이므로 [읽기전용] 으로 설정.
                //}******************************************************
                
                editor_edit_Form->_readOnly = true;

            //}

            //[<편집기제목줄:풍선도움말> 에 문서이름 출력]
            //{
                //[2022.06.28.화][추가]
                if(fileName[0] != '\0')
                {
                  //[API 이름 얻기]
                  //{
                      //[2022.07.14.목][추가]
                      STR_GetFileNameOnly_ExceptExt(fileName, apiName_);

                  //}


                  //[2022.07.14.목][새 함수로 수정]
                  editor_top_Form->_BalloonBox_Print_At_FindStr(apiName_, 0, fileName);

                }  

            //}

          }
          else
          {
            //<*.gtxt> 문서의 확장자를 <*.h> 로 바꾸어 준다.
            //이 문서는 <*.glib> 에 반드시 존재한다.
            STR_ChangeFileExt(fileName, "h", fileHName);

            //<*.h> 문서를 열어준다.
            editor_top_Form->_List_Add((AnsiString)fileHName);

            //[읽기전용 설정]
            //{
                //[2022.06.30.목][추가]{*********************************
                //여기서 여는 문서는 [원본] 이므로 [읽기전용] 으로 설정.
                //}******************************************************
                
                editor_edit_Form->_readOnly = true;

            //}

            //[<편집기제목줄:풍선도움말> 에 문서이름 출력]
            //{
                //[2022.06.28.화][추가]
                if(fileHName[0] != '\0')
                {
                  //[API 이름 얻기]
                  //{
                      //[2022.07.14.목][추가]
                      STR_GetFileNameOnly_ExceptExt(fileHName, apiName_);

                  //}


                  //[2022.07.14.목][새 함수로 수정]
                  editor_top_Form->_BalloonBox_Print_At_FindStr(apiName_, 0, fileHName);

                }

            //}

          }

      //}

  //}

  //[<순간보기> 문서 후처리:편집기 요소 다시 그리기]
  //{
      //[2022.06.28.화][추가]{----------------------------------------------
      //위에서 [순간보기] 시 [깜박임방지] 처리를 했으므로 여기서 반드시
      //[편집기 요소] 를 다시 그려준다.
      //이는 깜박임 방지 처리시에는 다시 그리기가 중지 되기 때문.
      //
      //물론 여기서 문서를 여는 경우는 <Tree:API/API 검색> 의 [순간보기] 로
      //이미 열려 있는 문서를 다시 여는 경우가 되어 다시 그리지 않아도 이전
      //문서 그대로라 상관이 없으나, 확실하게 하기 위해서 다시 그려준다.
      //}-------------------------------------------------------------------

      ide_editor_Form->_Shape();

  //}

  return;

}

void __fastcall Ide_Tree_Api_Add_Glib_To_Gprj(//[2022.06.24.금][추가]
                                              //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 사용.
                                              //[Tree:API 검색] 지원하기 위한것.
                                              int  pTreeIndex)
{
  //[2009.06.01.월][생성!!!]{------------------------------------------------------------------
  //현재 선택된 항목을 [설계묶음] 에 추가한다.
  //[옹  이] : 이 [옹이] 자체 폴더를 전부 [설계묶음] 안의 [glib] 폴더(없으면 만든다) 에
  //           같은 이름으로 그대로 복사하고, 안의 모든 <*.glib> 를 [함수묶음] 에 등록해 준다.
  //           즉, 한꺼번에 지정 폴더 안의 모든 [함수묶음] 을 추가하는 경우다.
  //
  //<*.glib> : 한개의 지정된 <*.glib> 를 추가하는 경우에 해당한다.
  //           [glib] 폴더를 포함하여 완전히 같은 경로에 복사후 [함수묶음] 에 등록해 준다.
  //
  //[주의!!!]----------------------------------------------------------------------------------
  //반드시 <*.glib> 는 <*.h> , <*.gtxt> 와 짝이 되어야 하므로 항상 같이 복사한다.
  //죽, 항상 3 개 문서를 복사해 주어야 한다.
  //
  ///[2009.09.12.토][중요수정!!!]--------------------------------------------------------------
  //현재 [새설계묶음] 인 경우는 처리해서는 안된다.
  //이 경우 기본 경로이므로 해당 IDE\[glib] 안의 해당 API 가 삭제된다.
  //
  //[2022.06.24.금][중요수정]------------------------------------------------------------------
  //}------------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class   DATABASE  *database;

      struct  TREE   *tree;

      char    srcPath[OPT_lineStrSize];
      char    dstPath[OPT_lineStrSize];

      char    fileName[OPT_lineStrSize];

      //[문서목록] 을 가진다.
      TStringList  *fileList = NULL;

      int     i;

  //}

  //[새설계묶음인가?]
  //{
      //[2009.09.12.토][중요추가!!!]{--------------------
      //[새설계묶음] 인 경우는 API 를 추가해서는 안된다.
      //}------------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        //추가해서는 안된다.

        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 API 를 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        //더이상 처리하지 않고 종료한다.
        return;

      }

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&database);

      //[Tree 확인]
      //{
          //[2022.06.24.금][추가]{-------------------------------
          //<d_TREE_api>, <d_TREE_apiSrch> 둘중 하나만 허용된다.
          //}----------------------------------------------------

          if(!((pTreeIndex == d_TREE_api) || (pTreeIndex == d_TREE_apiSrch))) return;

      //}

      tree = &(tree_tree_Form->_tree[pTreeIndex]);

  //}

  //[항목이 <*.glib> 인가?]
  //{
      //항목이 <*.glib> 인 경우는 바로 복사한다.
      if(tree->items[tree->select_itemindex].bmpindex == d_ITEMBMP_api)
      {
        //[항목 경로 얻기]
        //{
            //현재 항목의 [Tree] 상의 경로를 구한다("glib\" 까지 포함된것).
            Ide_Tree_Api_Make_ItemPath(pTreeIndex, tree->select_itemindex, fileName);

        //}

        //[출발지 경로 합성]
        //{
            //출발지 경로 합성.
            STR_Add_AB(srcPath, database->programpath, fileName);

        //}

        //[도착지 경로 합성]
        //{
            //사용자 [설계묶음] 경로안으로 하면된다(출발지 경로에 "glib" 가 있으므로).
            STR_Add_AB(dstPath, database->projectpath, fileName);

        //}

        //[복사]
        //{
            //[<*.h> 복사]
            //{
                STR_ChangeFileExt(dstPath, "h", fileName); STR_Assign(dstPath, fileName);
                STR_ChangeFileExt(srcPath, "h", fileName); STR_Assign(srcPath, fileName);
                File_Copy(dstPath, srcPath);

            //}

            //[<*.gtxt> 복사]
            //{
                STR_ChangeFileExt(dstPath, "gtxt", fileName); STR_Assign(dstPath, fileName);
                STR_ChangeFileExt(srcPath, "gtxt", fileName); STR_Assign(srcPath, fileName);
                File_Copy(dstPath, srcPath);

             //}

            //[<*.glib> 복사]
            //{
                //바로 다음 부분에서 [함수묶음] 에 바로 추가 할수 있도록 가장 나중에 처리한다.
                STR_ChangeFileExt(dstPath, "glib", fileName); STR_Assign(dstPath, fileName);
                STR_ChangeFileExt(srcPath, "glib", fileName); STR_Assign(srcPath, fileName);
                File_Copy(dstPath, srcPath);

            //}

        //}

        //[함수묶음에 등록]
        //{
            //이미 등록된 것은 이 함수에서 자동으로 걸러지므로 다시 등록되지는 않는다.
            IDE_Project_Add_Glib(dstPath);

        //}

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //이 경우는 폴더에 해당 하는 경우로 안의 모든 문서를 복사하면 된다.

  //[경로 만들기]
  //{
      //[항목 경로 얻기]
      //{
          //현재 항목의 [Tree] 상의 경로를 구한다("glib\" 까지 포함된것).
          Ide_Tree_Api_Make_ItemPath(pTreeIndex, tree->select_itemindex, fileName);

      //}

      //[출발지 경로 합성]
      //{
          //출발지 경로 합성.
          STR_Add_AB(srcPath, database->programpath, fileName);

      //}

      //[도착지 경로 합성]
      //{
          //사용자 [설계묶음] 경로안으로 하면된다(출발지 경로에 "glib" 가 있으므로).
          STR_Add_AB(dstPath, database->projectpath, fileName);

      //}

  //}

  //[복사]
  //{
      //지정 [항목] 을 사용자 [설계묶음] 안의 [glib] 폴더 안의 같은 경로를 만들고 저장한다.
      Dir_Copy(dstPath, srcPath);

  //}

  //[추가]
  //{
      //[문서 목록 얻기]
      //{
          //현재 지정 [옹이] 폴더 안의 <*.glib> 문서목록을 구한다.

          //[목록 생성]{--------------
          fileList = new TStringList;
          fileList->Clear();
          //}-------------------------

          //지정 [옹이] 에 대응하는 폴더안의 <*.glib> 문서목록을 얻는다.
          Dir_Get_FileList_BoundDir(dstPath, "glib", false, d_File, fileList);

      //}

      for(i = 0; i < fileList->Count; i++)
      {
        //[함수묶음] 에 등록.
		if(IDE_Project_Add_Glib(((AnsiString)(fileList->Strings[i])).c_str()) != true) break;

      }

  //}

  //[후처리]
  //{
      if(fileList != NULL) { delete fileList; fileList = NULL; }

  //}

}

//------------------------------------------------------------------------------
//[편집기:실시간 선언정보판]----------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_EditorInfoTree_DoubleClick(void)
{
  //[2012.04.14.토][생성]{--------------------------------------------------------------------
  //[설계 정보] [Tree] 선택 항목의 [더블클릭] 의 경우를 처리한다.
  //
  //이 경우는 해당 항목이 선언되 있는 [문서] 를 열어 주고 [선언위치] 를 지정해 주어야 한다.
  //이미 <tem.dbRecIndex> 에 {DATABASE} 상의 <ecord-index> 정보가 기록되 있으므로 간단하게
  //해당 정보를 추출하여 처리할수 있다.
  //
  //[2012.04.16.월][수정!!!]------------------------------------------------------------------
  //[실시간 선언정보판] 의 경우는 [선언문서열기+위치지정] 이 큰 의미가 없다.
  //<*.h> 문서만 [선어정보수집] 이 가능한데 문제는 이 경우 [선언문서열기+위치지정] 가 안된다.
  //모든 경우를 다 포함하지 않으므로 일단 주석으로 처리.
  //
  //[2012.05.27.일][중요수정!!!]--------------------------------------------------------------
  //[실시간 선언 정보판] 이 오류없이 완벽 동작 하므로 활성화 한다.
  //더불어, [정의이름] 의 값을 수정하는데는 반드시 [선어부 찾기] 기능이 있어야 쉽게 수정가능.
  //의외로 [선언정보 찾기] 가 어렵기 때문에 반드시 필요하다.
  //}-----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      struct INFOTREE   *tree;

      int    nodeItemIndex;
      int    nodeLastItemIndex;

      //선택된 항목을 기록한다(표시 길이를 줄이가 위한것).
      int    selIndex;
      int    recIndex;
      int    fileListIndex;
      int    wordIndex;
      int    wordLength;

  //}

  //[선택된 것이 있는가?]
  //{
      //선택된 것이 없다면 아예 처리 하지 않는다.
      if(info_tree_Form->_tree.select_itemindex < 0) return;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(info_tree_Form->_tree);

      //선택된 항목을 기록한다.
      selIndex = tree->select_itemindex;

  //}

  //[예외처리]
  //{
      //[2009.02.17.화][추가!!!]{---------------------------
      //<dbRecIndex> 정보가 없는 경우는 처리할 필요가 없다.
      //}---------------------------------------------------

      if(tree->items[selIndex].info1 == -1) return;

  //}

  //[종류 구분 처리]
  //{
      //[!]{--------------------------------------------------------------------------------
      //[#define] 으로 선언된 것은 {definelist} 를 대상으로 해야 하므로 별도 구분하여 처리.
      //}-----------------------------------------------------------------------------------

      info_tree_Form->_Tree_Get_Node_LastItemIndex2(tree, "define", &nodeItemIndex, NULL, &nodeLastItemIndex);

      if((nodeItemIndex < selIndex) && (selIndex <= nodeLastItemIndex))
      {
        //[!]{------------------------------------------------------------
        //[#define] 으로 선언된 것이므로 {definelist[]} 를 대상으로 처리.
        //}---------------------------------------------------------------

        //[정보수집]
        //{
            recIndex      = tree->items[selIndex].info1;

            fileListIndex = database->definelist[recIndex].filelistindex;

            wordIndex     = database->definelist[recIndex].index;

            wordLength    = STR_Length(database->definelist[recIndex].defname);

        //}

      }
      else
      {
        //[!]{-----------------------------------------
        //일반적인 경우로 {database} 를 대상으로 처리.
        //}--------------------------------------------

        //[정보수집]
        //{
            recIndex      = tree->items[selIndex].info1;

            fileListIndex = database->record[recIndex].filelistindex;

            wordIndex     = database->record[recIndex].index;

            wordLength    = STR_Length(database->record[recIndex].name);

        //}

      }

  //}

  //[공통 처리]
  //{
      //[!]{-----------------------------------------------------------------------
      //이미 위에서 모든 정보를 얻었으므로 해당 항목이 있는 문서를 열어 주고 지정.
      //}--------------------------------------------------------------------------

      //[해당 문서 열기]
      //{
          //[2009.02.18.수][중요!!!]{-----------------------------------------------------
          //일단 문서를 열때는 깜박거림을 방지하기 위하여 [다시출력] 하지 않게 만든다.
          //이는 이전에 [선택] 된 것이 있는 경우 [깜박거림] 으로 보기 좋지 않기 때문이다.
          //여러 가지가 있으니 사용하지 않는 _edit_paste_ing 사용하여 처리한다.
          //
          //문서를 다시 출력하여 [선택영역] 을 반영하는 것은 아래 _Edit_SelectX() 함수
          //안에서 자동으로 한번만 처리 되어 [깜박거림] 이 없어 깔끔하다.
          //}-----------------------------------------------------------------------------

          editor_edit_Form->_edit_paste_ing = true;
          //{
              //파일을 열어준다.
              editor_top_Form->_List_Add(database->filelist[fileListIndex].name);

          //}
          editor_edit_Form->_edit_paste_ing = false;

      //}

      //[단어 지정]
      //{
          //[2009.02.18.수][추가!!!]{---
          //해당 단어를 지정해 준다.
          //}---------------------------

          editor_edit_Form->SetFocus();

          editor_edit_Form->_Edit_SelectX(//[선택영역] 시작 위치.
                                          wordIndex,
                                          //[선택영역] 끝 위치.
                                          wordIndex + wordLength,
                                          //자동으로 [선택영역] 이 항상 보이는 위치에 있게 만든다.
                                          true,
                                          NULL,
                                          true);

      //}

  //}

}

//------------------------------------------------------------------------------
//[기타 처리 함수]--------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall IDE_Database_View(void)
{
  //[2005.10.23.일][생성!!!]

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

  //}

  //[Database 주소 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  database->DEBUG_Database_View();

  return;

}

void __fastcall Ide_ErrorLine(//[오류] 가 있는 문서.
                              char  *pErrorFileName,
                              //[오류] 가 있는 [행번호].
                              int    pErrorLineNumber)
{
  //[2009.02.18.수][생성]{----------------------------------------------------------
  //[오류] 가 발생한 행의 정보를 바탕으로 [오류] 가 발생한 행을 [선택] 한다.
  //문법 검사시 정확하게 [단어] 의 index 를 얻기 힘들며, 상황에 따라 직접 [단어] 를
  //넣어 주는 경우가 있으나 [행] 은 정확하게 처리 되므로 이 [행] 을 아예
  //[선택영역] 으로 지정해 준다.
  //[단어] 는 아래 [알림창] 에 출력되므로 [행] 을 지정하는 것이 효과적이다.
  //
  //[2011.04.29.금][수정!!!]--------------------------------------------------------
  //무효처리 구분을 추가한다.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

      int   lineStartIndex;
      int   lineEndIndex;
      
  //}

  //[확인]
  //{
      //[2011.04.29.금][추가!!!]{--------------------------------------------
      //지정행이 <-1> 인 경우는 무효처리로 간주하여 아무 처리도 하지 않는다.
      //}--------------------------------------------------------------------

      if(pErrorLineNumber < 0) return;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[오류 단어 지정]
  //{
      //이미 위에서 모든 정보를 얻었으므로 해당 항목이 있는 문서를 열어 주고 지정해준다.

      //[해당 문서 열기]
      //{
          //[2009.02.18.수][중요!!!]{-----------------------------------------------------
          //일단 문서를 열때는 깜박거림을 방지하기 위하여 [다시출력] 하지 않게 만든다.
          //이는 이전에 [선택] 된 것이 있는 경우 [깜박거림] 으로 보기 좋지 않기 때문이다.
          //여러 가지가 있으니 사용하지 않는 _edit_paste_ing 사용하여 처리한다.
          //
          //문서를 다시 출력하여 [선택영역] 을 반영하는 것은 아래 _Edit_SelectX() 함수
          //안에서 자동으로 한번만 처리 되어 [깜박거림] 이 없어 깔끔하다.
          //}-----------------------------------------------------------------------------

          editor_edit_Form->_edit_paste_ing = true;
          //{
              //파일을 열어준다.
              editor_top_Form->_List_Add(pErrorFileName);

          //}
          editor_edit_Form->_edit_paste_ing = false;

      //}

      //[정보 얻기]
      //{
          //[주의!!!]{---------------------------------------------------------------
          //[위치] 정보가 아니고 [행] 정보를 바탕으로 처리해야 하므로 [행] 정보로
          //[위치] 정보를 얻기 위해서는 먼저 [문서] 를 [저장소] 에 열어 주어야 한다.
          //[저장소] 에 저장된 문자열을 대상으로 위치를 구하기 때문이다.
          //}------------------------------------------------------------------------

          //[오류행] 의 시작 위치 얻기.
          STR_Get_LineStartIndex(editor_edit_Form->_editbuf,
                                 pErrorLineNumber,
                                 &lineStartIndex);

          //[오류행] 의 끝 위치 얻기.
          STR_Get_ThisLineEndIndex(editor_edit_Form->_editbuf,
                                   lineStartIndex,
                                   &lineEndIndex);

      //}

      //[단어 지정]
      //{
          //[2009.02.18.수][추가!!!]{---
          //해당 단어를 지정해 준다.
          //}---------------------------

          editor_edit_Form->SetFocus();

          editor_edit_Form->_Edit_SelectX(//[선택영역] 시작 위치.
                                          lineStartIndex,
                                          //[선택영역] 끝 위치.
                                          lineEndIndex,
                                          //자동으로 [선택영역] 이 항상 보이는 위치에 있게 만든다.
                                          true,
                                          NULL,
                                          true);

      //}

  //}

  return;

}

//------------------------------------------------------------------------------
//[검증 구동 관련]--------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_VDEBUG_Run(void)
{
  //[2009.04.07.화][생성!!!]{-------------
  //[VDEBUG Thread] 를 생성하고 실행한다.
  //
  //[2011.06.15.수][추가!!!]--------------
  //[검증식] 관련 처리를 수행한다.
  //}-------------------------------------

  //[중복 실행 검사]
  //{
      //[!]{---------------------------------------------------
      //[VDEBUG Tgread] 가 이미 생성되 있는 상태인지 확인한다.
      //이미 생성되 있다면 생성처리 하지 않아야 한다.
      //}------------------------------------------------------

      if(VDEBUG_Exist() == true)
      {
        //이미 생성된 것이 있으므로 처리하지 않아야 한다.
        //ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
        //                         "이미 [검증 구동기] 가 구동 중입니다."
        //                        );

        return;

      }

  //}

  //[VDEBUG Thread 생성]
  //{
      //[!]{---------------------------------------------------
      //[VDEBUG 가상구동] 을 위한 [VDEBUG Thread] 를 생성한다.
      //딱, 한개만 있으면 된다.
      //}------------------------------------------------------

      VDEBUG_ThreadCreate();

  //}

  //[검증식 관련 처리]
  //{
      //[2011.06.15.수][추가!!!]
      DebugView_Create();

  //}

  return;

}

void __fastcall Ide_VDEBUG_Quit(void)
{
  //[2009.04.07.화][생성!!!]{--------------------------------------
  //[VDEBUG Thread] 를 종료한다.
  //실제 가상 구동중인 [VDEBUG] 를 완전히 [종료] 하고 [삭제] 한다.
  //
  //[2011.06.15.수][추가!!!]---------------------------------------
  //[검증식] 관련 처리를 수행한다.
  //}--------------------------------------------------------------

  //[중복 실행 검사]
  //{
      //[!]{---------------------------------------------------------------
      //[VDEBUG Tgread] 가 이미 종료/삭제된 상태라면 처리하지 않아야 한다.
      //}------------------------------------------------------------------

      if(VDEBUG_Exist() != true)
      {
        //이미 삭제된 상태이므로 처리하지 않는다.
        //ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
        //                         "이미 [검증 구동기] 가 종료되었습니다."
        //                        );

        return;

      }

  //}

  //[VDEBUG Thread 삭제]
  //{
      //[!]{-------------------------------------
      //동적 생성된 [VDEBUG Thread] 를 삭제한다.
      //}----------------------------------------

      VDEBUG_ThreadDelete();

  //}

  //[검증식 관련 처리]
  //{
      //[2011.06.15.수][추가!!!]
      DebugView_Delete();

  //}

  return;

}

bool __fastcall Ide_VDEBUG_Exsist(void)
{
  //[2009.04.07.화][생성!!!]{-------------------------
  //[VDEBUG Thread] 가 생성되어 존재 하는지 확인한다.
  //빈번하게 사용되므로 별도의 함수로 만든다.
  //}-------------------------------------------------

  //[VDEBUG 구동 확인]
  //{
      //[!]{-----------------------------------------------------------------
      //처리를 위하여 먼저 [VDEBUG] 가 생성된 상태인지 존재를 확인해야 한다.
      //}--------------------------------------------------------------------

      if(VDEBUG_Exist() == true)
      {
        //존재한다.
        return(true);

      }
      else
      {
        //존재하지 않는다.
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "[검증 구동기] 가 구동되고 있지 않습니다.\r\n"
                                 "먼저 [검증 구동기] 를 구동해 주시기 바랍니다."
                                );

        return(false);

      }

  //}

}

bool __fastcall Ide_VDEBUG_Done(void)
{
  //[2018.05.06.일][생성!!!]{-----------------------------------------------------
  //[검증] 을 완전히 중단하고 [가상기계개발] 기본탭으로 전환.
  //[가상기계개발] 탭으로 전한시 모든 검증은 종료하게 되는데 이 관련 함수를 사용.
  //
  //[main():종료] 시 검증 대상이 완전히 메모리에서 해제 되어 더이상 존재하지 않아
  //검증이 무의미해질때 사용.
  //
  //이 함수는 [main():종료] 감지 부에서 반드시 호출돼야 한다.
  //}-----------------------------------------------------------------------------

  //[가상기계개발:0] 기본 탭으로 강제 전환.
  ide_buttons_Form->_tabs->_TabIndex(0);

}

//------------------------------------------------------------------------------
//[가상구동 관련]---------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_VMOS_Run(void)
{
  //[2009.03.15.일][생성!!!]{------------
  //[VMOS Thread] 를 생성하고 실행한다.
  //실제 [VMOS] 를 가상 구동하는 것이다.
  //}------------------------------------

  //[중복 실행 검사]
  //{
      //[2009.03.16.월][추가!!!]{----------------------------
      //[VMOS Thread] 가 이미 생성되 있는 상태인지 확인한다.
      //이미 생성되 있다면 생성처리 하지 않아야 한다.
      //}----------------------------------------------------

      if(VMOS_Exist() == true)
      {
        //이미 생성된 것이 있으므로 처리하지 않아야 한다.
        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "이미 [맷돌] 이 가상 구동 중입니다."
                                );

        return;

      }

  //}

  //[VMOS Thread 생성]
  //{
      //[2009.03.16.월][추가!!!]{--------------------------
      //[VMOS 가상구동] 을 위한 [VMOS Thread] 를 생성한다.
      //딱, 한개만 있으면 된다.
      //}--------------------------------------------------

      VMOS_ThreadCreate();

  //}

  return;

}

void __fastcall Ide_VMOS_Quit(void)
{
  //[2009.03.15.일][생성!!!]{------------------------------------
  //[VMOS Thread] 를 종료한다.
  //실제 가상 구동중인 [VMOS] 를 완전히 [종료] 하고 [삭제] 한다.
  //}------------------------------------------------------------

  //[중복 실행 검사]
  //{
      //[2009.03.17.화][추가!!!]{----------------------------
      //[VMOS Tgread] 가 이미 종료/삭제된 상태라면 처리하지 않아야 한다.
      //}----------------------------------------------------

      if(VMOS_Exist() != true)
      {
        //이미 삭제된 상태이므로 처리하지 않는다.
        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "이미 [맷돌] 가상 구동이 종료되었습니다."
                                );

        return;

      }

  //}

  //[VMOS Thread 삭제]
  //{
      //[2009.03.16.월][추가!!!]{--------------
      //동적 생성된 [VMOS Thread] 를 삭제한다.
      //}--------------------------------------

      VMOS_ThreadDelete();

  //}

  return;

}

bool __fastcall Ide_VMOS_Exsit(void)
{
  //[2009.03.18.수][생성!!!]{-----------------------
  //[VMOS Thread] 가 생성되어 존재 하는지 확인한다.
  //빈번하게 사용되므로 별도의 함수로 만든다.
  //}-----------------------------------------------

  //[VMOS 구동 확인]
  //{
      //[2009.03.18.수][추가!!!]{------------------------------------------
      //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
      //}------------------------------------------------------------------

      if(VMOS_Exist() == true)
      {
        //존재한다.
        return(true);

      }
      else
      {
        //존재하지 않는다.
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "[맷돌] 이 구동되고 있지 않습니다.\r\n"
                                 "먼저 [맷돌] 을 구동해 주시기 바랍니다."
                                );

        return(false);

      }

  //}

}

bool __fastcall Ide_VMOS_Download(void)
{
  //[2009.03.12.목][생성!!!]{-------------------------------------------------------
  //<Build> 후 완성된 <*.gvmx> 를 읽어 들여 [가상구동] 한다.
  //실제 [VMOS] 와 완전히 같은 [가상 VMOS] 에서 구동시키며 [검증구동] 도 완벽하고
  //동일하게 실행된다.
  //이 경우 모든 정보는 {database} 를 참고한다.
  //실제 [통합개발환경] 자체 기능이 아니라 [VMOS] 를 검증하기 위한 개발자 기능이다.
  //
  //일단 G.M.RC.BASIC 용으로 한개의 <*.gvmx> 만 구동한다.
  //
  //[주의!!!][2009.03.17.화]--------------------------------------------------------
  //이 함수는 반드시 [VMOS] 가 가상 구동 중일때(존재할때)만 사용해야 한다.
  //
  //[2009.08.17.월][추가!!!]--------------------------------------------------------
  //[가상구동] 인 경우는 <*.gvms> 를 설치한다.
  //<*.gvmx> 는 실제 [맷돌모듈] 인 경우만 사용된다.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *database;
      struct TREE      *tree;

      class  VMOS      *vmos;

      char   tempStr[OPT_lineStrSize];
      char   fileName[OPT_lineStrSize];

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[DATABASE 위치 얻기]{-------------------------------------------------
  DATABASE_GetPtr(&database);
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[VMEX 설치]
  //{
      //[!]{-------------------------------------------------------------------
      //이미 <Link> 후에 <*.gvms> 가 생성된 상태이므로이 <*.gvms> 를 읽어 들여
      //VMOS 의 해당 공간에 설치한다.
      //}----------------------------------------------------------------------

      //[경로 만들기]
      //{
          STR_Assign(tempStr, database->buildpath);

          //[설계묶음] 의 이름은 현재 [Tree] 의 <root>.text 가 된다.
          //[2012.04.20.금][수정!!!]
          STR_Add(tempStr, tree_tree_Form->_Item_Txt_StrPtr3(tree, 0));

          //확장자를 <*.gvms> 로 바꿔준다.
          STR_ChangeFileExt(tempStr, "gvms", fileName);

          //[존재 확인]
          //{
              //[2009.03.14.토][추가!!!]{----------------------------
              //생성되 있는 <*.gvms> 가 없다면 처리하지 않아야 한다.
              //}----------------------------------------------------

              if(FileExists(fileName) != true)
              {
                //<*.gvms> 가 존재 하지 않으므로 처리하지 않는다.
                ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                         "실행할 <*.gvms> 가 만들어지지 않았습니다.\r\n"
                                         "먼저 실행 될수 있는 [가상기계<*.gvms>] 를 만들어 주십시요."
                                        );

                //더이상 처리하지 않고 여기서 종료한다.
                return(false);

              }

          //}

      //}

      //[설치]
      //{
          //[!]{------------------------------------------------------------------
          //<*.gvms> 를 설치한다.
          //현재는 G.M.RC.BASiC 지원용으로 현재 [설계묶음] 1 개만 처리 하면 된다.
          //}---------------------------------------------------------------------

          if(vmos->vmosMode == d_VMOS_Mode_Stop)
          {
            if(vmos->Mount(fileName) != true) return(false);

          }

      //}

  //}

  //[가상기계 이름 저장]
  //{
      //[2011.10.16.일][중요추가!!!]{------------------------------------------------------------
      //[확인] 등 다른 곳에서 현재 구동중인 [가상기계] 를 참조할수 있도록
      //[가상기계 이름] 을 별도 관리한다.
      //
      //이는 새로 추가된 API <_Ide_가상기계_실행경로_()> 와 <_Ide_가상기계_실행이름확장자_()> 를
      //지원하기 위한 것이다.
      //}----------------------------------------------------------------------------------------

      STR_Assign(_ide_Option.gvmName, fileName);

  //}

  return(true);

}

bool __fastcall Ide_VMOS_Download_Gvms(//가상 구동용 <*.gvms> 를 지정하여 설치한다.
                                       char  *pGvmsFileName)
{
  //[2009.03.12.목][생성!!!]{------------------------------------------------------------------
  //<Ide_VMOS_Download()> 함수를 기본으로 지정 [가상기계<*.gvms>] 를 설치하는 것으로 수정한다.
  //이는 새로 추가된 [가상기계 구동 전용 환경] 을 위한 것이다.
  //Ide_Ctrl_Stop() 로 VMOS 를 먼저 정지시킨다음에 사용해야 제대로 설치된다.
  //}------------------------------------------------------------------------------------------

  //[VAR]
  //{
      class  VMOS  *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[VMEX 설치]
  //{
      //[존재 확인]
      //{
          //[!]{-------------------------------------------------
          //생성되 있는 <*.gvms> 가 없다면 처리하지 않아야 한다.
          //}----------------------------------------------------

          if(FileExists(pGvmsFileName) != true)
          {
            //<*.gvms> 가 존재 하지 않으므로 처리하지 않는다.
            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "설치할 <*.gvms> 가 존재하지 않습니다."
                                    );

            //더이상 처리하지 않고 여기서 종료한다.
            return(false);

          }

      //}

      //[설치]
      //{
          //[!]{-----------------------
          //지정 <*.gvms> 를 설치한다.
          //}--------------------------

          if(vmos->vmosMode == d_VMOS_Mode_Stop)
          {
            if(vmos->Mount(pGvmsFileName) != true) return(false);

          }

      //}

  //}

  //[가상기계 이름 저장]
  //{
      //[!]{--------------------------------------------------------------
      //[확인] 등 다른 곳에서 현재 구동중인 [가상기계] 를 참조할수 있도록
      //[가상기계 이름] 을 별도 관리한다.
      //}-----------------------------------------------------------------

      STR_Assign(_ide_Option.gvmName, pGvmsFileName);

  //}

  return(true);

}

bool __fastcall Ide_VMOS_Upload(void)
{
  //[2009.03.18.수][생성!!!]

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------




  return(true);

}

bool __fastcall Ide_VMOS_Verify(void)
{
  //[2009.03.18.수][생성!!!]

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------



  return(true);

}

bool __fastcall Ide_VMOS_Erase(void)
{
  //[2009.03.18.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{-------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Msg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VMOS_RomErase;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VMOS_Start(void)
{
  //[2009.03.18.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Mode);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]-------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_VMOS_Mode_Run;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VMOS_Stop(void)
{
  //[2009.03.18.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Mode);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]-------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_VMOS_Mode_Stop;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VMOS_Reset(void)
{
  //[2009.03.18.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{-------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Msg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VMOS_Reset;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}-------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VMOS_DebugReset(void)
{
  //[2009.04.06.월][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{-------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Msg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VMOS_DebugReset;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}-------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VMOS_ResetStop(void)
{
  //[2010.07.07.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{-------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_Msg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VMOS_ResetStop;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}-------------------------------------------------------------------------------

  return(true);

}

//------------------------------------------------------------------------------
//[VM 명령]---------------------------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_VM_Reset(void)
{
  //[2009.04.08.수][생성!!!]{----------------------------------------
  //[VM] 을 <Reset Vector> 에서부터 다시 실행 시킨다([정지점] 적용).
  
  //}----------------------------------------------------------------

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) { return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{---------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_vmMsg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]-----------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]---------------------------ㅈ-----------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VM_Reset;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]-----------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}---------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VM_ResetVector(void)
{
  //[2009.04.08.수][생성!!!]{------------------------------
  //[VM] 을 <Reset Vector> 에 @PC 를 위치 시키고 정지한다.
  //}------------------------------------------------------

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{---------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_vmMsg);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]-----------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]----------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = d_Msg_VM_ResetVector;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]-----------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}---------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VM_Mode(int  pVmMode)
{
  //[2009.04.08.수][생성!!!]

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{-------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_vmMode);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]--------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  main_Form->comM1_TxdBuf[2] = pVmMode;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]---------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}-------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VM_Mode_Read(int  *rVmMode)
{
  //[2011.05.28.토][생성!!!]{----------------------------------------------
  //[VMOS] 에서 현재 구동중인 [VM] 의 구동상태를 읽어서 반환한다.
  //
  //[쓰레드] 에서는 읽는 것은 직접 읽어도 무관하므로 직접 읽어서 처리한다.
  //}----------------------------------------------------------------------

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[현재 VM-MODE 읽어서 반환]
  //{
      (*rVmMode) = vmos->vmMode;

  //}

  return(true);

}

bool __fastcall Ide_VM_SysBreakPoint(DTU8  pAdr)
{
  //[2009.04.09.목][생성!!!]{---
  //[특수정지점] 을 설정한다.
  //}---------------------------

  //[VAR]
  //{
      class  VMOS   *vmos;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[주소]{------------------------------------------------------------------------
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 1, d_Map_Vmos_SysBP);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]-------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 1);
  *((DTU8 *)(&(main_Form->comM1_TxdBuf[2]))) = pAdr;
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 10;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_VM_BreakPoint(bool  pEnable)
{
  //[2009.04.29.수][생성!!!]{-----------------------------------------------------------
  //[정지점] 12 개를 한꺼번에 일괄 설정한다.
  //
  //[2009.04.29.수][수정!!!]------------------------------------------------------------
  //<pEnable:true>  : 현재 [정지점] 을 그대로 설정해 준다.
  //<pEnable:false> : [정지점] 을 무효화 하므로 모두 0xF:F 로 초기화 한것으로 설정한다.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      class  VMOS   *vmos;

      struct BPLIST *bpList;

      int    i;

  //}

  //[VMOS 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_VMOS_Exsit() != true) {  return(false); }
  //}------------------------------------------------------------------

  //[VMOS 위치 얻기]{------------------------------
  //이미 생성되 있는 [가상 VMOS] 의 위치를 얻는다.
  VMOS_GetPtr(&vmos);
  //}----------------------------------------------

  //[정지점 관리자 위치 얻기]{---
  Debug_BpList_GetPtr(&bpList);
  //}----------------------------

  //[주소]{------------------------------------------------------------------------
  //<8Byte 크기의 [정지점] 12 개>-----------------------------v
  GxCom_M1_AdrPacket(main_Form->comM1_TxdBuf, d_GxCom_M1_Wr, 8*12, d_Map_Vmos_BP);
  //전송을 시작한다.
  main_Form->comM1_TxdCount = 3;
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //[자료]-------------------------------------------------------------------------
  GxCom_M1_Hdr_Encode(main_Form->comM1_TxdBuf, d_GxCom_M1_Data, d_GxCom_M1_Wr, 8 * 12);

  //[정지점 12개 정리]
  //{
      for(i = 0; i < 12; i++)
      {
        if(pEnable == true)
        {
          //[정지점] 을 사용하는 경우이므로 설정된 값을 사용한다.
          ((DTU8 *)(&(main_Form->comM1_TxdBuf[2])))[i] = bpList->items[i].adr;

        }
        else
        {
          //[정지점] 을 일시 해제하는 것이므로 동작되지 않도록 무조건 0xF:F 초기값으로 설정한다.
          ((DTU8 *)(&(main_Form->comM1_TxdBuf[2])))[i] = 0xffffffffffffffff;

        }

      }

  //}

  //전송을 시작한다.
  main_Form->comM1_TxdCount = (2) + (8 * 12);
  main_Form->ComM1_Txd();
  vmos->Com_Process();
  //[ACK]--------------------------------------------------------------------------
  if(Ide_Ctrl_Ack(2000) != true) { return(false); }
  //}------------------------------------------------------------------------------

  return(true);

}

//------------------------------------------------------------------------------
//[맷돌모듈 제어관련]-----------------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_Mdl_Exsist(void)
{
  //[2009.07.14.화][생성!!!]{-------------------------------------------------
  //[맷돌모듈] 이 연결되 있는지 확인한다.
  //[장치정보문자열] 을 [직렬버스] 로 읽어 들여 간단하게 학인할수 있다.
  //
  //[2009.08.01.토][추가!!!]--------------------------------------------------
  //<d_Map_VmosBuildDate> 로 VMOS 의 제작날짜를 읽어 들이는 것으로 처리한다.
  ///읽어 들인 값자체는 의미가 없으므로 단지 읽는 과정에서 제대로 응답한다면,
  //[맷돌모듈] 이 연결되 있는 것으로 본다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      DTU8  vmosBuildDate;

  //}

  //[주의!!!]{-------------------------------------------------------------------------
  //실제 모듈은 계속 확인 하는 경우 빈번한 사용으로 통신오류가 발생하고,
  //각각 통신시 계속 [시간제한] 으로 자동 확인되므로 여기서느 무조건 true 를 반환한다.
  return(true);
  //}----------------------------------------------------------------------------------

  //[VMOS 제작 날짜 읽기]
  //{
      /*
      //8Byte 크기-------------------------v
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_B, 3, d_Map_BuildDate, (DTU1 *)(&vmosBuildDate)) == true)
      {
        //존재한다.
        return(true);

      }
      else
      {
        //존재하지 않는다.
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "[맷돌] 이 연결되어 있지 않습니다.\r\n"
                                 "먼저 [맷돌] 이 연결되 있는지 확인해 주시고,\r\n"
                                 "연결돼 있다면 전원이 공급중인지 확인바랍니다."
                                );

        return(false);

      }
      */
  //}    

}

bool __fastcall Ide_Mdl_Download(void)
{
  //[2009.07.15.수][생성!!!]{-----------------------------------------
  //<Build> 후 완성된 <*.gvmx> 를 실제 [맷돌모듈] 에 설치한다.
  //이 경우 모든 정보는 {database} 를 참고한다.
  //
  //현재는 1 개의 <*.gvmx> 만 구동한다.
  //
  //이 함수는 반드시 [맷돌모듈] 이 연결된 상태에서만 사용되어야 한다.
  //
  //무조건 현재 <설계묵음.gvmx> 을 대상으로 처리한다.
  //}-----------------------------------------------------------------

  //[VAR]
  //{
      class   DATABASE  *database;
      struct  TREE      *tree;

      char    tempStr[OPT_lineStrSize];
      char    fileName[OPT_lineStrSize];

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[DATABASE 위치 얻기]{-------------------------------------------------
  DATABASE_GetPtr(&database);
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------

  //[VMEX 설치]
  //{
      //[!]{--------------------------------------------------------------------
      //이미 <Link> 후에 <*.gvmx> 가 생성된 상태이므로 이 <*.gvmx> 를 읽어 들여
      //VMOS 의 해당 공간에 설치한다.
      //}-----------------------------------------------------------------------

      //[경로 만들기]
      //{
          STR_Assign(tempStr, database->buildpath);

          //[설계묶음] 의 이름은 현재 [Tree] 의 <root>.text 가 된다.
          //[2012.04.20.금][수정!!!]
          STR_Add(tempStr, tree_tree_Form->_Item_Txt_StrPtr3(tree, 0));

          //확장자를 <*.gvmx> 로 바꿔준다.
          STR_ChangeFileExt(tempStr, "gvmx", fileName);

          //[존재 확인]
          //{
              //[!]{-------------------------------------------------
              //생성되 있는 <*.gvmx> 가 없다면 처리하지 않아야 한다.
              //}----------------------------------------------------

              if(FileExists(fileName) != true)
              {
                //<*.gvmx> 가 존재 하지 않으므로 처리하지 않는다.
                ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                         "실행할 <*.gvmx> 가 만들어지지 않았습니다.\r\n"
                                         "먼저 실행 될수 있는 [가상기계<*.gvmx>] 를 만들어 주십시요."
                                        );

                //더이상 처리하지 않고 여기서 종료한다.
                return(false);

              }

          //}

      //}

      //[설치]
      //{
          //[2009.07.15.수][추가!!!]{-----------------------------------------------
          //<*.gvmx> 를 설치한다.
          //정해진 [VMOS] 의 [사용자 Flash] 영역에 설치해 주어야 한다.
          //현재는 1개 밖에는 지원하지 않으므로 무조건 시작 주소부터 처리하면 된다.
          //
          //[2009.08.18.화][수정!!!]------------------------------------------------
          //Matdol_Gvmx_Install() 함수를 사용하는 것으로 수정한다.
          //}-----------------------------------------------------------------------


          //[알림글 출력]
          //{
              //[2009.08.18.화][추가!!!]
              msg_msg_Form->_PrintAddLine(d_msg_msg, "[가상기계] : ");
              msg_msg_Form->_PrintAdd(d_msg_msg, fileName);

          //}

          //[2011.11.13.일][수정!!!]
          //[VMOS:API 적합성 검사] 수행----v
          if(Matdol_Gvmx_Install(fileName, true, NULL) != true) return(false);

      //}

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Download_Gvmx(//맷돌(G.MTDL.A) 구동용 <*.gvmx> 를 지정하여 설치한다.
                                      char              *pGvmxFileName,
                                      //[2011.11.11.금][추가!!!]
                                      //<PCC:VMOS> 와 동기화를 위한것(미사용인 경우 NULL).
                                      struct VMOS_SYNC  *pVmosSync)
{
  //[2009.03.12.목][생성!!!]{-----------------------------------------------------------------
  //<Ide_Mdl_Download()> 함수를 기본으로 지정 [가상기계<*.gvmx>] 를 설치하는 것으로 수정한다.
  //이는 새로 추가된 [가상기계 구동 전용 환경] 을 위한 것이다.
  //Ide_Ctrl_Stop() 로 VMOS 를 먼저 정지시킨다음에 사용해야 제대로 설치된다.
  //}-----------------------------------------------------------------------------------------

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[VMEX 설치]
  //{
      //[존재 확인]
      //{
          //[!]{-------------------------------------------------
          //생성되 있는 <*.gvmx> 가 없다면 처리하지 않아야 한다.
          //}----------------------------------------------------

          if(FileExists(pGvmxFileName) != true)
          {
            //<*.gvmx> 가 존재 하지 않으므로 처리하지 않는다.
            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "실행할 <*.gvmx> 가 존재하지 않습니다."
                                    );

            //더이상 처리하지 않고 여기서 종료한다.
            return(false);

          }

      //}

      //[설치]
      //{
          //[!]{-----------------------
          //지정 <*.gvmx> 를 설치한다.
          //}--------------------------

          //[2011.11.13.일][수정!!!]
          //이 함수는 [설계묶음] 없이 바로 <GVMX> 를 맷돌에 설치하는 것이므로
          //[VMOS:API 적합성 검사] 하지 않는다.
          //------------------------------------v
          if(Matdol_Gvmx_Install(pGvmxFileName, false, pVmosSync) != true) return(false);

      //}

  //}

  //[가상기계 이름 저장]
  //{
      //[!]{--------------------------------------------------------------
      //[확인] 등 다른 곳에서 현재 구동중인 [가상기계] 를 참조할수 있도록
      //[가상기계 이름] 을 별도 관리한다.
      //}-----------------------------------------------------------------

      if(pVmosSync == NULL)
      {
        //[2011.11.11.금][수정!!!]{---------------------------------------
        //<맷돌C:API> 처리를 위하여 사용되는 경우는 처리하지 않아야 한다.
        //이는 [맷돌-개발환경] 에 영향을 주어서는 안되기 때문이다.
        //<Ide_API_GVMX_Install()> 함수안의 설명을 참고한다.
        //}---------------------------------------------------------------

        STR_Assign(_ide_Option.gvmName, pGvmxFileName);

      }

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Upload(void)
{
  //[2009.07.16.목][생성!!!]{---------------------------------------------------------
  //실제 <*.gvmx> 는 _ROM_[0] 부터존재하지 않으며, 이곳에는 전체 정보도 같이 있으므로
  //무조건 _ROM_ 을 전부 읽어 들인다고 되지는 않는다.
  //현재 이 기능은 그리 필요하지 않으므로 비워둔다.
  //
  //[2013.06.19.수][제작!!!]----------------------------------------------------------
  //1) [맷돌] 에서 [가상기계] 를 읽어들여 지정 폴더안에 저장.
  //
  //2) "[ide]\upload\가상기계.gvmx" 로 저장.
  //
  //기능 추가.
  //}---------------------------------------------------------------------------------

  //[VAR]
  //{
      class   DATABASE  *database;

      char    tempStr[OPT_lineStrSize];

  //}

  //[맷돌 존재 확인]{-----------------------------
  //처리를 위하여 먼저 대상 [VMOS] 존재 확인.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}---------------------------------------------

  //[DATABASE 위치 얻기]{-----
  DATABASE_GetPtr(&database);
  //}-------------------------

  //[경로 만들기]
  //{
      //[!]{----------------------------------
      //"[ide]\upload\가상기계.gvmx" 로 고정.
      //폴더가 없는 경우는 자동 생성.
      //}-------------------------------------

      STR_Assign(tempStr, database->programpath);
      STR_Add(tempStr, "upload\\");

      //[폴더 생성]
      //{
          //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성.
          File_CreateDirectory(tempStr);

      //}

      STR_Add(tempStr, "가상기계.gvmx");

  //}

  //[가상기계(GVMX) 복사/수거]
  //{
      if(Matdol_Mount_Upload(tempStr) != true) return(false);

  //}

  //[알림창에 전체 경로 출력]
  //{
      //[복사/수거] 된 가상기계(*.gvmx) 위치 출력.
      msg_msg_Form->_PrintAddLine(d_msg_msg, tempStr);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Verify(void)
{
  //[2009.07.15.수][생성!!!]{---------------------------------------------------
  //[2009.08.02.일][제작!!!]
  //<Build> 후 완성된 <*.gvmx> 를 기준으로, 현재 설치된 것을 읽어들여 비교한다.
  //
  //현재는 1 개의 <*.gvmx> 만 구동한다.
  //이 함수는 반드시 [맷돌모듈] 이 연결된 상태에서만 사용되어야 한다.
  //무조건 현재 <설계묵음.gvmx> 을 대상으로 처리한다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      class   DATABASE  *database;
      struct  TREE      *tree;

      char    tempStr[OPT_lineStrSize];
      char    fileName[OPT_lineStrSize];

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[DATABASE 위치 얻기]{-------------------------------------------------
  DATABASE_GetPtr(&database);
  //[Tree 치환]-----------------------------------------------------------
  //[문장] 을 간결하게 하기 위하여 [Tree] 를 [포인터] 로 받아서 사용한다.
  tree = &(tree_tree_Form->_tree[d_TREE_project]);
  //}---------------------------------------------------------------------

  //[VMEX 확인]
  //{
      //[!]{--------------------------------------------------------------------
      //이미 <Link> 후에 <*.gvmx> 가 생성된 상태이므로 이 <*.gvmx> 를 읽어 들여
      //VMOS 의 해당 공간에 설치한다.
      //}-----------------------------------------------------------------------

      //[경로 만들기]
      //{
          STR_Assign(tempStr, database->buildpath);

          //[설계묶음] 의 이름은 현재 [Tree] 의 <root>.text 가 된다.
          //[2012.04.20.금][수정!!!]
          STR_Add(tempStr, tree_tree_Form->_Item_Txt_StrPtr3(tree, 0));

          //확장자를 <*.gvmx> 로 바꿔준다.
          STR_ChangeFileExt(tempStr, "gvmx", fileName);

          //[존재 확인]
          //{
              //[!]{-------------------------------------------------
              //생성되 있는 <*.gvmx> 가 없다면 처리하지 않아야 한다.
              //}----------------------------------------------------

              if(FileExists(fileName) != true)
              {
                //<*.gvmx> 가 존재 하지 않으므로 처리하지 않는다.
                ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                         "검사할 <*.gvmx> 가 만들어지지 않았습니다.\r\n"
                                         "먼저 검사할 [가상기계<*.gvmx>] 를 만들어 주십시요."
                                        );

                //더이상 처리하지 않고 여기서 종료한다.
                return(false);

              }

          //}

      //}

      //[비교검사]
      //{
          //처리가 복잡하므로 전용함수를 사용한다.
          //비교검사결과 일치하지 않는 경우는 이 함수 내부적으로 관련 [알림글] 을 처리하게 된다.
          if(Matdol_Mount_Verify(fileName, NULL) != true) return(false);

      //}

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Verify_Gvmx(char              *pGvmxFileName,
                                    //[2011.11.11.금][추가!!!]
                                    //<PCC:VMOS> 와 동기화를 위한것(미사용인 경우 NULL).
                                    struct VMOS_SYNC  *pVmosSync)
{
  //[2010.07.07.수][생성!!!]{------------------------------------------------------
  //<Ide_Mdl_Verify()> 함수로 만든것으로 [가상기계 전용 환경용 처리를 위한 것이다.
  //}------------------------------------------------------------------------------

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[VMEX 확인]
  //{
      //[존재 확인]
      //{
          if(FileExists(pGvmxFileName) != true)
          {
            //<*.gvmx> 가 존재 하지 않으므로 처리하지 않는다.
            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "검사할 <*.gvmx> 가 존재하지 않습니다."
                                    );

            //더이상 처리하지 않고 여기서 종료한다.
            return(false);

          }

      //}

      //[비교검사]
      //{
          //처리가 복잡하므로 전용함수를 사용한다.
          //비교검사결과 일치하지 않는 경우는 이 함수 내부적으로 관련 [알림글] 을 처리하게 된다.
          if(Matdol_Mount_Verify(pGvmxFileName, pVmosSync) != true)
          {
            //[!]{------------------------------------------------------------------
            //[가상기계 전용 환경] 에서는 별도의 오류 문자열을 표시할 창이 없으므로
            //여기서 기본적으로 오류가 발생했음을 알려 주어야 한다.
            //}---------------------------------------------------------------------

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                     "설치한 [가상기계(*.gvmx)] 가 원본과 일치하지 않습니다."
                                    );

            return(false);

          }

      //}

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Erase(void)
{
  //[2009.07.16.목][생성!!!]{----------------------------------------------------
  //실제 [맷돌] 의 모든 [사용자 ROM 영역] 을 지운다.
  //실제 STM32F103 을 대상으로 처리하므로 전용함수로 처리한다.
  //
  //[2009.07.24.금][추가!!!]-----------------------------------------------------
  //[직렬버스:B] 로 직접 VMOS 의 해당 변수에 [명령] 을 기록하는 방법을 사용한다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_Msg_VMOS_RomErase;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Msg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_MsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_MsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{-----------------------
      //[시간제한] 이 적용되었다.
      //[지우기] 는 시간이 많이 걸리므로 길게 설정한다.
      //}-----------------------------------------------

      //명령처리가 완료될때까지 대기한다.

      if(ComBus_FwByte_Read(d_CBFW_FIN, 5000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Start(void)
{
  //[2009.07.27.월][생성!!!]{------------
  //[맷돌모듈] 의 VMOS 를 [기동] 시킨다.
  //}------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_VMOS_Mode_Run;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Mode, &temp) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Stop(void)
{
  //[2009.07.27.월][생성!!!]{------------
  //[맷돌모듈] 의 VMOS 를 [정지] 시킨다.
  //}------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_VMOS_Mode_Stop;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Mode, &temp) != true) return(false);

  //}

  //Sleep(250);

  return(true);

}

bool __fastcall Ide_Mdl_Reset(//[2010.05.07.금][추가!!!]
                              //Ide_Mdl_Stop() 함수를 사용할지 말지를 결정한다.
                              bool  pVmosStopUse)
{
  //[2009.07.27.월][생성!!!]{----------------------------------------------------
  //[맷돌모듈] 을 <SW-Reset> 시킨다.
  //실제는 VMOS 자체를 재기동 하는 것이다.
  //
  //[2010.05.07.금][수정!!!]-----------------------------------------------------
  //OS 를 VMOS 계열 이외의 다른 것도 설치할수 있는데, Ide_Mdl_Stop() 명령은
  //VMOS 에만 적용되는 것이므로 다른 OS 의 경우는 사용하지 않도록 결정하게 한다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  if(pVmosStopUse == true)
  {
    //[2010.05.07.금][수정!!!]{-------------------
    //VMOS 계열 OS 인 경우만 사용하도록 수정한다.
    //}-------------------------------------------

    //[맷돌 존재 확인]{--------------------------------------------------
    //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
    if(Ide_Mdl_Exsist() != true) { return(false); }
    //}------------------------------------------------------------------

    //[2009.09.05.토][중요추가!!!]{------------------------------------------------
    //먼저 VMOS 를 멈춘다음에 처리하는 것이 동작이 확실하다.
    //다른 경우에는 맷돌내부적으로 이벤트가 발생하고 있는 경우에 제대로 <Hw-Reset>
    //되지 않는 경우가 발생하였다.
    //금일 API _Gpio_이벤트_() 를 검증하다가 이문제를 발견하고 수정한다.
    if(Ide_Mdl_Stop() != true) { return(false); }
    //}----------------------------------------------------------------------------

  }

  //[명령전송]
  //{
      temp = d_Msg_VMOS_Reset;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Msg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_MsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_MsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{---
      //[시간제한] 이 적용되었다.
      //}---------------------------

      //명령처리가 완료될때까지 대기한다.
      if(ComBus_FwByte_Read(d_CBFW_FIN, 3000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_DebugReset(void)
{
  //[2009.07.29.수][생성!!!]{-----------------------------------------------
  //[맷돌모듈] 을 <Debug-Reset> 시킨다.
  //새로운 가상기계를 [설치] 하고 생성후 [처음명령] 실행전 정지하게 만든다.
  //VM 은 [정지] 하지만 VMOS 자체는 [실행] 상태가 된다.
  //}-----------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_Msg_VMOS_DebugReset;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Msg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_MsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_MsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{---
      //[시간제한] 이 적용되었다.
      //}---------------------------

      //명령처리가 완료될때까지 대기한다.
      if(ComBus_FwByte_Read(d_CBFW_FIN, 3000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_ResetStop(void)
{
  //[2010.07.07.수][생성!!!]{--------------------------------------------------
  //VMOS 자체를 재기동하되 바로 정지 시킨다.
  //이는 [가상기계] 설치후 설치한 [가상기계] 를 VMOS 에 올려놓은 상태로 [정지]
  //하여 언제나 [재기동] 없이 [실행] 할수 있는 상태로 만들기 위한 것이다.
  //}--------------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_Msg_VMOS_ResetStop;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_Msg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_MsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_MsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{---
      //[시간제한] 이 적용되었다.
      //}---------------------------

      //명령처리가 완료될때까지 대기한다.
      if(ComBus_FwByte_Read(d_CBFW_FIN, 3000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_Reset(void)
{
  //[2009.07.29.수][생성!!!]{-----------------------------------------------
  //[맷돌모듈] 을 <Debug-Reset> 시킨다.
  //새로운 가상기계를 [설치] 하고 생성후 [처음명령] 실행전 정지하게 만든다.
  //VM 은 [정지] 하지만 VMOS 자체는 [실행] 상태가 된다.
  //}-----------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_Msg_VM_Reset;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMsg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_vmMsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{---
      //[시간제한] 이 적용되었다.
      //}---------------------------

      //명령처리가 완료될때까지 대기한다.
      if(ComBus_FwByte_Read(d_CBFW_FIN, 3000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_ResetVector(void)
{
  //[2009.07.29.수][생성!!!]{-----------------------------------------------
  //[VM] 을 <Reset Vector> 위치로 돌려놓고 [정지] 한다.
  //<Reset Vector> 로 이동후 [정지] 한다는 것이 <VM_Reset> 과의 차이점이다.
  //}-----------------------------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = d_Msg_VM_ResetVector;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMsg, &temp) != true) return(false);

  //}

  //[처리요청]
  //{
      //명령처리를 요청한다.
      temp = d_vmMsgExe_Set;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMsgExe, &temp) != true) return(false);

  //}

  //[처리완료확인]
  //{
      //[2009.08.01.토][수정!!!]{---
      //[시간제한] 이 적용되었다.
      //}---------------------------

      //명령처리가 완료될때까지 대기한다.
      if(ComBus_FwByte_Read(d_CBFW_FIN, 3000) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_Mode(int  pVmMode)
{
  //[2009.07.29.수][생성!!!]{----
  //[VM] 의 동작방식을 설정한다.
  //}----------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      temp = pVmMode;
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMode, &temp) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_Mode_Read(int  *rVmMode)
{
  //[2011.05.28.토][생성!!!]{-------------------------
  //맷돌에서 직접 [VM] 의 동작방식을 읽어서 반환한다.
  //}-------------------------------------------------

  //[VAR]
  //{
      unsigned char  temp;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      //직접 VM-MODE 를 읽어들인다.
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_B, 0, d_Map_Vmos_vmMode, &temp) != true) return(false);

  //}

  //[반환]
  //{
      (*rVmMode) = temp;

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_SysBreakPoint(DTU8  pAdr)
{
  //[2009.07.29.수][생성!!!]{-----------------
  //[검증] 을 위한 [특수 정지점] 을 설정한다.
  //}-----------------------------------------

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[명령전송]
  //{
      //8Byte 크기--------------------------v
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 3, d_Map_Vmos_SysBP, (DTU1 *)&pAdr) != true) return(false);;

  //}

  return(true);

}

bool __fastcall Ide_Mdl_VM_BreakPoint(bool  pEnable)
{
  //[2009.07.29.수][생성!!!]{-----------------------------
  //[검증] 을 위한 [일반 정지점] 12 개를 한번에 설정한다.
  //}-----------------------------------------------------

  //[VAR]
  //{
      //[정지점] 관리자 위치를 얻는다.
      struct BPLIST  *bpList;

      //모든 [정지점] 의 주소만 전송을 위하여 저장한다.
      DTU8   bpAdrList[d_BpItem_Max];

      int    i;

  //}

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[정지점 관리자 위치 얻기]{---
  Debug_BpList_GetPtr(&bpList);
  //}----------------------------

  //[정지점 정리]
  //{

      for(i = 0; i < d_BpItem_Max; i++)
      {
        if(pEnable == true)
        {
          //[정지점] 을 사용하는 경우이므로 설정된 값을 사용한다.
          bpAdrList[i] = bpList->items[i].adr;

        }
        else
        {
          //[정지점] 을 일시 해제하는 것이므로 동작되지 않도록 무조건 0xF:F 초기값으로 설정한다.
          bpAdrList[i] = 0xffffffffffffffff;

        }

      }

  //}

  //[명령전송]
  //{
      //[참고!!!]{---------------------------------------------------------------
      //현재 [정지점] 은 총 12 개를 사용하므로 8*12 = 96Byte 가 된다.
      //따라서, <2^지수승> 으로 크기를 표현하기 위하여 128Byte 에 크기를 맞춘다.
      //}------------------------------------------------------------------------

      //128Byte 크기------------------------v
      if(ComBus_Write(d_CB_TS_S, d_CB_AK_B, 7, d_Map_Vmos_BP, (DTU1 *)(&bpAdrList)) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_BuildDate(unsigned long long  *rBuildDate)
{
  //[2009.08.05.수][생성!!!]{----------------------------------------------
  //실제 [맷돌모듈] 의 [제조날짜] 를 읽어 들여 반환한다.
  //
  //BaseVM/VMOS 모두 다 적용되며, 0x0000000000000000 이 읽힌다면 BaseVM 이
  //OS 로 기동중인 것으로 확인할수 있다.
  //즉, 어떤 OS 가 구동중인지도 더불어 알수 있다.
  //}----------------------------------------------------------------------

  //[맷돌 존재 확인]{--------------------------------------------------
  //처리를 위하여 먼저 [VMOS] 가 생성된 상태인지 존재를 확인해야 한다.
  if(Ide_Mdl_Exsist() != true) { return(false); }
  //}------------------------------------------------------------------

  //[제조날짜 읽기]
  //{
      //88Byte 크기------------------------v
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_B, 3, d_Map_BuildDate, (DTU1 *)rBuildDate) != true) return(false);

  //}

  return(true);

}

bool __fastcall Ide_Mdl_Change_OS_To_BaseVM(void)
{
  //[2009.08.07.금][생성!!!]{-----------------------------------------------------
  //현재 연결되 있는 [맷돌모듈] 이 BaseVM 구동 상태인지 확인하고,
  //BaseVM 이 아닌 경우는 강제로 BaseVM 으로 전환시킨다.
  //
  //(1) <BaseVM> 이 구동되고 있는 상태인지 확인.
  //
  //(2) <VMOS> 상태라면 통신으로 <BaseVM> 으로 전환시킨다.
  //    [BaseVM 구동] 표시를 하고 <HW Reset> 을 시킨다.
  //    자동으로 BaseVM 구동으로 들어간다.
  //
  //(3) <BaseVM> 으로 제대로 전환되었는지 다시 확인한다.
  //
  //[2010.05.07.금][수정!!!]------------------------------------------------------
  //맷돌에 VMOS 계열 이외의 다른 OS 를 설치하여 다른 제어기로 사용할수 있도록
  //기능을 개선하므로, 이에 맞게 수정한다.
  //VMOS 계열 이외의 OS 가 설치된 상황에서는 Ide_Mdl_Stop() 함수등 VMOS 와 관련된
  //함수들을 사용하면 [통신오류] 가 발생하므로 [OS 종류] 를 확인하여 VMOS 계열이
  //아닌 경우는 VMOS 와만 관련된 함수들을 사용하지 않는 것으로 수정한다.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      DTU8  buildDate;
      DTU2  osSelectValue;

      //[2010.05.07.금][추가!!!]
      //OS 종류가 VMOS 계열인지 구분값을 갖는다.
      bool  isVMOS;

  //}

  //[VMOSINFO 위치 얻기]
  //{
      //[2010.12.10.금][추가!!!]
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}

  //[(1)현재 OS 상태 확인]
  //{
      //[!]{------------------------------------------------------
      //[제조날짜] 를 읽어서 현재 어떤 OS 가 구동중인지 확인한다.
      //여기는 BaseVM 인지 VMOS 등 OS 인지 구분하기 위한 것이다.
      //}---------------------------------------------------------

      if(Ide_Mdl_BuildDate(&buildDate) != true) return(false);

      //BaseVM 과 VMOS 를 구분하여 처리한다.
      if(buildDate == 0x0000000000000000)
      {
        //현재 BaseVM 이 구동 중이다.
        return(true);

      }
      else
      {
        //현재 VMOS 가 구동 중이므로 BaseVM 으로 강제 전환한다.

      }

  //}

  //[현재 VMOS 계열이 구동중인가?]
  //{
      //[2010.05.07.금][추가!!!]{-------------------
      //현재 구동중인 OS 가 VMOS 계열인지 확인한다.
      //}-------------------------------------------

      Matdol_Sys_OS_X_Is_VMOS(&isVMOS);

  //}

  //[VMOS 정지]
  //{
      //[2010.05.07.금][수정!!!]{----------------------------------------------------
      //현재 구동중인 OS 가 VMOS 계열이 아닌 경우는 이 함수를 사용하면 [통신오류] 가
      //발생하므로 이를 구분하여 처리해야 한다.
      //}----------------------------------------------------------------------------

      if(isVMOS == true)
      {
        //VMOS 인 경우는 현재 구동을 중지시켜야 한다.
        if(Ide_Mdl_Stop() != true) return(false);

      }

  //}

  //[(2) BaseVM 상태로 전환]
  //{
      //[OS 표시 영역] 에 BaseVM 사용을 기록한다.
      //각각 2Byte 크기를 갖으며, 0x0000 을 기록하면 해당 OS 를 사용하는 것이 된다.

      //[OS:BaseVM 구동]
      //{
          //[Flash 접근 허용]{---------------------------------
          //STM32F 의 <Flash> 에 접근을 허용한다.
          //이는 [OS 표시 영역] 이 Flash 에 존재하기 때문이다.
          if(Flash_Key() != true) return(false);
          //}--------------------------------------------------

          osSelectValue = 0x0000;

          //BaseVM 사용 표시 영역 위치-------------------v
          //28Byte 크기-------------------------v
          if(ComBus_Write(d_CB_TS_S, d_CB_AK_M, 1, vmosInfo->sys_OS_BaseVM, (DTU1 *)(&osSelectValue)) != true) return(false);

      //}

      //[<맷돌모듈> 재기동]
      //{
          //[맷돌모듈] 을 [재시작] 한다.
          //이후 자동으로 BaseVM 으로 전환된다.

          //[2010.05.07.금][수정!!!]{--------------------------------------
          //현재 OS 가 VMOS 계열이 아닌 경우는 VMOS 관련 부분은 내부적으로
          //처리하지 않도록 수정한다.
          //}--------------------------------------------------------------

          if(Ide_Mdl_Reset(isVMOS) != true) return(false);

          //[맷돌모듈] 이 완전히 [재기동] 하는동안 대기한다.
          Sleep(1000);

      //}

  //}

  //[(3)현재 OS 상태 다시 확인]
  //{
      //[!]{--------------------------------------------------------------------------
      //[제조날짜] 를 읽어서 현재 BaseVM 으로 제대로 전환됐는지 확인한다.
      //제대로 전환 되지 않았다면 다시 전환 시키지 않고 [오류] 로 보고 그냥 종료한다.
      //}-----------------------------------------------------------------------------

      if(Ide_Mdl_BuildDate(&buildDate) != true) return(false);

      //BaseVM 과 VMOS 를 구분하여 처리한다.
      if(buildDate == 0x0000000000000000)
      {
        //현재 BaseVM 이 구동 중이다.
        return(true);

      }
      else
      {
        //현재 VMOS 가 구동 중으로 BaseVM 으로 제대로 전환되지 않은 것이므로
        //[오류] 로 간주하고 flase 를 반환한다.
        //이 경우는 PA.0 = 0 으로 만들어 강제로 BaseVM 을 구동 시킬수도 있다.
        return(false);
        
      }

  //}

}

bool __fastcall Ide_Mdl_Vmos_Install(char  *pVmosFileName)
{
  //[2009.08.07.금][생성!!!]{---------------------------------------------------
  //실제 맷돌의 [운영체제] 인 VMOS 를 새로 설치(향상)한다.
  //직접 [대화상자] 를 보여주고, 사용자가 직접 <vmos.bin> 을 고를수 있게한다.
  //
  //[2009.08.26.수][중요수정!!!]------------------------------------------------
  //일일히 대화상자를 열어 지정하지 않도록, 미리 정의된 경로의 문서를 직접 읽어
  //처리하도록 수정한다.
  //이 함수는 [운영체제] 기본만 설치한다.
  //
  //[VMOS통합판수정중][2010.12.08.수]-------------------------------------------
  //VMOS 안에 수학 API 가 통합되었으며, 보다 다양한 API 를 지원하기 위하여
  //VMOS 를 세분화 하고 전용 [VMOS 설치 대화상자] 를 운영하므로 이에 맞게
  //직접 <vmos.gos> 의 경로를 전달받는 것으로 수정한다.
  //}---------------------------------------------------------------------------

  //[계속 진행 할지 묻기]
  //{
      if(ide_msgbox_Form->_MsgBox_Ok_Cancle
         (d_MSGBOX_info,
          "맷돌에 [운영체제] 를 설치 합니다.\r\n"
          "맷돌안의 모든 내용이 지워지고 완전히 초기화 됩니다.\r\n"
          "계속 진행하려면 [확인] 을, 중단하려면 [취소] 를 눌러주세요.") == true)
      {
        //[확인] 이 눌린 경우.

        //[OS:BaseVM 으로 전환]
        //{
            //[!]{-----------------------------------------------------------------------
            //VMOS 설치는 반드시 BaseVM 에서 처리해야 하므로, 일단 BaseVM 으로 전환한다.
            //}--------------------------------------------------------------------------

            if(Ide_Mdl_Change_OS_To_BaseVM() != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[운영체제:BaseVM] 으로 전환할수 없습니다.\r\n"
                                       "다시 시도해 주십시요.");

              return(false);

            }

        //}

        //[설치]
        //{
            //[VMOS통합판수정중][2010.12.08.수]{----------------------------------------
            //직접 전달받은 <vmos.gos> 경로를 넘겨주는 것으로 바로 설치할수 있다.
            //
            //[주의!!!]-----------------------------------------------------------------
            //VMOS 인지 VMOS:AT45DB041X 인지는 [폴더이름] 을 가지고 쉽게 구분할슈 있다.
            //"vmos_at45db041x_0_m" 처럼 '_' 문자를 [구분자] 로 쉽게 단어를 추출하여
            //구분할수 있다.
            //}-------------------------------------------------------------------------

            if(Matdol_Vmos_Install(pVmosFileName) != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[운영체제] 가 제대로 설치되지 못했습니다.\r\n"
                                       "다시 시도해 주십시요.");

              return(false);

            }
            else
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_default,
                                       "[운영체제] 가 제대로 설치되었습니다.\r\n"
                                       "맷돌을 재기동 해주시기 바랍니다.");

            }

        //}

      }

  //}

  //[재설치] 하지 않은 경우라도 이상은 없는 것이므로 true 를 반환한다.
  return(true);

}

bool __fastcall Ide_Mdl_OSX_Install(char  *pFileName)
{
  //[2010.05.07.금][생성!!!]{----------------------------------------------
  //맷돌에 일반적인 확장 OS 를 설치한다.
  //맷돌용 VMOS 계열을 제외한 확장 OS 는 전부 이 함수를 사용하여 설치한다.
  //}----------------------------------------------------------------------

  //[계속 진행 할지 묻기]
  //{
      if(ide_msgbox_Form->_MsgBox_Ok_Cancle
         (d_MSGBOX_info,
          "맷돌에 [운영체제] 를 설치 합니다.\r\n"
          "맷돌안의 모든 내용이 지워지고 완전히 초기화 됩니다.\r\n"
          "계속 진행하려면 [확인] 을, 중단하려면 [취소] 를 눌러주세요.") == true)
      {
        //[확인] 이 눌린 경우.

        //[OS:BaseVM 으로 전환]
        //{
            //[!]{-----------------------------------------------------------------------
            //VMOS 설치는 반드시 BaseVM 에서 처리해야 하므로, 일단 BaseVM 으로 전환한다.
            //}--------------------------------------------------------------------------

            if(Ide_Mdl_Change_OS_To_BaseVM() != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[운영체제:BaseVM] 으로 전환할수 없습니다.\r\n"
                                       "다시 시도해 주십시요.");

              return(false);

            }

        //}

        //[설치]
        //{
            //[!]{-----------------------------------------------
            //맷돌을 특수 제어기로 변환하는 전용 OS 를 설치한다.
            //}--------------------------------------------------

            if(Matdol_OSX_Install(pFileName) != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[운영체제] 가 제대로 설치되지 못했습니다.\r\n"
                                       "다시 시도해 주십시요.");

              return(false);

            }
            else
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_default,
                                       "[운영체제] 가 제대로 설치되었습니다.\r\n"
                                       "맷돌을 재기동 해주시기 바랍니다.");

            }

        //}

      }

  //}

  //[재설치] 하지 않은 경우라도 이상은 없는 것이므로 true 를 반환한다.
  return(true);

}

bool __fastcall Ide_Mdl_OS_Check(void)
{
  //[2010.12.13.월][생성!!!]{-------------------------------------------------
  //맷돌에 설치되 있는 [운영체제] 의 정보를 읽어서 [출력창] 에 출력해 준다.
  //더불어, 날짜를 비교하여 맷돌의 [운영체제] 가 현재 [최신판] 이 아닌 경우는
  //이를 알려주고 [최신판] 으로 설치할 것을 권고하는 알림글을 보여준다.
  //
  //모든 [운영체제] 는 [os 폴더] 에서 관리되므로 이 안의 <*.ginf> 를 읽으면
  //[운영체제] 의 종류와 자세한 정보를 쉽게 알수 있다.
  //모든 [운영체제] 는 각각의 [식별자] 를 가지고 있으므로 이것으로 구분한다.
  //
  //[2011.05.05.목][수정!!!]--------------------------------------------------
  //가장 위에 [운영체제 이름] 정보를 추가한다.
  //16진수 표기의 [식별자] 만으로는 정확한 [이름] 을 알수 없기 때문이다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      //[os폴더] 안의 [폴더] 목록을 관리한다.
      //이 [폴더] 은 [vmos], [osx] 등 [운영체제] 의 큰 분류가 된다.
      TStringList  *osFolderList = NULL;

      //<osFolderList> 에서 구한 목록안의 [폴더] 목록을 관리한다.
      //이는 [vmos] 나 [osx] 등 안의 각각의 세부 [운영체제 목록] 이 된다.
      TStringList  *osList = NULL;

      int           i, m;

      //[맷돌정보]
      //{
          DTU8  osID;
          DTU8  osDate;

      //}

      //[<*.ginf> 문서 처리용]
      //{
          char   ginfFileName[OPT_lineStrSize];
          char  *ginfFileBuf = NULL;

          char   lastFolderName[OPT_lineStrSize];

          DTU8   ginfID;
          DTU8   ginfDate;

      //}

      //설명문 정리용.
      char  descriptStr[OPT_lineStrSize*10];

      char  tempStr[OPT_lineStrSize];

  //}

  //[VMOSINFO 위치 얻기]
  //{
      //[2010.12.10.금][추가!!!]
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}

  //[맷돌의 현재 정보 얻기]
  //{
      //[!]{---------------------------------------------------------
      //맷돌에 설치된 [운영체제] 의 정보를 알기 위하여 먼저 맷돌에서
      //[식별자] 와 [날짜] 정보를 읽어들인다.
      //}------------------------------------------------------------

      //[식별자 읽기]
      //{
          //운영체제 정보를 읽어들인다.
          if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_OS_ID, (DTU1 *)(&osID)) != true) goto lbError;

      //}

      //[제작 날짜 읽기]
      //{
          if(ComBus_Read(d_CB_TS_S, d_CB_AK_B, 3, d_Map_BuildDate, (DTU1 *)(&osDate)) != true) goto lbError;

          //[BaseVM 인지 확인]
          //{
              //[중요!!!]{---------------------------------------------------------------------------
              //[날짜] 정보로 현재 <BaseVM> 이 기동중인지는 바로 알수 있으므로 여기서 먼저 처리한다.
              //}------------------------------------------------------------------------------------

              //BaseVM 의 날짜 정보는 0x0000000000000000 을 갖는다.
              if(osDate == 0x0000000000000000)
              {
                ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                         "현재 맷돌은 복구용 [BaseVM] 이 기동중입니다.\r\n"
                                         "[BaseVM] 기동 해제후 다시 확인하십시요.");

                //더이상 처리하지 않고 종료한다.
                goto lbOk;

              }

          //}

      //}

  //}

  //[운영체제 대분류 목록 얻기]
  //{
      //[!]{-------------------------------------------------
      //[os 폴더] 안의 [운영체제 대분류 폴더] 목록을 만든다.
      //현재는 [vmos], [osx] 2 개 뿐이다.
      //}----------------------------------------------------

      osFolderList = new TStringList;
      osFolderList->Clear();

      osList       = new TStringList;

      //[목록 구하기]
      //{
          //[!]{--------------------------------------------
          //전용 함수를 사용하여 안의 [폴더목록] 을 구한다.
          //}-----------------------------------------------

          Dir_Get_FileList_BoundDir(Ide_OS_Root_Path,
                                    "*",
                                    //지정 폴더안만 대상으로 한다.
                                    true,
                                    //안의 [폴더] 만 대상으로 하고 경로까지 얻는다(기본).
                                    //버튼 이름으로 사용할 것이 아니므로 [경로] 까지 다 얻어야 한다.
                                    d_Directory,// | d_NameOnly,
                                    osFolderList);

      //}

  //}

  //[운영체제 찾기]
  //{
      //[!]{-------------------------------------------------------------------------
      //위에서 구한 [목록] 을 사용하여 차례로 맷돌에서 읽어들인 [식별자] 와 일치하는
      //[운영체제] 가 있는지 확인하고, 이 운영체제의 <*.ginf> 문서 경로를 얻는다.
      //}----------------------------------------------------------------------------

      for(i = 0; i < osFolderList->Count; i++)
      {
        //[운영체제 목록 얻기]
        //{
            //[!]{--------------------------------------
            //[운영체제] 폴더안의 [운영체제 목록] 얻기.
            //}-----------------------------------------

            osList->Clear();

            //[목록 구하기]
            //{
                //[!]{--------------------------------------------
                //전용 함수를 사용하여 안의 [폴더목록] 을 구한다.
                //}-----------------------------------------------

                //[운영체제 대분류] 를 기준으로 하나씩 처리한다.
                Dir_Get_FileList_BoundDir(osFolderList->Strings[i] + "\\",
                                          "*",
                                          //지정 폴더안만 대상으로 한다.
                                          true,
                                          //안의 [폴더] 만 대상으로 하고 경로까지 얻는다(기본).
                                          //버튼 이름으로 사용할 것이 아니므로 [경로] 까지 다 얻어야 한다.
                                          d_Directory,// | d_NameOnly,
                                          osList);

            //}

        //}

        for(m = 0; m < osList->Count; m++)
        {
          //[!]{--------------------------------------------------------------------------
          //지정된 [운영체제] 가 맷돌에 설치된 것과 같은지 [식별자] 를 비교하여 알아낸다.
          //}-----------------------------------------------------------------------------

          //[최종폴더이름 얻기]
          //{
              //[!]{----------------------------------------------------------------
              //[폴더이름] 과 "폴더이름.ginf" 로 같은 이름을 사용하도록 돼 있으므로
              //최종 [폴더이름] 을 구한다.
              //}-------------------------------------------------------------------

			  STR_Get_FileFullName_LastFolderName(((AnsiString)((osList->Strings[m] + "\\"))).c_str(), lastFolderName);

          //}

          //[<*.ginf> 문서이름 만들기]
          //{
              //[!]{-------------------------------------------------
              //"[문서이름] = [폴더경로] + [폴더이름.ginf]" 가 된다.
              //}----------------------------------------------------

              STR_Assign(ginfFileName, ((AnsiString)(osList->Strings[m])).c_str()); STR_Add(ginfFileName, "\\");
              STR_Add(ginfFileName, lastFolderName); STR_Add(ginfFileName, ".ginf");

          //}

          //[<*.ginf> 문서 열기]
          //{
              if(Ginf_Open(ginfFileName, (unsigned char **)(&ginfFileBuf), NULL) != true) goto lbError;

          //}

          //[<식별자> 읽기]
          //{
              ginfID = Ginf_Get_Id(ginfFileBuf);

          //}

          //[맷돌의 <식별자> 와 일치하나?]
          //{
              //일치하는 경우는 다음 처리로 이동한다.
              if(osID == ginfID) goto lbPostProc;

          //}

          //[동적 삭제]
          //{
              //[!]{----------------------------------------------------------
              //현재 연 <*.ginf> 는 해당없으므로 생성된 [저장소] 를 삭제한다.
              //}-------------------------------------------------------------

              if(ginfFileBuf != NULL) { delete [] ginfFileBuf; ginfFileBuf = NULL; }

          //}

        }

      }

      //[찾는 것이 없다!!!]
      //{
          //[!]{----------------------------------------------
          //여기까지 온 것은 일치하는 [운영체제] 없는 경우다.
          //관련 알림문을 보여주고 종료한다.
          //단, 오류는 아니다.
          //}-------------------------------------------------

          ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                   "현재 맷돌의 [운영체제] 를 식별할수 없습니다.\r\n"
                                   "맷돌에 [운영체제] 를 설치 후 다시 확인하십시요.");

          goto lbOk;

      //}

  //}

  lbPostProc:
  {
    //[!]{---------------------------------------------------------------------
    //맷돌의 [운영체제] 와 일치하는 것을 찾은 경우를 처리한다.
    //1) 일단 해당 [운영체제] 의 정보를 정리하여 보여준다.
    //2) 맷돌의 [운영체제] 가 [최신판] 이 아닌경우는 [최신판] 으로 설치할 것을
    //   권고하는 알림글을 보여준다.
    //
    //아직 <ginfFileBuf[]> 안의 내용은 그대로 존재한다.
    //}------------------------------------------------------------------------

    //[설명문 만들기]
    //{
        //문자열 초기화.
        STR_Assign(descriptStr, "");

        //[<운영체체 이름> 정보 추가]
        //{
            //[2011.05.05.목][추가!!!]{------------------------
            //[운영체제 이름] 정보를 가장 위에 추가한다.
            //이는 [식별자] 로는 [이름] 을 알수 없기 때문이다.
            //}------------------------------------------------

            STR_Add(descriptStr, "[이   름] : ");

            //<*.ginf> 문서가 들어있는 [폴더이름] 이 [운영체제 이름] 이 된다.
            STR_Add(descriptStr, lastFolderName);

            STR_Add(descriptStr, "\r\n");

        //}

        //[<식별자> 정보 추가]
        //{
            STR_Add(descriptStr, "[고유번호] : ");

            //CONV_LongVal_To_Hex(ginfID, 16, &(descriptStr[STR_Length(descriptStr)]));
            //[2010.12.15.수][수정!!!]
            //"H4:L4" 형식 표기로 변환하는 새로운 함수를 사용한다.
            Conv_0xId_To_IdStr(ginfID, &(descriptStr[STR_Length(descriptStr)]));

            STR_Add(descriptStr, "\r\n");

        //}

        //[<날짜> 정보 추가]
        //{
            //[!]{-----------------------------------------------
            //날짜는 [최신판]/[맷돌 현재판] 을 같이 나열해 준다.
            //}--------------------------------------------------

            //[<*.ginf> 에서 날짜 정보 추출]
            //{
                //[!]{-------------------------------------------------------------------------
                //맷돌의 날짜는 이미 위에서 읽었으므로 <*.ginf> 안의 <날짜> 정보를 읽어들인다.
                //}----------------------------------------------------------------------------

                ginfDate = Ginf_Get_Date(ginfFileBuf);

            //}

            STR_Add(descriptStr, "[제작날짜] : 최신판(");
            //날짜를 "년.월.일-시:분" 의 문자열 형식으로 변환한다.
            Conv_0xDate_To_DateStr(ginfDate, NULL, &(descriptStr[STR_Length(descriptStr)]));
            STR_Add(descriptStr, "):맷돌(");
            //날짜를 "년.월.일-시:분" 의 문자열 형식으로 변환한다.
            Conv_0xDate_To_DateStr(osDate, NULL, &(descriptStr[STR_Length(descriptStr)]));
            STR_Add(descriptStr, ")\r\n\r\n");

        //}

        //[<설명문> 정보 추가]
        //{
            //<*.ginf> 안의 <설명문> 은 문자열이므로 그대로 추가한다.
            Ginf_Get_DescriptStr(ginfFileBuf, &(descriptStr[STR_Length(descriptStr)]));
            //STR_Add(descriptStr, "\r\n");

        //}

    //}

    //[판올림 확인]
    //{
        //[!]{----------------------------------------------------------------------
        //[운영체제] 날짜를 비교하여 맷돌안에 설치돼 있는 것의 날짜가 이전 것이라면
        //[최신판] 으로 설치할 것을 알려준다.
        //
        //단순하게 직접 8 Byte 날짜 값을 그대로 값을 비교하면 쉽게 알수 있다.
        //}-------------------------------------------------------------------------

        if(osDate < ginfDate)
        {
          //[!]{--------------------------------------------------
          //이 경우는 맷돌의 운영체제가 최신판보다 오래된 것이다.
          //}-----------------------------------------------------

          STR_Add(descriptStr,
                  "\r\n\r\n"
                  "<경고!!!>\r\n"
                  "맷돌의 운영체제가 구형입니다.\r\n"
                  "최신판으로 설치하기 바랍니다.");

        }

    //}

    //[설명문 출력]
    //{
        //[!]{------------------------------------
        //출력창에 출력하거나, 알림글로 보여준다.
        //}---------------------------------------

        ide_msgbox_Form->_MsgBox(d_MSGBOX_default, descriptStr);  

    //}

  }

  lbOk:
  {

    //[동적 삭제]
    //{
        //혹시 동적 생성이 돼 있는 경우는 삭제한다.
        if(osFolderList != NULL) { delete    osFolderList; osFolderList = NULL; }
        if(osList       != NULL) { delete    osList;       osList       = NULL; }
        if(ginfFileBuf  != NULL) { delete [] ginfFileBuf;  ginfFileBuf  = NULL; }

    //}

    return(true);

  }

  lbError:
  {
    //[동적 삭제]
    //{
        //혹시 동적 생성이 돼 있는 경우는 삭제한다.
        if(osFolderList != NULL) { delete    osFolderList; osFolderList = NULL; }
        if(osList       != NULL) { delete    osList;       osList       = NULL; }
        if(ginfFileBuf  != NULL) { delete [] ginfFileBuf;  ginfFileBuf  = NULL; }

    //}

    return(false);

  }

}

bool __fastcall Ide_Mtdl_Get_OS_Name(char  *rOS_Name)
{
  //[2011.11.17.목][생성!!!]{---------------------------------------------------------------
  //현재 맷돌에 설치돼 있는 [운영체에 이름] 을 구해서 반환.
  //
  //VMOS 와 OSX 구분은 반환되는 <rOS_Name> 를 참고하여 사용하는 쪽에서 직접 처리.
  //GVMX 설치 도중에 자동으로 [맷돌(VMOS] 이 아닌 경우는 자동으로 걸러지기 때문에
  //여기서 처리할 필요는 없다.
  //단지, 현재 설치돼 있는 [운영체제 이름] 을 알고자 하는 것이 목적.
  //
  //[주의!!!]-------------------------------------------------------------------------------
  //<rOS_Name> 의 반환 자료가 "" 인 경우는 찾은 것이 없는 경우이나, 이 경우는 [알림창] 으로
  // 내용이 표시되므로 여기서 별도 처리할 필요는 없다.
  //이 함수를 호출한 곳에서 참고하고 오류로 간주하면 된다.
  //단, 이 함수 내부적으로는 [오류] 가 아니다.
  //
  //[참고!!!]-------------------------------------------------------------------------------
  //<Ide_ListSubMenu_GVMX_Install()> 함수안에서 <GVMX> 설치시, 현재 맷돌의 [운영체제 이름]
  //을 [출력창] 에 표시할때 사용된다.
  //
  //<Ide_Mdl_OS_Check()> 함수를 가지고 만든 것으로 오직 [운영체제 이름] 만 추출한다.
  //}---------------------------------------------------------------------------------------

  //[VAR]
  //{
      //[os폴더] 안의 [폴더] 목록을 관리한다.
      //이 [폴더] 은 [vmos], [osx] 등 [운영체제] 의 큰 분류가 된다.
      TStringList  *osFolderList = NULL;

      //<osFolderList> 에서 구한 목록안의 [폴더] 목록을 관리한다.
      //이는 [vmos] 나 [osx] 등 안의 각각의 세부 [운영체제 목록] 이 된다.
      TStringList  *osList = NULL;

      int           i, m;

      //[맷돌정보]
      //{
          DTU8  osID;
          DTU8  osDate;

      //}

      //[<*.ginf> 문서 처리용]
      //{
          char   ginfFileName[OPT_lineStrSize];
          char  *ginfFileBuf = NULL;

          char   lastFolderName[OPT_lineStrSize];

          DTU8   ginfID;

      //}

  //}

  //[VMOSINFO 위치 얻기]
  //{
      //[2010.12.10.금][추가!!!]
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}
  
  //[초기화]
  //{
      //기본적으로 "" 로 초기화.
      STR_Assign(rOS_Name, "");
  
  //}

  //[맷돌의 현재 정보 얻기]
  //{
      //[!]{---------------------------------------------------------
      //맷돌에 설치된 [운영체제] 의 정보를 알기 위하여 먼저 맷돌에서
      //[식별자] 와 [날짜] 정보를 읽어들인다.
      //}------------------------------------------------------------

      //[식별자 읽기]
      //{
          //운영체제 정보를 읽어들인다.
          if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_OS_ID, (DTU1 *)(&osID)) != true) goto lbError;

      //}

      //[제작 날짜 읽기]
      //{
          if(ComBus_Read(d_CB_TS_S, d_CB_AK_B, 3, d_Map_BuildDate, (DTU1 *)(&osDate)) != true) goto lbError;

          //[BaseVM 인지 확인]
          //{
              //[중요!!!]{---------------------------------------------------------------------------
              //[날짜] 정보로 현재 <BaseVM> 이 기동중인지는 바로 알수 있으므로 여기서 먼저 처리한다.
              //}------------------------------------------------------------------------------------

              //BaseVM 의 날짜 정보는 0x0000000000000000 을 갖는다.
              if(osDate == 0x0000000000000000)
              {
                ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                         "현재 맷돌은 복구용 [BaseVM] 이 기동중입니다.\r\n"
                                         "[BaseVM] 기동 해제후 다시 확인하십시요.");

                //더이상 처리하지 않고 종료한다.
                goto lbOk;

              }

          //}

      //}

  //}

  //[운영체제 대분류 목록 얻기]
  //{
      //[!]{-------------------------------------------------
      //[os 폴더] 안의 [운영체제 대분류 폴더] 목록을 만든다.
      //현재는 [vmos], [osx] 2 개 뿐이다.
      //}----------------------------------------------------

      osFolderList = new TStringList;
      osFolderList->Clear();

      osList       = new TStringList;

      //[목록 구하기]
      //{
          //[!]{--------------------------------------------
          //전용 함수를 사용하여 안의 [폴더목록] 을 구한다.
          //}-----------------------------------------------

          Dir_Get_FileList_BoundDir(Ide_OS_Root_Path,
                                    "*",
                                    //지정 폴더안만 대상으로 한다.
                                    true,
                                    //안의 [폴더] 만 대상으로 하고 경로까지 얻는다(기본).
                                    //버튼 이름으로 사용할 것이 아니므로 [경로] 까지 다 얻어야 한다.
                                    d_Directory,// | d_NameOnly,
                                    osFolderList);

      //}

  //}

  //[운영체제 찾기]
  //{
      //[!]{-------------------------------------------------------------------------
      //위에서 구한 [목록] 을 사용하여 차례로 맷돌에서 읽어들인 [식별자] 와 일치하는
      //[운영체제] 가 있는지 확인하고, 이 운영체제의 <*.ginf> 문서 경로를 얻는다.
      //}----------------------------------------------------------------------------

      for(i = 0; i < osFolderList->Count; i++)
      {
        //[운영체제 목록 얻기]
        //{
            //[!]{--------------------------------------
            //[운영체제] 폴더안의 [운영체제 목록] 얻기.
            //}-----------------------------------------

            osList->Clear();

            //[목록 구하기]
            //{
                //[!]{--------------------------------------------
                //전용 함수를 사용하여 안의 [폴더목록] 을 구한다.
                //}-----------------------------------------------

                //[운영체제 대분류] 를 기준으로 하나씩 처리한다.
                Dir_Get_FileList_BoundDir(osFolderList->Strings[i] + "\\",
                                          "*",
                                          //지정 폴더안만 대상으로 한다.
                                          true,
                                          //안의 [폴더] 만 대상으로 하고 경로까지 얻는다(기본).
                                          //버튼 이름으로 사용할 것이 아니므로 [경로] 까지 다 얻어야 한다.
                                          d_Directory,// | d_NameOnly,
                                          osList);

            //}

        //}

        for(m = 0; m < osList->Count; m++)
        {
          //[!]{--------------------------------------------------------------------------
          //지정된 [운영체제] 가 맷돌에 설치된 것과 같은지 [식별자] 를 비교하여 알아낸다.
          //}-----------------------------------------------------------------------------

          //[최종폴더이름 얻기]
          //{
              //[!]{----------------------------------------------------------------
              //[폴더이름] 과 "폴더이름.ginf" 로 같은 이름을 사용하도록 돼 있으므로
              //최종 [폴더이름] 을 구한다.
              //}-------------------------------------------------------------------

			  STR_Get_FileFullName_LastFolderName(((AnsiString)(osList->Strings[m] + "\\")).c_str(), lastFolderName);

          //}

          //[<*.ginf> 문서이름 만들기]
          //{
              //[!]{-------------------------------------------------
              //"[문서이름] = [폴더경로] + [폴더이름.ginf]" 가 된다.
              //}----------------------------------------------------

              STR_Assign(ginfFileName, ((AnsiString)(osList->Strings[m])).c_str()); STR_Add(ginfFileName, "\\");
              STR_Add(ginfFileName, lastFolderName); STR_Add(ginfFileName, ".ginf");

          //}

          //[<*.ginf> 문서 열기]
          //{
              if(Ginf_Open(ginfFileName, (unsigned char **)(&ginfFileBuf), NULL) != true) goto lbError;

          //}

          //[<식별자> 읽기]
          //{
              ginfID = Ginf_Get_Id(ginfFileBuf);

          //}

          //[맷돌의 <식별자> 와 일치하나?]
          //{
              //일치하는 경우는 다음 처리로 이동한다.
              if(osID == ginfID) goto lbPostProc;

          //}

          //[동적 삭제]
          //{
              //[!]{----------------------------------------------------------
              //현재 연 <*.ginf> 는 해당없으므로 생성된 [저장소] 를 삭제한다.
              //}-------------------------------------------------------------

              if(ginfFileBuf != NULL) { delete [] ginfFileBuf; ginfFileBuf = NULL; }

          //}

        }

      }

      //[찾는 것이 없다!!!]
      //{
          //[!]{----------------------------------------------
          //여기까지 온 것은 일치하는 [운영체제] 없는 경우다.
          //관련 알림문을 보여주고 종료한다.
          //단, 오류는 아니다.
          //}-------------------------------------------------

          ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                   "현재 맷돌의 [운영체제] 를 식별할수 없습니다.\r\n"
                                   "맷돌에 [운영체제] 를 설치 후 다시 확인하십시요.");

          goto lbOk;

      //}

  //}

  lbPostProc:
  {
    //[!]{---------------------------------------------------------------------
    //맷돌의 [운영체제] 와 일치하는 것을 찾은 경우를 처리한다.
    //아직 <ginfFileBuf[]> 안의 내용은 그대로 존재한다.
    //
    //단지, [운영체제 이름] 만 알려주면 된다.
    //}------------------------------------------------------------------------
    
    //[이름얻기]
    //{
        //<*.ginf> 문서가 들어있는 [폴더이름] 이 [운영체제 이름] 이 된다.
        STR_Assign(rOS_Name, lastFolderName);
        
    //}

  }

  lbOk:
  {
    //[동적 삭제]
    //{
        //혹시 동적 생성이 돼 있는 경우는 삭제한다.
        if(osFolderList != NULL) { delete    osFolderList; osFolderList = NULL; }
        if(osList       != NULL) { delete    osList;       osList       = NULL; }
        if(ginfFileBuf  != NULL) { delete [] ginfFileBuf;  ginfFileBuf  = NULL; }

    //}

    return(true);

  }

  lbError:
  {
    //[동적 삭제]
    //{
        //혹시 동적 생성이 돼 있는 경우는 삭제한다.
        if(osFolderList != NULL) { delete    osFolderList; osFolderList = NULL; }
        if(osList       != NULL) { delete    osList;       osList       = NULL; }
        if(ginfFileBuf  != NULL) { delete [] ginfFileBuf;  ginfFileBuf  = NULL; }

    //}

    return(false);

  }

}

//------------------------------------------------------------------------------
//[동작 제어 관련]--------------------------------------------------------------
//------------------------------------------------------------------------------

//[2009.04.04.토][추가!!!]{----------------------------------------------------------------
//실제적인 동작 제어를 수행하는 함수들이다.
//[가상구동] 의 경우와 [맷돌구동] 의 경우 두가지가 존재하므로 이를 함수내부적으로 구분하여
//자동적으로 해당 기능의 함수를 호출하여 처리한다.
//}----------------------------------------------------------------------------------------

bool __fastcall Ide_Ctrl_Exsist(void)
{
  //[2009.04.04.토][생성!!!]{-------------
  //대상이 [존재] 하는지 여부를 확인한다.
  //}-------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상구동] 을 위한 [쓰레드] 의 존재를 확인한다.

    if(Ide_VMOS_Exsit() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌모듈] 이 실제 연결돼 있는지 확인한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Exsist() != true) return(false);

  }

  //[알림글]{------------------------------------------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "\r\n[맷돌] 을 [재기동] 시키면 설치한 [가상기계] 가 실행됩니다.");
  //}--------------------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Download(void)
{
  //[2009.04.04.토][생성!!!]{------
  //<*.gvmx> 실행 기계를 설치한다.
  //}------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 안의 설치 공간에 <*.gvmx> 를 설치한다.

    //[가상기계 전용 환경 구분 처리]
    //{
        //[2010.07.07.수][수정!!!]
        if(_ide_Option.gvmMode == true)
        {
          if(Ide_VMOS_Download_Gvms(_ide_Option.gvmName) != true) return(false);

        }
        else
        {
          if(Ide_VMOS_Download() != true) return(false);

        }

    //}

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 의 설치 공간에 <*.gvmx> 를 설치한다.

    //[가상기계 전용 환경 구분 처리]
    //{
        //[2010.07.07.수][수정!!!]
        if(_ide_Option.gvmMode == true)
        {
          if(Ide_Mdl_Download_Gvmx(_ide_Option.gvmName, NULL) != true) return(false);

        }
        else
        {
          //[2009.07.14.화][추가!!!]
          if(Ide_Mdl_Download() != true) return(false);

        }

    //}

  }

  //[알림글]{-------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "가상기계 [설치] 완료.");
  //}---------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Upload(void)
{
  //[2009.04.04.토][생성!!!]{-----------
  //[설치] 되 있는 가상기계를 수거한다.
  //}-----------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 안의 설치 공간에서 현재 설치된 <*.gvmx> 를 읽어들여 해당 저장소에 보관한다.

    if(Ide_VMOS_Upload() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 안의 설치 공간엣서 현재 설치된 <*.gvmx> 를 읽어들여 해당 저장소에 보관한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Upload() != true) return(false);

  }

  //[알림글]{-----------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "가상기계 [복제] => [수거] 완료.");
  //}-------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Verify(void)
{
  //[2009.04.04.토][생성!!!]{-----------------------------------------
  //설치된 <*.gvmx> 가 제대로 설치되 있는지 원본과 비교하여 확인한다.
  //}-----------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 안의 설치 공간에 설치되 있는 <*.gvmx> 를 원본과 비교한다.

    if(Ide_VMOS_Verify() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 안의 설치 공간에 설치되 있는 <*.gvmx> 를 원본과 비교한다.

    //[가상기계 전용 환경 구분 처리]
    //{
        //[2010.07.07.수][수정!!!]
        if(_ide_Option.gvmMode == true)
        {
          if(Ide_Mdl_Verify_Gvmx(_ide_Option.gvmName, NULL) != true) return(false);

        }
        else
        {
          //[2009l.07.14.화][추가!!!]
          if(Ide_Mdl_Verify() != true) return(false);

        }

    //}

  }

  //[알림글]{------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "가상기계 [설치 검사] 완료.");
  //}--------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Erase(void)
{
  //[2009.04.04.토][생성!!!]{--------------
  //설치 공간 전부를 삭제하고 초기화 한다.
  //}--------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 안의 설치공간의 내용을 완전히 삭제하고 초기화 한다.

    if(Ide_VMOS_Erase() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 안의 설치공간의 내용을 완전히 삭제하고 초기화 한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Erase() != true) return(false);

  }

  //[2010.07.07.수][추가!!!]{------------------------------------------
  //[가상기계 전용 구동 환경] 인 경우는 문자열이 출력되지 않도록 한다.
  if(_ide_Option.gvmMode == true) return(true);
  //}------------------------------------------------------------------

  //[알림글]{---------------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "가상기계 설치장소 완전 초기화 완료.");
  //}-----------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Start(void)
{
  //[2009.04.04.토][생성!!!]{---------------------------
  //[일시정지] 되 있는 상태를 [실행] 상태로 만들어준다.
  //}---------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [실행 명령] 을 전달한다.

    if(Ide_VMOS_Start() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [실행 명령] 을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Start() != true) return(false);

  }

  //[알림글]{-------------------------------------------------------------
  //msg_msg_Form->_PrintAddLine(d_msg_msg,
  //                            "[맷돌] 기동 시작.");
  //[2009.05.14.목][수정!!!]----------------------------------------------
  //<msg_msg_Form> 의 문자열 출력시 먼저 해당 영역을 보여주에 되므로
  //여기서 문자열을 출력하면 [검증문자열] 출력때문에 계속 영역이 전환되어
  //깜박임이 발생할수 있다. 따라서 여기는 문자열을 출력하지 않는다.
  //}---------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Stop(void)
{
  //[2009.04.04.토][생성!!!]{--------------------
  //[가상 VMOS] 나 [맷돌] 을 [일시 정지] 시킨다.
  //}--------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [일지 정지 명령] 을 전달한다.

    if(Ide_VMOS_Stop() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [일지 정지 명령] 을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Stop() != true) return(false);

  }

  //[알림글]{-------------------------------------------------------------
  //msg_msg_Form->_PrintAddLine(d_msg_msg,
  //                            "[맷돌] 기동 중지.");
  //[2009.05.14.목][수정!!!]----------------------------------------------
  //<msg_msg_Form> 의 문자열 출력시 먼저 해당 영역을 보여주에 되므로
  //여기서 문자열을 출력하면 [검증문자열] 출력때문에 계속 영역이 전환되어
  //깜박임이 발생할수 있다. 따라서 여기는 문자열을 출력하지 않는다.
  //}---------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Reset(void)
{
  //[2009.04.04.토][생성!!!]{-------------------------------------
  //[가상 VMOS] 나 [맷돌] 을 완전히 초기화 하고 다시 실행 시킨다.
  //}-------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [초기화] 명령을 전달한다.

    if(Ide_VMOS_Reset() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [초기화] 명령을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_Reset( true) != true) return(false);

  }

  //[알림글]{-------------------------------------------------------------
  //msg_msg_Form->_PrintAddLine(d_msg_msg,
  //                            "[맷돌] 초기화 재기동.");
  //[2009.05.14.목][수정!!!]----------------------------------------------
  //<msg_msg_Form> 의 문자열 출력시 먼저 해당 영역을 보여주에 되므로
  //여기서 문자열을 출력하면 [검증문자열] 출력때문에 계속 영역이 전환되어
  //깜박임이 발생할수 있다. 따라서 여기는 문자열을 출력하지 않는다.
  //}---------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_DebugReset(void)
{
  //[2009.04.06.월][생성!!!]{-------------------------------------
  //완전한 [재기동] 이 아닌 검증을 위한 [검증재기동] 을 실시한다.
  //}-------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [검증재기동] 명령을 전달한다.

    if(Ide_VMOS_DebugReset() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [검증재기동] 명령을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_DebugReset() != true) return(false);

  }

  //[알림글]{-------------------------------------------------------------
  //msg_msg_Form->_PrintAddLine(d_msg_msg,
  //                            "[맷돌] 검증을 위한 재기동.");
  //[2009.05.14.목][수정!!!]----------------------------------------------
  //<msg_msg_Form> 의 문자열 출력시 먼저 해당 영역을 보여주에 되므로
  //여기서 문자열을 출력하면 [검증문자열] 출력때문에 계속 영역이 전환되어
  //깜박임이 발생할수 있다. 따라서 여기는 문자열을 출력하지 않는다.
  //}---------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_ResetStop(void)
{
  //[2010.07.07.수][생성!!!]{---------------------------------------------
  //VMOS 를 재기동후 정지시킨다.
  //이는 [가상기계] 를 설치후 VMOS 에 올린뒤 정지시켜 [재기동] 없이
  //바로 [실행] 할수 있는 상태로 만들기 위하여 반드시 핊요하다.
  //
  //[주의!!!]-------------------------------------------------------------
  //단, 이 함수는 [검증] 시에는 사용하지 않는다.
  //[검증] 시에는 <DebugReset> 으로 비슷한 내용이 자동 적용되기 때문이다.
  //}---------------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [검증재기동] 명령을 전달한다.

    if(Ide_VMOS_ResetStop() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [검증재기동] 명령을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_ResetStop() != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Auto(void)
{
  //[2009.04.04.토][생성!!!]{----------------------------------------
  //[가상기계 제작] -> [설치] -> [검사] 까지 완전 자동으로 처리한다.
  //}----------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상기계제작]{-----------------------------------------------------------------------------
    //오류가 있는 경우는 다음을 실행하지 않고 종료해야 한다.
    if(IDE_Build(d_Build_Parser|d_Build_Object|d_Build_Link|d_Build_Gvmx) != true) return(false);
    //[기동정지]----------------------------------------------------------------------------------
    //[2009.04.05.일][추가!!!]
    //[맷돌] 을 미리 여기서 [정지] 시켜야 한다.
    if(Ide_Ctrl_Stop() != true) return(false);
    //[지우기]------------------------------------------------------------------------------------
    //설치전 먼저 설치공간을 전부 지운다.
    if(Ide_Ctrl_Erase() != true) return(false);
    //[설치]--------------------------------------------------------------------------------------
    if(Ide_Ctrl_Download() != true) return(false);
    //[확인]--------------------------------------------------------------------------------------
    if(Ide_Ctrl_Verify() != true) return(false);
    //}-------------------------------------------------------------------------------------------

    //[맷돌] 은 현재 [정지] 대기 상태로 [재기동] 명령을 보내면 현재 [설치] 한 [가상기계] 를 구동하게 된다.

    //[2010.07.07.수][추가!!!]{----------------------------------------------------------
    //[재기동] 하지 않고 설치된 [가상기계] 를 [실행] 상태로 만들고 [VMOS] 를 정지시킨다.
    if(Ide_Ctrl_ResetStop() != true) return(false);
    //}----------------------------------------------------------------------------------

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 의 설치 공간에 <*.gvmx> 를 설치한다.

    //[2009.07.14.화][추가!!!]{------------------------------------------------
    //실제 [맷돌모듈] 의 구동도 [가상구동] 과 완전히 동일하게 처리 가능하다.
    //처리 함수 내부적으로 [맷돌모듈] 의 경우는 자동으로 해당 함수로 처리된다.
    //}------------------------------------------------------------------------

    //[가상기계제작]{-----------------------------------------------------------------------------
    //오류가 있는 경우는 다음을 실행하지 않고 종료해야 한다.
    if(IDE_Build(d_Build_Parser|d_Build_Object|d_Build_Link|d_Build_Gvmx) != true) return(false);
    //[기동정지]----------------------------------------------------------------------------------
    //[맷돌] 을 미리 여기서 [정지] 시켜야 한다.
    if(Ide_Ctrl_Stop() != true) return(false);
    //[지우기]------------------------------------------------------------------------------------
    //설치전 먼저 설치공간을 전부 지운다.
    if(Ide_Ctrl_Erase() != true) return(false);
    //[설치]--------------------------------------------------------------------------------------
    if(Ide_Ctrl_Download() != true) return(false);
    //[확인]--------------------------------------------------------------------------------------
    if(Ide_Ctrl_Verify() != true) return(false);
    //}-------------------------------------------------------------------------------------------

    //[2010.07.07.수][추가!!!]{----------------------------------------------------------
    //[재기동] 하지 않고 설치된 [가상기계] 를 [실행] 상태로 만들고 [VMOS] 를 정지시킨다.
    if(Ide_Ctrl_ResetStop() != true) return(false);
    //}----------------------------------------------------------------------------------

  }
  else
  {
    //[2009.11.20.금][추가!!!]{---------------------------------------
    //위의 두 경우에 해당하지 않는다면 처리하지 않는다.
    //이 경우는 아직 해당 기능이 완전히 활성화 되 있지 않는 경우이다.
    //}---------------------------------------------------------------

    return(false);

  }

  //[알림글]{--------------------------------------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "[맷돌] 을 [재기동] 시키면 설치한 [가상기계] 가 실행됩니다.");
  //}----------------------------------------------------------------------------------------

  return(true);

}

bool __fastcall Ide_Ctrl_Auto_Debug(//[2009.12.28.월][수정!!!]{------------------------------------------
                                    //[개발검증] 시 계속 다시 설치할지를 결정한다.
                                    //이는 변경내용이 없는 경우는 굳이 다시 설치할 필요가 없기 때문이다.
                                    //true  : 다시 설치하지 않고 바로 전환한다.
                                    bool  pNoDownload
                                    //}------------------------------------------------------------------
                                    )
{
  //[2009.04.04.토][생성!!!]{----------------------------------------------
  //[개발검증] 탭으로 전환시 이 함수로 모든 과정을 자동 처리한다.
  //[검증] 을 위한 기본 [검증정보 수집/정리] 도 같이 수행해 주어야 한다.
  //
  //[2009.04.07.화][추가!!!]-----------------------------------------------
  //[점증] 시에는 항상 [검증 구동기] 를 구동시켜야 한다.
  //이는 [정지점] 등으로 정지한 경우등 [맷돌] 이 보내는 [요청] 을 검지하고
  //[동작함수] 형식으로 처리하기 위한 [쓰레드] 다.
  //
  //[2012.04.29.일][설명!!!]-------------------------------------------------
  //<Debug_LineList_Create()> 함수가 <debug.cpp> 문서의 [전역변수] 들에
  //[검증정보] 를 생성한 상태로 [검증] 단계로 넘어가지 못하고 오류로
  //종료하는 경우는 원래 생성된 [검증정보] 를 여기서 [삭제] 해야 하지만
  //<Ide_Ctrl_Auto_Debug()> 함수가 <ide_buttons:_EVENT_TabSelect()> 에서
  //한번만 사용되므로 이 사용부에서 <Debug_Info_DeleteAll()> 함수로 처리한다.
  //
  //[전역변수] 로 돼 있는 [검증정보] 는 사실상 [검증시] 재생성 되는 것으로
  //반드시 [삭제] 할 필요는 없지만 규칙적으로 처리하는 것으로 한다.
  //
  //이는 [메모리] 사용량을 줄이고 사용한 것은 반드시 [해제] 하기 위한것.
  //}----------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *database;

      char   fileName[OPT_filepath_length];
      char   tempStr[OPT_filepath_length];

  //}

  //[Database 의 주소를 얻기]{---
  DATABASE_GetPtr(&database);
  //}----------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[수정된 것이 있나?]
    //{
        //[2009.12.28.월][추가!!!]{-------------------------------------------
        //[켄타우로스] 정도는 처리 분양이 많으므로 해석에 시간이 많이 걸린다.
        //따라서, 수정된 것이 있는 경우만 처리하도록 수정한다.
        //}-------------------------------------------------------------------

        if((editor_edit_Form->_TEXTINFO_IsChangedOne() == true) ||
           //[설계묶음] 을 처음 연 경우는 수정된 것은 없으나 아직 빌드하지 않은 상태라
           //{DATABASE} 가 비어 있어 검증정보가 하나도 없다.
           //따라서, 이 경우는 무조건 다시 빌드해야 한다(전용함수를 사용한다).
           (Ide_IsBuilded() == false) ||
           //[새설계묶음] 인 경우는 무조건 다시 빌드하도록 해야 한다.
           //이는 작업중인 설계묶음을 닫은 경우도 정보는 남아 있게 되므로 반드시 이를 검사해야 한다.
           //[2012.04.20.금][수정!!!]
           (STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true))
        {
          //[가상기계제작]{-----------------------------------------------------------------------------
          //오류가 있는 경우는 다음을 실행하지 않고 종료해야 한다.
          if(IDE_Build(d_Build_Parser|d_Build_Object|d_Build_Link|d_Build_Gvmx) != true) return(false);
          //}-------------------------------------------------------------------------------------------

        }

    //}

    //[기동정지]-----------------------------------
    //[2009.04.05.일][추가!!!]
    //[맷돌] 을 미리 여기서 정지 시켜야 한다.
    if(Ide_Ctrl_Stop() != true) return(false);
    //[지우기]-------------------------------------
    //설치전 먼저 설치공간을 전부 지운다.
    if(Ide_Ctrl_Erase() != true) return(false);
    //[설치]---------------------------------------
    if(Ide_Ctrl_Download() != true) return(false);
    //[확인]---------------------------------------
    if(Ide_Ctrl_Verify() != true) return(false);
    //}--------------------------------------------

    //[검증정보 수집/정리]
    //{
        //[2009.04.05.일][추가!!!]

        //<*.$lst> 문서이름을 만든다.
        //[2012.04.20.금][수정!!!]
        STR_Add_AB(tempStr, database->buildpath, tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0));

        //확장자를 바꾼다.
        STR_ChangeFileExt(tempStr, "$lst", fileName);

        //문서를 전달하여 정보를 [수집/정리] 한다.
        Debug_LineList_Create(fileName);

    //}

    //[검증 구동기 구동][2009.04.07.화][추가!!!]--------------------------------------------------
    Ide_VDEBUG_Run();
    //}-------------------------------------------------------------------------------------------

    //[검증 재기동]
    //{
        //[2009.04.05.일][추가!!!]{-----------------------------------------------------------------
        //전체를 [재기동] 하는 것이 아니라 [검증] 을 위한 [검증재기동] 을 실행한다.
        //설치된 [가상기계] 를 다시 [생성] 하고 실행하지만 [검증] 관련 기능은 초기화 되지 않으므로
        //[맷돌] 은 계속 [중지] 상태가 되어, 처음 실행하는 [명령위치] 에서 @PC 가 멈추어 있게 된다.
        //즉, main() 함수의 처음 [명령위치] 에서 일단 정지한 상태로 대기하게 된다.
        //
        //[검증재기동] 을 하는 이유는 일단 [설치] 된 [가상기계] 가 [생성] 이 되어야 @CODE 등 여러
        //[세그먼트] 가 설정이 되므로 [절대번지] 를 계산 가능하기 때문이다.
        //}-----------------------------------------------------------------------------------------

        if(Ide_Ctrl_DebugReset() != true) return(false);

    //}

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 의 설치 공간에 <*.gvmx> 를 설치한다.

    //[2009.07.14.화][추가!!!]{-------------
    //실제 [맷돌모듈] 을 대상으로 처리한다.
    //[가상구동] 과 차이가 없다.
    //}-------------------------------------

    //[수정된 것이 있나?]
    //{
        //[2009.12.28.월][추가!!!]{-------------------------------------------
        //[켄타우로스] 정도는 처리 분양이 많으므로 해석에 시간이 많이 걸린다.
        //따라서, 수정된 것이 있는 경우만 처리하도록 수정한다.
        //}-------------------------------------------------------------------

        if((editor_edit_Form->_TEXTINFO_IsChangedOne() == true) ||
           //[설계묶음] 을 처음 연 경우는 수정된 것은 없으나 아직 빌드하지 않은 상태라
           //{DATABASE} 가 비어 있어 검증정보가 하나도 없다.
           //따라서, 이 경우는 무조건 다시 빌드해야 한다(전용함수를 사용한다).
           (Ide_IsBuilded() == false) ||
           //[새설계묶음] 인 경우는 무조건 다시 빌드하도록 해야 한다.
           //이는 작업중인 설계묶음을 닫은 경우도 정보는 남아 있게 되므로 반드시 이를 검사해야 한다.
           //[2012.04.20.금][수정!!!]
           (STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true))
        {
          //[가상기계제작]{-----------------------------------------------------------------------------
          //오류가 있는 경우는 다음을 실행하지 않고 종료해야 한다.
          if(IDE_Build(d_Build_Parser|d_Build_Object|d_Build_Link|d_Build_Gvmx) != true) return(false);
          //}-------------------------------------------------------------------------------------------

        }

    //}

    //[기동정지]-------------------------------
    //[맷돌] 을 미리 여기서 정지 시켜야 한다.
    if(Ide_Ctrl_Stop() != true) return(false);
    //}----------------------------------------

    if(pNoDownload == false)
    {
      //[2009.12.28.월][추가!!!]{---------------------------------------------------
      //수정된 것이 없는 경우는 다시 설치하지 않고 바로 검증단계로 진입하게 만든다.
      //}---------------------------------------------------------------------------

      //[지우기]-------------------------------------
      //설치전 먼저 설치공간을 전부 지운다.
      if(Ide_Ctrl_Erase() != true) return(false);
      //[설치]---------------------------------------
      if(Ide_Ctrl_Download() != true) return(false);
      //[확인]---------------------------------------
      if(Ide_Ctrl_Verify() != true) return(false);
      //}--------------------------------------------

    }

    //[검증정보 수집/정리]
    //{
        //<*.$lst> 문서이름을 만든다.
        //[2012.04.20.금][수정!!!]
        STR_Add_AB(tempStr, database->buildpath, tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0));

        //확장자를 바꾼다.
        STR_ChangeFileExt(tempStr, "$lst", fileName);

        //문서를 전달하여 정보를 [수집/정리] 한다.
        Debug_LineList_Create(fileName);

    //}

    //[검증 구동기 구동][2009.04.07.화][추가!!!]--------------------------------------------------
    Ide_VDEBUG_Run();
    //}-------------------------------------------------------------------------------------------

    //[검증 재기동]
    //{
        //[!]{--------------------------------------------------------------------------------------
        //전체를 [재기동] 하는 것이 아니라 [검증] 을 위한 [검증재기동] 을 실행한다.
        //설치된 [가상기계] 를 다시 [생성] 하고 실행하지만 [검증] 관련 기능은 초기화 되지 않으므로
        //[맷돌] 은 계속 [중지] 상태가 되어, 처음 실행하는 [명령위치] 에서 @PC 가 멈추어 있게 된다.
        //즉, main() 함수의 처음 [명령위치] 에서 일단 정지한 상태로 대기하게 된다.
        //
        //[검증재기동] 을 하는 이유는 일단 [설치] 된 [가상기계] 가 [생성] 이 되어야 @CODE 등 여러
        //[세그먼트] 가 설정이 되므로 [절대번지] 를 계산 가능하기 때문이다.
        //}-----------------------------------------------------------------------------------------

        if(Ide_Ctrl_DebugReset() != true) return(false);

    //}

  }

  //[알림글]{--------------------------------------------------------------------------------
  msg_msg_Form->_PrintAddLine(d_msg_msg,
                              "[맷돌] 을 [재기동] 시키면 설치한 [가상기계] 가 실행됩니다.");
  //}----------------------------------------------------------------------------------------

  return(true);

}

//------------------------------------------------------------------------------
//[VM 제어 명령]----------------------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_Ctrl_Vm_Reset(void)
{
  //[2009.04.08.수][생성!!!]{----------------------------
  //[VM] 을 <Reset Vector> 부터 다시 <Debug Run> 시킨다.
  //}----------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [검증재기동] 명령을 전달한다.

    if(Ide_VM_Reset() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [검증재기동] 명령을 전달한다.

    //[2009.07.14][추가!!!]
    if(Ide_Mdl_VM_Reset() != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Vm_ResetVector(void)
{
  //[2009.04.08.수][생성!!!]{-------------------------
  //[VM] 을 <Reset Vector> 위치로 이동후 정지 시킨다.
  //}-------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[가상 VMOS] 에 [검증재기동] 명령을 전달한다.

    if(Ide_VM_ResetVector() != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[맷돌] 에 [검증재기동] 명령을 전달한다.

    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_VM_ResetVector() != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Vm_Mode(int  pVmMode)
{
  //[2009.04.08.수][생성!!!]{---
  //[VM] 의 <Mode> 를 설정한다.
  //}---------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    if(Ide_VM_Mode(pVmMode) != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    if(Ide_Mdl_VM_Mode(pVmMode) != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Vm_Mode_Read(int  *rVmMode)
{
  //[2011.05.28.토][생성!!!]{----------
  //[VM] 의 <Mode> 를 읽어서 반환한다.
  //}----------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    if(Ide_VM_Mode_Read(rVmMode) != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    if(Ide_Mdl_VM_Mode_Read(rVmMode) != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Vm_SysBreakPoint(DTU8  pAdr)
{
  //[2009.04.09.목][생성!!!]{---
  //[특수정지점] 을 설정한다.
  //}---------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    if(Ide_VM_SysBreakPoint(pAdr) != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_VM_SysBreakPoint(pAdr) != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_Vm_BreakPoint(bool  pEnable)
{
  //[2009.04.29.수][생성!!!]{------
  //[정지점] 12개를 일괄 설정한다.
  //}------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    if(Ide_VM_BreakPoint(pEnable) != true) return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_VM_BreakPoint(pEnable) != true) return(false);

  }

  return(true);

}

bool __fastcall Ide_Ctrl_BuildDate(unsigned long long  *rBuildDate)
{
  //[2009.08.05.수][생성!!!]{-----------------
  //[제조날짜] 를 읽어 들인다.
  //단, 이것은 실제 [맷돌모듈] 에만 해당된다.
  //}-----------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //실제 [맷돌모듈] 에서만 의미가 있음을 알려준다.
    ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                             "현재는 [가상구동] 중으로,\r\n"
                             "이 기능은 실제 [맷돌모듈] 에만 적용 됩니다.");

    return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[2009.07.14.화][추가!!!]
    if(Ide_Mdl_BuildDate(rBuildDate) != true) return(false);

    return(true);

  }

  return(false);

}

bool __fastcall Ide_Ctrl_Vmos_Install(char  *pVmosFileName)
{
  //[2009.08.07.금][생성!!!]{----------------------------------------------------------------
  //실제 맷돌의 [운영체제] 인 VMOS 를 새로 설치(향상)한다.
  //
  //[2009.08.26.수][수정!!!]-----------------------------------------------------------------
  //[운영체제 기본] 만 설치한다.
  //
  //[VMOS통합판수정중][2010.12.08.수]--------------------------------------------------------
  //VMOS 에 수학 API 가 완전히 통합되고 다양한 API 에 따라 VMOS 가 여러 종류로
  //세분화 되어 전용 [VMOS 설치 대화상자] 가 추가 되었으므로, 보다 쉽게 설치
  //가능하도록 아예 <vmos.gos> 의 위치를 전달받는 것으로 수정한다.
  //
  //이 함수는 [VMOS 설치 대화상자] 에서 해당 [운영체제] 버튼이 눌린 경우 호출된다.
  //자동으로 설치할 <vmos.gos> 경로를 전달 받게 된다.
  //
  //[2011.04.26.화][추가!!!]-----------------------------------------------------------------
  //<VMOS:AT45DB041X> 계열인 경우는 <VMOS> 계열처럼 [운영체제 설치] 시에 자동으로 ROM 공간이
  //지워지지 않아서, GVMX 의 치명적인 오류로 다시 [운영체제] 를 설치하는 경우 다시 문제가
  //발생하는 경우가 있다.
  //따라서, 반드시 [운영체제 설치] 시 먼저 ROM 을 지우는 것으로 수정한다.
  //이는 일반적인 [지우기] 과정을 먼저 처리해 주면 된다.
  //실제 지우는 것은 명령을 받은 [맷돌] 이 내부적으로 처리한다.
  //
  //이 함수는 <폼:vmos_InstallBox> 에서 <vmosInfo->osID> 정보가 이미 설정된 후, 호출되므로
  //여기서는 <vmosInfo->osID> 를 바로 읽어서 구분처리 하면 된다.
  //
  //[2011.05.17.화][중요수정!!!]-------------------------------------------------------------
  //[운영체제] 설치시 <*.ginf> 의 [식별자] 가 아니라, 현재 [맷돌] 의 [식별자] 를 직접 읽어서
  //정확한 정보를 바탕으로 [ROM 지우기] 를 판별하는 것으로 중요 수정한다.
  //같은 날짜의 수정 내용을 참고한다.
  //}----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //[2011.05.17.화][추가!!!]{---------------------------------------------------------
      //현재 <VMOS> 를 설치할 대상의 [식별자] 를 얻는다.
      //이것은 <*.ginf> 문서 안의 [식별자] 가 아니라, 대상이 되는 <맷돌/맷돌28호> 등 에서
      //바로 직접 읽어들인 정보가 된다.
      //}---------------------------------------------------------------------------------

      DTU8  osID;

  //}

  //[VMOSINFO 위치 얻기]
  //{
      //[2011.04.26.화][추가!!!]
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //실제 [맷돌모듈] 에서만 의미가 있음을 알려준다.
    ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                             "현재는 [가상구동] 중으로,\r\n"
                             "이 기능은 실제 [맷돌모듈] 에만 적용 됩니다.");

    return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[<VMOS:AT45DB041X> 계열 운영체제 ROM 지우기]
    //{
        //[2011.04.26.화][추가!!!]{-----------------------------------------------------------------
        //<VMOS:AT45DB041X> 계열은 외부 ROM 을 [운영체제 설치] 전에 반드시 먼저 지워야 한다.
        //일반 <VMOS> 계열은 자체적으로 내부 Flash 가 지워지므로 상관없다.
        //여기서 처리하는 경우는 [중복처리] 가 되므로 일반 <VMOS> 계열은 처리하지 않는다.
        //
        //이미 [운영체제 정보 구조체] 에 [식별자] 가 기록돼 있으믈 이를 사용하여 구분한다.
        //상위 4 Byte 를 추출하면 쉽게 구분할수 있다.
        //
        //[2011.05.17.화][중요수정!!!]--------------------------------------------------------------
        //<vmosInfo->osID> 정보는 [설치할] <*.ginf> 문서의 [식별자] 정보이므로 이를 판단하여
        //[ROM 지우기] 를 해서는 안된다.
        //
        //이는 현재 대상이 되는 [제어기] 의 현재 정보가 아니라서, 현재 [맷돌] 에 [맷돌28호] 가
        //설치돼 있는 경우도 [설치할 <VMOS:AT45DB041X>] 의 [식별자] 를 가지고 판별하게 되므로
        //[ROM 지우기] 명령을 요청하게 되어 [통신 오류] 가 발생하게 된다.
        //[맷돌28호] 에는 [ROM 지우기] 명령이 존재하지 않기 때문이다.
        //
        //즉, [설치할] [운영체제] 를 기준으로 하지 않고, 지금 연결된 [맷돌] 의 [식별자] 를 기준으로
        //[ROM 지우기] 여부를 판별하는 것으로 수정한다.
        //
        //금일 [맷돌28호 + 맷돌] 예제를 만들어 실험중 [운영체제] 전환시 문제점을 발견하고 수정한다.
        //}-----------------------------------------------------------------------------------------

        //[현재 대상의 [식별자] 읽기]
        //{
            //[2011.05.17.화][중요추가!!!]{-------------------------
            //현재 연결돼 있는 [제어기] 의 [식별자] 를 읽어 들인다.
            //}-----------------------------------------------------

            if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_OS_ID, (DTU1 *)(&osID)) != true) return(false);

        //}

        if((osID & 0xffffffff00000000) == d_OS_at45db041x)
        {
          //현재 [맷돌] 의 [운영체제] 가 <VMOS:AT45DB041X> 계열인 경우는 먼저 ROM 을 지운다.
          if(Ide_Mdl_Erase() != true) return(false);

        }

    //}

    //[2009.08.07.금][추가!!!]
    //[2010.12.08.수][수정!!!]
    //직접 전달받은 <vmos.gos> 경로를 넘겨준다.
    if(Ide_Mdl_Vmos_Install(pVmosFileName) != true) return(false);

    return(true);

  }

  return(false);

}

bool __fastcall Ide_Ctrl_OSX_Install(char  *pOsxFileName)
{
  //[2010.12.14.화][생성!!!]{--------------
  //맷돌 변환 [운영체제(OSX)] 를 설치한다.
  //}--------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //실제 [맷돌모듈] 에서만 의미가 있음을 알려준다.
    ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                             "현재는 [가상구동] 중으로,\r\n"
                             "이 기능은 실제 [맷돌모듈] 에만 적용 됩니다.");

    return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //맷돌28호(3.3V 전용) OSX 를 설치한다.
    if(Ide_Mdl_OSX_Install(pOsxFileName) != true) return(false);

    return(true);

  }

  return(false);

}

bool __fastcall Ide_Ctrl_OS_Check(void)
{
  //[2010.12.13.월][생성!!!]{----------------------------------------------
  //현재 맷돌에 설치된 [운영체제] 의 종류를 검사하고 해당 정보를 보여준다.
  //VMOS 계열, OSX 계열 등이 전부 포함된다.
  //}----------------------------------------------------------------------

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //실제 [맷돌모듈] 에서만 의미가 있음을 알려준다.
    ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                             "현재는 [가상구동] 중으로,\r\n"
                             "이 기능은 실제 [맷돌모듈] 에만 적용 됩니다.");

    return(false);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //맷돌의 [운영체제] 종류를 확인한다.
    if(Ide_Mdl_OS_Check() != true) return(false);

    return(true);

  }

  return(false);

}

bool __fastcall Ide_Ctrl_OS_MemRange(//운영체제 사용 가능 메모리 전체 영역 시작 주소.
                                     unsigned long long  *rStartAdr,
                                     //운영체제 사용 가능 메모리 전체 영역 끝 주소.
                                     unsigned long long  *rEndtAdr)
{
  //[2011.07.23.토][생성!!!]{---------------------------------------------------
  //현재 [운영체제] 에서 실제 접근할수 있는 [ROM:RAM:HEAP] 영역 전체의
  //[시작/끝 절대주소] 를 얻는다.
  //
  //<VMOS> 는 [ROM:RAM:HEAP] 순으로 완전히 연결된 구조를 가지고 있으므로
  //각각의 영역을 구별하지 않고, 전체의 시작과 끝 [절대주소] 만 구하면 된다.
  //
  //이 함수는 [검증식 계산] 시 [주소범위 초과] 시 발생하는 오류를 사전에
  //점검하여 [통신오류] 등 의 문제를 해결하기 위하여 제작한다.
  //즉, [검증식] 처리 불가여부를 [논리적] 으로 먼저 확인하기 위한 것이다.
  //
  //[주의!!!]-------------------------------------------------------------------
  //이 함수는 순수한 [ROM, RAM, HEAP] 영역만을 대상으로 하고 [장치/특수] 영역은
  //대상으로 하지 않는다.
  //
  //[2011.07.24.일][중요정리!!!]------------------------------------------------
  //실제 [접근 주소 정보] 는 [운영체제] 를 설치할때 한번만 실제 [맷돌] 에 기록
  //되므로 <vmos_info.cpp> 의 정의정보로는 알수가 없다.
  //따라서, 반드시 [검증/재검증] 으로 진입시 한번은 직접 [맷돌] 로 부터 읽어
  //주어야 한다.
  //
  //직접 [직렬버스] 를 사용하므로 [검증] 으로 진입할때 [한번만] 읽어들인다.
  //}---------------------------------------------------------------------------

  //[VMOSINFO 위치 얻기]
  //{
      struct VMOSINFO  *vmosInfo;

      VmosInfo_GetPtr(&vmosInfo);

  //}

  if     (ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) //가상구동.
  {
    //[!]{-------------------------------------------------------------
    //[가상구동] 의 경우는 이미 정해진 값이 있으므로 이 값을 반환한다.
    //}----------------------------------------------------------------

    if(rStartAdr != NULL) { (*rStartAdr) = d_Sim_VMOS_ROM_START; }
    if(rEndtAdr  != NULL) { (*rEndtAdr)  = d_Sim_VMOS_HEAP_END;  }

    return(true);

  }
  else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true) //맷돌구동.
  {
    //[!]{--------------------------------------------------------------------------------
    //[직접연결] 의 경우는 설치된 [운영체제] 의 종류에 따라 사용 가능 범위가 다를수 있다.
    //}-----------------------------------------------------------------------------------

    //[시작위치] 구하기.
    if(rStartAdr != NULL)
    {
      //[ROM] 의시작 위치가 해당한다.
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_RomStart, (DTU1 *)rStartAdr) != true) return(false);

    }

    //[끝위치] 구하기.
    if(rEndtAdr  != NULL)
    {
      if(ComBus_Read(d_CB_TS_S, d_CB_AK_M, 3, vmosInfo->sys_HeapEnd, (DTU1 *)rEndtAdr) != true) return(false);

    }

    return(true);

  }

  return(false);

}

bool __fastcall Ide_Ctrl_GVM_VerCheck(//읽어들인 [가상기계] 1개 덩어리.
                                      unsigned char  *pGvm)
{
  //[2011.12.28.수][생성!!!]{------------------------------------------------
  //설치하는 [가상기계] 의 [선행정보:판번호] 를 확인하고
  //현재 현재 [맷돌-통합개발환경] 에서 지원하는 것인지 확인한다.
  //<c_define.h:Opt_Ide_GvmVersion> 값과 일치하는지만 확인하면 된다.
  //
  //이는 VMOS 지원 API 자체의 처리방식을 변경하였기에, API 관련 VMOS 등
  //모든 부분이 완전히 변경되었기 때문이다.
  //따라서, [가상기계] 를 설치할때 가장 먼저 [가상기계:판번호] 를 확인하여
  //기존 API 방식의 [가상기계] 를 걸러주어야 한다.
  //
  //[주의!!!]----------------------------------------------------------------
  //단, 이전 API 방식의 [맷돌-통합개발환경] 은 이 처리부가 없으므로
  //새로운 방식의 [가상기계] 가 걸러지지 않고 설치되나 API 방식이 다르다.
  //
  //[참고!!!]----------------------------------------------------------------
  //<matdol.cpp:Matdol_Mount()> 와 <vmos.cpp:Mount()> 에서 [가상기계] 내용을
  //설치를 위하여 읽어들인후 이 함수를 사용하여 비교 처리한다.
  //}------------------------------------------------------------------------

  //[가상기계 선행정보 구조]{----------------------------------------------
  //각 8 바이트 값으로 GVMX, GVMS 의 가장 처음에 배치돼 있다.
  //
  //< Version     >
  //< Header Size >
  //< Code   Size >
  //< Data   Size >
  //< Ram    Size > //< Memory Size > 에서 실제 사용 의미로 이름 변경(2021.01.15.금).
  //< Option      >
  //
  //여기서는 가장 처음의 <Version:판번호> 정보만 필요하므로 이것만 읽는다.
  //}----------------------------------------------------------------------

  //[VAR]
  //{
       char  tempStr[OPT_lineStrSize] = {""};

  //}

  //[<판번호> 비교]
  //{
      //[!]{------------------------------------------------------------------
      //지금 설치하는 [가상기계] 의 [판번호] 가 현재 [맷돌-통합개발환경] 에서
      //지원하는 것인지 확인한다.
      //}---------------------------------------------------------------------

      if((*((DTU8 *)pGvm)) == Opt_Ide_GvmVersion)
      {
        //현재 [맷돌-통합개발환경] 이 지원하는 [가상기계:판번호].
        return(true);

      }
      else
      {
        //[!]{------------------------------------------------------------------------------------
        //현재 [맷돌-통합개발환경] 에서 설치를 지원하지 않는 [가상기계:판번호].
        //관련 정보를 알려준다.
        //
        //[맷돌가상구동] 이건, [맷돌직접연결] 이건 [무관] 하고 단지 현재 [맷돌-통합개발환경] 에서
        //설치를 지원하지 않는 [구형] 임을 알려주면 된다.
        //}---------------------------------------------------------------------------------------

        //[출력문자열 정리]
        //{
            STR_Assign(tempStr, "현재 [맷돌-통합개발환경] 에서 설치를 지원하지 않는 [가상기계:판번호] 입니다.\r\n\r\n");

            STR_Add(tempStr, "< 현재지원 판번호 > : ");
            CONV_LongVal_To_Str2(Opt_Ide_GvmVersion, 0, false, &(tempStr[STR_Length(tempStr)]));
            STR_Add(tempStr, "\r\n");

            STR_Add(tempStr, "< 가상기계 판번호 > : ");
            CONV_LongVal_To_Str2((*((DTU8 *)pGvm)), 0, false, &(tempStr[STR_Length(tempStr)]));
            STR_Add(tempStr, "\r\n\r\n");

            STR_Add(tempStr, "[가상기계] 를 현재 [맷돌-통합개발환경] 에서 다시 만들어야 합니다.\r\n");

        //}

        ide_msgbox_Form->_MsgBox(d_MSGBOX_error, tempStr);

        return(false);

      }

  //}

}

bool __fastcall Ide_Ctrl_Ack(int  pAckTimeOut)
{
  //[2009.04.11.토][생성!!!]{-----------------------------------------------------------
  //<Ack> 가 도착했는지만 확인한다.
  //이전과 달리 [타이머] 를 사용하여 간단하게 처리한다.
  //<vdebug> 안에서 처리하는 경우는 [쓰레드] 동기화 문제로 자연스럽게 처리되지 않으며
  //<Break> 신호처리와 중복되어 충돌이 발생한다.
  //띠라서, <vdebug> 에서는 오로지 <Break> 처리만 하도록 하고 <Ack> 는 여기서 처리한다.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      class  VMOS      *vmos;
      class  VDEBUG    *vdebug;

  //}

  //[VMOS 위치 얻기]{-------------
  VMOS_GetPtr(&vmos);
  if(vmos == NULL) return(false);
  //}-----------------------------

  //[VDEBUG 위치 얻기]{---
  VDEBUG_GetPtr(&vdebug);
  //}---------------------

  //[타이머 설정/구동]
  //{
      //[제한시간] 을 설정한다.
      main_Form->timeOut_Timer->Interval = pAckTimeOut;

      //타이머를 구동시킨다.
      main_Form->timeOut_Timer->Enabled = true;

  //}

  //[<Ack> 확인]
  //{
      //타이머가 중지 된 상태라면 [시간제한] 에 걸린것으로 본다.
      while(main_Form->timeOut_Timer->Enabled)
      {
        //[타이머] 의 상태를 확인하기 위하여 반드시 필요하다.
        Application->ProcessMessages();

        //[수신] 된 것이 있는가?

        if((main_Form->comM0_RxdCount > 0) && (GxCom_M0_AckRead(main_Form->comM0_RxdBuf) == true))
        {
          main_Form->comM0_RxdCount = 0;

          //[타이머 끄기]{---------------------------
          main_Form->timeOut_Timer->Enabled = false;
          //}----------------------------------------

          //이상없이 <Ack> 를 수신하였다.
          return(true);

        }

      }

      //[확인 불가]
      //{
          //[!]{-------------------------------------------------
          //여기까지 온것은 [시간제한] 에 걸린 것이다.
          //<Ack> 를 [제한시간] 동안 수신하지 못했음을 알려준다.
          //}----------------------------------------------------

          ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                   "[맷돌] 에서 [처리완료] 신호를 수신할수 없습니다.");

          return(false);

      //}

  //}

  //여기까지 온것은 일단 오류로 간주한다.
  return(false);

}


//------------------------------------------------------------------------------
//[통신포트 제어 관련]----------------------------------------------------------
//------------------------------------------------------------------------------

bool __fastcall Ide_Comport_Open(int  pPortNum)
{
  //[2009.04.21.화][생성!!!]{-------------------------------------------------
  //[통신포트] 를 이미 지정된 설정으로 열어준다.
  //현재 38400BPS 만 사용되므로 이를 사용한다.
  //
  //[2009.07.24.금][수정!!!]--------------------------------------------------
  //실제 [맷돌] 은 현재 115200BPS 를 사용하므로 무조건 115200BPS 로 설정한다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      class  COMPORT  *comPort;

      char   tempStr[OPT_wordStrSize];

  //}

  //[통신포트 위치 얻기]{---------------------
  COMPORT_GetPtr(d_ComportID_Vmos, &comPort);
  //}-----------------------------------------

  //[통신포트 번호 문자열 합성]
  //{
      STR_Assign(tempStr, "COM");

	  STR_Add(tempStr, ((AnsiString)IntToStr(pPortNum)).c_str());

  //}

  if(comPort->Open(tempStr, CBR_115200) != true)
  {
    ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                             "[통신포트] 를 열수 없습니다.\r\n"
                             "다른 [통신포트 번호] 를 선택해 주십시요.");

    return(false);

  }

  return(true);

}

bool __fastcall Ide_Comport_Close(void)
{
  //[2009.04.21.화][생성!!!]{---
  //[IDE:통신포트] 닫아준다.
  //}---------------------------

  //[VAR]
  //{
      class  COMPORT  *comPort;

  //}

  //[통신포트 위치 얻기]{---------------------
  COMPORT_GetPtr(d_ComportID_Vmos, &comPort);
  //}-----------------------------------------

  if(comPort->Close() != true)
  {
    ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                             "[통신포트] 를 닫을수 없습니다.\r\n"
                             "다른 [통신포트 번호] 를 선택해 주십시요.");

    return(false);

  }

  return(true);

}

bool __fastcall Ide_Comport2_Open(int  pPortNum,
                                  int  pBaud)
{
  //[2009.10.02.금][생성!!!]{--------------------
  //[통신포트] 를 이미 지정된 설정으로 열어준다.
  //단, [검증용:통신포트] 만 해당한다.
  //}--------------------------------------------

  //[VAR]
  //{
      class  COMPORT  *comPort;

      char   tempStr[OPT_wordStrSize];

  //}

  //[통신포트 위치 얻기]{----------------------
  COMPORT_GetPtr(d_ComportID_Debug, &comPort);
  //}------------------------------------------

  //[통신포트 번호 문자열 합성]
  //{
      STR_Assign(tempStr, "COM");

	  STR_Add(tempStr, ((AnsiString)IntToStr(pPortNum)).c_str());

  //}

  if(comPort->Open(tempStr, pBaud) != true)
  {
    ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                             "[통신포트] 를 열수 없습니다.\r\n"
                             "다른 [통신포트 번호] 를 선택해 주십시요.");

    return(false);

  }

  return(true);

}

bool __fastcall Ide_Comport2_Close(void)
{
  //[2009.10.02.금][생성!!!]{----------
  //[통신포트] 를 닫아준다.
  //단, [검증용:통신포트} 만 해당한다.
  //}----------------------------------

  //[VAR]
  //{
      class  COMPORT  *comPort;

  //}

  //[통신포트 위치 얻기]{----------------------
  COMPORT_GetPtr(d_ComportID_Debug, &comPort);
  //}------------------------------------------

  if(comPort->Close() != true)
  {
    ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                             "[통신포트] 를 닫을수 없습니다.\r\n"
                             "다른 [통신포트 번호] 를 선택해 주십시요.");

    return(false);

  }

  return(true);

}

//------------------------------------------------------------------------------
//[메뉴:수평이동 관련]----------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_Menu_MoveRL_Right(void)
{
  //[2012.02.07.화][생성!!!]{---------------------------------------------
  //[수평이동:오른쪽] 을 처리.
  //<Ctrl+[->]> 조합과는 달리 [이동폭] 을 지정할수 있는 대화상자를 표시후
  //이 지정 [이동폭] 만큼 한번에 이동시킨다.
  //}---------------------------------------------------------------------

  //[VAR]
  //{
      //[2012.02.08.수][추가!!!]
      //[선택영역] 정보를 순서대로 얻기 위한것.
      struct CARETINFO  select_start;
      struct CARETINFO  select_end;

      int    moveSize;

  //}

  //[선택영역 존재 확인]
  //{
      //[2012.02.08.수][추가!!!]{-----------------------
      //[수평이동] 은 [선택영역] 을 대상으로 처리하므로
      //반드시 [선택영역] 이 존재해야 한다.
      //}-----------------------------------------------

      //[선택 영역 정보 얻기]
      //{
          editor_edit_Form->_SELECT_Get_StartEndIndex(&select_start, &select_end);

      //}

      //[선택영역이 존재하나?]
      //{
          //[!]{---------------------------------------------------------------
          //두 위치중 하나만 음수라면 [선택영역] 은 존재하지 않는 것으로 본다.
          //}------------------------------------------------------------------

          if((select_start.caret_index < 0) || (select_end.caret_index < 0))
          {
            ide_msgbox_Form->_MsgBox
                             (d_MSGBOX_error,
                              "[선택영역] 이 존재하는 경우만 처리 가능합니다."
                             );

            //더이상 처리하지 않는다.
            return;

          }

      //}

  //}

  //[대화상자 보이기]
  //{
      if(ide_msgbox_Form->_MsgBox_Edit
         (d_MSGBOX_default,
          "[오른쪽:수평이동] 할 [이동칸수] 를 입력합니다.\r\n\r\n"
          "10진수만 가능하고 1 - 1000 까지 사용할수 있습니다."
         ) != true) return;

  //}

  //[10진수 검사]
  //{
      if(CHECK_DecRule(ide_msgbox_Form->_edit_Edit->_editbuf) != true)
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "10진수만 사용가능 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[범위 검사]
  //{
      //[문자열=>값] 변환.
      CONV_DecStr_To_IntVal(ide_msgbox_Form->_edit_Edit->_editbuf, &moveSize);

      if(!((1 <= moveSize) && (moveSize <= 1000)))
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "[이동칸수] 는 1 - 1000 사이의 값이어야 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[수평이동]
  //{
      //지정 칸수 만큼 오른쪽으로 수평이동.
      editor_edit_Form->_LineBlock_MoveRL_Right(moveSize);

  //}

}

void __fastcall Ide_Menu_MoveRL_Left(void)
{
  //[2012.02.07.화][생성!!!]{---------------------------------------------
  //[수평이동:왼쪽] 을 처리.
  //<Ctrl+[<-]> 조합과는 달리 [이동폭] 을 지정할수 있는 대화상자를 표시후
  //이 지정 [이동폭] 만큼 한번에 이동시킨다.
  //}---------------------------------------------------------------------

  //[VAR]
  //{
      //[2012.02.08.수][추가!!!]
      //[선택영역] 정보를 순서대로 얻기 위한것.
      struct CARETINFO  select_start;
      struct CARETINFO  select_end;

      int    moveSize;

  //}

  //[선택영역 존재 확인]
  //{
      //[2012.02.08.수][추가!!!]{-----------------------
      //[수평이동] 은 [선택영역] 을 대상으로 처리하므로
      //반드시 [선택영역] 이 존재해야 한다.
      //}-----------------------------------------------

      //[선택 영역 정보 얻기]
      //{
          editor_edit_Form->_SELECT_Get_StartEndIndex(&select_start, &select_end);

      //}

      //[선택영역이 존재하나?]
      //{
          //[!]{---------------------------------------------------------------
          //두 위치중 하나만 음수라면 [선택영역] 은 존재하지 않는 것으로 본다.
          //}------------------------------------------------------------------

          if((select_start.caret_index < 0) || (select_end.caret_index < 0))
          {
            ide_msgbox_Form->_MsgBox
                             (d_MSGBOX_error,
                              "[선택영역] 이 존재하는 경우만 처리 가능합니다."
                             );

            //더이상 처리하지 않는다.
            return;

          }

      //}

  //}

  //[대화상자 보이기]
  //{
      if(ide_msgbox_Form->_MsgBox_Edit
         (d_MSGBOX_default,
          "[왼쪽:수평이동] 할 [이동칸수] 를 입력합니다.\r\n\r\n"
          "10진수만 가능하고 1 - 1000 까지 사용할수 있습니다."
         ) != true) return;

  //}

  //[10진수 검사]
  //{
      if(CHECK_DecRule(ide_msgbox_Form->_edit_Edit->_editbuf) != true)
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "10진수만 사용가능 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[범위 검사]
  //{
      //[문자열=>값] 변환.
      CONV_DecStr_To_IntVal(ide_msgbox_Form->_edit_Edit->_editbuf, &moveSize);

      if(!((1 <= moveSize) && (moveSize <= 1000)))
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "[이동칸수] 는 1 - 1000 사이의 값이어야 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[수평이동]
  //{
      //지정 칸수 만큼 왼쪽으로 수평이동.
      editor_edit_Form->_LineBlock_MoveRL_Left(moveSize);

  //}

}

//------------------------------------------------------------------------------
//[메뉴:편집:특수]--------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_Menu_TabToSpaceX(void)
{
  //[2018.05.06.일][생성!!!]{-----------------------------------------------
  //[탭키] => [지정수 공백] 으로 교체.
  //
  //BCB 소스를 복사후 [맷돌-IDE] 에서 사용시 이 탭키 때문에 문제가 많다.
  //[맷돌-IDE] 는 [탭키] 를 기본 1:1 로 공백으로 대신 표시를 하는데, 문제는
  //[맷돌-IDE] 에서 편집후 다시 BCB 에 복사시 이 [탭키] 가 다른 공백수로
  //변환되어 들여쓰기가 줄에 맞지 않는 문제가 발생하기 때문이다.
  //이를 수정하기 위하여 아예 [탭키] => [지정 공백수] 로 문서 자체를 변환
  //하는 함수를 만든다.
  //}-----------------------------------------------------------------------

  //[VAR]
  //{
      char  tempStr[OPT_lineStrSize];
      char  tempWord[OPT_wordStrSize];
      char  spaceStr[OPT_wordStrSize];
      int   tempVal;

      int   i;

  //}

  //[편집중인 문서가 있나?]
  //{
      //[!]{--------------------------------------------------------------------------
      //문서가 열려있는 경우만 처리해야 한다.
      //<ide_menu_Form->_EVENT_Select_SubMenuItem()> 내부에서 이미 처리를 했다.
      //편집 관련 메뉴의 경우 내부적으로 [편집중] 인 문서가 있는 경우만 처리되도록...
      //}-----------------------------------------------------------------------------

      /*
      if(editor_edit_Form->_textinfo_count == 0)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "[편집기] 에 문서가 열려있는 경우만 처리 가능합니다."
                                 );

        return;

      }
      */

  //}

  //[현재 설정값 문자열 변환]
  //{
      CONV_LongVal_To_Str(_ide_Option.tabToSpaceX, 3, false, tempWord);

  //}

  //[대화상자:현재 설정값 보이기]
  //{
      ide_msgbox_Form->_edit_Edit->_EDIT_TextOut(tempWord);

  //}

  //[문자 개수 얻기]
  //{
      tempVal = STR_Get_Moonja_Count(editor_edit_Form->_editbuf, '\t', 0, editor_edit_Form->_filesize);

      //[탭 문자가 존재하나?]
      //{
          //탭 문자가 없다면 더이상 처리하지 않고 종료.
          if(tempVal == 0)
          {
            ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                     "현재 문서에 [탭(Tab)] 문자가 존재하지 않습니다."
                                    );

            return;                        

          }

      //}

      CONV_LongVal_To_Str(tempVal, 0, false, tempWord);

      STR_Assign(tempStr, "발견된 [탭(Tab)] 문자 개수 : ");
      STR_Add(tempStr, tempWord); STR_Add(tempStr, "\r\n\r\n");

      STR_Add(tempStr, "[탭(Tab)] 문자를 지정 개수의 [공백(Space)] 문자로 교체합니다.");

  //}

  //[진행바 설정]
  //{
      //처리할 탭 문자 개수로 설정.
      ide_buttons_Form->_progress->_Min(0);
      ide_buttons_Form->_progress->_Max(tempVal);

  //}

  //[대화상자 보이기]
  //{
      if(ide_msgbox_Form->_MsgBox_Edit
                          (d_MSGBOX_default,
                           tempStr
                          ) != true) return;

  //}

  //[10진수 검사]
  //{
      if(CHECK_DecRule(ide_msgbox_Form->_edit_Edit->_editbuf) != true)
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "10진수만 사용가능 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[범위 검사]
  //{
      //[문자열=>값] 변환.
      CONV_DecStr_To_IntVal(ide_msgbox_Form->_edit_Edit->_editbuf, &tempVal);

      if(!((1 <= tempVal) && (tempVal <= 100)))
      {
        ide_msgbox_Form->_MsgBox
                         (d_MSGBOX_error,
                          "[공백(Space)] 수는 1 - 100 사이의 값이어야 합니다."
                         );

        //더이상 처리하지 않는다.
        return;

      }

      //검사 결과 이상없다면 설정.
      _ide_Option.tabToSpaceX = tempVal;

  //}

  //[교체 문자열 만들기]
  //{
      //지정수 대로 교체할 [공백 문자열] 을 만든다.
      for(i = 0; i < _ide_Option.tabToSpaceX; i++)
      {
        spaceStr[i] = ' ';

      }

      //문자열로 완성.
      spaceStr[i] = '\0';

  //}

  //[문서 처음 부터 시작]
  //{
      //[!]{----------------------------------------------------------------
      //전체 문서를 대상으로 처리하므로 문서 처음으로 이동.
      //이는 찾기에 사용하는 <find_DialogBox_Form->_Find2()> 는 기본적으로
      //[입력지정자] 위치부터 검사를 하기 때문.
      //}-------------------------------------------------------------------
      
      editor_edit_Form->History_SetCaretPos(0, true);

  //}

  //[교체]
  //{
      //[_EditBuf_Text() 기능 제어]{--------------------
      //_EditBuf_Text() 함수가 동작되지 못하게 한다.
      editor_edit_Form->_editBuf_Text_No_Select = true;
      //}-----------------------------------------------

      //[입력지정자:스텔스 설정]
      //{
          //[!]{------------------------------------------------------------------
          //<_Find()> 함수에서 <History_SelectX()> 를 사용하고
          //<History_SelectX()> 함수안에서 <_EDIT_CaretPos()> 를 사용하는데
          //이 <_EDIT_CaretPos()> 에서 <gui_caret->_Position()> 함수를 사용하므로
          //처리시 [입력지정자] 가 자동으로 보이지 않도록 [스텔스] 로 설정한다.
          //
          //[편집기] 자체는 모든 처리를 완료후 한번만 그려주지만, [입력지정자] 는
          //계속 보여지므로 이를 방지하기 위한것.
          //}---------------------------------------------------------------------

          editor_edit_Form->_caret->_Stealth(true);

      //}

      //[진행바:보이기]{-------------------------
      ide_buttons_Form->_Progress_Visible(true);
      //}----------------------------------------

      //처리 개수 초기화(진행바 진행을 위한것).
      i = 0;

      while(1)
      {
        //[찾기]
        //{
            //[!]{---------------------------------------------------------------------------
            //먼저 현재 문자열을 조건에 맞게 찾는다.
            //더이상 찾는 것이 없다는 것은 문서의 끝이라는 것도 되므로 여기서 [반복문] 종료.
            //}------------------------------------------------------------------------------

            //찾을 대상은 탭문자-------------v
            if(find_DialogBox_Form->_Find2("\t") != true) break;

        //}

        //[교체]
        //{
            //이미 [선택영역] 으로 지정된 상태이므로 교체할 [공백 문자열] 을 붙여넣기만 한다.
            editor_edit_Form->_EDIT_Paste(spaceStr, false);

        //}

        //[진행바:진행]{-----------------------------
        ide_buttons_Form->_progress->_Progress(++i);
        //}------------------------------------------

        Application->ProcessMessages();

        //Linux:wiine 지원]
        //{
            //[!]{----------------------------------------------------------------
            //[Linux:wine] 에서는 진행의 경우 [진행바] 변화가 반영되지 않는다.
            //처리 속도가 윈도우보다 훨씬 빠르기 때문에 GUI 구현이 제대로 안된다.
            //따라서, [Linux:wine] 의 경우는 GUI 를 충분히 구현할수 있는 <10ms>
            //지연 시간을 준다.
            //처리 속도가 빠른 CPU 일수록 큰 값이 필요. FX8300 에서 10ms 면 넉넉. 
            //}-------------------------------------------------------------------

            if(_ide_Option.wine == true) { Sleep(10); }

        //}

        //[정보 표시]
        //{
            /*CONV_LongVal_To_Str(ide_buttons_Form->_progress->_max, 0, false, tempWord);

            STR_Assign(tempStr, "진행 상황 : 전체 ");
            STR_Add(tempStr, tempWord); STR_Add(tempStr, " 개중 [ ");

            CONV_LongVal_To_Str(i, 0, false, tempWord);
            STR_Add(tempStr, tempWord); STR_Add(tempStr, " ] 개 처리 완료. ");

            msg_msg_Form->_Print(0, tempStr);
            */
        //}
        
      }

      //[진행바:감추기]{-------------------------
      ide_buttons_Form->_Progress_Visible(false);
      //}----------------------------------------
      
      //[입력지정자:스텔스 해제]
      //{
          editor_edit_Form->_caret->_Stealth(false);

      //}

      //[_EditBuf_Text() 기능 제어]{---------------------
      //_EditBuf_Text() 함수의 동작을 허용한다.
      editor_edit_Form->_editBuf_Text_No_Select = false;
      //}------------------------------------------------

      //[문서수정]{---------------------------------
      //문서가 수정됬음을 기록한다.
      editor_edit_Form->_EDIT_Changed(false, true);
      //}-------------------------------------------

      //[묶음주석 정보 얻기]
      //{
          //[!]{----------------------------
          //이 경우는 무조건 한번 처리한다.
          //}-------------------------------

          //[묶음주석] 정보 수집.
          editor_edit_Form->_CommentBlock_Info(false);

          //[다시 그리기]{----------------------------------------------------
          //[붙이기] 로 바꾸게 되므로 너무 많은 시간을 소비하게 되어 마지막에
          //딱, 한번만 다시 그려준다.
          editor_edit_Form->_EditBuf_Text();
          //}-----------------------------------------------------------------

      //}

  //}

}

void __fastcall Ide_Menu_SpaceArrange(void)
{
  //[2021.07.20.화][생성]{------------------------------------------------------
  //[편집기] 에 열려 있는 문서의 공백을 최소한으로 정리해 준다.
  //
  //1) "기술내용@@@@\r\n"
  //   => "기술내용\r\n" 으로 유효 문자를 제외한 됫부분의 모든 공백 제거.
  //
  //2) "@@@@@@\r\n"
  //   => "\r\n" 으로 공백만으로 된 행은 모든 공백을 없에고 NULL 행으로 만든다.
  //
  //3) 1), 2) 이외의 모든 공백은 그대로 유지.
  //
  //이 함수는 [배포판] 을 만들때 기술 내용을 깔끔하게 정리하기 위하여 만든다.
  //
  //[방법]**********************************************************************
  //
  //가) 1), 2) 조건에 맞는 "공백문자열" 을 [선택]지정.
  //
  //나) [선택] 된 "공백문자열" 을 [삭제].
  //
  //하는 방법으로 간단하게 처리.
  //모든 수정 내용은 [되돌리기/되살리기] 에 반영된다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      int  preSpaceCount;

      int  postSpaceCount;

      int  lineStartIndex;
      int  lineEndIndex;

      int  l;

  //}

  //[진행바 설정]
  //{
      //[!]{--------------------------------------------------------------------------
      //현재 열려 있는 문서를 대상으로 처리하므로, 현재 열려있는 문서 총 행수로 설정.
      //}-----------------------------------------------------------------------------

      ide_buttons_Form->_progress->_Min(0);
      
      ide_buttons_Form->_progress->_Max(editor_edit_Form->_linecount);

      ide_buttons_Form->_progress->_Progress(0);

  //}

  //[문서 처음 부터 시작]
  //{
      //[!]{----------------------------------------------------------------
      //전체 문서를 대상으로 처리하므로 문서 처음으로 이동.
      //
      //이는 찾기에 사용하는 <find_DialogBox_Form->_Find2()> 는 기본적으로
      //[입력지정자] 위치부터 검사를 하기 때문.
      //}-------------------------------------------------------------------

      editor_edit_Form->History_SetCaretPos(0, true);

  //}

  //[교체]
  //{
      //[_EditBuf_Text():중지]
      //{
          editor_edit_Form->_editBuf_Text_No_Select = true;

      //}

      //[입력지정자:스텔스 설정]
      //{
          //[!]{------------------------------------------------------------------
          //<_Find()> 함수에서 <History_SelectX()> 를 사용하고
          //<History_SelectX()> 함수안에서 <_EDIT_CaretPos()> 를 사용하는데
          //이 <_EDIT_CaretPos()> 에서 <gui_caret->_Position()> 함수를 사용하므로
          //처리시 [입력지정자] 가 자동으로 보이지 않도록 [스텔스] 로 설정한다.
          //
          //[편집기] 자체는 모든 처리를 완료후 한번만 그려주지만, [입력지정자] 는
          //계속 보여지므로 이를 방지하기 위한것.
          //}---------------------------------------------------------------------

          editor_edit_Form->_caret->_Stealth(true);

      //}

      //[진행바:보이기]
      //{
          ide_buttons_Form->_Progress_Visible(true);

      //}

      for(l = 0, lineStartIndex = 0;
          l < editor_edit_Form->_linecount;
          l++)
      {
        //[조건]{---------------------------------------------------------------------
        //
        //1) "기술내용@@@@\r\n"
        //   => "기술내용\r\n" 으로 유효 문자를 제외한 됫부분의 모든 공백 제거.
        //
        //2) "@@@@@@\r\n"
        //   => "\r\n" 으로 공백만으로 된 행은 모든 공백을 없에고 NULL 행으로 만든다.
        //}---------------------------------------------------------------------------

        //[현재행 앞공백수 얻기]
        //{
            //현재 행의 첫번째 [유효문자] 까지의 [공백] 수얻기.
            preSpaceCount = STR_Get_ThisLinePreSpaceCount(editor_edit_Form->_editbuf, lineStartIndex);

        //}

        if((editor_edit_Form->_editbuf[preSpaceCount] == '\r') &&
           (editor_edit_Form->_editbuf[preSpaceCount] == '\n'))
        {
          //[!]{---------------------------
          //(조건:2) "@@@@@@\r\n" 에 해당.
          //
          //1) 앞부분 모든 공백을 [선택].
          //2) 1) 의 선택된 공백을 [삭제].
          //}------------------------------

          //현재 행이 이미 NULL 행인 경우는 처리하지 않는다.
          if(preSpaceCount > 0)
          {
            //[선택]
            //{
                editor_edit_Form->History_SelectX(lineStartIndex,
                                                  lineStartIndex + preSpaceCount,
                                                  false,
                                                  NULL,
                                                  false,
                                                  false,
                                                  //입력지정자 아래쪽 보기.
                                                  true);

            //}

            //[선택 문자열 삭제]
            //{
                editor_edit_Form->_EDIT_SelectDelete();

            //}

          }

        }
        else
        {
          //[!]{-------------------------------------------------------------
          //그 밖의 경우는 무조건 "기술내용@@@@\r\n" 에 해당하는 것으로 보고
          //문장 뒤의 모든 공백을 제거한다.
          //
          //1)
          //}----------------------------------------------------------------

          //현재 행의 끝 [유효문자] 다음부터 행 끝까지의 [공백] 수 얻기.
          postSpaceCount = Str_Get_ThisLinePostSpaceCount(editor_edit_Form->_editbuf, lineStartIndex);

          //행 끝에 공백이 없다면 처리할 필요가 없다.
          if(postSpaceCount > 0)
          {
            STR_Get_ThisLineEndIndex(editor_edit_Form->_editbuf, lineStartIndex, &lineEndIndex);

            //[선택]
            //{
                editor_edit_Form->History_SelectX(lineEndIndex - postSpaceCount,
                                                  lineEndIndex,
                                                  false,
                                                  NULL,
                                                  false,
                                                  false,
                                                  true);

            //}

            //[선택 문자열 삭제]
            //{
                editor_edit_Form->_EDIT_SelectDelete();

            //}

          }

        }

        //[진행바:진행]
        //{
            ide_buttons_Form->_progress->_Progress(l);

            Application->ProcessMessages();

            //[Linux:wine 지원]
            //{
                //[!]{----------------------------------------------------------------
                //[Linux:wine] 에서는 진행의 경우 [진행바] 변화가 반영되지 않는다.
                //처리 속도가 윈도우보다 훨씬 빠르기 때문에 GUI 구현이 제대로 안된다.
                //따라서, [Linux:wine] 의 경우는 GUI 를 충분히 구현할수 있는 <10ms>
                //지연 시간을 준다.
                //처리 속도가 빠른 CPU 일수록 큰 값이 필요. FX8300 에서 10ms 면 넉넉.
                //}-------------------------------------------------------------------

                if(_ide_Option.wine == true) { Sleep(10); }

            //}

        //}

        //[다음행 시작 위치 얻기]
        //{
            //<반환값:false> 인 경우는 현재 행이 마지막행이므로 종료.
            if(STR_Get_NextLineStartIndex(editor_edit_Form->_editbuf, lineStartIndex, &lineStartIndex) != true) break;

        //}

      }

      //[진행바:감추기]
      //{
          ide_buttons_Form->_Progress_Visible(false);

      //}
      
      //[입력지정자:스텔스 해제]
      //{
          editor_edit_Form->_caret->_Stealth(false);

      //}

      //[_EditBuf_Text():허용]
      //{
          editor_edit_Form->_editBuf_Text_No_Select = false;

      //}

      //[문서수정:기록]
      //{
          //문서가 수정됬음을 기록한다.
          editor_edit_Form->_EDIT_Changed(false, true);
          
      //}

      //[묶음주석 정보 얻기]
      //{
          //[!]{----------------------------
          //이 경우는 무조건 한번 처리한다.
          //}-------------------------------

          //[묶음주석] 정보 수집.
          editor_edit_Form->_CommentBlock_Info(false);

          //[다시 그리기]{----------------------------------------------------
          //[붙이기] 로 바꾸게 되므로 너무 많은 시간을 소비하게 되어 마지막에
          //딱, 한번만 다시 그려준다.
          editor_edit_Form->_EditBuf_Text();
          //}-----------------------------------------------------------------

      //}

  //}

}

void __fastcall Ide_Menu_SpaceArrangeAll(void)
{
  //[2021.07.27.화][생성]{-------------------------------------------------------
  //[Tree:설계문서] 에 등록돼 있는 모든 문서를 대상으로 [공백정리] 를 수행한다.
  //
  //[방법]-----------------------------------------------------------------------
  //
  //1) 해당 문서를 연다.
  //2) 열린 문서의 공백을 정리.
  //3) 정리후 열려 있던 문서라면 그대로 두고, 닫혀 있던 문서라면 다시 닫아 준다.
  //4) [Tree:설계문서] 에 등록된 모든 문서의 공백을 정리할때가지 1) - 3) 반복.
  //
  //일단 문서를 연다음, <Ide_Menu_SpaceArrange()> 로 간단하게 처리한다.
  //단, <Ide_Menu_SpaceArrange()> 는 현재 보이는 문서를 대상으로 처리한다.
  //
  //[주의]-----------------------------------------------------------------------
  //
  //[Tree:설계문서] 에 처리할 문서가 없다면 처리하지 않는다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      class DATABASE  *db_;

      struct TREE     *tree_;

      int  nodeIndex;

      //<"c":nodeIndex> 의 직계 항목의 마지막 index.
      int  node1stItemEndIndex;

      //<"c":nodeIndex> 의 모든 하위 항목의 [시작 - 끝] index.
      int  nodeItemStartIndex;
      
      int  nodeItemEndIndex;

      int  node1stItemCount;


      char  pathNameExt[1024*10];

      int  i;

      char  *list;
      int    listCount;

      int    matchLineNum;

      bool   noClose;

  //}

  //[새설계묶음인가?]
  //{
      //[!]{------------------------------------------------------------------------------------------
      //현재 [새설계묶음] 상태인 경우는 먼저 <*.gprj> 로 저장할 것을 요구하고 더이상 처리하지 않는다.
      //[새설계묶음] 인 경우는 아무 문서도 등록돼있지 않으므로 처리할 필요가 없다.
      //}---------------------------------------------------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        return;

      }

  //}

  //[설계묶음 저장]
  //{
      IDE_Project_Save(false);

  //}

  //[문서 저장]
  //{
      IDE_File_SaveAll();

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&db_);

  //}

  //[Tree 치환]
  //{
      tree_ = &(tree_tree_Form->_tree[d_TREE_project]);

  //}

  //[<설계문서> 에 문서가 존재하나?]
  //{
      //[설계문서] 의 직계항목수 얻기.
      tree_tree_Form->_Tree_Get_Node_ItemCount(tree_,
                                               "c", //[설계문서] 옹이 이름.
                                               &nodeIndex,
                                               &node1stItemCount);

      //문서가 존재하지 않는다면 더이상 처리하지 않고 종료.
      if(node1stItemCount == 0) return;

  //}

  //[<설계문서> 하위 항목 범위 얻기]
  //{
      //[!]{-----------------------------------------------------------------
      //[설계문서] 안의 모든 <*.c>, <*.h> 문서를 순서대로 처리하기 위하여
      //[설계문서] 를 [옹이] 로 하는 모든 하위 항목의 <index> 범위를 구한다.
      //}--------------------------------------------------------------------

      tree_tree_Form->_Tree_Get_NodeInfo(tree_,
                                         "c", //[설계문서] 옹이 이름.
                                         &nodeIndex,
                                         &node1stItemEndIndex,
                                         &nodeItemEndIndex);

      nodeItemStartIndex = nodeIndex + 1;

      nodeItemEndIndex   = nodeItemEndIndex;

  //}

  //[목록:생성]
  //{
      //목록을 담을 공간을 생성.
      list = new char[1024*(nodeItemEndIndex - nodeItemStartIndex + 1)];

      //초기화.
      STR_Assign(list, "");

      listCount = 0;

  //}

  //[공백 정리]
  //{
      //[!]{----------------------------------------------------------------------
      //<*.c>, <*.h> 구분 없이 순서대로 문서를 열어 공백을 정리후 다시 닫아 준다.
      //단, 원래 열려있었던 문서라면 닫지 않고 그대로 둔다.
      //
      //[중복 처리 금지]**********************************************************
      //
      //1) 현재 처리할 <item.txt> 가 [목록] 에 존재하는 지 [행단위] 로 비교.
      //
      //2) 처리후 처리한 <item.txt> 를 [목록] 에 [행단위] 로 기록.
      //
      //3) 모두 처리할때까지 1) - 2) 반복.
      //
      //즉, 처리한 것을 기록해서 중복 처리를 방지하는 방법을 사용한다.
      //}-------------------------------------------------------------------------

      for(i = nodeItemStartIndex, noClose = false; i <= nodeItemEndIndex; i++)
      {
        //[목록 중복 확인]
        //{
            //[!]{------------------------------------------------------
            //현재 처리할 항목이 이미 처리한 목록에 등록돼 있는지 확인.
            //}---------------------------------------------------------

            STR_Search_LineStr_knowLineCount(list,
                                             listCount,
                                             tree_tree_Form->_Item_Txt_StrPtr3(tree_, i),
                                             &matchLineNum);

            //중복 항목이 존재하는 경우는 처리하지 않고 계속 진행.                                 
            if(matchLineNum >= 0) continue;

        //}

        //[전체:경로이름확장자 합성]
        //{
            STR_Assign(pathNameExt, db_->projectpath);

            STR_Add(pathNameExt, tree_tree_Form->_Item_Txt_StrPtr3(tree_, i));

        //}

        //[문서 열기]
        //{
            //[이미 열려있는 문서인가?]
            //{
                if(editor_edit_Form->_TEXTINFO_GetIndex_withFILEname(pathNameExt) >= 0)
                {
                  //현재 문서 처리 후 닫기 금지.
                  noClose = true;

                }
                else
                {
                  noClose = false;

                }

            //}

            editor_top_Form->_List_Add(pathNameExt);

        //}

        //[공백 정리]
        //{
            Ide_Menu_SpaceArrange();

        //}

        //[저장]
        //{
            IDE_File_Save();

        //}

        //[닫기]
        //{
            if(noClose == false)
            {
              editor_top_Form->_List_Delete(editor_edit_Form->_textinfo_index);

            }

        //}

        //[목록에 기록]
        //{
            //[!]{------------------------------------------------------------------
            //중복 처리 금지를 위해서, 현재 처리 항목을 [목록] 에 [행단위] 로 기록.
            //}---------------------------------------------------------------------

            STR_Add(list, tree_tree_Form->_Item_Txt_StrPtr3(tree_, i));

            STR_Add(list, "\r\n");

            listCount++;

            //msg_msg_Form->_PrintAdd(d_msg_debug, tree_tree_Form->_Item_Txt_StrPtr3(tree_, i));
            //msg_msg_Form->_PrintAdd(d_msg_debug, "\r\n");

        //}

      }

  //}

  //[목록:삭제]
  //{
      delete [] list;

  //}
  
}

//------------------------------------------------------------------------------
//[메뉴 관련]-------------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_Menu_GVMS_Install(//[2011.11.10.목][추가!!!]
                                      //구동할 <GVMS> 를 직접 지정한 경우만 사용.
                                      //일반적으로는 NULL 로 하여 대화상자를 보여준다.
                                      char  *pGvms,
                                      //즉시 실행까지 하는 경우는 <true>.
                                      bool   pReset)
{
  //[2010.07.05.월][생성!!!]{---------------------------------------------------
  //[가상기계(*.gvms)] 만 열어서 관련 환경으로 설정하고 바로 실행해 준다.
  //즉, [설계묶음] 을 거치지 않고 생성된 [가상기계(*.gvms)] 만 불러서 실행한다.
  //[가상기계] 구동만을 위한 [전용 환경] 을 만들어 준다.
  //
  //[2011.11.10.목][수정!!!]----------------------------------------------------
  //<pGvms> 경로를 직접 지정한 경우는 [GVMS 열기 대화상자] 등을 보여주지 않고
  //바로 처리한다.
  //
  //<pGvms:NULL> 인 경우는 기존방식으로 일반적인 처리 수행.
  //
  //[2012.03.14.수][중요수정!!!]------------------------------------------------
  //[가상기계:전용환경] 으로 전환시 현재 [설계묶음] 을 닫지 않는 것으로 수정.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      char  tempStr[OPT_lineStrSize];

      int   i;

  //}

  //[환경변수]
  //{
      //[2023.01.29.일][추가]
      struct  IDE_OPTION  *ideOption_;

      IDE_Get_Option(&ideOption_);

  //}

  //[열려있는 [설계묶음] 이 있나?]
  //{
      //[2012.03.14.수][중요수정!!!]{-------------------------------
      //현재 열려있는 [설계묶음] 을 닫지 않고 처리하는 것으로 수정.
      //[가상기계:전용환경] 을 사용하는 모든 경우에 해당.
      //}-----------------------------------------------------------

      /*
      //[!]{------------------------------------------------
      //현재 열려 있는 [설계묶음] 이 있다면 모두 닫아 준다.
      //}---------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_tree[d_TREE_project].items[0].txt, "새설계묶음") != true)
      {
        STR_Assign(tempStr,
                   "현재 작업 중인 [설계묶음] 이 존재 합니다.\r\n"
                   "작업 중인 [설계묶음] 을 자동으로 저장하려면 [확인] 을 누르고\r\n"
                   "저장하지 않고 그냥 닫으려면 [취소] 를 눌러 주세요.");

        //현재 작업 중인 <*.gprj> 에 대한 처리를 먼저 수행해 준다.
        if(ide_msgbox_Form->_MsgBox_Ok_Cancle(d_MSGBOX_info, tempStr) == true)
        {
          //[현재 설계묶음 저장]
          //{
              //[!]{-----------------------------------
              //현재 작업 중인 [설계묶음] 을 저장한다.
              //전용 함수로 간단하게 처리한다.
              //}--------------------------------------

              IDE_Project_Save(false);

          //}

        }
        else
        {
          //[취소] 가 눌린 경우는 [설계묶음] 을 저장하지 않는다.

        }

        //[현재 설계묶음 관련 문서 닫기]
        //{
            //만일 현재 저장되지 않음 문서가 있어서 [닫기] 시에 [대화상자] 가 나온
            //경우는 더이상 처리하지 않고 종료 해야 한다.
            //자세한 내용은 _List_DeleteAll() 함수의 설명을 참고 한다.
            if(editor_top_Form->_List_DeleteAll() != true) return;

        //}

        //[새설계묶음으로 초기화]
        //{
            //[2011.07.13.수][수정!!!]
            //[검증식 보기창] 도 전부 초기화 한다---------------------------v
            ide_tree_Form->_Tree_All_Init(d_Tree_Prj | d_Tree_Info | d_Tree_DbgExp);

        //}

      }
      */

  //}

  //[현재 [가상기계 전용 환경] 인가?]
  //{
      if(_ide_Option.gvmMode == true)
      {
        //[!]{------------------------------------------------------------
        //현재 [가상기계 전용 환경] 이 이미 구동중이다.
        //이 경우는 현재 실행중인 [가상기계] 를 정지, 삭제해 주어야 한다.
        //}---------------------------------------------------------------

        //[현재 [맷돌가상구동] 인가?]
        //{
            //[2010.07.07.수][추가!!!]{-------------------
            //현재 [맷돌가상구동] 인 경우만 처리가능하다.
            //}-------------------------------------------

            if(ide_buttons_Form->_vmosSim_CheckBtn->_checked != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[가상기계<*.gvms>] 는 [맷돌가상구동] 에서만 설치 가능합니다.");

              //더이상 처리하지 않는다.
              return;

            }

        //}

        ide_caption_Form->_Caption("::: 가상기계 전용 환경 ::: ");

      }
      else
      {
        //[!]{------------------------------
        //이 경우는 [맷돌 개발환경] 상태다.
        //}---------------------------------

        //[맷돌 가상구동/직접연결 모두 해제된 상태인가?]
        //{
            //[!]{-------------------------------------------------------------
            //[가상구동/직접연결] 모두 해제된 상태에서만 처리를 시작할수 있다.
            //}----------------------------------------------------------------

            if((ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) ||
               (ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true))
            {
              //이 경우는 [가상기계] 구동환경으로 진입할수 없다.

              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[가상기계<*.gvms>] 전용 구동은 [맷돌가상구동] 이나\r\n"
                                       "[맷돌직접연결] 모두 해제된 상태에서만 시작할수 있습니다.");

              //더이상 처리하지 않는다.
              return;

            }

        //}

      }

  //}

  //[<*.gvms> 를 열 대화상자 보이기]
  //{
      //[!]{------------------------------------------------------------------
      //실행할 [가상기계:<*.gvms>] 를 열 대화상자를 보여준다.
      //아무 것도 열지 않은 경우는 바로 종료한다.
      //
      //[2011.11.10.목][추가!!!]----------------------------------------------
      //직접 <GVMS> 를 지정하지 않은 경우만 [GVMS 열기 대화상자] 를 보여준다.
      //}---------------------------------------------------------------------

      if((pGvms == NULL) || (pGvms[0] == '\0'))
      {
        //[!]{-----------------------------------------------------------------
        //이 경우는 지정된 GVMS 가 없으므로, [GVMS 열기 대화상자] 를 보여준다.
        //}--------------------------------------------------------------------

        //[확장자 설정]
        //{
            main_Form->file_OpenDialog->Filter = "가상기계(*.gvms)|*.gvms";

        //}

        //아무것도 열지 않은 경우는 바로 종료한다.
        if(main_Form->file_OpenDialog->Execute() != true) return;

      }

  //}

  //[가상기계 전용 개발환경 인가?]
  //{
      //[2010.07.07.수][추가!!!]{----------------------------
      //이미 [가상기계 전용 환경] 인 경우는 처리하지 않는다.
      //}----------------------------------------------------

      if(_ide_Option.gvmMode  == true) goto lbGVMS_Install;

  //}

  //[개발환경 설정]
  //{
      //[!]{--------------------------------------------------
      //[개발환경] 을 [가상기계 실행 전용] 환경으로 변경한다.
      //}-----------------------------------------------------

      //메뉴에서 [가상기계] 항목을 제외한 모든 항목을 [무효화] 한다.
      //{
          for(i = 0; i < d_menu_count; i++)
          {
             //가상기계 항목만 유효하고 나머지는 전부 무효로 바꾼다.
            if(i == d_menu_gvm_ix) continue;

            ide_menu_Form->_ItemEnable(i, false);

          }

      //}

      //[실행/정지/재기동] 버튼을 제외한 모든 버튼을 무효화 한다.
      //{
          //[무효화]
          //{
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save]->_Enable(false);
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save_all]->_Enable(false);
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_open]->_Enable(false);

              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_check]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_compile]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_link]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_build]->_Enable(false);

          //}

          //[무효화]
          //{
              //[2023.01.27.금][수정]{-------------------------------------------------------
              //[GVMS] 가 완전히 부팅된 후 [유효화] 하기 위하여 여기서는 일단 [무효화] 한다.
              //이는, [GVMS] 가 완전히 부팅되기 전에 실행버튼(Reset)을 누르는 경우 VMOS 가
              //멈춰, [맷돌-IDE] 전체를 재실행 해야 하는 경우를 방지하기 위한것.
              //
              //이 함수 마지막 부분에서 [GVMS] 부팅이 완전히 완료된 후 [활성화] 한다.
              //}----------------------------------------------------------------------------

              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_download]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_verify]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_erase]->_Enable(false);

              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_run]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_stop]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_reset]->_Enable(false);

          //}

      //}

      //[탭] 을 무효화 한다.
      //{
          ide_buttons_Form->_tabs->_Enable(false);

      //}

      //[맷돌 가상구동/직접연결] 확인 상자 해제/무효화.
      //{
          //확인 해제.
          ide_buttons_Form->_vmosSim_CheckBtn->_Checked(false);
          ide_buttons_Form->_vmosMdl_CheckBtn->_Checked(false);

          //무효화.
          ide_buttons_Form->_vmosSim_CheckBtn->_Enable(false);
          ide_buttons_Form->_vmosMdl_CheckBtn->_Enable(false);

      //}

      //창관련 버튼 중 [최대화/닫기] 버튼을 [무효화] 시킨다.
      //{
          ide_menu_Form->_max_bmpbtns->_Enable(false);
          ide_menu_Form->_close_bmpbtns->_Enable(false);

      //}

      //필요한 부분만 보이도록 IDE 전체 높이를 조정한다.
      //{
          //최대화 돼있는 경우라도 무조건 기본상태로 변경한다.
          main_Form->WindowState = wsNormal;

          //[!]{----------------------------------
          //먼저 기본크기 변경이 반영되도록 한다.
          //Application->ProcessMessages();
          //}-------------------------------------

          //[현재 <위치/크기> 정보 [환경변수] 에 저장]
          //{
              //[주의!!!]{-------------------------------------------------------------
              //[최대화] 시에만 저장되는 값이며, [크기조정] 등에서는 저장되지 않으므로
              //반드시 여기서 현재 상태를 구해서 저장.
              //}----------------------------------------------------------------------

              _ide_Option.ideRect.left   = main_Form->Left;
              _ide_Option.ideRect.top    = main_Form->Top;
              _ide_Option.ideRect.width  = main_Form->Width;
              _ide_Option.ideRect.height = main_Form->Height;

          //}

          //[IDE 크기 정보 백업]
          //{
              //[2018.02.26.월][추가!!!]{----------------------------------------
              //IDE 자체 기본적인 [최대화/기본화] 를 위하여 현재 크기 정보 백업.
              //이는 GVMS 구동 환경과 기본 환경을 구분하기 위한것.
              //<Ide_Menu_GVM_Ide()> 에서 복구된다.
              //}----------------------------------------------------------------

              _ide_Option.ideRectBackup = _ide_Option.ideRect;

          //}

          //[크기 설정]
          //{
              main_Form->Constraints->MinHeight = 91;
              main_Form->Constraints->MinWidth  = 740;

              main_Form->Width  = main_Form->Constraints->MinWidth;
              main_Form->Height = main_Form->Constraints->MinHeight;

          //}

          //[현재 <위치/크기> 정보 [환경변수] 에 저장]
          //{
              //[복구] 할때를 위하여 현재 상태를 저장.
              _ide_Option.ideRect.left   = main_Form->Left;
              _ide_Option.ideRect.top    = main_Form->Top;
              _ide_Option.ideRect.width  = main_Form->Width;
              _ide_Option.ideRect.height = main_Form->Height;

          //}

      //}

  //}

  //[가상기계 전용 상태 기록]
  //{
      //[!]{---------------------------------------------------------------------
      //현재 [가상기계 전용 구동] 환경이 시작되었음을 기록한다.
      //반드시 [가상구동기] 를 실행하기 전에 처리해야 한다.
      //이는, <_EVENT_Click_vmosSim_CheckBtn()> 함수를 사용하는데 이 함수 안에서
      //<gvmMode> 를 구분하여 처리하기 때문이다.
      //}------------------------------------------------------------------------

      _ide_Option.gvmMode = true;

  //}

  //[맷돌 가상구동기 실행]
  //{
      //[!]{------------------------------------------
      //자동으로 [맷돌가상구동] 을 선택하고 실행한다.
      //}---------------------------------------------

      ide_caption_Form->_Caption("VMOS 가상구동 준비중...");

      //_EVENT_Click_vmosSim_CheckBtn() 의 동작을 위하여 [맷돌가상구동] 에 확인을 표시한다.
      ide_buttons_Form->_vmosSim_CheckBtn->_Checked(true);

      //전용함수로 간단하게 처리한다.
      ide_buttons_Form->_EVENT_Click_vmosSim_CheckBtn();

      //[VMOS 구동 시작 확인]
      //{
          //[2023.01.29.일][추가]{----------------------------------------------------
          //무조건 1.5 초를 대기하는 방식보다는, 확실하게 VMOS 가 구동되기 시작했는지
          //확인하는 방법으로 수정한다.
          //
          //이는 [Wine] 에서 GVMS 실행중 목록의 변경이 이루어지는 것을 막기 위한것.
          //동시에 처리 속도를 빠르게 하기 위한것.
          //}-------------------------------------------------------------------------

          while(!VMOS_Ready_GVMS_Install())
          {
            Application->ProcessMessages();

          }

          //[이전방식][주석처리]{----------------------------
          //VMOS 가 완전히 초기화 될때가지 일정 시간을 준다.
          //Sleep(1500);
          //}------------------------------------------------

      //}

      //[!]{********************************************************
      //여기까지 VMOS 구동이 시작되고, GVMS 설치 준비까지 완료된것.
      //}***********************************************************

  //}

  lbGVMS_Install:

  //[가상기계 설치]
  //{
      //[!]{------------------
      //<*.gvms> 를 설치한다.
      //}---------------------

      //먼저 VMOS 를 정지시킨다.
      if(Ide_Ctrl_Stop() != true) return;

      //지우기.
      if(Ide_Ctrl_Erase() != true) return;

      //[GVMS 지정 구분 처리]
      //{
          //[2011.11.10.목][수정!!!]---------------------------
          //직접 <GVMS> 를 지정하지 않은 경우를 구분하여 처리.
          //}--------------------------------------------------

          if((pGvms == NULL) || (pGvms[0] == '\0'))
          {
            //위에서 연 <*.gvms> 를 설치.
            if(Ide_VMOS_Download_Gvms(((AnsiString)main_Form->file_OpenDialog->FileName).c_str()) != true) return;
          }
          else
          {
            //<pGvms> 로 지정된 <GVMS> 를 설치.
            if(Ide_VMOS_Download_Gvms(pGvms) != true) return;

          }

      //}

      //[재기동] 없이 [실행] 할수 있도록 VMOS 를 초기화후 정지시킨다.
      if(Ide_Ctrl_ResetStop() != true) return;

  //}

  //[가상기계 실행]
  //{
      //[!]{-----------------------------
      //설치된 [가상기계] 를 실행시킨다.
      //}--------------------------------

      //[재기동] 시킨다.
      if(pReset == true)
      {
        //[2011.11.10.목][추가!!!]{----------------
        //[즉시실행] 하는 경우는 [실행] 까지 처리.
        //}----------------------------------------

        ide_buttons_Form->_EVENT_HwResetButton_Click();

      }

      //[2010.07.07.수][수정!!!]{--------------------------------------------------
      //[재설치] 를 위하여 [설치] 만 하고 실행하지는 않는다.
      //[실행] 은 [실행/재기동] 두가지 방법으로 가능하므로 자동실행은 하지 않는다.
      //따라서, 위의 실행문은 주석으로 처리한다.
      //}--------------------------------------------------------------------------

  //}

  //[현재 제목줄에 가상기계 이름 표시]
  //{
      //[2010.07.07.수][추가!!!]{-------------------------------------------
      //개발환경 [제목줄] 에 현재 [가상기계(*.gvms)] 의 [이름] 을 표시한다.
      //}-------------------------------------------------------------------

      i = STR_Assign(tempStr, "가상기계 : < ");

      //[GVMS 지정 구분 처리]
      //{
          //[2011.11.10.목][수정!!!]---------------------------
          //직접 <GVMS> 를 지정하지 않은 경우를 구분하여 처리.
          //}--------------------------------------------------

          //순수 [이름.확장자] 만 얻는다.
          if((pGvms == NULL) || (pGvms[0] == '\0'))
          {
            //[대화상자자] 를 연경우.
            STR_GetFileNameOnly(((AnsiString)main_Form->file_OpenDialog->FileName).c_str(), &(tempStr[i]));

          }
          else
          {
            //<pGvms> 로 지정된 경우.
            STR_GetFileNameOnly(pGvms, &(tempStr[i]));

          }

      //}

      STR_Add(tempStr, " >");

      ide_caption_Form->_Caption(tempStr);

  //}

  //[<실행/정지/재기동> 버튼 유효화]
  //{
      //[2023.01.27.금][추가]{------------------------------------------------------------
      //[GVMS] 가 완전히 부팅된 후 관련 버튼을 [활성화] 한다.
      //
      //이는, [GVMS] 가 아직 부팅 중인 경우에 [실행(Reset)] 버튼이 눌리는 경우 치명적인
      //VMOS 구동 오류로 VMOS 가 멈춰 [맷돌-IDE] 를 재실해야 하는 경우를 방지하기 위한것.
      //}---------------------------------------------------------------------------------

      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_download]->_Enable(true);
      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_verify]->_Enable(true);
      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_erase]->_Enable(true);

      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_run]->_Enable(true);
      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_stop]->_Enable(true);
      ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_reset]->_Enable(true);

  //}

  //[실행방법 도움 문자열 출력]
  //{
      //[2023.01.29.일][추가]{----------------------------------
      //[버튼:실행] 을 눌러야 GVMS 가 실행된다는 것을 알려준다.
      //}-------------------------------------------------------

      ide_buttons_Form->_tabs->_Blank_Text(" 실행하려면 이 버튼을 누르세요-------^",
                                           ideOption_->color_0);

  //}

}

void __fastcall Ide_Tree_Gvm_GVMX_Install(//<*.gvmx> 의 [경로이름확장자].
                                          char  *pGvmx,
                                          //즉시 실행까지 하는 경우는 <true>.
                                          bool   pReset)
{
  //[2011.11.16.수][생성!!!]{--------------------------------------------
  //이 함수는 <Ide_ListSubMenu_GVMX_Install()> 를 바탕으로 만든것으로
  //<*.gvmx> 의 [경로이름확장자] 를 직접 전달 받는 것만 다르다.
  //
  //[Tree:설계묶음:가상기계] 에 등록된 <*.gvmx> 를 바로 실행하는데 사용.
  //이 경우 [가상기계 전용환경] 에서 [설치] 하지 않고 조건에 맞는 경우
  //[일반설치] 로 바로 설치.
  //이는 { 메뉴 : GVMX(맷돌) } 의 처리와 같다.
  //}--------------------------------------------------------------------

  //[주의!!!]--------------------------------------------------------
  //<Ide_ListSubMenu_GVMS_Install()> 과는 달리 [가상기계전용환경] 을
  //사용하지 않으며(현재 상태에서바로 설치가능),
  //반드시 <[v]맷돌직접연결> 이 설정된 상태여야 한다.
  //
  //이 함수는 [맷돌-통합개발환경:기본상태] 에서만 동작하므로, 현재
  //[가상기계 전용환경] 의 경우는 고려할 필요가 없다.
  //
  //[참고!!!]--------------------------------------------------------
  //이 함수는 처리시 [설계묶음] 을 닫지 않는다.
  //}----------------------------------------------------------------

  //[VAR]
  //{
      //설명문 정리.
      char  infoStr[OPT_lineStrSize] = {""};
      char  tempStr[OPT_lineStrSize] = {""};

      int   gvmxSize;

      int   s;

  //}

  //[<[v]맷돌직접연결> 인가?]
  //{
      //[!]{-----------------------------------------------
      //[맷돌(G.MTDL.X)] 에 GVMX 를 설치하는 것으로 반드시
      //<[v]맷돌직접연결> 상태여야 한다.
      //}--------------------------------------------------

      if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "가상기계(GVMX)를 맷돌(G.MTDL.X)에 설치하려면\r\n"
         "\"[v]맷돌직접연결\" 로 설정돼 있어야 합니다."
        );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[<GVMX> 정보 만들기/표시]
  //{
      //[!]{-------------------------------------------------------
      //설치하는 <GVMX> 에 대한 간단한 3개 정보를 보여준다.
      //이는 [하위항목] 으로 바로 설치하므로 사용자가 어떤 GVMX 가
      //설치되고 있는지 까먹을수 있기 때문이다.
      //
      //[맷돌운영체제] : vmos_at45db041x_1_m
      //[가상기계이름] : 경로\이름.gvmx
      //[가상기계크기] : 0x100(126 바이트)
      //}----------------------------------------------------------

      //[현재 <맷돌 운영체제> 이름 얻기]
      //{
          s = STR_Assign(infoStr, "<맷돌운영체제> : ");

          if(Ide_Mtdl_Get_OS_Name(&(infoStr[s])) != true) return;

          s = STR_Add(&(infoStr[s]), "\r\n");

      //}

      //[가상기계이름]
      //{
          s = STR_Add(infoStr, "<가상기계이름> : ");
          s = STR_Add(infoStr, pGvmx);
          s = STR_Add(&(infoStr[s]), "\r\n");

      //}

      //[가상기계크기]
      //{
          s = STR_Add(infoStr, "<가상기계크기> : 0x");

          //크기얻기.
          FILE_Size(pGvmx, &gvmxSize);

          CONV_LongVal_To_Hex2(gvmxSize, tempStr);
          s = STR_Add(&(infoStr[s]), tempStr);

          STR_Add(infoStr, "(");
          CONV_LongVal_To_Str(gvmxSize, 0, false, tempStr);
          s = STR_Add(&(infoStr[s]), tempStr);

          STR_Add(infoStr, " 바이트)\r\n");

      //}

      //[<출력창> 에 출력]
      //{
          //[!]{----------------------------------------------
          //[맷돌-통합개발환경] 아래 [출력창] 에 출력해 준다.
          //}-------------------------------------------------

          msg_msg_Form->_PrintAddLine(0, infoStr);

      //}

  //}

  //[GVMX 설치]
  //{
      //[!]{-----------------------------------------------------------------------
      //해당 <GVMX> 를 [맷돌(G.MTDL.X)] 에 설치.
      //
      //<[v]맷돌직접연결> 상태로 시작하므로 <[v]맷돌가상구동> 에서 구동되는
      //[맷돌C:GVMS] 안에서 사용되는 API 와 [충돌] 할수는 없다.
      //따라서, API 용으로 만든 편리한 함수를 사용하여 처리한다.
      //
      //[주의!!!]------------------------------------------------------------------
      //[GVMX] 가 너무 큰(100 KByte 이상) 경우는 설치후 확인과정에서 많은 시간이
      //걸리지만, 정확하게 하기 위하여 일단 [확인] 까지 자동 처리하는 것으로 한다.
      //단, [실행] 시키는 것은 사용자 의도로 남긴다.
      //}--------------------------------------------------------------------------

      //[설치]
      //{
          //실행시키지 않는다------------v
          if(Ide_API_GVMX_Install(pGvmx, false, NULL) != true) return;

      //}

      //[확인]
      //{
          if(Ide_API_GVMX_Verify(pGvmx, NULL) != true) return;

      //}

  //}

  //[가상기계 실행]
  //{
      //[!]{--------------------------------------
      //설치된 [가상기계] 를 [조건] 에 따라 실행.
      //}-----------------------------------------

      //[재기동] 시킨다.
      if(pReset == true)
      {
        //Ide_Mdl_Stop() 함수는 위에서 이미 처리했으므로 여기서는 사용하지 않는다.
        //---------------v
        if(Ide_Mdl_Reset(false) != true) return;

      }

  //}

}

bool __fastcall Ide_API_GVMX_Install(//[맷돌] 에 설치할 [가상기계(GVMX)] 의 [경로이름확장자].
                                     char              *pGvmx,
                                     //즉시 실행까지 하는 경우는 <true>.
                                     bool               pReset,
                                     //[2011.11.11.금][추가!!!]
                                     //<PCC:VMOS> 와 동기화를 위한것(미사용인 경우 NULL).
                                     struct VMOS_SYNC  *pVmosSync)
{
  //[2011.11.10.목][생성!!!]{----------------------------------------------------------------
  //<Ide_Menu_GVMX_Install()> 함수를 거의 그대로 사용하되, [맷돌C용 API] 를 위하여
  //기능을 수정한다.
  //
  //즉, [대화상자] 를 보여주지 않고 지정된 [가상기계(GVMX)] 를 직접 [맷돌] 에 설치한다.
  //
  //<맷돌C:API> 는 항상 [맷동가상구동] 에서 동작하므로 <[v]맷돌직접연결> 에 표시하지 않고
  //내부적으로 직접 처리해야 한다.
  //이는 [맷돌가상구동] 과 [맷돌직접연결] 은 둘다 동시에 사용할수 없기 때문이다.
  //
  //[참고!!!]--------------------------------------------------------------------------------
  //[맷돌C] 로 만든 AVR-ISP 의 경우는 반드시 [맷돌] 에 대응하는 [가상기계] 가 설치돼
  //있어야 하는데, [맷돌-통합개발환경] 에서 모든 것을 처리하는 경우는 [맷돌] 이 연결돼있거나
  //동작중이 아닌 경우 [가상기계] 를 설치할수 없어 기회가 없게 된다.
  //이 경우, 아예 [가상구동] 되는 AVR-ISP 에서 직접 <GVMX> 를 [맷돌] 에 설치하면 쉽다.
  //얼마든지 반복적으로 재설치 할수 있어 더 유리하고, 통제권이 [GVMS] 쪽에 있으므로
  //일원화 되어 관리하기 쉽다.
  //}----------------------------------------------------------------------------------------

  //[가상기계 설치]
  //{
      //[!]{--------------------------------------------------------------------------
      //<*.gvmx> 를 설치한다.
      //
      //[주의!!!]---------------------------------------------------------------------
      //<맷돌C:API> 상에서 처리되므로 현재 <[v]맷돌가상구동> 상태이므로
      //<[v]맷돌가상구동> 상태 여부를 따지지 않도록 직접 [맷돌] 관련 함수를 사용한다.
      //}-----------------------------------------------------------------------------

      //먼저 [맷돌] 를 정지시킨다.
      if(Ide_Mdl_Stop() != true) { return(false); }

      //지우기.
      if(Ide_Mdl_Erase() != true) return(false);

      //위에서 연 <*.gvmx> 를 설치한다.
      if(Ide_Mdl_Download_Gvmx(pGvmx, pVmosSync) != true) return(false);

      //[재기동] 없이 [실행] 할수 있도록 VMOS 를 초기화후 정지시킨다.
      if(Ide_Mdl_ResetStop() != true) return(false);

  //}

  //[가상기계 실행]
  //{
      //[!]{-----------------------------
      //설치된 [가상기계] 를 실행시킨다.
      //}--------------------------------

      //[재기동] 시킨다.
      if(pReset == true)
      {
        //[즉시실행] 하는 경우는 [실행] 까지 처리.

        //[주의!!!]---------------------------------------------------------------------
        //<맷돌C:API> 상에서 처리되므로 현재 <[v]맷돌가상구동> 상태이므로
        //<[v]맷돌가상구동> 상태 여부를 따지지 않도록 직접 [맷돌] 관련 함수를 사용한다.
        //}-----------------------------------------------------------------------------

        //Ide_Mdl_Stop() 함수는 위에서 이미 처리했으므로 여기서는 사용하지 않는다.
        //---------------v
        if(Ide_Mdl_Reset(false) != true) return(false);

      }

  //}

  //여기까지 온 것은 이상없음.
  return(true);

}

bool __fastcall Ide_API_GVMX_Verify(//[맷돌] 에 설치할 [가상기계(GVMX)] 의 [경로이름확장자].
                                    char              *pGvmx,
                                    //<PCC:VMOS> 와 동기화를 위한것(미사용인 경우 NULL).
                                    struct VMOS_SYNC  *pVmosSync)
{
  //[2011.11.10.목][생성!!!]{------------------------------------------
  //<Ide_API_GVMX_Install()> 과 짝을 이루어 사용되는 [비교/확인] 함수.
  //<맷돌C> 에서 선택적으로 사용된다(꼭 사용할 필요는 없다).
  //실제는 API 를 지원해주기 위한 것이다.
  //
  //자세한 설명은 <Ide_API_GVMX_Install()> 처음 설명을 참고한다.
  //}------------------------------------------------------------------

  //[가상기계 설치]
  //{
      //[!]{--------------------------------------------------------------------------
      //<*.gvmx> 를 비교/확인한다.
      //
      //[주의!!!]---------------------------------------------------------------------
      //<맷돌C:API> 상에서 처리되므로 현재 <[v]맷돌가상구동> 상태이므로
      //<[v]맷돌가상구동> 상태 여부를 따지지 않도록 직접 [맷돌] 관련 함수를 사용한다.
      //}-----------------------------------------------------------------------------

      //먼저 [맷돌] 를 정지시킨다.
      if(Ide_Mdl_Stop() != true) { return(false); }

      //위에서 연 <*.gvmx> 를 설치한다.
      if(Ide_Mdl_Verify_Gvmx(pGvmx, pVmosSync) != true) return(false);

  //}

  //여기까지 온 것은 이상없음.
  return(true);

}

void __fastcall Ide_Menu_GVMX_Install(void)
{
  //[2010.07.07.수][생성!!!]{----------------------------------------------------------
  //[가상기계(*.gvmx)] 만 열어서 관련 환경으로 설정하고 바로 실행해 준다.
  //즉, [설계묶음] 을 거치지 않고 생성된 [가상기계(*.gvmx)] 만 불러서 처리한다.
  //
  //맷돌(G.MTDL.A) 를 대상으로 이미 만들어 놓은 [가상기계(*.gvmx)] 를
  //[설치/지우기/실행/정지/재기동] 할때 사용한다.
  //
  //[필요성!!!]------------------------------------------------------------------------
  //이는 맷돌(G.MTDL.A) 를 사용한 양산시 보다 [가상기계(*.gvmx)] 를 쉽게 계속
  //설치하거나 할때도 사용가능하다.
  //즉, 항상 [설계묶음] 을 열 필요 없이 [가상기계(*.gvmx)] 만 있으면 맷돌(G.MTDL.A) 을
  //돌릴수 있다.
  //
  //[2012.03.14.수][중요수정!!!]-------------------------------------------------------
  //[가상기계:전용환경] 으로 전환시 현재 [설계묶음] 을 닫지 않는 것으로 수정.
  //}----------------------------------------------------------------------------------

  //[VAR]
  //{
      char  tempStr[OPT_lineStrSize];

      int   i;

  //}

  //[열려있는 [설계묶음] 이 있나?]
  //{
      //[2012.03.14.수][중요수정!!!]{-------------------------------
      //현재 열려있는 [설계묶음] 을 닫지 않고 처리하는 것으로 수정.
      //[가상기계:전용환경] 을 사용하는 모든 경우에 해당.
      //}-----------------------------------------------------------

      /*
      //[!]{------------------------------------------------
      //현재 열려 있는 [설계묶음] 이 있다면 모두 닫아 준다.
      //}---------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_tree[d_TREE_project].items[0].txt, "새설계묶음") != true)
      {
        STR_Assign(tempStr,
                   "현재 작업 중인 [설계묶음] 이 존재 합니다.\r\n"
                   "작업 중인 [설계묶음] 을 자동으로 저장하려면 [확인] 을 누르고\r\n"
                   "저장하지 않고 그냥 닫으려면 [취소] 를 눌러 주세요.");

        //현재 작업 중인 <*.gprj> 에 대한 처리를 먼저 수행해 준다.
        if(ide_msgbox_Form->_MsgBox_Ok_Cancle(d_MSGBOX_info, tempStr) == true)
        {
          //[현재 설계묶음 저장]
          //{
              //[!]{-----------------------------------
              //현재 작업 중인 [설계묶음] 을 저장한다.
              //전용 함수로 간단하게 처리한다.
              //}--------------------------------------

              IDE_Project_Save(false);

          //}

        }
        else
        {
          //[취소] 가 눌린 경우는 [설계묶음] 을 저장하지 않는다.

        }

        //[현재 설계묶음 관련 문서 닫기]
        //{
            //만일 현재 저장되지 않음 문서가 있어서 [닫기] 시에 [대화상자] 가 나온
            //경우는 더이상 처리하지 않고 종료 해야 한다.
            //자세한 내용은 _List_DeleteAll() 함수의 설명을 참고 한다.
            if(editor_top_Form->_List_DeleteAll() != true) return;

        //}

        //[새설계묶음으로 초기화]
        //{
            //[2011.07.13.수][수정!!!]
            //[검증식 보기창] 도 전부 초기화 한다---------------------------v
            ide_tree_Form->_Tree_All_Init(d_Tree_Prj | d_Tree_Info | d_Tree_DbgExp);

        //}

      }
      */

  //}

  //[현재 [가상기계 전용 환경] 인가?]
  //{
      if(_ide_Option.gvmMode == true)
      {
        //[!]{------------------------------------------------------------
        //현재 [가상기계 전용 환경] 이 이미 구동중이다.
        //이 경우는 현재 실행중인 [가상기계] 를 정지, 삭제해 주어야 한다.
        //}---------------------------------------------------------------

        //[현재 [맷돌직접연결] 인가?]
        //{
            //[2010.07.07.수][추가!!!]{-------------------
            //현재 [맷돌직접연결] 인 경우만 처리가능하다.
            //}-------------------------------------------

            if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
            {
              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[가상기계<*.gvmx>] 는 [맷돌직접연결] 에서만 설치 가능합니다.");

              //더이상 처리하지 않는다.
              return;

            }

        //}

        ide_caption_Form->_Caption("::: 가상기계 전용 환경 ::: ");

      }
      else
      {
        //[!]{------------------------------
        //이 경우는 [맷돌 개발환경] 상태다.
        //}---------------------------------

        //[맷돌 가상구동/직접연결 모두 해제된 상태인가?]
        //{
            //[!]{-------------------------------------------------------------
            //[가상구동/직접연결] 모두 해제된 상태에서만 처리를 시작할수 있다.
            //}----------------------------------------------------------------

            if((ide_buttons_Form->_vmosSim_CheckBtn->_checked == true) ||
               (ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true))
            {
              //이 경우는 [가상기계] 구동환경으로 진입할수 없다.

              ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                       "[가상기계<*.gvmx>] 전용 구동은 [맷돌가상구동] 이나\r\n"
                                       "[맷돌직접연결] 모두 해제된 상태에서만 시작할수 있습니다.");

              //더이상 처리하지 않는다.
              return;

            }

        //}

      }

  //}

  //[<*.gvmx> 를 열 대화상자 보이기]
  //{
      //[!]{--------------------------------------------------
      //실행할 [가상기계:<*.gvmx>] 를 열 대화상자를 보여준다.
      //아무 것도 열지 않은 경우는 바로 종료한다.
      //}-----------------------------------------------------

      //[확장자 설정]
      //{
          main_Form->file_OpenDialog->Filter = "가상기계(*.gvmx)|*.gvmx";

      //}

      //아무것도 열지 않은 경우는 바로 종료한다.
      if(main_Form->file_OpenDialog->Execute() != true) return;

  //}

  //[가상기계 전용 개발환경 인가?]
  //{
      //[2010.07.07.수][추가!!!]{----------------------------
      //이미 [가상기계 전용 환경] 인 경우는 처리하지 않는다.
      //}----------------------------------------------------

      if(_ide_Option.gvmMode  == true) goto lbGVMX_Install;

  //}

  //[개발환경 설정]
  //{
      //[!]{--------------------------------------------------
      //[개발환경] 을 [가상기계 실행 전용] 환경으로 변경한다.
      //}-----------------------------------------------------

      //메뉴에서 [가상기계] 항목을 제외한 모든 항목을 [무효화] 한다.
      //{
          for(i = 0; i < d_menu_count; i++)
          {
             //가상기계 항목만 유효하고 나머지는 전부 무효로 바꾼다.
            if(i == d_menu_gvm_ix) continue;

            ide_menu_Form->_ItemEnable(i, false);

          }

      //}

      //[실행/정지/재기동] 버튼을 제외한 모든 버튼을 무효화 한다.
      //{
          //[무효화]
          //{
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save]->_Enable(false);
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save_all]->_Enable(false);
              ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_open]->_Enable(false);

              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_check]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_compile]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_link]->_Enable(false);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_build]->_Enable(false);

          //}

          //[유효화]
          //{
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_download]->_Enable(true);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_verify]->_Enable(true);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_erase]->_Enable(true);

              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_run]->_Enable(true);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_stop]->_Enable(true);
              ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_reset]->_Enable(true);

          //}

      //}

      //[탭] 을 무효화 한다.
      //{
          ide_buttons_Form->_tabs->_Enable(false);

      //}

      //[맷돌 가상구동/직접연결] 확인 상자 해제/무효화.
      //{
          //확인 해제.
          ide_buttons_Form->_vmosSim_CheckBtn->_Checked(false);
          ide_buttons_Form->_vmosMdl_CheckBtn->_Checked(false);

          //무효화.
          ide_buttons_Form->_vmosSim_CheckBtn->_Enable(false);
          ide_buttons_Form->_vmosMdl_CheckBtn->_Enable(false);

      //}

      //창관련 버튼 중 [최대화/닫기] 버튼을 [무효화] 시킨다.
      //{
          ide_menu_Form->_max_bmpbtns->_Enable(false);
          ide_menu_Form->_close_bmpbtns->_Enable(false);

      //}

      //필요한 부분만 보이도록 IDE 전체 높이를 조정한다.
      //{
          //최대화 되 있는 경우라도 무조건 기본상태로 변경한다.
          main_Form->WindowState = wsNormal;

          //[!]{----------------------------------
          //먼저 기본크기 변경이 반영되도록 한다.
          //Application->ProcessMessages();
          //}-------------------------------------

          //[현재 <위치/크기> 정보 [환경변수] 에 저장]
          //{
              //[주의!!!]{-------------------------------------------------------------
              //[최대화] 시에만 저장되는 값이며, [크기조정] 등에서는 저장되지 않으므로
              //반드시 여기서 현재 상태를 구해서 저장.
              //}----------------------------------------------------------------------
              
              _ide_Option.ideRect.left   = main_Form->Left;
              _ide_Option.ideRect.top    = main_Form->Top;
              _ide_Option.ideRect.width  = main_Form->Width;
              _ide_Option.ideRect.height = main_Form->Height;

          //}

          //[IDE 크기 정보 백업]
          //{
              //[2018.02.26.월][추가!!!]{----------------------------------------
              //IDE 자체 기본적인 [최대화/기본화] 를 위하여 현재 크기 정보 백업.
              //이는 GVMS 구동 환경과 기본 환경을 구분하기 위한것.
              //<Ide_Menu_GVM_Ide()> 에서 복구된다.
              //}----------------------------------------------------------------

              _ide_Option.ideRectBackup = _ide_Option.ideRect;

          //}

          //[크기 설정]
          //{
              main_Form->Constraints->MinHeight = 91;
              main_Form->Constraints->MinWidth  = 740;

              main_Form->Width  = main_Form->Constraints->MinWidth;
              main_Form->Height = main_Form->Constraints->MinHeight;

          //}

          //[현재 <위치/크기> 정보 [환경변수] 에 저장]
          //{
              //[복구] 할때를 위하여 현재 상태를 저장.
              _ide_Option.ideRect.left   = main_Form->Left;
              _ide_Option.ideRect.top    = main_Form->Top;
              _ide_Option.ideRect.width  = main_Form->Width;
              _ide_Option.ideRect.height = main_Form->Height;

          //}

      //}

  //}

  //[가상기계 전용 상태 기록]
  //{
      //[!]{---------------------------------------------------------------------
      //현재 [가상기계 전용 구동] 환경이 시작되었음을 기록한다.
      //반드시 [가상구동기] 를 실행하기 전에 처리해야 한다.
      //이는, <_EVENT_Click_vmosMdl_CheckBtn()> 함수를 사용하는데 이 함수 안에서
      //<gvmMode> 를 구분하여 처리하기 때문이다.
      //}------------------------------------------------------------------------

      _ide_Option.gvmMode = true;

  //}

  //[맷돌 가상구동기 실행]
  //{
      //[!]{------------------------------------------
      //자동으로 [맷돌가상구동] 을 선택하고 실행한다.
      //}---------------------------------------------

      //_EVENT_Click_vmosMdl_CheckBtn() 의 동작을 위하여 [맷돌가상구동] 에 확인을 표시한다.
      ide_buttons_Form->_vmosMdl_CheckBtn->_Checked(true);

      //전용함수로 간단하게 처리한다.
      ide_buttons_Form->_EVENT_Click_vmosMdl_CheckBtn();

      //VMOS 가 완전히 초기화 될때가지 일정 시간을 준다.
      Sleep(1500);

  //}

  lbGVMX_Install:

  //[가상기계 설치]
  //{
      //[!]{------------------
      //<*.gvmx> 를 설치한다.
      //}---------------------

      //먼저 VMOS 를 정지시킨다.
      if(Ide_Ctrl_Stop() != true) return;

      //지우기.
      if(Ide_Ctrl_Erase() != true) return;

      //위에서 연 <*.gvmx> 를 설치한다.
	  if(Ide_Mdl_Download_Gvmx(((AnsiString)main_Form->file_OpenDialog->FileName).c_str(), NULL) != true) return;

      //[재기동] 없이 [실행] 할수 있도록 VMOS 를 초기화후 정지시킨다.
      if(Ide_Ctrl_ResetStop() != true) return;

  //}

  //[가상기계 실행]
  //{
      //[!]{-----------------------------
      //설치된 [가상기계] 를 실행시킨다.
      //}--------------------------------

      //[재기동] 시킨다.
      //ide_buttons_Form->_EVENT_HwResetButton_Click();

      //[2010.07.07.수][수정!!!]{--------------------------------------------------
      //[재설치] 를 위하여 [설치] 만 하고 실행하지는 않는다.
      //[실행] 은 [실행/재기동] 두가지 방법으로 가능하므로 자동실행은 하지 않는다.
      //따라서, 위의 실행문은 주석으로 처리한다.
      //}--------------------------------------------------------------------------

  //}

  //[현재 제목줄에 가상기계 이름 표시]
  //{
      //[2010.07.07.수][추가!!!]{-------------------------------------------
      //개발환경 [제목줄] 에 현재 [가상기계(*.gvmx)] 의 [이름] 을 표시한다.
      //}-------------------------------------------------------------------

      i = STR_Assign(tempStr, "가상기계 : < ");

      //순수 <*.*> 만 얻는다.
	  STR_GetFileNameOnly(((AnsiString)main_Form->file_OpenDialog->FileName).c_str(), &(tempStr[i]));

      STR_Add(tempStr, " >");

      ide_caption_Form->_Caption(tempStr);

  //}

}

void __fastcall Ide_Menu_GVM_Ide(void)
{
  //[2010.07.05.월][생성!!!]{---------------------------------------------------------
  //[가상기계] 구동만을 위한 [전용 환경] => [맷돌-개발환경] 으로 다시 돌려 놓는다.
  //현재 구동중인 [가상기계] 가 있는 경우는 자동으로 종료시키는 등의 모든 부가 처리를
  //수행한다.
  //}---------------------------------------------------------------------------------

  //[VAR]
  //{
      int  i;

  //}

  //[환경변수]
  //{
      //[2023.01.29.일][추가]
      struct  IDE_OPTION  *ideOption_;

      IDE_Get_Option(&ideOption_);

  //}

  //[안전장치]
  //{
      //[2010.07.06.화][추가!!!]{-----------------------------------
      //반드시 현재 [가상기계 전용 환경] 인 경우만 처리되어야 한다.
      //}-----------------------------------------------------------

      if(_ide_Option.gvmMode != true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "현재 [가상기계<*.gvms/*.gvmx>] 전용 환경이 아닙니다.");

        return;

      }

  //}

  //[최대화/닫기] 버튼을 [유효화] 한다.
  //{
      ide_menu_Form->_max_bmpbtns->_Enable(true);
      ide_menu_Form->_close_bmpbtns->_Enable(true);

  //}

  //[맷돌 가상구동/직접연결] 유효화.
  //{
      //유효화.
      ide_buttons_Form->_vmosSim_CheckBtn->_Enable(true);
      ide_buttons_Form->_vmosMdl_CheckBtn->_Enable(true);

  //}

  //[맷돌 가상구동] 해제(가상기계 자동 종료, 관련 기능 활성화).
  //이 단계에서 [가상기계] 등이 자동 종료되고 [가상구동기] 도 자동으로 종료된다.
  //{
      //_EVENT_Click_vmosSim_CheckBtn() 의 동작을 위하여 [맷돌가상구동] 에 확인을 표시한다.

      if(ide_buttons_Form->_vmosSim_CheckBtn->_checked == true)
      {
        ide_buttons_Form->_vmosSim_CheckBtn->_Checked(false);

        //전용함수로 간단하게 처리한다.
        ide_buttons_Form->_EVENT_Click_vmosSim_CheckBtn();

      }
      else if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked == true)
      {
        ide_buttons_Form->_vmosMdl_CheckBtn->_Checked(false);

        //전용함수로 간단하게 처리한다.
        ide_buttons_Form->_EVENT_Click_vmosMdl_CheckBtn();

      }

  //}

  //버튼을 원래 상태로 돌려 놓는다.
  //{
      //[유효화]
      //{
          ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save]->_Enable(true);
          ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_save_all]->_Enable(true);
          ide_mbutton_Form->_main_bmpbtns[d_main_bmpbtn_open]->_Enable(true);

          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_check]->_Enable(true);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_compile]->_Enable(true);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_link]->_Enable(true);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_build]->_Enable(true);

      //}

      //[무효화]
      //{
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_download]->_Enable(false);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_verify]->_Enable(false);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_erase]->_Enable(false);

          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_run]->_Enable(false);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_stop]->_Enable(false);
          ide_buttons_Form->_ctrl_bmpbtns[d_ctrl_bmpbtn_hw_reset]->_Enable(false);

      //}

  //}

  //탭을 유효화 한다.
  //{
      ide_buttons_Form->_tabs->_Enable(true);

  //}

  //메뉴의 모든 항목을 유효화 한다.
  //{
      for(i = 0; i < d_menu_count; i++) { ide_menu_Form->_ItemEnable(i, true); }

  //}

  //[가상기계 전용 상태 기록]
  //{
      //[!]{----------------------------------------------------
      //현재 [가상기계 전용 구동] 환경이 시작되었음을 기록한다.
      //}-------------------------------------------------------

      _ide_Option.gvmMode = false;

  //}

  //[IDE 크기 정보 복구]
  //{
      //[2018.02.26.월][추가!!!]{-------------------------------------
      //IDE 자체 기본적인 [최대화/기본화] 를 위하여 백업 정보를 복구.
      //GVMS 실행 전용 환경에서 원래 IDE 환경으로 상태 정보 복구.
      //}-------------------------------------------------------------

      _ide_Option.ideRect = _ide_Option.ideRectBackup;

  //}

  //[IDE 원래 크기로 복구]
  //{
      //최소 크기 고정값을 복구한다.
      main_Form->Constraints->MinHeight = 0;
      main_Form->Constraints->MinWidth  = 0;

      //[가상기계:전용환경] 의 위치가 이동하는 경우라도 [편집기] 도 돌아가는 경우는
      //위치 까지 원래 그대로 돌려 놓는 것이 좋다.
      main_Form->Left   = _ide_Option.ideRect.left;
      main_Form->Top    = _ide_Option.ideRect.top;
      
      //[!]{------------------------------
      //먼저 위치가 결정되도록 넣어 준다.
      Application->ProcessMessages();
      //}---------------------------------

      main_Form->Width  = _ide_Option.ideRect.width;
      main_Form->Height = _ide_Option.ideRect.height;

      //[2010.07.08.목][주의!!!]{-----------------------------------------------
      //크기 조정후 <Tree> 가 다시 그려지지 않아 하얗게 나오므로 다시 그려준다.
      tree_tree_Form->_Draw();
      //}-----------------------------------------------------------------------

      main_Form->Constraints->MinHeight = 320;
      main_Form->Constraints->MinWidth  = 500;

  //}

  //[제목줄 개발환경으로 복구]
  //{
      //[2010.07.07.수][추가!!!]{-----------------------------
      //개발환경 [제목줄] 을 원래 개발환경 문자열로 북구한다.
      //}-----------------------------------------------------

      ide_caption_Form->_Caption(Opt_Ide_CaptionStr);

  //}

  //[<탭:문자열> 영역 지우기]
  //{
      //[2023.01.29.일][추가]{------------------------------------------------------
      //GVMS 설치시 [버튼:실행] 을 눌러야 GVMS 가 실행된다는 것을 알려주는 문자열이
      //<Ide_Menu_GVMS_Install()> 에서 출력되므로, 이 영역을 비운다.
      //}---------------------------------------------------------------------------

      ide_buttons_Form->_tabs->_Blank_Text("",
                                           ideOption_->color_0);

  //}

}

void __fastcall Ide_Menu_Gigyenics_GVMS(void)
{
  //[2010.07.08.목][생성!!!]{----------------------------------------------------
  //1) 열기 대화상자의 경로를 기계닉스 가상기계(*.gvms) 모음이 있는 위치를 지정.
  //2) Ide_Menu_GVMS_Install() 함수로 자동 처리.
  //
  //[2011.05.05.목][중요수정!!!]-------------------------------------------------
  //[GVMS] 경로가 강제설정되지 않은 문제 수정.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      char  initialDirStr[OPT_lineStrSize];
      char  fileNameStr[OPT_lineStrSize];

  //}

  //[이전에 연 문서 아름/경로 저장]
  //{
	  STR_Assign(initialDirStr, ((AnsiString)main_Form->file_OpenDialog->InitialDir).c_str());
	  STR_Assign(fileNameStr, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

  //}

  //[기계닉스 가상기계(*.gvms) 경로 지정]
  //{
      main_Form->file_OpenDialog->InitialDir = (AnsiString)Ide_System_GVMS_Path;

      //[2011.05.05.목][중요수정!!!]{--------------------------------------------------------
      //main_Form->file_OpenDialog->FileName = " "; 로 [문서이름] 이 지정돼 있지 않은 경우는
      //이 [경로] 가 강제 설정되지 않는다.
      //따라서, 반드시 <*.gvms> 의 모든 경우를 대상으로 지정하여 [전체 경로] 를 지정해 준다.
      //이렇게 해야, 이전에 어떤 문서를 열었든지에 상관없이 반드시 [GVMS] 위치가 열린다.
      main_Form->file_OpenDialog->FileName   = (AnsiString)Ide_System_GVMS_Path + "*.gvms";
      //}------------------------------------------------------------------------------------

  //}

  //[가상기계(*.gvms) 열기
  //{
      //[2011.11.10.목][추가!!!]{----------------------------------------
      //바로 실행하는 경우 [맷돌구동:GVMX] 의 경우는 [설치] 만 하므로
      //서로 혼란이 올수 있으므로, 둘다 같이 [설치] 만 하는 것으로 한다.
      //}-----------------------------------------------------------------

      //<GVMS> 설치후 정지--------v
      Ide_Menu_GVMS_Install(NULL, false);

  //}

  //[경로 복구]
  //{
      main_Form->file_OpenDialog->InitialDir = (AnsiString)initialDirStr;
      main_Form->file_OpenDialog->FileName   = (AnsiString)fileNameStr;

  //}

}

void __fastcall Ide_Menu_Gigyenics_GVMX(void)
{
  //[2010.07.08.목][생성!!!]{----------------------------------------------------
  //1) 열기 대화상자의 경로를 기계닉스 가상기계(*.gvmx) 모음이 있는 위치를 지정.
  //2) Ide_Menu_GVMX_Install() 함수로 자동 처리.
  //
  //[2011.05.05.목][중요수정!!!]-------------------------------------------------
  //[GVMS] 경로가 강제설정되지 않은 문제 수정.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      char  initialDirStr[OPT_lineStrSize];
      char  fileNameStr[OPT_lineStrSize];

  //}

  //[이전에 연 문서 아름/경로 저장]
  //{
	  STR_Assign(initialDirStr, ((AnsiString)main_Form->file_OpenDialog->InitialDir).c_str());
	  STR_Assign(fileNameStr, ((AnsiString)main_Form->file_OpenDialog->FileName).c_str());

  //}

  //[기계닉스 가상기계(*.gvmx) 경로 지정]
  //{
      main_Form->file_OpenDialog->InitialDir = (AnsiString)Ide_System_GVMX_Path;

      //[2011.05.05.목][중요수정!!!]{--------------------------------------------------------
      //main_Form->file_OpenDialog->FileName = " "; 로 [문서이름] 이 지정돼 있지 않은 경우는
      //이 [경로] 가 강제 설정되지 않는다.
      //따라서, 반드시 <*.gvms> 의 모든 경우를 대상으로 지정하여 [전체 경로] 를 지정해 준다.
      //이렇게 해야, 이전에 어떤 문서를 열었든지에 상관없이 반드시 [GVMS] 위치가 열린다.
      main_Form->file_OpenDialog->FileName   = (AnsiString)Ide_System_GVMX_Path + "*.gvmx";
      //}------------------------------------------------------------------------------------

  //}

  //[가상기계(*.gvmx) 열기
  //{
      Ide_Menu_GVMX_Install();

  //}

  //[경로 복구]
  //{
      main_Form->file_OpenDialog->InitialDir = (AnsiString)initialDirStr;
      main_Form->file_OpenDialog->FileName   = (AnsiString)fileNameStr;

  //}

}

void __fastcall Ide_ListSubMenu_GVMS_Install(char  *pItemStr)
{
  //[2011.11.15.화][생성!!!]{---------------------------------------
  //선택된 [항목] 에 해당하는 처리를 수행.
  //
  //[항목이름] 자체가 <Ide_System_GVMS_Path>의 [폴더이름] 이 되므로
  //[항목이름\항목이름.gvms] 를 읽어서 [맷돌가상구동] 시킨다.
  //
  //<메뉴:GVMS(PC)> 가 해당.
  //}---------------------------------------------------------------

  //[VAR]
  //{
      char  fileFullName[OPT_lineStrSize] = {""};

  //}

  //[<*.gvms> 의 [파일이름확장자] 합성]
  //{
      //[!]{-----------------------------------------------------
      //<[Ide_System_GVMS_Path]\pItemStr\pItemStr.gvms> 로 합성.
      //}--------------------------------------------------------

      //[기본경로] 합성.
	  STR_Assign(fileFullName, ((AnsiString)Ide_System_GVMS_Path).c_str());

      //해당 [폴더이름] 합성.
      STR_Add(fileFullName, pItemStr); STR_Add(fileFullName, "\\");

      //[이름] 합성.
      STR_Add(fileFullName, pItemStr); STR_Add(fileFullName, ".gvms");

  //}

  //[GVMS 설치]
  //{
      //[!]{-------------------------------------------
      //해당 GVMS 를 가상기계 전용 환경에서 설치 한다.
      //}----------------------------------------------

      Ide_Menu_GVMS_Install(fileFullName, false);

  //}

}

void __fastcall Ide_ListSubMenu_GVMX_Install(char  *pItemStr)
{
  //[2011.11.16.수][생성!!!]{----------------------------------------
  //선택된 [항목] 에 해당하는 처리를 수행.
  //
  //[항목이름] 자체가 <Ide_System_GVMX_Path>의 [폴더이름] 이 되므로
  //[항목이름\항목이름.gvmx] 를 읽어서 [맷돌(G.MTDL.X)] 에 설치한다.
  //
  //<메뉴:GVMX(맷돌)> 이 해당.
  //
  //[주의!!!]--------------------------------------------------------
  //<Ide_ListSubMenu_GVMS_Install()> 과는 달리 [가상기계전용환경] 을
  //사용하지 않으며(현재 상태에서바로 설치가능),
  //반드시 <[v]맷돌직접연결> 이 설정된 상태여야 한다.
  //
  //이 함수는 [맷돌-통합개발환경:기본상태] 에서만 동작하므로, 현재
  //[가상기계 전용환경] 의 경우는 고려할 필요가 없다.
  //
  //[참고!!!][2012.03.14.수]-----------------------------------------
  //이 함수는 처리시 [설계묶음] 을 닫지 않는다.
  //}----------------------------------------------------------------

  //[VAR]
  //{
      char  fileFullName[OPT_lineStrSize] = {""};

      //[2011.11.18.금][추가!!!]
      //설명문 정리.
      char  infoStr[OPT_lineStrSize] = {""};
      char  tempStr[OPT_lineStrSize] = {""};

      int   gvmxSize;

      int   s;

  //}

  //[<[v]맷돌직접연결> 인가?]
  //{
      //[!]{-----------------------------------------------
      //[맷돌(G.MTDL.X)] 에 GVMX 를 설치하는 것으로 반드시
      //<[v]맷돌직접연결> 상태여야 한다.
      //}--------------------------------------------------

      if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "가상기계(GVMX)를 맷돌(G.MTDL.X)에 설치하려면\r\n"
         "\"[v]맷돌직접연결\" 로 설정돼 있어야 합니다."
        );

        //더이상 처리하지 않는다.
        return;

      }

  //}

  //[<*.gvmx> 의 [파일이름확장자] 합성]
  //{
      //[!]{-----------------------------------------------------
      //<[Ide_System_GVMX_Path]\pItemStr\pItemStr.gvmx> 로 합성.
      //}--------------------------------------------------------

      //[기본경로] 합성.
	  STR_Assign(fileFullName, ((AnsiString)Ide_System_GVMX_Path).c_str());

      //해당 [폴더이름] 합성.
      STR_Add(fileFullName, pItemStr); STR_Add(fileFullName, "\\");

      //[이름] 합성.
      STR_Add(fileFullName, pItemStr); STR_Add(fileFullName, ".gvmx");

  //}

  //[<GVMX> 정보 만들기/표시]
  //{
      //[2011.11.17.목][추가!!!]{----------------------------------
      //설치하는 <GVMX> 에 대한 간단한 3개 정보를 보여준다.
      //이는 [하위항목] 으로 바로 설치하므로 사용자가 어떤 GVMX 가
      //설치되고 있는지 까먹을수 있기 때문이다.
      //
      //[맷돌운영체제] : vmos_at45db041x_1_m
      //[가상기계이름] : 경로\이름.gvmx
      //[가상기계크기] : 0x100(126 바이트)
      //}----------------------------------------------------------

      //[현재 맷돌 운영체제 이름 얻기]
      //{
          s = STR_Assign(infoStr, "<맷돌운영체제> : ");

          if(Ide_Mtdl_Get_OS_Name(&(infoStr[s])) != true) return;

          s = STR_Add(&(infoStr[s]), "\r\n");

      //}

      //[가상기계이름]
      //{
          s = STR_Add(infoStr, "<가상기계이름> : ");
          s = STR_Add(infoStr, fileFullName);
          s = STR_Add(&(infoStr[s]), "\r\n");

      //}

      //[가상기계크기]
      //{
          s = STR_Add(infoStr, "<가상기계크기> : 0x");

          //크기얻기.
          FILE_Size(fileFullName, &gvmxSize);

          CONV_LongVal_To_Hex2(gvmxSize, tempStr);
          s = STR_Add(&(infoStr[s]), tempStr);

          STR_Add(infoStr, "(");
          CONV_LongVal_To_Str(gvmxSize, 0, false, tempStr);
          s = STR_Add(&(infoStr[s]), tempStr);

          STR_Add(infoStr, " 바이트)\r\n");

      //}

      //[<출력창> 에 출력]
      //{
          //[!]{----------------------------------------------
          //[맷돌-통합개발환경] 아래 [출력창] 에 출력해 준다.
          //}-------------------------------------------------

          msg_msg_Form->_PrintAddLine(0, infoStr);

      //}

  //}
  
  //[GVMX 설치]
  //{
      //[!]{-----------------------------------------------------------------------
      //해당 GVMX 를 [맷돌(G.MTDL.X)] 에 설치.
      //
      //<[v]맷돌직접연결> 상태로 시작하므로 <[v]맷돌가상구동> 에서 구동되는
      //[맷돌C:GVMS] 안에서 사용되는 API 와 [충돌] 할수는 없다.
      //따라서, API 용으로 만든 편리한 함수를 사용하여 처리한다.
      //
      //[주의!!!]------------------------------------------------------------------
      //[GVMX] 가 너무 큰(100 KByte 이상) 경우는 설치후 확인과정에서 많은 시간이
      //걸리지만, 정확하게 하기 위하여 일단 [확인] 까지 자동 처리하는 것으로 한다.
      //단, [실행] 시키는 것은 사용자 의도로 남긴다.
      //}--------------------------------------------------------------------------

      //[설치]
      //{
          //실행시키지 않는다-------------------v
          if(Ide_API_GVMX_Install(fileFullName, false, NULL) != true) return;

      //}

      //[확인]
      //{
          if(Ide_API_GVMX_Verify(fileFullName, NULL) != true) return;

      //}

  //}

}

void __fastcall Ide_ListSubMenu_GVMS_Get_ItemList(char  **rItemList)
{
  //[2011.11.16.수][생성!!!]{--------------------------------------
  //<[Ide_System_GVMS_Path]\> 경로안의 모든 [폴더이름] 을 얻는다.
  //[폴더이름] 이 곧 해당 <GVMS> 의 개별적인 항목이 된다.
  //
  //[항목] 이 전혀 없는 경우는 <(*rItemList) = NULL> 로 생성자체를
  //하지 않았음을 알려준다.
  //}--------------------------------------------------------------

  //[VAR]
  //{
       TStringList  *itemList = NULL;

       int           size;

  //}

  //[목록 구하기]
  //{
      itemList = new TStringList;
      itemList->Clear();

      Dir_Get_FileList_BoundDir(Ide_System_GVMS_Path,
                                "*",
                                //<GVMS> 폴더만 대상으로 한다.
                                true,
                                //안의 [폴더] 만 대상으로 하고 경로를 제외한 [이름] 만 얻는다.
                                d_Directory | d_NameOnly,
                                itemList);

  //}

  //[항목이 있나?]
  //{
      //[주의!!!]{------------------------------------------------------
      //항목이 전혀 없다면 [문자열포인터] 자체 주소에 NULL 을 반환한다.
      //즉, 아예 생성을 하지 않는다.
      //}---------------------------------------------------------------

      if(itemList->Count == 0)
      {
        (*rItemList) = NULL;

        goto lbEnd;

      }

  //}

  //[항목 문자열 전달]
  //{
      //얻은 문자열의 길이 얻기.
	  size = STR_Length(((AnsiString)(itemList->Text)).c_str());

      //이미 생성된 것이 있다면 삭제.
      if((*rItemList) != NULL) { delete [] (*rItemList); (*rItemList) = NULL; }

      //'\0' 까지 저장.
      //(*rItemList) = new char[size + 1];
      //[동적생성단위적용][2021.01.24.일][수정]
      (*rItemList) = new char[UnitX(1024, size + 1)];

      STR_Assign((*rItemList), ((AnsiString)(itemList->Text)).c_str());

  //}

  //[마지막 행 삭제]
  //{
      //[중요주의!!!]{-------------------------------------------------------
      //위에서 행단위로 목록을 얻을때 가장 마지막 행에 CRLF 가 붙어 있으므로
      //이것을 제거한다.
      //이는 <GList> 항목의 마지막이 빈행으로 남지 않게하기 위한 것이다.
      //마지막 행을 제거시킨다.
      //'\0' 위치에서 <-2> 위치에 '\0' 을 기록하여 마무리 한다.
      //}--------------------------------------------------------------------

      (*rItemList)[size - 2] = '\0';

  //}

  lbEnd:

  //[후처리]
  //{
      if(itemList != NULL) { delete itemList; itemList = NULL; }

  //}

}

void __fastcall Ide_ListSubMenu_GVMX_Get_ItemList(char  **rItemList)
{
  //[2011.11.16.수][생성!!!]{--------------------------------------
  //<[Ide_System_GVMX_Path]\> 경로안의 모든 [폴더이름] 을 얻는다.
  //[폴더이름] 이 곧 해당 <GVMX> 의 개별적인 항목이 된다.
  //
  //[항목] 이 전혀 없는 경우는 <(*rItemList) = NULL> 로 생성자체를
  //하지 않았음을 알려준다.
  //}--------------------------------------------------------------

  //[VAR]
  //{
       TStringList  *itemList = NULL;

       int           size;

  //}

  //[목록 구하기]
  //{
      itemList = new TStringList;
      itemList->Clear();

      Dir_Get_FileList_BoundDir(Ide_System_GVMX_Path,
                                "*",
                                //<GVMX> 폴더만 대상으로 한다.
                                true,
                                //안의 [폴더] 만 대상으로 하고 경로를 제외한 [이름] 만 얻는다.
                                d_Directory | d_NameOnly,
                                itemList);

  //}

  //[항목이 있나?]
  //{
      //[주의!!!]{------------------------------------------------------
      //항목이 전혀 없다면 [문자열포인터] 자체 주소에 NULL 을 반환한다.
      //즉, 아예 생성을 하지 않는다.
      //}---------------------------------------------------------------

      if(itemList->Count == 0)
      {
        (*rItemList) = NULL;

        goto lbEnd;

      }

  //}

  //[항목 문자열 전달]
  //{
      //얻은 문자열의 길이 얻기.
	  size = STR_Length(((AnsiString)(itemList->Text)).c_str());

      //이미 생성된 것이 있다면 삭제.
      if((*rItemList) != NULL) { delete [] (*rItemList); (*rItemList) = NULL; }

      //'\0' 까지 저장.
      //(*rItemList) = new char[size + 1];
      //[동적생성단위적용][2021.01.24.일][수정]
      (*rItemList) = new char[UnitX(1024, size + 1)];

      STR_Assign((*rItemList), ((AnsiString)(itemList->Text)).c_str());

  //}

  //[마지막 행 삭제]
  //{
      //[중요주의!!!]{-------------------------------------------------------
      //위에서 행단위로 목록을 얻을때 가장 마지막 행에 CRLF 가 붙어 있으므로
      //이것을 제거한다.
      //이는 <GList> 항목의 마지막이 빈행으로 남지 않게하기 위한 것이다.
      //마지막 행을 제거시킨다.
      //'\0' 위치에서 <-2> 위치에 '\0' 을 기록하여 마무리 한다.
      //}--------------------------------------------------------------------

      (*rItemList)[size - 2] = '\0';

  //}

  lbEnd:

  //[후처리]
  //{
      if(itemList != NULL) { delete itemList; itemList = NULL; }

  //}

}

void __fastcall Ide_ListSubMenu_GVMS_Thumb_View(char  *pItemStr)
{
  //[2023.01.02.월][생성]{----------------------------------------------------------------------
  //[가선택] 시에 [항목이름] 에 해당하는 [썸네일] 을 해당 항목의 옆에 보여준다.
  //
  //[배치구조]**********************************************************************************
  //
  //IDE:gigyenics\gvm\gvms\[항목이름]\__모양새\항목이름.jpg   <---해당 GUI 의 썸네일(40% 크기).
  //IDE:gigyenics\gvm\gvms\[항목이름]\항목이름.gvms           <---해당 GVMS.
  //
  //<메뉴:GVMS(PC)> 만 해당되며, <GVMS:Ide_System_GVMS_Path> 가 기본 경로가 된다.
  //}-------------------------------------------------------------------------------------------

  //[VAR]
  //{
      char          jpgPathNameExt[OPT_lineStrSize] = {""};

      unsigned int  imageAreaWidth = 0, imageAreaHeight = 0;

      int           posX, posY;

  //}

  //[<*.gvms> 의 [파일이름확장자] 합성]
  //{
      //[!]{-------------------------------------------------------------
      //<[Ide_System_GVMS_Path]\pItemStr\__모양새\pItemStr.jpg> 로 합성.
      //}----------------------------------------------------------------

      //[기본경로] 합성.
	  STR_Assign(jpgPathNameExt, ((AnsiString)Ide_System_GVMS_Path).c_str());

      //해당 [폴더이름] 합성.
      STR_Add(jpgPathNameExt, pItemStr); STR_Add(jpgPathNameExt, "\\__모양새\\");

      //[이름] 합성.
      STR_Add(jpgPathNameExt, pItemStr); STR_Add(jpgPathNameExt, ".jpg");

  //}

  //[썸네일 보이기]
  //{
      //[그림 크기 얻기]
      //{
          //[!]{--------------------------------------------------------------------
          //표시하는 그림크기에 따라 <_gvms_GImageBox> 크기가 달라진다.
          //또한, 그림의 존재 유/무 나 오류까지 모두 검사하므로 가장 먼저 처리하고,
          //결과가 <true> 가 아니라면 더이상 처리하지 않고 여기서 종료.
          //}-----------------------------------------------------------------------

          if(Image_Get_Size(jpgPathNameExt, &imageAreaWidth, &imageAreaHeight) != true)
          {
            return;

          }

      //}

      //[<_gvms_GImageBox> 생성/설정]
      //{
          //[!]{-------------------------------------------------------------------
          //<ide_menu.cpp:_EVENT_FocusKill_listSubMenu()> 에서 삭제될때까지 이전에
          //생성된 것이 존재할수 있으므로 이미 존재한다면 생성하지 않는다.
          //}----------------------------------------------------------------------

          if(ide_menu_Form->_gvms_GImageBox == NULL)
          {
            //[생성]
            //{
                ide_menu_Form->_gvms_GImageBox          = new TGImageBox_Form(ide_menu_Form);
                ide_menu_Form->_gvms_GImageBox->Parent  = NULL;
                ide_menu_Form->_gvms_GImageBox->Visible = false;

            //}

            //[GImageBox 가 촛점을 갖지 못하게 설정]
            //{
                //[윈도우/Linux:Wine 공통 지원][2023.02.02.목]{*************************
                //<GImageBox> 로 만든 <_gvms_GImageBox> 이 [촛점] 을 갖지 못하도록
                //<Enable:false> 로 설정.
                //
                //이는 그대로 두면 <GImageBox> 도 <TForm> 으로 만든 것이라 자동으로
                //[생성] 시 [촛점] 을 가지게 된다.
                //
                //[촛점] 은 [설정/해제] 시점이 [윈도우] 와 [Linux:Wine] 사이에 가장
                //일치 하지 않는 부분이다.
                //
                //그동안, 이 불일치성으로 [썸네일보이기] 기능을 넣은후 여러 오류가 발생
                //하였고, 이를 그때 그때 부분적으로 대처하다가 [촛점] 에 기인한 것임을
                //최종적으로 발견하고 이에 대한 해결책을 추가 한다.
                //
                //[윈도우] 는 그대로 두어도 상관없으나, [Linux:Wine] 쪽에서는 심각한
                //오류를 발생시키므로, 둘다 완벽하게 지원하기 위하여 구분하지 않는다.
                //
                //이로써 [윈도우] 와 [Linux:Wine] 의 불일치성은 완벽하게 해결됐다.
                //
                //[참고]****************************************************************
                //[그림부품] 이 [촛점] 을 갖지 못하게 하기 위해서는 <Enable:false> 로
                //설정하면 간단하게 해결된다(모든 Msg 를 아예 받지 않게된다).
                //
                //향후, [촛점] 을 일시적으로나 영구히 받지 못하게 할때 이 방법을 사용.
                //}*********************************************************************

                //[비활성색 적용 해제]
                //{
                    //[!]{---------------------------------------------------------------
                    //단, [그림부품] 은 <Enable:false> 시 [비활성색] 으로 강제 적용되나
                    //<GImageBox> 는 <Enable:false> 시에도 [비활성색] 적용을 [해제] 하는
                    //기능이 있으므로 보기 좋게 하기 위하여 이를 사용한다.
                    //}------------------------------------------------------------------

                    ide_menu_Form->_gvms_GImageBox->_DisableShape(false);

                //}

                //[비활성:촛점 설정 불가 설정]
                //{
                    ide_menu_Form->_gvms_GImageBox->_Enable(false);

                //}

            //}

          }

          //[설정]
          //{
              ide_menu_Form->_gvms_GImageBox->_Width(imageAreaWidth);
              ide_menu_Form->_gvms_GImageBox->_Height(imageAreaHeight);

              ide_menu_Form->_gvms_GImageBox->_Border(true);

              ide_menu_Form->_gvms_GImageBox->_ImageAreaX(0);
              ide_menu_Form->_gvms_GImageBox->_ImageAreaY(0);
              ide_menu_Form->_gvms_GImageBox->_ImageAreaWidth(imageAreaWidth);
              ide_menu_Form->_gvms_GImageBox->_ImageAreaHeight(imageAreaHeight);

              ide_menu_Form->_gvms_GImageBox->_BorderColor(ide_menu_Form->_listSubMenu->_borderColor);
              ide_menu_Form->_gvms_GImageBox->_BackColor(clWhite);

          //}

      //}

      //[그림 올리기]
      //{
          ide_menu_Form->_gvms_GImageBox->_Image(jpgPathNameExt, false);

      //}

      //[보이기]
      //{
          //[!]{------------------------------------------------
          //해당 항목 바로 옆에 <2 pixel> 정도 띄어서 보여준다.
          //}---------------------------------------------------

          //[좌표 계산]
          //{
              posX = ide_menu_Form->_listSubMenu->Left + ide_menu_Form->_listSubMenu->Width - 1;

              posY = ide_menu_Form->_listSubMenu->Top +
                     (ide_menu_Form->_listSubMenu->_fontMaxHeight *
                     (ide_menu_Form->_listSubMenu->_itemMouseSelIndex - ide_menu_Form->_listSubMenu->_scrollV->_position))
                     + 1;

          //}

          //[배치]
          //{
              ide_menu_Form->_gvms_GImageBox->_Left(posX);
              ide_menu_Form->_gvms_GImageBox->_Top(posY);

          //}

          //[보이기]
          //{
              ide_menu_Form->_gvms_GImageBox->Visible = true;

          //}

      //}

  //}

}

//------------------------------------------------------------------------------
//[특수기능 관련]---------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Ide_System_Mtdl_RcServoZero(void)
{
  //[2009.11.20.금][생성!!!]{---------------------------------------------------------
  //[맷돌-통합개발환경] 안의 특수기능으로 맷돌안의 서보제어기의 영점조정을 위한
  //별도 처리를 일괄 수행한다.
  //
  //[2011.11.20.일][수정!!!]----------------------------------------------------------
  //이전과 달리 [설계묶음] 을 설치하지 않고 직접 [가상기계(GVMX)] 를 설치한다.
  //이는 현재 열려있는 [설계묶음] 을 닫지 않고도 사용할수 있게 하기 위한 것.
  //
  //1) <Ide_System_GmrcbasicSetGvmx_Path> 경로의 [가상기계(GVMX)] 를 맷돌에 설치.
  //
  //2) 맷돌(G.MTDL.X) 재기동.
  //
  //3) 맷돌 변수 주소 읽기.
  //
  //4) [G.M.RC.BASiC 설정용] 대화상자 보이기.
  //
  //[참고!!!]-------------------------------------------------------------------------
  //맷돌(G.MTDL.X)에 설치하는 가상기계(GVMX)는 단지 PWM 을 초기화 하는 것에 불과하고
  //실제는 [직렬버스] 를 사용하여 직접 STM32F103C8T6 의 PWM 장치에 값을 쓰는 방식으로
  //처리하므로, 가상기계(GVMX) 안의 변수주소를 읽어들일 필요는 없다.
  //}---------------------------------------------------------------------------------

  //[VAR]
  //{
      //[통신포트 처리용]
      //{
          //[2011.11.20.일][추가!!!]
          class  COMPORT  *comPort;

          //통신포트 위치 얻기.
          COMPORT_GetPtr(d_ComportID_Vmos, &comPort);

      //}

  //}

  //[맷돌직접연결 인가?]
  //{
      //실제 맷돌을 대상으로 하므로 [맷돌직접연결] 인지 확인한다.
      if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "이 기능은 [맷돌직접연결] 인 경우만 사용 가능합니다.\r\n"
         "[맷돌직접연결] 을 선택후 다시 시도해 주십시요.");

        return;

      }

  //}

  //[통신포트 수신 저장소 비우기]
  //{
      //[!]{--------------------------------------------------------------
      //맷돌이 재기동후 [SysCom] 으로 예측되지 않은 몇바이트를 전송하므로
      //PC 쪽 통신포트의 [수신저장소] 를 확실하게 비우고 시작한다.
      //}-----------------------------------------------------------------

      comPort->Clear_RxdBuf();

  //}

  //[<VMOS:API> 적합성 검사]
  //{
      //[!]{--------------------------------------------------------------------
      //현재 맷돌에 설치돼 있는 VMOS 가 "Pwm" 를 지원하는지 확인한다.
      //단, 사용하는 <API 종류구분 단어> 는 정확하게 정의된 것을 사용해야 한다.
      //[대/소] 문자 구분은 하지 않는다.
      //각 <[운영체제].ginf> 문서에 단어별로 지원되는 <API 종류구분 단어> 가
      //정의돼 있다.
      //
      //[참고!!!]---------------------------------------------------------------
      //<API_Com> 은 모든 VMOS 가 다 지원하므로 검사결과 오류일수는  없지만
      //하나의 계통으로 만든다.
      //}-----------------------------------------------------------------------

      if(Ide_Mtdl_Vmos_Api_Match("Pwm") != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "현재 맷돌(G.MTDL.X)에 설치된 운영체제(VMOS)가 <API_Pwm> 계열을\r\n"
         "지원하지 않거나 지원 여부를 확인할수 없는 상태입니다.\r\n\r\n"
         "맷돌(G.MTDL.X)과 통신에 문제가 없다면 맷돌에 해당 API 를 지원하는\r\n"
         "운영체제(VMOS)를 먼저 설치하기 바랍니다.\r\n"
         "{ 메뉴 : 설정->맷돌 [운영체제] 설치 }\r\n");

        return;

      }

  //}

  //[설치]
  //{
	  if(Ide_API_GVMX_Install(((AnsiString)Ide_System_RcServoZero_Gvmx_Path).c_str(), false, NULL) != true) return;

  //}

  //[확인]
  //{
	  if(Ide_API_GVMX_Verify(((AnsiString)Ide_System_RcServoZero_Gvmx_Path).c_str(), NULL) != true) return;

  //}

  //[재기동]
  //{
      if(Ide_Mdl_Reset(false) != true) return;

  //}

  //[초기화 시간 대기]
  //{
      //[!]{---------------------------------------------------
      //[재기동] 후에 맷돌에 설치된 [가상기계(GVMX)] 가 완전히
      //[동작대기] 상태가 될때가지 대기한다.
      //}------------------------------------------------------

      Sleep(500);

  //}

  //[영점조정 대화상자 보이기]
  //{
      //항상 처음 나올때는 어떤 PWM 채널도 선택안된 상태로 해야 한다.
      //이 기능을 가진 [동작함수] 를 사용하여 해제해 준다.
      servoZero_DialogBox_Form->_EVENT_Down_pwm_RadioBtn();

      //해당 대화상자를 보여준다.
      servoZero_DialogBox_Form->Visible = true;

  //}

  return;

}

void __fastcall Ide_System_Mtdl_GmRcBasic(void)
{
  //[2009.11.24.화][생성!!!]{-----------------------------------------------------
  //[맷돌-통합개발환경] 안의 특수기능으로 맷돌에 연결된 G.M.RC.BASiC 설정을 위한
  //별도 처리를 일괄 수행한다.
  //
  //[2011.11.19.토][수정!!!]------------------------------------------------------
  //이전과 달리 [설계묶음] 을 설치하지 않고 직접 [가상기계(GVMX)] 를 설치한다.
  //이는 현재 열려있는 [설계묶음] 을 닫지 않고도 사용할수 있게 하기 위한 것.
  //
  //1) <Ide_System_GmrcbasicSetGvmx_Path> 경로의 [가상기계(GVMX)] 를 맷돌에 설치.
  //
  //2) 맷돌(G.MTDL.X) 재기동.
  //
  //3) 맷돌 변수 주소 읽기.
  //
  //4) [G.M.RC.BASiC 설정용] 대화상자 보이기.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      //[통신포트 처리용]
      //{
          //[2011.11.19.토][추가!!!]
          class  COMPORT  *comPort;

          //통신포트 위치 얻기.
          COMPORT_GetPtr(d_ComportID_Vmos, &comPort);

      //}

  //}

  //[맷돌직접연결 인가?]
  //{
      //실제 맷돌을 대상으로 하므로 [맷돌직접연결] 인지 확인한다.
      if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "이 기능은 [맷돌직접연결] 인 경우만 사용 가능합니다.\r\n"
         "[맷돌직접연결] 을 선택후 다시 시도해 주십시요.");

        return;

      }

  //}

  //[통신포트 수신 저장소 비우기]
  //{
      //[!]{--------------------------------------------------------------
      //맷돌이 재기동후 [SysCom] 으로 예측되지 않은 몇바이트를 전송하므로
      //PC 쪽 통신포트의 [수신저장소] 를 확실하게 비우고 시작한다.
      //}-----------------------------------------------------------------

      comPort->Clear_RxdBuf();

  //}

  //[<VMOS:API> 적합성 검사]
  //{
      //[!]{--------------------------------------------------------------------
      //현재 맷돌에 설치돼 있는 VMOS 가 "Com" 를 지원하는지 확인한다.
      //단, 사용하는 <API 종류구분 단어> 는 정확하게 정의된 것을 사용해야 한다.
      //[대/소] 문자 구분은 하지 않는다.
      //각 <[운영체제].ginf> 문서에 단어별로 지원되는 <API 종류구분 단어> 가
      //정의돼 있다.
      //
      //[참고!!!]---------------------------------------------------------------
      //<API_Com> 은 모든 VMOS 가 다 지원하므로 검사결과 오류일수는  없지만
      //하나의 계통으로 만든다.
      //}----------------------------------------------------------------------- 

      if(Ide_Mtdl_Vmos_Api_Match("Com") != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "현재 맷돌(G.MTDL.X)에 설치된 운영체제(VMOS)가 <API_Com> 계열을\r\n"
         "지원하지 않거나 지원 여부를 확인할수 없는 상태입니다.\r\n\r\n"
         "맷돌(G.MTDL.X)과 통신에 문제가 없다면 맷돌에 해당 API 를 지원하는\r\n"
         "운영체제(VMOS)를 먼저 설치하기 바랍니다.\r\n"
         "{ 메뉴 : 설정->맷돌 [운영체제] 설치 }\r\n");

        return;

      }

  //}

  //[설치]
  //{
	  if(Ide_API_GVMX_Install(((AnsiString)Ide_System_GmrcbasicSet_Gvmx_Path).c_str(), false, NULL) != true) return;

  //}

  //[확인]
  //{
	  if(Ide_API_GVMX_Verify(((AnsiString)Ide_System_GmrcbasicSet_Gvmx_Path).c_str(), NULL) != true) return;

  //}

  //[재기동]
  //{
      if(Ide_Mdl_Reset(false) != true) return;

  //}

  //[초기화 시간 대기]
  //{
      //[!]{---------------------------------------------------
      //[재기동] 후에 맷돌에 설치된 [가상기계(GVMX)] 가 완전히
      //[동작대기] 상태가 될때가지 대기한다.
      //}------------------------------------------------------

      Sleep(500);

  //}

  //[기본 처리]
  //{
      //[2009.11.27.금][추가!!!]{----------------------------
      //맷돌에 설치된 가상기계의 중요 변수 위치 등을 얻는다.
      //}----------------------------------------------------

      if(gmrcbasic_DialogBox_Form->Mtdl_VarAdrTable_Read() != true) return;

  //}

  //[G.M.RC.BASiC 설정 대화상자 보이기]
  //{
      //해당 대화상자를 보여준다.
      gmrcbasic_DialogBox_Form->Visible = true;

  //}

  return;

}

void __fastcall Ide_System_Mtdl_GmRcBasic_Make(void)
{
  //[2009.12.05.토][생성!!!]{----------------------------------------------------------
  //[맷돌-통합개발환경] 안의 특수기능으로 맷돌에 연결된 G.M.RC.BASiC 을 자동 제작한다.
  //
  //[2011.11.13.일][전부수정!!!]-------------------------------------------------------
  //이전과 달리 대응하는 [설계묶음] 을 열고 진행하지 않고, 바로 [맷돌(G.MTDL.X)] 에
  //[가상기계(GVMX)] 를 설치하는 것으로 수정한다.
  //이 편이 [맷돌] 에 얼마든지 [가상기계] 를 재설치 할수 있으므로 유리하다.
  //
  //새로 [설계묶음] 을 열지 않기 때문에 현재 열려있는 설계묶음을 [닫을] 필요가 없다.
  //
  //1) 현재 <[v]맷돌직접연결> 상태인지 확인하고, 아니라면 <[v]맷돌직접연결> 로 만들기.
  //
  //2) [G.M.RC.BASiC 자동 제작기] 대화상자 보이기.
  //
  //3) 사용자가 [설치] 버튼으로 직접 [맷돌(G.MTDL.X)] 에 [가상기계(GVMX)] 설치.
  //
  //4) 사용준비 완료.
  //}----------------------------------------------------------------------------------

  //[맷돌직접연결 인가?]
  //{
      //실제 맷돌을 대상으로 하므로 [맷돌직접연결] 인지 확인한다.
      if(ide_buttons_Form->_vmosMdl_CheckBtn->_checked != true)
      {
        ide_msgbox_Form->_MsgBox
        (d_MSGBOX_error,
         "이 기능은 [맷돌직접연결] 인 경우만 사용 가능합니다.\r\n"
         "[맷돌직접연결] 을 선택후 다시 시도해 주십시요.");

        return;

      }

  //}

  //[기본 처리]
  //{
      //[2011.11.13.일][수정!!!]{----------------------------------------
      //아직 맷돌이 연결돼 있지 않을수 있으므로 여기서는 읽어들이지 않고
      //[자동 제작시] 에 읽고 시작하는 것으로 수정한다.
      //여기서는 [주석] 으로 처리하고 사용하지 않는다.
      //}----------------------------------------------------------------

      //if(gmrcbasicMake_DialogBox_Form->Table_VarAdrTable_Read() != true) return;

  //}

  //[G.M.RC.BASiC 설정 대화상자 보이기]
  //{
      //해당 대화상자를 보여준다.
      gmrcbasicMake_DialogBox_Form->Visible = true;

  //}

  return;

}

//------------------------------------------------------------------------------
//[시험용 함수들]---------------------------------------------------------------
//------------------------------------------------------------------------------

/*
void __fastcall Ide_Test_Gmrc(void)
{
  //[2009.04.21.화][생성!!!]{--------------------------
  //VMOS 에서 [G.M.RC.BASiC] 동작 제어 확인을 위한 것.
  //원래 AVR 소스를 그대로 돌렸는데 아주 잘 동작된다.
  //}--------------------------------------------------

  //[VAR]
  //{
      //8 개의 값을 포인터로 한번에 넘겨 주기 위한 임시 저장소.
      //여러 함수에서 사용하나 한개만 선언해 주면 된다.
      unsigned char tempVal[8];

  //}

  //[사전 설정]
  //{
      //구동 전에 G.M.RC.BASiC 을 해당 서보에 맞게 각각 설정한다.
      //각각의 자세한 정보는 홈페이지의 G.M.RC.BASiC 제품란을 참고 바람.

      //[완료보고시간 설정]
      //{
          //기본 값으로 100% 일때 보고 할수 있게 설정한다(100% 인 경우는 그냥 두어도 됨).
          tempVal[0] = 100;
          tempVal[1] = 100;
          GMRCBASIC_ReportTimeX(0, 2, tempVal);

      //}

      //[가감속상수 설정]
      //{
          //가감속상수는 완전 독립적으로 적용되며 각 서보의 동작에 맞게 설정하면 됨.
          tempVal[0] = 10;
          tempVal[1] = 5;
          GMRCBASIC_AccelDivX(0, 2, tempVal);

      //}

      //[속도 설정]
      //{
          //속도 값은 작을수록 빠르게 동작됨.
          //예제는 각도만 계속 반복적으로 변화되므로 속도는 여기서 한번만 설정한다.
          tempVal[0] = 5;
          tempVal[1] = 5;
          GMRCBASIC_SpdMemX(0, 2, tempVal);

          //설정해 놓은 속도를 일괄적으로 즉시 반영함.
          GMRCBASIC_MemSet(0);

      //}

  //}

  Start:

  //{
      //[30 도 위치로 이동]
      //{
          //각도를 기억시킨다.
          tempVal[0] = 0;
          tempVal[1] = 0;
          GMRCBASIC_DegMemX(0, 2, d_Accel, tempVal);

          //기억시킨 각도를 즉시 반영시킨다(서보 구동 시작).
          GMRCBASIC_MemSet(0);

      //}

      //[완료보고]
      //{
          //30 도 위치까지 도달한 경우 이를 보고할 것을 지시.
          GMRCBASIC_Report(0);

          //보고값이 전달될때까지 대기.
          GMRCBASIC_WaitReport();

          //

      //}

      //[150 도 위치로 이동]
      //{
          //각도를 기억시킨다.
          tempVal[0] = 180;
          tempVal[1] = 180;
          GMRCBASIC_DegMemX(0, 2, d_Accel, tempVal);

          //기억시킨 각도를 즉시 반영시킨다(서보 구동 시작).
          GMRCBASIC_MemSet(0);

      //}

      //[완료보고]
      //{
          //30 도 위치까지 도달한 경우 이를 보고할 것을 지시.
          GMRCBASIC_Report(0);

          //보고값이 전달될때까지 대기.
          GMRCBASIC_WaitReport();

      //}

  //}

  //반복을 위하여 다시 시작 위치로 이동.
  //굳이 goto 를 사용한것은 G.M.RC.BASiC-IDE 명령어에 맞추기 위한 것임.
  //반복을 위해서는 while(), for() 문을 사용해도 무방함.
  //goto  Start;

  return;

}
*/

/*
void __fastcall Ide_Test_Flash(void)
{
  //[2009.07.07.화][생성!!!]{------------------------------------------------------
  //[맷돌모듈] 에 사용되는 STM32F103 의 Flash 에 기록 속도등을 확인하기 위한 함수.
  //사용하기 전에 통신 포트를 열어주어야 한다.
  //}------------------------------------------------------------------------------

  //[VAR]
  //{
      //[통신포트 처리용]
      class  COMPORT  *comPort;

      int  i;


  //}


  //[통신포트 위치 얻기]{---
  COMPORT_GetPtr(&comPort);
  //}-----------------------


  //[통신포트열기]
  //{
      comPort->Open("COM4", 115200);

  //}


  msg_msg_Form->_Print(d_msg_msg, "");

  //Flash 에 접근을 허가한다.
  Flash_Key();
  msg_msg_Form->_PrintAddLine(d_msg_msg, "Flash 접근 허가완료!");


  //BaseVM 영역(4KByte)을 제외하고 전부 지운다.
  Flash_Erase();
  msg_msg_Form->_PrintAddLine(d_msg_msg, "Flash 60개 페이지 지우기 완료!");


  //1 KByte 를 기록한다.
  for(i = 0; i < 0x400; i += 2)
  {
    //한번에 2 Byte 씩만 기록이 가능하다.
    Flash_Write(//BaseVM 영역(4 KByte) 다음부터 시작한다.
                0x1000 + i,
                //해당 주소값을 그대로 기록한다.
                0x1000 + i);

  }

  msg_msg_Form->_PrintAddLine(d_msg_msg, "Flash 1 페이지(1024 Byte) 기록 완료!");


  //[통신포트닫기]
  //{
      comPort->Close();

  //}

  return;

}
*/

void __fastcall Ide_Copy_VmosGos_In_OsFolder(void)
{
  //[2009.08.26.수][생성!!!]{-----------------------------------------------------------
  //개발시에 계속 복사하기 불편하므로 아예 직접 IAR 에서 생성된 것을 [운영체제] 가 있는
  //"os" 와 "os+math" 폴더안에 자동 복사해주는 함수를 만든다.
  //
  //이 함수는 임시기능으로 개발시에만 유효하다.
  //}-----------------------------------------------------------------------------------

  //[<vmos.gos> 복사]
  //{
      //[!]{-----------------------------------------------
      //지정 폴더안의 <vmos.gos> 를 지정위치안에 복사한다.
      //"os" 와 "os+math" 두개 폴더안에 모두 복사한다.
      //}--------------------------------------------------

      //[이미 있는것 지우기]
      //{
          //[2009.09.05.토][수정!!!]{---------------------------------------------
          //File_Copy() 함수 내부적으로 도착지에 있는 같은 문서는 자동 삭제되므로
          //이 부분은 주석으로 처리한다.
          //}---------------------------------------------------------------------

          //DeleteFile(Ide_Os_Default_Path);
          //DeleteFile(Ide_Os_Math_Path);

      //}

      //[복사]
      //{
          /*
          //<os> 에 복사.
          File_Copy(Ide_Os_Default_Path,
                    "H:\\GIGYENICS\\GIGYEIN\\G_PART\\MTDL\\IAR\\맷돌(SPI Flash)\\VMOS\\VMOS\\Debug\\Exe\\vmos.gos");

          //<os+math> 에 복사.
          File_Copy(Ide_Os_Math_Path,
                    "H:\\GIGYENICS\\GIGYEIN\\G_PART\\MTDL\\IAR\\맷돌(SPI Flash)\\VMOS\\VMOS\\Debug\\Exe\\vmos.gos");

          */

          /*
          //[2009.12.14.월][추가!!!]
          File_Copy(Ide_Os_AT45DB041B,
                    "H:\\GIGYENICS\\GIGYEIN\\G_PART\\MTDL\\IAR\\맷돌(SPI Flash)\\VMOS\\VMOS\\Debug\\Exe\\vmos.gos");
          */

      //}

  //}

  return;

}

void __fastcall Ide_Test_TreeItem(int  pX, int  pY, char  *pStr)
{
  //[2012.05.17.목][생성!!!]{----------------
  //<tree_tree> 항목 문자열 [귀뜸말] 확인용.
  //}----------------------------------------

  //[VAR]
  //{
      class  DATABASE  *database;

      int    width;
      int    height;

      TRect  rect;

      int    color;

      int    listCount = 0;

  //}
           
  //[설정 정보]
  //{
      //[형식 적용 문자열] 저장소.
      unsigned char  confStr[10*1024];

      struct STRCONF_STRHEAP_ITEM  setList[4];

      struct STRCONFITEM  stdConf;

  //}

  //[재정리 문자열]
  //{
      //char  reMakeStr[1024*4];

      //문자열 재정리.
      //FuncDefStr_ReMake_TreeItem(pStr, reMakeStr);

  //}

  //[DB 위치 얻기]{-----------
  DATABASE_GetPtr(&database);
  //}-------------------------


  //[색밝기조정]
  //{
      BMP_Get_Bright_Color(_ide_Option.color_0, IDE_BRIGHT_hint, &color);

  //}


  //[기본:출력 형식 설정]
  //{
      stdConf.frontColor  = clBlack;
      stdConf.backColor   = color;//clWhite;
      stdConf.style       = d_FONTSTYLE_default;
      stdConf.transparent = false;

  //}

  //[예약어:출력 형식 설정]
  //{
      setList[listCount].sn = database->_strHeap_Conf_Keyword_s;
      setList[listCount].en = database->_strHeap_Conf_Keyword_e;

      setList[listCount].conf.frontColor  = _ide_Option.color_0;
      setList[listCount].conf.backColor   = color;
      setList[listCount].conf.style       = d_FONTSTYLE_bold;
      setList[listCount].conf.transparent = false;

      listCount++;

  //}

  //[연산자:출력 형식 설정]
  //{
      //"*"(operatorlist[27].op) 포인터를 지정하기 위한것.
      //

      setList[listCount].sn = database->_strHeap_Conf_Operator_s;
      setList[listCount].en = database->_strHeap_Conf_Operator_e;

      setList[listCount].conf.frontColor  = _ide_Option.color_0;
      setList[listCount].conf.backColor   = color;
      setList[listCount].conf.style       = d_FONTSTYLE_default;
      setList[listCount].conf.transparent = false;

      listCount++;

  //}

  //[기호:출력 형식 설정]
  //{
      /*
      setList[listCount].sn = database->_strHeap_Conf_Sign_s;
      setList[listCount].en = database->_strHeap_Conf_Sign_e;

      setList[listCount].conf.frontColor  = _ide_Option.color_0;
      setList[listCount].conf.backColor   = color;
      setList[listCount].conf.style       = d_FONTSTYLE_default;
      setList[listCount].conf.transparent = false;

      listCount++;
      */

  //}

  //[구조체/공용체 이름:출력 형식 설정]
  //{
      setList[listCount].sn = database->_strHeap_Conf_Type_s;
      setList[listCount].en = database->_strHeap_Conf_Type_e;

      setList[listCount].conf.frontColor  = _ide_Option.color_0;
      setList[listCount].conf.backColor   = color;
      setList[listCount].conf.style       = d_FONTSTYLE_default;
      setList[listCount].conf.transparent = false;

      listCount++;

  //}



  //[형식 문자열 변환]
  //{
      StrConf_Word_Set(confStr,
                       &(database->_strHeap_Conf),
                       setList, listCount,
                       stdConf,
                       pStr);

  //}



  ide_hint_Form->_ShowHint_StrConf_AutoLineInPart(tree_tree_Form, pX, pY, confStr);


  return;





  editor_edit_Form->_bmp_->Canvas->Brush->Color = clWhite;
  editor_edit_Form->_bmp_->Canvas->FillRect(editor_edit_Form->_bmp_->Canvas->ClipRect);


  //[출력]
  //{
      StrConf_Out_AutoLine(editor_edit_Form->_bmp_,
                           &(editor_edit_Form->_font),
                           0,
                           2,
                           editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,

                           confStr,

                           NULL,
                           NULL);

  //}

  //[2012.05.19.토[추가!!!]]
  StrConf_AutoLine_OutAreaInfo(&(editor_edit_Form->_font),
                                 editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,
                                 confStr,
                                 &width,
                                 &height);

/*
  Font_Get_AutoLineStr_OutAreaInfo(&(editor_edit_Form->_font),
                                   d_FONTSTYLE_default,
                                   editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,
                                   pStr,
                                   &width,
                                   &height);
*/

  editor_edit_Form->_bmp_->Canvas->Pen->Color   = clRed;
  editor_edit_Form->_bmp_->Canvas->Pen->Width   = 1;
  editor_edit_Form->_bmp_->Canvas->Brush->Style = bsClear;




    rect.Left   = editor_edit_Form->_font.margin_size;
    rect.Top    = 2;
    rect.Right  = rect.Left + (editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4);
    rect.Bottom = rect.Top + height;

    editor_edit_Form->_bmp_->Canvas->Pen->Color   = clRed;
    editor_edit_Form->_bmp_->Canvas->Rectangle(rect);



    rect.Left   = editor_edit_Form->_font.margin_size;
    rect.Top    = 2;
    rect.Right  = rect.Left + width;
    rect.Bottom = rect.Top + height;

    editor_edit_Form->_bmp_->Canvas->Pen->Color   = clBlue;
    editor_edit_Form->_bmp_->Canvas->Rectangle(rect);




  editor_edit_Form->_bmp_->Canvas->FillRect(editor_edit_Form->_bmp_->Canvas->ClipRect);



  editor_edit_Form->_Draw();


}

/*
void __fastcall Ide_Test(int  pTemp)
{
  //[2012.06.04.월][생성!!!]
  //전달 받은 값을 [출력창:제목줄] 에 표시.
  ide_msg_Form->_captionbar_Form->_Caption(IntToStr(pTemp));


}
*/

void __fastcall Ide_Test(void)
{
  //[2021.07.24.토][생성]

  /*
  //[VAR]
  //{
      int   postSpaceCount = 0;

      char  str[1024];


  //}

  postSpaceCount = Str_Get_ThisLinePostSpaceCount(editor_edit_Form->_editbuf,
                                                  editor_edit_Form->_caretindex);


  CONV_LongVal_To_Str(postSpaceCount, 0, false, str);

  ide_msgbox_Form->_MsgBox(d_MSGBOX_default,
                           str);
  */

  //Ide_Menu_SpaceArrange();

}

/*
void __fastcall Ide_Test(void)
{
  //[2012.05.17.목][생성!!!]{--
  //함수 확인용.
  //}--------------------------

  //[VAR]
  //{
      class  DATABASE  *database;

      char  *str;

  //}

  //[설정 정보]
  //{
      //[형식 적용 문자열] 저장소.
      unsigned char  confStr[10*1024];

      struct STRCONF_STRHEAP_ITEM  setList;

      struct STRCONFITEM  stdConf;

  //}

  //[DB 위치 얻기]{-----------
  DATABASE_GetPtr(&database);
  //}-------------------------

  //[기본:출력 형식 설정]
  //{
      stdConf.frontColor  = clBlack;
      stdConf.backColor   = clWhite;
      stdConf.style       = d_FONTSTYLE_default;
      stdConf.transparent = false;

  //}

  //[출력 형식 설정]
  //{
      setList.sn = database->_strHeap_Conf_Keyword_s;
      setList.en = database->_strHeap_Conf_Keyword_e;

      setList.conf.frontColor  = clRed;
      setList.conf.backColor   = clWhite;
      setList.conf.style       = d_FONTSTYLE_bold;
      setList.conf.transparent = false;

  //}

  //[형식 문자열 변환]
  //{
      str = "unsigned ((( > ;signed.  char-+ short++  \r\n*int   (long)제대로 처리 확인!";

      StrConf_Word_Set(confStr,
                       &(database->_strHeap_Conf),
                       &setList, 1,
                       stdConf,
                       str);

  //}

  //[출력]
  //{
      StrConf_Out_AutoLine(editor_edit_Form->_bmp_,
                           &(editor_edit_Form->_font),
                           0,
                           2,
                           editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,

                           confStr,

                           NULL,
                           NULL);

      editor_edit_Form->_Draw();

  //}

}
*/

/*
void __fastcall Ide_Test(void)
{
  //[2012.05.17.목][생성!!!]{--
  //함수 확인용.
  //}--------------------------

  //[VAR]
  //{
      char  *str;

  //}

  //[설정 정보]
  //{
      //[형식 적용 문자열] 저장소.
      unsigned char  confStr[10*1024];

      struct STRCONF_STRHEAP_ITEM  setList[3];

      struct STRCONFITEM  stdConf;

  //}

  //[STRHEAP 관련]
  //{
      //[2012.05.06.일][추가!!!]{-----------------------------------------
      //[문자열] 은 [STRHEAP] 으로 별도 관리.
      //작은 동적 생성으로 인한 부하를 줄이고 관리를 쉽게 하기위한것.
      //기본 크기는 <d_STRHEAP_Heap_addSize>, <d_STRHEAP_List_addSize> 의
      //[재생성] 시 추가 크기 증가분 정도면 충분하다.
      //
      //반드시 한번만 초기화 해야 한다.
      //}-----------------------------------------------------------------

      struct STRHEAP  strHeap;

      //STRHEAP 기록 번호 받기.
      int    shn;

      STRHEAP_Init(&strHeap);

      //생성.
      STRHEAP_Create(&strHeap,
                     //10K 크기.
                     10*1024,
                     //1024 개 목록.
                     d_STRHEAP_List_addSize);

  //}




  //[설정]
  //{
      //일단 비교 문자열은 각 2개씩 3개조만 사용.

      //처음 저장시는 반드시 <-1> 사용.

      //[0 - 1]
      //{
          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "unsigned");

          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "signed");

          //[출력 형식 설정]
          //{
              setList[0].sn = 0;
              setList[0].en = 1;

              setList[0].conf.frontColor  = clLime;
              setList[0].conf.backColor   = clBlack;
              setList[0].conf.style       = d_FONTSTYLE_default;
              setList[0].conf.transparent = false;

          //}

      //}



      //[2 - 3]
      //{
          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "char");

          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "short");

          //[출력 형식 설정]
          //{
              setList[1].sn = 2;
              setList[1].en = 3;

              setList[1].conf.frontColor  = clRed;
              setList[1].conf.backColor   = clGray;
              setList[1].conf.style       = d_FONTSTYLE_bold;
              setList[1].conf.transparent = false;

          //}

      //}

      //[4 - 5]
      //{
          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "int");

          shn = -1;
          STRHEAP_Str(&strHeap, &shn, "long");

          //[출력 형식 설정]
          //{
              setList[2].sn = 4;
              setList[2].en = 5;

              setList[2].conf.frontColor  = clBlue;
              setList[2].conf.backColor   = clLime;
              setList[2].conf.style       = d_FONTSTYLE_default;
              setList[2].conf.transparent = false;

          //}

      //}

      //[기본:출력 형식 설정]
      //{
          stdConf.frontColor  = clBlack;
          stdConf.backColor   = clWhite;
          stdConf.style       = d_FONTSTYLE_default;
          stdConf.transparent = false;

      //}

  //}




  //[형식 문자열 변환]
  //{
      str = "unsigned ((( > ;signed.  char-+ short++  \r\n*int   (long)제대로 처리 확인!";

      StrConf_Word_Set(confStr,
                       &strHeap,
                       setList, 3,
                       stdConf,
                       str);



  //}



  //[STRHEAP:삭제]
  //{
      //[2012.05.06.일][추가!!!]{------------
      //<txt> 를 위한 [STRHEAP] 전체를 삭제.
      //}------------------------------------

      STRHEAP_Delete(&strHeap);

  //}



  //[출력]
  //{
      StrConf_Out_AutoLine(editor_edit_Form->_bmp_,
                           &(editor_edit_Form->_font),
                           0,
                           2,
                           editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,

                           confStr,

                           NULL,
                           NULL);

      editor_edit_Form->_Draw();

  //}

}
*/

/*
void __fastcall Ide_Test(char  *pStr)
{
  //[2012.05.16.수][생성!!!]{--
  //함수 확인용.
  //}--------------------------

  //[VAR]
  //{
      int  width;
      int  height;

      TRect  rect;

  //}

  editor_edit_Form->_bmp_->Canvas->Brush->Color = clWhite;
  editor_edit_Form->_bmp_->Canvas->FillRect(editor_edit_Form->_bmp_->Canvas->ClipRect);

  Font_StyleStr_AutoLine(editor_edit_Form->_bmp_,
                         &(editor_edit_Form->_font),
                         0,
                         2,
                         editor_edit_Form->Width - editor_edit_Form->_bmp_debug->Width - 13 - 4,
                         clBlack,
                         clSilver,
                         false,
                         d_FONTSTYLE_default,
                         pStr,
                         d_FONT_underline_no,
                         true,
                         0,
                         clRed,
                         NULL,
                         NULL);

  Font_Get_AutoLineStr_OutAreaInfo(&(editor_edit_Form->_font),
                                   d_FONTSTYLE_default,
                                   editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,
                                   pStr,
                                   &width,
                                   &height);


  editor_edit_Form->_bmp_->Canvas->Pen->Color   = clRed;
  editor_edit_Form->_bmp_->Canvas->Pen->Width   = 1;
  editor_edit_Form->_bmp_->Canvas->Brush->Style = bsClear;




    rect.Left   = editor_edit_Form->_font.margin_size;
    rect.Top    = 2;
    rect.Right  = rect.Left + (editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4);
    rect.Bottom = rect.Top + height;

    editor_edit_Form->_bmp_->Canvas->Pen->Color   = clRed;
    editor_edit_Form->_bmp_->Canvas->Rectangle(rect);



    rect.Left   = editor_edit_Form->_font.margin_size;
    rect.Top    = 2;
    rect.Right  = rect.Left + width;
    rect.Bottom = rect.Top + height;

    editor_edit_Form->_bmp_->Canvas->Pen->Color   = clBlue;
    editor_edit_Form->_bmp_->Canvas->Rectangle(rect);




  editor_edit_Form->_bmp_->Canvas->FillRect(editor_edit_Form->_bmp_->Canvas->ClipRect);



  editor_edit_Form->_Draw();



}
*/

void __fastcall Ide_GuiPart_Test0(void)
{
  //editor_edit_Form->_LineBlock_MoveRL_Right(1);

  //Ide_Test();

  //return;


  /*
  //[VAR]
  //{
      char  tempStr[OPT_lineStrSize];

  //}

  Font_StyleStr_AutoLine(editor_edit_Form->_bmp_,
                         &(editor_edit_Form->_font),
                         0,
                         2,
                         editor_edit_Form->Width  - editor_edit_Form->_bmp_debug->Width - 13 - 4,
                         clBlack,
                         clSilver,
                         false,
                         d_FONTSTYLE_default,
                         "//문자열 출력후 변경된 (x, y) 좌표를 반환한다. \r\n//문자 출력 BOX 영역의 아래를 기준으로 한 위치.",

                         d_FONT_underline_no,
                         true,
                         0,
                         clRed,
                         NULL,
                         NULL);

  editor_edit_Form->_Draw();
  */

  //Ide_RealTimeInfo(editor_edit_Form->_textinfo[editor_edit_Form->_textinfo_index].filename.c_str());


/*
  Str_Line_AutoLine_Width(Ide_System_OS_AT45DB041B_Circuit_Path.c_str(),
                          &(editor_edit_Form->_font), d_FONTSTYLE_default,
                          400,
                          tempStr);

  ide_msgbox_Form->_MsgBox(d_MSGBOX_info, tempStr);

  return;

  Str_FileName_Width_Ellipsis(Ide_System_OS_AT45DB041B_Circuit_Path.c_str(),
                              &(editor_edit_Form->_font), d_FONTSTYLE_default,
                              400,
                              tempStr);

  ide_msgbox_Form->_MsgBox(d_MSGBOX_info, tempStr);

  return;
*/


/*
  //[VAR]
  //{
      //[선택영역] 정보를 순서대로 얻기 위한것.
      struct CARETINFO  select_start;
      struct CARETINFO  select_end;

  //}

  //[선택 영역 정보 얻기]
  //{
      editor_edit_Form->_SELECT_Get_StartEndIndex(&select_start, &select_end);

  //}

  //[영역 정보 얻기]
  //{
      //시작행 시작위치 얻기.
      STR_Get_ThisLineStartIndex(editor_edit_Form->_editbuf, select_start.caret_index, &(select_start.caret_index));

      //끝행 시작위치 얻기.
      STR_Get_ThisLineStartIndex(editor_edit_Form->_editbuf, select_end.caret_index, &(select_end.caret_index));

  //}

  editor_edit_Form->History_MoveRL_Right(select_start.caret_index,
                                         select_start.caret_index,
                                         select_end.caret_index,
                                         1);

  return;
*/

  /*
  struct DBGEXP_TREE_INFO   info;

  //초기화.
  DbgExpTreeInfo_Format(&info);

  STR_Assign(info.infoStr,
             "(A + B*C)/3 + 100\r\n"
             "1234\r\n"
             "함수이름 : main\r\n"
             "기반주소 : DATA(전역변수)\r\n"
             "자료유형 : (unsigned short)");

  Ide_Tree_DbgExp_Add(&info, NULL);


  STR_Assign(info.infoStr,
             "100*3.14\r\n"
             "0xabcdef\r\n"
             "함수이름 : 함수A\r\n"
             "기반주소 : LOCAL(지역변수)\r\n"
             "자료유형 : (unsigned long)");

  Ide_Tree_DbgExp_Add(&info, NULL);


  STR_Assign(info.infoStr,
             "변수이름\r\n"
             "0b11011101\r\n"
             "함수이름 : 함수B\r\n"
             "기반주소 : LOCAL(지역변수)\r\n"
             "자료유형 : (int)");

  Ide_Tree_DbgExp_Add(&info, NULL);
  */

}

void __fastcall Ide_GuiPart_Test1(void)
{
  //editor_edit_Form->_LineBlock_Move_Left(1);

  /*
  //[VAR]
  //{
      //[선택영역] 정보를 순서대로 얻기 위한것.
      struct CARETINFO  select_start;
      struct CARETINFO  select_end;

  //}

  //[선택 영역 정보 얻기]
  //{
      editor_edit_Form->_SELECT_Get_StartEndIndex(&select_start, &select_end);

  //}

  //[영역 정보 얻기]
  //{
      //시작행 시작위치 얻기.
      STR_Get_ThisLineStartIndex(editor_edit_Form->_editbuf, select_start.caret_index, &(select_start.caret_index));

      //끝행 시작위치 얻기.
      STR_Get_ThisLineStartIndex(editor_edit_Form->_editbuf, select_end.caret_index, &(select_end.caret_index));

  //}

  editor_edit_Form->History_MoveRL_Left(select_start.caret_index,
                                        select_start.caret_index,
                                        select_end.caret_index,
                                        1);

  return;

  */

  /*
  //[VAR]
  //{
      struct CARETINFO   select_start;
      struct CARETINFO   select_end;

      char  bufA[1024*10];
      char  bufB[1024*10];

      int   size;

  //}

  //[<선택영역> 이 존재하나?]
  //{
      if(editor_edit_Form->_SELECT_Get_StartEndIndex(&select_start, &select_end) != true) return;

  //}

  //[<선택영역> 문자열 추출]
  //{
      //[문자열 크기 얻기]
      //{
          //순수 문자열 길이 얻기.
          size = select_end.caret_index - select_start.caret_index;

      //}

      //[문자열 추출]
      //{
          //[선택영역] 문자열을 추출한다.
          STR_SubString(editor_edit_Form->_editbuf,
                        select_start.caret_index, size,
                        bufA);

      //}

  //}

  //[주석문 제거]
  //{
      Str_Delete_Comment(bufA, bufB);

  //}

  //[한개 행으로 합성]
  //{
      Str_XLine_To_1Line_Trim(bufB, bufA, 0);

  //}

//  ide_msgbox_Form->_MsgBox(d_MSGBOX_info, bufA);
//  return;



  //[길이에 따른 "..." 처리]
  //{
      Str_Width_Ellipsis(bufA,
                         &(editor_edit_Form->_dbgView_font),
                         d_FONTSTYLE_default,
                         500,
                         bufB);

  //}

  ide_msgbox_Form->_MsgBox(d_MSGBOX_info, bufB);
  */

}

bool __fastcall Ide_Parser_OneFile(char  *pPathNameExt)
{
  //[2012.05.11.금][생성!!!]{---------------------------------------
  //<Alt+F9> 조합의 경우 사용.
  //지정 한개 문서(C/H) 만 [문법검사(Parser())] 수행하고 결과 보고.
  //
  //[2012.05.16+2.금][수정!!!]--------------------------------------
  //[2012.05.23.수][수정!!!]----------------------------------------
  //[2012.05.26.토][수정!!!]----------------------------------------
  //[중복 처리 방지] 기능 추가.
  //[2012.05.27.일][수정!!!]----------------------------------------
  //[중복 처리 방지] 기능 [해제].
  //[2022.06.02.목][중요수정]---------------------------------------
  //}---------------------------------------------------------------

  //[VAR]
  //{
      class DATABASE  *database;

      AnsiString       msgStr = "";

      //[풍선도움말 API 추가 정보 문자열 관련]
      //{
          //[2022.06.02.목][추가]
          //자동 추가된 API 기본 정보를 출력하기 위하여 필요.
          char  balloonStr[1024*10];
          int   bls;

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.06.08.수][추가]
          VSTRBUF  *vStrBuf_ = NULL;
          
          char     *defFile_ApiList_ = NULL;
          int       defFile_ApiCount = 0;
          char      defFile_ApiName_[OPT_filepath_length];

          //[2022.06.09.목][추가]
          //[오류단어] 가 <struct, union> 인 경우 다음단어를 가진다.
          char      errorNextWord_[OPT_filepath_length];

          //[2022.07.14.목][추가]
          //[단어] 가 존재하지 않는 경우는 <-1>.
          int       errorWordStartIndex;

      //}

  //}

  //[{DB} 위치 얻기]
  //{
      //[2023.01.29.일][중요추가]{*********************************************************
      //{DB} 주소 얻는 부분을 이 위치로 이동.
      //이는 [설계묶음] 이 없는 경우 아래 [새설계묶음인가?] 부분에서 오류로 처리 되어
      //<lbError:> 로 이동하게 되는데, 아직 {DB} 의 주소를 얻지 못한 상태에서 이 처리 부의
      //<API_Check()> 함수가 <DB> 에 접근하기 때문에 [포인터오류] 가 계속 발생하게 된다.
      //따라서, 어떤 경우라도 확실하게 {DB} 에 접근할수 있도록 아예 이 함수 가장 첫부분인
      //여기서 {DB} 주소를 확정한다.
      //}**********************************************************************************

      DATABASE_GetPtr(&database);

  //}


  lbStart: //[2022.06.02.목][추가]

  //[<Parser()> 중복 처리 방지]
  //{
      //[2012.05.26.토][추가!!!]{------------------------------------------
      //<Parser()> 함수의 [중복실행] 을 [방지] 하기위한것.
      //
      //[2012.05.27.일][수정!!!]-------------------------------------------
      //<Ctrl+Space> 의 경우는 [중복] 시에도 큰 문제가 없고 완벽 동작한다.
      //<Ctrl+F9>, <Alt+F9> 의 경우는 자체적으로 [중복 방지] 된다.
      //
      //이 방식은 [예측할수 없는 오류] 등으로 종료되는 경우는 계속 값을
      //가지고 있기 때문에 [재동작] 시 [중복] 으로 간주되어 다시 함수를
      //동작 시킬수 없게 된다.
      //
      //일단, 사용하지 않는 것으로 하고 [주석] 처리한다.
      //}------------------------------------------------------------------

      //이미 처리중이라면 [이상없음] 으로 종료.
      //if(_ParserMode_Read() != d_ParserMode_NULL) return(true);

  //}

  //[API 자동 추가 관련]
  //{
      //[2022.06.02.목][추가]{--------------------------------------------------
      //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
      //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨다.
      //
      //[촛점:해제] 시에도 사라지지 않고 [알림창] 처럼 동작 시키기 위한것.
      //}-----------------------------------------------------------------------

      editor_top_Form->_balloonBox->_KillFocusUse(false);

  //}

  //[정보판:감추기]
  //{
      //[2012.05.23.수][추가!!!]{-----------------
      //잔상이 남지 않도록 반드시 가장 먼저 처리.
      //}-----------------------------------------

      if(info_tree_Form != NULL)
      {
        if(info_tree_Form->Visible == true) { info_tree_Form->Hide(); }

      }

  //}

  //[문서가 있나?]
  //{
      //[!]{---------------------------------------------------------------
      //[버튼:문법검사] 처리부에서 호출되는 경우는 [편집기] 에 아무 문서도
      //열려있지 않은 상태일수 있다.
      //이 경우는 <pPathNameExt:NULL> 이 되므로 처리하지 않는다.
      //}------------------------------------------------------------------

      if(STR_Match(pPathNameExt, "") == true) return(false);

  //}

  //[새설계묶음 인가?]
  //{
      //[!]{-------------------------------------------------------------------------------
      //현재 [새설계묶음] 상태인 경우는 먼저 <*.gprj> 로 저장할 것을 요구한다.
      //이전처럼 바로 [저장대화상자] 를 보여 주는 경우는, 기존 <*.gprj> 를 여는 대화상자로
      //오인하여 기존의 [설계묶음] 을 덮어써버리는 문제가 있다.
      //나도 착각하여 여러번 낭패를 보았으므로, 아예 사용자가 직접 저장할수 있도록 한다.
      //즉, [새설계묶음] 인 경우는 저장할것을 요구하고 더이상 처리하지 않고 종료한다.
      //}----------------------------------------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "현재 [새설계묶음] 입니다.\r\n"
                                 "저장되지 않은 [설계묶음] 은 처리 할수 없습니다.\r\n"
                                 "먼저 [설계묶음] 을 <*.gprj> 로 저장해 주십시요."
                                );

        goto lbError;

      }

  //}

  //[기본설정]
  //{
      //[!]{-------------------------------------------------------------
      //새로 추가된 <Parser()> 의 [해석종류] 를 기본으로 초기화.
      //여기서는 일단 기본 <Parser()>처리 그대로 [1차번역] 도 처리 한다.
      //
      //[주의!!!]--------------------------------------------------------
      //이는 <Parser()> 함수를 별도 구동하여 사용하므로 여기서는 반드시
      //기본값으로 설정해 주어야 한다.
      //}----------------------------------------------------------------

      _ParserMode(d_ParserMode_All);

  //}

  //[설계묶음 저장]
  //{
      //[!]{-----------------------------------
      //현재 작업 중인 [설계묶음] 을 저장한다.
      //}--------------------------------------

      IDE_Project_Save(false);

  //}

  //[문서 저장]
  //{
      //[!]{-----------------------------------------------------
      //[문법검사] 전에 먼저 현재 편집중인 모든 문서를 저장한다.
      //}--------------------------------------------------------

      IDE_File_SaveAll();

  //}

  //[{DB} 위치 얻기]
  //{
      //[2023.01.29.일][주석처리]{**************************************
      //이부분은 이 함수의 가장 첫 위치로 이동(해당부분의 설명을 참조).
      //}***************************************************************

      //DATABASE_GetPtr(&database);

  //}

  //[경로 만들기]
  //{
      //[!]{---------------------------------------------------
      //<*.gprj> 문서 경로를 기준으로 다른 경로를 만들어 준다.
      //}------------------------------------------------------

      //[Build]
      //{
          //[build] 폴더는 항상 <*.gprj> 와 같은 위치에 있는 것으로 한다.
          //이 경로에 [build] 폴더가 없는 경우는 자동으로 하나 생성해 준다.
          STR_Assign(database->buildpath, database->projectpath);
          STR_Add_AB(database->buildpath, database->buildpath, "build\\");

          //[해당 경로 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->buildpath);

          //}

      //}

      //[Debug]
      //{
          STR_Assign(database->debugPath, database->projectpath);
          STR_Add_AB(database->debugPath, database->debugPath, "debug\\");

          //[해당 경로를 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->debugPath);

          //}

      //}

  //}

  //[DATABASE 초기화]
  //{
      //[!]{---------------------------------------------
      //반드시 {DATABASE} 를 먼저 초기화 해 주어야 한다.
      //
      //[선언정보] 의 경우는 {DB} 에 모두 정리.
      //}------------------------------------------------

      database->Init();

  //}

  //[<함수묶음.h> 만들기]
  //{
      //[!]{--------------------------------------------------------------------------------
      //현재 [설계묶음] 에 포함된 모든 [함수묶음] 의 <*.h> 를 모아 놓은 <함수묶음.h> 문서를
      //현재 [설계묶음] 위치에 만들어 준다.
      //
      //[설계묶음<*.gprj>] 문서로 만들기 때문에 반드시 [설계묶음] 을 먼저 저장해야 한다!!!
      //
      //현재 처리하는 <*.c> 에 <#include> 형태로 <함수묶음.h> 등 문서가 추가될수 있으므로
      //반드시 새 정보로 유지해 주어야 한다.
      //}-----------------------------------------------------------------------------------

      Ide_Glib_MakeHeader();

  //}

  //[진행 상태창 보이기]
  //{
      buildStatus_Form->_On();

  //}

  //[현재 문서 처리]
  //{
      //[!]{-----------------------
      //전달받은 한개 문서만 처리.
      //}--------------------------

      //[알림창 지우기]
      //{
          //현재 처리할 문서의 경로를 보여준다.
          msg_msg_Form->_Print(d_msg_msg, "");

      //}

      //[경로 보여주기!!!]
      //{
          //현재 처리할 문서의 경로를 보여준다.
          msg_msg_Form->_PrintAddLine(d_msg_msg, pPathNameExt);

      //}

      //[문법검사]
      //{
          if(Parser(pPathNameExt, database) == true)
          {
            //[!]{------
            //이상없음.
            //}---------

            msg_msg_Form->_PrintAddLine(d_msg_msg, "[문법검사] 이상없음!");

          }
          else
          {
            //[!]{-----------
            //[오류] 발생!!!
            //}--------------

            //[행지정]
            //{
                //[오류행] 전체를 [선택영역] 으로 지정.
                Ide_ErrorLine(database->errorinfo.fileFullName,
                              database->errorinfo.line);

            //}

            //[구분처리]
            //{
                //[!]{--------------------------------------------------------
                //[사용자 처리 중지] 인 경우는 오류로 간주하지만, [오류행] 을
                //지정하지 않으므로 이 경우를 구분하여 처리한다.
                //이 경우는 [오류행:-1] 로 쉽게 구분 가능하다.
                //}-----------------------------------------------------------

                if(database->errorinfo.line < 0)
                {
                  //[!]{--------------------------------------------------------------------------
                  //[가상기계 제작 중지] 의 경우로 [오류행] 이 존재하지 않으므로 표시하지 않는다.
                  //}-----------------------------------------------------------------------------

                  msgStr = "\r\n[ " + (AnsiString)database->errorinfo.word + " ]\r\n" +
                           (AnsiString)database->errorinfo.strbuf.buf;

                }
                else
                {
                  msgStr = "[ " + IntToStr(database->errorinfo.line) + " 행 ]\r\n" +
                           "[ " + (AnsiString)database->errorinfo.word + " ]\r\n" +
                           (AnsiString)database->errorinfo.strbuf.buf;

                }

            //}

            //[!]{------------------------------------------------------------
            //계속 행이 추가 되는 경우는 구별이 분명하지 않는 경우가 있으므로
            //이전에 출력된 내용을 완전히 지우고 지금 결과만 추가.
            //}---------------------------------------------------------------

            //[2022.06.02.목][주석처리]
            //msg_msg_Form->_PrintAddLine(d_msg_msg, msgStr.c_str());

            //[API 자동 추가 관련]
            //{
                //[2022.06.09.목][추가]{**************************************************
                //함수안의 선언부에서 [구조체/공용체] 선언시
                //
                //void 맷돌28호_각도구동확인(void)
                //{
                //  struct SPDXWR_3  속도목록[28];
                //  ...
                //
                //여기서, <SPDXWR_3> 이 선언되있지 않은 [구조체이름] 인 경우
                //<SPDXWR_3> 이 단어를 [오류단어] 로 지정하지 않고, <struct> 가
                //[오류단어] 로 지정된다.
                //
                //이 경우 <lbError> 의 오류 처리부에서 <API_DefFile_Check()> 함수로
                //제대로 된 <API이름> 을 찾을수 없다.
                //
                //따라서, 여기서 이를 위하여 <struct> 가 [오류단어] 인 경우는 [다음단어]
                //까지 추출하여 이 [다음단어] 를 오류처리부의 <API_DefFile_Check()> 에
                //넘겨 주어야 한다.
                //
                //이는 일반적인 오류 처리에는 불필요 하나, [API 자동 추가] 를 위해서는
                //반드시 필요한 기능이다.
                //
                //아직 이 위치에서 <Parser()> 의 <ParserInfo> 가 유효하므로 이를 이용하여
                //이 위치에서 다음 단어까지 추출한다.
                //
                //단, struct, union 인 경우만 처리하면 된다.
                //}***********************************************************************

                //[키워드] 와 비교하므로 대소문자를 구분해서 비교해야 한다. 
                if((STR_Match(database->errorinfo.word, "struct") == true) ||
                   (STR_Match(database->errorinfo.word, "union") == true))
                {
                  //"struct", "union" 다음 단어를 추출한다.
                  //[2022.07.14.목][추가]
                  //<errorWordStartIndex> 로 오류 단어 시작 위치를 반환 받도록 수정.
                  errorWordStartIndex = CheckNextWord(&database->parserinfo, errorNextWord_);

                  //[중요]{*************************************************
                  //<Check_NextWord()> 는 #define 으로 선언된 이름인 경우
                  //해당문자열로 대체하므로, 구체적인 문법을 적용하지 않고,
                  //단순하게 [다음단어] 만 추출하는 <CheckNextWord()> 를
                  //사용해야 한다.
                  //}*******************************************************

                }
                else
                {
                  //해당하지 않는다면 NULL 로 초기화.
                  errorNextWord_[0] = '\0';

                  //[2022.07.14.목][추가]
                  //<errorWordStartIndex> 로 오류 단어 시작 위치를 반환 받도록 수정.
                  errorWordStartIndex = database->parserinfo.wordindex;

                }

            //}

            //오류가 있으므로 더이상 진행하지 않고 여기서 종료.
            goto lbError;

          }

      //}

      //[<*.c> 에 <include> 된 문서 추가]
      //{
          Ide_Project_C_IncludeFile();

      //}

      //[구조체/공용체 단어 정리]
      //{
          //[2012.05.16+2.금][추가!!!]{---------------------------------------------
          //<{DB}._strHeap_Conf> 의 해당 [구간] 에 [구조체/공용체 이름] 을 정리.
          //이 정보는 <Parser()> 를 돌릴때 마다 수정될수 있으므로 <Parser()> 사용후
          //한번씩 처리해야 한다.
          //
          //[2012.05.19.토][중요!!!]----------------------------------------------------
          //<Ide_TreeInfo> 안에서 [형식 적용 문자열] 정보 정리를 위하여 [구조체/공용체]
          //정보를 사용하므로 먼저 처리해야 한다.
          //}-----------------------------------------------------------------------

          database->StrHeapConf_Type();

      //}

      //[설계정보 표시]
      //{
          //[!]{--------------------------------------------
          //{DATABASE} 의 내용을 [정보창:설계정보] 에 정리.
          //}-----------------------------------------------

          Ide_TreeInfo();

      //}

  //}

  lbOk:
  //{
      //[진행 상태창 감추기]
      //{
          buildStatus_Form->_Off();

      //}

      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      //[편집기 선택영역 해제]
      //{
          //[2022.06.02.목[추가]{----------------------------------------
          //[이상없이] 종료된 경우는, 이전에 [오류] 등으로 존재 할수 있는
          //[선택영역] 을 해제시킨다(사용자가 오류로 착각하는 것을 방지).
          //}-------------------------------------------------------------

          editor_edit_Form->_Edit_Select_Off();

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.06.02.목][추가]{-----------------------------------------------------
          //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
          //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨 것을 기본으로 북구.
          //}--------------------------------------------------------------------------

          editor_top_Form->_balloonBox->_KillFocusUse(true);

      //}

      return(true);

  //}

  lbError:
  //{
      //[오류 내용 출력]
      //{
          //[2022.06.02.목][추가]{-----------------------------------------------------
          //위의 <Parser()>, <Link()> 에서 즉시 처리하지 않고 여기서 한번에 출력한다.
          //이는 API 자동 추가기능 추가로, 여기에 해당하는 이름의 경우는 오류가 아니라
          //[API 자동 추가 대상] 이기 때문이다.
          //
          //즉, [오류단어] 가 [API 이름] 이 아닌 경우만 순수 오류로 보고 [오류내용] 을
          //출력하기 위한것.
          //}--------------------------------------------------------------------------

          if(API_Check(database->errorinfo.word) == true)
          {
            //[중요]{**************************************************************************
            //이 경우는 [오류단어] 가 API 에 해당하는 것으로 보고(추가되지 않은 API 사용 등),
            //자동으로 API 를 [Tree:설계묶음->함수묶음] 에 추가하고 다시 이 IDE_Build() 함수를
            //처음부터 시작시킨다.
            //}********************************************************************************

            if(API_Add_To_Project(database->errorinfo.word) == true)
            {
              //[편집기 제목줄 풍선도움말에 추가한 API 표기]
              //{
                  //[2022.06.02.목][추가]

                  bls  = STR_Assign(balloonStr, "API : \"");
                  bls += STR_Assign(&(balloonStr[bls]), database->errorinfo.word);
                  bls += STR_Assign(&(balloonStr[bls]), "\" 함수가 [설계묶음] 에 자동으로 추가됐습니다.");

                  //[풍선도움말 출력]
                  //{
                      //[2022.07.14.목][추가]{---------------------------------------------------
                      //<errorWordStartIndex < 0> 으로 지정된 것이 없다면 그냥 기본 위치에 표시.
                      //지정된 것이 있다면 편집기 상의 해당 단어 위치에 출력.
                      //}------------------------------------------------------------------------

                      if(errorWordStartIndex < 0)
                      {
                        editor_top_Form->_BalloonBox_Print(balloonStr);

                      }
                      else
                      {
                        editor_top_Form->_BalloonBox_Print_At_FindStr(NULL, errorWordStartIndex, balloonStr);

                      }

                  //}

              //}

              //자동으로 API 를 추가했으므로 다시 이 함수 처음부터 실행한다.
              goto lbStart;

            }
            else
            {
              //API 추가시 오류가 발생한 경우도 일반 오류로 간주하고 해당 처리부로 넘긴다.
              goto lbErrorInfoPrint;

            }

          }
          else
          {
            //[API 에 사용된 <정의/구조체/공용체이름> 인지 확인]
            //{
                //[오류단어 확인]
                //{
                    //[2022.06.09.목][수정]{-------------------------------------------------
                    //[VAR]{ ... } 안에서 [구조체/공용체] 생성 오류인 경우는 [오류단어] 가
                    //<struct>, <union> 으로 지정되어 구체적인 API 를 찾을수 없으므로,
                    //이 경우는 위의 <Parser()> 함수의 오류 처리부에서 얻은 <errorNextWord_>
                    //를 사용한다.
                    //}----------------------------------------------------------------------

                    //[키워드] 와 비교하므로 대소문자를 구분해서 비교해야 한다.
                    if((STR_Match(database->errorinfo.word, "struct") == true) ||
                       (STR_Match(database->errorinfo.word, "union") == true))
                    {
                      defFile_ApiCount = API_DefFile_Check(errorNextWord_, &defFile_ApiList_);

                    }
                    else
                    {
                      defFile_ApiCount = API_DefFile_Check(database->errorinfo.word, &defFile_ApiList_);

                    }

                //}

                if(defFile_ApiCount > 0)
                {
                  //[!]{--------------------------------------------------------
                  //이 경우는 [오류단어] 가 <[API 이름.h> 에 정의된 [정의이름] 인 경우다.
                  //}-----------------------------------------------------------

                  if(defFile_ApiCount == 1)
                  {
                    //[!]{---------------------------------------------------
                    //단, 한 개의 API 라면 여기서 해당 API 를 바로 추가한다.
                    //}------------------------------------------------------

                    //[API 이름 추출]
                    //{
                        //[!]{---------------------------------------------------------------------------------
                        //[API 목록] 은 행단위 목록으로 항목이 한개라도 뒤에 [NULL 행] 이 있으므로(실제는 2행)
                        //[API 이름] 에 해당하는 첫번째 행만 추출한다.
                        //}------------------------------------------------------------------------------------

                        STR_Get_ThisLineStr(defFile_ApiList_, 0, defFile_ApiName_);                          

                    //}
                    
                    //[<def_file> 관련 저장소 초기화]
                    //{
                        //[!]{----------------------------------------------------------------------------------------
                        //<IDE_Build()> 가 API 자동 추가로 계속 반복 실행될수 있으므로, 여기서 기존에 생성/사용한 것을 삭제해주어야 한다.
                        //이미 <defFile_ApiList_> 에서 <defFile_ApiName_> 을 얻었으므로 이 시점에서 더이상 불필요
                        //}-------------------------------------------------------------------------------------------
                        
                        if(defFile_ApiList_ != NULL) { delete defFile_ApiList_; defFile_ApiList_ = NULL; }

                    //}

                    if(API_Add_To_Project(defFile_ApiName_) == true)
                    {
                      //[편집기 제목줄 풍선도움말에 추가한 API 표기]
                      //{
                          bls  = STR_Assign(balloonStr, "API : \"");
                          bls += STR_Assign(&(balloonStr[bls]), defFile_ApiName_);
                          bls += STR_Assign(&(balloonStr[bls]), "\" 함수가 [설계묶음] 에 자동으로 추가됐습니다.");

                          //[풍선도움말 출력]
                          //{
                              //[2022.07.14.목][추가]{---------------------------------------------------
                              //<errorWordStartIndex < 0> 으로 지정된 것이 없다면 그냥 기본 위치에 표시.
                              //지정된 것이 있다면 편집기 상의 해당 단어 위치에 출력.
                              //}------------------------------------------------------------------------

                              if(errorWordStartIndex < 0)
                              {
                                editor_top_Form->_BalloonBox_Print(balloonStr);

                              }
                              else
                              {
                                editor_top_Form->_BalloonBox_Print_At_FindStr(NULL, errorWordStartIndex, balloonStr);

                              }

                          //}

                      //}

                      //자동으로 API 를 추가했으므로 다시 이 함수 처음부터 실행한다.
                      goto lbStart;

                    }
                    else
                    {
                      //API 추가시 오류가 발생한 경우도 일반 오류로 간주하고 해당 처리부로 넘긴다.
                      goto lbErrorInfoPrint;

                    }

                  }
                  else
                  {
                    //[!]{-------------------------------------------------------------------------
                    //[정의이름] 을 포함하고 있는 API 가 2 개 이상이라면 이 [정의이름] 을 가진 API 목록을 보여주고
                    //사용자가 직접 해당 API 를 [설계묶음] 에 추가할수 있도록 안내한다.
                    //}----------------------------------------------------------------------------

                    //[VSTRBUF:생성]
                    //{                      
                        vStrBuf_ = new VSTRBUF;
                        
                        //내부에서 자동으로 "" 로 초기화.
                        vStrBuf_->Create();
                        
                    //}    
                    
                    //[출력 내용 합성]
                    //{
                        vStrBuf_->Add("정의되지 않은 [ ");
                        vStrBuf_->Add(database->errorinfo.word);
                        vStrBuf_->Add(" ] 사용으로 인한 오류 발견.\r\n\r\n");

                        vStrBuf_->Add("아래 API 목록중 하나를 선택하여 [설계묶음] 에 추가하는 것으로\r\n");
                        vStrBuf_->Add("이 오류를 해결할 수 있습니다.\r\n\r\n");
                        vStrBuf_->Add(defFile_ApiList_);
                    
                    //}
                    
                    //[알림문 출력]
                    //{
                        ide_msgbox_Form->_MsgBox(d_MSGBOX_info, vStrBuf_->Get_Str());
                        
                    //}
                                          
                    //[VSTRBUF:삭제]
                    //{
                        if(vStrBuf_ != NULL)
                        {
                          vStrBuf_->Delete();

                          delete vStrBuf_;

                        }

                    //}

                    //[<def_file> 관련 저장소 초기화]
                    //{
                        //[!]{----------------------------------------------------------------------------------------
                        //<IDE_Build()> 가 API 자동 추가로 계속 반복 실행될수 있으므로, 여기서 기존에 생성/사용한 것을 삭제해주어야 한다.
                        //}-------------------------------------------------------------------------------------------
                        
                        if(defFile_ApiList_ != NULL) { delete defFile_ApiList_; defFile_ApiList_ = NULL; }

                    //}

                  }
                  
                }  

            //}

            lbErrorInfoPrint:

            //[오류 문자열 출력]
            //{
                //[2023.01.29.일][수정]{---------------------
                //"" 인 경우는 오류문자열을 출력하지 않는다.
                //}------------------------------------------

                if(msgStr != "")
                {
                  //이 경우는 순수 오류에 해당하므로 오류 문자열을 출력.
                  msg_msg_Form->_PrintAddLine(d_msg_msg, msgStr.c_str());

                }

            //}

          }

      //}

      //[진행 상태창 감추기]
      //{ 
          buildStatus_Form->_Off();

      //}

      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      //[API 자동 추가 관련]
      //{
          //[2022.06.02.목][추가]{-----------------------------------------------------
          //자동 추가 되는 [API 정보] 를 <editor_top:풍선도움말> 에 출력하기 위하여
          //<editor_top:풍선도움말> 의 [촛점해제] 기능을 중지 시킨 것을 기본으로 북구.
          //}--------------------------------------------------------------------------

          editor_top_Form->_balloonBox->_KillFocusUse(true);

      //}

      //[오류 알림]
      //{
          //[2022.06.04.토][추가]{---------------------------------------------------------------------
          //[맷돌-IDE] 아래 [출력창] 의 출력 문자열 만으로는 이상없이 종료됐는지, [오류] 로 종료됐는지
          //직관적으로 알수 없어, [오류]  임에도 그냥 지나치는 경우가 있어 이를 방지하고자 확실하게
          //[오류] 임을 알려주는 [알림문] 을 출력한다.
          //
          //단, 오류 내용이 있는 경우에 한한다.
          //이는 <Build> 관련 오류(문법검사 등)의 경우에만 사용하기 위한것.
          //}------------------------------------------------------------------------------------------

          if((msgStr.c_str())[0] != '\0')
          {
            //[주의]{******************************************************************
            //if(msgStr != "") 로 처리하는 경우는 [최적화] 과정에서 <msgStr> 에 한번도
            //문자열 저장이 없는 경우(Build 관련 이외의 오류)에서 <msgStr> 자체가 생성
            //되지 않아 [BCB:포인터오류] 가 발생할 수 있다.
            //그러므로, 반드시 사용된 코드로 인식하도록 <msgStr.c_str()> 로 사용한다.
            //}************************************************************************

            ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
		     						 "오류가 발견됐습니다.\r\n\r\n"
                                     "자세한 정보는 아래 [출력창] 의 내용을 참고 바랍니다.");

          }

      //}

      return(false);

  //}
  
}

bool __fastcall Ide_RealTimeInfo(char  *pPathNameExt,
                                 //[2012.05.10.목][추가!!!]
                                 //현재 [편집기] 상 [입력지정자:위치] 정보.
                                 //이는 [실시간 선언정보 수집] 시 [입력지정자] 가 위치한
                                 //함수영역 정보를 자세하게 얻는데 필요.
                                 int    pEditorCaretIndex)
{
  //[2012.04.04.화][생성!!!]{-----------------------------------
  //현재 [편집중] 인 문서(<*.c>, <*.h>) 를 검사하고 해당 정보를
  //{DB} 에 정리.
  //즉, 한개 문서만 <Parser()> 로 처리하는것.
  //
  //[2012.05.10.목][수정!!!]------------------------------------
  //[2012.05.16+2.금][수정!!!]----------------------------------
  //[2012.05.22.화][수정!!!]------------------------------------
  //[2012.05.23.수][수정!!!]------------------------------------
  //[2012.05.26.토][수정!!!]------------------------------------
  //[중복 처리 방지] 기능 추가.
  //[2012.05.27.일][수정!!!]------------------------------------
  //[중복 처리 방지] 기능 [해제].
  //}-----------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *database;

  //}

  //[<Parser()> 중복 처리 방지]
  //{
      //[2012.05.26.토][추가!!!]{------------------------------------------
      //<Parser()> 함수의 [중복실행] 을 [방지] 하기위한것.
      //
      //[2012.05.27.일][수정!!!]-------------------------------------------
      //<Ctrl+Space> 의 경우는 [중복] 시에도 큰 문제가 없고 완벽 동작한다.
      //<Ctrl+F9>, <Alt+F9> 의 경우는 자체적으로 [중복 방지] 된다.
      //
      //이 방식은 [예측할수 없는 오류] 등으로 종료되는 경우는 계속 값을
      //가지고 있기 때문에 [재동작] 시 [중복] 으로 간주되어 다시 함수를
      //동작 시킬수 없게 된다.
      //
      //일단, 사용하지 않는 것으로 하고 [주석] 처리한다.
      //}------------------------------------------------------------------

      //이미 처리중이라면 [이상없음] 으로 종료.
      //if(_ParserMode_Read() != d_ParserMode_NULL) return(true);

  //}

  //[정보판:감추기]
  //{
      //[2012.05.23.수][추가!!!]{-----------------
      //잔상이 남지 않도록 반드시 가장 먼저 처리.
      //}-----------------------------------------

      if(info_tree_Form != NULL)
      {
        if(info_tree_Form->Visible == true) { info_tree_Form->Hide(); }

      }

  //}

  //[새설계묶음인가?]
  //{
      //[!]{-------------------------------------------------------------------
      //실시간 [선언정보 수집] 의 경우도 [설계묶음] 경로가 정의돼 있어야 한다.
      //<함수묶음.h> 같은 자동생성 문서는 [설계묶음] 경로에 생성되기 때문.
      //}----------------------------------------------------------------------

      //[2012.04.20.금][수정!!!]
      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_error,
                                 "현재 [새설계묶음] 입니다.\r\n"
                                 "저장되지 않은 [설계묶음] 은 처리 할수 없습니다.\r\n"
                                 "먼저 [설계묶음] 을 <*.gprj> 로 저장해 주십시요."
                                );

        goto lbError;

      }

  //}

  //[Database 의 주소를 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&database);

  //}

  //[입력 지정자 위치 정보 설정 및초기화]
  //{
      //[2012.05.10.목][추가!!!]{----------------------------------------
      //[실시간 선언정보 수집] 시 [함수영역정보] 가 [입력지정자 위치] 를
      //바탕으로 얻어지므로 먼저 [입력지정자 위치] 정보를 설정한다.
      //
      //나머지 정보는 반드시 처음 한번은 기본값으로 초기화 한다.
      //}----------------------------------------------------------------

      database->_rtDefInfoEtc.caretIndex = pEditorCaretIndex;

      //[초기화]
      //{
          //모두 사용되지 않은 상태로 초기화.
          database->_rtDefInfoEtc.funcRecIndex     = -1;
          database->_rtDefInfoEtc.areaStartIndex   = -1;
          database->_rtDefInfoEtc.areaEndIndex     = -1;
          database->_rtDefInfoEtc.localDefEndIndex = -1;
          //[2012.05.22.화][추가!!!]
          database->_rtDefInfoEtc.fileListIndex    = -1;

      //}

  //}

  //[기본설정]
  //{
      //실시간 [선언정보] 추출로 <Parser()> 사용.
      _ParserMode(d_ParserMode_Def);

  //}

  //[설계묶음 저장]
  //{
      //[!]{----------------------------------------------------------------
      //현재 열려있는 <*.c> 만을 대상으로 처리하므로 [설계묶음] 경로가 이미
      //존재한다면 [설계묶음] 자체를 저장해줄 필요는 없다.
      //
      //[2012.05.08.화][설명!!!]--------------------------------------------
      //기본 적으로 개발 과정이므로 항상 [저장] 하도록 한다.
      //}-------------------------------------------------------------------

      IDE_Project_Save(false);

  //}

  //[문서 저장]
  //{
      //[!]{------------------------------------------------------------
      //[자동저장] 기능 대신으로 보고 [항상 저장] 한다.
      //저장후 해당 문서를 대상으로 [선언정보] 를 추출하는 것이
      //가장 정확하기 때문.
      //
      //[2012.05.08.화][설명!!!]----------------------------------------
      //수정이 잘못된 경우는 거의 무제한의 [되돌리기/되살리기] 기능이
      //있으므로 얼마든지 복구할수 있다.
      //
      //[주의!!!]-------------------------------------------------------
      //의미상은 현재 [편집중(보이고있는 문서)] 만을 대상으로 하지만
      //이 문서 안에 <#include> 로 다른 문서가 포함될수 있으므로 반드시
      //전체 문서를 다 저장해야 한다.
      //}---------------------------------------------------------------

      IDE_File_SaveAll();

  //}

  //[경로 만들기]
  //{
      //[!]{------------------------------------------------------------------------------
      //<*.gprj> 문서 경로를 기준으로 다른 경로를 만들어 준다.
      //
      //실시간 [선언정보] 추출시에는 [1차번역] 등 임시문서가 생기기 않으므로 불필요하지만
      //{DB} 에 정리된 정보를 보기 위하여 설정.
      //}---------------------------------------------------------------------------------

      //[Build]
      //{
          //[build] 폴더는 항상 <*.gprj> 와 같은 위치에 있는 것으로 한다.
          //이 경로에 [build] 폴더가 없는 경우는 자동으로 하나 생성해 준다.
          STR_Assign(database->buildpath, database->projectpath);
          STR_Add_AB(database->buildpath, database->buildpath, "build\\");

          //[해당 경로를 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->buildpath);

          //}

      //}

      //[Debug]
      //{
          STR_Assign(database->debugPath, database->projectpath);
          STR_Add_AB(database->debugPath, database->debugPath, "debug\\");

          //[해당 경로를 생성]
          //{
              //지정 경로(폴더) 가 존재 하는지 확인하고 존재하지 않는다면 생성한다.
              File_CreateDirectory(database->debugPath);

          //}

      //}

  //}

  //[DATABASE 초기화]
  //{
      //[!]{--------------------------------------------------------------------
      //compile 을 하기 전에는 반드시 {DATABASE} 를 먼저 초기화 해 주어야 한다.
      //
      //<projectpath> 등 [경로] 정보등은 초기화 되지 않는다.
      //
      //실시간 [선언정보] 의 경우는 {DB} 에 모두 정리.
      //
      //동적생성된 개체등 모드 삭제되고 기본 상태로 초기화.
      //}-----------------------------------------------------------------------

      database->Init();

  //}

  //[<함수묶음.h> 만들기]
  //{
      //[!]{--------------------------------------------------------------------------------
      //현재 [설계묶음] 에 포함된 모든 [함수묶음] 의 <*.h> 를 모아 놓은 <함수묶음.h> 문서를
      //현재 [설계묶음] 위치에 만들어 준다.
      //
      //[2012.05.08.화][설명!!!]------------------------------------------------------------
      //[설계묶음<*.gprj>] 문서로 만들기 때문에 반드시 [설계묶음] 을 먼저 저장해야 한다!!!
      //
      //현재 처리하는 <*.c> 에 <#include> 형태로 <함수묶음.h> 등 문서가 추가될수 있으므로
      //반드시 새 정보로 유지해 주어야 한다.
      //}-----------------------------------------------------------------------------------

      Ide_Glib_MakeHeader();

  //}

  //[현재 문서 처리]
  //{
      //[문법검사]
      //{
          //[!]{---------------------------------------------------------------
          //실시간 [선언정보] 수집의 경우는 사용자가 처리를 알지 말아야 하므로
          //오류는 무시한다.
          //오류 정보를 출력할 필요는 없다.
          //{DB} 에 [선언정보] 를 정리하는 것만 의미가 있다.
          //
          //[실시간 선언정보 수집] 의 경우는 [선언] 관련 부분만 처리하므로
          //대부분의 [문장 오류] 와 무관하지만, [오류] 발생시에는 내부적으로
          //[종료] 하게 되므로 오류 발생전 위치까지만 정보를 수집하게 된다.
          //}------------------------------------------------------------------

          if(Parser(pPathNameExt, database) == true)
          {
            //이상없이 처리 되었다.

          }
          else
          {
            //[오류] 발생!!!

          }

      //}

      //[구조체/공용체 단어 정리]
      //{
          //[2012.05.16+2.금][추가!!!]{---------------------------------------------
          //<{DB}._strHeap_Conf> 의 해당 [구간] 에 [구조체/공용체 이름] 을 정리.
          //이 정보는 <Parser()> 를 돌릴때 마다 수정될수 있으므로 <Parser()> 사용후
          //한번씩 처리해야 한다.
          //
          //[2012.05.19.토][중요!!!]------------------------------------------------
          //<Ide_InfoTree_SetInfo> 안에서 [형식 적용 문자열] 정보 정리를 위하여
          //[구조체/공용체] 정보를 사용하므로 먼저 처리해야 한다.
          //}-----------------------------------------------------------------------

          database->StrHeapConf_Type();

      //}

      //[문서 번호 기록]
      //{
          //[2012.05.22.화][추가!!!]{----------------------------------------
          //[실시간 선언정보 수집] 은 [한개 문서] 를 대상으로 하므로
          //현재 [문서번호] 를 기록해 놓는다.
          //이는 <Tinfo_tree_Form::_TitleView_Word()> 함수에서 [정의이름] 을
          //찾는데 필요하다.
          //}----------------------------------------------------------------

          database->FILELIST_GetIndex_WithName(pPathNameExt,
                                               &(database->_rtDefInfoEtc.fileListIndex));

      //}

      //[설계정보 표시]
      //{
          //[!]{----------------------------------------------------------
          //이 함수를 호출한 곳에서 <Ide_InfoTree_SetInfo()> 함수로 처리.
          //}-------------------------------------------------------------

      //}

  //}

  lbOk:
  //{
      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      return(true);

  //}

  lbError:
  //{
      //[기본상태]
      //{
          //[2012.05.26.토][추가!!!]
          _ParserMode(d_ParserMode_NULL);

      //}

      return(false);

  //}

}

void __fastcall Ide_InfoTree_SetInfo(//[2012.05.29.화][추가!!!]
                                     //NULL 이 아닌 경우는 [근접단어정렬] 로 처리.
                                     //[2012.05.30.수][수정!!!]
                                     //NULL 은 아니지만 [문자열] 이 "" 인 경우는 삭제 없이 전체 수집.
                                     //즉, "" 인 경우는 [근접단어정렬] 에 해당하지 않는 것으로 본다.
                                     char  *pPartName_,
                                     //[2012.05.30.수][추가!!!]
                                     //현재 영역 정보.
                                     //<전역영역:-1> 이 아닌 경우는 이 함수 영역안에서
                                     //사용할수 있는(유효한) 정보만 정리한다.
                                     //단, [지역변수] 에만 적용되고 <pPartName_:NULL> 아닌 경우만 유효.
                                     int    pFncRecIndex,
                                     //[2012.06.01.금][추가!!!]
                                     //[다시 그리기] 하는 경우는 <true>.
                                     bool   pRePaint)
{
  //[2012.05.29.화][생성!!!]{--------------------------------------------------------------
  //<Build> 후에 {DATABASE} 안의 모든 내용을 정리하여 [Tree] 상의 "설계정보" 창에
  //전부 해당 항목 별로 정리해 주어야 한다.
  //
  //단, [define] 으로 선언된 것은 {definelist[]} 로 별도 관리 되므로 역시
  //별도로 처리해 주어야 한다.
  //
  //[<name> 지정 방법]---------------------------------------------------------------------
  //
  // [일반항목]
  //
  //  <name> : 현재 {DATABASE} 상의 record-index 의 16진수 문자열을 사용한다.
  //           record-index 는 절대 서로 겹치지 않으므로 name 으로 제격이다.
  //
  // [define 정의 항목]
  //
  //  <name> : <#define> 항목은 {definelist[]} 를 별도 운영하고 있으므로 이것을 사용한다.
  //           "def.recindex" 의 형식으로 앞에 "def." 를 붙여서 구분한다.
  //
  //[2012.04.16.월][수정!!!]---------------------------------------------------------------
  //[하위항목] 이 전혀 없는 [대표항목] 은 아예 삭제한다.
  //[구조체/공용체선언], [전역변수] 등은 없는 경우도 많으므로 아예 보이지 않는다.
  //단, {DB} 를 전부 검색해야 항목의 존재를 확인가능하므로
  //
  //1) 일단 모든 [대표항목] 을 만들어 놓는다.
  //2) 처리가 끝나고 하위항목이 존재하지 않는 [대표항목] 은 삭제한다.
  //
  //[2012.04.20.금][수정!!!]---------------------------------------------------------------
  //[2012.05.07.월][추가!!!]---------------------------------------------------------------
  //모든 추가 항목은 반드시 <_Item_Init()> 함수로 초기화후 사용해야 한다.
  //내부의 <txt> 관리 때문.
  //
  //[2012.05.16+2.금][수정!!!]-------------------------------------------------------------
  //[2012.05.21.월][수정!!!]---------------------------------------------------------------
  //[2012.05.29.화][중요수정!!!]-----------------------------------------------------------
  //<pPartName_> 과 첫부분부터 부분적으로 [일치] 하는 <name> 을 가지는 정보만 정리.
  //단, <pPartName_:NULL> 인 경우는 [전체] 를 대상으로 처리.
  //
  //이 기능을 위하여 금일 <Str_Match_Part()> 함수를 새로 만들었다.
  //
  //[2012.05.30.수][수정!!!]---------------------------------------------------------------
  //<pPartName_:NULL> 은 아니지만 <pPartName_:""> 로 [단어] 가 없는 경우도 <NULL> 과 같이
  //모든 정보르 다 수집하는 것으로 한다.
  //즉, [단어재정리] 를 하지 않는 <NULL> 과 같은 조건으로 본다.
  //
  //[2012.05.31.목][중요수정!!!]-----------------------------------------------------------
  //[재정렬] 시에는 <Application->ProcessMessages()> 를 사용해서는 안된다.
  //이 함수가 처리에 시간이 걸리는데 [편집기] 에서 [실시간 선언 정보판] 이 보여진 상태에서
  //[단어조합] 이 진행중인 경우는 계속 {DB} 정보로 [근접단어정렬] 을 하는 경우
  //이 함수가 처리중인 상태에서 <Application->ProcessMessages()> 로 정리중에 계속 상태가
  //가변되고 [편집기] 동작 중 [되돌리기/되살리기] 기능에 영향을 준다.
  //수시로 [촛점] 이 변경되는 과정에서 [선택영역] 을 사용하는 [편집기] 기능 등에 오류를
  //발생시키게 된다.
  //
  //가장 확실한 것은 [근접단어정렬] 시에는 <Application->ProcessMessages()> 를 사용하지
  //않는 방법이다.
  //
  //보다 확실한 방법을 찾기 전까지는 [근접단어정렬] 시에는 사용하지 않는 것으로 한다.
  //
  //[2012.05.31.목][수정!!!]--------------------------------------------------------------
  //[근접단어정렬] 시에 <pFncRecIndex >= 0> 인 경우 즉, 현재 특정 함수 안이라면
  //다른 [함수] 의 경우 [인수] 나 [지역변수] 는 수집할 필요가 없다.
  //어차피 현재 [함수] 안에서 다른 [함수] 의 [인수/지역변수] 는 사용할수 없으므로.
  //이는 [재정리] 시 [처리 시간 단축] 을 위한 것.
  //
  //[2012.05.31.목][수정!!!]--------------------------------------------------------------
  //일단 <Application->ProcessMessages()> 는 사용하지 않는 것으로 처리.
  //{DB} 에 이미 존재하는 것을 [실시간 선언 정보판] 에 [정리] 만 하는 것으로 처리 시간이
  //많이 걸리지 않기 때문에 모든 처리가 끝나는 동안은 외부 처리를 못하게 하는 것이 좋다.
  //실제 확인해 본 결과 [편집] 에 전혀 지장을 주지 않는 정도로 빠르다.
  //}-------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class DATABASE  *DB_;

      char  tempStr[OPT_lineStrSize];
      char  hexStr[OPT_wordStrSize];

      //[tree 관련]
      //{
          struct  INFOTREE         *tree;

          struct  INFOTREE_ITEM     item;

      //}

      int   i, j;

      int   motherIndex;
      char  motherName[OPT_wordStrSize];
      int   memberCount;

      char  isStructUnion = 0;

      //[2009.10.04.일][추가!!!]
      //[2012.05.16+2.금][크기수정!!!]
      char  itemTxt[OPT_lineStrSize];

      //[2012.04.16.월][추가!!!]
      int   itemIndex;
      int   itemCount;

      //[2012.05.29.화][추가!!!]
      int   itemMotherIndex;

  //}

  //[Database 의 주소를 얻기]
  //{
      DATABASE_GetPtr(&DB_);

  //}

  //[Tree 치환]
  //{
      //[문장] 을 간결하게 하기 위하여 [정보 Tree] 를 [포인터] 로 받아서 사용한다.
      tree = &(info_tree_Form->_tree);

  //}

  //[Tree:초기화]
  //{
      //[2012.04.15.일][추가!!!]{--------------------------------------------
      //새로운 내용을 위하여 기존의 내용을 전부 지우고 초기화.
      //단, [크기 재생성] 은 하지 않는다.
      //
      //[2012.05.08.화][수정!!!]---------------------------------------------
      //[Tree] 와 동기되는 [STRHEAP] 모두 현재 생성된 공간을 유지하고
      //내부만 미사용 상태로 초기화(비우기) 한다.
      //
      //[2012.05.13.일][추가!!!]
      //[설계묶음] 을 닫는 경우 <IDE_Project_Close()> 함수 안에서 자동적으로
      //<infoTree> 의 모든 공간을 삭제하고 초기화 하는 것으로 수정하였다.
      //따라서, 이 부분에서는 [재생성] 하지 않고 [비우기] 만 하면 충분하다.
      //크기가 커지더라도 이 [설계묶음] 이 닫힐때 자동적으로 [삭제/초기화]
      //되기 때문이다.
      //}--------------------------------------------------------------------

      //info_tree_Form->_Tree_Init(tree, 250);
      info_tree_Form->_Tree_Clear(tree);

  //}


  //[초기화]
  //{
      //[!]{-------------------------------------
      //[실시간 정보 보기] 형식으로 틀을 만든다.
      //}----------------------------------------

      //[root]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          //처음은 아무 것도 없으므로 무조건 하나 root 를 추가한다.
          item.kind = '-';
          item.level = 0;
          STR_Assign(item.name, "root");
          info_tree_Form->_Item_Txt(&item, "설계정보");
          item.bmpindex = d_ITEMBMP_root;
          info_tree_Form->_Tree_Add_Item(tree, &item);

      //}

      //[define]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          item.kind = '.';
          STR_Assign(item.name, "define");
          info_tree_Form->_Item_Txt(&item, "이름정의");
          item.bmpindex = d_ITEMBMP_define;
          info_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);

      //}

      //[struct]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          item.kind = '.';
          STR_Assign(item.name, "struct");
          info_tree_Form->_Item_Txt(&item, "구조체선언");
          item.bmpindex = d_ITEMBMP_struct_def;
          info_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);

      //}

      //[union]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          item.kind = '.';
          STR_Assign(item.name, "union");
          info_tree_Form->_Item_Txt(&item, "공용체선언");
          item.bmpindex = d_ITEMBMP_union_def;
          info_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);

      //}

      //[전역변수]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          item.kind = '.';
          STR_Assign(item.name, "global");
          info_tree_Form->_Item_Txt(&item, "전역변수");
          item.bmpindex = d_ITEMBMP_global;
          info_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);

      //}

      //[함수]
      //{
          //[2012.05.07.월][추가!!!]{-------------
          //<txt> 를 위하여 반드시 초기화후 사용.
          info_tree_Form->_Item_Init(&item);
          //}-------------------------------------

          item.kind = '.';
          STR_Assign(item.name, "function");
          info_tree_Form->_Item_Txt(&item, "함수");
          item.bmpindex = d_ITEMBMP_function;
          info_tree_Form->_Tree_Add_NodeItem(tree, "root", &item, NULL);

      //}

  //}


  //[설계 정보 정리]
  //{
      //[지정이름]
      //{
          for(i = 0; i < DB_->definelist_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                if(!((pPartName_ != NULL) && (pPartName_[0] != '\0')))
                {
                  //[2012.05.31.목][수정!!!]{-----------
                  //[근접단어정렬] 이 아닌 경우만 처리.
                  //}-----------------------------------

                  //[2012.05.31.목][주석처리!!!]
                  //Application->ProcessMessages();

                }

            //}

            //[<pPartName_> 을 가진 <name> 인가?]
            //{
                //[2012.05.29.화][추가!!!]{--------------------------------------
                //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                //시작부분부터 일치하는 [항목] 만 추가.
                //}--------------------------------------------------------------

                if((pPartName_ != NULL) &&
                    //[2012.05.30.수][추가!!!]
                    //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                   (pPartName_[0] != '\0'))
                {
                  //일치하지 않는 경우는 다음 항목으로 넘긴다.
                  //[2012.07.21.토][수정!!!]
                  //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                  if(Str_Match_Part_NoCase(DB_->definelist[i].defname, pPartName_) != true) continue;

                }

            //}

            //[항목 초기화]
            //{
                info_tree_Form->_Item_Init(&item);

            //}

            //[<name> 만들기]
            //{
                //"def.definelistindex" 형식으로 만들어 준다.
                //이는 {DATABASE} 항목의 recordindex 와 겹치는 겻을 방지하기 위한 것이다.

                STR_Assign(item.name, "def.");
                CONV_LongVal_To_Hex2(i, hexStr);
                STR_Add_AB(item.name, item.name, hexStr);

            //}

            //[<text> 만들기]
            //{
                //"[정의이름] [문자열]" 형식으로 합성한다.

                STR_Assign(itemTxt, DB_->definelist[i].defname);
                STR_Add(itemTxt, " ");
                STR_Add(itemTxt, DB_->definelist[i].defstr);

                info_tree_Form->_Item_Txt(&item, itemTxt);

            //}

            //[기타 설정]
            //{
                item.kind = '.';
                item.bmpindex = d_ITEMBMP_define;

            //}

            //[<recindex> 기록]
            //{
                //{definelist[]} 상의 <recindex> 를 기록해 준다.
                item.info1 = i;

            //}

            //[추가]
            //{
                info_tree_Form->_Tree_Add_NodeItem(tree, "define", &item, NULL);

            //}

          }

          //[하위항목 존재 확인]
          //{
              //[2012.04.16.월][추가!!!]{----------------------------
              //[하위항목] 이 전혀 없다면 이 [대표항목] 을 삭제한다.
              //}----------------------------------------------------

              //해당 [대표항목] 위치 찾기.
              info_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "define", &itemIndex);

              //하위항목 개수 얻기.
              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemIndex, &itemCount);

              if(itemCount == 0)
              {
                //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                info_tree_Form->_Tree_Delete_Item(tree, itemIndex);

              }

          //}

      //}

      //[구조체 선언]
      //{
          for(i = 0; i < DB_->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                if(!((pPartName_ != NULL) && (pPartName_[0] != '\0')))
                {
                  //[2012.05.31.목][수정!!!]{-----------
                  //[근접단어정렬] 이 아닌 경우만 처리.
                  //}-----------------------------------

                  //[2012.05.31.목][주석처리!!!]
                  //Application->ProcessMessages();

                }

            //}

            //[구조체 선언 시작 찾기]
            //{
                //[구조체 선언] 이 아니라면 계속 다음을 검사한다.
                if(DB_->record[i].kind != _recKIND_structtype) continue;

            //}

            //[구조체 선언 자체 처리]
            //{
                //일단 [구조체 선언] 자체 항목을 추가 한다.

                //[항목 초기화]
                //{
                    info_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[<text> 만들기]
                //{
                    //[record.name] 을 그대로 사용한다.
                    //STR_Assign(item.text, DB_->record[i].name);
                    info_tree_Form->_Item_Txt(&item, DB_->record[i].name);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';
                    item.bmpindex = d_ITEMBMP_struct_def;

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    info_tree_Form->_Tree_Add_NodeItem(tree, "struct", &item,
                                                       //[2012.05.29.화][수정!!!]
                                                       //추가한 [구조체] 위치를 얻기.
                                                       &itemMotherIndex);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[구성원 처리]
            //{
                for(//아직 [구조체 모체] 의 위치 이므로 i++ 하고 시작한다.
                    j = i + 1, memberCount = 0;
                    j < DB_->record_count;
                    j++, memberCount++)
                {
                  //[영역검사]
                  //{
                      //[모체 영역 안] 인 경우만 처리하면 된다.
                      if(DB_->record[j].area != motherIndex) break;

                  //}

                  //[<pPartName_> 을 가진 <name> 인가?]
                  //{
                      //[2012.05.29.화][추가!!!]{--------------------------------------
                      //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                      //시작부분부터 일치하는 [항목] 만 추가.
                      //}--------------------------------------------------------------

                      if((pPartName_ != NULL) &&
                         //[2012.05.30.수][추가!!!]
                         //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                         (pPartName_[0] != '\0'))
                      {
                        //일치하지 않는 경우는 다음 항목으로 넘긴다.
                        //[2012.07.21.토][수정!!!]
                        //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                        if(Str_Match_Part_NoCase(DB_->record[j].name, pPartName_) != true) continue;

                      }

                  //}

                  //[항목 초기화]
                  //{
                      info_tree_Form->_Item_Init(&item);

                  //}

                  //[<name> 만들기]
                  //{
                      //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                      CONV_LongVal_To_Hex2(j, hexStr);
                      STR_Assign(item.name, hexStr);

                  //}

                  //[기타 설정]
                  //{
                      item.kind = '.';

                      //일단 기본 그림으로 설정한다.
                      item.bmpindex = d_ITEMBMP_item;

                  //}

                  //[<text> 만들기]
                  //{
                      //[2009.02.14.토][수정!!!]{------------------------------------
                      //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                      //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                      //}------------------------------------------------------------

                      Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                      info_tree_Form->_Item_Txt(&item, itemTxt);

                      if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                      else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                  //}

                  //[<recindex> 기록]
                  //{
                      //{definelist[]} 상의 <recindex> 를 기록해 준다.
                      item.info1 = j;

                  //}

                  //[추가]
                  //{
                      //모체에 추가 해야 한다.
                      info_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                  //}

                }

                //[구성원 존재 확인]
                //{
                    //[2012.05.30.수][추가!!]{--------------------------------
                    //[근접 단어 정렬] 시에는 [하위항목] 이 없는 경우만 삭제.
                    //[근접단어] 만 남겨 놓아야 하므로 그외 모든 항목은 삭제.
                    //}-------------------------------------------------------

                    if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
                    {
                      //하위항목 개수 얻기.
                      info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemMotherIndex, &itemCount);

                      if(itemCount == 0)
                      {
                        //단, <pPartName_> 과 부분일치 한다면 [삭제] 하지 않아야 한다.
                        //[2012.07.21.토][수정!!!]
                        //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                        if(Str_Match_Part_NoCase(DB_->record[i].name, pPartName_) != true)
                        {
                          //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                          info_tree_Form->_Tree_Delete_Item(tree, itemMotherIndex);

                        }

                      }

                    }

                //}

                i += memberCount;

            //}

          }

          //[하위항목 존재 확인]
          //{
              //[2012.04.16.월][추가!!!]{----------------------------
              //[하위항목] 이 전혀 없다면 이 [대표항목] 을 삭제한다.
              //}----------------------------------------------------

              //해당 [대표항목] 위치 찾기.
              info_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "struct", &itemIndex);

              //하위항목 개수 얻기.
              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemIndex, &itemCount);

              if(itemCount == 0)
              {
                //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                info_tree_Form->_Tree_Delete_Item(tree, itemIndex);

              }

          //}

      //}

      //[공용체 선언]
      //{
          for(i = 0; i < DB_->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                if(!((pPartName_ != NULL) && (pPartName_[0] != '\0')))
                {
                  //[2012.05.31.목][수정!!!]{-----------
                  //[근접단어정렬] 이 아닌 경우만 처리.
                  //}-----------------------------------

                  //[2012.05.31.목][주석처리!!!]
                  //Application->ProcessMessages();

                }

            //}

            //[공용체 선언 시작 찾기]
            //{
                //[구조체 선언] 이 아니라면 계속 다음을 검사한다.
                if(DB_->record[i].kind != _recKIND_uniontype) continue;

            //}

            //[공용체 선언 자체 처리]
            //{
                //일단 [공용체 선언] 자체 항목을 추가 한다.

                //[항목 초기화]
                //{
                    info_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[<text> 만들기]
                //{
                    //[record.name] 을 그대로 사용한다.
                    //STR_Assign(item.text, DB_->record[i].name);
                    info_tree_Form->_Item_Txt(&item, DB_->record[i].name);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';
                    item.bmpindex = d_ITEMBMP_union_def;

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    info_tree_Form->_Tree_Add_NodeItem(tree, "union", &item,
                                                       //[2012.05.29.화][추가!!!]
                                                       //추가한 [공용체] 위치 얻기.
                                                       &itemMotherIndex);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[구성원 처리]
            //{
                for(//아직 [공용체 모체] 의 위치 이므로 j = i + 1 로 시작한다.
                    j = i + 1, memberCount = 0;
                    j < DB_->record_count;
                    j++, memberCount++)
                {
                  //[영역검사]
                  //{
                      //[모체 영역 안] 인 경우만 처리하면 된다.
                      if(DB_->record[j].area != motherIndex) break;

                  //}

                  //[<pPartName_> 을 가진 <name> 인가?]
                  //{
                      //[2012.05.29.화][추가!!!]{--------------------------------------
                      //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                      //시작부분부터 일치하는 [항목] 만 추가.
                      //}--------------------------------------------------------------

                      if((pPartName_ != NULL) &&
                         //[2012.05.30.수][추가!!!]
                         //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                         (pPartName_[0] != '\0'))
                      {
                        //일치하지 않는 경우는 다음 항목으로 넘긴다.
                        //[2012.07.21.토][수정!!!]
                        //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                        if(Str_Match_Part_NoCase(DB_->record[j].name, pPartName_) != true) continue;

                      }

                  //}

                  //[항목 초기화]
                  //{
                      info_tree_Form->_Item_Init(&item);

                  //}

                  //[<name> 만들기]
                  //{
                      //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                      CONV_LongVal_To_Hex2(j, hexStr);
                      STR_Assign(item.name, hexStr);

                  //}

                  //[기타 설정]
                  //{
                      item.kind = '.';

                      //일단 기본그림으로 설정한다.
                      item.bmpindex = d_ITEMBMP_item;

                  //}

                  //[<text> 만들기]
                  //{
                      //[2009.02.14.토][수정!!!]{------------------------------------
                      //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                      //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                      //}------------------------------------------------------------

                      Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                      info_tree_Form->_Item_Txt(&item, itemTxt);

                      if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                      else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                  //}

                  //[<recindex> 기록]
                  //{
                      //{definelist[]} 상의 <recindex> 를 기록해 준다.
                      item.info1 = j;

                  //}

                  //[추가]
                  //{
                      //모체에 추가 해야 한다.
                      info_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                  //}

                }

                //[구성원 존재 확인]
                //{
                    //[2012.05.30.수][추가!!]{--------------------------------
                    //[근접 단어 정렬] 시에는 [하위항목] 이 없는 경우만 삭제.
                    //[근접단어] 만 남겨 놓아야 하므로 그외 모든 항목은 삭제.
                    //}-------------------------------------------------------

                    if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
                    {
                      //하위항목 개수 얻기.
                      info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemMotherIndex, &itemCount);

                      if(itemCount == 0)
                      {
                        //단, <pPartName_> 과 부분일치 한다면 [삭제] 하지 않아야 한다.
                        //[2012.07.21.토][수정!!!]
                        //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                        if(Str_Match_Part_NoCase(DB_->record[i].name, pPartName_) != true)
                        {
                          //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                          info_tree_Form->_Tree_Delete_Item(tree, itemMotherIndex);

                        }

                      }

                    }

                //}

                i += memberCount;

            //}

          }

          //[하위항목 존재 확인]
          //{
              //[2012.04.16.월][추가!!!]{----------------------------
              //[하위항목] 이 전혀 없다면 이 [대표항목] 을 삭제한다.
              //}----------------------------------------------------

              //해당 [대표항목] 위치 찾기.
              info_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "union", &itemIndex);

              //하위항목 개수 얻기.
              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemIndex, &itemCount);

              if(itemCount == 0)
              {
                //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                info_tree_Form->_Tree_Delete_Item(tree, itemIndex);

              }

          //}

      //}

      //[전역변수]
      //{
          for(i = 0; i < DB_->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                if(!((pPartName_ != NULL) && (pPartName_[0] != '\0')))
                {
                  //[2012.05.31.목][수정!!!]{-----------
                  //[근접단어정렬] 이 아닌 경우만 처리.
                  //}-----------------------------------

                  //[2012.05.31.목][주석처리!!!]
                  //Application->ProcessMessages();

                }

            //}

            //[전역변수 확인]
            //{
                //[전역영역] 에서 선언된 [구조체/공용체/변수] 등이 해당된다.
                //[전역변수] 는 [_recKIND_data] 한가지만 가진다.
                //단, 전역 영역이므로 반드시 <area>:-1 이어야 한다.
                if(!((DB_->record[i].kind == _recKIND_data) &&
                     (DB_->record[i].area == -1))) continue;

            //}

            //[<pPartName_> 을 가진 <name> 인가?]
            //{
                //[2012.05.29.화][추가!!!]{--------------------------------------
                //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                //시작부분부터 일치하는 [항목] 만 추가.
                //}--------------------------------------------------------------

                if((pPartName_ != NULL)  &&
                   //[2012.05.30.수][추가!!!]
                   //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                   (pPartName_[0] != '\0'))
                {
                  //일치하지 않는 경우는 다음 항목으로 넘긴다.
                  //[2012.07.21.토][수정!!!]
                  //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                  if(Str_Match_Part_NoCase(DB_->record[i].name, pPartName_) != true) continue;

                }

            //}

            //[항목 초기화]
            //{
                info_tree_Form->_Item_Init(&item);

            //}

            //[<name> 만들기]
            //{
                //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                CONV_LongVal_To_Hex2(i, hexStr);
                STR_Assign(item.name, hexStr);

            //}

            //[기타 설정]
            //{
                item.kind = '.';

                //일단 기본그림으로 설정한다.
                item.bmpindex = d_ITEMBMP_item;

            //}

            //[<text> 만들기]
            //{
                //[!]{---------------------------------------------------------
                //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                //}------------------------------------------------------------

                Ide_TreeInfo_ItemTextMake(i, itemTxt, &isStructUnion);

                info_tree_Form->_Item_Txt(&item, itemTxt);

                if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

            //}

            //[<recindex> 기록]
            //{
                //{definelist[]} 상의 <recindex> 를 기록해 준다.
                item.info1 = i;

            //}

            //[추가]
            //{
                info_tree_Form->_Tree_Add_NodeItem(tree, "global", &item, NULL);

            //}

          }

          //[하위항목 존재 확인]
          //{
              //[2012.04.16.월][추가!!!]{----------------------------
              //[하위항목] 이 전혀 없다면 이 [대표항목] 을 삭제한다.
              //}----------------------------------------------------

              //해당 [대표항목] 위치 찾기.
              info_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "global", &itemIndex);

              //하위항목 개수 얻기.
              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemIndex, &itemCount);

              if(itemCount == 0)
              {
                //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                info_tree_Form->_Tree_Delete_Item(tree, itemIndex);

              }

          //}

      //}

      //[함수]
      //{
          //[2012.05.31.목][중요수정!!!]{--------------------------------------
          //[근접단어정렬(재정리)] 시에는 [현재함수] 영역만 [인수/지역변수] 만
          //의미가 있으므로 다른 함수의 경우는 [함수 자체 항목] 만 추가한다.
          //이는 실시간 [처리속도] 를 단축하기 위한것.
          //}------------------------------------------------------------------

          for(i = 0; i < DB_->record_count; i++)
          {
            //[Win7 <응답이 없는 상태> 해결]
            //{
                //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
                //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
                //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
                //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
                //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
                //이런 형상이 발생하지 않도록 수정한다.
                //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
                //이 문장을 넣어 준다.
                //}-------------------------------------------------------------------------------------------

                if(!((pPartName_ != NULL) && (pPartName_[0] != '\0')))
                {
                  //[2012.05.31.목][수정!!!]{-----------
                  //[근접단어정렬] 이 아닌 경우만 처리.
                  //}-----------------------------------

                  //[2012.05.31.목][주석처리!!!]
                  //Application->ProcessMessages();

                }

            //}

            //[함수 확인]
            //{
                //[!]{--------------------------------------------------
                //[함수] 는 [선언/본체] 로 [종류] 가 구분되 있으나 <redcord> 는
                //하나 밖에 존재 할수 없으으로 이 두 경우 중 하나에 해당한다면
                //[함수] 로 본다.
                //단, 전역 영역이므로 반드시 <area>:-1 이어야 한다.

                if(!(((DB_->record[i].kind == _recKIND_func_def) ||
                      (DB_->record[i].kind == _recKIND_func_body)) &&
                      (DB_->record[i].area == -1))) continue;

            //}

            //[함수 자체 항목 처리]
            //{
                //[항목 초기화]
                //{
                    info_tree_Form->_Item_Init(&item);

                //}

                //[<name> 만들기]
                //{
                    //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                    CONV_LongVal_To_Hex2(i, hexStr);
                    STR_Assign(item.name, hexStr);

                //}

                //[기타 설정]
                //{
                    item.kind = '.';

                    //일단 기본그림으로 설정한다.
                    item.bmpindex = d_ITEMBMP_function;

                //}

                //[<text> 만들기]
                //{
                    //[!]{---------------------------------------------------------
                    //[함수선언] 문자열은 이미 <record>.str_mem 에 저장되 있으므로
                    //이것을 그대로 읽어서 사용한다.
                    //
                    //[2012.05.16+2.금][수정!!!]--------------------------------------
                    //{DB} 의 [함수 선언 정보 문자열] 은 보기 좋지 않기 때문에
                    //보기 좋게 [재정리] 한다.
                    //이를 위하여 금일 만든 <FuncDefStr_ReMake_TreeItem()> 함수 사용.
                    //}---------------------------------------------------------------

                    //[재정리]
                    //{
                        //[2012.05.16+2.금][추가!!!]
                        FuncDefStr_ReMake_TreeItem(STRHEAP_Str_Ptr(&(DB_->_strHeap), DB_->record[i].str_mem),
                                                   itemTxt);

                    //}

                    //[2012.04.20.금][수정!!!]
                    info_tree_Form->_Item_Txt(&item, itemTxt);

                //}

                //[<recindex> 기록]
                //{
                    //{definelist[]} 상의 <recindex> 를 기록해 준다.
                    item.info1 = i;

                //}

                //[추가]
                //{
                    info_tree_Form->_Tree_Add_NodeItem(tree, "function", &item,
                                                       //[2012.05.29.화][추가!!!]
                                                       //추가한 [함수] 위치 얻기.
                                                       &itemMotherIndex);

                //}

                //[모체정보저장]
                //{
                    STR_Assign(motherName, item.name);
                    motherIndex = item.info1;

                //}

            //}

            //[현재 편집중인 함수 인가?]
            //{
                //[2012.05.31.목][추가!!!]{-----------------------------------------------------
                //[근접단어정렬] 시에는 [함수(현재 영역)] 의 [인수/지역변수] 만 의미가 있으므로
                //다른 [함수] 는 [함수항목] 자체만 수집하고 [인수/지역변수] 는 수집하지 않는다.
                //[재정리] 시 최대한 [처리시간] 을 [단축] 하기 위한것.
                //}-----------------------------------------------------------------------------

                //단, [근접단어정렬] 시만 사용.
                if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
                {
                  //전체 [지역변수] 개수가 없는 경우 [함수항목] 을 삭제해주는 부분으로 이동.
                  if(pFncRecIndex != motherIndex) goto lbCheckLocalVarCount;

                }  

            //}

            //[지역변수 처리]
            //{
                //[!]{-----------------------------------------------------------------------
                //[함수] 는 [선언] 이 먼저오고 [본체] 가 나중에 오는 경우도 있다.
                //이 경우는 [인수] 부분은 [함수선언] 부분과 붙어 있지만 내부의
                //[지역변수] 는 [함수본체] 가 오는 부분에 오므로 서로 떨어져 있게 된다.
                //따라서, 아래와 같이 처리 한다.
                //
                // 1) 먼저 [인수] 를 처리한다.
                //
                //    - [인수] 다음에 [지역변수] 가 계속된다면 바로 3) 단계를 처리하면 된다.
                //
                // 2) [함수영역] 을 찾는다(여기부터 [지역변수] 시작이 된다).
                //
                // 3) 일단 [함수영역] 은 다시 분리되지 않는다.
                //
                //}--------------------------------------------------------------------------

                //[인수 처리]
                //{
                    //[!]{-------------------------------------
                    //[인수] 는 [함수] 바로 다음부터 시작된다.
                    //먼저 [인수] 를 처리한다.
                    //}----------------------------------------

                    for(//아직 [함수] 의 위치 이므로 j = i + 1 로 시작한다.
                        j = i + 1, memberCount = 0;
                        j < DB_->record_count;
                        j++, memberCount++)
                    {
                      //[영역 검사]
                      //{
                          //[함수 영역] 안 이고 [인수] 에 해당하는 것만 처리한다.
                          if(!((DB_->record[j].area == motherIndex) &&
                               (DB_->record[j].kind == _recKIND_func_param))) break;

                      //}

                      //[<pPartName_> 을 가진 <name> 인가?]
                      //{
                          //[2012.05.29.화][추가!!!]{--------------------------------------
                          //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                          //시작부분부터 일치하는 [항목] 만 추가.
                          //}--------------------------------------------------------------

                          if((pPartName_ != NULL) &&
                             //[2012.05.30.수][추가!!!]
                             //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                             (pPartName_[0] != '\0'))
                          {
                            //일치하지 않는 경우는 다음 항목으로 넘긴다.
                            //[2012.07.21.토][수정!!!]
                            //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                            if(Str_Match_Part_NoCase(DB_->record[j].name, pPartName_) != true) continue;

                            //[2012.05.30.수][수정!!!]
                            //<pFncRecIndex:-1> 이 아닌 경우는 [현재 함수 영역] 에서
                            //사용 가능한 [지역변수] 만 남겨놓아야 한다.
                            if(!((pFncRecIndex >= 0) && (pFncRecIndex == motherIndex))) continue;

                          }

                      //}

                      //[항목 초기화]
                      //{
                          info_tree_Form->_Item_Init(&item);

                      //}

                      //[<name> 만들기]
                      //{
                          //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                          CONV_LongVal_To_Hex2(j, hexStr);
                          STR_Assign(item.name, hexStr);

                      //}

                      //[기타 설정]
                      //{
                          item.kind = '.';

                          //일단 기본그림으로 설정한다.
                          item.bmpindex = d_ITEMBMP_item;

                      //}

                      //[<text> 만들기]
                      //{
                          //[!]{---------------------------------------------------------
                          //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                          //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                          //}------------------------------------------------------------

                          Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                          info_tree_Form->_Item_Txt(&item, itemTxt);

                          if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                          else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                      //}

                      //[<recindex> 기록]
                      //{
                          //{definelist[]} 상의 <recindex> 를 기록해 준다.
                          item.info1 = j;

                      //}

                      //[추가]
                      //{
                          //모체에 추가 해야 한다.
                          info_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                      //}

                    }

                    i += memberCount;

                //}

                //[순수 지역변수 처리]
                //{
                    //[함수 지역 영역 시작 찾기]
                    //{
                        for(//아직 [함수] 나 마지막 [인수] 의 위치 이므로 j = i + 1 로 시작한다.
                            j = i + 1;
                            j < DB_->record_count;
                            j++)
                        {
                          //[지역변수] 는 [함수영역] 시작 부터 다시 시작되므로 일단
                          //이 함수 영역이 다시 시작되는 부분을 찾는다.

                          if(DB_->record[j].area == motherIndex)
                          {
                            //시작 위치를 찾았으므로 계속 [진역 변수] 를 처리한다.
                            goto FUNC_LOCAL_ITEM;

                          }

                        }


                        //[하위 항목 존재 확인:인수부]
                        //{
                            //[주의!!!]{-------------------------------------------------------------------
                            //[인수] 가 없는 함수라도 [지역변수] 는 있을수 있으므로 [인수] 처리부 끝에서
                            //[인수] 가 없다고 [함수] 를 삭제하는 경우는 [지역변수] 가 있는 경우 [추가할]
                            //대상 [함수] 항목이 존재하지 않는 상태가 된다.
                            //그렇다고 [지역변수] 끝에서만 처리하는 경우는 [지역변수] 가 없는 경우는
                            //건너뛰게 되므로 [함수] 항목이 남겨지게 된다.
                            //따라서, [인수] 부를 반드시 [지역변수] 가 없는 경우를 처리하는 이 지점에서
                            //처리해 주어야 두 경우 모두 확실하게 처리할수 있다.
                            //
                            //<i> 는 이미 [수정] 된 상태이나 <motherIndex> 에 [함수위치] 가 있으므로 무관.
                            //
                            //[2012.05.30.수][추가!!]{-----------------------------------------------------
                            //[근접 단어 정렬] 시에는 [하위항목] 이 없는 경우만 삭제.
                            //[근접단어] 만 남겨 놓아야 하므로 그외 모든 항목은 삭제.
                            //}----------------------------------------------------------------------------

                            if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
                            {
                              //하위항목 개수 얻기.
                              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemMotherIndex, &itemCount);

                              if(itemCount == 0)
                              {
                                //단, <pPartName_> 과 부분일치 한다면 [삭제] 하지 않아야 한다.
                                //[2012.07.21.토][수정!!!]
                                //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                                if(Str_Match_Part_NoCase(DB_->record[motherIndex].name, pPartName_) != true)
                                {
                                  //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                                  info_tree_Form->_Tree_Delete_Item(tree, itemMotherIndex);

                                }

                              }

                            }

                        //}


                        //[다음 함수 처리 계속]
                        //{
                            //[중요 주의!!!]
                            //{
                                //다음 계속할 위치는 현재 [함수] 위치다음부터 시작되어야 한다.
                                //이는 [선언] 이 먼저 오고 [본체] 가 나중에 있는 경우는 반드시
                                //[선언] 된 순서대로 [본체] 가 온다는 보장이 없기 때문이다.
                                //따라서, 이미 처리한 [함수] 는 제외하고 다음부터 계속 검사해야 한다.
                                //항상 [함수] 를 먼저 찾으므로 다음이 [인수] 나 [지역변수] 가 되어도
                                //무시되므로 상관 없다.

                                i = motherIndex;

                            //}

                            //여기 까지 온것은 이미 이 [함수] 는 더이상 처리할 것이 없는 것이다.
                            //따라서, 계속 다음 [함수] 를 처리한다.
                            continue;

                        //}

                    //}

                    FUNC_LOCAL_ITEM:

                    for(//j 는 이미 위에서 구한 위치부터 시작하면 된다.
                        memberCount = 0;
                        j < DB_->record_count;
                        j++, memberCount++)
                    {
                      //[영역 검사]
                      //{
                          //[함수 영역] 안 이고 [인수] 에 해당하는 것만 처리한다.
                          if(!((DB_->record[j].area == motherIndex) &&
                               (DB_->record[j].kind == _recKIND_data))) break;

                      //}

                      //[<pPartName_> 을 가진 <name> 인가?]
                      //{
                          //[2012.05.29.화][추가!!!]{--------------------------------------
                          //<pPartName_:NULL> 인 경우가 아니라면 <name> 에 <pPartName_> 가
                          //시작부분부터 일치하는 [항목] 만 추가.
                          //}--------------------------------------------------------------

                          if((pPartName_ != NULL) &&
                             //[2012.05.30.수][추가!!!]
                             //[단어] 가 없는 경우도 NULL 과 같은 것으로 취급.
                             (pPartName_[0] != '\0'))
                          {
                            //일치하지 않는 경우는 다음 항목으로 넘긴다.
                            //[2012.07.21.토][수정!!!]
                            //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                            if(Str_Match_Part_NoCase(DB_->record[j].name, pPartName_) != true) continue;

                            //[2012.05.30.수][수정!!!]
                            //<pFncRecIndex:-1> 이 아닌 경우는 [현재 함수 영역] 에서
                            //사용 가능한 [지역변수] 만 남겨놓아야 한다.
                            if(!((pFncRecIndex >= 0) && (pFncRecIndex == motherIndex))) continue;

                          }

                      //}

                      //[항목 초기화]
                      //{
                          info_tree_Form->_Item_Init(&item);

                      //}

                      //[<name> 만들기]
                      //{
                          //{DATABASE} 상의 record-index 값으로 [이름] 을 만든다.
                          CONV_LongVal_To_Hex2(j, hexStr);
                          STR_Assign(item.name, hexStr);

                      //}

                      //[기타 설정]
                      //{
                          item.kind = '.';

                          //일단 기본그림으로 설정한다.
                          item.bmpindex = d_ITEMBMP_item;

                      //}

                      //[<text> 만들기]
                      //{
                          //[!]{---------------------------------------------------------
                          //[구조체/공용체/포인터/배열] 등 다양한 형태로 선언되 있으므로
                          //전용 함수를 사용하여 [선언문자열] 을 합성한다.
                          //}------------------------------------------------------------

                          Ide_TreeInfo_ItemTextMake(j, itemTxt, &isStructUnion);

                          info_tree_Form->_Item_Txt(&item, itemTxt);

                          if     (isStructUnion == 's') { item.bmpindex = d_ITEMBMP_struct; }
                          else if(isStructUnion == 'u') { item.bmpindex = d_ITEMBMP_union;  }

                      //}

                      //[<recindex> 기록]
                      //{
                          //{definelist[]} 상의 <recindex> 를 기록해 준다.
                          item.info1 = j;

                      //}

                      //[추가]
                      //{
                          //모체에 추가 해야 한다.
                          info_tree_Form->_Tree_Add_NodeItem(tree, motherName, &item, NULL);

                      //}

                    }

                    //***********************************************
                    lbCheckLocalVarCount: //[2012.05.31.목][추가!!!]
                    //***********************************************

                    //[하위 항목 존재 확인:지역변수부]
                    //{
                        //[2012.05.30.수][추가!!]{--------------------------------
                        //[근접 단어 정렬] 시에는 [하위항목] 이 없는 경우만 삭제.
                        //[근접단어] 만 남겨 놓아야 하므로 그외 모든 항목은 삭제.
                        //}-------------------------------------------------------

                        if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
                        {
                          //하위항목 개수 얻기.
                          info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemMotherIndex, &itemCount);

                          if(itemCount == 0)
                          {
                            //단, <pPartName_> 과 부분일치 한다면 [삭제] 하지 않아야 한다.
                            //[2012.07.21.토][수정!!!]
                            //[대/소 문자 구분] 을 하지 않는 함수로 교체.
                            if(Str_Match_Part_NoCase(DB_->record[motherIndex].name, pPartName_) != true)
                            {
                              //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                              info_tree_Form->_Tree_Delete_Item(tree, itemMotherIndex);

                            }

                          }

                        }  

                    //}

                    //[중요 주의!!!]
                    //{
                        //다음 계속할 위치는 현재 [함수] 위치다음부터 시작되어야 한다.
                        //이는 [선언] 이 먼저 오고 [본체] 가 나중에 있는 경우는 반드시
                        //[선언] 된 순서대로 [본체] 가 온다는 보장이 없기 때문이다.
                        //따라서, 이미 처리한 [함수] 는 제외하고 다음부터 계속 검사해야 한다.
                        //항상 [함수] 를 먼저 찾으므로 다음이 [인수] 나 [지역변수] 가 되어도
                        //무시되므로 상관 없다.

                        i = motherIndex;

                    //}

                //}

            //}

          }

          //[하위항목 존재 확인]
          //{
              //[2012.04.16.월][추가!!!]{----------------------------
              //[하위항목] 이 전혀 없다면 이 [대표항목] 을 삭제한다.
              //}----------------------------------------------------

              //해당 [대표항목] 위치 찾기.
              info_tree_Form->_Tree_Get_ItemIndex_withNAME(tree, "function", &itemIndex);

              //하위항목 개수 얻기.
              info_tree_Form->_Tree_Get_Node_ItemCount2(tree, itemIndex, &itemCount);

              if(itemCount == 0)
              {
                //하위 항목이 존재하지 않으므로 [대표항목] 삭제.
                info_tree_Form->_Tree_Delete_Item(tree, itemIndex);

              }

          //}

      //}

  //}

  //[형식 적용 문자열 정보 재정리]
  //{
      //[2012.05.20.일][추가!!!]{----------------------------------------------
      //이 함수 자체가 <Parser()> 후 [Tree:설계정보] 를 채워주는 것으로
      //[구조체/공용체] 는 계속 변화될수 있으므로 이 정보때문에 다시 정리한다.
      //
      //[2012.05.21.월][수정!!!]-----------------------------------------------
      //[귀뜸말] 뿐 아니라 <Tree:항목> 에도 [형식 적용 문자열] 을 지원하므로
      //<_TreeView()> 로 그려지기 전에 먼저 설정해야 한다.
      //}----------------------------------------------------------------------

      info_tree_Form->_ConfStr_Info_Set();

  //}

  //[전체 펼치기]
  //{
      //[2012.05.30.수][추가!!!]{---------------------------------------------
      //[근접 단어 정렬] 시에는 모든 [항목] 이 보일수 있도록 전부다 펼쳐준다.
      //어차피 <pPartName_> 과 일치하는 단어의 경우는 [수량이 적다] 이므로
      //모두 펼치는 경우라도 항목이 많지 않다.
      //BCB 의 경우도 모든 내용을 다 보여주는 방식이므로 큰 지장은 없다.
      //}---------------------------------------------------------------------

      if((pPartName_ != NULL) && (pPartName_[0] != '\0'))
      {
        //[!]{-----------------------------------------------
        //[근접 단어 정렬] 의 경우이므로 모든 항목을 펼친다.
        //}--------------------------------------------------

        //다음 [반영] 에서 다시 그리기 하므로 여기서는 [다시 그리기] 하지 않는다.
        info_tree_Form->_Tree_ExpandAll(false);

      }

  //}

  //[반영]
  //{
      //[2012.06.01.금][수정!!!]{----------------------------------------------
      //[다시 그리기] 요청이 있는 경우만 마지막에 한번 [다시 그리기] 처리한다.
      //}----------------------------------------------------------------------

      if(pRePaint == true)
      {
        //내용만 다시 그리므로 폼을 잘라내지 않는다.
        info_tree_Form->_TreeView(false, false);

      }

  //}

}

bool __fastcall Ide_InfoTree_Operator(void)
{
  //[2012.06.21.목][생성!!!]{-----------------------------------------------------------------
  //<{DB}->_rtExpMark> 정보를 참고로 [식] 을 처리하고 지정 "->", "." [연산자] 의
  //대상 [모체:선언형] 을 얻어 <{DB}->_rtExpMark> 내부에 저장.
  //
  //단, [실시간 선언 정보판] 을 위한 것으로 현재 [편집기] 에 열려있는 문서를
  //대상으로 처리하고, 반드시 [실시간 선언 정보] 를 먼저 처리하여 <{DB}->_rtExpMark>
  //안에 처리할 대상 정보가 들어 있어야 처리 할수 있다.
  //
  //<Teditor_edit_Form::InfoTree_Call()> 함수에서 사용된다.
  //
  //[2012.06.23.토][대폭수정!!!]--------------------------------------------------------------
  //"... 모체.모체-> |" 인 경우("|" 는 [입력지정자])는 원래 사용할수 있는 [구성원 정보] 를
  //보여주어야 하지만, 아직 [식] 이 모두 완성되지 않은 상태라 이 상태에서 [식] 을 처리할 경우
  //<TREE_Expression_1_Level()> 함수에서 오류가 발생하여 더이상 진행이 안되기 때문에
  //<TREE_Expression()> 자체가 완료가 안되고 오류가 되어 결과를 알수 없게 된다.
  //
  //이를 방지하고 [식] 이 미완성 상태라도 [모체:선언형] 을 알수 있도록 방법을 수정.
  //[구성원] 자체는 중요하지 않다.
  //실제 <EXPRESSION_Optr_Opnd_Match()> 함수에서 "->", "." [연산자] 부분에서 [모체:선언형] 만
  //추출하는 즉시 종료하기 때문.
  //
  //1) [식:시작위치] 부터 [연산자] 포함위치까지 [식] 추출.
  //   단, 이 [식] 에는 [주석문] 이 들어 있을수 있으나 절대 삭제하지 않고 그대로 사용.
  //
  //   [중요!!!]{*********************************************************************
  //   절대 [주석문] 을 삭제하면 안된다.
  //   이는 [연산자:위치] 는 본문 그대로의 위치로 [주석문] 까지 포함한 위치이기 때문.
  //   즉, [식] 에 [주석문] 을 그대로 두고 처리해야 한다.
  //   }******************************************************************************
  //
  //   식) "모체.모체->"
  //
  //2) [식] 뒤에 "0" 으로 [상수:0] 을 붙여준다.
  //   이는 <TREE_Expression_1_Level()> 로 [식] 을 검사할때 규칙을 맞추어 오류가 발생하지
  //   않게 하기 위한 것으로 [연산자 의미상] 은 맞지 않지만 [짝을 맞추기 위한] 용도이다.
  //   이는 <TREE_Expression_1_Level()> 을 통과해야 [식] 을 처리할수 있기 때문.
  //   <EXPRESSION_Optr_Opnd_Match()> 함수에서는 "->", "." 연산자인 경우 [모체:선언형] 만
  //   추출하고 바로 종료하며 (R) 과 [적합성 검사] 는 하지 않는다.
  //
  //   식) "모체.모체->0"
  //
  //3) 2) 에서 합성된 [식] 을 <TREE_Expression()> 함수로 처리하고 [모체:선언형] 정보 추출.
  //
  //[주의!!!]*********************************************************************************
  //이 함수는 반드시 [식:시작위치], "->", "." [연산자] 위치를 검출한 뒤 사용되어야 한다.
  //
  //절대 [주석문] 을 제거한 식을 사용하면 안된다.
  //[연산자:위치] 와 [식:시작위치] 자체가 [주석문] 까지 포함된 위치이기 때문.
  //
  //[참고!!!]---------------------------------------------------------------------------------
  //[검증식] 처리에 사용되는 <DebugView_Get_ExpStr_fromEditor()> 함수를 참고하였다.
  //
  //[0212.06.25.월][중요수정!!!]**************************************************************
  //[식] 저장공간을 [크기대로:동적 생성] 하는 경우는 너무 크기가 작은 경우가 발생하는데
  //아주 빠르게 반복하여 <Ctrl+Space> 눌러(1초에 10회 이상)대는 경우는 동작 시킬때는 문제가
  //없는데 [맷돌-통합개발환경] 을 종료할때 [치명적인 오류] 가 발생한다.
  //
  //너무 작은 크기의 [동적생성] 이 빠르게  반복되는 경우는 [해제] 시 등 여러 내부 API 에서
  //오류가 발생하는 것 같다.
  //
  //[고정크기] 로 만드는 경우는 [식] 문자열의 길이를 가늠할수 없게 되어 넘칠수 있으므로
  //<1K> 단위로 생성하는 것으로 처리.
  //실제 { expStr_ = new char[((expStrSize/1024) + 1)*1024]; } 와 같이 처리하였다.
  //
  //결과적으로 [치명적인 오류] 는 발생하지 않는다.
  //
  //더이상 [오류] 가 나지 않는한 계속 이 방법 유지.
  //}-----------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *DB_;

      int    rslt;

      //[식:문자열 관련]
      //{
          //[2012.06.23.토][추가!!!]{--------------------------------------------------
          //[주석문] 이 들어 있는 경우도 그대로 사용해야(위치가 변경되면 안되므로)하나
          //[주석문] 의 양을 알수가 없기 때문에 [동적생성] 으로 처리.
          //
          //[2012.06.25.월][중요!!!]---------------------------------------------------
          //단, 기타 [오류] 방지 차원에서 <1K> 단위로 동적 생성.
          //}--------------------------------------------------------------------------

          char  *expStr_ = NULL;
          int    expStrSize;

      //}

  //}

  //[초기화]
  //{
      //{DataBase} 주소 얻기.
      DATABASE_GetPtr(&DB_);

  //}

  //[확인]
  //{
      //[2012.06.23.토][추가!!!]{-------------------------
      //[식:문자열] 추출시 사용되는 정보가 유효한지 확인.
      //}-------------------------------------------------

      //[2012.06.25.월][추가!!!]{-----------------
      if(editor_edit_Form == NULL) return(false);
      //}-----------------------------------------

      if(DB_->RtExpMark_Read() == -1)   { return(false); }
      if(DB_->_rtExpMark.opIndex == -1) { return(false); }

  //}

  //[식 얻기]
  //{
      //[중요!!!]{********************************************************************************
      //[식:시작위치] 부터 [연산자] 포함위치까지 [식] 을 추출.
      //
      //[주석문] 은 절대 제거하면 안된다!!!
      //
      //[식:시작위치], [연산자:위치] 는 모두 본문에서 [주석문] 까지 포함한 [위치] 이므로
      //[주석문] 을 삭제해 버리면 [식:시작위치] 는 어차피 [처음] 부터라 상관이 없으나
      //[연산자] 위치가 [변경] 되어 [위치 비교] 시 문제가 된다.
      //
      //[주석문] 이 있어도 <TREE_Expression()> 를 처리하는데 문제가 없다.
      //
      //다음 부분에서 { DB_->_rtExpMark.opIndex -= DB_->RtExpMark_Read(); } 로
      //정보를 수정할때 [주석문] 이 없는 [식 문자열] 의 [연산자] 위치와 [본문] 에서
      //구한 [위치] 는 [식:처음위치] 와 [연산자:위치] 사이에 있었던 [주석문 양] 에 따라 달라진다.
      //}*****************************************************************************************

      //<[식> 부분 존재 확인]
      //{
          //[2012.06.25.월][추가!!!]{----------------------------------------
          //[식] 부분 문자열이 존재하지 않는다면 추출하지 않고 종료.
          //문서 자체가 아예 NULL 인 경우등도 있으므로 사전에 미리 걸러낸다.
          //
          //[크기] 정보로 [동적생성] 하기 전에 먼저 처리.
          //}----------------------------------------------------------------

          //[편집기] 에 문자열이 없는 경우는 처리하지 않는다.
          if(editor_edit_Form->_editbuf[0] == '\0') return(false);

          if((DB_->_rtExpMark.opIndex - DB_->RtExpMark_Read()) <= 0) return(false);

      //}

      //[추출 크기 얻기]
      //{
          //저장소를 동적 생성해야 하므로 미리 크기를 계산.
          expStrSize = (DB_->_rtExpMark.opIndex - DB_->RtExpMark_Read()) +
                        //[연산자] 까지 추출해야 하므로 [연산자] 길이 추가.
                        DB_->_rtExpMark.opLength +
                        //'\0' 까지 저장해야 한다.
                        1;

      //}

      //[저장소 생성]
      //{
          //[2012.06.25.월][중요수정!!!]{**************************************************
          //얻은 <expStrSize> 크기는 [너무 작은] 경우가 대부분인데 [1초에 수십번]
          //<Ctrl+Space> 를 눌러 [실시간 선언 정보판] 을 보이는 극악한 시험 환경에서
          //동작시는 문제가 없었는데 [맷돌-통합개발환경] 종료시 알수 없는 [메모리 오류] 가
          //발생하였다.
          //
          //이를 방지하기 위하여 [너무작은:동적생성] 이 반복되는 것을 막기 위하여
          //<1K> 단위로 [동적생성] 한다.
          //}******************************************************************************

          //<1K> 단위 동적생성-----------------------v
          expStr_ = new char[((expStrSize/1024) + 1)*1024];
          
      //}

      //[식 문자열 추출]
      //{
          //[2012.06.23.토][추가!!!]
          STR_SubString(editor_edit_Form->_editbuf,
                        //[식:시작위치] 부터 추출.
                        DB_->RtExpMark_Read(),
                        //'\0' 까지 포함한 크기이므로 -1 한 값을 사용.
                        expStrSize - 1,
                        expStr_);

     //}

     //[식 완성]
     //{
         //[!]{--------------------------------------------------------------------------
         //<TREE_Expression_1_Level()> 함수에서 [기본규칙] 오류가 발생하지 않도록
         //[연산자] 까지 수집된 [식 문자열] 에 [가상 구성원] 으로 "0" 을 추가.
         //
         //실제 <EXPRESSION_Optr_Opnd_Match()> 함수에서 [연산자] 처리시 [모체:선언형] 만
         //얻은뒤 [적합성] 검사는 아예 하지 않기 때문에 전혀 문제가 없다.
         //}-----------------------------------------------------------------------------

         STR_Add(expStr_, "0");

     //}

  //}

  //[정보 수정]
  //{
      //[중요!!!]{**********************************************************
      //<DB_->_rtExpMark.opIndex> 정보는 [편집기] 전제 문자열을 기준으로 한
      //정보 이므로 여기서 추출된 [식 문자열] 에 맞게 수정.
      //
      //[식:시작위치] 부터를 기준으로 위치 수정.
      //}*******************************************************************

      DB_->_rtExpMark.opIndex -= DB_->RtExpMark_Read();

  //}

  //[[식] 처리에 맞게 초기화]
  //{
      //[!]{-----------------------------------------------------------
      //<parserInfo> 의 대부분의 정보는 [식 문자열] 처리에 무의미하다.
      //꼭 필요한 정보만 재정의 한다.
      //
      //[식] 은 현재 <_editbuf[]> 상의 위치를 대상으로 하고 [식] 의
      //정확한 위치는 이 함수를 호출한 곳에서 이미 얻은 상태이므로
      //처리할 [식] 의 시작 위치를 직접 기록한다.
      //}--------------------------------------------------------------

      //[초기화]
      //{
          //[검증식 문자열] 을 처음부터 처리하는 것이므로 반드시 초기화.
          DB_->PARSERINFO_Format(&(DB_->parserinfo));

      //}

      //[식 문자열] 을 [문서] 처럼 처리 하도록 대상으로 지정해 주어야 한다.
      DB_->parserinfo.buf = expStr_;

      //[식] 시작위치 설정.
      //이미 [식] 부분을 별도 추출하였으므로 이 문자열의 시작위치부터 처리.
      DB_->parserinfo.index = 0;

      //[식 문자열] 을 하나의 문서로 보고 크기를 정확하게 지정한다.
      //이는 <Get_NextWord()> 함수 처리시 내부적으로 문서의 크기를 알아야 종료하기 때문이다.
      DB_->parserinfo.filesize = expStrSize;

      //[함수영역] 지정.
      //<TREE_Expression()> 함수에서 [지역변수] 를 검사하는데 반드시 필요하다.
      //이 함수를 호출한 곳에서 먼저 정리해 놓았으므로 이 정보를 사용.
      DB_->parserinfo.area_gl = DB_->_rtExpMark.funcRecIndex;

      //[주의!!!]{-----------------------------------------------------------------------------
      //현재 처리할 [식] 이 존재하는 문서는 [편집기] 에 열려있는 문서가 된다.
      //<Ide_RealTimeInfo()> 함수 처리시 자동으로 얻어지는 정보를 그대로 사용한다.
      //이 함수 자체는 <Teditor_edit_Form::InfoTree_Call()> 함수에서 <Ide_RealTimeInfo()> 함수
      //바로 다음에 사용된다.
      DB_->parserinfo.filelistindex = DB_->_rtDefInfoEtc.fileListIndex;
      //}--------------------------------------------------------------------------------------

  //}

  //[식 계산]
  //{
      //[!]{--------------------------------------------------------------------
      //반환정보는 전혀 필요 없으며 내부적으로 "->", "." 연산자인 경우
      //자동으로 [모체:선언형] 정보가 <{DB}->_rtExpMark.motherTypeListIndex> 에
      //수집된다.
      //}-----------------------------------------------------------------------

      rslt = TREE_Expression(DB_, &(DB_->parserinfo),
                             //{TEMP} 는 반드시 초기화.
                             true,
                             NULL, NULL, NULL, NULL, NULL, d_ExpKind_RtInfo);

  //}

  //[동적삭제]
  //{
      //[2012.06.23.토][추가!!!]{---
      //동적생성한 개체를 삭제.
      //}---------------------------

      if(expStr_ != NULL) { delete [] expStr_; expStr_ = NULL; }

  //}

  return(rslt);

}

//******************************************************************************
//[API 자동 추가 관련]**********************************************************
//******************************************************************************

//[반환값] : 구한 [API 목록] 의 문자열 길이.
int __fastcall API_Get_List(//API 목록 반환(내부에서 동적 생성하므로 (**) 사용).
                            char **rApiList)
{
  //[2022.05.24.화][생성]{----------------------------------------------
  //[IDE\glib] 폴더 안의 [API:이름] 만 추출해서 [행단위목록] 으로 반환.
  //
  //[참고]**************************************************************
  //[API 자동추가] 기능 때문에 제작했으나 현재 <API_Add_To_Project() 와
  //<API_Check()> 함수 만으로 충분하므로 사용하지 않음.
  //
  //[주의]--------------------------------------------------------------
  //이 함수는 내부적으로 <rApiHList> 를 동적 생성하여 반환하므로,
  //반드시 이 함수를 호출한 곳에서 사용 후 동적 삭제해야 한다.
  //--------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *DB_;
      
      TStringList      *list_;

      //[2022.06.07.화][추가]
      int               listSize;
      
      char              glibPath_[OPT_lineStrSize];
      
  //}
  
  //[Database 주소 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&DB_);

  //}

  //[<glib> 경로 만들기]
  //{
      STR_Add_AB(glibPath_, DB_->programpath, "glib\\");

  //}

  //[API 목록 얻기]
  //{
      list_ = new TStringList;
      list_->Clear();

      Dir_Get_FileList_BoundDir2(glibPath_,
                                 //검색할 확장자.
                                 "glib",
                                 //하위 경로까지 검사.
                                 false,
                                 //<파일만 검사> && <경로와 확장자가 제거된 순수한 [이름] 만 수집>.
                                 d_File | d_NameExceptExt,//d_File,// | d_NameExceptExt,
                                 list_);

  //}

  //[저장소 생성]
  //{
      //API 목록을 저장할 저장소 생성.
      //'\0' 까지 저장----------------------------------------------------------v
      (*rApiList) = new char[UnitX(1024, ((AnsiString)(list_->Text)).Length() + 1)];

  //}

  //[목록 저장]
  //{
      STR_Assign((*rApiList), ((AnsiString)(list_->Text)).c_str());

  //}

  //[목록 크기 얻기]
  //{
      //[2022.06.07.화][중요수정]{-------------------------------------------------------
      //{ return(list_->Text.Length()) } 으로 사용하는 경우는 동적으로 생성한 <list_> 를
      //삭제하지 못하는 문제가 있으므로, 아래 처럼 별도로 크기를 구해서 사용한다.
      //}--------------------------------------------------------------------------------

      listSize = ((AnsiString)(list_->Text)).Length();

  //}

  //[API 목록 삭제]
  //{
      //[2022.06.07.화][추가]{-------
      //동적 생성한 <list_> 를 삭제.
      //}----------------------------

      if(list_ != NULL) { delete list_; }

  //}

  //[목록 크기 반환]
  //{
      //구한 [API 목록] 의 문자열 길이를 반환.
      return(listSize);

  //}

}

bool __fastcall API_Add_To_Project(//확장자 없이 "_XXX_" 나 "_XXX" 같은 순수 이름만 사용.
                                   char  *pApiName)
{
  //[2022.05.26.목][생성]{------------------------------------------------------------------------
  //[탭:API] 에서 API 를 [Tree:설계묶음] 에 등록하는데 사용되는 <Ide_Tree_Api_Add_Glib_To_Gprj()>
  //함수를 가지고, <pApiName> 을 직접 입력 받아 처리하는 것으로 수정한것.
  //
  //[중요]{***************************************************************************************
  //<pApiName> 이 API 에 해당하지 않는 경우는 <반환:false> 후 종료하므로, 해당 [이름] 이 API 인지
  //확인하는 용도로도 사용 가능하나, 해당하는 경우는 API 가 자동 [복사/추가] 되므로 이런 용도로는
  //<API_Check()> 함수를 사용할것.
  //}*********************************************************************************************
  //
  //이 함수는 실제 아래 2 개 동작을 처리한다.
  //
  //1) <pApiName> 에 해당하는 API 를 [설계묶음\glib] 안에 복사.
  //
  //2) [Tree:설계묶음->함수묶음] 에 추가.
  //
  //[주의]----------------------------------------------------------------------------------------
  //반드시 <*.glib> 는 <*.h> , <*.gtxt> 와 짝이 되어야 하므로 항상 같이 복사한다.
  //죽, 항상 3 개 문서를 복사해 주어야 한다.
  //
  //현재 [새설계묶음] 인 경우는 처리해서는 안된다.
  //이 경우 기본 경로이므로 해당 IDE\[glib] 안의 해당 API 가 삭제된다.
  //
  //API 자동 추가 기능이 필요해서 관련 함수 묶음을 제작.
  //}---------------------------------------------------------------------------------------------

  //[VAR]
  //{
      //{DATABASE} 의 본체 주소값을 가지는 pointer.
      class  DATABASE  *DB_;

      struct TREE      *tree;

      char   srcPathNameExt[OPT_lineStrSize];
      char   dstPathNameExt[OPT_lineStrSize];

      //<Ide_Tree_Api_Make_ItemPath()> 함수로 구한 <"glib\옹이\옹이\옹이\...\항목.glib"> 를 저장하기 위한것.
      char   apiInnerPathNameExt[OPT_lineStrSize];

      //<pApiName> + ".glib" 를 저장하기 위한것.
      char   apiNameExt[OPT_lineStrSize];

      int    itemIndex;

  //}

  //[새설계묶음인가?]
  //{
      //[!]{---------------------------------------------
      //[새설계묶음] 인 경우는 API 를 추가해서는 안된다.
      //}------------------------------------------------

      if(STR_Match_NoCase(tree_tree_Form->_Item_Txt_StrPtr(d_TREE_project, 0), "새설계묶음") == true)
      {
        ide_msgbox_Form->_MsgBox(d_MSGBOX_info,
                                 "[새설계묶음] 상태에서는 API 를 추가 할수 없습니다.\r\n"
                                 "먼저 <*.gprj> 로 [설계묶음] 을 저장해야 합니다."
                                );

        //더이상 처리하지 않고 종료한다.
        return(false);

      }

  //}

  //[기본 처리]
  //{
      DATABASE_GetPtr(&DB_);

      tree = &(tree_tree_Form->_tree[d_TREE_api]);

  //}

  //[<Tree:API> 에서 <pApiName> 찾기]
  //{
      //검색시에는 <*.glib> 로 검색해야 하므로 <pApiName> 뒤에 ".glib" 를 붙여준다.
      STR_Add_AB(apiNameExt, pApiName, ".glib");

      //<Tree> 에서 보여지는 문자열로 해당 항목의 절대위치를 찾는다(찾지 못한 경우는 <-1> 반환). 
      tree_tree_Form->_Tree_Get_ItemIndex_withText(tree,
                                                   //검사할 <text> 항목.
                                                   apiNameExt,
                                                   //<text> 를 가진 itemindex.
                                                   &itemIndex);

      //[존재확인]
      //{
          if(itemIndex < 0)
          {
            //<pApiName> 은 API 가 아니므로 더이상 진행하지 않고 종료.
            return(false);

          }

      //}

  //}

  //[경로 합성]
  //{
      //[항목 경로 얻기]
      //{
          //[!]{-------------------------------------------------------------------------------------------
          //[Tree:API] 상의 경로를 정부 합성하는 것으로 <"glib\옹이\옹이\옹이\...\항목.glib"> 형식이 된다.
          //}----------------------------------------------------------------------------------------------

          Ide_Tree_Api_Make_ItemPath(d_TREE_api, itemIndex, apiInnerPathNameExt);

      //}

      //[출발지 경로 합성]
      //{
          //[!]{-------------------------------
          //출발지 [전체:경로이름확장자] 합성.
          //}----------------------------------
          
          STR_Add_AB(srcPathNameExt, DB_->programpath, apiInnerPathNameExt);

      //}

      //[도착지 경로 합성]
      //{
          //[!]{---------------------------------------------------------------------
          //도착지 [전체:경로이름확장자] 합성.
          //사용자 [설계묶음] 경로안으로 하면된다(출발지 경로에 "glib" 가 있으므로).
          //}------------------------------------------------------------------------
          
          STR_Add_AB(dstPathNameExt, DB_->projectpath, apiInnerPathNameExt);

      //}

  //}    

  //[복사]
  //{
      //[!]{-------------------------------------------------------------
      //해당 API 를 [IDE\glib] => [설계묶음(*.gprj)\glib] 로 복사.
      //
      //API(*.glib) 와 항상 짝을 이루는 <*.h>, <*.gtxt> 까지 같이 복사.
      //
      //[참고]***********************************************************
      //단, <*.gtxt> 는 API 에 따라 존재하지 않을수도 있으나, 복사시
      //파일이 존재하지 않은 경우는 자동으로 복사되지 않으므로 여기서는
      //존재를 확인하지 않는다.
      //}----------------------------------------------------------------

      //[<*.h> 복사]
      //{
          STR_ChangeFileExt(dstPathNameExt, "h", apiInnerPathNameExt); STR_Assign(dstPathNameExt, apiInnerPathNameExt);
          STR_ChangeFileExt(srcPathNameExt, "h", apiInnerPathNameExt); STR_Assign(srcPathNameExt, apiInnerPathNameExt);
          File_Copy(dstPathNameExt, srcPathNameExt);

      //}

      //[<*.gtxt> 복사]
      //{
          //[참고]{*******************************************************************
          //API 에 따라 <*.gtxt> 는 존재하지 않을수 있으나, <File_Copy()> 내부 적으로
          //[존재확인] 을 처리하므로 여기서는 항상 복사 처리한다.
          //}*************************************************************************

          STR_ChangeFileExt(dstPathNameExt, "gtxt", apiInnerPathNameExt); STR_Assign(dstPathNameExt, apiInnerPathNameExt);
          STR_ChangeFileExt(srcPathNameExt, "gtxt", apiInnerPathNameExt); STR_Assign(srcPathNameExt, apiInnerPathNameExt);
          File_Copy(dstPathNameExt, srcPathNameExt);

       //}

      //[<*.glib> 복사]
      //{
          //바로 다음 부분에서 [함수묶음] 에 바로 추가 할수 있도록 가장 나중에 처리한다.
          STR_ChangeFileExt(dstPathNameExt, "glib", apiInnerPathNameExt); STR_Assign(dstPathNameExt, apiInnerPathNameExt);
          STR_ChangeFileExt(srcPathNameExt, "glib", apiInnerPathNameExt); STR_Assign(srcPathNameExt, apiInnerPathNameExt);
          File_Copy(dstPathNameExt, srcPathNameExt);

      //}

  //}

  //[<Tree:설계묵음->함수묶음> 에 등록]
  //{
      //[중요]{************************************************************************************
      //아래 함수 내부에서 중복 방지 처리를 수행하므로, 여기서는 중복을 고려하지 않고 추가만 한다.
      //}******************************************************************************************
      
      if(IDE_Project_Add_Glib(dstPathNameExt) != true)
      {
        //[추가] 시에 오류가 발생한 경우는 추가되지 않은 것으로 간주한다.
        return(false);

      }

  //}

  //[참고]{***************************************
  //[Tree:다시그리기] 는 여기서 처리 하지 않는다.
  //}*********************************************

  //여기까지 온것은 API 가 이상없이 자동 추가된것.
  return(true);

}

bool __fastcall API_Check(//확장자 없이 "_XXX_" 나 "_XXX" 같은 순수 이름만 사용.
                          char  *pName)
{
  //[2022.05.26.목][생성]{------------------------------------------------------
  //<pName> 이 API 에 해당하는지 확인.
  //
  //간단하게 [탭:API] 의 API 이름에 해당하는지 확인후 해당한다면 <true> 반환.
  //
  //이미 정리된 [탭:Tree:API] 를 대상으로 이미 존재하는 <Tree> 관련 함수를 사용
  //하는 것이 가장 간단한 방법이다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      //<pApiName> + ".glib" 를 저장하기 위한것.
      char   apiNameExt[OPT_lineStrSize];

      int    itemIndex;

  //}

  //[기본 조건 확인]
  //{
      //[2022.05.27.금][추가]{---------------------------------------
      //기계닉스 모든 API 는 아래의 2 개 종류를 갖는다.
      //
      //1) 명령형 API         : "_XXX_" 형식(앞/뒤에 "_" 이 붙는다).
      //
      //2) 맷돌-C 로 만든 API : "_XXX"  형식(앞에만 "_" 이 붙는다).
      //}------------------------------------------------------------

      if     ((pName[0] == '_') && (STR_WordLastChar(pName) != '_'))
      {
        //명령형 API 형태인 경우.

      }
      else if(pName[0] == '_')
      {
        //맷돌-C 로 만든 API 형태인 경우.

      }
      else
      {
        //형식 자체가 API 에 해당하지 않는다.
        return(false);

      }

  //}

  //[<Tree:API> 에서 <pName> 찾기]
  //{
      //[!]{---------------------------------------------------
      //API 기본 조건은 만족 시키므로, API 에 해당하는지 확인.
      //}------------------------------------------------------

      //검색시에는 <*.glib> 로 검색해야 하므로 <pName> 뒤에 ".glib" 를 붙여준다.
      STR_Add_AB(apiNameExt, pName, ".glib");

      //<Tree> 에서 보여지는 문자열로 해당 항목의 절대위치를 찾는다(찾지 못한 경우는 <-1> 반환).
      tree_tree_Form->_Tree_Get_ItemIndex_withText(&(tree_tree_Form->_tree[d_TREE_api]),
                                                   //검사할 <text> 항목.
                                                   apiNameExt,
                                                   //<text> 를 가진 itemindex.
                                                   &itemIndex);

      if(itemIndex >= 0) return(true);   //API 에 해당하는 것.
      else               return(false);  //API 에 해당하지 않는다.

  //}

}

int __fastcall API_Get_List_H(//API 목록 반환(내부에서 동적 생성하므로 (**) 사용).
                              char **rApiHList)
{
  //[2022.06.05.일][생성]{----------------------------------------
  //<API.h> 만 추출해서 목록을 가진다.
  //
  //[주의]--------------------------------------------------------
  //이 함수는 내부적으로 <rApiHList> 를 동적 생성하여 반환하므로,
  //반드시 이 함수를 호출한 곳에서 사용 후 동적 삭제해야 한다.
  //--------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *DB_;
      
      TStringList      *list_;

      //[2022.06.07.화][추가]
      int               listSize;
      
      char              glibPath_[OPT_lineStrSize];
      
  //}
  
  //[Database 주소 얻기]
  //{
      //{DATABASE} 의 주소를 얻는다.
      DATABASE_GetPtr(&DB_);

  //}

  //[<glib> 경로 만들기]
  //{
      STR_Add_AB(glibPath_, DB_->programpath, "glib\\");

  //}

  //[API 목록 얻기]
  //{
      list_ = new TStringList;
      list_->Clear();
      
      //[전체 경로] 를 모두 추출.
      Dir_Get_FileList_BoundDir2(glibPath_,
                                 //검색할 확장자.
                                 "h",
                                 //하위 경로까지 검사.
                                 false,
                                 //<파일만 검사>
                                 d_File,
                                 list_);

  //}

  //[저장소 생성]
  //{
      //API 목록을 저장할 저장소 생성.
      //'\0' 까지 저장-----------------------------------------------------------v
      (*rApiHList) = new char[UnitX(1024, ((AnsiString)(list_->Text)).Length() + 1)];

  //}

  //[목록 저장]
  //{
      STR_Assign((*rApiHList), ((AnsiString)(list_->Text)).c_str());

  //}

  //[목록 크기 얻기]
  //{
      //[2022.06.07.화][중요수정]{-------------------------------------------------------
      //{ return(list_->Text.Length()) } 으로 사용하는 경우는 동적으로 생성한 <list_> 를
      //삭제하지 못하는 문제가 있으므로, 아래 처럼 별도로 크기를 구해서 사용한다.
      //}--------------------------------------------------------------------------------

      listSize = ((AnsiString)(list_->Text)).Length();

  //}

  //[API 목록 삭제]
  //{
      //[2022.06.07.화][추가]{-------
      //동적 생성한 <list_> 를 삭제.
      //}----------------------------

      if(list_ != NULL) { delete list_; }

  //}

  //[목록 크기 반환]
  //{
      //구한 [API_h 목록] 의 문자열 길이를 반환.
      return(listSize);

  //}

}

void __fastcall API_Make_DefFile(void)
{
  //[2022.06.05.일][생성]{-----------------------------------------------------
  //<API_Get_List_H()> 함수를 사용해서 <IDE:\glib\api_def.h> 문서를 만든다.
  //
  //단, <API_XXX.h> 문서안에  { #define  <d_정의이름> <문자열> } 이 있는
  //<API_XXX.h> 문서만 해당한다.
  //
  //[2022.06.08.수][중요수정]**************************************************
  //[정의이름] 뿐만 아니라, [구조체이름], [공용체이름] 까지 같이 포함시킨다.
  //
  //이는 <API이름.h> 안에 [구조체/공용체] 선언이 있는 경우가 있고, 실제 사용된
  //부분에서 역시 해당 [구조체/공용체] 선언부를 가진 <API이름.h> 를 자동 등록
  //할 필요가 있기 때문이다.
  //
  //[내용]---------------------------------------------------------------------
  //
  //API_XXX  <---API 순수 이름.
  //{
  //# d_정의이름  <---정의이름만 기록.
  //s 구조체이름  <---struct 구조체이름{ ... }; 으로 선언한 것.
  //u 공용체이름  <---union  공용체이름{ ... }; 으로 선언한 것.
  // ...
  //
  //}
  //  <---항목묶음 당 1행 공백 추가.
  //API_YYY
  //{
  // ...
  //}
  //
  //앞의 식별자 "#, s, u" 로 각 유형을 구분하지만, 실제는 두번째 단어인 [이름]
  //만 필요하다.
  //
  //의 형식으로 문서를 만든다.
  //
  //[주의]*********************************************************************
  //
  //이 함수는 [구조체/공용체:선언] 의 문법 검사까지 하지 않으며, 문법오류가
  //없다는 가정하에서 기본 기술 형식만으로 정보를 추출하는 것이다.
  //
  //또한, 구조체 안의 구조체 사용 부분까지 처리하지 않는다.
  //즉, 순수한 [구조체/공용체] 선언만을 대상으로 처리한다.
  //
  //struct 구조체이름 <---이 부분만 대상으로 처리한다(나머지 문법검사 불필요).
  //{
  //  ...
  //
  //};
  //
  //기계닉스는 항상 위의 규정된 기술을 사용하므로 이를 가정하고 진행한다.
  //
  //[참고]---------------------------------------------------------------------
  //이 함수는 [맷돌-IDE] 가 실행시 반드시 한 번 호출된다.
  //}--------------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *DB_;

      char  *apiH_List_ = NULL;

      int    apiH_List_Size = 0;

      //[파일 관련]
      //{
          char   filePathNameExt_[OPT_lineStrSize];

          char  *fileBuf_ = NULL;

          int    fileSize = 0;

      //}

      int   lineStartIndex;

      int   h_lineStartIndex;

      char  lineStr_[OPT_lineStrSize];

      char  wordStr_[OPT_lineStrSize];

      char  apiName_[OPT_lineStrSize];

      int   defCount;

      class VSTRBUF  *vStrBuf_ = NULL;

      bool  thisLineIsLast;

      //[2022.06.08.수][추가]
      char  kind; //'#'(정의이름), 's'(구조체이름), 'u'(공용체이름).

  //}

  //[DB 위치 얻기]
  //{
      DATABASE_GetPtr(&DB_);

  //}

  //[<폴더:glib> 안의 <*.h> 문서 목록 얻기]
  //{
      //실제 <*.h> 문서를 열어야 하므로 전체 목록으로 얻는다(전용 함수 사용).
      apiH_List_Size = API_Get_List_H(&apiH_List_);

      //[<apiH_List_> 내부 내용]{--------------------------------------------------------
      //아래와 같이 전체 경로가 들어 있다.
      //
      //C:\@기계닉스\Turbo2006\IDE\glib\IDE\API_Ide_Gvms\_Ide_가상기계_실행경로_.h
      //C:\@기계닉스\Turbo2006\IDE\glib\IDE\API_Ide_Gvms\_Ide_가상기계_실행이름확장자_.h
      // ...
      //
      //}--------------------------------------------------------------------------------

  //}

  //[<def_file> 문서 만들기]
  //{
      //[!]{---------------------------------------------------------------------------------------------------
      //<apiH_List_> 안의 내용으로 각각 문서를 열고, <#define> 으로 시작되는 행이 있다면 목록에 정리해서 추가.
      //}------------------------------------------------------------------------------------------------------

      //[<def_file> 문서 저장소 생성]
      //{
          vStrBuf_ = new VSTRBUF;

          //내부에서 자동으로 "" 로 초기화. 
          vStrBuf_->Create();

      //}

      //<apiH_List_> 문서 처리를 위한것.
      for(lineStartIndex = 0;
          ;
          //다음행 시작위치 얻기.
          STR_Get_NextLineStartIndex(apiH_List_, lineStartIndex, &lineStartIndex))
      {
        //[<apiH_List_> 에서 행 추출]
        //{
            //[!]{-------------------------------------------
            //추출된 행은 [전체:경로이름확장자] 에 해당한다.
            //}----------------------------------------------

            STR_Get_ThisLineStr(apiH_List_, lineStartIndex, filePathNameExt_);

            //[모두 처리 했나?]
            //{
                //추출한 행문자열 <filePathNameExt> 이 "" 인 경우는 모두 처리한 것으로 보고 종료.
                if(filePathNameExt_[0] == '\0') break;

            //}

        //}

        //[<*.h> 문서 열기]
        //{
            //[!]{-----------------------------------------------------------------------
            //<FILE_Open()> 함수 내부에서 [문서존재] 까지 처리되므로, 이상이 있는 경우는
            //종료하지 말고 다음 문서를 처리.
            //}--------------------------------------------------------------------------

            if(FILE_Open((AnsiString)filePathNameExt_, (unsigned char **)(&fileBuf_), &fileSize) != true) continue;

        //}

        //[<*.h> 문서 처리]
        //{
            //[!]{---------------------------------------------------------------
            //<apiH_List_> 목록에서 추출한 <*.h> 문서를 연 내용을 대상으로 처리.
            //}------------------------------------------------------------------

            for(h_lineStartIndex = 0, defCount = 0, thisLineIsLast = true;
                ;
                //다음행 시작위치 얻기.
                thisLineIsLast = STR_Get_NextLineStartIndex(fileBuf_, h_lineStartIndex, &h_lineStartIndex))
            {
              //[<*.h> 에서 행 추출]
              //{
                  STR_Get_ThisLineStr(fileBuf_, h_lineStartIndex, lineStr_);

                  //[모두 처리 했나?]
                  //{
                      //[주의]{--------------------------------------------------------------------------
                      //[<*.h> 문서] 는 행단위 목록이 아니므로, 모든 처리를 완료했음을 <lineStr_:""> 인
                      //경우로 판단해서는 안된다(행 자체가 NULL 행일수 있으므로).
                      //따라서, <STR_Get_NextLineStartIndex()> 함수로 얻는 <thisLineIsLast> 으로 판단한다.
                      //<thisLineIsLast:false = 현재 행이 마지막 행인것>.
                      //
                      //단, 마지막 행인 경우도 일단 처리는 하고 종료해야 하므로 아래 [종료확인] 부분으로
                      //종료확인후 종료한다(2 군데 사용).
                      //}--------------------------------------------------------------------------------

                      //이 부분에서는 아래 방식으로 종료해서는 안된다.
                      //추출한 행문자열 <lineStr_> 이 "" 인 경우는 모두 처리한 것으로 보고 종료.
                      //if(lineStr_[0] == '\0') break;

                  //}

              //}

              //[첫 단어 추출]
              //{
                  STR_Get_LineWord_withSpace(lineStr_, 0, wordStr_);

              //}

              if     (STR_Match_NoCase(wordStr_, "#define") == true)
              {
                //[!]{----------------------------
                //{ #define [정의이름] } 인 경우.
                //}-------------------------------

                //[정의이름 추출]
                //{
                    STR_Get_LineWord_withSpace(lineStr_, 1, wordStr_);

                //}

                //[종류 기록]
                //{
                    //[2022.06.08.수][추가]
                    kind = '#';

                //}

              }   
              else if(STR_Match_NoCase(wordStr_, "struct") == true)
              { 
                //[2022.06.08.수][추가]{------------------
                //{ struct 구조체이름 { ... }; } 인 경우.
                //}---------------------------------------

                //[구조체이름 추출]
                //{
                    STR_Get_LineWord_withSpace(lineStr_, 1, wordStr_);

                //}

                //[종류 기록]
                //{
                    kind = 's';

                //}

              }
              else if(STR_Match_NoCase(wordStr_, "struct") == true)
              { 
                //[2022.06.08.수][추가]{-----------------
                //{ union 공용체이름 { ... }; } 인 경우.
                //}--------------------------------------
              
                //[공용체이름 추출]
                //{
                    STR_Get_LineWord_withSpace(lineStr_, 1, wordStr_);

                //}

                //[종류 기록]
                //{
                    kind = 'u';

                //}

              }
              else
              {
                //[종료확인:현재 처리한 행이 마지막 행인가?]
                //{
                    //현재 처리한 행이 마지막 행이므로 종료.
                    if(thisLineIsLast == false) break;

                //}

                //해당하지 않는 경우는 0.
                kind = 0;

                continue;

              }

              //[API 이름만 얻기]
              //{
                  STR_GetFileNameOnly_ExceptExt(filePathNameExt_, apiName_);

              //}

              //[<def_file> 에 추가]
              //{
                  //[API 이름 추가]
                  //{
                      //[!]{----------------------------------------
                      //단, 첫 번째 [정의이름] 을 추가할 때만 기록.
                      //}-------------------------------------------

                      if(defCount == 0)
                      {
                        vStrBuf_->Add(apiName_); vStrBuf_->Add("\r\n");
                        vStrBuf_->Add("{\r\n");

                      }

                  //}

                  //[항목 추가]
                  //{
                      //[2022.06.08.수][수정]{---------------------------
                      //'#'(정의이름), 's'(구조체이름), 'u'(공용체이름).
                      //
                      //[형식]-------------------------------------------
                      //
                      //# 정의이름
                      //s 구조체이름
                      //u 공용체이름
                      //}------------------------------------------------

                      //[식별자 추가]
                      //{
                          if     (kind == '#') { vStrBuf_->Add("# "); }
                          else if(kind == 's') { vStrBuf_->Add("s "); }
                          else if(kind == 'u') { vStrBuf_->Add("u "); }

                      //}

                      //[이름 추가]
                      //{
                          vStrBuf_->Add(wordStr_); vStrBuf_->Add("\r\n");

                      //}    

                  //}

              //}

              //추가한 [정의이름] 개수 기록.
              defCount++;

              //[종료확인:현재 처리한 행이 마지막 행인가?]
              //{
                  //현재 처리한 행이 마지막 행이므로 종료.
                  if(thisLineIsLast == false) break;

              //}    

            }

            //[<fileBuf> 삭제]
            //{
                //[!]{--------------------------------------------------------------
                //<FILE_Open()> 내부에서 동적 생성된 <fileBuf> 를 삭제.
                //}-----------------------------------------------------------------

                if(fileBuf_ != NULL) { delete fileBuf_; fileBuf_ = NULL; }

            //}

            //[API 정보 한 개 마무리]
            //{
                //[!]{-------------------------------------------
                //"}" 행을 추가하여 한 개 API 정보 마무리.
                //단, 추가된 [정의이름] 이 존재하는 경우만 처리.
                //}----------------------------------------------

                if(defCount > 0)
                {
                  vStrBuf_->Add("}\r\n");

                  //NULL 행 하나 추가.
                  vStrBuf_->Add("\r\n");

                }

            //}

        //}

      }

      //[<apiH_List_> 삭제]
      //{
          //[!]{--------------------------------------------------------------
          //<API_Get_List_H()> 내부에서 동적 생성된 <API_Get_List_H> 를 삭제.
          //}-----------------------------------------------------------------

          if(apiH_List_ != NULL) { delete apiH_List_; }

      //}

  //}

  //[<def_file> 문서 저장]
  //{
      //[!]{------------------------------
      //<IDE\glib\def_file.glst> 로 저장.
      //}---------------------------------

      //[저장경로 합성]
      //{
          STR_Assign(filePathNameExt_, DB_->programpath);

          STR_Add(filePathNameExt_, "glib\\def_file.glst");

      //}

      FILE_Save((AnsiString)((char *)filePathNameExt_),
                (unsigned char *)vStrBuf_->Get_Str(),
                vStrBuf_->Get_StrLength());

  //}

  //[<def_file> 문서 저장소 삭제]
  //{
      vStrBuf_->Delete();

  //}

  //[VSTRBUF 자체 삭제]
  //{
      //[2022.06.07.화][추가]
      if(vStrBuf_ != NULL) { delete vStrBuf_; } 

  //}

}

//[반환정보]
//0      : <pName> 은 API 에서 사용되는 [이름정의] 가 아님.
//1      : <pName> 은 단 한개의 API 에서 사용되는 [이름정의] 에 해당.
//2 이상 : <pName> 은 다 수의 API 에서 복수적으로 사용되는 [이름정의] 에 해당.
int __fastcall API_DefFile_Check(char   *pName,
                                 //<def_file.glst> 에서 <pName> 과 일치하는 [API 이름] 이
                                 //있는 경우 이 목록(1행 단위 목록)을 반환한다(내부적으로 동적 생성).
                                 char  **rApiList)
{
  //[2022.06.07.화][생성]{--------------------------------------------------------
  //<IDE\glib\def_file.glst> 를 대상으로 <pName> 에 해당하는 [정의이름] 을 가진
  //API 를 찾고 있는 경우(1개나 그 이상일수도 있음) 해당 [API 이름 목록] 을 반환.
  //
  //기계닉스에서 직접 만든 <VSTRBUF> 를 적극적으로 사용한다.
  //
  //[2022.06.08.수][중요수정]*****************************************************
  //[정의이름] 뿐만 아니라, [구조체이름], [공용체이름] 까지 포함하는 것으로 수정.
  //따라서, 내용도 변경됐으므로 이에 맞게 수정.
  //
  //찾는 이름은 [두번째 단어] 에 해당한다.
  //
  //[정보묶음]--------------------------------------------------------------------
  //
  //API_XXX  <---API 순수 이름.
  //{
  //# d_정의이름  <---정의이름만 기록.
  //s 구조체이름  <---struct 구조체이름{ ... }; 으로 선언한 것.
  //u 공용체이름  <---union  공용체이름{ ... }; 으로 선언한 것.
  // ...
  //
  //}
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *DB_;

      //[<def_file.glst> 파일 관련]
      //{
          char   defFile_PathNameExt_[OPT_lineStrSize];

          char  *defFile_Buf_ = NULL;

          int    defFile_Size = 0;

      //}

      int   lineStartIndex;

      char  lineStr_[OPT_lineStrSize];

      char  wordStr_[OPT_lineStrSize];

      char  apiName_[OPT_lineStrSize];

      int   apiCount = 0;

      class VSTRBUF  *vStrBuf_ = NULL;

      bool  thisLineIsLast = true;

      int   itemCount = 0;

      bool  isMatch = false;

  //}

  //[DB 위치 얻기]
  //{
      DATABASE_GetPtr(&DB_);

  //}

  //[<def_file.glst> 경로 합성]
  //{
      //[!]{---------------------------------------------
      //<IDE\glib\def_file.glst> 로 전체경로를 합성한다.
      //}------------------------------------------------

      STR_Add_AB(defFile_PathNameExt_, DB_->programpath, "glib\\def_file.glst");

  //}

  //[<def_file.glst> 문서 열기]
  //{
      //[!]{-----------------------------------------------------------------------
      //<FILE_Open()> 함수 내부에서 [문서존재] 까지 처리되므로, 이상이 있는 경우는
      //종료하지 말고 다음 문서를 처리.
      //}--------------------------------------------------------------------------

      if(FILE_Open((AnsiString)defFile_PathNameExt_, (unsigned char **)(&defFile_Buf_), &defFile_Size) != true) goto lbPostProc;

  //}

  //[<VSTRBUF> 생성]
  //{
      //[!]{------------------------------------------------------
      //<rApiList> 로 반환할 [API 목록] 을 저장할 <VSTRBUF> 생성.
      //}---------------------------------------------------------

      vStrBuf_ = new VSTRBUF;

      //내부에서 자동으로 "" 로 초기화.
      vStrBuf_->Create();

  //}

  //[<def_file.glst> 검색]
  //{
      //[<def_file.glst> 내용]------------------------------------------------
      //[API 이름] 당 묶음으로 규정돼 있으며, 이 묶음의 연속으로 정의돼 있음.
      //
      //API_XXX  <---API 순수 이름.
      //{
      //# d_정의이름  <---정의이름만 기록.
      //s 구조체이름  <---struct 구조체이름{ ... }; 으로 선언한 것.
      //u 공용체이름  <---union  공용체이름{ ... }; 으로 선언한 것.
      // ...
      //
      //}
      //<---NULL 행.
      //
      //}---------------------------------------------------------------------

      for(lineStartIndex = 0, apiCount = 0, thisLineIsLast = true, itemCount = 0, isMatch = false;
          ;
          //다음행 시작위치 얻기.
          thisLineIsLast = STR_Get_NextLineStartIndex(defFile_Buf_, lineStartIndex, &lineStartIndex))
      {
        //[항목 추출]
        //{
            //[!]{---------------------------------------------------------------
            //1행 1항목이므로 추출한 행이 곧 [API 이름] 이나 [정의단어] 가 된다.
            //단, [정보묶음] 을 구분하기 위한 식별자 "{", "}" 항목도 존재.
            //}------------------------------------------------------------------

            STR_Get_ThisLineStr(defFile_Buf_, lineStartIndex, lineStr_);

            //[주의]{----------------------------------------------------------------
            //여기서는 문서 끝 여부를 판별하지 않는다.
            //자세한 내용은 <API_Make_DefFile()> 안의 두번째 <for()> 안의 설명 참고.
            //}----------------------------------------------------------------------

        //}

        if    (itemCount == 0)
        {
          //[!]{---------------------------------------
          //[정보묶음] 의 첫행은 항상 [API 이름] 이다.
          //}------------------------------------------

          //[API 이름] 추출.
          STR_Assign(apiName_, lineStr_);

          itemCount++;

        }
        else if(STR_Match_NoCase(lineStr_, "{") == true)
        {
          //실제 <itemCount : 1> 에 해당하며, [정보묶음] 에서 [정의이름] 시작부를 알려주는 "#{" 에 해당.
          itemCount++;

        }
        else if(STR_Match_NoCase(lineStr_, "}") == true)
        {
          //[정보묶음] 에서 [정의이름] 끝을 알려주는 "#}" 에 해당.
          itemCount++;

        }
        else if(STR_Match_NoCase(lineStr_, "") == true)
        {
          //[!]{------------------------------------------------------------------------------
          //[정보묶음] "#}" 다음 항목인 NULL 행으로, 다음 [정보묶음] 처리를 위한 초기화 수행.
          //}---------------------------------------------------------------------------------

          itemCount = 0;
          
          isMatch   = false;

        }
        else
        {
          //[!]{------------------------------------------------------
          //"{" ... "}" 사이에 있는 [정의이름:목록] 부분에 해당.
          //<pName> 과 일치하는 [정의이름] 을 찾고, 해당 처리를 수행.
          //
          //# d_정의이름  <---정의이름만 기록.
          //s 구조체이름  <---struct 구조체이름{ ... }; 으로 선언한 것.
          //u 공용체이름  <---union  공용체이름{ ... }; 으로 선언한 것.
          //
          //찾는 대상은 [두번째 단어] 가 해당한다.
          //}---------------------------------------------------------

          //[이름 추출]
          //{
              STR_Get_LineWord_withSpace(lineStr_, 1, wordStr_);

          //}

          if(//[정의이름] 은 한개 <*.h> 에서 중복될수 없으므로 일단 찾은 것이 있다면 더이상 검사하지 않는다.
             (isMatch == false) &&
             (STR_Match_NoCase(wordStr_, pName) == true))
          {
            //[!]{--------------------------------------------------------------
            //일치하는 것을 찾았으므로 관련 처리 수행.
            //
            //[참고]{-----------------------------------------------------------
            //한개의 <*.h> 에서 [정의이름] 은 중복 될수 없으므로, 일단 찾았다면
            //이를 표시하고해당 [정보묶음] 에서는 더이상 검사하지 않는다.
            //}-----------------------------------------------------------------

            //일치하는 [정의이름] 을 <API 이름.h> 에 선언한 [API 이름] 을 목록에 추가.
            vStrBuf_->Add(apiName_); vStrBuf_->Add("\r\n");

            //추가한 [API 이름] 개수 기록. 
            apiCount++;

            //이 [정보묶음] 에서 일치하는 것을 찾았음을 표시.
            //더 이상 이 [정보묶음] 을 대상으로 검색하지 않기 위한것.
            isMatch = true;

          }

          itemCount++;

        }

        //[문서 종료 확인]
        //{
            //[!]{----------------------------------------------------------
            //현재 처리한 행이 마지막 행이라면 종료.
            //<STR_Get_NextLineStartIndex()> 의 반환값이 <false> 인 경우는
            //이 함수가 지정한 행이 마지막 행이라는 것이므로 이를 활용한것.
            //}-------------------------------------------------------------

            if(thisLineIsLast == false) break;

        //}

      }

  //}

  lbPostProc: //후처리.

  //[찾은 API 목록 반환]
  //{
      //[!]{---------------------------------------------------------------------
      //<pName> 을 <API 이름.h> 에 [정의이름] 으로 가진 [API 이름 목록] 을 반환.
      //}------------------------------------------------------------------------

      if(rApiList != NULL)
      {
        //[저장소 생성]
        //{
            //'\0' 까지 저장------------------------------------------------v
            (*rApiList) = new char[UnitX(1024, vStrBuf_->Get_StrLength()) + 1];

        //}

        //[목록 전달]
        //{
            STR_Assign((*rApiList), vStrBuf_->Get_Str());

        //}

      }  

  //}

  //[<def_file.glst> 저장소 삭제]
  //{
      //[!]{-----------------------------------------------------------------------
      //<FILE_Open()> 내부에서 자동 생성되므로 여기서 사용후 반드시 삭제해야 한다.
      //}--------------------------------------------------------------------------

      if(defFile_Buf_ != NULL) { delete defFile_Buf_; defFile_Buf_ = NULL; }

  //}

  //[<vStrBuf_> 삭제]
  //{
      if(vStrBuf_ != NULL)
      {
        vStrBuf_->Delete();

        delete vStrBuf_; vStrBuf_ = NULL;

      }

  //}

  //[찾은 API 개수 반환]
  //{
      return(apiCount);

  //}
  
}

void __fastcall API_Test(void)
{
  /*
  //[VAR]
  //{
      char  *apiList_ = NULL;

      int    apiCount;



  //}

  apiCount = API_DefFile_Check("d_폴더", &apiList_);

  ShowMessage("[ " + (AnsiString)apiCount + " ] 개를 찾았음\r\n\r\n" + (AnsiString)apiList_);

  if(apiList_ != NULL) delete apiList_;
  */

  //API_Make_DefFile();

  /*
  //[VAR]
  //{
      char  *apiH_List_ = NULL;

      int    strSize;

  //}

  strSize = API_Get_List_H(&apiH_List_);

  FILE_Save("C:\\Users\\AMD\\Downloads\\API_H 목록.gtxt",
            (unsigned char *)apiH_List_,
            strSize);

  if(apiH_List_ != NULL) { delete apiH_List_; }

  return;
  */
  /*
  //[VAR]
  //{
      struct  TREE   *tree;

      int             itemIndex;

  //}

  tree = &(tree_tree_Form->_tree[d_TREE_api]);

  tree_tree_Form->_Tree_Get_ItemIndex_withText(tree,
                                               //검사할 <text> 항목.
                                               "_Ide_Vmos_정지_.glib",
                                               //<text> 를 가진 itemindex.
                                               &itemIndex);

  ShowMessage(itemIndex);
  */

  /*
  API_Add_To_Project("_GPrintBox_모서리배경색_");

  API_Add_To_Project("_DS1620_온도");

  API_Add_To_Project("_MCP3008_생성");

  tree_tree_Form->_TreeView(d_TREE_project, false);
  */

  /*
  if(API_Check("_Str_행문자열일치_행번호얻기_") == true)
  {
    ShowMessage("API 에 해당함.");

  }
  else
  {
    ShowMessage("API 아님.");

  }
  */

  /*
  //[VAR]
  //{
      char  *apiList_ = NULL;

      int    strSize;

  //}

  strSize = API_Get_List(&apiList_);

  FILE_Save("C:\\Users\\AMD\\Downloads\\API 목록.gtxt",
            (unsigned char *)apiList_,
            strSize);

  if(apiList_ != NULL) { delete apiList_; }

  return;
  */


}

//******************************************************************************
//[정보창:API 검색 관련]********************************************************
//******************************************************************************

void __fastcall Ide_Tree_ApiSrch_Item_Add(struct TREE  *pTreeSrc_,
                                          struct TREE  *pTreeDst_,
                                          int           pSrcItemIndex,
                                          //[형식적용문자열] 지원을 위한 부가 정보.
                                          int           pInfo1, //[형식적용문자열] 을 적용할 시작위치.
                                          int           pInfo2) //[형식적용문자열] 을 적용할 끝위치.
{
  //[2022.06.20.월][생성]{--------------------------------------------------------------------------
  //<_Tree_Item_Copy()> 와 동일하나 [검색문자열] 과 일치하는 <txt> 에 [형식적용문자열] 을 지원하기 위하여
  //<info[1:2]> 에 이를 위한 정보를 추가한다.
  //
  //이는 <d_TREE_find> 에 [찾기문자열] 에 해당하는 부분이 [형식적용문자열] 로 출력된 것과 유사한 방식이며
  //<Tree:API 검색> 에서 [검색] 결과를 출력시 동일하게, <txt> 출력시 [검색문자열] 에 해당하는 부분을 [형식적용문자열] 로
  //출력해 주기 위한 것이다.
  //
  //단, <d_TREE_find> 는 <info[1:3]> 의 3 개를 사용하지만, 여기서는 <info[1:2]> 의 2 개만 사용하며,
  //[형식적용문자열] 이 적용되는 구간은 [검색문자열] 과 겹치는 문자열 구간이 해당된다.
  //이 구간 정보는 이 함수를 호출한 곳에서 계산후 인수로 전달한다.
  //
  //<info1> : [형식적용문자열] 을 적용할 <txt> 상의 시작위치.
  //<info2> : [형식적용문자열] 을 적용할 <txt> 상의 끝위치.
  //
  //이 정보 <info[1:2]> 는 <_Tree()> 함수에서 그릴때 <Tree:API 검색> 인 경우 자동 반영되며, <glib> 항목에서만 유효하다.
  //[항목] 은 <kind:'.'> 로 판별.

  //[설명]------------------------------------------------------------------------------------------
  //<pTreeSrc> => <pTreeDst> 로 <pTreeSrc:pTreeSrcIndex> 항목을 복사한다.
  //단, 항목의 Tree 구조((ex)... 옹이->옹이->항목)까지 그대로 복사한다.
  //
  //[중요/주의]***********************************************************
  //[복사] 의 경우 <txt> 는 각각의 [Tree:_strHeap] 에서 <STRHEAP> 으로
  //관리되므로 별도 처리로 복사해야 한다.
  //
  //[참고]****************************************************************
  //"root" 의 경우는 <name> 이 동일하므로 복사되지 않는다.
  //"API", "API 검색" 으로 각각의 제목이 그대로 유지 되어야 한다.
  //이 <name> 중복 검사는 복사를 수행하는 <_Tree_Add_Item_CheckName()> 가
  //내부적으로 자동 처리한다.
  //}---------------------------------------------------------------------

  //[VAR]
  //{
      struct TREEITEM   item;

      int  itemIndex;

      int  nodeIndex;

  //}

  //[현재 항목의 옹이가 존재하나?]
  //{
      //상위 [옹이] 찾기.
      tree_tree_Form->_Tree_Get_NodeIndex_of_ThisItem(pTreeSrc_, pSrcItemIndex, &nodeIndex);

      if(nodeIndex >= 0)
      {
        //현재 nodeIndex 는 다음 검사할 [항목] 이 된다.
        itemIndex = nodeIndex;

        //[재귀호출]
        //{
            //같은 계통의 처리이므로 이 함수를 재귀호출해서 처리한다.
            Ide_Tree_ApiSrch_Item_Add(pTreeSrc_, pTreeDst_, itemIndex, pInfo1, pInfo2);

        //}

      }
      else
      {
        //이 경우는 현재 항목을 복사한다.
        goto  lbItemCopy;

      }

  //}

  lbItemCopy:

  //[항목 추가 예외 확인]
  //{
      //[!]{--------------------------------------------------------------------------
      //<nodeIndex == -1> 인 경우는 현재 항목이 <root> 인 경우이므로 추가하지 않는다.
      //이는 <root> 는 [제목] 이 되므로 이 제목을 변경해서는 안된다.
      //}-----------------------------------------------------------------------------

      if(nodeIndex < 0) return;

  //}

  //[항목 원본 추출]
  //{
      item = pTreeSrc_->items[pSrcItemIndex];

  //}

  //[중복검사]
  //{
      //<name> 을 사용하여 중복 검사 수행.
      tree_tree_Form->_Tree_Get_ItemIndex_withNAME(pTreeDst_, item.name, &itemIndex);

      //중복되는 경우는 추가하지 않고 종료.
      if(itemIndex >= 0) return;

  //}

  //[항목 수정 및 정보 추가]
  //{
      //[<kind> 설정]
      //{
          //[2022.06.23.목][중요추가]{********************************************************************
          //[옹이] 의 경우라도 기본적으로는 [항목] 으로 추가된다.
          //[항목] 에 하위 항목이 등록되면서 <_Tree_Add_NodeItem()> 에서 [옹이] 로 자동 설정된다.
          //따라서, 복사 원본이 "[+], [-]" 인 [옹이] 라도 여기서는 무조건 [항목] 으로 강제 설정해야 한다.
          //}*********************************************************************************************

          item.kind = '.';

      //}

      //[<txt> 추가]
      //{
          //[주의]{---------------------------------------------------------------------------
          //<txt> 는 <STRHEAP> 을 사용하여 <index> 형태로 관리되므로 반드시 전용 함수로 처리.
          //}---------------------------------------------------------------------------------

          //기본적으로 원본 정보를 초기화.
          item.txt = -1;

          tree_tree_Form->_Item_Txt(pTreeDst_,
                                    &item,
                                    tree_tree_Form->_Item_Txt_StrPtr3(pTreeSrc_, pSrcItemIndex));

      //}

      //[<lastItem> 초기화]
      //{
          //[!]{---------------------------------------------------------------------------------------------------------
          //[원본] 에서는 [끝 항목] 일수 있으나 [대상] 에서는 아닐수 있으므로 여기서 반드시 <false> 로 초기화 해야 한다.
          //초기화 하지 않는 경우는 <_Tree()> 로 그릴때 메모리 오류 등 치명적 오류가 발생할수 있다.
          //}------------------------------------------------------------------------------------------------------------

          item.lastItem = false;

      //}

      //[<info[1:2] 정보 추가]
      //{
          //[!]{-----------------------------------------------------------------------------------
          //이 정보는 <txt> 를 [형식적용문자열] 로 출력할때 사용되며, [항목<glib>] 의 경우만 유효.
          //[항목/옹이] 구분없이 일단 값을 기록한다.
          //<tree_tree_Form->_Tree()> 에서 [항목] 의 경우만 [형식적용문자열] 로 자동 적용되므로.
          //}--------------------------------------------------------------------------------------

          item.info1 = pInfo1;

          item.info2 = pInfo2;

      //}

  //}

  //[항목 추가]
  //{
      tree_tree_Form->_Tree_Add_NodeItem(pTreeDst_,
                                         pTreeSrc_->items[nodeIndex].name,
                                         &item,
                                         NULL);

  //}

}

void __fastcall Ide_Tree_ApiSrch_Search(//[2022.06.21.화][추가]
                                        //[한줄편집기] 전체 문자열을 사용하는 경우는 <true>.
                                        //[입력지정자] 까지의 문자열을 사용하는 경우는 <false>.  
                                        bool  pFullStrUse)
{
  //[2022.06.20.월][생성]{----------------------------------------------------------
  //<ide_tree_Form->_findEdit> 의 문자열을 <txt> 로 가지는 항목을 <Tree:API> 에서
  //찾아서, <Tree:API 검색> 으로 전부 복사한다.
  //
  //<ide_tree_Form->_findEdit> 의 문자열과 완전히 일치하는 <txt> 를 가진 항목은
  //<Tree:API 검색> 에서 [선택항목] 으로 지정해 주고, 항상 보이는 영역의 중간에
  //위치하도록 처리한다.
  //
  //[2022.06.21.화][중요수정]-------------------------------------------------------
  //<pFullStrUse> 에 따라 [전체문자열] 이나 [입력지정자까지의 문자열] 을 선택 사용.
  //이는 [입력지정자] 가 이동하는 경우도 [편집기:실시간선언정보판] 처럼 실시간으로
  //검색 후 결과를 전시하기 위한 것.
  //}-------------------------------------------------------------------------------

  //[VAR]
  //{
      struct TREE  *treeApi_;
      struct TREE  *treeApiSrch_;

      //검색대상 문자열(한줄편집기 표준인 1024 로 크기 설정).
      char  srchStr_[1024];
      char  tempStr_[1024];

      //찾은 위치.
      int    findIndex;

      int    i;

  //}

  //[치환]
  //{
      //[!]{----------------------------
      //표기를 단순화 하기 위하여 치환.
      //}-------------------------------

      treeApi_     = &(tree_tree_Form->_tree[d_TREE_api]);

      treeApiSrch_ = &(tree_tree_Form->_tree[d_TREE_apiSrch]);

  //}

  //[검색 문자열 선택]
  //{
      //[2022.06.21.화][수정]{-------------------------------------------------------
      //<pFullStrUse> 에 따라 [전체문자열/입력지정자까지의 문자열] 중 선택 적용한다.
      //}----------------------------------------------------------------------------

      if(pFullStrUse == true)
      {
        //[!]{--------------------------------
        //[한줄편집기] 의 문자열 전체를 사용.
        //}-----------------------------------

        STR_Assign(tempStr_, ide_tree_Form->_findEdit->_editbuf);

      }
      else
      {
        //[!]{------------------------------------
        //[입력지정자] 까지의 부분 문자열을 사용.
        //}---------------------------------------

        //일단 전체 문자열을 복사.
        STR_Assign(tempStr_, ide_tree_Form->_findEdit->_editbuf);

        //[입력지정자] 위치에 '\0' 을 끼워 넣어 문자열로 완성.
        tempStr_[ide_tree_Form->_findEdit->_caretindex] = '\0';

      }

  //}

  //[문자열 앞뒤 공백 제거]
  //{
      //[2022.06.23.목][추가]
      Str_Trim(tempStr_,
               //앞 공백 제거 유무.
               true,
               //뒤 공백 제거 유무.
               true,
               //정리된 문자열.
               srchStr_);

  //}

  //[검색할 문자열이 존재하나?]
  //{
      //[2022.06.23.목][수정]{----------------------------------
      //"" 이나 "      " 등 공백만 있는 경우는 처리하지 않는다.
      //}-------------------------------------------------------

      if(srchStr_[0] == '\0')
      {
        //찾을 문자열이 없다면 내용을 완전히 초기화 해야 한다.
        ide_tree_Form->_Tree_All_Init(d_Tree_ApiSrch,
                                      //초기화 후 바로 종료하므로 [다시 그리기] 한다.
                                      true);

        return;

      }

  //}

  //[<Tree:API 검색> 초기화]
  //{
      ide_tree_Form->_Tree_All_Init(d_Tree_ApiSrch,
                                    //[다시 그리기] 는 하지 않는다.
                                    false);

  //}

  //[검색/복사]
  //{
      //[방법]{*****************************************************************************
      //1) <Tree:API> 에서 <_findEdit> 의 문자열을 포함하고 있는 <txt> 를 가진 항목을 찾기.
      //   단, <glib> 에 해당하는 항목(kind:'.')만 검사해야 한다.
      //
      //2) 1) 의 찾은 항목을 <Tree:API 검색> 에 복사.
      //
      //3) 더이상 찾는 것이 없을때 까지 1) - 2) 반복.
      //}***********************************************************************************

      for(i = 0; i < treeApi_->items_count; i++)
      {
        //[<glib> 인가?]
        //{
            //[!]{--------------------------------------------------------------------
            //<glib> 에 해당하는 항목만 처리한다.
            //<Tree:API> 는 <glib> 항목의 경우는 [항목.kind:'.'] 으로 설정돼 있으므로
            //이 <kind> 로 구분한다.
            //간단하게 아래와 같이 사용해도 무방.
            //if(treeApi_->items[i].bmpindex != d_ITEMBMP_api) continue;
            //}-----------------------------------------------------------------------

            if(treeApi_->items[i].kind != '.') continue;

        //}

        //[<txt> 를 대상으로 검색]
        //{
            //[2022.06.22.수][수정]{--------------------------------------------------
            //모든 항목은 "xxx.glib" 로 돼 있으므로, 순수 이름 부분반 비교하기 위하여
            //<STR_Find()> 에 문자열 길이부분을 [문자열길이 - 5(".glib" 길이)] 주어
            //".glib" 전까지만 비교하도록 한다.
            //}-----------------------------------------------------------------------

            STR_Find(//검사할 [저장소].
                     tree_tree_Form->_Item_Txt_StrPtr3(treeApi_, i),
                     //".glib" 이전까지를 문자열로 인식시킨다.
                     STR_Length(tree_tree_Form->_Item_Txt_StrPtr3(treeApi_, i)) - 5,
                     //[찾기조건]{-----------------
                     //찾기 시작 위치.
                     0,
                     //[단어] 구분 없이 검색.
                     false,
                     //[대/소문자] 구분 없이 검색.
                     false,
                     //}---------------------------
                     //찾을 문자열.
                     srchStr_,
                     //찾은 위치(찾지 못한 경우는 -1 을 반환).
                     &findIndex);

            //찾지 못한 경우는 계속 다음 처리.
            if(findIndex < 0) continue;

            //여기까지 온것은 찾은것.

        //}

        //[복사]
        //{
            //[!]{-------------------------------------------------
            //찾은 항목을 <Tree:API> => <Tree:API 검색> 으로 복사.
            //}----------------------------------------------------

            Ide_Tree_ApiSrch_Item_Add(treeApi_, treeApiSrch_, i, findIndex,
                                      //[2022.06.23.목][중요수정]
                                      //반드시 앞에 <findIndex> 를 더한다.
                                      //끝위치는 <findIndex> 에 대한 추가위치 이므로.
                                      findIndex + STR_Length(srchStr_));

        //}

      }

  //}

  //[전부 펼치기]
  //{
      //찾은 목록을 한눈에 볼수 있도록 전부 펼친다.

      tree_tree_Form->_Tree_ExpandAll(d_TREE_apiSrch,
                                      //[다시 그리기] 한다.
                                      true);
      
  //}

}

void __fastcall Ide_Tree_ApiSrch_Test(void)
{
  //[Tree:API] 에서 지정 [문자열] 을 포함하는 <TXT> 를 가진 모든 항목을 찾아서
  //[Tree:API 검색] 에 출력하는 함수.

  //[VAR]
  //{
      int  i;

  //}

  for(i = 0; i < 1106; i++)
  {
    Ide_Tree_ApiSrch_Item_Add(&(tree_tree_Form->_tree[d_TREE_api]),
                              &(tree_tree_Form->_tree[d_TREE_apiSrch]),
                              i,
                              -1,
                              -1);

  }

  tree_tree_Form->_Tree_ExpandAll(d_TREE_apiSrch, true);


  //ShowMessage(tree_tree_Form->_tree[d_TREE_api].items_count);

  /*
  //***************************************************************************
  //<select_itemindex> 로 행을 얻어 이 행을 보이는 가장 [첫 행] 에 위치시킨다.
  //<지정행> 을 인수로 이 기능을 하는 전용 함수 제작 필요.
  //***************************************************************************

  //[VAR]
  //{
      struct  TREE  *tree_;

      Tgui_scroll_v_Form  *scrollV;

      bool  scrolled = false;

  //}

  //[Tree 치환]------------------------
  //현재 보여지는 [Tree] 얻기.
  tree_ = &(tree_tree_Form->_tree[d_TREE_api]);
  //}----------------------------------

  //[줄이동자 치환]{--------------------------------------------
  scrollV = ide_tree_Form->_scroll_v_Form;
  //}-----------------------------------------------------------

  tree_->select_itemindex = 100;

  tree_tree_Form->_Get_LineNumber_withItemIndex(tree_,
                                                tree_->select_itemindex,
                                                &(tree_->select_line));



  scrollV->_Position(tree_->select_line);

  return;

  */

  /*

  tree_tree_Form->_tree_select_index = d_TREE_api;

  scrolled =  tree_tree_Form->_Tree_SelItem_ViewPos(false, false);

  if(scrolled != true)
  {
    tree_tree_Form->_TreeView(d_TREE_api, false);

  }
  */


  /*

  tree_tree_Form->_tree_select_index = d_TREE_apiSrch;

  ide_tree_Form->_scroll_v_Form->_position= tree_tree_Form->_tree[tree_tree_Form->_tree_select_index].scroll_position;

  //다시 그려서 보이기------------------------------------------------v
  tree_tree_Form->_V_Scroll(ide_tree_Form->_scroll_v_Form->_position, true);
  */

}














































