bbs

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2021 License: MIT Imports: 9 Imported by: 2

README

Package bbs

Package bbs is a Go module that interacts with legacy textfiles encoded with Bulletin Board Systems (BBS) color codes to reconstruct them into HTML documents.

BBSes were popular in the 1980s and 1990s, and allowed computer users to chat, message, and share files over the landline telephone network. The commercialization and ease of access to the Internet eventually replaced BBSes, as did the world-wide-web.

These centralized systems, termed boards, used a text-based interface, and their owners often applied colorization, text themes, and art to differentiate themselves.

While in the 1990s, ANSI control codes were in everyday use on the PC/MS-DOS, the standard comes from mainframe equipment. Home microcomputers often had difficulty interpreting it. So BBS developers created their own, more straightforward methods to colorize and theme the text output to solve this.

*Please note, while many PC/MS-DOS boards used ANSI control codes for colorizations, this library does not support the standard.

Go Package with docs and examples.


PCBoard

One of the most well-known applications for hosting a PC/MS-DOS BBS, PCBoard pioneered the file_id.diz file descriptor, as well as being endlessly expandable through software plugins known as PPEs. It developed the popular @X color code and @ control syntax.

Celerity

Another PC/MS-DOS application that was very popular with the hacking, phreaking, and pirate communities in the early 1990s. It introduced a unique | pipe code syntax in late 1991 that revised the code syntax in version 2 of the software.

Renegade

A PC/MS-DOS application that was a derivative of the source code of Telegard BBS. Surprisingly there was a new release of this software in 2021. Renegade had two methods to implement color, and this library uses the Pipe Bar Color Codes.

Telegard

A PC/MS-DOS application became famous due to a source code leak or release by one of its authors back in an era when most developers were still highly secretive with their code. The source is incorporated into several other projects.

WVIV

A mainstay in the PC/MS-DOS BBS scene of the 1980s and early 1990s, it became well known for releasing its source code to registered users. It allowed them to expand the code to incorporate additional software such as games or utilities and port it to other platforms. The source is now Open Source and is still updated. Confusingly WWIV has three methods of colorizing text, 10 Pipe colors, two-digit pipe colors, and its original Heart Codes.

Wildcat

WILDCAT! was a popular, propriety PC/MS-DOS application from the late 1980s that later migrated to Windows. It was one of the few BBS applications that sold at retail in a physical box. It extensively used @ color codes throughout later revisions of its software.

Documentation

Overview

Package bbs interacts with legacy textfiles encoded with Bulletin Board Systems (BBS) color codes to reconstruct them into HTML documents.

BBSes were popular in the 1980s and 1990s, and allowed computer users to chat, message, and share files over the landline telephone network. The commercialization and ease of access to the Internet eventually replaced BBSes, as did the world-wide-web.

These centralized systems, termed boards, used a text-based interface, and their owners often applied colorization, text themes, and art to differentiate themselves.

While in the 1990s, ANSI control codes were in everyday use on the PC/MS-DOS, the standard comes from mainframe equipment. Home microcomputers often had difficulty interpreting it. So BBS developers created their own, more straightforward methods to colorize and theme the text output to solve this.

*Please note, while many PC/MS-DOS boards used ANSI control codes for colorizations, this library does not support the standard.

PCBoard

One of the most well-known applications for hosting a PC/MS-DOS BBS, PCBoard pioneered the file_id.diz file descriptor, as well as being endlessly expandable through software plugins known as PPEs. It developed the popular @X color code and @ control syntax.

Celerity

Another PC/MS-DOS application that was very popular with the hacking, phreaking, and pirate communities in the early 1990s. It introduced a unique | pipe code syntax in late 1991 that revised the code syntax in version 2 of the software.

Renegade

A PC/MS-DOS application that was a derivative of the source code of Telegard BBS. Surprisingly there was a new release of this software in 2021. Renegade had two methods to implement color, and this library uses the Pipe Bar Color Codes.

Telegard

A PC/MS-DOS application became famous due to a source code leak or release by one of its authors back in an era when most developers were still highly secretive with their code. The source is incorporated into several other projects.

WVIV

A mainstay in the PC/MS-DOS BBS scene of the 1980s and early 1990s, it became well known for releasing its source code to registered users. It allowed them to expand the code to incorporate additional software such as games or utilities and port it to other platforms. The source is now Open Source and is still updated. Confusingly WWIV has three methods of colorizing text, 10 Pipe colors, two-digit pipe colors, and its original Heart Codes.

Wildcat

WILDCAT! was a popular, propriety PC/MS-DOS application from the late 1980s that later migrated to Windows. It was one of the few BBS applications that sold at retail in a physical box. It extensively used @ color codes throughout later revisions of its software.

