
//[2009.01.20.화][생성!!!]{-------------------------------------------------
//*.ob1 문서를 번역하여 *.obj 문서를 만들어 준다.
//이 문서는 *.obj 로 만들기 위한 전단계의 모든 [지역라벨] 이 해당 [asm기호]
//로 치환되어 있는 상태로, 그대로 code 로 번역하면 바로 *.obj 가 된다.
//즉, *.obj 를 보다 간단하게 번역하기 위하여 임시로 만드는 문서가 된다.
//
//[2012.06.30.토][중요수정!!!]**********************************************
//[가상기계(GVMX/GVMX)] 크기를 최대한 작게 하기 위하여 [미사용 함수] 는
//<Link()> 단계에서 [합성하지 않는] 방식으로 모두 제거한다.
//
//이는 같은 [함수묶음] 인 경우라도 이 안에서 사용된 함수만 합성한다.
//}-------------------------------------------------------------------------


#include <vcl.h>
#pragma hdrstop


//[사용 header file]
//{
    #include "c_define.h"
    #include "ide_library.h"
    #include "library.h"
    #include "file.h"
    #include "database.h"
    #include "parser.h"
    //#include "asmencoder.h"
    //#include "object1st.h"
    #include "object.h"
    #include "link.h"
    #include "debug_file.h"

    #include "ide_msgbox.h"
    #include "msg_msg.h"

    //[설계묶음] 에 접근하기 위한것.
    #include "tree_tree.h"

    //[2011.04.29.금][추가!!!]
    #include "buildStatus.h"

//}


