Last Update: Oct.5,2001

C Source Library

「LSI C-86 Ver.3.30c 試食版」、「Borland C++ 5.5」、「Microsoft Visual C++ 6.0」でコンパイル出来ます。

■ CソースをHTML化するサンプル(旧版)→新版はこちら

/*
 *  c2html.c : CソースをHTML化する
 *
 *  Copyright (c) 2000, 2001 AOK. 
 *  
 *      2000/04/01 - 初版
 *      2001/10/03 - 10版
 *
 *      使い方: C2HTML ファイル名
 *  
 *  出力されるHTMLファイル名は内部で作成される(.c → .htm)
 *  同名のファイルがあると上書きされてしまう(^-^;)
 *
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* HTMLのカラーを指定 */
const char *color_keyword = "blue";
const char *color_comment = "red";
const char *color_string  = "teal";

#ifndef LSI_C /* Borland C++ 5.5 */
    #include <mbctype.h>
    #include <mbstring.h>
    #define chkctype(x, y)  _mbbtype(x, y)
    #define CT_ANK          _MBC_SINGLE
    #define CT_KJ1          _MBC_LEAD
    #define CT_KJ2          _MBC_TRAIL
    #define CT_ILGL         _MBC_ILLEGAL
#else /* LSI C-86 */
    #include <jctype.h>
#endif

typedef int (*FPTR)(const void*, const void*);

#define BUFLEN      127
#define TABWIDTH    4
    
#define AL_NON      0
#define AL_COM      1
#define AL_STR      2
#define AL_CHR      3

#define NUM_OF_ARR(x)   (sizeof(x)/sizeof(x[0]))
    
char key[][10] = {  /* 昇順に並べておく */
    "#define","#elif","#else","#endif","#error","#if","#ifdef",
    "#ifndef","#import","#include","#line","#pragma","#undef",
    "auto","break","case","char","const","continue","default",
    "do","double","else","enum","extern","float","for","goto",
    "if","int","long","register","return","short","signed",
    "sizeof","static","struct","switch","typedef","union",
    "unsigned","void","volatile","while" };
    
/* 拡張子の付け替え */
int change_ext(char *fname)
{
    char *p;
    int len;
    len = strlen(fname);
    p = strrchr(fname, '.');
    if (len >= 3 && len <= FILENAME_MAX-2 && p != NULL)
    {
        if (strcmpi(p, ".c") == 0 || strcmpi(p, ".h") == 0)
            strcpy(p, ".htm");
        else
        {
            *fname = '\0';
            puts("入力ファイルはCソースではありません.");
            return 0;
        }
    }
    else
    {
        *fname = '\0';
        puts("拡張子の付け替えが出来ません.");
        return 0;
    }
    return 1;
}

/* 予約語かどうか(2分探索) */
int check_keyword(char *c)
{
    return (bsearch(c, key, NUM_OF_ARR(key), sizeof(key[0]), (FPTR)strcmp) != NULL);
}

/* バッファの書き出し */
void empty_buffer(char buf[], int align, FILE *fp)
{
    if (buf[0]=='\0') return;
    if (align == AL_NON && check_keyword(buf))
    {
        fprintf(fp, "<font color=\"%s\">", color_keyword);
        fputs(buf, fp);
        fputs("</font>", fp);
    }
    else
        fputs(buf, fp);    
    buf[0] = '\0';
}

/* バッファへ1文字入れる */
void input_buffer(char buf[], char c)
{
    int len;
    len = strlen(buf);
    buf[len] = c;
    buf[len+1] = '\0';
}

/* タブをスペースに変換 */
void fill_space(int n, FILE *fp)
{
    int num, i;
    num = TABWIDTH - n % TABWIDTH;
    for (i = 0; i < num; i++)
        putc(' ', fp);
}

