summaryrefslogtreecommitdiff
path: root/ref.go
diff options
context:
space:
mode:
Diffstat (limited to 'ref.go')
-rw-r--r--ref.go167
1 files changed, 167 insertions, 0 deletions
diff --git a/ref.go b/ref.go
new file mode 100644
index 0000000..ba30c79
--- /dev/null
+++ b/ref.go
@@ -0,0 +1,167 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "strings"
+ "sort"
+ "io"
+)
+
+const (
+ bufsize = 512
+ prefix = `.\"s `
+ end = `.\"e`
+ section = `.\"ยง`
+ tableHead = ".TS\nexpand;\nl1w(1.5i) l1w(4.5i)."
+ tableFoot = ".TE"
+ mac = ".ref"
+ delim = "()"
+ extraPrefix = `\fC`
+ extraSuffix = `\fP`
+)
+
+type Reference struct {
+ name string
+ contents string
+ index int
+}
+
+func getRefTxt(lines []string) string {
+ var txt string
+ for _, line := range lines {
+ if strings.HasPrefix(line, end) {
+ break
+ }
+ txt += line + "\n"
+ }
+ return string(txt)
+}
+
+func findIndex(refs []Reference, name string) int {
+ for _, ref := range refs {
+ if ref.name == name {
+ return ref.index
+ }
+ }
+ return -1
+}
+
+func checkLetter(ch rune) bool {
+ if ch >= 'A' && ch <= 'Z' ||
+ ch >= 'a' && ch <= 'z' {
+ return true
+ }
+ return false
+}
+
+func checkAllCaps(word string) bool {
+ for _, ch := range word {
+ if !checkLetter(ch) {
+ continue
+ }
+ if ch < 'A' || ch > 'Z' {
+ return false
+ }
+ }
+ return true
+}
+// Typographic niceties.
+func extraFmt(ref string) string {
+ words := strings.Split(ref, " ")
+ if checkAllCaps(words[0]) {
+ words[0] = extraPrefix + words[0] + extraSuffix
+ }
+ words[1] = extraPrefix + words[1] + extraSuffix
+
+ return words[0] + " " + words[1]
+}
+
+func main() {
+ in := os.Stdin
+ if len(os.Args) > 1 {
+ var err error
+ in, err = os.Open(os.Args[1])
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ bytes, err := io.ReadAll(in)
+ if err != nil {
+ log.Fatal(err)
+ }
+ contents := string(bytes)
+
+ /* Iterate through the contents of the file twice:
+ Once to find and index all references.
+ Again to refer to each reference. */
+ var refs []Reference
+ div := -1
+ lines := strings.Split(contents, "\n")
+ for i, line := range lines {
+ if line == section {
+ div = i
+ }
+ }
+ // If no split, quietly return contents.
+ if div == -1 {
+ fmt.Print(contents)
+ return
+ }
+
+ for i, line := range lines[div:] {
+ if strings.HasPrefix(line, prefix) {
+ var ref Reference
+ ref.name = line[len(prefix):]
+ // i is relative to the lines after div.
+ ref.contents = getRefTxt(lines[div+i+1:])
+ refs = append(refs, ref)
+ }
+ }
+
+ /* Sort references alphabetically. */
+ sort.Slice(refs, func(i, j int) bool {
+ return strings.Compare(refs[i].name, refs[j].name) < 0
+ })
+
+ for i := range refs {
+ refs[i].index = i
+ }
+
+ // Second pass.
+ for _, line := range lines[:div] {
+ if strings.HasPrefix(line, mac) {
+ var name string
+ var start, end int
+ for i := range line {
+ if line[i] == delim[0] {
+ start = i+1
+ }
+ if line[i] == delim[1] {
+ end = i
+ break
+ }
+ }
+ name = line[start:end]
+ index := findIndex(refs, name)
+ fmt.Printf(".post.url #%d \"%s\"\n\n", index,
+ extraFmt(line[start-1:]))
+ } else {
+ fmt.Println(line)
+ }
+ }
+
+ // Format References into AMS Style bibiography.
+ /* As it turns out, in order to be referenced individually,
+ each reference needs its own table. */
+ for _, ref := range refs {
+ fmt.Printf(".post.name %d\n", ref.index)
+ fmt.Println(tableHead)
+ fmt.Printf("T{\n%c%s%c\nT}", delim[0], extraFmt(ref.name),
+ delim[1])
+ fmt.Printf("\tT{\n%s\nT}\n", ref.contents)
+ fmt.Println(tableFoot)
+ }
+}