bool __fastcall Link(char  rSaveFileName[])
{
  //[2009.02.07.토][생성!!!]{--------------------------------------------------------------
  //<*.gobj> 를 읽어서 <*.glnk> 을 만들어 준다.
  //
  //[함수라벨]
  //
  // - _CODE_:BASE 로한 [추가주소] 를 확정해 주어야 한다.
  // - 사용된 부분에 해당 code(little Endian) 로 변환하여 치환한다.
  //
  //[기타]
  //
  // - 최종적으로 <*.glnk> 문서를 합성하여 <*.gvmx> 의 [binary 문서] 실행기계를 만든다.
  //
  //[2011.05.09.월][중요수정!!!]-----------------------------------------------------------
  //[Tree:함수묶음] 의 구조가 [경로] 방식에서 [Tree 구조] 로 변경되었으므로 [함수묶음]
  //처리부를 다 수정해 주어야 한다.
  //
  //[2012.04.28.토][중요수정!!!]-----------------------------------------------------------
  //동적 [생성] 개체의 [삭제] 처리 빠진것 추가.
  //
  //[2012.07.02.월][중요수정!!!]***********************************************************
  //<Link()> 시 [크기:최적화] 관련 수정있음.
  //
  //<*.gobj>, <*.glib> 를 [합성] 시 [미사용 함수:본체] 를 제거하는 방법으로 [크기:최적화].
  //
  //사용된 함수는 { 2d(fncall) :함수라벨: } 로 [호출된 함수] 가 해당.
  //
  //[함수묶음] 인 <*.glib> 안에 여러개의 함수가 있어도 이중에서 [사용된 함수] 만 결합된다.
  //
  //[설계묶음] 안에 [함수묶음] 등이 이 다수 추가된 상황에서도 일일히 정리할 필요가 없다.
  //자동적으로 [사용된 함수] 만 합성되어 언제나 [꼭 필요한 것만 들어있는] 상태가 된다.
  //
  //맷돌(G.MTDL.X) 의 경우 ROM 을 최소한만 사용하게 되어 매우 유용.
  //
  //[검증시] 에 [크기:최적화] 가 전혀 영향을 주지 않음을 확인하였다.
  //
  //[주의!!!]******************************************************************************
  //<main()>, <event()> 함수는 본체가 존재하면서 [사용되지 않는 함수] 이기는 하나 반드시
  //존재해야 하는 것이므로 어떤 경우라도 [항상 추가] 되어야 한다.
  //이 두 함수는 [미사용함수] 에서 처리 예외가 된다.
  //
  //[부가정보 처리]************************************************************************
  //
  //1) [이동주소(VECTOR)]
  //
  //   "#VECT :main: "
  //   "#VECT :event: "
  //
  //   그대로 복사.
  //
  //2) [문서정보]
  //
  //   "#main.c "
  //
  //   <Link()> 도중에 [함수] 가 어떤 문서에 존재하는지 기록하기 위하여 참고하는
  //   것으로 실제 복사되지 않는다.
  //
  //실제 최적화를 수행하는 <Link_Delete_UnUseFunction()> 함수에서 자동 처리.
  //}--------------------------------------------------------------------------------------

  //[방법]{----------------------------------------------------------------------
  //
  // 1) 함성할 <*.gobj> 와 <*.glib> 의 총 문서의 크기를 얻는다.
  //
  // 2) 총 크기를 기준으로 <*.glnk> 를 저장할 [저장소] 를 동적 생성한다.
  //
  // 3) [설계묶음] 에 위치한 문서순서대로 <*.gobj> 를 [저장소] 에 추가한다.
  //
  // 4) [설계묶음] 에 포함된 순서대로 <*.glib> 를 [저장소] 체 추가한다.
  //
  // 5) [저장소] 의 완전히 함성된 문서를 기준으로 [함수라벨] 의 위치를 확정한다.
  //
  // 6) [함수라벨] 이 사용된 곳을 [함수라벨] 의 [code] 로 치환한다.
  //
  // 7) <*.glnk> 문서로 저장한다.
  //
  // 8) <*.glnk> -> <*.gvmx> 의 binary 문서로 최종 생성한다.
  //
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *database;
      int    result = 0;

      //처리에 필요한 정보 구조체는 한개만 생성하면 된다.
      struct LINKINFO  linkInfo;

      //부가 정보를 관리한다.
      //수집 라벨 등 수많은 정보를 관리 하므로 용량이 크므로 별도로 관리 되어야 한다.
      struct LINKINFOETC  linkInfoEtc;

      char   fileName[OPT_filepath_length];
      char   fileNameOnly[OPT_filepath_length];
      char   tempStr[OPT_lineStrSize];

      int    fileSize      = 0;
      int    fileTotalSize = 0;

      //[합성] 한 [Object] 전체를 저장한다.
      char  *objBuf = NULL;

      //[<설계묶음> 관련]
      //{
          struct  TREE   *tree;

          int     nodeIndex;
          int     nodeItemCount;

      //}

      int  i;

      //처리한 문서수.
      int  cnt;

      //지정 문서의 [라벨] 총 수를 가진다.
      int  labelTotalCount;

      //[2011.05.09.월][추가!!!]
      int  nodeLastItemIndex;

      //[2011.05.22.일][추가!!!]
      //<*.gobj>, <*.glib> 의 합성할 총 문서수를 가진다.
      int  totalDocCount;

  //}

  //[DATABASE 위치 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

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

  //}

  //[설계묶음 문서 총크기 얻기]
  //{
      //[!]{---------------------------------------------------------------------
      //[설계묶음] 을 처리하여 나온 모든 <*.gobj> 와 등록된 모든 <*.glib> 문서의
      //총 크기를 구해준다.
      //이는 이 문서 모두를 합성하여 저장할 [저장소] 를 생성하기 위한 것이다.
      //}------------------------------------------------------------------------

      //<*.gobj>  와 <*.glib> 문서의 전체 크기를 얻는다.
      //[2011.05.22.일][수정!!!]
      //처리할 <*.gobj>, <*.glib> 문서의 총 수를 같이 얻는다.
      totalDocCount = Link_Get_ObjectFileTotalSize(&fileTotalSize);

  //}

  //[합성 문자열 저장소 생성]
  //{
      //[합성] 할 [문자열] 저장소를 생성한다.
      //실제 처리 대상이 된다.
      //[이동주소목록(event vector)] 을 추가 해야 하므로 약간 여유있게 생성해 준다.
      /*objBuf =  new char [fileTotalSize + 1024 +
                          //[2011.05.23.월][추가!!!]{-----------------------------------------
                          //추가되는 <#문서경로> 정보를 위하여 [설계묶음 내부 경로] 의 길이를
                          //문서당 256 바이트로 가정하고 문서수에 맞게 크기를 추가한다.
                          totalDocCount*OPT_pathInGprj_length];
                          //}-----------------------------------------------------------------
      */

      //[동적생성단위적용][2021.01.24.일][수정]
      objBuf =  new char [UnitX(1024, fileTotalSize + 1024 +
                                      //[2011.05.23.월][추가!!!]{-----------------------------------------
                                      //추가되는 <#문서경로> 정보를 위하여 [설계묶음 내부 경로] 의 길이를
                                      //문서당 256 바이트로 가정하고 문서수에 맞게 크기를 추가한다.
                                      totalDocCount*OPT_pathInGprj_length)];
                                      //}-----------------------------------------------------------------

  //}

  //[tempfile][<*.glnk> 저장소 생성]
  //{
      //[tempfile 저장소 생성]
      //{
          //<*.glnk> 문서는 처리할 모든 [Object 문서] 크기 합보다 2 배 정도 크게 잡는다.
          //이미 위에서 구한 값이다.
          TEMPFILE_Create(fileTotalSize * OPT_LnkFile_SizeFactor);

      //}

      //[<*.glnk> 문서 이름 만들기]
      //{
          //[!]{---------------------------------------------------------------
          //저장할 <*.glnk> 문서 이름을 미리 만들어 놓는다.
          //[설계묶음] 의 이름을 그대로 사용하고 경로는 [build] 안이어야 한다.
          //}------------------------------------------------------------------

          //[문서 경로 합성]
          //{
              STR_Assign(tempStr, database->buildpath);

              //[설계묶음] 의 이름은 현재 [Tree] 의 <root>.text 가 된다.
              //[2012.04.20.금][수정!!!]
              STR_Add(tempStr, tree_tree_Form->_Item_Txt_StrPtr3(tree, 0));

              //확장자를 <*.glnk> 로 바꿔준다.
              STR_ChangeFileExt(tempStr, "glnk", fileName);

          //}

          //이미 만들어 진 확장자 이지만 함수 형식상 다시 만들어 준다.
          TEMPFILE_MakeFileName(fileName, "glnk");

      //}

      //[<*.glnk> 문서이름 반환]
      //{
          //[2009.02.11.수][추가!!!]{------------------------------------------------
          //다음 처리를 위하여 지금 결과를 저장하는 <*.glnk> 문서의 경로를 반환한다.
          //}------------------------------------------------------------------------

          if(rSaveFileName != NULL) { STR_Assign(rSaveFileName, fileName); }

      //}

  //}

  //[초기화]
  //{
      //이전에 값이 저장되 있으므로 다시 초기화 한다.
      //이것은 저장을 위한 [저장소] 의 위치를 얻는데 중요한 정보가 된다.
      fileTotalSize = 0;

  //}

  //[VECT 추가하기]
  //{
      //[2009.02.08.일][추가!!!]{---------------------------------------------
      //[함성] 을 하기 전에 먼저 [저장소] 앞에 [이동주소목록] 을 추가해 준다.
      //나중에 다른 종류가 더 추가 될수도 있으나 현재는 2 개만 존재한다.
      //
      // "#VECT :main: "    -> reset vector
      // "#VECT :event: "   -> event vector
      //
      //로 2 행의 고정 표현을 기술한다.
      //이곳에는 각각 8byte 크기의 해당 함수라벨의 _CODE_:BASE 의 [추가주소]
      //값이 <LittleEndian> 으로 치환된다.
      //이 경우 "#VECT" 기호를 참고하면 간단하게 처리 할수 있다.
      //}---------------------------------------------------------------------

      STR_Assign(objBuf, "");
      STR_Add(objBuf, "#VECT :main: \r\n");
      STR_Add(objBuf, "#VECT :event: \r\n");

      //현재 추가한 [문자열] 의 길이를 추가해 준다.
      //다음 [문자열] 은 이 다음부터 이어지게 된다.
      fileTotalSize += STR_Length("#VECT :main: \r\n#VECT :event: \r\n");

  //}

  //[문서 합성]
  //{
      //[!]{--------------------------------------------------------------------------
      //<*.gobj> 와 <*.glib> 를 [설계묶음] 에 등록된 순서대로 한개의 문서로 합성한다.
      //하나씩 문서를 열어서 이미 만들어져 있는 [저장소] 에 차례로 추가해 준다.
      //}-----------------------------------------------------------------------------

      //[<설계문서> 처리]
      //{
          //[!]{----------------------------------------------------------------
          //[설계문서] 순서대로 [build] 폴더안의 <*.gobj> 문서를 열어 합성한다.
          //}-------------------------------------------------------------------

          //[<설계문서> [옹이] 정보얻기]
          //{
              tree_tree_Form->_Tree_Get_Node_ItemCount(tree, "c", &nodeIndex, &nodeItemCount);

          //}

          for(i = 0, cnt = 0; cnt < nodeItemCount; i++)
          {
            //[문서 경로 합성]
            //{
                //[!]{-------------------------------------------------------------
                //전체 [문서 경로] 를 만들어 준다.
                //단, <*.gobj> 문서를 열어야 하므로 [build] 폴더 경로를 추가 한다.
                //}----------------------------------------------------------------

                //[직계가지 인가?]
                //{
                    //[!]{-----------------------------------------------------
                    //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
                    //이는 [옹이] 의 [직계가지] 에만 해당한다.
                    //}--------------------------------------------------------

                    //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
                    if((tree->items[nodeIndex].level + 1) != tree->items[i + (nodeIndex + 1)].level) continue;

                //}

                STR_Assign(tempStr, database->buildpath);

                //[순수 이름만 추출]
                //{
                    //[!]{---------------------------------------------------------------------------------
                    //실제 대상이 되는 모든 문서는 전부 [build] 에 있으므로 순수한 문서이름만 있으면 된다.
                    //}------------------------------------------------------------------------------------

                    //[2012.04.20.금][수정!!!]
                    STR_GetFileNameOnly(tree_tree_Form->_Item_Txt_StrPtr3(tree, i + (nodeIndex + 1)), fileNameOnly);

                    STR_Add(tempStr, fileNameOnly);

                //}

                //확장자를 <*.gobj> 로 바꿔준다.
                STR_ChangeFileExt(tempStr, "gobj", fileName);

            //}

            //[문서이름 넣기]
            //{
                //[2011.05.23.월][추가!!!]{--------------------------------------------------------
                //{ #[설계묶음안문서경로] } 행을 해당 문서를 추가하기전 추가한다.
                //이는 [함수라벨] 이 어떤 문서에 속하는지 쉽게 알기 위한 것이다.
                //일반 <*.c> 가 있는 [함수라벨] 은 해당 <*.$> 안에 이미 정보가 있으나,
                //[함수묶음] 안의 [함수라벨] 은 이 [문서] 정보를 알수가 없다.
                //따라서, [LINK] 시에 [함수라벨] 의 정보를 수집하면서 쉽게 어떤 문서 안의 함수인지
                //알수 있게 만들어 주기 위한 것이다.
                //
                // #[함수묶음내문서경로]
                //
                //로 한개행을 차지하게 만든다.
                //}--------------------------------------------------------------------------------

                fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), "#");
                //[2012.04.20.금][수정!!!]
                fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), tree_tree_Form->_Item_Txt_StrPtr3(tree, i + (nodeIndex + 1)));

                fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), "\r\n");

            //}

            //[문서열기]
            //{
                FILE_Open_inBUF(fileName,
                                &(objBuf[fileTotalSize]),
                                &fileSize);

                //현재 fileSize 는 '\0' 까지 포함한 크기를 가지므로,
                //이 위치는 빼 주어야 한다.
                fileTotalSize += (fileSize - 1);

            //}

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

            //}

          }

      //}

      //[<함수묶음> 처리]
      //{
          //[!]{----------------------------------------------------------------
          //[함수묶음] 순서대로 <*.glib> 문서를 열어 합성한다.
          //
          //[2011.05.09.월][중요수정!!!]----------------------------------------
          //[Tree:함수묶음] 의 구조가 [경로] 에서 [Tree 구조] 로 변경되었으므로
          //전부 다시 고친다.
          //}-------------------------------------------------------------------

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

          //}

          //[문서 합성]
          //{
              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;

                //}

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

                //}

                //[문서이름 넣기]
                //{
                    //[2011.05.23.월][추가!!!]{--------------------------------------------------------
                    //{ #[설계묶음안문서경로] } 행을 해당 문서를 추가하기전 추가한다.
                    //이는 [함수라벨] 이 어떤 문서에 속하는지 쉽게 알기 위한 것이다.
                    //일반 <*.c> 가 있는 [함수라벨] 은 해당 <*.$> 안에 이미 정보가 있으나,
                    //[함수묶음] 안의 [함수라벨] 은 이 [문서] 정보를 알수가 없다.
                    //따라서, [LINK] 시에 [함수라벨] 의 정보를 수집하면서 쉽게 어떤 문서 안의 함수인지
                    //알수 있게 만들어 주기 위한 것이다.
                    //
                    // #[함수묶음내문서경로]
                    //
                    //로 한개행을 차지하게 만든다.
                    //}--------------------------------------------------------------------------------

                    fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), "#");
                    fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), tempStr);
                    fileTotalSize += STR_Add(&(objBuf[fileTotalSize]), "\r\n");

                //}

                //[전체 경로 합성]
                //{
                    STR_Assign(fileName, database->projectpath);
                    STR_Add(fileName, tempStr);

                //}

                //[문서열기]
                //{
                    FILE_Open_inBUF(fileName,
                                    &(objBuf[fileTotalSize]),
                                    &fileSize);

                    //현재 fileSize 는 '\0' 까지 포함한 크기를 가지므로,
                    //이 위치는 빼 주어야 한다.
                    fileTotalSize += (fileSize - 1);

                //}

              }

          //}

      //}

  //}


  //[크기 최적화 처리]
  //{
      //[2012.06.30.토][추가!!!]{--------------------------------------------------------
      //[가상기계(GVMS/GVMX)] 크기를 최소한으로 줄이기 위하여 [사용되지 않은 함수] 는
      //제거한다.
      //
      //같은 [함수묶음] 안에 존재하더라도 역시 [사용되지 않은 함수] 는 제거한다.
      //즉, 어떤 경우라도 [합성] 된 상태에서 [사용된 함수] 만 남긴다.
      //이는 [한단계] 로 처리할수 없으며 아래의 [두단계] 로 처리.
      //
      //처리가 복잡하므로 <Link_Delete_UnUseFunction()> 전용 함수로 처리.
      //
      //1) <objBuf[]> 에서 먼저 "2d :함수라벨: " 인 행의 ":함수라벨:" 만 수집.
      //   [함수호출] 의 경우로 [사용된 함수] 목록을 얻는다.
      //
      //2) 모든 함수는 아래와 같이 구성되므로 정확하게 영역을 알수 있기 때문에
      //   현재 [함수] 가 [사용된 함수] 가 아니라면 <memmove()> 를 사용하여 [당겨붙이기]
      //   방식으로 <objBuf[]> 내부적으로 제거한다.
      //   즉, 하나의 저장소 안에서 직접 [제거/정리] 하는 방법을 사용한다.
      //
      //   ":함수라벨: "
      //   "2e :함수라벨: ... "  <fnstart>
      //   "..."
      //   "2f "                 <fnend>
      //
      //[부가정보 처리]******************************************************************
      //
      //1) [이동주소(VECTOR)]
      //
      //   "#VECT :main: "
      //   "#VECT :event: "
      //
      //   그대로 복사.
      //
      //2) [문서정보]
      //
      //   "#main.c "
      //
      //   <Link()> 도중에 [함수] 가 어떤 문서에 존재하는지 기록하기 위하여 참고하는
      //   것으로 실제 복사되지 않는다.
      //}--------------------------------------------------------------------------------

      //[!]{------------------------------------------------------------
      //<Link()> 용으로 [합성된 첫 임시문서] 내용을 보려면 주석을 해제.
      FILE_Save(AnsiString(database->tempfilename) + "(가)",
                objBuf,
                fileTotalSize);
      //}---------------------------------------------------------------

      //(가) 임시 문서를 (나) 크기 최적화. 
      Link_Delete_UnUseFunction(&objBuf, fileTotalSize, &fileTotalSize);

      //[!]{-------------------------------------------------------------
      //<Link()> 용으로 [크기 최적화 된 결과] 내용을 보려면 주석을 해제.
      FILE_Save(AnsiString(database->tempfilename) + "(나)",
                objBuf,
                fileTotalSize);
      //}----------------------------------------------------------------

  //}


  //[정보 초기화]
  //{
      //[Object] 문서가 저장돼 있는 위치를 얻는다.
      linkInfo.objBuf  = objBuf;

      //<*.glnk> 문서가 저장중인 위치를 얻는다.
      linkInfo.lnkBuf  = database->tempfile.buf;

      //총 행수를 얻는다.
      linkInfo.lineTotalCount = STR_Get_LineCount(linkInfo.objBuf);

      linkInfo.lineStartIndex = 0;

      linkInfo.line           = 0;

      linkInfo.word[0]        = '\0';

      linkInfo.wordStartIndex = 0;

      //[부가정보] 의 위치를 얻는다.
      //용량이 크므로 [주소] 로 관리한다.
      linkInfo.infoEtc        = &linkInfoEtc;

      //[부가 정보 초기화]
      //{
          //[라벨 총 개수 얻기]
          //{
              //[!]{---------------------------------------------------------------
              //위에서 함성된 문서의 [라벨] 총 수를 구한다.
              //이는 라벨을 저장할 저장소를 꼭 필요한 만큼만 생성하기 위한 것이다.
              //이 문서에는 [함수라벨] 만 있다.
              //}------------------------------------------------------------------

              StrBuf_GetLabelCount(linkInfo.objBuf, linkInfo.lineTotalCount, &labelTotalCount);

              //[2011.05.21.토][중요수정!!!]
              //

          //}

          //_CODE_:BASE 의 [추가주소] 는 0h 부터 시작한다.
          linkInfo.infoEtc->ofsAdr = 0;

          //[함수라벨] 의 공간을 생성한다.
          //linkInfo.infoEtc->labelItems = new struct LINKLABELITEM[labelTotalCount];
          //[동적생성단위적용][2021.01.24.일][수정]
          linkInfo.infoEtc->labelItems = new struct LINKLABELITEM[UnitX(1024, labelTotalCount)];

          //처음에는 아무것도 저장 된 것이 없다.
          linkInfo.infoEtc->labelItemCount = 0;

      //}

  //}


  //[가상기계 제작 진행창]
  //{
      //[2011.04.29.금][추가!!!]{--------------------------------------
      //현재 처리중인 [문서정보] 를 [가상기계 제작 진행창] 에 보여주고
      //관련설정을 수행한다.
      //}--------------------------------------------------------------

      //[!]{-------------------------------------------------------------------------
      //문서를 읽어들일때 [행수] 를 얻지 않으므로, 여기서 직접 얻어서 전달해야 한다.
      //단, <STR_Get_LineCount()> 함수는 처리 시간이 많이 걸리는데 주의한다.
      //}-----------------------------------------------------------------------------

      buildStatus_Form->_fileLineCount = linkInfo.lineTotalCount;
      buildStatus_Form->_FileInfo(rSaveFileName, buildStatus_Form->_fileLineCount);

  //}


  //[함수라벨 수집/위치확정]
  //{
      //[!]{----------------------------------------------------------------
      //[함수라벨] 수집하는 것과 동시에 라벨의 _CODE_:BASE 의 [추가주소] 를
      //확정해준다.
      //}-------------------------------------------------------------------

      GET_FUNC_LABEL:

      //[Win7 <응답이 없는 상태> 해결]
      //{
          //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
          //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
          //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
          //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
          //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
          //이런 형상이 발생하지 않도록 수정한다.
          //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
          //이 문장을 넣어 준다.
          //}-------------------------------------------------------------------------------------------

          Application->ProcessMessages();

      //}


      //[가상기계 제작 진행창]
      //{
          //[2011.04.29.금][추가!!!]{--------------------------------------------
          //[중지] 요청이 있는 경우는 더이상 처리하지 않고 종료해야 한다.
          //일단, [오류] 로 처리하고, [오류 문자열] 에 [중지요청] 임을 알려준다.
          //}--------------------------------------------------------------------

          if(buildStatus_Form->Visible == false)
          {
            //[!]{-------------------------------------------------------
            //이 경우는 [즁지] 요청으로 간주하고 여기서 처리를 종료한다.
            //}----------------------------------------------------------

            msg_msg_Form->_PrintAddLine
            (d_msg_msg,
             "\r\n"
             "[ 가상기계 제작 취소! ]\r\n"
             "사용자 요청으로 가상기계 제작이 [취소] 되었습니다.");

            goto LINK_ERROR;

          }

      //}
      

      //여기서부터 또 하나의 행이 시작되는 것이다.

      //[현재 행에 내용이 있는가?]
      //{
          //[!]{----------------------------------------------------
          //현재 행에 처리할 것이 없다면 다음 행으로 넘어가야 한다.
          //[첫번째 단어] 만 추출해 보면 간단하게 알수 있다.
          //}-------------------------------------------------------

          Link_GetWord(&linkInfo, 0);

          //첫 단어가 아무것도 없는 경우는 이 행에는 처리할게 없는 것이므로 다음 행으로 넘긴다.
          if(STR_Match(linkInfo.word, "") == true) { goto GET_FUNC_LABEL_LINE_END; }

      //}

      //[이동주소공간]
      //{
          //[2011.05.23.월][참고!!!]{------------------------------
          //이 처리 부는 이전 것으로 현재는 사용되지 않는 것 같다.
          //앞으로의 예약기능으로 간주한다.
          //}------------------------------------------------------

          result = Tree_Link1st_VectorLine(&linkInfo);

          switch(result)
          {
            case yes   :  goto GET_FUNC_LABEL_LINE_END;
            case no    :  break;

          }

      //}

      //[문서경로]
      //{
          //[2011.05.23.월][추가!!!]{----
          //{ #문서경로 } 행만 처리한다.
          //}----------------------------

          result = Tree_Link1st_FileName(&linkInfo);

          switch(result)
          {
            case yes   :  goto GET_FUNC_LABEL_LINE_END;
            case no    :  break;

          }

      //}

      //[함수라벨]
      //{
          //오직 [선언함수라벨] 정보만 처리한다.

          result = Tree_Link1st_FuncLabel(&linkInfo);

          switch(result)
          {
            case yes   :  goto GET_FUNC_LABEL_LINE_END;
            case no    :  break;

            //[2009.03.29.일][추가!!!]
            //[함수라벨] 중복의 경우.
            case error :  goto LINK_ERROR;

          }

      //}

      //[<fnend:0x2f> 명령 처리]
      //{
          //[2011.05.22.일][추가!!!]{--------------------------
          //오직 [함수끝위치] 인 <fnend:0x2f> 명령만 처리한다.
          //}--------------------------------------------------

          result = Tree_Link1st_FuncEnd(&linkInfo);

          switch(result)
          {
            case yes   :  goto GET_FUNC_LABEL_LINE_END;
            case no    :  break;

          }

      //}

      //[일반 행 처리]
      //{
          //이 함수는 무조건 처리 된다.
          result = Tree_Link1st_Line(&linkInfo);

          switch(result)
          {
            case yes   :  goto GET_FUNC_LABEL_LINE_END;
            case no    :  break;

          }

      //}

      GET_FUNC_LABEL_LINE_END:


      //[가상기계 제작 진행창]
      //{
          //[2011.04.29.금][추가!!!]{-------------------------------------------
          //현재 처리중인 [현재 행] 과 [총 처리 행수] 를 처리한다.
          //여기서 처리하는 이유는 [듬성 듬성] 처리하여 정보는 보여주되
          //처리 시간 증가에 영향을 주지않기 위함이다.
          //
          //이 문서는 전부 1 행 단위로 처리 되므로 [문서량/10] 단위로 처리한다.
          //}-------------------------------------------------------------------

          if((buildStatus_Form->_fileLineCount/10) > 0)
          {
            if(linkInfo.line%(buildStatus_Form->_fileLineCount/10) == 0)
            {
              //[현재행] 보여주기.
              buildStatus_Form->_LineNum(linkInfo.line);

              //[전체 처리 행수] 보여주기.
              buildStatus_Form->_TotalLineNum();

            }

          }
          else
          {
            //[현재행] 보여주기.
            buildStatus_Form->_LineNum(linkInfo.line);

            //[전체 처리 행수] 보여주기.
            buildStatus_Form->_TotalLineNum();

          }

      //}


      //각각의 [행] 을 처리한 다음에 다음 [행] 을 지정하거나 문서의 끝에 도달한 경우 등의 처리를 수행한다.

      //[문서의 끝인가?]
      //{
          //현재 [행번호 + 2] 이 총 행수와 같다면 모든 행을 다 처리한 것이다.
          //이는 [Object] 문서에 빈행은 없으나 맨 마지막 문서행은 내용이 없는 CRLF 만 있기 때문이다.

          if((linkInfo.line + 2) >= linkInfo.lineTotalCount)
          {
            //모든 행을 다 처리 하였으므로 문서를 저장하는 곳으로 이동한다.
            goto MAIN_CHECK;

          }
          else
          {
            //[다음행 지정]
            //{
                //다음 행의 시작 index 를 구한다.
                STR_Get_NextLineStartIndex(linkInfo.objBuf,
                                           linkInfo.lineStartIndex,
                                           &(linkInfo.lineStartIndex));

                //행 순번 증가.
                linkInfo.line++;

                //[가상기계 제작 진행창]
                //{
                    //[2011.04.29.금][추가!!!]{----------------------------------------
                    //[가상기계 제작 상태 창] 에 [총 처리 행수] 정보를 표시하기 위하여
                    //이 창에서 관리하는 [총 처리 행수] 환경변수를 수정해 준다.
                    //}----------------------------------------------------------------

                    //행이 증가할때 마다 같이 증가시켜 준다.
                    buildStatus_Form->_totalLineNum++;

                //}

            //}

            //다시 다음 행을 처리한다.
            goto GET_FUNC_LABEL;

          }

      //}

  //}

  //---------------------------------------------------------------------------------------
  //[2st 처리]-----------------------------------------------------------------------------
  //---------------------------------------------------------------------------------------

  MAIN_CHECK:

  //[main 존재 확인]
  //{
      if(Link_Check_Main(&linkInfo) != true) { goto LINK_ERROR; }

  //}

  //[함수라벨 사용부분 code 로 치환]
  //{
      //[!]{--------------------------------------------------------------------------------
      //여기서 [사용함수라벨] 치환 하면서 치환되지 않는(즉, 선언이 존재하지 않는것)것은
      //쉽게 말하여 사용된 함수인데 실체가 없는 것이므로 [Link 오류] 를 출력해 주어야 한다.
      //이 경우는 오류로 더이상 진행하지 않고 여기서 종료해야 한다.
      //}-----------------------------------------------------------------------------------

      //[정보 초기화]
      //{
          linkInfo.lineStartIndex = 0;

          linkInfo.line           = 0;

          linkInfo.word[0]        = '\0';

          linkInfo.wordStartIndex = 0;

      //}    

      LINK_LINE_START:

      //[Win7 <응답이 없는 상태> 해결]
      //{
          //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
          //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
          //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
          //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
          //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
          //이런 형상이 발생하지 않도록 수정한다.
          //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
          //이 문장을 넣어 준다.
          //}-------------------------------------------------------------------------------------------

          Application->ProcessMessages();

      //}


      //[가상기계 제작 진행창]
      //{
          //[2011.04.29.금][추가!!!]{--------------------------------------------
          //[중지] 요청이 있는 경우는 더이상 처리하지 않고 종료해야 한다.
          //일단, [오류] 로 처리하고, [오류 문자열] 에 [중지요청] 임을 알려준다.
          //}--------------------------------------------------------------------

          if(buildStatus_Form->Visible == false)
          {
            //[!]{-------------------------------------------------------
            //이 경우는 [즁지] 요청으로 간주하고 여기서 처리를 종료한다.
            //}----------------------------------------------------------

            msg_msg_Form->_PrintAddLine
            (d_msg_msg,
             "\r\n"
             "[ 가상기계 제작 취소! ]\r\n"
             "사용자 요청으로 가상기계 제작이 [취소] 되었습니다.");

            goto LINK_ERROR;

          }

      //}


      //여기서부터 또 하나의 행이 시작되는 것이다.

      //[현재 행에 내용이 있는가?]
      //{
          //[!]{----------------------------------------------------
          //현재 행에 처리할 것이 없다면 다음 행으로 넘어가야 한다.
          //[첫번째 단어] 만 추출해 보면 간단하게 알수 있다.
          //}-------------------------------------------------------

          Link_GetWord(&linkInfo, 0);

          //첫 단어가 아무것도 없는 경우는 이 행에는 처리할게 없는 것이므로 다음 행으로 넘긴다.
          if(STR_Match(linkInfo.word, "") == true) { goto LINK_LINE_END; }

      //}

      //[이동주소공간]
      //{
          result = Tree_Link_VectorLine(&linkInfo);

          switch(result)
          {
            case yes   :  goto LINK_LINE_END;
            case no    :  break;

          }

      //}

      //[문서이름]
      //{
          //[2011.05.23.월][추가!!!]

          result = Tree_Link_FileName(&linkInfo);

          switch(result)
          {
            case yes   :  goto LINK_LINE_END;
            case no    :  break;

          }

      //}

      //[선언함수라벨]
      //{
          result = Tree_Link_FuncLabel(&linkInfo);

          switch(result)
          {
            case yes   :  goto LINK_LINE_END;
            case no    :  break;

          }

      //}

      //[일반행]
      //{
          result = Tree_Link_Line(&linkInfo);

          switch(result)
          {
            case yes   :  goto LINK_LINE_END;
            case no    :  break;
            case error :  goto LINK_ERROR;

          }

      //}

      LINK_LINE_END:


      //[가상기계 제작 진행창]
      //{
          //[2011.04.29.금][추가!!!]{-------------------------------------------
          //현재 처리중인 [현재 행] 과 [총 처리 행수] 를 처리한다.
          //여기서 처리하는 이유는 [듬성 듬성] 처리하여 정보는 보여주되
          //처리 시간 증가에 영향을 주지않기 위함이다.
          //
          //이 문서는 전부 1 행 단위로 처리 되므로 [문서량/10] 단위로 처리한다.
          //}-------------------------------------------------------------------

          if((buildStatus_Form->_fileLineCount/10) > 0)
          {
            if(linkInfo.line%(buildStatus_Form->_fileLineCount/10) == 0)
            {
              //[현재행] 보여주기.
              buildStatus_Form->_LineNum(linkInfo.line);

              //[전체 처리 행수] 보여주기.
              buildStatus_Form->_TotalLineNum();

            }

          }
          else
          {
            //[현재행] 보여주기.
            buildStatus_Form->_LineNum(linkInfo.line);

            //[전체 처리 행수] 보여주기.
            buildStatus_Form->_TotalLineNum();

          }

      //}


      //각각의 [행] 을 처리한 다음에 다음 [행] 을 지정하거나 문서의 끝에 도달한 경우 등의 처리를 수행한다.

      //[문서의 끝인가?]
      //{
          //현재 [행번호 + 2] 이 총 행수와 같다면 모든 행을 다 처리한 것이다.
          //이는 [Object] 문서에 빈행은 없으나 맨 마지막 문서행은 내용이 없는 CRLF 만 있기 때문이다.

          if((linkInfo.line + 2) >= linkInfo.lineTotalCount)
          {
            //모든 행을 다 처리 하였으므로 문서를 저장하는 곳으로 이동한다.
            goto LINK_OK;

          }
          else
          {
            //[다음행 지정]
            //{
                //다음 행의 시작 index 를 구한다.
                STR_Get_NextLineStartIndex(linkInfo.objBuf,
                                           linkInfo.lineStartIndex,
                                           &(linkInfo.lineStartIndex));

                //행 순번 증가.
                linkInfo.line++;

                //[가상기계 제작 진행창]
                //{
                    //[2011.04.29.금][추가!!!]{----------------------------------------
                    //[가상기계 제작 상태 창] 에 [총 처리 행수] 정보를 표시하기 위하여
                    //이 창에서 관리하는 [총 처리 행수] 환경변수를 수정해 준다.
                    //}----------------------------------------------------------------

                    //행이 증가할때 마다 같이 증가시켜 준다.
                    buildStatus_Form->_totalLineNum++;

                //}

            //}

            //다시 다음 행을 처리한다.
            goto LINK_LINE_START;

          }

      //}

  //}

  LINK_OK:
  //{
      //[<*.glnk> 문서로 저장]
      //{
          //[!]{---------------------------------------------------
          //tempfile [저장소] 의 내용을 <*.glnk> 문서로 저장한다.
          //저장할 파일의 이름은 이미 사전에 만들어진 상태이다.
          //해당 buffer 의 삭제는 아래 함수에서 자동으로 처리된다.
          //}------------------------------------------------------

          TEMPFILE_Save();

      //}

      //[함수라벨 주소 정리]
      //{
          //[2009.03.28.토][추가!!!]{---------------------------------------
          //[함수라벨] 의 [추가주소] 를 {DATABASE} 의 해당 정보에 정리한다.
          //}---------------------------------------------------------------
          
          Link_Database_FuncOfsAdr(&linkInfo);

      //}

      //[<*.$> 문서에 [함수라벨] 주소 정리]
      //{
          //[2009.03.29.일][추가!!!]{--------------------------------------------------------
          //<*.$> 문서를 다시 읽어서 [함수라벨] 주소를 추가후 다시 <*.$> 문서로 저장해 준다.
          //}--------------------------------------------------------------------------------

          if(DebugFile_Add_FuncOfsAdr_To_LineFile(linkInfo.infoEtc) != true) goto LINK_ERROR;

      //}

      //[<*.$lst> 문서 합성]
      //{
          //[2009.03.29.일][추가!!!]{--------------------------------------
          //<*.$> 문서를 전부 합성하여 <*.$lst> 문서로 만들어 준다.
          //
          //[2011.05.24.화][수정!!!]---------------------------------------
          //<*.$lst> [문서이름] 을 전달 받는 것으로 수정한다.
          //이는 다음 <DebugFile_Make_LineListFile_FuncEndInfo()> 함수에서
          //<*.$lst> [문서이름] 이 필요하기 때문이다.
          //}--------------------------------------------------------------

          DebugFile_Make_LineListFile(fileName);

      //}

      //[<*.$lst> 문서 보완]
      //{
          //[2011.05.23.월][추가!!!]{------------------------------------
          //<*.$lst> 문서에 [함수끝위치] 정보를 추가한다.
          //이는 [함수끝위치] 정보가 [검증] 시 반드시 필요하기 때문이다.
          //}------------------------------------------------------------

          DebugFile_Make_LineListFile_FuncEndInfo(fileName,
                                                  linkInfo.infoEtc);

      //}

      //[<*.gasm> 문서 재생성]
      //{
          //[2009.03.29.일][추가!!!]{-------------------------------------------------
          //<*.gasm> 과 <*.gasm2> 문서를 합성하여 새로운 <*.gasm> 문서로 만들어 준다.
          //}-------------------------------------------------------------------------

          if(DebugFile_ReMake_Gasm(linkInfo.infoEtc) != true) goto LINK_ERROR;

      //}

      //[<*.gcsm> 문서 합성]
      //{
          //[2009.03.30.월][추가!!!]{-----------------------------------
          //<*.c> 와 <*.gasm> 문서를 합성하여 <*.gcsm> 문서를 합성한다.
          //}-----------------------------------------------------------
          DebugFile_Make_Gcsm();

      //}

      //[삭제]
      //{
          //동적으로 생성된 [저장소] 들을 삭제한다.
          //TEMPFILE_Delete();

          //동적으로 생성한 개체를 삭제한다.
          if(objBuf != NULL) { delete [] objBuf; objBuf = NULL; }

          //동적 생성한 것을 삭제한다.
          if(linkInfo.infoEtc->labelItems != NULL) { delete [] linkInfo.infoEtc->labelItems; linkInfo.infoEtc->labelItems = NULL; }

      //}

      return(true);

  //}

  LINK_ERROR:
  //{
      //[삭제]
      //{
          //동적으로 생성된 [저장소] 들을 삭제한다.
          TEMPFILE_Delete();

          //동적으로 생성한 개체를 삭제한다.
          if(objBuf != NULL) { delete [] objBuf; objBuf = NULL; }

          //동적 생성한 것을 삭제한다.
          if(linkInfo.infoEtc->labelItems != NULL) { delete [] linkInfo.infoEtc->labelItems; linkInfo.infoEtc->labelItems = NULL; }

      //}

      return(false);

  //}

}

