//*****************************************************************************
// SrcToHtmlPre.cpp
//      C, C++ のソースのコメント行やキーワードをカラー表示するためのHTMLタグを生成。
//      呼ぶ手順は(HTMLファイルの生成手順)は、末尾の example を参照
//      キーワードの種類やチェック方法(/* */も含めて)は、厳密なものではありません。
//*****************************************************************************

#include "stdafx.h"

int SrcToHtmlPre( const char* ps , char* pd , int slen ) ;
BYTE* SearchTextSimple( BYTE* hStartP , int blen , LPCSTR lpszFind, BOOL bNext, BOOL bCase ) ;
int IsKeyword( const char* pb , int slen ) ;

#define MAXCCPPKEYWORDLEN       25

struct ccppkeywordtblstruct {
    int len ;
    BYTE str[MAXCCPPKEYWORDLEN+1] ;
} ;

static struct ccppkeywordtblstruct cppktbl[] = {
    {5,"__asm"} , {10,"__fastcall"} , {6,"__self"} , {4,"auto"} , {5,"float"} , {9,"__segment"} ,
    {7,"__based"} , {3,"for"} , {9,"__segname"} , {5,"break"} , {9,"__fortran"} , {5,"short"} ,
    {4,"case"} , {4,"goto"} , {6,"signed"} , {7,"__cdecl"} , {6,"__huge"} , {6,"sizeof"} ,
    {4,"char"} , {2,"if"} , {6,"static"} , {5,"const"} , {8,"__inline"} , {6,"struct"} , {8,"continue"} ,
    {3,"int"} , {6,"switch"} , {7,"default"} , {11,"__interrupt"} , {7,"typedef"} ,{2,"do"} ,
    {8,"__loadds"} , {5,"union"} , {6,"double"} , {4,"long"} , {8,"unsigned"} , {4,"else"} ,{6,"__near"} ,
    {4,"void"} , {4,"enum"} , {8,"__pascal"} , {8,"volatile"} , {8,"__export"} , {8,"register"} ,
    {5,"while"} , {6,"extern"} , {6,"return"} , {5,"__far"} , {10,"__saveregs"} , {7,"#define"} ,
    {6,"#error"} , {8,"#include"} , {5,"#elif"} , {3,"#if"} , {5,"#line"} , {5,"#else"} ,{6,"#ifdef"} ,
    {7,"#pragma"} , {6,"#endif"} , {7,"#ifndef"} , {6,"#undef"} ,
    {6,"_based"} , {8,"_segname"} , {7,"fortran"} , {8,"_fortran"} , {6,"_cdecl"} , {5,"cdecl"} ,
    {4,"huge"} , {5,"_huge"} , {7,"_inline"} , {9,"interrupt"} , {10,"_interrupt"} , {7,"_loadds"} ,
    {4,"near"} , {5,"_near"} , {6,"pascal"} , {7,"_pascal"} , {7,"_export"} , {3,"far"} , {4,"_far"} ,
    {9,"_saveregs"} , 
    {5,"class"} , {8,"operator"} , {3,"try"} , {6,"delete"} , {7,"private"} , {7,"virtual"} ,
    {6,"friend"} , {9,"protected"} , {22,"__multiple_inheritance"} , {6,"inline"} , {6,"public"} ,
    {20,"__single_inheritance"} , {3,"new"} , {4,"this"} , {21,"__virtual_inheritance"}

} ;

