tmtms-review 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/COPYING +515 -0
  4. data/ChangeLog +2083 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +56 -0
  7. data/VERSION +1 -0
  8. data/bin/review-check +178 -0
  9. data/bin/review-checkdep +63 -0
  10. data/bin/review-compile +205 -0
  11. data/bin/review-epubmaker +661 -0
  12. data/bin/review-epubmaker-ng +176 -0
  13. data/bin/review-index +118 -0
  14. data/bin/review-pdfmaker +208 -0
  15. data/bin/review-preproc +142 -0
  16. data/bin/review-validate +51 -0
  17. data/bin/review-vol +102 -0
  18. data/debian/README.Debian +12 -0
  19. data/debian/README.source +5 -0
  20. data/debian/changelog +5 -0
  21. data/debian/compat +1 -0
  22. data/debian/control +22 -0
  23. data/debian/copyright +62 -0
  24. data/debian/docs +6 -0
  25. data/debian/manpage.1.ex +59 -0
  26. data/debian/patches/path.diff +91 -0
  27. data/debian/patches/series +1 -0
  28. data/debian/review.install +13 -0
  29. data/debian/review.links +4 -0
  30. data/debian/rules +13 -0
  31. data/debian/source/format +1 -0
  32. data/doc/format.rdoc +582 -0
  33. data/doc/format_idg.rdoc +180 -0
  34. data/doc/libepubmaker/sample.yaml +90 -0
  35. data/doc/quickstart.rdoc +188 -0
  36. data/doc/ruby-uuid/README +11 -0
  37. data/doc/ruby-uuid/README.ja +34 -0
  38. data/doc/sample.css +108 -0
  39. data/doc/sample.yaml +62 -0
  40. data/lib/epubmaker.rb +28 -0
  41. data/lib/epubmaker/content.rb +82 -0
  42. data/lib/epubmaker/epubv2.rb +418 -0
  43. data/lib/epubmaker/epubv3.rb +249 -0
  44. data/lib/epubmaker/producer.rb +204 -0
  45. data/lib/epubmaker/resource.rb +66 -0
  46. data/lib/lineinput.rb +155 -0
  47. data/lib/review.rb +3 -0
  48. data/lib/review/book.rb +46 -0
  49. data/lib/review/book/base.rb +235 -0
  50. data/lib/review/book/chapter.rb +81 -0
  51. data/lib/review/book/compilable.rb +159 -0
  52. data/lib/review/book/index.rb +339 -0
  53. data/lib/review/book/page_metric.rb +38 -0
  54. data/lib/review/book/parameters.rb +97 -0
  55. data/lib/review/book/part.rb +44 -0
  56. data/lib/review/book/volume.rb +65 -0
  57. data/lib/review/builder.rb +444 -0
  58. data/lib/review/compiler.rb +550 -0
  59. data/lib/review/configure.rb +38 -0
  60. data/lib/review/epubbuilder.rb +18 -0
  61. data/lib/review/exception.rb +21 -0
  62. data/lib/review/extentions.rb +3 -0
  63. data/lib/review/extentions/object.rb +9 -0
  64. data/lib/review/extentions/string.rb +33 -0
  65. data/lib/review/htmlbuilder.rb +1097 -0
  66. data/lib/review/htmllayout.rb +19 -0
  67. data/lib/review/htmlutils.rb +36 -0
  68. data/lib/review/i18n.rb +30 -0
  69. data/lib/review/i18n.yaml +34 -0
  70. data/lib/review/idgxmlbuilder.rb +1145 -0
  71. data/lib/review/latexbuilder.rb +815 -0
  72. data/lib/review/latexindex.rb +35 -0
  73. data/lib/review/latexutils.rb +79 -0
  74. data/lib/review/preprocessor.rb +563 -0
  75. data/lib/review/review.tex.erb +232 -0
  76. data/lib/review/textbuilder.rb +17 -0
  77. data/lib/review/textutils.rb +66 -0
  78. data/lib/review/tocparser.rb +342 -0
  79. data/lib/review/tocprinter.rb +221 -0
  80. data/lib/review/topbuilder.rb +785 -0
  81. data/lib/review/unfold.rb +138 -0
  82. data/lib/uuid.rb +312 -0
  83. data/review.gemspec +141 -0
  84. data/test/CHAPS +2 -0
  85. data/test/bib.re +13 -0
  86. data/test/book_test_helper.rb +35 -0
  87. data/test/test.re +43 -0
  88. data/test/test_book.rb +598 -0
  89. data/test/test_book_chapter.rb +418 -0
  90. data/test/test_book_parameter.rb +42 -0
  91. data/test/test_book_part.rb +50 -0
  92. data/test/test_builder.rb +144 -0
  93. data/test/test_compiler.rb +44 -0
  94. data/test/test_epubmaker.rb +507 -0
  95. data/test/test_helper.rb +27 -0
  96. data/test/test_htmlbuilder.rb +554 -0
  97. data/test/test_htmlutils.rb +28 -0
  98. data/test/test_i18n.rb +64 -0
  99. data/test/test_idgxmlbuilder.rb +589 -0
  100. data/test/test_index.rb +31 -0
  101. data/test/test_latexbuilder.rb +656 -0
  102. data/test/test_lineinput.rb +198 -0
  103. data/test/test_preprocessor.rb +23 -0
  104. data/test/test_textutils.rb +68 -0
  105. data/test/test_topbuilder.rb +244 -0
  106. data/test/test_uuid.rb +156 -0
  107. metadata +161 -0
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #
4
+ # Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ # For details of the GNU LGPL, see the file "COPYING".
10
+ #
11
+
12
+ require 'pathname'
13
+ bindir = Pathname.new(__FILE__).realpath.dirname
14
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
15
+ require 'review'
16
+ require 'epubmaker'
17
+ include EPUBMaker
18
+
19
+ def main
20
+ if ARGV.size != 1
21
+ puts "Usage: #{$0} configfile"
22
+ exit 0
23
+ end
24
+
25
+ yamlfile = ARGV[0]
26
+ @params = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile))
27
+ @epub = Producer.new(@params)
28
+ @epub.load(yamlfile)
29
+ @params = @epub.params
30
+
31
+ bookname = @params["bookname"]
32
+
33
+ if File.exist?("#{bookname}.epub")
34
+ STDERR.puts "#{bookname}.epub exists. Please remove or rename it first."
35
+ exit 1
36
+ end
37
+ if @params["debug"] && File.exist?("#{bookname}")
38
+ STDERR.puts "#{bookname} debug directory exists. Please remove or rename it first."
39
+ exit 1
40
+ end
41
+
42
+ basetmp = Dir.mktmpdir
43
+
44
+ FileUtils.cp(@params["cover"], "#{basetmp}/#{@params["cover"]}") if !@params["cover"].nil? && File.exist?(@params["cover"])
45
+
46
+ if @params["titlepage"] # FIXME
47
+ FileUtils.cp(@params["titlepage"], "#{basetmp}/#{@params["titlepage"]}")
48
+ @epub.contents.push(Content.new("id" => "title", "file" => @params["titlepage"], "title" => @epub.res.v("titlepagetitle")))
49
+ end
50
+
51
+ makeBody(basetmp, yamlfile)
52
+
53
+ if @params["colophon"]
54
+ if @params["colophon"].instance_of?(String)
55
+ FileUtils.cp(@params["colophon"], "#{basetmp}/colophon.#{@params["htmlext"]}")
56
+ else
57
+ File.open("#{basetmp}/colophon.#{@params["htmlext"]}", "w") {|f| @epub.colophon(f) }
58
+ end
59
+ @epub.contents.push(Content.new("id" => "colophon", "file" => "colophon.#{@params["htmlext"]}", "title" => @epub.res.v("colophontitle")))
60
+ end
61
+
62
+ epubtmpdir = @params["debug"].nil? ? nil : "#{Dir.pwd}/#{bookname}"
63
+ unless @params["debug"].nil?
64
+ Dir.mkdir(bookname)
65
+ end
66
+ @epub.produce("#{bookname}.epub", basetmp, epubtmpdir)
67
+
68
+ FileUtils.rm_r(basetmp)
69
+ end
70
+
71
+ def makeBody(basetmp, yamlfile)
72
+ pre = 0
73
+ body = 0
74
+ post = 0
75
+ @manifeststr = ""
76
+ @ncxstr = ""
77
+ @tocdesc = Array.new
78
+ toccount = 2
79
+
80
+ if File.exists?("PREDEF")
81
+ File.open("PREDEF") do |chaps|
82
+ chaps.each_line do |l|
83
+ pre += 1
84
+ next if l =~ /\A#/
85
+ fork {
86
+ STDOUT.reopen("#{basetmp}/pre#{pre}.#{@params["htmlext"]}")
87
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
88
+ }
89
+ Process.waitall
90
+ getanchors(basetmp, "pre#{pre}.#{@params["htmlext"]}")
91
+ end
92
+ end
93
+ end
94
+
95
+ if File.exists?("CHAPS")
96
+ File.open("CHAPS") do |chaps|
97
+ chaps.each_line do |l|
98
+ body += 1
99
+ next if l =~ /\A#/
100
+ fork {
101
+ STDOUT.reopen("#{basetmp}/chap#{body}.#{@params["htmlext"]}")
102
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
103
+ }
104
+ Process.waitall
105
+ getanchors(basetmp, "chap#{body}.#{@params["htmlext"]}")
106
+ end
107
+ end
108
+ end
109
+
110
+ if File.exists?("POSTDEF")
111
+ File.open("POSTDEF") do |chaps|
112
+ chaps.each_line do |l|
113
+ post += 1
114
+ next if l =~ /^#/
115
+ fork {
116
+ STDOUT.reopen("#{basetmp}/post#{post}.#{@params["htmlext"]}")
117
+ exec("review-compile --target=html --yaml=#{yamlfile} #{l}")
118
+ }
119
+ Process.waitall
120
+ getanchors(basetmp, "post#{post}.#{@params["htmlext"]}")
121
+ end
122
+ end
123
+ end
124
+ if File.exist?("images")
125
+ Dir.mkdir("#{basetmp}/images")
126
+ copyImagesToDir("images", "#{basetmp}/images")
127
+ end
128
+ end
129
+
130
+ def getanchors(basetmp, filename)
131
+ File.open("#{basetmp}/#{filename}") do |f|
132
+ firsttime = true
133
+ f.each_line do |l|
134
+ if l =~ /\A<h(\d)><a id=\"(.+?)\" \/>(.+?)<\/h/
135
+ # level, ID, content
136
+ level = $1.to_i
137
+ id = $2
138
+ title = $3
139
+ if level == 1 && !firsttime.nil?
140
+ @epub.contents.push(Content.new({
141
+ "id" => "#{filename.sub(".#{@params["htmlext"]}", '')}",
142
+ "file" => "#{filename}",
143
+ "level" => level,
144
+ "title" => title
145
+ }))
146
+ firsttime = nil
147
+ else
148
+ @epub.contents.push(Content.new({
149
+ "id" => "#{filename.sub(".#{@params["htmlext"]}", '')}-#{id}",
150
+ "file" => "#{filename}##{id}",
151
+ "level" => level,
152
+ "title" => title
153
+ }))
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ def copyImagesToDir(dirname, copybase)
161
+ Dir.open(dirname) do |dir|
162
+ dir.each do |fname|
163
+ next if fname =~ /\A\./
164
+ if FileTest.directory?("#{dirname}/#{fname}")
165
+ copyImagesToDir("#{dirname}/#{fname}", "#{copybase}/#{fname}")
166
+ else
167
+ if fname =~ /\.(png|gif|jpg|jpeg|svg)\Z/i
168
+ Dir.mkdir(copybase) unless File.exist?(copybase)
169
+ FileUtils.cp "#{dirname}/#{fname}", copybase
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ main
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #
4
+ # Copyright (c) 1999-2007 Minero Aoki
5
+ # 2008-2010 Minero Aoki, Kenshi Muto
6
+ #
7
+ # This program is free software.
8
+ # You can distribute or modify this program under the terms of
9
+ # the GNU LGPL, Lesser General Public License version 2.1.
10
+ # For details of the GNU LGPL, see the file "COPYING".
11
+ #
12
+
13
+ require 'pathname'
14
+
15
+ bindir = Pathname.new(__FILE__).realpath.dirname
16
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
17
+
18
+ require 'review/book'
19
+ require 'review/tocparser'
20
+ require 'review/tocprinter'
21
+ require 'optparse'
22
+
23
+ def main
24
+ Signal.trap(:INT) { exit 1 }
25
+ if RUBY_PLATFORM !~ /mswin(?!ce)|mingw|cygwin|bccwin/
26
+ Signal.trap(:PIPE, 'IGNORE')
27
+ end
28
+ _main
29
+ rescue Errno::EPIPE
30
+ exit 0
31
+ end
32
+
33
+ def _main
34
+ $KCODE = 'UTF-8' unless defined?(Encoding)
35
+
36
+ printer_class = ReVIEW::TextTOCPrinter
37
+ source = nil
38
+ upper = ReVIEW::TOCPrinter.default_upper_level
39
+ param = {
40
+ "inencoding" => "UTF-8",
41
+ "outencoding" => "UTF-8"
42
+ }
43
+
44
+ parser = OptionParser.new
45
+ parser.on('--inencoding=ENCODING', 'Set input encoding. (UTF-8, EUC, JIS, and SJIS)') {|enc|
46
+ param["inencoding"] = enc
47
+ }
48
+ parser.on('--outencoding=ENCODING', 'Set output encoding. (UTF-8[default], EUC, JIS, and SJIS)') {|enc|
49
+ param["outencoding"] = enc
50
+ }
51
+ parser.on('-a', '--all', 'print all chapters.') {
52
+ begin
53
+ source = ReVIEW.book
54
+ rescue ReVIEW::Error => err
55
+ error_exit err.message
56
+ end
57
+ }
58
+ parser.on('-p', '--part N', 'list only part N.') {|n|
59
+ source = ReVIEW.book.part(Integer(n)) or
60
+ error_exit "part #{n} does not exist in this book"
61
+ }
62
+ parser.on('-c', '--chapter C', 'list only chapter C.') {|c|
63
+ begin
64
+ source = ReVIEW::Book::Part.new(nil, 1, [ReVIEW.book.chapter(c)])
65
+ rescue
66
+ error_exit "chapter #{c} does not exist in this book"
67
+ end
68
+ }
69
+ parser.on('-l', '--level N', 'list upto N level (1..4, default=4)') {|n|
70
+ upper = Integer(n)
71
+ unless (0..4).include?(upper) # 0 is hidden option
72
+ $stderr.puts "-l/--level option accepts only 1..4"
73
+ exit 1
74
+ end
75
+ }
76
+ parser.on('--text', 'output in plain text (default)') {
77
+ printer_class = ReVIEW::TextTOCPrinter
78
+ }
79
+ parser.on('--html', 'output in HTML (deprecated)') {
80
+ printer_class = ReVIEW::HTMLTOCPrinter
81
+ }
82
+ parser.on('--idg', 'output in InDesign XML') {
83
+ printer_class = ReVIEW::IDGTOCPrinter
84
+ }
85
+ parser.on('--help', 'print this message and quit.') {
86
+ puts parser.help
87
+ exit 0
88
+ }
89
+ begin
90
+ parser.parse!
91
+ rescue OptionParser::ParseError => err
92
+ $stderr.puts err.message
93
+ $stderr.puts parser.help
94
+ exit 1
95
+ end
96
+ if source
97
+ unless ARGV.empty?
98
+ error_exit '-a/-s option and file arguments are exclusive'
99
+ end
100
+ else
101
+ puts parser.help
102
+ exit 0
103
+ end
104
+
105
+ begin
106
+ printer_class.new(upper, param).print_book source
107
+ rescue ReVIEW::Error, Errno::ENOENT => err
108
+ raise if $DEBUG
109
+ error_exit err.message
110
+ end
111
+ end
112
+
113
+ def error_exit(msg)
114
+ $stderr.puts "#{File.basename($0)}: #{msg}"
115
+ exit 1
116
+ end
117
+
118
+ main
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #
4
+ # Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ # For details of the GNU LGPL, see the file "COPYING".
10
+ #
11
+
12
+ require 'tmpdir'
13
+ require 'yaml'
14
+ require 'fileutils'
15
+ require 'erb'
16
+
17
+ require 'pathname'
18
+ bindir = Pathname.new(__FILE__).realpath.dirname
19
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
20
+
21
+ require 'review'
22
+
23
+ def error(msg)
24
+ $stderr.puts "#{File.basename($0, '.*')}: error: #{msg}"
25
+ exit 1
26
+ end
27
+
28
+ def usage
29
+ $stderr.puts "Usage: #{$0} configfile"
30
+ exit 0
31
+ end
32
+
33
+ def check_book(values)
34
+ pdf_file = values["bookname"]+".pdf"
35
+ if File.exists? pdf_file
36
+ error "file already exists:#{pdf_file}"
37
+ end
38
+ end
39
+
40
+ def build_path(values)
41
+ if values["debug"].nil?
42
+ Dir.mktmpdir+"/#{values["bookname"]}-pdf"
43
+ else
44
+ "./#{values["bookname"]}-pdf"
45
+ end
46
+ end
47
+
48
+ def main
49
+ usage if ARGV.size != 1
50
+
51
+ yamlfile = ARGV[0]
52
+ values = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile))
53
+ check_book(values)
54
+ @basedir = Dir.pwd
55
+ @path = build_path(values)
56
+ bookname = values["bookname"]
57
+ Dir.mkdir(@path)
58
+
59
+ @chaps_fnames = Hash.new{|h, key| h[key] = ""}
60
+
61
+ ReVIEW::Book.load(@basedir).parts.each do |part|
62
+ if part.name.present?
63
+ if part.file?
64
+ filename = "#{File.basename(part.path, ".*")}.tex"
65
+ output_chaps(filename, values)
66
+ @chaps_fnames["CHAPS"] << %Q|\\input{#{filename}}\n|
67
+ else
68
+ @chaps_fnames["CHAPS"] << %Q|\\part{#{part.name}}\n|
69
+ end
70
+ end
71
+
72
+ part.chapters.each do |chap|
73
+ filename = "#{File.basename(chap.path, ".*")}.tex"
74
+ output_chaps(filename, values)
75
+ @chaps_fnames["PREDEF"] << "\\input{#{filename}}\n" if chap.on_PREDEF?
76
+ @chaps_fnames["CHAPS"] << "\\input{#{filename}}\n" if chap.on_CHAPS?
77
+ @chaps_fnames["POSTDEF"] << "\\input{#{filename}}\n" if chap.on_POSTDEF?
78
+ end
79
+ end
80
+
81
+ values["pre_str"] = @chaps_fnames["PREDEF"]
82
+ values["chap_str"] = @chaps_fnames["CHAPS"]
83
+ values["post_str"] = @chaps_fnames["POSTDEF"]
84
+
85
+ values["usepackage"] = ""
86
+ if values["texstyle"]
87
+ values["usepackage"] = "\\usepackage{#{values['texstyle']}}"
88
+ end
89
+
90
+ copy_images("./images", "#{@path}/images")
91
+ copyStyToDir(Dir.pwd + "/sty", @path)
92
+ copyStyToDir(Dir.pwd, @path, "tex")
93
+
94
+ Dir.chdir(@path) {
95
+ template = get_template(values)
96
+ File.open("./book.tex", "wb"){|f| f.write(template)}
97
+
98
+ ## do compile
99
+ enc = values["params"].to_s.split(/\s+/).find{|i| i =~ /\A--outencoding=/ }
100
+ kanji = enc ? enc.split(/=/).last.gsub(/-/, '').downcase : 'utf8'
101
+ fork {
102
+ exec("platex -kanji=#{kanji} book.tex")
103
+ }
104
+ Process.waitall
105
+ fork {
106
+ exec("platex -kanji=#{kanji} book.tex")
107
+ }
108
+ Process.waitall
109
+ fork {
110
+ exec("platex -kanji=#{kanji} book.tex")
111
+ }
112
+ Process.waitall
113
+ fork {
114
+ exec("dvipdfmx -d 5 book.dvi")
115
+ }
116
+ Process.waitall
117
+ }
118
+ FileUtils.cp("#{@path}/book.pdf", "#{@basedir}/#{bookname}.pdf")
119
+ end
120
+
121
+ def output_chaps(filename, values)
122
+ fork {
123
+ STDOUT.reopen("#{@path}/#{filename}")
124
+ $stderr.puts "compiling #{filename}"
125
+ exec("review-compile --target=latex --level=#{values["secnolevel"]} --toclevel=#{values["toclevel"]} #{values["params"]} #{filename}")
126
+ }
127
+ Process.waitall
128
+ end
129
+
130
+ def copy_images(from, to)
131
+ if File.exist?(from)
132
+ Dir.mkdir(to)
133
+ ReVIEW::MakerHelper.copy_images_to_dir(from, to)
134
+ Dir.chdir(to) {
135
+ fork {
136
+ begin
137
+ exec("extractbb *.png *.jpg *.pdf */*.jpg */*.png */*.pdf;extractbb -m *.png *.jpg *.pdf */*.jpg */*.png */*.pdf")
138
+ rescue
139
+ exec("ebb *.png *.jpg *.pdf */*.jpg */*.png */*.pdf")
140
+ end
141
+ }
142
+ }
143
+ Process.waitall
144
+ end
145
+ end
146
+
147
+ def make_custom_titlepage(coverfile)
148
+ coverfile_sty = coverfile.to_s.sub(/\.[^.]+$/, ".tex")
149
+ if File.exist?(coverfile_sty)
150
+ File.read(coverfile_sty)
151
+ else
152
+ nil
153
+ end
154
+ end
155
+
156
+ def get_template(values)
157
+ dclass = values["texdocumentclass"] || []
158
+ documentclass = dclass[0] || "jsbook"
159
+ documentclassoption = dclass[1] || "oneside"
160
+
161
+ okuduke = ""
162
+ authors = ""
163
+ if values["aut"]
164
+ okuduke += "著 者 & #{values["aut"]} \\\\\n"
165
+ authors = values["aut"]+ "\\vspace*{1zh} 著"
166
+ end
167
+ if values["trl"]
168
+ authors += " \\\\\n"+values["trl"]+ "\\vspace*{1zh} 訳"
169
+ okuduke += "翻 訳 & #{values["trl"]} \\\\\n"
170
+ end
171
+ if values["edt"]
172
+ okuduke += "編集者 & #{values["edt"]} \\\\\n"
173
+ end
174
+ okuduke += <<EOB
175
+ 発行所 & #{values["prt"]} \\\\
176
+ EOB
177
+
178
+ custom_titlepage = make_custom_titlepage(values["coverfile"])
179
+
180
+ template = File.expand_path(File.dirname(__FILE__) +
181
+ '/../lib/review/review.tex.erb')
182
+ layout_file = File.join(@basedir, "layouts", "layout.tex.erb")
183
+ if File.exists?(layout_file)
184
+ template = layout_file
185
+ end
186
+
187
+ erb = ERB.new(File.open(template).read)
188
+ erb.result(binding)
189
+ end
190
+
191
+ def copyStyToDir(dirname, copybase, extname = "sty")
192
+ unless File.directory?(dirname)
193
+ $stderr.puts "No such directory - #{dirname}"
194
+ return
195
+ end
196
+
197
+ Dir.open(dirname) {|dir|
198
+ dir.each {|fname|
199
+ next if fname =~ /^\./
200
+ if fname =~ /\.(#{extname})$/i
201
+ Dir.mkdir(copybase) unless File.exist?(copybase)
202
+ FileUtils.cp "#{dirname}/#{fname}", copybase
203
+ end
204
+ }
205
+ }
206
+ end
207
+
208
+ main