1 /**
   2  * @fileOverview
   3  * 全てのスクリプトをロードするために必要ないくつかの基本オブジェクトを生成する、アプリケーションの起動スクリプトです。
   4  * <p class="org_comment">
   5  * A bootstrap script that creates some basic required objects
   6  * for loading other scripts.
   7  * </p>
   8  * @author Michael Mathews, micmath@gmail.com
   9  * @version $Id: run.js 756 2009-01-07 21:32:58Z micmath $
  10  */
  11 
  12 /**
  13  * @namespace
  14  * 実行中のスクリプトからのログメッセージの出力に関する機能を提供します。
  15  * <p class="org_comment">
  16  * Keep track of any messages from the running script.
  17  * </p>
  18  */
  19 LOG = {
  20     /**
  21      * 警告メッセージを出力します。eに例外オブジェクトを指定すると、ファイル名と行数が出力されます。
  22      * @param {String} msg メッセージ
  23      * @param {Exception} [e] 例外オブジェクト
  24      */
  25     warn: function(msg, e) {
  26         if (JSDOC.opt.q) return;
  27         if (e) msg = e.fileName+", line "+e.lineNumber+": "+msg;
  28         
  29         msg = ">> WARNING: "+msg;
  30         LOG.warnings.push(msg);
  31         if (LOG.out) LOG.out.write(msg+"\n");
  32         else print(msg);
  33     },
  34 
  35     /**
  36      * 情報メッセージを出力します。(-vコマンドラインオプションが指定されている場合のみ有効)
  37      * @param {String} msg メッセージ
  38      */
  39     inform: function(msg) {
  40         if (JSDOC.opt.q) return;
  41         msg = " > "+msg;
  42         if (LOG.out) LOG.out.write(msg+"\n");
  43         else if (typeof LOG.verbose != "undefined" && LOG.verbose) print(msg);
  44     }
  45 };
  46 
  47 /**
  48  * これまでに出力された警告メッセージを配列として保持するプロパティ
  49  * @type String[]
  50  */
  51 LOG.warnings = [];
  52 
  53 /**
  54  * 詳細ログ出力フラグ。-vコマンドラインオプションが指定されている場合trueが設定されます。
  55  * @type Boolean @default false
  56  */
  57 LOG.verbose = false
  58 
  59 /**
  60  * -oコマンドラインオプションで指定されたログファイルへのテキスト出力ストリームライター。
  61  * -oオプションが未指定の場合、何も設定されません。
  62  * @type Packages.java.io.PrintWriter
  63  */
  64 LOG.out = undefined;
  65 
  66 
  67 /**
  68  * @class
  69  * ファイルパスを操作するための機能を提供するクラス。
  70  * <p class="org_comment">
  71  * Manipulate a filepath.
  72  * </p>
  73  * @param {String} absPath ファイルの絶対パス
  74  * @param {String} [separator="/"] パスセパレータ
  75  * 
  76  * @property {String}   slash パスセパレータ
  77  * @property {String}   root  ファイルパスの最上位ディレクトリ
  78  * @property {String[]} path  最上位階層とファイル名を除くパス階層の配列
  79  * @property {String}   file  ファイル名
  80  */
  81 function FilePath(absPath, separator) {
  82     this.slash =  separator || "/"; 
  83     this.root = this.slash;
  84     this.path = [];
  85     this.file = "";
  86     
  87     var parts = absPath.split(/[\\\/]/);
  88     if (parts) {
  89         if (parts.length) this.root = parts.shift() + this.slash;
  90         if (parts.length) this.file =  parts.pop()
  91         if (parts.length) this.path = parts;
  92     }
  93     
  94     this.path = this.resolvePath();
  95 }
  96 
  97 /**
  98  * Collapse any dot-dot or dot items in a filepath. 
  99  * @ignore
 100  */
 101 FilePath.prototype.resolvePath = function() {
 102     var resolvedPath = [];
 103     for (var i = 0; i < this.path.length; i++) {
 104         if (this.path[i] == "..") resolvedPath.pop();
 105         else if (this.path[i] != ".") resolvedPath.push(this.path[i]);
 106     }
 107     return resolvedPath;
 108 }
 109 
 110 /**
 111  * ファイルの情報を除去します。
 112  * <p class="org_comment">Trim off the filename.</p>
 113  * @return {FilePath} このオブジェクトの参照
 114  */
 115 FilePath.prototype.toDir = function() {
 116     if (this.file) this.file = "";
 117     return this;
 118 }
 119 
 120 /**
 121  * ファイル名と最下層のディレクトリを除去し、オブジェクトの示す階層を1段階上げます。
 122  * <p class="org_comment">Go up a directory.</p>
 123  * @return {FilePath} このオブジェクトの参照
 124  */
 125 FilePath.prototype.upDir = function() {
 126     this.toDir();
 127     if (this.path.length) this.path.pop();
 128     return this;
 129 }
 130 
 131 /**
 132  * オブジェクトの文字列表現として、オブジェクトの示すファイルパスを返します。
 133  * @return {String} オブジェクトの示すファイルパス
 134  */
 135 FilePath.prototype.toString = function() {
 136     return this.root
 137         + this.path.join(this.slash)
 138         + ((this.path.length > 0)? this.slash : "")
 139         + this.file;
 140 }
 141 
 142 /**
 143  * パスからファイル名を取り出します。
 144  * <p class="org_comment">Turn a path into just the name of the file.</p>
 145  * @param {String} path ファイルパス
 146  * @return {String} ファイル名
 147  */
 148 FilePath.fileName = function(path) {
 149     var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
 150     return path.substring(nameStart);
 151 }
 152 
 153 /**
 154  * ファイル名から拡張子を取り出します。
 155  * <p class="org_comment">Get the extension of a filename</p>
 156  * @param {String} filename ファイルパス
 157  * @return {String} ファイル拡張子
 158  */
 159 FilePath.fileExtension = function(filename) {
 160    return filename.split(".").pop().toLowerCase();
 161 };
 162 
 163 /**
 164  * パスからディレクトリ部分を取り出します。
 165  * <p class="org_comment">Turn a path into just the directory part.</p>
 166  * @param {String} path ファイルパス
 167  * @return {String} パスのディレクトリ部分
 168  */
 169 FilePath.dir = function(path) {
 170     var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0);
 171     return path.substring(0, nameStart-1);
 172 }
 173 
 174 
 175 importClass(java.lang.System);
 176 
 177 /**
 178  * @namespace
 179  * 様々なシステム情報をプロパティに持つ名前空間。特に[[SYS.pwd]]プロパティはテンプレート開発者にとって重要です。
 180  * <p class="org_comment">A collection of information about your system.</p>
 181  */
 182 SYS = {
 183     /**
 184      * OS情報。アーキテクチャ、名称、バージョンをカンマ区切りで結合した文字列です。
 185      * <p class="org_comment">Information about your operating system: arch, name, version.</p>
 186      * @type String
 187      */
 188     os: [
 189         new String(System.getProperty("os.arch")),
 190         new String(System.getProperty("os.name")),
 191         new String(System.getProperty("os.version"))
 192     ].join(", "),
 193     
 194     /**
 195      * パス区切り文字。
 196      * <p class="org_comment">Which way does your slash lean.</p>
 197      * @type String
 198      */
 199     slash: System.getProperty("file.separator")||"/",
 200     
 201     /**
 202      * 実行中のJavaの作業ディレクトリ。
 203      * <p class="org_comment">The path to the working directory where you ran java.</p>
 204      * @type String
 205      */
 206     userDir: new String(System.getProperty("user.dir")),
 207     
 208     /**
 209      * Javaのホームディレクトリ。
 210      * <p class="org_comment">Where is Java's home folder.</p>
 211      * @type String
 212      */
 213     javaHome: new String(System.getProperty("java.home")),
 214     
 215     /**
 216      * app/run.jsの絶対パス。
 217      * <p class="org_comment">The absolute path to the directory containing this script.</p>
 218      * @type String
 219      */
 220     pwd: undefined
 221 };
 222 
 223 // jsrun appends an argument, with the path to here.
 224 if (arguments[arguments.length-1].match(/^-j=(.+)/)) {
 225     if (RegExp.$1.charAt(0) == SYS.slash || RegExp.$1.charAt(1) == ":") { // absolute path to here
 226         SYS.pwd = new FilePath(RegExp.$1).toDir().toString();
 227     }
 228     else { // relative path to here
 229         SYS.pwd = new FilePath(SYS.userDir + SYS.slash + RegExp.$1).toDir().toString();
 230     }
 231     arguments.pop();
 232 }
 233 else {
 234     print("The run.js script requires you use jsrun.jar.");
 235     quit();
 236 }
 237 
 238 
 239 // shortcut
 240 var File = Packages.java.io.File;
 241 
 242 /**
 243  * @namespace
 244  * ファイルの読み書きを実行するメソッドのコレクションです。
 245  * <p class="org_comment">A collection of functions that deal with reading a writing to disk.</p>
 246  */
 247 IO = {
 248 
 249     /**
 250      * 文字列をファイルに保存します。
 251      * <p class="org_comment">Create a new file in the given directory, with the given name and contents.</p>
 252      * @param {String} outDir 出力ディレクトリ
 253      * @param {String} fileName 出力ファイル名
 254      * @param {String} content ファイルに保存する内容
 255      */
 256     saveFile: function(/**string*/ outDir, /**string*/ fileName, /**string*/ content) {
 257         var out = new Packages.java.io.PrintWriter(
 258             new Packages.java.io.OutputStreamWriter(
 259                 new Packages.java.io.FileOutputStream(outDir+SYS.slash+fileName),
 260                 IO.encoding
 261             )
 262         );
 263         out.write(content);
 264         out.flush();
 265         out.close();
 266     },
 267     
 268     /**
 269      * ファイルを読み込み、その内容を文字列として返します。
 270      * @param {String} path ファイルパス
 271      * @return {String} ファイルの内容
 272      * @throws {Exception} 指定されたファイルパスが存在しない場合に発生します。
 273      */
 274     readFile: function(/**string*/ path) {
 275         if (!IO.exists(path)) {
 276             throw "File doesn't exist there: "+path;
 277         }
 278         return readFile(path, IO.encoding);
 279     },
 280 
 281     /**
 282      * ファイルをコピーします。
 283      * @param {String} inFile 入力ファイルのパス 
 284      * @param {String} outDir 出力ファイルのディレクトリパス
 285      * @param {String} [fileName] 出力ファイル名。省略した場合は入力ファイル名がそのまま使用されます。
 286      */
 287     copyFile: function(/**string*/ inFile, /**string*/ outDir, /**string*/ fileName) {
 288         if (fileName == null) fileName = FilePath.fileName(inFile);
 289     
 290         var inFile = new File(inFile);
 291         var outFile = new File(outDir+SYS.slash+fileName);
 292         
 293         var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096);
 294         var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096);
 295         var theChar;
 296         while ((theChar = bis.read()) != -1) {
 297             bos.write(theChar);
 298         }
 299         bos.close();
 300         bis.close();
 301     },
 302 
 303     /**
 304      * ディレクトリ階層を作成します。
 305      * <p class="org_comment">Creates a series of nested directories.</p>
 306      * @param {String | String[]} path ディレクトリパスを表す文字列、もしくは各階層のディレクトリ名を要素に持つ配列
 307      */
 308     mkPath: function(/**Array*/ path) {
 309         if (path.constructor != Array) path = path.split(/[\\\/]/);
 310         var make = "";
 311         for (var i = 0, l = path.length; i < l; i++) {
 312             make += path[i] + SYS.slash;
 313             if (! IO.exists(make)) {
 314                 IO.makeDir(make);
 315             }
 316         }
 317     },
 318     
 319     /**
 320      * ディレクトリを作成します。
 321      * <p class="org_comment">Creates a directory at the given path.</p>
 322      * @param {String} path ディレクトリパス
 323      */
 324     makeDir: function(/**string*/ path) {
 325         (new File(path)).mkdir();
 326     },
 327 
 328     /**
 329      * 指定されたディレクトリの配下を再帰的に検索し、全てのファイルパスの配列を返します。
 330      * @param {String} dir 検索を開始するディレクトリ。
 331      *                     <p class="org_comment">The starting directory to look in.</p>
 332      * @param {Number} [recurse=1] 検索する階層数
 333      *                             <p class="org_comment">How many levels deep to scan.</p>
 334      * @param {String[]} [_allFiles] 再帰呼び出し中に使用されるパラメータ
 335      * @param {String}   [_path]     再帰呼び出し中に使用されるパラメータ
 336      * @return {String[]} 検索されたディレクトリに存在する全てのファイルパス。
 337      *                    <p class="org_comment">An array of all the paths to files in the given dir.</p>
 338      */
 339     ls: function(/**string*/ dir, /**number*/ recurse, _allFiles, _path) {
 340         if (_path === undefined) { // initially
 341             var _allFiles = [];
 342             var _path = [dir];
 343         }
 344         if (_path.length == 0) return _allFiles;
 345         if (recurse === undefined) recurse = 1;
 346         
 347         dir = new File(dir);
 348         if (!dir.directory) return [String(dir)];
 349         var files = dir.list();
 350         
 351         for (var f = 0; f < files.length; f++) {
 352             var file = String(files[f]);
 353             if (file.match(/^\.[^\.\/\\]/)) continue; // skip dot files
 354     
 355             if ((new File(_path.join(SYS.slash)+SYS.slash+file)).list()) { // it's a directory
 356                 _path.push(file);
 357                 if (_path.length-1 < recurse) IO.ls(_path.join(SYS.slash), recurse, _allFiles, _path);
 358                 _path.pop();
 359             }
 360             else {
 361                 _allFiles.push((_path.join(SYS.slash)+SYS.slash+file).replace(SYS.slash+SYS.slash, SYS.slash));
 362             }
 363         }
 364     
 365         return _allFiles;
 366     },
 367 
 368     /**
 369      * 指定されたパスが存在するか判定します。 
 370      * @param {String} path ファイルパス
 371      * @return {Boolean} ファイルパスが存在すればtrue、なければfalse
 372      */
 373     exists: function(/**string*/ path) {
 374         file = new File(path);
 375     
 376         if (file.isDirectory()){
 377             return true;
 378         }
 379         if (!file.exists()){
 380             return false;
 381         }
 382         if (!file.canRead()){
 383             return false;
 384         }
 385         return true;
 386     },
 387 
 388     /**
 389      * 指定されたファイルパスへの出力ストリームライターを作成して返します。
 390      * @param {String} path ファイルパス
 391      * @param {Boolean} [append] (このパラメータは使用されていません。) 
 392      * @return {Packages.java.io.PrintWriter} 指定されたファイルパスへの出力ストリームライター
 393      */
 394     open: function(/**string*/ path, /**string*/ append) {
 395         var append = true;
 396         var outFile = new File(path);
 397         var out = new Packages.java.io.PrintWriter(
 398             new Packages.java.io.OutputStreamWriter(
 399                 new Packages.java.io.FileOutputStream(outFile, append),
 400                 IO.encoding
 401             )
 402         );
 403         return out;
 404     },
 405 
 406     /**
 407      * この名前空間のメソッドによるファイル入出力処理で使用される文字エンコーディングを設定します。
 408      * <p class="org_comment">
 409      * Sets {@link IO.encoding}.
 410      * Encoding is used when reading and writing text to files,
 411      * and in the meta tags of HTML output.
 412      * </p>
 413      * @param {String} encoding 文字エンコーディング名
 414      */
 415     setEncoding: function(/**string*/ encoding) {
 416         if (/ISO-8859-([0-9]+)/i.test(encoding)) {
 417             IO.encoding = "ISO8859_"+RegExp.$1;
 418         }
 419         else {
 420             IO.encoding = encoding;
 421         }
 422     },
 423 
 424     /**
 425      * @default "utf-8"
 426      * @private
 427      */
 428     encoding: "utf-8",
 429     
 430     /**
 431      * SYS.pwd からの相対パスで指定されたファイルをロードします。
 432      * <p class="org_comment">Load the given script.</p>
 433      * @param {String} relativePath [[SYS.pwd]]からの相対パスで指定されたファイルパス
 434      */
 435     include: function(relativePath) {
 436         load(SYS.pwd+relativePath);
 437     },
 438     
 439     /**
 440      * SYS.pwd からの相対パスで指定されたディレクトリに含まれるスクリプトファイル(拡張子が.jsのファイル)を全てロードします。
 441      * <p class="org_comment">Loads all scripts from the given directory path.</p>
 442      * @param {String} relativePath [[SYS.pwd]]からの相対パスで指定されたディレクトリパス
 443      */
 444     includeDir: function(path) {
 445         if (!path) return;
 446         
 447         for (var lib = IO.ls(SYS.pwd+path), i = 0; i < lib.length; i++) 
 448             if (/\.js$/i.test(lib[i])) load(lib[i]);
 449     }
 450 }
 451 
 452 // now run the application
 453 IO.include("frame.js");
 454 IO.include("main.js");
 455 
 456 main();
 457