C++版novelのひな形

まだ全然機能がないけど。

code(Linux / g++4.8 / libboost)

#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/regex.hpp>
using namespace std;

// for noveltable
typedef struct{
    int size; // 章数
    string title; // title
    string author; // author
    string publicdir; // Web Directory
    string basename; // basename
    string cssfilename; // CSS filename
    string data; // honbun
    string tmplate; // tmplate
    vector<string> subtitle;
    vector<string> dx;
    vector<string> header;
} novel;

// 指定テキストファイルを読み出す。(vector版)
vector<string> vget_file(string fn)
{
  boost::regex rlf("\\r");
  boost::regex rcr("\\n");
  vector<string> r;
  string a = "";
  ifstream ifs(fn.c_str());
  if(ifs)
  {
    while(getline(ifs,a)){
      if(boost::regex_search(a,rlf)||boost::regex_search(a,rcr)) // なんか改行してるっぽい
      {
        r.push_back(a);
      }else{   // 改行っぽいコードが見当たらないよ?
        r.push_back(a + "\n"); // とりあえずつけとけ。
      }
    }
    ifs.close();
  }else{
    r.push_back("ERROR");
  }
  return(r);
}

// 指定ファイルに内容を書き込む。
void set_file(string fn,string str){
  ofstream ofs(fn.c_str());
  ofs << str;
}

// 指定テキストファイルを読み込む。(string)
string get_file(string fn)
{
  boost::regex rlf("\\r");
  boost::regex rcr("\\n");
  string r = "";
  string a = "";
  ifstream ifs(fn.c_str());
  if(ifs)
  {
    while(getline(ifs,a)){
      if(boost::regex_search(a,rlf)||boost::regex_search(a,rcr)) // なんか改行してるっぽい
      {
        r += a;
      }else{   // 改行っぽいコードが見当たらないよ?
        r += (a + "\n"); // とりあえずつけとけ。
      }
    }
    ifs.close();
  }else{
    r += "ERROR";
  }
  return(r);
}

// index.cssをpublic領域に複写する。

int copy_indexcss(novel n1)
{
  string f = "index.css";
  string fn = "";
  fn = n1.publicdir + "/" + f;
  boost::filesystem::path fpath(fn);
  if(boost::filesystem::exists(fpath)){
    cout << "already exists index.css("<<fn<<")"<<endl;
  }else{
    try{
      boost::filesystem::path srce(f);
      boost::filesystem::path drst(fn);
      boost::filesystem::copy_file(srce, drst);
    }catch(boost::filesystem::filesystem_error& ex){
      cout<<ex.what()<<endl;
      throw;
    }
  }
  return(0);
}


// テンプレートを読み込む。
string read_tmplate(string fn)
{
  return(get_file(fn));
}

string kill_crlf(string x)  // 改行よさようなら。
{
    boost::regex reg("(\\r|\\n)");
    string r = regex_replace(x,reg,"");
    return(r);
}

string get_subtitle(string x)
{
    boost::regex subt("\\A\\*\\ ");
    string r = regex_replace(x,subt,"");
    r = kill_crlf(r);
    return(r);
}

bool make_dir(string dir) // 指定ディレクトリを作成する。存在するなら抜ける。
{
  bool r = true;
  if(mkdir(dir.c_str(), 0755) != 0)
  {
    r = false;
  }
  return(r);
}

string get_basename(string fn)
{
  string r = fn;
  boost::regex reg1("\\A.*/");
  boost::regex reg2("\\.txt\\z");
  r = regex_replace(fn,reg1,"");
  r = regex_replace(r,reg2,"");
  return(r);
}

string make_novel_directory(string fn, string pubdir)
{
    string r = "";
    string basename = get_basename(fn);
    if(make_dir(pubdir) == true){
      if(make_dir(pubdir + "/" + basename) == true){
        r = basename;
      }
    }
    return(r);
}

// サブタイトル一覧を<ul></ul>にして返す。
string vector2link(vector<string> subtitle, string sufx){
  string r = "";
  string fn = "";
  if(subtitle.size() > 1){
    r = "<ul>";
    for(int i=1;i<subtitle.size();i++){
      fn = (boost::format("%1%%2%") % i % sufx).str();;
      r = r + "<li><a href=\"" + fn + "\">" + subtitle[i] + "</a></li>";
    }
  }
  return(r);
}