//*****************************************************************************
// 機能 :c, c++ のソースのコメント行やキーワードをカラー表示するためのHTMLタグを生成
//  注意  :ps[slen]はアクセス可能前提
//          呼ぶ手順は(HTMLファイルの生成手順)は、末尾の example を参照
//*****************************************************************************
int SrcToHtmlPre( const char* ps , char* pd , int slen ) 
{
    int i ;
    int j ;
    for ( i = 0 , j = 0 ; i < slen ; )
    {
        BYTE bt = (BYTE)ps[i] ;

        if ( _ismbblead( bt ) )
        {   
            pd[j++] = ps[i++] ;
            pd[j++] = ps[i++] ;
            continue ;

        }

        BYTE nt = (BYTE)ps[i+1] ;
        
        if ( bt == '/' && nt == '/' )
        {
            CString wstr = "<span class=\"lc\">//" ;
            strcpy( pd+j , (const char*)wstr ) ;
            j += wstr.GetLength( ) ;
            i += 2 ;
            
            BYTE* bp = SearchTextSimple( (BYTE*)(&ps[i]) , slen-i , "\r", TRUE , TRUE ) ;
                
            if ( bp == NULL )
            {
                memcpy( pd+j , (BYTE*)(&ps[i]) , slen-i ) ;
                j += slen-i ;

                CString wstr = "</span>" ;
                strcpy( pd+j , (const char*)wstr ) ;
                j += wstr.GetLength( ) ;

                break ;

            }
            else
            {
                int wlen = bp - (BYTE*)(&ps[i]) ;
                memcpy( pd+j , (BYTE*)(&ps[i]) , wlen ) ;
                j += wlen ;

                CString wstr = "</span>" ;
                strcpy( pd+j , (const char*)wstr ) ;
                j += wstr.GetLength( ) ;

                i += wlen ;

            }

        }
        else if ( bt == '/' && nt == '*' )
        {
            CString wstr = "<span class=\"mc\">/*" ;
            strcpy( pd+j , (const char*)wstr ) ;
            j += wstr.GetLength( ) ;
            i += 2 ;
            
            BYTE* bp = SearchTextSimple( (BYTE*)&ps[i] , slen-i , "*/", TRUE , TRUE ) ;
                
            if ( bp == NULL )
            {
                memcpy( pd+j , &ps[i] , slen-i ) ;
                j += slen-i ;

                CString wstr = "</span>" ;
                strcpy( pd+j , (const char*)wstr ) ;
                j += wstr.GetLength( ) ;

                break ;

            }
            else
            {
                int wlen = bp - (BYTE*)(&ps[i]) ;
                memcpy( pd+j , (const char*)(&ps[i]) , wlen+2 ) ;
                j += wlen+2 ;

                CString wstr = "</span>" ;
                strcpy( pd+j , (const char*)wstr ) ;
                j += wstr.GetLength( ) ;

                i += wlen + 2 ;

            }

        }
        else if ( i == 0 || bt == ' ' || bt == '(' || bt == '\t' || bt == '\n' )
        {
            if ( i != 0 )   
                pd[j++] = ps[i++] ;

            int klen = IsKeyword( &ps[i] , slen-i ) ;

            if ( klen == 0 )
                continue ;

            CString wstr = "<span class=\"kw\">" ;
            strcpy( pd+j , (const char*)wstr ) ;
            j += wstr.GetLength( ) ;

            memcpy( pd+j , (const char*)(&ps[i]) , klen ) ;
            j += klen ;
            i += klen ;

            wstr = "</span>" ;
            strcpy( pd+j , (const char*)wstr ) ;
            j += wstr.GetLength( ) ;

        }
        else
        {
            pd[j++] = ps[i++] ;

        }

    }

    return j ;

}


//*****************************************************************************
// 機能 : 指定範囲の中で文字列を検索する。
//  戻り値: 見つかった文字列位置へのポインタ、NULLのときは見つからなかったことを意味する。
//*****************************************************************************
BYTE* SearchTextSimple( BYTE* hStartP , int blen , LPCSTR lpszFind, BOOL bNext, BOOL bCase )
{
    int ret ;
    BYTE* hpszFound ;

    hpszFound = NULL ;
    UINT nLenSearch = lstrlen(lpszFind);

    ASSERT( nLenSearch > 0 ) ;          // 0 だと != NULLで戻ってしまう?!!! 

    int  nChFind ;
    if ( _ismbblead( (BYTE)(*lpszFind) ) )
        nChFind = 2 ;
    else
        nChFind = 1 ;

    BYTE* hStopP = hStartP + blen - nLenSearch + 1 ;
    if ( hStartP >= hStopP || blen < nChFind )
        return NULL ;


    BYTE* hpsz = hStartP ;
    BYTE* hpszStop = hStopP ;
    
    for ( ; hpsz < hpszStop ; )
    {
        if ( bCase )
            ret = memcmp( (BYTE*)hpsz , lpszFind , nChFind ) ;
        else
            ret = _mbsnbicmp( (const BYTE*)hpsz , (const BYTE*)lpszFind , nChFind ) ;

        if ( ret == 0 )
        {
            if ( bCase )
                ret = memcmp( (BYTE*)hpsz , lpszFind , nLenSearch ) ;
            else
                ret = _mbsnbicmp( (const BYTE*)hpsz , (const BYTE*)lpszFind , nLenSearch ) ;

            if ( ret == 0 )
            {
                hpszFound = hpsz ;
                if ( bNext )
                    break ;
            }
        }

        if ( _ismbblead( (BYTE)(*hpsz) ) )
            hpsz += 2 ;
        else
            hpsz += 1 ;
    }
    return hpszFound ;
}

