1module JISX0208
2  class Char
3    class << self
4      def from_sjis(sjis)
5        unless 0x8140 <= sjis && sjis <= 0xFCFC
6          raise ArgumentError, "out of the range of JIS X 0208: 0x#{sjis.to_s(16)}"
7        end
8        sjis_hi, sjis_lo = sjis >> 8, sjis & 0xFF
9        sjis_hi = (sjis_hi - ((sjis_hi <= 0x9F) ? 0x80 : 0xC0)) << 1
10        if sjis_lo <= 0x9E
11          sjis_hi -= 1
12          sjis_lo -= (sjis_lo <= 0x7E) ? 0x3F : 0x40
13        else
14          sjis_lo -= 0x9E
15        end
16        return self.new(sjis_hi, sjis_lo)
17      end
18    end
19
20    def initialize(row, cell=nil)
21      if cell
22        @code = row_cell_to_code(row, cell)
23      else
24        @code = row.to_int
25      end
26    end
27
28    def ==(other)
29      if self.class === other
30        return Integer(self) == Integer(other)
31      end
32      return super(other)
33    end
34
35    def to_int
36      return @code
37    end
38
39    def hi
40      Integer(self) >> 8
41    end
42
43    def lo
44      Integer(self) & 0xFF
45    end
46
47    def row
48      self.hi - 0x20
49    end
50
51    def cell
52      self.lo - 0x20
53    end
54
55    def succ
56      succ_hi, succ_lo = self.hi, self.lo + 1
57      if succ_lo > 0x7E
58        succ_lo = 0x21
59        succ_hi += 1
60      end
61      return self.class.new(succ_hi << 8 | succ_lo)
62    end
63
64    def to_sjis
65      h, l = self.hi, self.lo
66      h = (h + 1) / 2 + ((0x21..0x5E).include?(h) ? 0x70 : 0xB0)
67      l += self.hi.odd? ? 0x1F + ((l >= 0x60) ? 1 : 0) : 0x7E
68      return h << 8 | l
69    end
70
71    def inspect
72      "#<JISX0208::Char:#{self.object_id.to_s(16)} sjis=#{self.to_sjis.to_s(16)} jis=#{self.to_int.to_s(16)}>"
73    end
74
75    private
76
77    def row_cell_to_code(row, cell)
78      unless 0 < row && (1..94).include?(cell)
79        raise ArgumentError, "out of row-cell range: #{row}-#{cell}"
80      end
81      return (row + 0x20) << 8 | (cell + 0x20)
82    end
83  end
84end
85