#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <ctype.h>
#include "cpp2html.h"
static const char* c2hprog = "cpp2html v1.0";
enum STR_STATE {
STR_NORMAL = 0,
STR_CHAR = 1,
STR_STRING = 2,
STR_CCOMMENT = 3,
STR_CPPCOMMENT = 4
};
static const char* html_sym[] = {
"&",
"<",
">",
""",
0
};
static const char* cpp_pp[] = {
"#if",
"#ifdef",
"#ifndef",
"#endif",
"#else",
"#elif",
"#undef",
"#define",
"#pragma",
0
};
static const char* cpp_kwd[] = {
"and",
"and_eq",
"auto",
"bitand",
"bitor",
"bool",
"break",
"case",
"catch",
"char",
"class",
"compl",
"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",
"not",
"not_eq",
"operator",
"or",
"or_eq",
"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",
"xor",
"xor_eq",
0
};
#if (USE_LIB==0)
int main(int argc, char* argv[])
{
Cpp2Html* c2h = new Cpp2Html(argc,argv);
if ( !c2h->ReadCode() ) return 0;
if ( c2h->Convert() ) c2h->WriteCode();
delete c2h;
return 0;
}
#endif
void split_path(char* fpath, char* dir, char* file, char* ext)
{
int i,len = strlen(fpath);
for ( i=len-1; i>=0; i-- ) if ( fpath[i] == '.' ) break;
strncpy(ext,fpath+i,len-i);
strncpy(file,fpath,i);
ext[len-i] = '\0';
file[i] = '\0';
len = i;
for ( i=len-1; i>=0; i-- ) if ( file[i] == '/' ) break;
i++;
strncpy(dir,file,i);
strncpy(file,file+i,len-i);
dir[i] = '\0';
file[len-i] = '\0';
}
void filestr_count(char* fname, int& sum_sc, int& sum_lc, int& sum_tc)
{
FILE* fp;
int rsc;
char buf[BUFSIZ];
memset(buf,0,BUFSIZ);
sum_sc = sum_lc = sum_tc = 0;
if ( (fp=fopen(fname,"r")) == NULL ) {
fprintf(stderr,"read file[%s]: No such file or directory\n",fname);
return;
}
while ( (rsc=fread(buf,sizeof(char),BUFSIZ,fp)) ) {
for ( int i=0; i<rsc; i++ ) {
if ( buf[i] == '\n' ) sum_lc ++;
if ( buf[i] == 't' ) sum_tc ++;
}
sum_sc += rsc;
}
sum_sc += rsc;
fclose(fp);
}
void str_count(char* code, int& sum_sc, int& sum_lc, int& sum_tc)
{
sum_sc = sum_lc = sum_tc = 0;
sum_sc = strlen(code);
for ( int i=0; i<sum_sc; i++ ) {
if ( code[i] == '\n' ) sum_lc ++;
if ( code[i] == 't' ) sum_tc ++;
}
}
int read_string(char* fname, int read_sc, char* inbuf)
{
FILE* fp;
int rsc;
if ( (fp=fopen(fname,"r")) == NULL ) {
perror("read file open");
return 0;
}
rsc = fread(inbuf,sizeof(char),read_sc,fp);
if ( rsc != read_sc ) perror("read size");
fclose(fp);
return 1;
}
int kwd_compare(const void *x, const void *y) {
return (strlen(*(char **)y) - strlen(*(char **)x));
}
int kwd_sch(char* code, int str_len, int ki, const char* kwd)
{
int i,klen = strlen(kwd);
if ( ki+klen > str_len ) return 0;
for ( i=0; i<klen; i++ ) {
if ( code[ki+i] != kwd[i]) break;
}
if ( i == klen ) return 1;
return 0;
}
int Kwd_sch(char* code, int str_len, int ki, char* kwd)
{
int i,klen = strlen(kwd);
if ( ki+klen > str_len ) return 0;
for ( i=0; i<klen; i++ ) {
if ( (code[ki+i]) != kwd[i] && (code[ki+i]|32) != kwd[i] ) break;
}
if ( i == klen ) return 1;
return 0;
}
int line_schchar(char* c_code, int str_len, int ki, char fc)
{
int i;
unsigned char c;
for ( i=0; ki+i<str_len; i++ ) {
c = c_code[ki+i];
if ( c == fc ) break;
if ( c == '\n' ) return -1;
}
return i;
}
int line_schstr(char* c_code, int str_len, int ki, const char* kwd)
{
for ( int i=0; ki+i<str_len; i++ ) {
if ( kwd_sch(c_code,str_len,ki+i,kwd) ) return i;
if ( c_code[ki+i] == '\n' ) return -1;
}
return -1;
}
void Cpp2Html::usage()
{
fprintf(stderr,"USAGE: %s srcfile [-disp] [-plain] [-out htmlfile] [-t n] [-no]\n",cmdopt.cmd);
fprintf(stderr,"option:\n");
fprintf(stderr,"\t-disp \toutput to display (default _cpp.html file).\n");
fprintf(stderr,"\t-plain\tdo not display HTML header and footer.\n");
fprintf(stderr,"\t-t n \ttab order (insert n spaces instead of a tab)\n");
fprintf(stderr,"\t-out htmlfile\toutput filename\n");
fprintf(stderr,"\t-no\tdisplay line number\n");
}
int Cpp2Html::ReadArg(int argc, char* argv[], CSrcOption& cmdopt)
{
strcpy(cmdopt.cmd,argv[0]);
#ifdef __DEBUG__
strcpy(cmdopt.fIn,"cpp2html.cpp");
#else
if ( argc == 1 ) { return FALSE; }
#endif
for ( int i=1; i<argc; i++ ) {
if ( argv[i][0] == '-' ) {
if ( !strcmp(argv[i], "-out") ) {
if ( ++i >= argc ) return FALSE;
strcpy(cmdopt.fOut,argv[i]);
} else if ( !strcmp(argv[i], "-plain") ) {
if ( i >= argc ) return FALSE;
cmdopt.Hfmt = FMT_PLAIN;
} else if ( !strcmp(argv[i], "-disp") ) {
if ( i >= argc ) return FALSE;
cmdopt.Hdst = DST_DISP;
} else if ( !strcmp(argv[i], "-t") ) {
if ( ++i >= argc ) return FALSE;
cmdopt.t2s = atoi(argv[i]);
} else if ( !strcmp(argv[i], "-no") ) {
if ( i >= argc ) return FALSE;
cmdopt.swLine = SW_LINE;
} else {
fprintf(stderr,"unrecognized option '%s'\n",argv[i]);
return FALSE;
}
} else {
strcpy(cmdopt.fIn,argv[i]);
}
}
return TRUE;
}
Cpp2Html::Cpp2Html(int argc, char* argv[])
{
Run = ReadArg(argc,argv,cmdopt);
if ( Run == FALSE ) { usage(); return; }
InitClass();
}
Cpp2Html::Cpp2Html(CSrcOption opt)
{
Run = TRUE;
cmdopt = opt;
InitClass();
}
Cpp2Html::Cpp2Html(int Hfmt, int t2s, int swLine)
{
Run = TRUE;
cmdopt.Hfmt = Hfmt;
cmdopt.t2s = t2s;
cmdopt.swLine = swLine;
InitClass();
}
Cpp2Html::~Cpp2Html()
{
if ( Run ) {
if ( Ccode != NULL ) free(Ccode);
if ( Hcode != NULL ) free(Hcode);
}
}
void Cpp2Html::SetBodyColor(int color, int bgcolor)
{
colopt.setBodyColor(color,bgcolor);
}
void Cpp2Html::SetFontFormat(FONT_TYPE type, int color, int weight, int style)
{
colopt.setFontFormat(type,color,weight,style);
}
void Cpp2Html::InitClass()
{
char dir[128],file[128],ext[10];
if ( strcmp(cmdopt.fIn,std_in) ) {
split_path(cmdopt.fIn,dir,file,ext);
sprintf(DocTitle,"%s%s",file,ext);
if ( !strcmp(cmdopt.fOut,std_out) ) {
if ( cmdopt.Hdst == DST_FILE ) {
ext[0] = '_';
sprintf(cmdopt.fOut,"%s%s.html",file,ext);
}
}
} else {
sprintf(DocTitle,"cpp2html");
}
memset(tabstr,0,sizeof(char)*256);
for ( int i=0; i<cmdopt.t2s; i++ ) strcat(tabstr," ");
SortKwd();
Ccode = Hcode = NULL;
OFP = NULL;
sprintf(FootCode,"</body>\n</html>\n");
}
void Cpp2Html::SortKwd()
{
int ki;
for ( ki=0; cpp_pp[ki] != 0; ki++ ) pp_table[ki] = (char*)cpp_pp[ki];
qsort(pp_table,ki,sizeof(char*),kwd_compare);
for ( int i=0; i<ki; i++ ) pp_len[i] = strlen(pp_table[i]);
pp_len[ki] = 0;
for ( ki=0; cpp_kwd[ki] != 0; ki++ ) kwd_table[ki] = (char*)cpp_kwd[ki];
qsort(kwd_table,ki,sizeof(char*),kwd_compare);
for ( int i=0; i<ki; i++ ) kwd_len[i] = strlen(kwd_table[i]);
kwd_len[ki] = 0;
}
void Cpp2Html::SetCode(char* src)
{
lineSum = tabSum = fcLen = 0;
str_count(src,fcLen,lineSum,tabSum);
Ccode = (char*)calloc(fcLen+1,sizeof(char));
strcpy(Ccode,src);
}
int Cpp2Html::ReadCode()
{
if ( Run == FALSE ) return FALSE;
lineSum = tabSum = fcLen = 0;
filestr_count(cmdopt.fIn,fcLen,lineSum,tabSum);
if ( fcLen == 0 ) {
return FALSE;
}
Ccode = (char*)calloc(fcLen+1,sizeof(char));
if ( !read_string(cmdopt.fIn,fcLen,Ccode) ) {
fprintf(stderr,"input file reading error.\n");
return FALSE;
}
return TRUE;
}
int Cpp2Html::ReadFile(char* fname)
{
if ( Run == FALSE ) return FALSE;
strcpy(cmdopt.fIn,fname);
char dir[128],file[128],ext[10];
split_path(cmdopt.fIn,dir,file,ext);
sprintf(DocTitle,"%s%s",file,ext);
ext[0] = '_';
sprintf(cmdopt.fOut,"%s%s.html",file,ext);
lineSum = tabSum = fcLen = 0;
filestr_count(cmdopt.fIn,fcLen,lineSum,tabSum);
if ( fcLen == 0 ) return FALSE;
Ccode = (char*)calloc(fcLen+1,sizeof(char));
if ( !read_string(cmdopt.fIn,fcLen,Ccode) ) {
fprintf(stderr,"input file reading error.\n");
return FALSE;
}
return TRUE;
}
int Cpp2Html::Convert()
{
if ( Run == FALSE ) return FALSE;
sprintf(HeadCode,
"<html>\n"
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html\">\n"
"<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n"
"<title>%s</title>\n"
"<style type=\"text/css\">\n"
"<!--\n"
"body {%s}\n"
"span.comment {%s}\n"
"span.ditective {%s}\n"
"span.function {%s}\n"
"span.keyword {%s}\n"
"span.string {%s}\n"
"span.linenum {%s}\n"
"-->\n"
"</style>\n"
"</head>\n"
"<body>\n",
DocTitle,
colopt.getBodyFmt(),
colopt.getCommentFmt(),colopt.getDitectiveFmt(),colopt.getFunctionFmt(),
colopt.getCommandFmt(),colopt.getStringFmt(),colopt.getLinenumFmt());
int tabmem = 6*cmdopt.t2s*tabSum;
int linemem = 0;
if ( cmdopt.swLine ) {
linemem = 38 * (lineSum+1);
if ( lineSum < 100 ) linefmt = 2;
else if ( lineSum < 1000 ) linefmt = 3;
else linefmt = 4;
}
int buflen = FMINSIZ+fcLen*3+tabmem+linemem;
if ( !Initbuf(buflen) ) {
fprintf(stderr,"cannot alloc output buffer.\n");
return FALSE;
}
Cpp2html();
return TRUE;
}
int Cpp2Html::CodeLen()
{
int len = 0;
if ( !cmdopt.Hfmt ) len += strlen(HeadCode);
len += strlen(Hcode);
if ( !cmdopt.Hfmt ) len += strlen(FootCode);
return len;
}
void Cpp2Html::GetCode(char* dst)
{
if ( !cmdopt.Hfmt ) strcat(dst,HeadCode);
strcat(dst,Hcode);
if ( !cmdopt.Hfmt ) strcat(dst,FootCode);
}
void Cpp2Html::WriteCode()
{
if ( cmdopt.Hdst == DST_FILE ) {
if ( !strcmp(cmdopt.fOut,std_out) ) {
fprintf(stderr,"**%s\n\toutput file is not detected.\n",c2hprog);
return;
}
fprintf(stderr,"**%s\n\t%s -> %s\n",c2hprog,cmdopt.fIn,cmdopt.fOut);
}
OFP = stdout;
if ( !cmdopt.Hdst ) {
if ( (OFP=fopen(cmdopt.fOut,"w")) == NULL ) {
fprintf(stderr,"output file[%s]: cannot writable.\n",cmdopt.fOut);
return;
}
}
if ( !cmdopt.Hfmt ) Html_headout();
Html_codeout();
if ( !cmdopt.Hfmt ) Html_footout();
fclose(OFP);
}
void Cpp2Html::FreeCode()
{
if ( Run ) {
if ( Ccode != NULL ) free(Ccode); Ccode = NULL;
if ( Hcode != NULL ) free(Hcode); Hcode = NULL;
}
}
void Cpp2Html::Html_headout()
{
fprintf(OFP,"%s",HeadCode);
fflush(OFP);
}
void Cpp2Html::Html_footout()
{
fprintf(OFP,"%s",FootCode);
fflush(OFP);
}
void Cpp2Html::Html_codeout()
{
fwrite(Hcode,sizeof(char),strlen(Hcode),OFP);
}
int Cpp2Html::Initbuf(int buflen)
{
hci = 0;
Hcode = (char*)calloc(buflen,sizeof(char));
memset(Hcode,0,buflen);
if ( Hcode == NULL ) return 0;
return 1;
}
void Cpp2Html::PushLine()
{
char linebuf[50];
char fmt[10];
switch ( linefmt ) {
case 2: sprintf(fmt,"%%02d:<br>"); break;
case 3: sprintf(fmt,"%%03d:<br>"); break;
case 4: sprintf(fmt,"%%04d:<br>"); break;
default: sprintf(fmt,"%%d<br>"); break;
}
strpush("<table border=\"0\">\n<tr>\n<td>\n<pre><span class=\"linenum\">");
for ( int i=0; i<lineSum; i++ ) {
sprintf(linebuf,fmt,i+1);
strpush(linebuf);
}
strpush("</span></pre>\n</td>\n<td>\n");
}
void Cpp2Html::strpush(const char* buf)
{
for ( unsigned i=0; i<strlen(buf); i++ ) Hcode[hci++] = buf[i];
}
void Cpp2Html::charpush(const char buf)
{
Hcode[hci++] = buf;
}
int Cpp2Html::htmlsym_sch(char c)
{
if ( c == '&' ) return 0;
if ( c == '<' ) return 1;
if ( c == '>' ) return 2;
return -1;
}
char* Cpp2Html::get_htmlsym(int kn)
{
return (char*)html_sym[kn];
}
int Cpp2Html::ch_strstate(unsigned char pre_c, unsigned char now_c, unsigned char nxt_c)
{
if ( pre_c != '\\' && now_c == '\'' ) return STR_CHAR;
if ( pre_c != '\\' && now_c == '\"' ) return STR_STRING;
if ( now_c == '/' && nxt_c == '*' ) return STR_CCOMMENT;
if ( now_c == '/' && nxt_c == '/' ) return STR_CPPCOMMENT;
return STR_NORMAL;
}
int Cpp2Html::rep_strarea(int kstat, char* c_code, int iPos)
{
int reti;
switch ( kstat ) {
case STR_CHAR:
strpush("<span class=\"string\">\'");
reti = rep_area(c_code,iPos,"\'");
strpush("\'");
break;
case STR_STRING:
strpush("<span class=\"string\">\"");
reti = rep_area(c_code,iPos,"\"");
strpush("\"");
break;
case STR_CCOMMENT:
strpush("<span class=\"comment\">/*");
reti = rep_area(c_code,iPos+1,"*/");
strpush("*/");
reti += 2;
break;
case STR_CPPCOMMENT:
strpush("<span class=\"comment\">//");
reti = rep_area(c_code,iPos+1,"\n");
break;
}
strpush("</span>");
return reti;
}
int Cpp2Html::rep_area(char* c_code, int iPos, const char* estr)
{
int i,hkey,iStart,fopt;
unsigned char c,pre_c;
fopt = (estr[0] == '\'' ) ? 1 : 0;
i = iPos;
iStart = 1;
while ( iStart && i++ < fcLen ) {
pre_c = c_code[i-1];
c = c_code[i];
if ( c == '\t' ) { strpush(tabstr); continue; }
if ( kwd_sch(c_code,fcLen,i,"\\\\") ) { strpush("\\\\"); i++; continue; }
if ( kwd_sch(c_code,fcLen,i,"\\\'") ) { strpush("\\\'"); i++; continue; }
if ( kwd_sch(c_code,fcLen,i,"\\\"") ) { strpush("\\\""); i++; continue; }
hkey = htmlsym_sch(c);
if ( hkey >= 0 ) {
strpush(get_htmlsym(hkey));
} else {
if ( kwd_sch(c_code,fcLen,i,estr) ) iStart = 0;
else charpush(c);
}
}
return (i-iPos);
}
int Cpp2Html::ch_ditective(char* c_code, int iPos, unsigned char pre_c)
{
int klen,kend;
for ( int ki=0; pp_len[ki] != 0; ki++ ) {
klen = pp_len[ki];
if ( iPos+klen >= fcLen ) continue;
kend = c_code[iPos+klen];
if ( kwd_sch(c_code,fcLen,iPos,(char*)pp_table[ki]) && !isalpha(pre_c) && !isalpha(kend) ) {
return ki;
}
}
return -1;
}
int Cpp2Html::ch_function(char* c_code, int iPos, unsigned char pre_c)
{
int kp;
unsigned char c = c_code[iPos];
if ( pre_c == '\n' ) {
if ( isalpha(c) ) {
kp = line_schchar(Ccode,fcLen,iPos,'(');
if ( kp > 0 ) return 1;
}
return 0;
}
return 0;
}
int Cpp2Html::rep_function(char* c_code, int iPos, unsigned char pre_c)
{
int i=iPos,kno,kp;
unsigned char c;
if ( (kno = ch_keyword(c_code,i,pre_c)) >= 0 ) {
strpush("<span class=\"keyword\">");
strpush(kwd_table[kno]);
strpush("</span>");
i += strlen(kwd_table[kno]);
}
c = c_code[i];
if ( c == '*' ) { charpush('*'); i++; c = c_code[i]; }
if ( c == '*' ) { charpush('*'); i++; c = c_code[i]; }
kp = line_schstr(Ccode,fcLen,i,"::");
if ( kp >= 0 ) {
memset(repst,0,sizeof(char)*256);
strpush("<span class=\"ditective\">");
strncpy(repst,Ccode+i,kp);
strpush(repst);
strpush("</span>::");
i += kp+2;
}
kp = line_schchar(Ccode,fcLen,i,'(');
if ( kp >= 0 ) {
memset(repst,0,sizeof(char)*256);
strpush("<span class=\"function\">");
strncpy(repst,Ccode+i,kp);
strpush(repst);
strpush("</span>");
i += kp-1;
}
return (i-iPos);
}
int Cpp2Html::ch_keyword(char* c_code, int iPos, unsigned char pre_c)
{
int klen,kend;
for ( int ki=0; kwd_len[ki] != 0; ki++ ) {
klen = kwd_len[ki];
if ( iPos+klen >= fcLen ) continue;
kend = c_code[iPos+klen];
if ( kwd_sch(c_code,fcLen,iPos,(char*)kwd_table[ki]) && !isalpha(pre_c) && !isalpha(kend) ) {
return ki;
}
}
return -1;
}
void Cpp2Html::Cpp2html()
{
int kno,kp;
int hkey=0,kstat=0;
unsigned char c,nxt_c,pre_c=' ';
if ( cmdopt.swLine ) PushLine();
strpush("<pre>");
for ( int i=0; i<fcLen; pre_c=Ccode[i++] ) {
c = Ccode[i];
nxt_c = (i<fcLen-1) ? Ccode[i+1] : 0;
if ( c == '\t' ) { strpush(tabstr); continue; }
if ( (hkey = htmlsym_sch(c)) >= 0 ) {
strpush(get_htmlsym(hkey)); continue;
}
if ( (kstat = ch_strstate(pre_c,c,nxt_c)) != 0 ) {
i += rep_strarea(kstat,Ccode,i);
continue;
}
if ( (kno = ch_ditective(Ccode,i,pre_c)) >= 0 ) {
strpush("<span class=\"ditective\">");
strpush(pp_table[kno]);
strpush("</span>");
i += pp_len[kno]-1;
continue;
}
if ( ch_function(Ccode,i,pre_c) ) {
i += rep_function(Ccode,i,pre_c);
continue;
}
if ( (kno = ch_keyword(Ccode,i,pre_c)) >= 0 ) {
strpush("<span class=\"keyword\">");
strpush(kwd_table[kno]);
strpush("</span>");
i += kwd_len[kno]-1;
continue;
}
if ( kwd_sch(Ccode,fcLen,i,"#include") ) {
int fopt = 0;
strpush("<span class=\"ditective\">#include</span>");
i += 8;
if ( line_schchar(Ccode,fcLen,i,'<') >= 0 ) fopt = 1;
kp = line_schchar(Ccode,fcLen,i,(fopt) ? '<' : '\"');
if ( kp >= 0 ) {
memset(repst,0,sizeof(char)*256);
strncpy(repst,Ccode+i,kp);
strpush(repst);
i += kp+1;
}
if ( fopt ) {
strpush("<span class=\"keyword\"><");
kp = line_schchar(Ccode,fcLen,i,'>');
} else {
strpush("<span class=\"string\">\"");
kp = line_schchar(Ccode,fcLen,i,'\"');
}
if ( kp >= 0 ) {
memset(repst,0,sizeof(char)*256);
strncpy(repst,Ccode+i,kp);
strpush(repst);
i += kp+1;
strpush((fopt) ? ">" : "\"");
}
c = Ccode[i];
strpush("</span>");
}
charpush(c);
}
if ( cmdopt.swLine ) {
strpush("</td>\n</tr>\n</table>\n");
}
strpush("</pre>\n");
charpush('\0');
}