rfil 0.2

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.
@@ -0,0 +1,90 @@
1
+ =begin rdoc
2
+ Plugin for RFIL to create a typescript usable for ConTeXt.
3
+ =end
4
+
5
+ # :enddoc:
6
+
7
+ class TypescriptWriterConTeXt < RFIL::RFI::Plugin
8
+
9
+ def initialize(fontcollection)
10
+ @fc=fontcollection
11
+ super(:context,:typescript)
12
+ end
13
+
14
+ STOPTYPESCRIPT="\\stoptypescript\n\n"
15
+
16
+ def run_plugin
17
+ ret=[]
18
+ str=""
19
+ puts "running context plugin" if @fc.options[:verbose]
20
+ @fc.texenc.each { |e|
21
+ str << typescript(e)
22
+ str << "\n"
23
+ }
24
+ h={}
25
+ h[:type]=:typescript
26
+ h[:filename],h[:contents]=["type-#{@fc.name}.tex",str]
27
+ ret.push(h)
28
+ ret
29
+ end
30
+
31
+ # Returns hash: Style, font
32
+ def find_fonts
33
+ ret={}
34
+ @fc.fonts.each { |font|
35
+ ret[""]=font if font.variant==:regular and font.weight==:regular
36
+ # ret[""]=font if font.variant==:regular and font.weight==:regular and font.style!=:sans
37
+ ret["Bold"]=font if font.variant==:regular and font.weight==:bold
38
+ ret["Italic"]=font if font.variant==:italic and font.weight==:regular
39
+ ret["Caps"]=font if font.variant==:smallcaps and font.weight==:regular
40
+ }
41
+ ret
42
+ end
43
+ def typescript(e)
44
+ contextenc=case e.encname
45
+ when "ECEncoding"
46
+ "ec"
47
+ when "TS1Encoding"
48
+ "ts1"
49
+ when "T1Encoding"
50
+ "tex256"
51
+ when "TeXBase1Encoding"
52
+ "8r"
53
+ else
54
+ raise "unknown context encoding: #{e.encname}"
55
+ end
56
+ # i know that this is crap, it's just a start
57
+ contextstyle=case @fc.style
58
+ when :sans
59
+ "Sans"
60
+ when :roman, :serif
61
+ "Serif"
62
+ when :typewriter
63
+ "Typewriter"
64
+ else
65
+ raise "unknown style found: #{@fc.style}"
66
+ end
67
+ tmp = ""
68
+ fontname=@fc.name
69
+ tmp << "\\starttypescript[#{@fc.style}][#{fontname}][name]\n"
70
+ find_fonts.sort{ |a,b| a[0] <=> b[0]}.each { |style,font|
71
+ tmp << "\\definefontsynonym [#{contextstyle}"
72
+ p style
73
+ tmp << "#{style}" if style.length > 0
74
+ tmp << "] [#{fontname}"
75
+ tmp << "-#{style}" if style.length > 0
76
+ tmp << "]\n"
77
+ }
78
+ tmp << STOPTYPESCRIPT
79
+
80
+ tmp << "\\starttypescript[#{@fc.style}][#{fontname}][#{contextenc}]\n"
81
+ find_fonts.sort{ |a,b| a[0] <=> b[0]}.each { |style,font|
82
+ tmp << "\\definefontsynonym [#{fontname}"
83
+ tmp << "-#{style}" if style.length > 0
84
+ tmp << "][#{font.tex_fontname(e)}]\n"
85
+ }
86
+ tmp << STOPTYPESCRIPT
87
+
88
+ return tmp
89
+ end
90
+ end
@@ -0,0 +1,95 @@
1
+ =begin rdoc
2
+ Plugin for RFIL to create a fontdefinition file (<tt>.fd</tt>) for LaTeX
3
+ =end
4
+
5
+ # :enddoc:
6
+
7
+ class FDWriterLaTeX < RFIL::RFI::Plugin
8
+
9
+ def initialize(fontcollection)
10
+ @fc=fontcollection
11
+ super(:latex,:sty)
12
+ end
13
+
14
+ def run_plugin
15
+ ret=[]
16
+ @fc.texenc.each { |e|
17
+ h={}
18
+ h[:type]=:fd
19
+ h[:filename],h[:contents]=latex_fd(e)
20
+ ret.push(h)
21
+ }
22
+ ret
23
+ end
24
+
25
+
26
+ # example, should be an extra plugin
27
+ def latex_fd(e)
28
+ latexenc=case e.encname
29
+ when "ECEncoding","T1Encoding"
30
+ "T1"
31
+ when "TeXBase1Encoding"
32
+ "8r"
33
+ when "TS1Encoding"
34
+ "TS1"
35
+ when "OT2AdobeEncoding"
36
+ "OT2"
37
+ else
38
+ raise "unknown latex encoding: #{e.encname}"
39
+ end
40
+ filename="#{latexenc.downcase}#{@fc.name}.fd"
41
+
42
+ fd="\\ProvidesFile{#{filename}}
43
+ \\DeclareFontFamily{#{latexenc}}{#{@fc.name}}{}
44
+ "
45
+ weight=[:m,:b,:bx]
46
+ variant=[:n,:sc,:sl,:it]
47
+ for i in 0..11
48
+ w=weight[i/4]
49
+ v=variant[i % 4]
50
+ f=find_font(w,v)
51
+ if f
52
+ name = f.tex_fontname(e)
53
+ else
54
+ if i < 4
55
+ name = "ssub * #{@fc.name}/m/n"
56
+ else
57
+ name = "ssub * #{@fc.name}/#{weight[i/4 - 1]}/#{v}"
58
+ end
59
+ end
60
+
61
+ # [[:m,:n],[:m,:sc],[:m,:sl],[:m,:it],
62
+ # [:b,:n],[:b,:sc],[:b,:sl],[:b,:it],
63
+ # [:bx,:n],[:bx,:sc],[:bx,:sl],[:bx,:it]].each{ |w,v|
64
+ # f=find_font(w,v)
65
+
66
+ # name = f ? f.tex_fontname(e) : "<->ssub * #{@fc.name}/m/n"
67
+ fd << "\\DeclareFontShape{#{latexenc}}{#{@fc.name}}{#{w}}{#{v}}{
68
+ <-> #{name}
69
+ }{}
70
+ "
71
+ end
72
+ return [filename,fd]
73
+ end
74
+ def find_font(w,v)
75
+ weight={}
76
+ variant={}
77
+ weight[:m]=:regular
78
+ weight[:b]=:bold
79
+ variant[:n]=:regular
80
+ variant[:it]=:italic
81
+ variant[:sl]=:slanted
82
+ variant[:sc]=:smallcaps
83
+
84
+ # w is one of :m, :b, :bx
85
+ # v is one of :n, :sc, :sl, :it
86
+ @fc.fonts.each { |font|
87
+ #p b[:weight]==weight[w]
88
+ if font.variant ==variant[v] and font.weight==weight[w]
89
+ return font
90
+ end
91
+ }
92
+ return nil
93
+ end
94
+
95
+ end
@@ -0,0 +1,3 @@
1
+ RFIL_VERSION="0.2"
2
+ COPYRIGHT="Copyright (c) 2006 Patrick Gundlach <patrick@gundla.ch>"
3
+ HOMEPAGE="https://foundry.supelec.fr/projects/rfil"
data/lib/tex/enc.rb ADDED
@@ -0,0 +1,223 @@
1
+ #--
2
+ # enc.rb - read and parse TeX's encoding files
3
+ # Last Change: Tue May 16 17:24:31 2006
4
+ #++
5
+ # See the class ENC for the api description.
6
+
7
+ require 'strscan'
8
+ require 'set'
9
+ require 'forwardable'
10
+
11
+ module TeX
12
+
13
+ # = ENC -- Access encoding files
14
+ #
15
+ # == General information
16
+ #
17
+ # Read a TeX encoding vector (<tt>.enc</tt>-file) and associated
18
+ # ligkern instructions. The encoding slot are accessible via <em>[]</em>
19
+ # and <em>[]=</em>, just like an Array.
20
+ #
21
+ # == Example usage
22
+ #
23
+ # === Read an encoding file
24
+ # filename = "/opt/tetex/3.0/texmf/fonts/enc/dvips/base/EC.enc"
25
+ # File.open(filename) { |encfile|
26
+ # enc=ENC.new(encfile)
27
+ # enc.encname # => "ECEncoding"
28
+ # enc # => ['grave','acute',...]
29
+ # enc.filename # => "EC.enc"
30
+ # enc.ligkern_instructions # => ["space l =: lslash","space L =: Lslash",... ]
31
+ # }
32
+ # === Create an encoding
33
+ # enc=ENC.new
34
+ # enc.encname="Exampleenc"
35
+ # enc[0]="grave"
36
+ # # all undefined slots are ".notdef"
37
+ # ....
38
+ #
39
+ # # write encoding to <tt>new.enc</tt>
40
+ # File.open("new.enc") do |f|
41
+ # f << enc.to_s
42
+ # end
43
+ # ---
44
+ # Remark: This interface is pretty much fixed.
45
+ #--
46
+ # dont't subclass Array directly, it might be a bad idea. See for
47
+ # example [ruby-talk:147327]
48
+ #++
49
+
50
+ class ENC # < DelegateClass(Array)
51
+ def self.documented_as_accessor(*args) # :nodoc:
52
+ end
53
+
54
+ extend Forwardable
55
+ def_delegators(:@encvector, :size, :[],:each, :each_with_index)
56
+
57
+ # _encname_ is the PostScript name of the encoding vector.
58
+ attr_accessor :encname
59
+
60
+ # ligkern_instructions is an array of strings (instructions) as
61
+ # found in the encoding file, such as:
62
+ # "quoteright quoteright =: quotedblright"
63
+ # "* {} space"
64
+ attr_accessor :ligkern_instructions
65
+
66
+ # Hash: key is glyph name, value is a Set of indexes.
67
+ # Example: glyph_index['hyphen']=#<Set: {45, 127}> in
68
+ # <tt>ec.enc</tt>. Automatically updated when changing the encoding
69
+ # vector via <em>[]=</em>.
70
+ attr_reader :glyph_index
71
+
72
+ # Filename of the encoding vector. Used for creating mapfile
73
+ # entries. Always ends with ".enc" if read (unless it is unset).
74
+ documented_as_accessor :filename
75
+
76
+ # Optional enc is either a File object or a string with the contents
77
+ # of a file. If set, the object is initialized with the given
78
+ # encoding vector.
79
+ def initialize (enc=nil)
80
+ @glyph_index={}
81
+ @ligkern_instructions=[]
82
+ # File, Tempfile, IO respond to read
83
+ if enc
84
+ @encvector=[]
85
+ string = enc.respond_to?(:read) ? enc.read : enc
86
+ if enc.respond_to?(:path)
87
+ self.filename= enc.path
88
+ end
89
+ parse(string)
90
+ else
91
+ @encvector=Array.new(256,".notdef")
92
+ end
93
+ end
94
+
95
+ def filename # :nodoc:
96
+ @filename
97
+ end
98
+
99
+ def filename=(fn) # :nodoc:
100
+ @filename=File.basename(fn.chomp(".enc")+".enc")
101
+ end
102
+
103
+ # Return true if the encoding name and the encoding Array are the
104
+ # same. If _obj_ is an Array, only compare the Array elements.
105
+ def ==(obj)
106
+ return false if obj==nil
107
+ if obj.instance_of?(ENC)
108
+ return false unless @encname==obj.encname
109
+ end
110
+
111
+ return false unless obj.respond_to?(:[])
112
+ 0.upto(255) { |i|
113
+ return false if @encvector[i]!=obj[i]
114
+ }
115
+ true
116
+ end
117
+
118
+ # todo: document and test
119
+ def -(obj)
120
+ tmp=[]
121
+ for i in 0..255
122
+ tmp[i]=obj[i]
123
+ end
124
+ @encvector - tmp
125
+ end
126
+
127
+ # also updates the glyph_index
128
+ def []=(i,obj) # :nodoc:
129
+ if obj==nil and @encvector[i] != nil
130
+ @glyph_index.delete(@encvector[i])
131
+ return obj
132
+ end
133
+
134
+ @encvector[i]=obj
135
+ addtoindex(obj,i)
136
+ return obj
137
+ end
138
+
139
+ # Return a string representation of the encoding that is compatible
140
+ # with dvips and alike.
141
+ def to_s
142
+ str = ""
143
+ @ligkern_instructions.each { |instr|
144
+ str << "% LIGKERN #{instr} ;\n"
145
+ }
146
+ str << "%\n"
147
+ str << "/#@encname [\n"
148
+ @encvector.each_with_index { |glyphname,i|
149
+ str << "% #{i}\n" if (i % 16 == 0)
150
+ str << " " unless (i % 8 == 0)
151
+ str << "/#{glyphname}"
152
+ str << "\n" if (i % 8 == 7)
153
+ }
154
+ str << "] def\n"
155
+ str
156
+ end
157
+
158
+ #######
159
+ private
160
+ #######
161
+
162
+ # creates the glyph_index from the encvector. Use this method after
163
+ # you made changes to the encvector.
164
+ def update_glyph_index
165
+ @encvector.each_with_index { |name,i|
166
+ next if name==".notdef"
167
+ addtoindex(name,i)
168
+ }
169
+ end
170
+
171
+ # Adds position i to glyph_index for glyph _glyph_.
172
+ def addtoindex(glyph,i)
173
+ return if glyph==".notdef"
174
+ if @glyph_index[glyph]
175
+ @glyph_index[glyph].add i
176
+ else
177
+ @glyph_index[glyph]=Set.new().add(i)
178
+ end
179
+ end
180
+
181
+ # return the next postscript element (e.g. /name or [ )
182
+ def tok(s)
183
+ unless s.peek(1) == "/"
184
+ s.skip_until(/[^\/\[\]]+/) # not '/' '[' or ']'
185
+ end
186
+ s.scan(/(?:\/\.?\w+|\[|\])/)
187
+ end
188
+
189
+ # fill Array with contents of string.
190
+ def parse(str)
191
+ count=0
192
+ s=StringScanner.new(str)
193
+ ligkern=""
194
+ while s.skip_until(/^%\s+LIGKERN\s+/)
195
+ ligkern << s.scan_until(/$/)
196
+ end
197
+ ligkern.split(';').each { |instruction|
198
+ @ligkern_instructions.push instruction.strip
199
+ }
200
+ s.string=(str.gsub(/%.*/,''))
201
+ t=tok(s)
202
+ @encname=t[1,t.length-1]
203
+ loop do
204
+ t = tok(s)
205
+ case t
206
+ when "["
207
+ # ignore
208
+ when "]"
209
+ unless @encvector.size == 256
210
+ raise "Unexpected size of encoding. It should contain 256 entries, but has #{@encvector.size} entries."
211
+ end
212
+ update_glyph_index
213
+ return
214
+ else
215
+ name = t[1,t.length-1]
216
+ @encvector.push(name)
217
+ end
218
+ end
219
+ # never reached
220
+ raise "Internal ENC error"
221
+ end
222
+ end #class Enc
223
+ end
@@ -0,0 +1,63 @@
1
+ #--
2
+ # kpathsea.rb - libkpathsea access for ruby
3
+ # Last Change: Tue May 16 17:23:14 2006
4
+ #++
5
+
6
+
7
+ module TeX
8
+
9
+ # Find TeX related files with help of the 'kpsewhich' program.
10
+ class Kpathsea
11
+ # _progname_ defaults to the name of the main Ruby script.
12
+ # _progname_ is used to find program specific files as in
13
+ # <tt>TEXINPUT.progname</tt> in the <tt>texmf.cnf</tt>.
14
+ def initialize (progname=File.basename($0))
15
+ raise ArgumentError if progname.match(/('|")/)
16
+ @progname=progname
17
+ end
18
+
19
+ def reset_program_name(suffix)
20
+ @progname=suffix
21
+ end
22
+
23
+ # Return the complete path of the file _name_. _name_ must not
24
+ # contain single or double quotes.
25
+ def find_file(name,fmt="tex",mustexist=false)
26
+ raise ArgumentError if name.match(/('|")/)
27
+ raise ArgumentError if fmt.match(/('|")/)
28
+ runkpsewhich(name,fmt,mustexist)
29
+ end
30
+
31
+ # Return a File object. Raise Errno::ENOENT if file is not found. If
32
+ # block is given, a File object is passed into the block and the
33
+ # file gets closed when leaving the block. It behaves exactly as
34
+ # the File.open method.
35
+ def open_file(name,fmt="tex")
36
+ loc=self.find_file(name,fmt)
37
+ raise Errno::ENOENT, "#{name}" unless loc
38
+ if block_given?
39
+ File.open(loc) { |file|
40
+ yield file
41
+ }
42
+ else
43
+ File.open(loc)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def runkpsewhich(name,fmt,mustexist)
50
+ fmt.untaint
51
+ name.untaint
52
+ @progname.untaint
53
+ # path or amok XXX
54
+ cmdline= "kpsewhich -progname=\"#{@progname}\" -format=\"#{fmt}\" #{name}"
55
+ # puts cmdline
56
+ lines = ""
57
+ IO.popen(cmdline) do |io|
58
+ lines = io.readlines
59
+ end
60
+ return $? == 0 ? lines.to_s.chomp.untaint : nil
61
+ end
62
+ end
63
+ end