int __fastcall Tree_Link1st_VectorLine(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{-------------------------------------
  //"#VECT" 로 시작하는 [이동주소공간] 행을 처리한다.
  //_CODE_:BASE 의 [추가주소] 를 계산해 주어야 한다.
  //단, 이 [이동주소공간] 은 무조건 각각 8 Byte 의 크기를 갖는다.
  //}-------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Link_GetWord(prLinkInfo, 0);

  //}

  //[[이동주소공간] 행 인가?]
  //{
      //첫단어가 "#VECT" 로 시작한다.
      if(STR_Match(prLinkInfo->word, "#VECT") != true)
      {
        //이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[추가주소계산]
  //{
      //[이동주소공간] 은 무조건 8 Byte 의 크기를 갖는다.
      prLinkInfo->infoEtc->ofsAdr += 8;

  //}

  return(yes);

}

int __fastcall Tree_Link1st_FuncLabel(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{-----------------------------------------------------------
  //[함수라벨] 부분을 처리한다.
  // ":함수이름:" 형식으로 앞뒤에 다 ":" 이 붙어 있으며
  //반드시 행의 첫단어 위치에 오므로 간단하게 구분 처리 할수 있다.
  //
  //[함수라벨] 을 일단 여기서 전부 수집하고 _CODE_:BASE 로한 [추가주소] 룰 구해야 한다.
  //이는 전용 [저장소] 를 대상으로 처리한다.
  //
  //[2009.03.29.일][중요수정!!!]--------------------------------------------------------
  //[함수라벨] 이 중복 되는 경우는 오류도 간주해야 한다.
  //이런 경우는 <*.c> 안의 [함수] 와 <*.glib> 안의 [함수] 가 같은 경우 발생하며 이전
  //단계에서는 절대 걸러낼수 없으므로 여기서 걸러내야 한다.
  //[정보구조체] 에 [함수] 를 추가 하기전 이미 존재하는지 확인한다.
  //
  //[2011.05.23.월][중요수정!!!]--------------------------------------------------------
  //[함수라벨] 이 어떤 [문서] 안에 존재하는지 쉽게 알수 있게 현재
  //[문서이름<prLinkInfo->fileName>] 의 정보를 해당 [함수라벨] 의 정보에 기록해 준다.
  //이를 위하여 [함수라벨] 정보 안에 [문서이름] 정보를 저장할 항목이 추가되었다.
  //
  //항상 [문서이름] 이 먼저 시작되고, 다음에 해당 문서의 내용이 추가된 상태이므로
  //[문서이름] 은 먼저 정리돼 있어 바로 사용하면 된다.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

      //[2009.03.29,일][추가!!!]
      class  DATABASE  *database;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Link_GetWord(prLinkInfo, 0);

  //}

  //[함수라벨 인가?]
  //{
      //[함수라벨] 은 유일한 [전역라벨] 로 단어의 시작이 ":" 문자로 시작한다.
      if(prLinkInfo->word[0] != ':')
      {
        //[함수라벨] 이 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[중복 검사]
  //{
      //[2009.03.29.일][추가!!!]{-------------
      //[함수라벨] 이 [중복] 되는지 확인한다.
      //}-------------------------------------

      //[DATABASE 위치 얻기]
      //{
          DATABASE_GetPtr(&database);

      //}

      if(Link_Get_FuncOfsAdrHexStr_withName(prLinkInfo->infoEtc, prLinkInfo->word, false, NULL) >= 0)
      {
        //함수가 중복되므로 오류!

        //[오류문자열]
        //{
            database->ERRORINFO_Word(prLinkInfo->word);
            database->ERRORINFO_Add("[함수이름] 이 [설계묶음] 안에서 [중복] 됩니다.\r\n"
                                    "[함수이름] 은 절대로 [설계묶음] 안에서 [중복] 될수 없습니다.\r\n"
                                   );

        //}

        return(error);

      }

  //}

  //[함수라벨 정리]
  //{
      //[문서이름]
      //{
          //[2011.05.23.월][추가!!!]{----------------------------
          //이 [함수라벨] 이 존재하는 [문서이름] 을 기록한다.
          //이미 정보가 [관리] 되고 있으므로 바로 할당하면 된다.
          //}----------------------------------------------------

          STR_Assign(prLinkInfo->infoEtc->labelItems[prLinkInfo->infoEtc->labelItemCount].fileName, prLinkInfo->fileName);

          //[2011.05.24.화][수정!!!]{--------------------------------------------------------------------
          //[함수라벨] 은 순서대로 오고, 문서 정보는 중복될 필요가 없으므로 한번 기록후 지워준다.
          //이는 <DebugFile_Make_LineListFile_FuncEndInfo()> 함수에서 정보 처리를 쉽게 하기 위한 것이다.
          prLinkInfo->fileName[0] = '\0';
          //}--------------------------------------------------------------------------------------------

      //}

      //[라벨이름]
      //{
          //현재 단어가 [함수라벨] 이름 자체가 된다.
          STR_Assign(prLinkInfo->infoEtc->labelItems[prLinkInfo->infoEtc->labelItemCount].name,
                     prLinkInfo->word);

      //[라벨주소]
      //{
          //현재 ofsAdr 의 값이 이 [함수라벨] 의 _CODE_:BASE 로한 [추가주소] 가 된다.
          prLinkInfo->infoEtc->labelItems[prLinkInfo->infoEtc->labelItemCount].ofsAdr = prLinkInfo->infoEtc->ofsAdr;

      //}

      //[함수라벨] 정보가 하나 저장되었다.
      prLinkInfo->infoEtc->labelItemCount++;

  //}

  return(yes);

}

int __fastcall Tree_Link1st_Line(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{---------------------------------------
  //순수한 일반 행을 처리한다.
  //_CODE_:BASE 의 [추가주소] 를 계산해 주어야 한다.
  //
  // 1) [일반단어]      : (문자열길이/2) Byte 크기.
  //
  // 2) [사용 함수라벨] : 무조건 (2 + 8 = 10) Byte 크기로 처리한다.
  //
  //}---------------------------------------------------------------

  //[VAR]
  //{
      int  strLength;
      int  i;

  //}

  //[주소계산]
  //{
      for(i = 0; ; i++)
      {
        //[단어 추출]
        //{
            //현재 지정 순번의 단어를 추출한다.
            Link_GetWord(prLinkInfo, i);

            //추출한 단어가 "" 인 경우는 더이상 이 행에 처리할 단어가 없는 것이다.
            if(prLinkInfo->word[0] == '\0') break;

        //}

        //[사용함수라벨] 과 [일반단어] 를 구분하여 처리한다.
        if(prLinkInfo->word[0] == ':')
        {
          //[사용함수라벨] 이 해당한다.
          //[type(2) + 주소(8)] = 10 Byte 가 된다.

          prLinkInfo->infoEtc->ofsAdr += 10;

        }
        else
        {
          //[일반단어] 가 해당한다.
          
          strLength = STR_Length(prLinkInfo->word);

          //문자열 길이 / 2 가 해당 실제 Byte 수가 된다.
          prLinkInfo->infoEtc->ofsAdr += (strLength / 2);

        }

      }

  //}

  return(yes);

}

int __fastcall Tree_Link1st_FuncEnd(struct LINKINFO  *prLinkInfo)
{
  //[2011.05.21.토][생성!!!]{----------------------------------------------------------
  //오로지 <fnend:0x2f> 의 명령어 행만 처리한다.
  //이 행에는 오직 <0x2f> 1 바이트만 존재한다.
  //
  //이는 [검증] 시 [함수탈출] 등의 기능에 반드시 [함수끝위치] 를 알아야 하기 때문이다.
  //
  //원래 { "FD.X.}:" } 에 해당하는 위치로 실제는 <fnend:0x2f> 명령의 위치가 된다.
  //
  //현재 [LINK] 단계이므로 여기서 계산된 위치는 바로 _CODE_:BASE 의 [추가주소] 가 되며
  //바로 사용하면 된다.
  //
  //2f : 무조건 1 바이트 크기 고정값이다.
  //
  //[주의!!!]--------------------------------------------------------------------------
  //<Tree_Link1st_FuncLabel()> 에서 [함수라벨] 은 이미 정보가 정리돼 있는데
  //항상 <fnend> 보다 먼저 있으므로, 가장 마지막에 처리한 [함수라벨] 의 정보가
  //지금 <fnend> 의 정보를 추가할 대상이 된다.
  //즉, 힘들게 검색하여 찾은후 처리할 필요가 없다는 것이다.
  //}----------------------------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Link_GetWord(prLinkInfo, 0);

  //}

  //[<fnend:0x2f> 인가?]
  //{
      //[!]{--------------------------------------------------------------------------
      //<fnend:0x2f> 로 실제는 "2f" 로 기록돼 있으므로 이 단어와 일치하는지 확인한다.
      //이것은 [명령어] 로 [고정] 값이다.
      //}-----------------------------------------------------------------------------

      //만일의 경우를 위하여 [대/소] 문자 구분없이 검사한다.
      if(STR_Match_NoCase(prLinkInfo->word, "2f") != true)
      {
        //<fnend> 명령행이 아니다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[함수라벨 정보 추가]
  //{
      //[!]{----------------------------------------------------------------------
      //이 <fnend> 를 가지는 [함수라벨] 의 정보에 <fnend> 명령 위치를 기록한다.
      //{ [함수라벨] ... <fnend> } 로 반드시 1:1 로 순서대로 짝이 지워져 있으므로
      //이 시점에서 가장 마지막에 추가된 [함수라벨] 이 짝이 된다.
      //즉, 가장 마지막 [함수라벨정보] 에 지금 <fnend> 주소를 기록한다.
      //}-------------------------------------------------------------------------

      //현재 <prLinkInfo->infoEtc->ofsAdr> 값이 <fnend> 의 _CODE_:BASE [추가주소] 가 된다.
      //[함수라벨] 추가시 <++> 되었으므로 [함수라벨] 정보 저장 위치는 <-1> 을 한 위치가 된다.
      //--------------------------------------------------------------------v
      prLinkInfo->infoEtc->labelItems[prLinkInfo->infoEtc->labelItemCount - 1].ofsAdr_fnend = prLinkInfo->infoEtc->ofsAdr;

  //}

  //[주소계산]
  //{
      //[!]{---------------------------------------
      //<fnend:0x2f> 로 무조건 1 바이트 값이다.
      //자체가 명령어로 한 행에 1 명령만 존재한다.
      //}------------------------------------------

      //이 명령 크기 1 바이트--------v
      prLinkInfo->infoEtc->ofsAdr += 1;

  //}

  return(yes);

}

int __fastcall Tree_Link1st_FileName(struct LINKINFO  *prLinkInfo)
{
  //[2011.05.23.월][생성!!!]{----------------------------------------
  //
  //{ #[설계묶음안문서경로] }
  //
  //행을 처리하고, [문서경로] 를 전용 저장소에 저장해 놓는다.
  //이는 [함수라벨] 이 어떤 [문서] 안인지 쉽게 확인하기 위한 것이다.
  //}----------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

      //지금 행의 끝 위치.
      int    lineEndIndex;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[문서경로 인가?]
  //{
      //[!]{--------------------------------------------------------------
      //반드시 첫 [문자] 가 '#' 로 시작되므로 이 [문자] 만 검사하면 된다.
      //}-----------------------------------------------------------------

      //지금 검사행의 [첫문자] 를 바로 검사한다.
      if(prLinkInfo->objBuf[prLinkInfo->lineStartIndex] != '#')
      {
        //[문서이름] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[문서이름 저장]
  //{
      //[!]{--------------------------------------------------
      //전용 저장소에 현재 문서이름을 추출하여 기록해 놓는다.
      //}-----------------------------------------------------

      //[현재행의 끝 위치 얻기]
      //{
          //[!]{-----------------------------------------------------------------------------
          //검사행의 시작을 0 으로 본 행 끝의 위치를 구한다(고속 처리/계산의 편의를 위한것).
          //이는 문자열의 길이를 쉽게 구할수 있기 때문이다.
          //}--------------------------------------------------------------------------------

          STR_Get_ThisLineEndIndex(&(prLinkInfo->objBuf[prLinkInfo->lineStartIndex]), 0, &lineEndIndex);

          //[!]{------------------------------------------------------------------------------
          //행 끝은 [공백] 한개가 붙어 있으므로 이 위치는 제외한다.
          //
          //[2012.07.01.일][중요설명!!!]******************************************************
          //실제 [문서정보] 는 "#문서경로\r\n" 으로 행에 공백이 없이 바로 <CRLF 가 온다.
          //<STR_Get_ThisLineEndIndex()> 함수에서 얻는 [행:끝위치] 는 바로 <CR> 위치가 되므로
          //[공백] 이 부터 있는줄 알고 <--> 한 값을 사용한 것과 결과적으로 같은 것이라
          //즉, [행:끝위치] 를 여기서는 [마지막 문자위치] 로 본 것이다.
          //그동안 오류가 없었다.
          //
          //금일 발견하고 정확한 개념을 정리한다.
          //}---------------------------------------------------------------------------------

          lineEndIndex--;

      //}

      //[경로 문자열 추출/저장]
      //{
          //[!]{--------------------------------------------------------------------
          //이 행의 첫문자 "#" 를 제외하고 행의 끝 위치가지 문자여을 추출하면 된다.
          //행 뒤의 [공백] 은 이미 위에서 <lineEndIndex--> 로 제거 되었다.
          //}-----------------------------------------------------------------------

          STR_SubString(//현재 행을 대상으로 처리하면 된다.
                        &(prLinkInfo->objBuf[prLinkInfo->lineStartIndex]),
                        //[0] 위치는 '#" 문자가 있으므로 [1] 위치부터가 추출하는 문자열의 시작 위치가 된다.
                        1,
                        //추출할 길이.
                        (lineEndIndex - 1) + 1,
                        //추출된 [문서이름].
                        prLinkInfo->fileName);

      //}

  //}

  return(yes);

}

//[LINK]------------------------------------------------------------------------

int __fastcall Tree_Link_VectorLine(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{---------------------------------------------------
  //"#VECT" 로 시작하는 [이동주소공간] 행을 처리한다.
  //
  // 1) #VECT :main:
  //
  //    => ":main:" 의  [추가주소] 를 기록.
  //
  // 2) #VECT :event:
  //
  //    가) ":event:" 가 사용된 상황이라면 ":event:" 의 [추가주소] 를 기록.
  //
  //    나) ":event:" 가 없다면 0h 로 채워주면 된다.
  //
  //이 [이동주소공간] 은 직접 적으로 기술되는 [주소영역] 으로 8 Byte 로 주소만
  //직접 기술해 주면 된다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

      char   code[OPT_wordStrSize];

      char   hexStr[OPT_wordStrSize];

      int    itemIndex;

      unsigned long long ofsAdr;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Link_GetWord(prLinkInfo, 0);

  //}

  //[[이동주소공간] 행 인가?]
  //{
      //첫단어가 "#VECT" 로 시작한다.
      if(STR_Match(prLinkInfo->word, "#VECT") != true)
      {
        //이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[해당 함수 라벨 주소얻기]
  //{
      //[둘째 단어 추출]{----------
      Link_GetWord(prLinkInfo, 1);
      //}--------------------------

      if     (STR_Match(prLinkInfo->word, ":main:") == true)
      {
        //[라벨 찾기]
        //{
            //<Link1st> 에서 수집한 [라벨] 에 있는지 찾는다.
            Link_Get_Label_ItemIndex(prLinkInfo, ":main:", &itemIndex);

            //":main:" 은 반드시 존재한다.

        //}

        //[주소얻기]
        //{
            ofsAdr = prLinkInfo->infoEtc->labelItems[itemIndex].ofsAdr;

        //}

      }
      else if(STR_Match(prLinkInfo->word, ":event:") == true)
      {

        //[라벨 찾기]
        //{
            //<Link1st> 에서 수집한 [라벨] 에 있는지 찾는다.
            Link_Get_Label_ItemIndex(prLinkInfo, ":event:", &itemIndex);

            //":event:" 은 존재할수도 존재하지 않을수도 있다.

        //}

        //[존재 구분 처리]
        //{
            //[!]{---------------------------------------------
            //":event": 는 사용하지 않는 경우는 없을수도 있다.
            //이 경우는 무조건 0h 로 간주 해야 한다.
            //}------------------------------------------------

            if(itemIndex >= 0)
            {
              //[주소얻기]
              //{
                  ofsAdr = prLinkInfo->infoEtc->labelItems[itemIndex].ofsAdr;

              //}

            }
            else
            {
              //[주소얻기]
              //{
                  ofsAdr = 0;

              //}

            }

        //}

      }

  //}

  //[16진수로 변환]
  //{
      //무조건 16 digit 로 표기 되어야 한다.
      CONV_LongVal_To_Hex(ofsAdr, 16, hexStr);

  //}

  //[Little Endian 으로 변환]
  //{
      //문자열을 가지고 직접 변환한다.
      Endian_Change_HexStr(hexStr, code);

  //}

  //[*.glnk 에 추가]
  //{
      //[code] 자체가 한개의 [단어] 로 되 있으므로 그냥 그대로 추가해 주면 된다.
      TEMPFILE_Add(code); TEMPFILE_Add(" \r\n");

  //}

  return(yes);

}

int __fastcall Tree_Link_FileName(struct LINKINFO  *prLinkInfo)
{
  //[2011.05.23.월][생성!!!]{----
  //
  //{ #[문서경로] }
  //
  //행을 처리한다.
  //
  //<*.glnk> 에 필요하지 않다.
  //<*.glnk> 에 추가하지 않는다.
  //}----------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[문서이름 인가?]
  //{
      //이 행의 첫 문자가 '#' 인지만 확인한다.
      if(prLinkInfo->objBuf[prLinkInfo->lineStartIndex] != '#')
      {
        //[문서이름] 행에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[문서이름 처리]
  //{
      //더이상 필요없으므로 아무 처리도 하지 않는다.

  //}

  return(yes);

}

int __fastcall Tree_Link_FuncLabel(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.09.월][생성!!!]{--------------------------------------
  //[함수라벨] 부분을 처리한다.
  // ":함수이름:" 형식으로 앞뒤에 다 ":" 이 붙어 있으며
  //반드시 행의 첫단어 위치에 오므로 간단하게 구분 처리 할수 있다.
  //
  //<*.glnk> 에는 더이상 [함수라벨] 은 필요가 없다.
  //<*.glnk> 에 추가하지 않는다.
  //}--------------------------------------------------------------

  //[VAR]
  //{
      struct LINKINFO  linkInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      linkInfo_Backup = (*prLinkInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Link_GetWord(prLinkInfo, 0);

  //}

  //[함수라벨 인가?]
  //{
      //[함수라벨] 은 유일한 [전역라벨] 로 단어의 시작이 ":" 문자로 시작한다.
      if(prLinkInfo->word[0] != ':')
      {
        //[함수라벨] 이 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prLinkInfo) = linkInfo_Backup;

        //}                     

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[함수라벨 처리]
  //{
      //더이상 필요없으므로 아무 처리도 하지 않는다.

  //}

  return(yes);

}

int __fastcall Tree_Link_Line(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{---------------------------------------
  //순수한 일반 행을 처리한다.
  //
  // 1) [일반단어]
  //
  //    => 그대로 복사한다.
  //
  // 2) [사용 함수라벨]
  //
  //    => 해당
  //
  //}---------------------------------------------------------------

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

      char   code[OPT_wordStrSize];

      char   symbol[OPT_1st_symbol_length] = {""};

      char   tempWord[OPT_wordStrSize];

      int    itemIndex;

      int    i;

  //}

  //[DATABASE 위치 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[구분 처리]
  //{
      for(i = 0; ; i++)
      {
        //[단어 추출]
        //{
            //현재 지정 순번의 단어를 추출한다.
            Link_GetWord(prLinkInfo, i);

            //추출한 단어가 "" 인 경우는 더이상 이 행에 처리할 단어가 없는 것이다.
            if(prLinkInfo->word[0] == '\0') break;

        //}

        //[사용함수라벨] 과 [일반단어] 를 구분하여 처리한다.
        if(prLinkInfo->word[0] == ':')
        {
          //[사용함수라벨] 이 해당한다.

          //[라벨 찾기]
          //{
              //<Link1st> 에서 수집한 [라벨] 에 있는지 찾는다.
              Link_Get_Label_ItemIndex(prLinkInfo, prLinkInfo->word, &itemIndex);

              //[존재 확인]
              //{
                  if(itemIndex == -1)
                  {
                    //이 경우는 [함수] 가 사용되었으나 "존재하지 않는 것" 이다.

                    //[전역 라벨] 은 ":이름:" 형식으로 되 있으므로 여기서 순순한 [이름] 만 추출한다.
                    SYMBOL_Asm_ExtractName_From_GlobalLabel(prLinkInfo->word, tempWord);

                    //[오류문자열]
                    //{
                        database->ERRORINFO_Word(tempWord);
                        database->ERRORINFO_Add("사용된 [함수] 가 [설계묶음] 안에 존재하지 않습니다.\r\n"
                                                "사용 [함수] 는 반드시 [설계묶음] 안에 [본체] 가 존재해야 합니다.\r\n"
                                               );

                    //}

                    return(error);

                  }

              //}

          //}

          //[ASM 기호 얻기]
          //{
              //일단, 해당 [추가주소] 의 <ASM 기호> 를 얻는다.
              SYMBOL_Link_Asm_GlobalLabel(prLinkInfo->infoEtc->labelItems[itemIndex].ofsAdr, symbol);

          //}

          //[기호를 code 로 변환]
          //{
              //일관된 방법으로 처리하기 위하여 이미 만들어 놓은 전용 함수를 사용한다.
              Object_Operand(symbol, code);

          //}

          //[*.glnk 에 추가]
          //{
              //[code] 자체가 한개의 [단어] 로 되 있으므로 그냥 그대로 추가해 주면 된다.
              //더이상의 단어 구분은 의미가 없으므로 [공백] 없이 바로 추가 한다.
              TEMPFILE_Add(code);

          //}

        }
        else
        {
          //[일반단어] 가 해당한다.
          //그대로 복사해 주면 된다.
          //더이상의 단어 구분은 의미가 없으므로 [공백] 없이 바로 추가 한다.

          TEMPFILE_Add(prLinkInfo->word);

        }

      }

      //[행구분]
      //{
          //여기까지 한개 행의 처리가 끝났으므로 행을 만들어 준다.
          TEMPFILE_Add(" \r\n");

      //}

  //}

  return(yes);

}

//[추가함수]--------------------------------------------------------------------

int __fastcall Link_Get_ObjectFileTotalSize(int  *rObjectFileTotalSize)
{
  //[2009.02.07.토][생성!!!]{----------------------------------------------
  //현재 [설계묶음] 처리에 사용되는 모든 <*.gobj> 와 <*.glib> 문서의 총
  //크기를 구하여 반환한다.
  //이 크기를 바탕으로 <*.glnk> 문서를 합성할 [저장소] 를 생성하게 된다.
  //
  //[2011.05.22.일][중요수정!!!]-------------------------------------------
  //현재 처리한 <*.gobj> 와 <*.glib> 문서의 총 수를 반환한다.
  //이는 이 문서를 합칠때 이전과 달리 <#문서이름> 정보를 추가하게 되었는데
  //이 추가 정보 문자열만큼 [저장소] 크기를 늘려주기 위한 것이다.
  //낭비하지 않고 추가 크기를 계산할때 반드시 필요한 정보다.
  //}----------------------------------------------------------------------

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

      char  fileName[OPT_filepath_length];
      char  tempStr[OPT_lineStrSize];
      char  fileNameOnly[OPT_lineStrSize];

      int   fileSize      = 0;
      int   fileTotalSize = 0;

      //[<설계묶음> 관련]
      //{
          struct  TREE   *tree;

          int     nodeIndex;
          int     nodeItemCount;

      //}

      int  i;
      int  cnt;

      //[2011.05.09.월][추가!!!]
      int  nodeLastItemIndex;

      //[2011.05.22.일][추가!!!]
      //총 문서수를 얻는다.
      int  totalDocCount = 0;


  //}

  //[초기화]
  //{
      (*rObjectFileTotalSize) = 0;

  //}

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

  //}

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

  //}

  //[<설계문서> 처리]
  //{
      //[!]{-------------------------------------------------------------------
      //[설계문서] 순서대로 [build] 폴더안의 <*.gobj> 문서의 총 크기를 구한다.
      //}----------------------------------------------------------------------

      //[<설계문서> [옹이] 정보얻기]
      //{
          tree_tree_Form->_Tree_Get_Node_ItemCount(tree, "c", &nodeIndex, &nodeItemCount);

      //}

      for(i = 0, cnt = 0; cnt < nodeItemCount; i++)
      {
        //[문서 경로 합성]
        //{
            //[!]{-------------------------------------------------------------
            //전체 [문서 경로] 를 만들어 준다.
            //단, <*.gobj> 문서를 열어야 하므로 [build] 폴더 경로를 추가 한다.
            //}----------------------------------------------------------------

            //[직계가지 인가?]
            //{
                //[!]{-----------------------------------------------------
                //단지 <*.c> 에 해당하는 문서만을 대상으로 처리해야 하는데
                //이는 [옹이] 의 [직계가지] 에만 해당한다.
                //}--------------------------------------------------------

                //[직계가지] 에 해당하지 않는다면 계속 다음을 검사한다.
                if((tree->items[nodeIndex].level + 1) != tree->items[i + (nodeIndex + 1)].level) continue;

            //}

            STR_Assign(tempStr, database->buildpath);

            //[순수 이름만 추출]
            //{
                //[!]{---------------------------------------------------------------------------------
                //실제 대상이 되는 모든 문서는 전부 [build] 에 있으므로 순수한 문서이름만 있으면 된다.
                //}------------------------------------------------------------------------------------

                //[2012.04.20.금][수정!!!]
                STR_GetFileNameOnly(tree_tree_Form->_Item_Txt_StrPtr3(tree, i + (nodeIndex + 1)), fileNameOnly);

                STR_Add(tempStr, fileNameOnly);

            //}

            //확장자를 <*.gobj> 로 바꿔준다.
            STR_ChangeFileExt(tempStr, "gobj", fileName);

        //}

        //[크기 얻기]
        //{
            File_GetSize(fileName, &fileSize);

            //전체 크기를 함성한다.
            fileTotalSize += fileSize;

        //}

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

            //[2011.05.22.일][추가!!!]{-----------
            //현재 처리한 전체 문서수를 기록한다.
            totalDocCount++;
            //}-----------------------------------

        //}

      }

  //}

  //[<함수묶음> 처리:총 크기 얻기]
  //{
      //[!]{--------------------------------------------------------------------------
      //[함수묶음] 순서대로 <*.glib> 문서의 [총 크기] 를 구한다.
      //
      //[2011.05.09.월][중요수정!!!]--------------------------------------------------
      //[Tree:함수묶음] 의 구조가 [경로] 방식에서 [Tree 구조] 방식으로 변경되었으므로
      //이제 맞게 해당 처리 부분을 전부 수정해 준다.
      //}-----------------------------------------------------------------------------

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

      //}

      //[문서 크기 얻기]
      //{
          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;

            //}

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

            //}

            //[전체 경로 합성]
            //{
                STR_Assign(fileName, database->projectpath);
                STR_Add(fileName, tempStr);

            //}

            //[크기 얻기]
            //{
                File_GetSize(fileName, &fileSize);

                //전체 크기를 함성한다.
                fileTotalSize += fileSize;

            //}

            //[2011.05.22.일][추가!!!]{-----------
            //현재 처리한 전체 문서수를 기록한다.
            totalDocCount++;
            //}-----------------------------------

          }

      //}

  //}

  //[반환]
  //{
      (*rObjectFileTotalSize) = fileTotalSize;

  //}

  //현재 처리한 총 문서수를 반환한다.
  return(totalDocCount);

}

bool __fastcall Link_Check_Main(struct LINKINFO  *prLinkInfo)
{
  //[2009.02.08.일][생성!!!]{---------------------------
  // "main" 이 존재하는지와 한개만 존재하는지 확인한다.
  //
  //1) "main" 이 존재 하는가?
  //
  //2) 한개만 존재하는가?
  //
  //}---------------------------------------------------

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

      int   i;

      //main 이 있는 경우는 true 로 표시해 놓는다.
      bool  isMain = false;

  //}

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

  //}

  //[<main> 이 존재하는가?]
  //{
      //main() 함수가 존재하는지 확인한다.
      for(i = 0; i < prLinkInfo->infoEtc->labelItemCount; i++)
      {
        if(STR_Match(prLinkInfo->infoEtc->labelItems[i].name, ":main:") == true)
        {
          if(isMain != true)
          {
            isMain = true;

          }
          else
          {
            //main() 이 중복으로 존재 하는 것이므로 오류다.
            goto MAIN_X;

          }

        }

      }

      //[<main> 존재?]
      //{
          if(isMain != true) { goto MAIN_NONE; }

      //}

  //}

  MAIN_OK:
  //{
      //아무 이상 없음.
      return(true);

  //}

  MAIN_NONE:
  //{
      //main() 이 존재하지 않는다.

      //[오류문자열]
      //{
          database->ERRORINFO_Word("main");
          database->ERRORINFO_Add("\"main\" 이 [설계묶음] 에 존재하지 않습니다.\r\n"
                                  "\"void main(void)\" 형식으로 반드시 [설계묶음] 에 존재해야 합니다.\r\n"
                                 );

      //}

      return(false);

  MAIN_X:
  //{
      //[오류문자열]
      //{
          database->ERRORINFO_Word("main");
          database->ERRORINFO_Add("\"main\" 이 [설계묶음] 에 중복됩니다.\r\n"
                                  "\"void main(void)\" 형식으로 반드시 [설계묶음] 에 한개만 존재해야 합니다.\r\n"
                                 );

      //}

      return(false);

  //}

}

void __fastcall Link_Get_Label_ItemIndex(struct LINKINFO  *prLinkInfo,
                                         char             *pLabelName,
                                         int              *rItemIndex)
{
  //[2009.02.08.일][생성!!!]{----------------------------------------------
  //수집한 [함수라벨] 에서 지정된 [이름] 의 것을 찾아서 index 를 반환한다.
  //찾는 것이 없다면 -1 을 반환한다.
  //}----------------------------------------------------------------------

  //[VAR]
  //{
      int  i;

  //}

  //[초기화]
  //{
      //일단은 찾는 것이 없는 것으로 초기화 한다.
      if(rItemIndex != NULL) { (*rItemIndex) = -1; }

  //}

  //[찾기]
  //{
      for(i = 0; i < prLinkInfo->infoEtc->labelItemCount; i++)
      {
        if(STR_Match(prLinkInfo->infoEtc->labelItems[i].name, pLabelName) == true)
        {
          //원하는 것을 찾았다.
          if(rItemIndex != NULL) { (*rItemIndex) = i; }

        }

      }

  //}

  return;

}

void __fastcall Link_Database_FuncOfsAdr(struct LINKINFO  *pLinkInfo)
{
  //[2009.03.28.토][생성!!!]{---------------------------------------------
  //[LINK] 확정되는 [함수주소] 를 {DATABASE} 의 해당 공간에 기록해 준다.
  //
  //[주의!!!]-------------------------------------------------------------
  //[함수라벨] 인 [전역라벨] 은 ":" 이 앞뒤에 붙어 있으므로 이를 제거하고
  //단어를 검사해야 한다. 이는 전용 함수로 처리한다.
  //}---------------------------------------------------------------------

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

      char  tempWord[OPT_wordStrSize] = {""};

      int   i;
      int   recIndex;

  //}

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

  //}

  //[주소 기록]
  //{
      //현재 수집된 [함수라벨] 정보를 사용하여 확정된 [함수라벨 주소] 를 기록한다.
      for(i = 0; i < pLinkInfo->infoEtc->labelItemCount; i++)
      {
        //[함수 찾기]
        //{
            //먼저 [함수라벨] 에서 비교할 순수한 [이름] 만 추출한다.
            SYMBOL_Asm_ExtractName_From_GlobalLabel(pLinkInfo->infoEtc->labelItems[i].name,
                                                    tempWord);

            //해당 이름을 찾는다.
            database->REC_Search_withNameAndArea(0,
                                                 tempWord,
                                                 //[함수이름] 만 찾을 것이므로 [전역영역] 만 대상으로 한다.
                                                 -1,
                                                 //{DATABASE} 전체를 대상으로 검색한다.
                                                 true,
                                                 &recIndex);

        //}

        if(recIndex >= 0)
        {
          //일단, [이름] 과 일치하는것을 찾았다.

          //[함수 인가?]
          //{
              //[함수] 인지 확인한다.

              if((database->record[recIndex].kind == _recKIND_func_def) ||
                 (database->record[recIndex].kind == _recKIND_func_body))
              {
                //[함수] 이므로 [추가주소] 를 기록한다.
                database->record[recIndex].address = pLinkInfo->infoEtc->labelItems[i].ofsAdr;

              }

          //}

        }

      }

  //}

  return;

}

int __fastcall Link_Get_FuncOfsAdrHexStr_withName(struct  LINKINFOETC  *pLinkInfoEtc,
                                                  char   *pFuncLabelName,
                                                  //16자리로 확정해야 하는 경우는 true.
                                                  bool    p16Digit,
                                                  char   *rHexStr)
{
  //[2009.03.29.일][생성!!!]{---------------------------------------------
  //[함수라벨] 을 전달 받아서 해당 [함수라벨] 의 [추가주소] 를 찾은 후
  //[16진수 최소표기 문자열] 로 변환하여 반환한다.
  //
  //이 함수는 <*.$> 문서안의 [함수라벨] 의 [추가 주소] 를 기록하여 새로운
  //<*.$> 문서를 만드는데 필요하다.
  //
  //[2011.05.24.화][수정!!!]----------------------------------------------
  //찾은 <index> 를 반환하는 것으로 수정한다.
  //<-1> 인 경우는 찾는 것이 없는 경우.
  //}---------------------------------------------------------------------

  //[VAR]
  //{
      int   i;

  //}

  //[검색]
  //{
      //현재 수집된 [함수라벨] 정보에서 해당 [함수라벨] 을 찾는다.
      for(i = 0; i < pLinkInfoEtc->labelItemCount; i++)
      {
        if(STR_Match(pFuncLabelName, pLinkInfoEtc->labelItems[i].name) == true)
        {
          if(rHexStr != NULL)
          {
            //원하는 것을 찾았으므로 [주소값] 을 [16진수 최소표기문자열] 로 변환하여 반환한다.

            if(p16Digit == true)
            {
              CONV_LongVal_To_Hex(pLinkInfoEtc->labelItems[i].ofsAdr, 16, rHexStr);

            }
            else
            {
              CONV_LongVal_To_Hex2(pLinkInfoEtc->labelItems[i].ofsAdr, rHexStr);

            }

          }

          //찾은 위치를 반환한다.
          return(i);

        }

      }

  //}

  //여기까지 온것은 찾는 것이 없는 것이나, 실제 도달할수 없다.
  if(rHexStr != NULL) { rHexStr[0] = '\0'; }
  return(-1);

}

int __fastcall Link_Get_FuncEndOfsAdrHexStr_withName(struct  LINKINFOETC  *pLinkInfoEtc,
                                                     //찾을때는 [함수라벨] 로 찾는다.
                                                     char   *pFuncLabelName,
                                                     //16자리로 확정해야 하는 경우는 true.
                                                     bool    p16Digit,
                                                     char   *rHexStr)
{
  //[2011.05.24.화][생성!!!]{----------------------------------------------------
  //<Link_Get_FuncOfsAdrHexStr_withName()> 함수를 가지고 만든 것으로
  //단지, [함수라벨] 의 [주소] 가 아니라, 이 [함수라벨] 에 대응하는 [함수끝라벨]
  //주소를 16진수 문자열로 반환한다.
  //
  //찾은 위치를 반환한다.
  //<-1> 인 경우는 찾는 것이 없는 것이다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      int   i;

  //}

  //[검색]
  //{
      //현재 수집된 [함수라벨] 정보에서 해당 [함수라벨] 을 찾는다.
      for(i = 0; i < pLinkInfoEtc->labelItemCount; i++)
      {
        if(STR_Match(pFuncLabelName, pLinkInfoEtc->labelItems[i].name) == true)
        {
          if(rHexStr != NULL)
          {
            //원하는 것을 찾았으므로 [주소값] 을 [16진수 최소표기문자열] 로 변환하여 반환한다.

            if(p16Digit == true)
            {
              //[함수끝라벨] 의 주소--------------------------v
              CONV_LongVal_To_Hex(pLinkInfoEtc->labelItems[i].ofsAdr_fnend, 16, rHexStr);

            }
            else
            {
              //[함수끝라벨] 의 주소---------------------------v
              CONV_LongVal_To_Hex2(pLinkInfoEtc->labelItems[i].ofsAdr_fnend, rHexStr);

            }

          }

          return(i);

        }

      }

  //}

  //여기까지 온것은 찾는 것이 없는 것이나, 실제 도달할수 없다.
  if(rHexStr != NULL) { rHexStr[0] = '\0'; }
  return(-1);

}

//------------------------------------------------------------------------------
//[기본 처리 함수]--------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Link_GetWord(//정보구조체.
                             struct LINKINFO  *prLinkInfo,
                             //지정 단어 순번(BASE : 0).
                             int    pWordXst)
{
  //[2009.02.08.일][생성!!!]{-----------------------------------------------------------------
  //[정보구조체] 를 전달 받아서 현재 정보를 참고하여 해당 순번의 [단어] 를 추출하여 반환한다.
  //현재 행의 시작 index 값등 기본 정보는 전부 [정보구조체] 에 들어 있다.
  //}-----------------------------------------------------------------------------------------

  //[단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      STR_GetLineWordBuf(prLinkInfo->objBuf,
                         prLinkInfo->lineStartIndex,
                         pWordXst,
                         &(prLinkInfo->wordStartIndex),
                         prLinkInfo->word);

  //}

  return;

}

//------------------------------------------------------------------------------
//[최적화 관련 함수]------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Link_Delete_UnUseFunction(//<*.gobj/*.glib> 가 하나로 합성돼있는 저장소 자체 주소를 넘겨받는다.
                                          //내부적으로 [재생성] 되며 다시 [재생성] 공간을 등록해 주어야 하기 때문.
                                          //[재생성] 장소는 같은 크기를 갖는다.
                                          char  **prObjBuf_,
                                          int     pObjBufSize,
                                          //재처리한 문서 전체 크기.
                                          int    *rTotalSize_)
{
  //[2012.06.30.토][생성!!!]{--------------------------------------------------------
  //[가상기계(GVMS/GVMX)] 크기를 최소한으로 줄이기 위하여 [사용되지 않은 함수] 는
  //제거한다.
  //
  //같은 [함수묶음] 안에 존재하더라도 역시 [사용되지 않은 함수] 는 제거한다.
  //즉, 어떤 경우라도 [합성] 된 상태에서 [사용된 함수] 만 남긴다.
  //이는 [한단계] 로 처리할수 없으며 아래의 [두단계] 로 처리.
  //
  //1) <objBuf[]> 에서 먼저 "2d :함수라벨: " 인 행의 ":함수라벨:" 만 수집.
  //   [함수호출] 의 경우로 [사용된 함수] 목록을 얻는다.
  //
  //2) 모든 함수는 아래와 같이 구성되므로 정확하게 영역을 알수 있기 때문에
  //   현재 [함수] 가 [사용된 함수] 가 아니라면 <memmove()> 를 사용하여 [당겨붙이기]
  //   방식으로 <objBuf[]> 내부적으로 제거한다.
  //   즉, 하나의 저장소 안에서 직접 [제거/정리] 하는 방법을 사용한다.
  //
  //   ":함수라벨: "
  //   "2e :함수라벨: ... "  <fnstart>
  //   "..."
  //   "2f "                 <fnend>
  //
  //[부가정보 처리]******************************************************************
  //
  //1) [이동주소(VECTOR)]
  //
  //   "#VECT :main: "
  //   "#VECT :event: "
  //
  //   그대로 복사.
  //
  //2) [문서정보]
  //
  //   "#main.c "
  //
  //   <Link()> 도중에 [함수] 가 어떤 문서에 존재하는지 기록하기 위하여 참고하는
  //   것으로 실제 복사되지 않는다.
  //
  //[주의!!!]************************************************************************
  //<main()>, <event()> 함수는 본체가 존재하면서 [사용되지 않는 함수] 이기는 하나
  //반드시 존재해야 하는 것이므로 어떤 경우라도 [항상 추가] 되어야 한다.
  //이 두 함수는 [미사용함수] 에서 처리 예외가 된다.
  //
  //[주의!!!]------------------------------------------------------------------------
  //반드시 <*.gobj/*.glib> 가 한덩어리로 합성돼 있는 저장소를 전달 받아야 한다.
  //
  //원래 문서보다 [용량] 이 줄어들게 된다.
  //}--------------------------------------------------------------------------------

  //[VAR]
  //{
      //[STRHEAP]
      //{
          //[사용함수라벨] 문자열을 효율적으로 관리하기 위하여 [STRHEAP] 사용.
          struct STRHEAP   strHeap;
          //<strHeap> 에 저장된 문자열 개수를 보관.
          int              itemCount;
          char            *itemStr;

      //}

      //[저장소]
      //{
          char  *orgBuf_ = NULL;
          char  *newBuf_ = NULL;

          //실제 [새저장소] 에 정리되는 문서 크기.
          int   realSize = 0;

      //}

      //[함수라벨] 을 저장하도록 넉넉하게 설정.
      char   funcLabel[256];

      //행시작위치.
      int    lsi = 0;

      int    i;

  //}

  //[STRHEAP]
  //{
      //처음 한번은 반드시 초기화.
      STRHEAP_Init(&strHeap);

      //일단 기본 크기로 생성.
      STRHEAP_Create(&strHeap, d_STRHEAP_Heap_addSize, d_STRHEAP_List_addSize);

  //}

  //[준비]
  //{
      //표기를 단순화.
      orgBuf_ = (*prObjBuf_);

  //}

  //[사용 함수 라벨 얻기]
  //{
      //[!]{---------------------------------------------------------------
      //"2d :함수라벨: "
      //
      //로 행의 첫 3 문자를 비교하여 "2d " 인 경우가 해당하는 것으로 간주.
      //행의 <1st> 에 해당하는 [단어] 가 [사용함수라벨] 이 된다.
      //
      //[문자열 코드] 가 존재할수 있는데 문자열은 [1문자] 인 경우라도 뒤에
      //'\0' 이 붙게 되어 실제는 최소 3바이트 가 되기 때문에 절대 "2d " 와
      //겹칠수가 없다. 따라서 "2d " 로 3바이트만 검사한다.
      //}------------------------------------------------------------------

      //[수집]
      //{
          //[<main/event> 추가]
          //{
              //[2012.07.01.일][중요추가!!!]{*************************************
              //<main()/event()> 함수는 [호출] 할수 없으나 반드시 존재해야 하므로
              //항상 [사용함수] 로 추가하고 시작.
              //}*****************************************************************

              //반환받는 <[등록번호] + 1> 이 현재 저장된 개수가 된다.
              itemCount = STRHEAP_Str_Add(&strHeap, ":event:") + 1;
              itemCount = STRHEAP_Str_Add(&strHeap, ":main:") + 1;

          //}

          lbCollectFuncLabel_Start:

          if((orgBuf_[lsi] == '2') && (orgBuf_[lsi + 1] == 'd') && (orgBuf_[lsi+2] == ' '))
          {
            //[!]{------------------------------
            //[1st:단어] 가 [함수라벨] 에 해당.
            //}---------------------------------

            //[1st:단어] 추출.
            STR_GetLineWordBuf(orgBuf_, lsi, 1, NULL, funcLabel);

            //반환받는 <[등록번호] + 1> 이 현재 저장된 개수가 된다.
            itemCount = STRHEAP_Str_Add(&strHeap, funcLabel) + 1;

          }

          //[다음행 시작위치 얻기]
          //{
              //다음 행 시작위치 얻기.
              if(STR_Get_NextLineStartIndex(orgBuf_, lsi, &lsi) != true)
              {
                //문서 끝에 도달한 경우로 다음 단계로 이동.
                goto lbCollectFuncLabel_End;

              }
              else
              {
                //계속 [사용함수라벨] 추출.
                goto lbCollectFuncLabel_Start;

              }

          //}

          lbCollectFuncLabel_End:

      //}

  //}

  //[<복사> 방식으로 미사용 함수 제거]
  //{
      //[!]{------------------------------------------------------------
      //수집된 [사용함수라벨] 정보를 바탕으로 [미사용 함수라벨] 을 가진
      //함수는 복사하지 않는 방법으로 제거.
      //}---------------------------------------------------------------

      //[새저장소 만들기/초기화]
      //{
          //[!]{----------------------------
          //기존 저장소와 같은 크기로 생성.
          //newBuf_ = new char [pObjBufSize];
          //[동적생성단위적용][2021.01.24.일][수정]
          newBuf_ = new char [UnitX(1024, pObjBufSize)];
          //}-------------------------------

          //<orgBuf_[]> 처음부터 다시 검사 시작.
          lsi = 0;

      //}

      //[복사]
      //{
          //[!]{-----------------------------------------------
          //"#" 문자로 시작하는 행은 항상 복사.
          //':' 문자로 시작하는 행은 [함수라벨] 조건 검사처리.
          //}--------------------------------------------------

          lbCopy:

          if     (orgBuf_[lsi] == '#')
          {
            //[!]{---------------------------
            //1) "#VECT :함수라벨: \r\n"
            //2) "#문서이름\r\n"
            //
            //두가지가 해당되고 그대로 복사.
            //}------------------------------

            //[현재행 복사]
            //{
                realSize += STR_Get_ThisLineStr(orgBuf_, lsi, &(newBuf_[realSize]));
                realSize += STR_Add(&(newBuf_[realSize]), "\r\n");

            //}

            //[다음행 시작위치 얻기]
            //{
                if(STR_Get_NextLineStartIndex(orgBuf_, lsi, &lsi) != true) { goto lbEnd;  }
                else                                                       { goto lbCopy; }

            //}

          }
          else if(orgBuf_[lsi] == ':')
          {
            //[함수 라벨 추출]
            //{
                //[0st:단어] 추출----------------v
                STR_GetLineWordBuf(orgBuf_, lsi, 0, NULL, funcLabel);

            //}

            //[사용된 함수인가?]
            //{
                //[!]{------------------------------------------------------------
                //이 함수 첫 부분에서 수집된 [사용 함수 라벨] 에 해당하는지 확인.
                //}---------------------------------------------------------------

                for(i = 0; i < itemCount; i++)
                {
                  //[사용 함수 라벨] 하나 얻기.
                  itemStr = STRHEAP_Str_Ptr(&strHeap, i);

                  if(STR_Match(funcLabel, itemStr) == true) goto lbFuncLabelCopy;

                }

                //[!]{-------------------------------------------------
                //여기까지 온것은 현재 [함수라벨] 이 [미사용] 인 경우.
                //}----------------------------------------------------

                //[다음행 시작위치 얻기]
                //{
                    if(STR_Get_NextLineStartIndex(orgBuf_, lsi, &lsi) != true) { goto lbEnd;  }

                //}

                goto lbCopy;

            //}

            lbFuncLabelCopy:

            //[함수 라벨 복사]
            //{
                realSize += STR_Get_ThisLineStr(orgBuf_, lsi, &(newBuf_[realSize]));
                realSize += STR_Add(&(newBuf_[realSize]), "\r\n");

            //}

            lbFuncCopy:

            //[다음행 시작위치 얻기]
            //{
                if(STR_Get_NextLineStartIndex(orgBuf_, lsi, &lsi) != true) { goto lbEnd;  }

            //}

            //[계속 함수 안인가?]
            //{
                //[!]{------------------------------------------------------------------------------
                //현재 행 첫문자가 '#', ':' 문자라면 [함수복사] 는 완료한 것으로 본다.
                //아니라면 계속 [함수복사] 수행.
                //이는 [함수] 안에서 [문자열] 을 사용한 경우 이 [문자열 코드] 까지 복사하기 위한것.
                //}---------------------------------------------------------------------------------

                if     ((orgBuf_[lsi] == '#') || (orgBuf_[lsi] == ':')) { goto lbCopy; }
                else if(orgBuf_[lsi] == '\0')                           { goto lbEnd;  }

            //}

            //[함수 관련 복사]
            //{
                realSize += STR_Get_ThisLineStr(orgBuf_, lsi, &(newBuf_[realSize]));
                realSize += STR_Add(&(newBuf_[realSize]), "\r\n");

            //}

            //계속 함수 내부 복사.
            goto lbFuncCopy;

          }
          else if(orgBuf_[lsi] == '\0')
          {
            //[중요!!!]{-----------------------------------------------------------------
            //<*.c> 문서 안에 아무 내용이 없는 경우는 <*.gobj> 도 아무 내용이 없으므로
            //':' 로 시작하는 것이 하나도 없을수 있으며 이경우는 반드시 '\0' 로 [문서끝]
            //인 경우가 해당하므로 반드시 처리해 준다.
            //}--------------------------------------------------------------------------

            goto lbEnd;

          }
          else
          {
            //[다음행 시작위치 얻기]
            //{
                if(STR_Get_NextLineStartIndex(orgBuf_, lsi, &lsi) != true) { goto lbEnd;  }

            //}

            goto lbCopy;

          }

      //}

  //}

  lbEnd:

  //[STRHEAP:삭제]
  //{
      STRHEAP_Delete(&strHeap);

  //}

  //[저장소 삭제/교체/부가처리]
  //{
      //[!]{------------------------
      //1) 새 저장소를 등록하고
      //2) 기존 원본 저장소는 삭제.
      //}---------------------------

      //원본 삭제.
      if(orgBuf_ != NULL) { delete [] orgBuf_; orgBuf_ = NULL; }

      //[새저장소] 등록.
      (*prObjBuf_) = newBuf_;

      if(rTotalSize_ != NULL) { (*rTotalSize_) = realSize; }

  //}

}