//*****************************************************************************
// 機能 :
//*****************************************************************************
int IsKeyword( const char* pb , int slen )
{
    int kcount = sizeof(cppktbl)/sizeof(struct ccppkeywordtblstruct) ;

    int klen = 0 ;

    int i ;
    for ( i = 0 ; i < kcount ; i++ )
    {
         klen = cppktbl[i].len ;

        if ( klen > slen )
            continue ;

        if ( strncmp( pb , (const char*)cppktbl[i].str , klen ) == 0 )
            break ;

    }

    if ( i == kcount )
        return 0 ;

    if ( klen == slen )
        return klen ;

    BYTE bt = (BYTE)pb[klen] ;

    if ( bt == ' ' || bt == ')' || bt == '*' )
        return klen ;

    CString fstr = (const char*)(cppktbl[i].str) ;

    if ( bt == ':' && ( fstr == "private" || fstr == "protected" || fstr == "public" ) )
        return klen ;

    return FALSE ;

}


//*****************************************************************************
// SrcToHtmlPre.cpp : Ver1.00  2006/12/29
// Example :
//
/*
void CMainFrame::OnDropFiles(HDROP hDropInfo)
{
    // TODO : ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。

//  CMDIFrameWnd::OnDropFiles(hDropInfo);

    SetActiveWindow();      // activate us first !

    UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);

    nFiles = 1 ;

    CString path = "" ;
    TCHAR szFileName[_MAX_PATH];

    for (UINT iFile = 0; iFile < nFiles; iFile++)
    {
        ::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);

        path = (const char*)szFileName ;

    }

    ::DragFinish(hDropInfo);

    CString mstr = path ;
    mstr += "\n  を変換しますが、よろしいですか?" ;

    if ( AfxMessageBox( (const char*)mstr , MB_OKCANCEL ) != IDOK )
        return ;

    int dlen ;  
    BYTE* ps = W_ReadTheFileEx( (const char*)path , 1024*1024*20 , (DWORD*)&dlen ) ;

    if ( ps == NULL )
        return ;

    CString ostr = MakeStr( ps , dlen ) ;

    delete ps ;

    int result ;

    CString findstr = "<" ;
    CString newstr = "&lt;" ;
    CString tstr = ReplaceStrUniFast( ostr , findstr , newstr , &result ) ;

    findstr = ">" ;
    newstr = "&gt;" ;
    tstr = ReplaceStrUniFast( tstr , findstr , newstr , &result ) ;

    BYTE* pd = W_GetUserBuf( dlen * 3 + 20*1024  ) ;

    int nlen = SrcToHtmlPre( (const char*)tstr , (char*)pd , tstr.GetLength( ) ) ;

    if ( nlen <= 0 || nlen > 1024*1024*40 )
    {
        delete pd ;

        return ;
    }

    ostr = "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n<title></title>\r\n<link href=\"sstyle.css\" rel=\"stylesheet\" type=\"text/css\">\r\n</head>\r\n\r\n<body>\r\n<pre>\r\n" ;

    tstr = MakeStr( pd , nlen ) ;

    ostr += tstr ;
    
    ostr += "</pre>\r\n</body>\r\n</html>" ;

    CString fname = GetFileTitlePart( path ) ;
    CString outpath = "D:\\HomePage\\src\\" ;
    outpath += fname ;
    outpath += ".html" ;

    W_WriteTheFile( (const char*)outpath , (BYTE*)(const char*)ostr , ostr.GetLength( ) ) ;

    delete pd ;
}
*/
//  補足 :
//    W_ReadTheFileEx, MakeStr, GetFileTitlePart, W_WriteTheFile, W_GetUserBuf, ReplaceStrUniFast は、
//          ローカルな関数です。
//    InitInstanceで pMainFrame->DragAcceptFiles(); でDropも有効にしておくこと。
//    元のソースファイルのタブは、エディタで空白に変換しておくこと(さもないと、ブラウザ表示でずれる)
//
//   sstyle.cssファイルの内容例 --- 上の例では、D:\HomePage\src に置いておく必要があります。
//          .lc { color: green; }
//          .mc { color: green; }
//          .kw { color: blue; }
//
// Copyright(C) Edcom Inc. (http://www.edcom.jp/) All rights reserved. 
//*****************************************************************************