string make_link(string name, string base, string sufx){
  string fn = (boost::format("%1%%2%") % base % sufx).str();
  if(fn == "0.html"){
    fn = "index.html";
  }
  return("<a href=\"" + fn + "\">" + name + "(/a)");
}
string make_ffn(int n){
  string fn = (boost::format("%1%") % n).str();
  return(fn);
}
// ヘッダ(またはフッタ)を作成して返す。
string make_HeaderOrFooter(vector<string> subtitle, string sufx, int n){
  string r = "";
  int i = 0, ii = 0;
  // 単ページなら、もっとも単純なイメージを返す。
  // 下の端(0ページでなおかつ1以上がある)なら、+1つきのを返す。
  // 末端ページなら、-1のみを返す。
  // どれでもないのなら、-1と+1を返す。
  if(subtitle.size() == 1){
    r = make_link("戻る","../index",sufx);
  }else if(n == 0){ // 単頁ではなく、しかも最初の頁
    r = make_link("戻る","../index",sufx) +
        make_link("進む",make_ffn(n+1),sufx);
  }else if(n == (subtitle.size() - 1)){ // 単頁ではなく、そして末尾の頁
    r = make_link("最初","0",sufx) +
        make_link("戻る",make_ffn(n-1),sufx);
  }else{
    r = make_link("最初","0",sufx) +
        make_link("戻る",make_ffn(n-1),sufx) +
        make_link("進む",make_ffn(n+1),sufx);
  }
  return(r);
}

// テンプレート適用
string check_tmplate(novel n1, int i)
{
    string r = n1.tmplate;
    boost::regex startend("\\A(\\ |\\r|\\n|)+(.*)(\\ |\\r|\\n|)+\\z");
    boost::regex kaigyo("\\n");
    boost::regex honbun(":__CONTENTS__:");
    boost::regex subt(":__SUBTITLE__:");
    boost::regex maint(":__TITLE__:");
    boost::regex header(":__HEADER__:");
    boost::regex footer(":__FOOTER__:");
    boost::regex cssfile(":__CSSFILE__:");
    n1.dx[i] = regex_replace(n1.dx[i], startend,"<p>$2</p>");
    n1.dx[i] = regex_replace(n1.dx[i], kaigyo,"<br />\\n");
    r = regex_replace(r, maint, n1.title);
    r = regex_replace(r, cssfile, n1.cssfilename);
    r = regex_replace(r, honbun, n1.dx[i]);
    r = regex_replace(r, subt, n1.subtitle[i]);
    r = regex_replace(r, header, n1.header[i]);
    r = regex_replace(r, footer, n1.header[i]);
    return(r);
}

void out_data(novel n1)
{
  string fn = "";
  string x = "";
  string y = "";
  for(int i=0;i<n1.dx.size();i++)
  {
    // ファイル名を決定する。
    fn = (boost::format("%1%.html") % i).str();
    if(fn == "0.html"){
      fn = "index.html";
    }
    x = n1.dx[i];
    y = n1.subtitle[i];
    if((i == 0) && (n1.dx.size() > 1)){ // 単ページでなく、そして最初のページ
      // ページ目録を作成する。
      n1.dx[i] += vector2link(n1.subtitle, ".html");
    }
    //set_file(fn,check_tmplate(x,y,n1.tmplate));
    cout<<"set_file:"<<fn<<endl;
    set_file(fn,check_tmplate(n1,i));
  }
}

