api.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2023 The Knuth Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:generate make generate
  5. // Package tex is the TEX program by D. E. Knuth, transpiled to Go.
  6. //
  7. // http://mirrors.ctan.org/systems/knuth/dist/tex/tex.web
  8. package tex // modernc.org/knuth/tex
  9. import (
  10. // Required by go:embed
  11. _ "embed"
  12. "fmt"
  13. "io"
  14. "runtime/debug"
  15. "unsafe"
  16. "modernc.org/knuth"
  17. )
  18. //go:embed tex.pool
  19. var pool string
  20. // program TEX; {all file names are defined dynamically}
  21. // Main executes the tex program using the supplied arguments.
  22. func Main(stdin io.Reader, stdout, stderr io.Writer, options ...Option) (mainErr error) {
  23. defer func() {
  24. switch x := recover().(type) {
  25. case nil:
  26. // ok
  27. case signal:
  28. switch {
  29. case mainErr == nil:
  30. mainErr = fmt.Errorf("aborted")
  31. default:
  32. mainErr = fmt.Errorf("aborted: %v", mainErr)
  33. }
  34. case knuth.Error:
  35. mainErr = x
  36. default:
  37. mainErr = fmt.Errorf("PANIC %T: %[1]v, error: %v\n%s", x, mainErr, debug.Stack())
  38. }
  39. }()
  40. prg := &prg{
  41. dviFile: knuth.NewBinaryFile(nil, nil, 1, nil),
  42. fmtFile: knuth.NewBinaryFile(nil, nil, int(unsafe.Sizeof(memoryWord{})), opener),
  43. logFile: knuth.NewTextFile(nil, nil, nil),
  44. poolFile: knuth.NewPoolFile(pool),
  45. stderr: knuth.NewTextFile(nil, stderr, nil),
  46. termIn: knuth.NewTextFile(stdin, nil, nil),
  47. termOut: knuth.NewTextFile(nil, stdout, nil),
  48. tfmFile: knuth.NewBinaryFile(nil, nil, 1, opener),
  49. }
  50. for _, v := range options {
  51. if err := v(prg); err != nil {
  52. return err
  53. }
  54. }
  55. for i := range prg.inputFile {
  56. prg.inputFile[i] = knuth.NewTextFile(nil, nil, opener)
  57. }
  58. for i := range prg.writeFile {
  59. prg.writeFile[i] = knuth.NewTextFile(nil, nil, nil)
  60. }
  61. for i := range prg.readFile {
  62. prg.readFile[i] = knuth.NewTextFile(nil, nil, nil)
  63. }
  64. prg.main()
  65. return nil
  66. }
  67. var opener = func(nm string) (io.Reader, error) {
  68. return knuth.Open(nm, []string{"."})
  69. }
  70. // Option adjusts program behavior.
  71. type Option func(p *prg) error
  72. // WithInputFile replaces input file 'replace' with 'r'.
  73. func WithInputFile(replace string, r io.Reader) Option {
  74. return func(p *prg) error {
  75. prev := opener
  76. opener = func(nm string) (io.Reader, error) {
  77. if nm == replace {
  78. return r, nil
  79. }
  80. return prev(nm)
  81. }
  82. return nil
  83. }
  84. }
  85. // WithDVIFile sets the output DVI file to 'w'.
  86. func WithDVIFile(w io.Writer) Option {
  87. return func(p *prg) error {
  88. p.dviFile = &binaryWriter{w: w}
  89. return nil
  90. }
  91. }
  92. // WithLogFile sets the output log file to 'w'.
  93. func WithLogFile(w io.Writer) Option {
  94. return func(p *prg) error {
  95. p.logFile = &textWriter{w: w}
  96. return nil
  97. }
  98. }
  99. type binaryWriter struct {
  100. buf [1]byte
  101. w io.Writer
  102. }
  103. func (w *binaryWriter) ByteP() *byte {
  104. panic("internal error")
  105. }
  106. func (w *binaryWriter) Close() {
  107. // nop
  108. }
  109. func (w *binaryWriter) CurPos() int32 {
  110. panic("internal error")
  111. }
  112. func (w *binaryWriter) Data4P() *[4]byte {
  113. panic("internal error")
  114. }
  115. func (w *binaryWriter) EOF() bool {
  116. panic("internal error")
  117. }
  118. func (w *binaryWriter) EOLN() bool {
  119. panic("internal error")
  120. }
  121. func (w *binaryWriter) ErStat() int32 {
  122. return 0
  123. }
  124. func (w *binaryWriter) Get() {
  125. panic("internal error")
  126. }
  127. func (w *binaryWriter) Put() {
  128. panic("internal error")
  129. }
  130. func (w *binaryWriter) Read(args ...interface{}) {
  131. panic("internal error")
  132. }
  133. func (w *binaryWriter) Readln(args ...interface{}) {
  134. panic("internal error")
  135. }
  136. func (w *binaryWriter) Reset(args ...interface{}) {
  137. panic("internal error")
  138. }
  139. func (w *binaryWriter) Rewrite(args ...interface{}) {
  140. // nop
  141. }
  142. func (w *binaryWriter) SetPos(int32) {
  143. panic("internal error")
  144. }
  145. func (w *binaryWriter) Write(args ...interface{}) {
  146. for _, v := range args {
  147. w.buf[0] = v.(byte)
  148. w.w.Write(w.buf[:])
  149. }
  150. }
  151. func (w *binaryWriter) Writeln(args ...interface{}) {
  152. panic("internal error")
  153. }
  154. type textWriter struct {
  155. w io.Writer
  156. }
  157. func (w *textWriter) ByteP() *byte {
  158. panic("internal error")
  159. }
  160. func (w *textWriter) Close() {
  161. // nop
  162. }
  163. func (w *textWriter) CurPos() int32 {
  164. panic("internal error")
  165. }
  166. func (w *textWriter) Data4P() *[4]byte {
  167. panic("internal error")
  168. }
  169. func (w *textWriter) EOF() bool {
  170. panic("internal error")
  171. }
  172. func (w *textWriter) EOLN() bool {
  173. panic("internal error")
  174. }
  175. func (w *textWriter) ErStat() int32 {
  176. return 0
  177. }
  178. func (w *textWriter) Get() {
  179. panic("internal error")
  180. }
  181. func (w *textWriter) Put() {
  182. panic("internal error")
  183. }
  184. func (w *textWriter) Read(args ...interface{}) {
  185. panic("internal error")
  186. }
  187. func (w *textWriter) Readln(args ...interface{}) {
  188. panic("internal error")
  189. }
  190. func (w *textWriter) Reset(args ...interface{}) {
  191. panic("internal error")
  192. }
  193. func (w *textWriter) Rewrite(args ...interface{}) {
  194. // nop
  195. }
  196. func (w *textWriter) SetPos(int32) {
  197. panic("internal error")
  198. }
  199. func (w *textWriter) Write(args ...interface{}) {
  200. for _, v := range args {
  201. fmt.Fprintf(w.w, "%v", v)
  202. }
  203. }
  204. func (w *textWriter) Writeln(args ...interface{}) {
  205. for _, v := range args {
  206. fmt.Fprintf(w.w, "%v", v)
  207. }
  208. fmt.Fprintln(w.w)
  209. }