/* 変換の本体 */
void convert(FILE *fin, FILE *fout)
{
    int n, len, mode = 0;
    char ch;
    char buf[BUFLEN+1];
    int align = AL_NON, col = 0;
    
    buf[0] = '\0';
    
    while ((n = getc(fin)) != EOF)
    {
        ch = (char)n;
        mode = chkctype(ch, mode);
        if (mode == CT_ANK || mode == CT_ILGL)
        {
            switch (ch)
            {
            case '\"':
                switch (align)
                {
                case AL_NON:
                    empty_buffer(buf, align, fout);
                    fprintf(fout, "<font color=\"%s\">", color_string);
                    fputs("&quot;", fout);
                    align = AL_STR;
                    break;
                case AL_STR:
                    if (strcmp(buf, "\\") != 0)
                    {
                        empty_buffer(buf, align, fout);
                        fputs("&quot;", fout);
                        fputs("</font>", fout);
                        align = AL_NON;
                    }
                    else
                    {
                        empty_buffer(buf, align, fout);
                        fputs("&quot;", fout);
                    }
                    break;
                default:
                    empty_buffer(buf, align, fout);
                    fputs("&quot;", fout);
                    break;
                }
                break;
            case '\'':
                switch (align)
                {
                case AL_NON:
                    empty_buffer(buf, align, fout);
                    fprintf(fout, "<font color=\"%s\">", color_string);
                    fputs("\'", fout);
                    align = AL_CHR;
                    break;
                case AL_CHR:
                    if (strcmp(buf, "\\") != 0)
                    {
                        empty_buffer(buf, align, fout);
                        fputs("\'", fout);
                        fputs("</font>", fout);
                        align = AL_NON;
                    }
                    else
                    {
                        empty_buffer(buf, align, fout);
                        fputs("\'", fout);
                    }
                    break;
                default:
                    empty_buffer(buf, align, fout);
                    fputs("\'", fout);
                    break;
                }
                break;
            case '/':
                if (align == AL_COM && strcmp(buf, "*") == 0)
                {
                    align = AL_NON;
                    empty_buffer(buf, align, fout);
                    putc(ch, fout);
                    fputs("</font>", fout);
                }
                else
                {
                    empty_buffer(buf, align, fout);
                    input_buffer(buf, ch);
                }
                break;
            case '*':
                if (align == AL_NON && strcmp(buf, "/") == 0)
                {
                    align = AL_COM;
                    fprintf(fout, "<font color=\"%s\">", color_comment);
                    empty_buffer(buf, align, fout);
                    putc(ch, fout);
                }
                else
                {
                    empty_buffer(buf, align, fout);
                    input_buffer(buf, ch);
                }
                break;
            case '\\':
                if (strcmp(buf, "\\") == 0)
                {
                    empty_buffer(buf, align, fout);
                    putc(ch, fout);
                }
                else
                {
                    empty_buffer(buf, align, fout);
                    input_buffer(buf, ch);
                }
                break;
            case '\n':
                col = -1;
            case '\t': case ' ':
            case '+': case '-': case '%': case '|': case '=': case '!':
            case '(': case ')': case '{': case '}': case '[': case ']':
            case ',': case ':': case ';': case '&': case '>': case '<':
                if (buf[0] == '*')
                {
                    putc('*', fout);
                    strcpy(buf, buf+1);
                }
                else if (buf[0] == '/')
                {
                    putc('/', fout);
                    strcpy(buf, buf+1);
                }
                empty_buffer(buf, align, fout);
                
                if (ch == '\t')
                {
                    fill_space(col, fout);
                    col = -1;
                }
                else if (ch == '&')
                    fputs("&amp;", fout);
                else if (ch == '>')
                    fputs("&gt;", fout);
                else if (ch == '<')
                    fputs("&lt;", fout);
                else
                    putc(ch, fout);
                break;
            default:
                len = strlen(buf);
                if (len > BUFLEN-1)
                    empty_buffer(buf, align, fout);
                input_buffer(buf, ch);
                break;
            }
        }
        else if (mode == CT_KJ1 || mode == CT_KJ2)
        {
            empty_buffer(buf, align, fout);
            putc(ch, fout);
        }
        col++;
    }

    /* バッファに溜まっている文字列の処理 */
    empty_buffer(buf, align, fout);
}

/* プログラムのエントリポイント */
int main(int argc, char *argv[])
{
    char fname[FILENAME_MAX+1];
    FILE *fin, *fout;
    
    /* コマンドライン引き数のチェック */
    if (argc >= 2)
    {
        strncpy(fname, argv[1], FILENAME_MAX);
        fname[FILENAME_MAX] = '\0';
    }
    else
    {
        puts("パラメータが足りません.\n\n使い方: C2HTML ファイル名");
        exit(EXIT_FAILURE);
    }
    
    /* 入出力ファイルをオープン */
    printf("入力ファイル名: %s\n", fname);
    if ((fin = fopen(fname, "r")) == NULL)
    {
        perror("入力ファイルをオープン出来ません.\n");
        exit(EXIT_FAILURE);
    }
  
    if (change_ext(fname) == 0) /* 拡張子の付け替え */
    {
        fclose(fin);
        exit(EXIT_FAILURE);
    }
    
    printf("出力ファイル名: %s\n", fname);
    if ((fout = fopen(fname, "w")) == NULL)
    {
        perror("出力ファイルをオープン出来ません.\n");
        fclose(fin);
        exit(EXIT_FAILURE);
    }
    
    /* 変換実行 */
    fputs("<html>\n<head>\n", fout);
    fputs("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=Shift_JIS\">\n", fout);
    fputs("<meta name=\"GENERATOR\" content=\"C2HTML (c)2000,2001 AOK\">\n", fout);
    fputs("</head>\n<body>\n<pre>", fout);
    convert(fin, fout);   /* 変換の本体 */
    fputs("</pre>\n</body>\n</html>", fout);

    /* 入出力ファイルをクローズ */
    fclose(fin);
    fclose(fout);
    
    puts("\n*** 変換に成功しました.");

    return 0;
}