int main(int argc, char *argv[])
{
    string fn = "genko/2ndc.txt";
    novel n1;
    if(argc > 1){
      fn = (boost::format("genko/%1%") % argv[1]).str();
    }
    boost::regex subt("\\A\\*\\ ");
    // public_html
    n1.publicdir = "public_html";
    // テンプレートの読み込み
    n1.tmplate = read_tmplate("tmplate.html");
    // CSSの所在はここ。
    n1.cssfilename = "index.css";
    vector<string> d = vget_file(fn);
    n1.title = kill_crlf(d[0]);
    n1.author = kill_crlf(d[1]);
    //
    n1.dx.push_back("");
    n1.subtitle.push_back(n1.title);
    int s = 0;
    int c = d.size();
    for(int i=0;i<c;i++){
      if(regex_search(d[i],subt)){ // 章の区切りキタ━(゚∀゚)━!
        n1.dx.push_back(""); // ここでd[i]を入れるとタイトル文字が入ってしまうので、飛ばす。
        n1.subtitle.push_back(get_subtitle(d[i]));
        s++;
      }else{
        n1.dx[s] += (kill_crlf(d[i]) + "\n");
      }
    }
    cout<<"タイトル:"<<n1.title<<endl;
    cout<<"作者:"<<n1.author<<endl;
    cout<<"行数 "<<c<<endl;
    cout<<"章数 "<<n1.dx.size()<<endl;
    //if(n1.subtitle.size() > 1)
    //{
        for(int ii=0;ii<n1.subtitle.size();ii++){
            cout<<"副題:"<<n1.subtitle[ii]<<endl;
            n1.header.push_back(make_HeaderOrFooter(n1.subtitle,".html", ii));
        }
    //}
    cout<<"ディレクトリを作成します。 ....";
    n1.basename = make_novel_directory(fn,n1.publicdir);
    copy_indexcss(n1);
    if(n1.basename != ""){
      cout<<"OK"<<endl;
      cout<<get_current_dir_name()<<endl;
      cout<<n1.basename<<endl;
      chdir(n1.publicdir.c_str());
      chdir(n1.basename.c_str());
      cout<<get_current_dir_name()<<endl;
      cout<<"ファイルを吐き出します。(開始)"<<endl;;
      //out_data(n1.dx, n1.subtitle, n1.tmplate);
      out_data(n1);
      cout<<"ファイルを吐き出します。(終了)"<<endl;
    }else{
      cout<<"NG"<<endl;
    }
}

テンプレート

カレントディレクトリに、tmplate.htmlという名前で保管しておく。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xml:lang="ja-JP" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <link rel="stylesheet" type="text/css" href="../:__CSSFILE__:" title="Normal" />
  <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
  <title>:__SUBTITLE__: / :__TITLE__:</title>
</head>
<body>
  <div class="header">:__HEADER__:</div>
  <div class="title">
    <h1>:__SUBTITLE__:</h1>
  </div>
  <div class="honbun">
    <div class="wadai">

    <div class="setu">
:__CONTENTS__:
    </div>

    </div>
  </div>
  <hr />

  <div class="footer">:__FOOTER__:</div>
<hr />
  <div class="footer">
        <div class="update">:__LASTUPDATE__:</div>
  </div>
  <div class="wadai"><h2>感想メールフォーム</h2>
      <form method="post" action="http://ellidanus-b.ddo.jp/cgi-bin/form.cgi" enctype="text/html">

      <div>
	  <input type="hidden" name="return" value=":__BASEURL__:">
          <input type="hidden" name="subject" value="感想『:__TITLE__:』" />
          <input type="hidden" name="mail" value="iris_von_einzbern@yahoo.co.jp" />
          <input type="hidden" name="style" value="../index.css" />
          <label for="OName">お名前(ハンドル等):</label><input id="OName" accesskey="a" tabindex="0" type="text" name="name1" value="名無しのナボコフ" /><br />
          <label for="OMail">メールアドレス(なくてもいいです):</label><input id="OMail" accesskey="b" tabindex="1" type="text" name="mailfrom" value="" />
      </div>

    <h3>PLZ 選んでください(未選択だとエラー)</h3>
      <div>
        <label for="n1">素晴らしい!</label><input id="n1" accesskey="h" tabindex="6" type="radio" name="kansou" value="素晴らしい!" /><br />
        <label for="n2">なかなか</label><input id="n2" accesskey="i" tabindex="7" type="radio" name="kansou" value="なかなか" /><br />
        <label for="n3">それなりかな</label><input id="n3" accesskey="j" tabindex="8" type="radio" name="kansou" value="それなりかな" /><br />
        <label for="n4">微妙〜</label><input id="n4" accesskey="k" tabindex="9" type="radio" name="kansou" value="微妙〜" /><br />

        <label for="n5">ドン引き orz</label><input id="n5" accesskey="l" tabindex="10" type="radio" name="kansou" value="ドン引き orz" /><br />
        <textarea accesskey="c" tabindex="2" rows="8" name="comment">(コメント)</textarea><br />
        <input accesskey="d" tabindex="3" type="submit" name="wei" value="送信" />-+-<input accesskey="e" tabindex="4" type="reset" name="nap" value="消去" />
      </div>
      </form>
  </div>
</body>
</html>

原稿テキスト

こんな感じの原稿を、たとえば genko/sample.txt にいれておく。

テスト原稿
hachikun
テスト


 テスト原稿なんだよん。


* 第一章

 テストです。

* 第ニ章

 テストテスト。

* 第三章

 これがテストだ!


他に必要なもの。

index.cssという名前でテンプレートを、やっぱりカレントディレクトリに用意してください。