. 확장자 연결

문법강조 기능은 ApiEdit와 분석기의 협조에 의해 구현되며 호스트 프로그램은 거의 관여하지 않는다. 호스트가 문법강조와 관련해서 제공하는 유일한 기능은 문서가 열릴 때 어떤 문법을 적용할 것인지를 자동으로 선택하는 것이다. ApiEdit는 문서를 문자열 덩어리로만 인식할 뿐 파일에 대해서는 모르기 때문에 분석기를 선택하는 작업은 호스트가 해야 한다.

호스트는 파일을 열 때 확장자를 보고 적절한 분석기를 선택한다. 확장자가 .cpp .h이면 이 파일을 C 언어 소스로 인식하고 htm이나 html이면 웹 문서 파일로 인식하는 것이다. 윈도우즈는 파일의 종류 구분을 위해 별도의 표식을 달지 않으므로 확장자 이외에는 파일의 문법을 판단할 수 있는 근거가 전혀 없다. 확장자 연결 상태도 전역 옵션이므로 SOption 구조체에 기억시킨다. SOption에 다음 배열을 추가한다.

 

struct SOption

{

     ....

     TCHAR arExt[4][250];

};

 

각 분석기별로 연결된 확장자 목록을 문자열로 정의한다. 현재 총 4개의 분석기를 계획하고 있으므로 배열크기를 4로 하였다. 0번은 기본 분석기인데 기본 분석기는 나머지 분석기가 처리하지 않는 모든 파일을 처리하므로 연결될 확장자를 별도로 가지지 않는다. 결국 0번 첨자는 버리는 셈이다. 이 배열은 Util.cpp에서 다음과 같이 초기화한다.

 

void SOption::Init()

{

     ....

     lstrcpy(arExt[0],"");

     lstrcpy(arExt[1],"c;cpp;h;hpp");

     lstrcpy(arExt[2],"html;htm;asp;php");

     lstrcpy(arExt[3],"sql");

};

 

1번 분석기와 연결되는 확장자는 c,cpp,h,hpp 네 가지라는 뜻이다. 이 배열값도 어디까지나 초기값에 불과하며 사용자에 의해 변경될 수 있다. 호스트는 파일을 열 때 파일의 확장자가 어떤 배열에 속하는지 보고 적절한 분석기를 선택해야 한다. Dangeun.cpp에 다음 함수를 추가한다.

 

void SelectParser(CApiEdit &Ae,TCHAR *path)

{

     TCHAR ext[_MAX_EXT];

     int i;

     int ID=0;

 

     _splitpath(path,NULL,NULL,NULL,ext);

     CharLower(ext);

     for (i=1;i<=3;i++) {

          if (strstr(Option.arExt[i],ext+1)!=0) {

              ID=i;

              break;

          }

     }

 

     Ae.SetParser(ID);

}

 

이 함수는 파일의 확장자로부터 분석기를 선택한다. 0번 분석기가 디폴트이므로 ID 0으로 초기화하였다. 열고자 하는 파일의 확장자를 조사한 후 이 확장자와 연결된 분석기를 조사한다. 연결된 분석기가 없으면 ID의 디폴트값인 0이 그대로 적용되어 기본 분석기가 선택되며 문법강조를 하지 않는다. 연결된 분석기를 찾으면 그 분석기의 ID로부터 ApiEdit SetParser 함수를 호출하여 분석기를 선택한다.

연결될 확장자 목록을 분석기가 정의할 수 있다면 더 좋을 것 같다. GetInfo 함수로 확장자의 목록을 조사할 수 있도록 하고 호스트는 분석기의 GetInfo 함수를 호출하여 이 문서를 처리할 수 있는지 질문하면 된다. 임의의 확장자 abc가 있을 때 분석기를 순회하면서 ! 이거 니 거야? 하면서 질문을 던지다가 그 중 한 분석기가 그거 제 건데요라는 응답을 하면 그 분석기를 선택하면 된다. 아무도 응답하지 않으면 기본 분석기가 선택될 것이다.

과연 좋은 생각이기는 하지만 현재 구조에서는 분석기를 일일이 동적으로 생성해야만 하는 큰 문제가 있어 실제 적용하기가 어렵다. 분석기가 20개 정도 되면 모든 분석기를 생성, 해제하면서 확장자를 조사해야 하는데 시간이 너무 많이 걸리기 때문이다. 그래서 불가피하게 호스트가 확장자와 분석기의 연결 관계를 가지도록 하였다.

이 함수는 OpenFileToChild 함수에서 파일을 열 때 호출한다. 파일열기에 성공하면 이 파일을 분석하기 위한 적절한 분석기를 생성하며 파일이 화면에 출력되기 전에 분석기가 동작하여 문법을 분석해놓을 것이다.

 

BOOL OpenFileToChild(HWND hChild, TCHAR *Path)

{

     ....

    SelectParser(pSi->Ae,Path);

     pSi->Ae.InitDoc();

     ....

 

새 파일에 이름을 주고 저장할 때도 사용자가 입력한 파일명으로부터 적절한 분석기를 선택해야 한다. 예를 들어 이름없음 12를 작성한 후 index.html로 저장한다면 이제부터 이 파일은 HTML로 분석해야 한다. SaveAs 함수에 다음 코드를 추가한다.

 

BOOL SaveAs(HWND hChild)

{

     ....

    SelectParser(pSi->Ae,OFN.lpstrFile);

     Mru.AddMRU(OFN.lpstrFile);

     lstrcpy(pSi->NowFile,OFN.lpstrFile);

     SetWindowText(hChild,pSi->NowFile);

     return TRUE;

}

 

분석기의 종류가 더 많이 늘어나면 SOption 구조체의 arExt 배열을 늘려 주고 ApiEdit SetParser 함수를 확장하면 된다.