/* * Copyright (C) 2007, Sander van Dijk. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ template File { close_when_done = false; file = (); void File(mixed res_or_name) { if (is_resource(res_or_name) && is_file_resource(res_or_name)) { this.file = res_or_name; this.close_when_done = false; } else if (is_string(res_or_name)) { this.file = fopen(res_or_name, "r"); if (!this.file) throw sprintf("%s: can't open file \x22%s\x22", tmpl_of(this), res_or_name); this.close_when_done = true; } else throw sprintf("%s: illegal argument", tmpl_of(this)); } void close() { if (!is_resource(this.file) || !is_file_resource(this.file)) throw sprintf("%s: attempt to close a non-open file", tmpl_of(this)); fclose(this.file); this.file = (); } mixed getword() { if (!this.file) return (); w = mkarray(); for (i=0; c = fgetc(this.file);) if (isgraph(c)) w[i++] = c; else if (w) return implode(w); if (this.close_when_done) this.close(); return (); } } template Markov { dict = (); plen = 2; seed = ""; void Markov(int plen) { this.plen = plen; if (!this.plen > 0) throw sprintf("%s: invalid prefix length", tmpl_of(this)); this.dict = dopen(16); if (!this.dict) throw sprintf("%s: can't open dictionary", tmpl_of(this)); } void addfile(mixed res_or_name) { file = new File(res_or_name); // can throw an exception prefix = replicate(this.seed, this.plen); while (true) { w = file.getword(); arr = dread(this.dict, this.mkkey(prefix)); if (!arr) arr = nil(); arr = cons(w, arr); dwrite(this.dict, this.mkkey(prefix), arr); if (!w) break; prefix = cons(w, init(prefix)); } } void generate(int max) { prefix = replicate(this.seed, this.plen); for (i=0; (max>0 ? i] [-g ] [file ...]\n", "\n", " Possible arguments:\n", " -p The length (in words) of the prefixes.\n", " Default is 2.\n", " -g The maximum length (in words) of the generated output\n", " (0 or negative values mean generate until an\n", " endpoint of one of the input files is generated).\n", " Default is 0.\n", " file ... The files to use as input. \x22-\x22 means standard input.\n", " Default is standard input.\n", "\n"); exit(0); } else files = cons(argv[i], files); } if (!files) files = cons(stdin, files); /* main */ try { markov = new Markov(plen); for (i=0; i