Example
package main

import (
	"bytes"
	"embed"
	"fmt"
	"log"

	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/transform"

	"github.com/bengarrett/bbs"
)

var (
	//go:embed static/*
	static embed.FS
)

func main() {
	// print about the file
	file, err := static.Open("static/examples/hello.pcb")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	s, b, err := bbs.Fields(file)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Found %d %s color controls.\n\n", len(s), b)

	// reopen the file
	file, err = static.Open("static/examples/hello.pcb")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// transform the MS-DOS legacy text to Unicode
	decoder := charmap.CodePage437.NewDecoder()
	reader := transform.NewReader(file, decoder)

	// create the HTML equivalent of BBS color codes
	var buf bytes.Buffer
	if _, err := bbs.HTML(&buf, reader); err != nil {
		log.Fatal(err)
	}
	fmt.Print(buf.String())

}
Output:
Found 11 PCBoard @X color controls.

<i class="PB0 PFF">    </i><i class="PB7 PF0"> ┌─────────────┐ </i><i class="PB0 PF7">
</i><i class="PB0 PFF">    </i><i class="PB7 PF0"> │ Hello </i><i class="PBF PF0">world </i><i class="PB7 PF0">│ </i><i class="PB0 PF7">
</i><i class="PB0 PFF">    </i><i class="PB7 PF0"> └─────────────┘ </i><i class="PB0 PF7"></i>

Index

Examples

Constants

View Source
const (
	// ClearCmd is a PCBoard specific control to clear the screen that's occasionally found in ANSI text.
	ClearCmd string = "@CLS@"

	// CelerityMatch is a regular expression to match Celerity BBS color codes.
	CelerityMatch string = `\|(k|b|g|c|r|m|y|w|d|B|G|C|R|M|Y|W|S)`

	// PCBoardMatch is a case-insensitive, regular expression to match PCBoard BBS color codes.
	PCBoardMatch string = "(?i)@X([0-9A-F][0-9A-F])"

	// RenegadeMatch is a regular expression to match Renegade BBS color codes.
	RenegadeMatch string = `\|(0[0-9]|1[1-9]|2[0-3])`

	// TelegardMatch is a case-insensitive, regular expression to match Telegard BBS color codes.
	TelegardMatch string = "(?i)`([0-9|A-F])([0-9|A-F])"

	// WildcatMatch is a case-insensitive, regular expression to match Wildcat! BBS color codes.
	WildcatMatch string = `(?i)@([0-9|A-F])([0-9|A-F])@`

	// WWIVHashMatch is a regular expression to match WWIV BBS # color codes.
	WWIVHashMatch string = `\|#(\d)`

	// WWIVHeartMatch is a regular expression to match WWIV BBS ♥ color codes.
	WWIVHeartMatch string = `\x03(\d)`
)

Variables

View Source
var (
	ErrColorCodes = errors.New("no bbs color codes found")
	ErrANSI       = errors.New("ansi escape code found")
)

Functions

func HTMLCelerity

func HTMLCelerity(dst *bytes.Buffer, src []byte) error

HTMLCelerity writes to dst the HTML equivalent of Celerity BBS color codes with matching CSS color classes.

Example
package main

import (
	"bytes"
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("|cHello |C|S|wworld")
	if err := bbs.HTMLCelerity(&out, src); err != nil {
		fmt.Print(err)
	}
	fmt.Print(out.String())
}
Output:
<i class="PBk PFc">Hello </i><i class="PBk PFC"></i><i class="PBw PFC">world</i>

func HTMLPCBoard

func HTMLPCBoard(dst *bytes.Buffer, src []byte) error

HTMLPCBoard writes to dst the HTML equivalent of PCBoard BBS color codes with matching CSS color classes.

Example
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("@X03Hello world")
	if err := bbs.HTMLPCBoard(&out, src); err != nil {
		log.Print(err)
	}
	fmt.Print(out.String())
}
Output:
<i class="PB0 PF3">Hello world</i>

func HTMLRenegade

func HTMLRenegade(dst *bytes.Buffer, src []byte) error

HTMLRenegade writes to dst the HTML equivalent of Renegade BBS color codes with matching CSS color classes.

Example
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("|03Hello |07|19world")
	if err := bbs.HTMLRenegade(&out, src); err != nil {
		log.Print(err)
	}
	fmt.Print(out.String())
}
Output:
<i class="P0 P3">Hello </i><i class="P0 P7"></i><i class="P19 P7">world</i>

func HTMLTelegard

func HTMLTelegard(dst *bytes.Buffer, src []byte) error

