| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Copyright 2023 The Knuth Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- //go:generate make generate
- // Package tex is the TEX program by D. E. Knuth, transpiled to Go.
- //
- // http://mirrors.ctan.org/systems/knuth/dist/tex/tex.web
- package tex // modernc.org/knuth/tex
- import (
- // Required by go:embed
- _ "embed"
- "fmt"
- "io"
- "runtime/debug"
- "unsafe"
- "modernc.org/knuth"
- )
- //go:embed tex.pool
- var pool string
- // program TEX; {all file names are defined dynamically}
- // Main executes the tex program using the supplied arguments.
- func Main(stdin io.Reader, stdout, stderr io.Writer, options ...Option) (mainErr error) {
- defer func() {
- switch x := recover().(type) {
- case nil:
- // ok
- case signal:
- switch {
- case mainErr == nil:
- mainErr = fmt.Errorf("aborted")
- default:
- mainErr = fmt.Errorf("aborted: %v", mainErr)
- }
- case knuth.Error:
- mainErr = x
- default:
- mainErr = fmt.Errorf("PANIC %T: %[1]v, error: %v\n%s", x, mainErr, debug.Stack())
- }
- }()
- prg := &prg{
- dviFile: knuth.NewBinaryFile(nil, nil, 1, nil),
- fmtFile: knuth.NewBinaryFile(nil, nil, int(unsafe.Sizeof(memoryWord{})), opener),
- logFile: knuth.NewTextFile(nil, nil, nil),
- poolFile: knuth.NewPoolFile(pool),
- stderr: knuth.NewTextFile(nil, stderr, nil),
- termIn: knuth.NewTextFile(stdin, nil, nil),
- termOut: knuth.NewTextFile(nil, stdout, nil),
- tfmFile: knuth.NewBinaryFile(nil, nil, 1, opener),
- }
- for _, v := range options {
- if err := v(prg); err != nil {
- return err
- }
- }
- for i := range prg.inputFile {
- prg.inputFile[i] = knuth.NewTextFile(nil, nil, opener)
- }
- for i := range prg.writeFile {
- prg.writeFile[i] = knuth.NewTextFile(nil, nil, nil)
- }
- for i := range prg.readFile {
- prg.readFile[i] = knuth.NewTextFile(nil, nil, nil)
- }
- prg.main()
- return nil
- }
- var opener = func(nm string) (io.Reader, error) {
- return knuth.Open(nm, []string{"."})
- }
- // Option adjusts program behavior.
- type Option func(p *prg) error
- // WithInputFile replaces input file 'replace' with 'r'.
- func WithInputFile(replace string, r io.Reader) Option {
- return func(p *prg) error {
- prev := opener
- opener = func(nm string) (io.Reader, error) {
- if nm == replace {
- return r, nil
- }
- return prev(nm)
- }
- return nil
- }
- }
- // WithDVIFile sets the output DVI file to 'w'.
- func WithDVIFile(w io.Writer) Option {
- return func(p *prg) error {
- p.dviFile = &binaryWriter{w: w}
- return nil
- }
- }
- // WithLogFile sets the output log file to 'w'.
- func WithLogFile(w io.Writer) Option {
- return func(p *prg) error {
- p.logFile = &textWriter{w: w}
- return nil
- }
- }
- type binaryWriter struct {
- buf [1]byte
- w io.Writer
- }
- func (w *binaryWriter) ByteP() *byte {
- panic("internal error")
- }
- func (w *binaryWriter) Close() {
- // nop
- }
- func (w *binaryWriter) CurPos() int32 {
- panic("internal error")
- }
- func (w *binaryWriter) Data4P() *[4]byte {
- panic("internal error")
- }
- func (w *binaryWriter) EOF() bool {
- panic("internal error")
- }
- func (w *binaryWriter) EOLN() bool {
- panic("internal error")
- }
- func (w *binaryWriter) ErStat() int32 {
- return 0
- }
- func (w *binaryWriter) Get() {
- panic("internal error")
- }
- func (w *binaryWriter) Put() {
- panic("internal error")
- }
- func (w *binaryWriter) Read(args ...interface{}) {
- panic("internal error")
- }
- func (w *binaryWriter) Readln(args ...interface{}) {
- panic("internal error")
- }
- func (w *binaryWriter) Reset(args ...interface{}) {
- panic("internal error")
- }
- func (w *binaryWriter) Rewrite(args ...interface{}) {
- // nop
- }
- func (w *binaryWriter) SetPos(int32) {
- panic("internal error")
- }
- func (w *binaryWriter) Write(args ...interface{}) {
- for _, v := range args {
- w.buf[0] = v.(byte)
- w.w.Write(w.buf[:])
- }
- }
- func (w *binaryWriter) Writeln(args ...interface{}) {
- panic("internal error")
- }
- type textWriter struct {
- w io.Writer
- }
- func (w *textWriter) ByteP() *byte {
- panic("internal error")
- }
- func (w *textWriter) Close() {
- // nop
- }
- func (w *textWriter) CurPos() int32 {
- panic("internal error")
- }
- func (w *textWriter) Data4P() *[4]byte {
- panic("internal error")
- }
- func (w *textWriter) EOF() bool {
- panic("internal error")
- }
- func (w *textWriter) EOLN() bool {
- panic("internal error")
- }
- func (w *textWriter) ErStat() int32 {
- return 0
- }
- func (w *textWriter) Get() {
- panic("internal error")
- }
- func (w *textWriter) Put() {
- panic("internal error")
- }
- func (w *textWriter) Read(args ...interface{}) {
- panic("internal error")
- }
- func (w *textWriter) Readln(args ...interface{}) {
- panic("internal error")
- }
- func (w *textWriter) Reset(args ...interface{}) {
- panic("internal error")
- }
- func (w *textWriter) Rewrite(args ...interface{}) {
- // nop
- }
- func (w *textWriter) SetPos(int32) {
- panic("internal error")
- }
- func (w *textWriter) Write(args ...interface{}) {
- for _, v := range args {
- fmt.Fprintf(w.w, "%v", v)
- }
- }
- func (w *textWriter) Writeln(args ...interface{}) {
- for _, v := range args {
- fmt.Fprintf(w.w, "%v", v)
- }
- fmt.Fprintln(w.w)
- }
|