No Description

code.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright (C) 2017 Keelan Lightfoot
  2. // Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
  3. // System (Univ. of Wisconsin-Madison, Trace R&D Center)
  4. // Copyright (C) 2007-2008 Omnitor AB
  5. // Copyright (C) 2007-2008 Voiceriver Inc
  6. //
  7. // This library is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU Lesser General Public License as published by
  9. // the Free Software Foundation; either version 2.1 of the License, or (at
  10. // your option) any later version.
  11. package gortty
  12. import (
  13. "fmt"
  14. "unicode"
  15. )
  16. const (
  17. shiftUnknown = iota
  18. shiftLetter
  19. shiftFigure
  20. shiftWhitespace
  21. )
  22. var (
  23. defaultSubstitutes = map[rune]rune{
  24. '{': '(',
  25. '}': ')',
  26. '[': '(',
  27. ']': ')',
  28. }
  29. codeSets = map[string]CodeSet{
  30. // TDD Telecommunications Device for the Deaf standard
  31. "TDD": CodeSet{
  32. Codes: [2][]rune{
  33. {'\b', 'E', '\n', 'A', ' ', 'S', 'I', 'U', '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G', '\x0e', 'M', 'X', 'V', '\x0f'},
  34. {'\b', '3', '\n', '-', ' ', ',', '8', '7', '\r', '$', '4', '\'', ',', '!', ':', '(', '5', '"', ')', '2', '=', '6', '0', '1', '9', '?', '+', '\x0e', '.', '/', ';', '\x0f'},
  35. },
  36. Substitutes: defaultSubstitutes,
  37. Fallback: '\'',
  38. ShiftCode: 0x1b,
  39. UnshiftCode: 0x1f,
  40. },
  41. // USTTY US Teletype Corporation
  42. "USTTY": CodeSet{
  43. Codes: [2][]rune{
  44. {'\x00', 'E', '\n', 'A', ' ', 'S', 'I', 'U', '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G', '\x0e', 'M', 'X', 'V', '\x0f'},
  45. {'\x00', '3', '\n', '-', ' ', '\a', '8', '7', '\r', '$', '4', '\'', ',', '!', ':', '(', '5', '"', ')', '2', '#', '6', '0', '1', '9', '?', '&', '\x0e', '.', '/', ';', '\x0f'},
  46. },
  47. Substitutes: defaultSubstitutes,
  48. Fallback: '-',
  49. ShiftCode: 0x1b,
  50. UnshiftCode: 0x1f,
  51. },
  52. // USITA2 USITA2
  53. "USITA2": CodeSet{
  54. Codes: [2][]rune{
  55. {'\x00', 'E', '\n', 'A', ' ', 'S', 'I', 'U', '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G', '\x0e', 'M', 'X', 'V', '\x0f'},
  56. {'\x00', '3', '\n', '-', ' ', '\'', '8', '7', '\r', '$', '4', '\a', ',', '!', ':', '(', '5', '"', ')', '2', '=', '6', '0', '1', '9', '?', '&', '\x0e', '.', '/', '=', '\x0f'},
  57. },
  58. Substitutes: defaultSubstitutes,
  59. Fallback: '-',
  60. ShiftCode: 0x1b,
  61. UnshiftCode: 0x1f,
  62. },
  63. // Weather US Weather
  64. "Weather": CodeSet{
  65. Codes: [2][]rune{
  66. {'\x00', 'E', '\n', 'A', ' ', 'S', 'I', 'U', '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G', '\x0e', 'M', 'X', 'V', '\x0f'},
  67. {'\x00', '3', '\n', '↑', ' ', '\a', '8', '7', '\r', '↗', '4', '↙', '⦷', '→', '○', '←', '5', '+', '↖', '2', '↓', '6', '0', '1', '9', '⊕', '↘', '\x0e', '.', '/', '⦶', '\x0f'},
  68. },
  69. Substitutes: defaultSubstitutes,
  70. Fallback: '-',
  71. ShiftCode: 0x1b,
  72. UnshiftCode: 0x1f,
  73. },
  74. // Fractions US Fractions
  75. "Fractions": CodeSet{
  76. Codes: [2][]rune{
  77. {'\x00', 'E', '\n', 'A', ' ', 'S', 'I', 'U', '\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K', 'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G', '\x0e', 'M', 'X', 'V', '\x0f'},
  78. {'\x00', '3', '\n', '↑', ' ', '\a', '8', '7', '\r', '$', '4', '\'', '⅞', '¼', '⅛', '½', '5', '"', '¾', '2', ' ', '6', '0', '1', '9', '⅝', '&', '\x0e', '.', '/', '⅜', '\x0f'},
  79. },
  80. Substitutes: defaultSubstitutes,
  81. Fallback: '-',
  82. ShiftCode: 0x1b,
  83. UnshiftCode: 0x1f,
  84. },
  85. }
  86. )
  87. // CodeSet represents a teletype character set.
  88. type CodeSet struct {
  89. // Codes specifies a mapping of runes to codes. There are two tables, 0 for ltrs, 1 for figs
  90. Codes [2][]rune
  91. // Substitutes specifies what characters to re-map to existing table entries
  92. Substitutes map[rune]rune
  93. // Fallback specifies what rune to use when a table entry or substitution cant be found
  94. Fallback rune
  95. // ShiftRune is fun
  96. ShiftCode byte
  97. // UnshiftRune is fun
  98. UnshiftCode byte
  99. runeToCodeSet map[rune]code
  100. initialized bool
  101. }
  102. type code struct {
  103. shift int
  104. v byte
  105. }
  106. //LoadCodeSet is fun
  107. func LoadCodeSet(n string) (*CodeSet, error) {
  108. cs, ok := codeSets[n]
  109. if !ok {
  110. return nil, fmt.Errorf("Attempt to load nonexistent codeset: %s", n)
  111. }
  112. cs.initialize()
  113. return &cs, nil
  114. }
  115. func (cs *CodeSet) initialize() *CodeSet {
  116. cs.runeToCodeSet = make(map[rune]code)
  117. for i, runes := range cs.Codes {
  118. var shift int
  119. switch i {
  120. case 0:
  121. shift = shiftLetter
  122. case 1:
  123. shift = shiftFigure
  124. }
  125. for v, r := range runes {
  126. if c, exists := cs.runeToCodeSet[r]; exists {
  127. c.shift = shiftWhitespace
  128. cs.runeToCodeSet[r] = c
  129. } else {
  130. cs.runeToCodeSet[r] = code{
  131. shift: shift,
  132. v: byte(v),
  133. }
  134. }
  135. }
  136. }
  137. for in, out := range cs.Substitutes {
  138. if _, ok := cs.runeToCodeSet[in]; ok {
  139. // dont load a translation if it overlaps an existing table entry
  140. continue
  141. }
  142. if b, ok := cs.runeToCodeSet[out]; ok {
  143. // only set the translation if the output exists in table
  144. cs.runeToCodeSet[in] = b
  145. }
  146. }
  147. return cs
  148. }
  149. func (cs *CodeSet) toCode(r rune) code {
  150. if c, ok := cs.runeToCodeSet[unicode.ToUpper(r)]; ok {
  151. return c
  152. }
  153. return cs.runeToCodeSet[cs.Fallback]
  154. }
  155. func (cs *CodeSet) toByte(r rune) byte {
  156. if c, ok := cs.runeToCodeSet[unicode.ToUpper(r)]; ok {
  157. return c.v
  158. }
  159. return cs.runeToCodeSet[cs.Fallback].v
  160. }
  161. func (c code) toByte() byte {
  162. return c.v
  163. }
  164. func (cs *CodeSet) shift() byte {
  165. return cs.ShiftCode
  166. }
  167. func (cs *CodeSet) unshift() byte {
  168. return cs.UnshiftCode
  169. }
  170. func (cs *CodeSet) toRune(shift int, b byte) rune {
  171. var i int
  172. switch shift {
  173. case shiftLetter:
  174. i = 0
  175. case shiftFigure:
  176. i = 1
  177. }
  178. if int(b) < len(cs.Codes[i]) {
  179. return cs.Codes[i][int(b)]
  180. }
  181. return '�'
  182. }