HTMLTelegard writes to dst the HTML equivalent of Telegard BBS color codes with matching CSS color classes.

func HTMLWHash

func HTMLWHash(dst *bytes.Buffer, src []byte) error

HTMLWildcat writes to dst the HTML equivalent of WWIV BBS # color codes with matching CSS color classes.

func HTMLWHeart

func HTMLWHeart(dst *bytes.Buffer, src []byte) error

HTMLWildcat writes to dst the HTML equivalent of WWIV BBS ♥ color codes with matching CSS color classes.

func HTMLWildcat

func HTMLWildcat(dst *bytes.Buffer, src []byte) error

HTMLWildcat writes to dst the HTML equivalent of Wildcat! BBS color codes with matching CSS color classes.

func HasCelerity

func HasCelerity(src []byte) bool

HasCelerity reports if the bytes contains Celerity BBS color codes. The format uses the vertical bar "|" followed by a case sensitive single alphabetic character.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("|cHello |C|S|wworld")
	fmt.Printf("Has b Celerity BBS text? %v", bbs.HasCelerity(b))
}
Output:
Has b Celerity BBS text? true

func HasPCBoard

func HasPCBoard(src []byte) bool

HasPCBoard reports if the bytes contains PCBoard BBS color codes. The format uses an "@X" prefix with a background and foreground, 4-bit hexadecimal color value.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("@X03Hello world")
	fmt.Printf("Has b PCBoard BBS text? %v", bbs.HasPCBoard(b))
}
Output:
Has b PCBoard BBS text? true

func HasRenegade

func HasRenegade(src []byte) bool

HasRenegade reports if the bytes contains Renegade BBS color codes. The format uses the vertical bar "|" followed by a padded, numeric value between 00 and 23.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("|03Hello |07|19world")
	fmt.Printf("Has b Renegade BBS text? %v", bbs.HasRenegade(b))
}
Output:
Has b Renegade BBS text? true

func HasTelegard

func HasTelegard(src []byte) bool

HasTelegard reports if the bytes contains Telegard BBS color codes. The format uses the grave accent followed by a padded, numeric value between 00 and 23.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	const grave = "\u0060" // godoc treats a grave character as a special control
	b := []byte(grave + "7Hello world")
	fmt.Printf("Has b Telegard BBS text? %v", bbs.HasTelegard(b))
}
Output:
Has b Telegard BBS text? true

func HasWHash

func HasWHash(src []byte) bool

HasWHash reports if the bytes contains WWIV BBS # (hash or pound) color codes. The format uses a vertical bar "|" with the hash "#" characters as a prefix with a numeric value between 0 and 9.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("|#7Hello world")
	fmt.Printf("Has b WVIV BBS # text? %v", bbs.HasWHash(b))
}
Output:
Has b WVIV BBS # text? true

func HasWHeart

func HasWHeart(src []byte) bool

HasWHeart reports if the bytes contains WWIV BBS ♥ (heart) color codes. The format uses the ETX character as a prefix with a numeric value between 0 and 9. In the standard MS-DOS, USA codepage (CP-437), the ETX (end-of-text) character is substituted with a heart character.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("\x037Hello world")
	fmt.Printf("Has b WWIV BBS ♥ text? %v", bbs.HasWHeart(b))
}
Output:
Has b WWIV BBS ♥ text? true

func HasWildcat

func HasWildcat(src []byte) bool

HasWildcat reports if the bytes contains Wildcat! BBS color codes. The format uses an a background and foreground, 4-bit hexadecimal color value enclosed by two at "@" characters.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("@0F@Hello world")
	fmt.Printf("Has b Wildcat! BBS text? %v", bbs.HasWildcat(b))
}
Output:
Has b Wildcat! BBS text? true

func TrimControls

func TrimControls(src []byte) []byte

TrimControls removes common PCBoard BBS controls prefixes from the bytes.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := []byte("@CLS@@PAUSE@Hello world")
	r := bbs.TrimControls(b)
	fmt.Print(string(r))
}
Output:
Hello world

Types

type BBS

type BBS int

Bulletin Board System color code format. Other than for Find, the ANSI type is not supported by this library.

const (
	ANSI      BBS = iota // ANSI escape sequences.
	Celerity             // Celerity BBS pipe codes.
	PCBoard              // PCBoard BBS @ codes.
	Renegade             // Renegade BBS pipe codes.
	Telegard             // Telegard BBS grave accent codes.
	Wildcat              // Wildcat! BBS @ codes.
	WWIVHash             // WWIV BBS # codes.
	WWIVHeart            // WWIV BBS ♥ codes.
)

func Fields

func Fields(src io.Reader) ([]string, BBS, error)

