■ C/C++ ソースを HTML 化する
/*
* c2htmlx.c : C/C++ ソースを HTML 化する
*
* Copyright (c) 2001, 2005, 2006 AOK.
*
* 2001/10/05 - 初版
* 2001/10/14 - 2 版
* 2005/10/19 - 3 版
* 2006/11/03 - 4 版(css)
* 2006/11/29 - 5 版
* 2006/12/02 - 6 版(C++ 拡張)
*
* 使い方: C2HTMLX ファイル名
*
* 出力される HTML ファイル名は内部で生成される(.c → .htm)
* 同名のファイルがあると上書きされてしまう(^-^;)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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
#else /* LSI C-86 */
#include <jctype.h>
#endif
int tabw = 4; /* タブの幅 */
const char *tag_com = "<span class='color_comment'>";
const char *tag_key = "<span class='color_keyword'>";
const char *tag_str = "<span class='color_string'>";
const char *tag_end = "</span>";
int col = -1, error = 0;
char chbuf;
FILE *fin, *fout;
typedef int (*FPTR)(const void*, const void*);
#define BUFLEN 127
#define NUM_OF_ARR(x) (sizeof(x)/sizeof(x[0]))
const char key[][17] = { /* 昇順に並べておく */
"#define","#elif","#else","#endif","#error",
"#if","#ifdef","#ifndef","#import","#include",
"#line","#pragma","#undef","#using","auto",
"bool","break","case","catch","char",
"class","const","const_cast","continue","default",
"delete","do","double","dynamic_cast","else",
"enum","explicit","export","extern","false",
"float","for","friend","goto","if",
"inline","int","long","mutable","namespace",
"new","operator","private","protected","public",
"register","reinterpret_cast","return","short","signed",
"sizeof","static","static_cast","struct","switch",
"template","this","throw","true","try",
"typedef","typeid","typename","union","unsigned",
"using","virtual","void","volatile","wchar_t",
"while" };
/* 1文字取ってくる */
int getnext(void)
{
int n;
if ((n = getc(fin)) == EOF)
{
error++;
return 0;
}
chbuf = (char)n;
col++;
return 1;
}
/* 1文字戻す */
int ungetnext(char c)
{
if (ungetc(c, fin) == EOF)
{
error++;
return 0;
}
if (--col < 0) col = tabw - 1;
return 1;
}
/* 予約語かどうか(2分探索) */
int check_keyword(char *c)
{
return (bsearch(c, key, NUM_OF_ARR(key),
sizeof(key[0]), (FPTR)strcmp) != NULL);
}
/* バッファへ1文字入れる */
void input_buffer(char buf[], char c)
{
int len;
len = strlen(buf);
buf[len] = c;
buf[len+1] = '\0';
}
/* タブをスペースに変換 */
void fillspace(void)
{
int num;
num = tabw - col % tabw;
/* printf("(%2ld,%2ld) ", col, num); */
while (num-- > 0) putc(' ', fout);
col = -1;
}
/* 標準の書き出し */
void normal(void)
{
switch (chbuf)
{
case '\t': fillspace(); break;
case '>': fputs(">", fout); break;
case '<': fputs("<", fout); break;
case '&': fputs("&", fout); break;
case '\"': fputs(""", fout); break;
case '\n': col = -1;
default: putc(chbuf, fout); break;
}
}
/* コメント文 */
void comment(void)
{
fprintf(fout, "%s/*", tag_com);
while (getnext())
{
if (chbuf == '*')
{
putc(chbuf, fout);
if (!getnext()) return;
if (chbuf == '/')
{
fprintf(fout, "/%s", tag_end);
return;
}
else if (chbuf == '*')
ungetnext(chbuf);
else
normal();
}
else normal();
}
}
void comment_cpp(void)
{
fprintf(fout, "%s//", tag_com);
while (getnext())
{
if (chbuf == '\n')
{
fprintf(fout, "%s", tag_end);
normal();
return;
}
else normal();
}
}
/* 文字列定数 */
void string(void)
{
int escape = 0, mode = CT_ANK;
fprintf(fout, "%s"", tag_str);
while (getnext())
{
mode = chkctype(chbuf, mode);
if (mode == CT_KJ1 || mode == CT_KJ2)
{
escape = 0;
putc(chbuf, fout);
}
else
{
if (escape == 0 && chbuf == '\"')
{
fprintf(fout, ""%s", tag_end);
return;
}
else if (chbuf == '\\')
{
escape = (escape == 0 ? 1 : 0);
putc(chbuf, fout);
}
else
{
escape = 0;
normal();
}
}
}
}
/* 文字定数 */
void character(void)
{
int escape = 0;
fprintf(fout, "%s'", tag_str);
while (getnext())
{
if (escape == 0 && chbuf == '\'')
{
fprintf(fout, "'%s", tag_end);
return;
}
else if (chbuf == '\\')
{
escape = (escape == 0 ? 1 : 0);
putc(chbuf, fout);
}
else
{
escape = 0;
normal();
}
}
}
/* 予約語を探す */
void symbol(void)
{
char buf[BUFLEN+1];
buf[0] = '\0';
input_buffer(buf, chbuf);
if (!getnext())
{
fputs(buf, fout);
return;
}
while (isalnum(chbuf) || chbuf == '_' || chbuf=='.')
/* '.' は構造体や float.h 対策 */
{
input_buffer(buf, chbuf);
if (!getnext()) break;
}
if (check_keyword(buf))
{
fprintf(fout, "%s%s%s", tag_key, buf, tag_end);
/* printf("%s, ", buf); */
}
else fputs(buf, fout);
if (!error) ungetnext(chbuf);
}
/* 最初の文字を判定して処理を分岐する */
void getsym(void)
{
if (!getnext()) return;
if (chbuf == '/')
{
if (!getnext())
{
putc('/', fout);
return;
}
if (chbuf == '*')
comment();
else if (chbuf == '/')
comment_cpp();
else
{
putc('/', fout);
ungetnext(chbuf);
}
}
else if (chbuf == '\"') string();
else if (chbuf == '\'') character();
else if (isalnum(chbuf) || chbuf == '_' || chbuf == '#') symbol();
else normal();
}
/* 拡張子の付け替え */
int change_ext(char *fname)
{
char *p = strrchr(strlwr(fname), '.');
if (p != NULL && (strcmp(p, ".c") == 0 ||
strcmp(p, ".cpp") == 0 || strcmp(p, ".h") == 0))
{
strcpy(p, ".htm");
return 1;
}
puts("入力ファイルは C/C++ ソースではありません.");
return 0;
}
/* プログラムのエントリポイント */
int main(int argc, char *argv[])
{
char fname[FILENAME_MAX+1];
/* コマンドライン引き数のチェック */
if (argc >= 2)
{
strncpy(fname, argv[1], FILENAME_MAX);
fname[FILENAME_MAX] = '\0';
}
else
{
puts("パラメータが足りません.\n\n使い方: C2HTMLX ファイル名");
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\"\n", fout);
fputs("content=\"text/html;charset=Shift_JIS\">\n", fout);
fputs("<meta name=\"GENERATOR\" content=\"C2HTMLX (c)2001, 2006 AOK\">\n", fout);
fprintf(fout, "<title>%s</title>\n", argv[1]);
fputs("<style type=\"text/css\">\n", fout);
fputs("<!--\n", fout);
fputs("span.color_comment { color:#c00000; }\n", fout);
fputs("span.color_string { color:teal; }\n", fout);
fputs("span.color_keyword { color:blue; }\n", fout);
fputs("-->\n", fout);
fputs("</style>\n", fout);
fputs("</head>\n<body>\n<pre>", fout);
while (!error) getsym(); /* 変換の本体 */
fputs("</pre>\n</body>\n</html>", fout);
/* 入出力ファイルをクローズ */
fclose(fin);
fclose(fout);
puts("\n*** 変換に成功しました.");
return 0;
}