このプログラムは、最初、Eメールなど、60文字程度に改行されてきたテキストファイルを連結するプログラムとして作りました。
convert() { int c, c2; c2=' '; while((c=getc(inp))!=EOF){ switch(c){ case '\n': if(c2=='\n') putc('\n', out); break; default: putc(c, out); } c2=c; } }
上記は、改行二つなら、改行記号をつけるが、改行ひとつなら、改行記号をとっぱらって、行を連結してしまうという単純なプログラムです。ソースファイルで空白行があれば、それを段落の目印にするわけです。c2 にひとつ前に読んだ文字を残してあるのがミソです。
ここから、どうせ段落を作るなら、html の <p> --- </p> タグをつけてしまえと、上記を次のように変更しました。
convert() { int c, c2; c2=' '; while((c=getc(inp))!=EOF){ switch(c){ if(c2=='\n') fputs("</p>\n<p>", out); break; default: putc(c, out); } c2=c; } }
ここから発展して、* が先頭についているときはリスト項目、タブがついている時はテーブル項目と解釈させ、自動的に、箇条書と表作成ができるようにしました。ついでにタグの記号 < と > をそれぞれ < > に変換させるようにしました。
convert() { int c, c2, list_item, table_data; list_item=NO; table_data=NO; c2=' '; while((c=getc(inp))!=EOF){ switch(c){ case '*': if(c2=='\n' && list_item==NO){ fputs("\n<ul>\n<li>", out); list_item=YES; } else if(c2=='\n' && list_item==YES) fputs("\n<li>", out); else putc('*', out); break; case '\t': if(c2=='\n' && table_data==NO){ fputs("\n<table>\n<tr><td>", out); table_data=YES; } else if(c2=='\n' && table_data==YES) fputs("</td></tr>\n<tr><td>", out); else fputs("</td><td>", out); break; case '\n': if(c2=='\n' && list_item==YES){ fputs("\n</ul></p>\n<p>", out); list_item=NO; } else if(c2=='\n' && table_data==YES){ fputs("</td></tr>\n</table>\n<p>", out); table_data=NO; } else if(c2=='\n') fputs("</p>\n<p>", out); break; case '<': fputs("<", out); break; case '>': fputs(">", out); break; default: putc(c, out); } c2=c; } }
これでだいたいうまくいったのですが、インデントなどで、行頭に空白がついている場合、行頭の空白を無視するようにしました。またこのページを作っている時に、& も & に変換しておかなければならないことに気づき、それを加えたのが、最終リストにある convert() サブルーチンです。
それから、テキストファイルのコードを自動的に判別する機能を加えるため、wkf のライブラリーを使おうとしましたがうまくいかず、get_code() では習ったばかりの popen() を使って wkf -c の判定結果をバッファにいれて利用しています。
get_code() { FILE *inp; char buf[40], command[80]; memset(buf, '\0', 40); //バッファの初期化 sprintf(command, "wkf -c %s", inpname); //wkf にファイル名を渡す if((inp=popen(command, "r"))==NULL){ //pipe を開けなかった時の処理 printf("Can't get character code.\n"); exit(0); } if((fread(buf, sizeof(char), 40, inp))==0){ //pipe の値が 0 の時の処理 printf("Can't get character code.\n"); pclose(inp); exit(0); } pclose(inp); //pipe を閉じる buf[strlen(buf)-1]='\0'; //バッファの値を得る
//以下略 }
このプログラムを使用するには、漢字コード変換プログラム wkf がインストールされていなければなりませんが、wkf はあれば便利なプログラムですから、ひとつ入れておかれると良いでしょう。
/* text2html.c text to html converter */ #include <stdio.h> #define YES 1 #define NO 0 /* Grobal */ FILE *inp, *out; char inpname[40], outname[40], charcode[40], title[80]; main(int argc, char *argv[]) { if(argc>1) strcpy(inpname, argv[1]); else{ printf("This will convert text file to html file.\n"); printf("Input text file name.\n"); exit(0); } get_code(); get_title(); get_outname(); open_files(); html_head(); printf("%s --> ", inpname); convert(); html_tail(); printf("%s\n", outname); } get_code() { FILE *inp; char buf[40], command[80]; memset(buf, '\0', 40); sprintf(command, "wkf -c %s", inpname); if((inp=popen(command, "r"))==NULL){ printf("Can't get character code.\n"); exit(0); } if((fread(buf, sizeof(char), 40, inp))==0){ printf("Can't get character code.\n"); pclose(inp); exit(0); } pclose(inp); buf[strlen(buf)-1]='\0'; if(strcmp(buf, "newjis")==0 || strcmp(buf, "oldjis")==0 || strcmp(buf, "jis1990")==0){ printf("Can't handle JIS code file.\n"); exit(0); } else if(strcmp(buf, "sjis")==0) strcpy(charcode, "EUC-JP"); else if(strcmp(buf, "euc-jp")==0) strcpy(charcode, "EUC-JP"); else if(strcmp(buf, "ascii")==0) strcpy(charcode, "ISO-8859-1"); else{ printf("Can't determine charcter code.\n"); exit(0); } } get_title() { FILE *inp; if((inp=fopen(inpname, "r"))==NULL){ printf("Can't open <kcode>\n"); exit(0); } fgets(title, 80, inp); fclose(inp); title[strlen(title)-1]='\0'; } get_outname() { int i, lastdot; for(i=strlen(inpname); i>0; i--){ if(inpname[i]=='.') break; } lastdot=i; if(lastdot==0) sprintf(outname, "%s.html", inpname); else{ for(i=0; i<lastdot; i++) outname[i]=inpname[i]; outname[i]='\0'; sprintf(outname, "%s.html", outname); } } open_files() { if((inp=fopen(inpname, "r"))==NULL){ printf("Can't open <%s>\n", inpname); exit(0); } if((out=fopen(outname, "w"))==NULL){ printf("Can't creat <%s>\n", outname); exit(0); } } convert() { int c, c2, list_item, table_data; list_item=NO; table_data=NO; c2=' '; while((c=getc(inp))!=EOF){ switch(c){ case '*': if((c2=='\n' || c2==' ') && list_item==NO){ fputs("\n<ul>\n<li>", out); list_item=YES; } else if((c2=='\n' || c2==' ') && list_item==YES) fputs("\n<li>", out); else putc('*', out); break; case '\t': if(c2=='\n' && table_data==NO){ fputs("\n<table>\n<tr><td>", out); table_data=YES; } else if(c2=='\n' && table_data==YES) fputs("</td></tr>\n<tr><td>", out); else fputs("</td><td>", out); break; case '\n': if(c2=='\n' && list_item==YES){ fputs("\n</ul></p>\n<p>", out); list_item=NO; } else if(c2=='\n' && table_data==YES){ fputs("</td></tr>\n</table>\n<p>", out); table_data=NO; } else if(c2=='\n') fputs("</p>\n<p>", out); break; case '<': fputs("<", out); break; case '>': fputs(">", out); break; case '&': fputs("&", out); break; case ' ': if(c2=='\n' || c2==' ') continue; else putc(' ', out); break; default: putc(c, out); } c2=c; } } html_head() { fputs("<html>\n", out); fputs("<head>\n", out); fputs(" <meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; ", out); fprintf(out, "charset=%s\">\n", charcode); fprintf(out, " <title>%s</title>\n", title); fputs("</head>\n", out); fputs("<body bgcolor=\"#FFFFFF\">\n", out); fputs("<p>", out); } html_tail() { fputs("</p>\n", out); fputs("</body>\n", out); fputs("</html>\n", out); }