Fields splits the io.Reader around the first instance of one or more consecutive BBS color codes. An error is returned if no color codes are found or if ANSI control sequences are first found.

Example
package main

import (
	"fmt"
	"log"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	r := strings.NewReader("@X03Hello @XF0world")
	s, b, err := bbs.Fields(r)
	if err != nil {
		log.Print(err)
	}
	fmt.Printf("Found %d %s sequences.", len(s), b)
}
Output:
Found 2 PCBoard @X sequences.
Example (None)
package main

import (
	"errors"
	"fmt"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	r := strings.NewReader("Hello world.")
	_, _, err := bbs.Fields(r)
	if errors.Is(err, bbs.ErrColorCodes) {
		fmt.Print(err)
	}
}
Output:
no bbs color codes found

func Find

func Find(src io.Reader) BBS

Find the format of any known BBS color code sequence within the reader. If no sequences are found -1 is returned.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	r := strings.NewReader("@X03Hello world")
	f := bbs.Find(r)
	fmt.Printf("Reader is in a %s BBS format", f.Name())
}
Output:
Reader is in a PCBoard BBS format
Example (None)
package main

import (
	"fmt"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	r := strings.NewReader("Hello world")
	f := bbs.Find(r)
	if !f.Valid() {
		fmt.Print("reader is plain text")
	}
}
Output:
reader is plain text

func HTML

func HTML(dst *bytes.Buffer, src io.Reader) (BBS, error)

HTML writes to dst the HTML equivalent of BBS color codes with matching CSS color classes. The first found color code format is used for the remainder of the Reader.

Example
package main

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := strings.NewReader("@X03Hello world")
	if _, err := bbs.HTML(&out, src); err != nil {
		fmt.Print(err)
	}
	fmt.Print(out.String())
}
Output:
<i class="PB0 PF3">Hello world</i>

func (BBS) Bytes

func (b BBS) Bytes() []byte

Bytes returns the BBS color toggle sequence as bytes.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	b := bbs.PCBoard.Bytes()
	fmt.Printf("%s %v", b, b)
}
Output:
@X [64 88]

func (BBS) CSS

func (b BBS) CSS(dst *bytes.Buffer) error

CSS writes to dst the Cascading Style Sheets classes needed by the HTML. The CSS relies on cascading variables. See https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties for details.

Example
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"

	"github.com/bengarrett/bbs"
)

func main() {
	var buf bytes.Buffer
	if err := bbs.PCBoard.CSS(&buf); err != nil {
		fmt.Print(err)
	}

	f, err := os.OpenFile("pcboard.css", os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(f.Name()) // clean up

	if _, err := buf.WriteTo(f); err != nil {
		log.Fatal(err)
	}
}

func (BBS) HTML

func (b BBS) HTML(dst *bytes.Buffer, src []byte) error

HTML writes to dst the HTML equivalent of BBS color codes with matching CSS color classes.

Example
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("@X03Hello world")
	if err := bbs.PCBoard.HTML(&out, src); err != nil {
		log.Print(err)
	}
	fmt.Print(out.String())
}
Output:
<i class="PB0 PF3">Hello world</i>

func (BBS) Name

func (b BBS) Name() string

Name returns the name of the BBS color format.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	fmt.Print(bbs.PCBoard.Name())
}
Output:
PCBoard

func (BBS) Remove

func (b BBS) Remove(dst *bytes.Buffer, src []byte) error

Remove the BBS color codes from src and write it to dst.

Example
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("@X03Hello @X07world")
	if err := bbs.PCBoard.Remove(&out, src); err != nil {
		log.Print(err)
	}
	fmt.Print(out.String())
}
Output:
Hello world
Example (Find)
package main

import (
	"bytes"
	"fmt"
	"log"

	"github.com/bengarrett/bbs"
)

func main() {
	var out bytes.Buffer
	src := []byte("@X03Hello @X07world")
	r := bytes.NewReader(src)
	b := bbs.Find(r)
	if err := b.Remove(&out, src); err != nil {
		log.Print(err)
	}
	fmt.Print(out.String())
}
Output:
Hello world

func (BBS) String

func (b BBS) String() string

String returns the BBS color format name and toggle sequence.

Example
package main

import (
	"fmt"

	"github.com/bengarrett/bbs"
)

func main() {
	fmt.Print(bbs.PCBoard)
}
Output:
PCBoard @X

func (BBS) Valid

func (b BBS) Valid() bool

Valid reports whether the BBS type is valid.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/bengarrett/bbs"
)

func main() {
	r := strings.NewReader("Hello world")
	f := bbs.Find(r)
	fmt.Print("reader is BBS text? ", f.Valid())
}
Output:
reader is BBS text? false

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL