# BST module – implementing the BibTeX .bst language

The implementation of the .bst language

This module implements the BibTeX Style Language, as described in the `btxhak` document in the BibTeX package at CTAN.

The key function here is the `process-bibs/bst` function, which is suitable as an argument to `call-with-aux-file` from the `aux` module.

## Extensions

Beastie supports a couple of minor enhancements to the `.bst` language, in the form of additional built-in functions.

- `show.stack$$` : The BibTeX `stack$` function displays the stack and clears it. This actually isn't terribly helpful for debugging. The function `show.stack$$` displays the stack in the same way, but leaves it unchanged.

- `printf$$` : this pops a string format, and then pops as many further objects as there are `~a` or `~s` format specifiers in the string. It then formats and outputs the format string and arguments, replacing the format specifiers, from first to last, by the items popped from the stack, in the reverse order they were popped (that is, from left to right, in the usual way of laying out a `.bst` file). The format `~a` prints the item in a readable way, whereas `~s` does so in a possibly variant way which makes it clearer what type the object is. The format string may also include `~~` or `~%` to append a tilde or newline respectively.

- `printf.push$$` and `printf.pop$$` : by default, `printf$$` sends its output to the same destination as `write$`, but this can be adjusted. The `printf.push$$` function pops one argument from the `.bst` stack, and leaves none behind. The `printf.pop$$` function pops nothing from the `.bst` stack, and pushes one item.

  If `printf.push$$` is given a string argument, then it names a file which will be created, and which will receive the material written by `write$`, `newline$` and `printf$$`, until a matching appearance of `printf.pop$$`. That matching call will return the output to what it was before, and leave the name of the file on the stack.

  The function `printf.push$$` can also be given a numeric argument. If this is `#1` or `#2`, then beastie redirects output to stdout or the current error-port respectively, and `printf.pop$$` will leave an indicative string on the stack. If the argument is `#0`, however, then output will be directed to a string, which is what will be left on the stack by `printf.pop$$`.

For example:

    function {try.printing}
    {
      "Hello from try.printing" write$ newline$ %chatter as normal

      "test.txt" printf.push$$      % redirect to file "test.txt"
      "Going to a file" write$ newline$
      #1 #2 "string" "string" "sending 1=~s and 2=~s and string=~a/~s via printf~%" printf$$
      printf.pop$$                  % leaves the filename on the stack
      "file was: " swap$ * write$ newline$ % ...printed

      #0 printf.push$$              % write to a string
      "Going to a file" write$ newline$
      printf.pop$$                  % leaves the string on the stack
      "string was: " swap$ * write$ newline$ % ...displayed
    }

## Functions

Index:

- en-dashify
- lowercase-string/bst
- parse-bst-file
- parse-bst-string
- process-bibs/bst
- string->page-range
- titlecase-string/bst
- uppercase-string/bst
- write/bstscm!

### en-dashify

`(en-dashify s)` : Replace '-' or '--' or Unicode en-dash in the string with en-dash '–'. BibTeX permits "1+" to indicate a start-of-range, so that has to turn into a dash. If the argument is not a string, evaluates to #f

### lowercase-string/bst

`(lowercase-string/bst us)` : Lowercase a ustring, returning a copy. The function mutates characters using `uchar-downcase`, similarly to `uppercase-string/bst`.

See also `titlecase-string/bst`.

### parse-bst-file

`parse-bst-file : [filename] -> list?` : Parse a .bst file, returning a 'compiled' version of it. This is not of much general use, since the only thing which can use the result is internal functions in this module, but it may be of interest.

If the filename is absent or `#f`, then parse from stdin.

I have vague plans to create a decompiler, to turn the output of this into a .bst file, so that it would be possible to edit the result here and create a modified or derivative .bst file without insane pattern-matching.

### parse-bst-string

(parse-bst-string input) : as with parse-bst-file, but parsing from a string argument (mostly for testing)

### process-bibs/bst

`process-bibs/bst : (or (listof symbol) 'all) (listof string?) string? -> unspecified` : In `(process-bibs/bst citation-list bibdata-files bibstyle-file)`, the `citation-list` is a list of string citations, or the symbol `'all`.

`bibdata-files` is a list of `.bib` files to be searched. Each of these is looked up in the usual TeX search path, both without then with a .bib file extension.

`bibstyle-file` is the .bst file to be used. This, also, is looked up both without and with the .bst file extension.

### string->page-range

`(string->page-range str)` : Break a string page-range into the quoted page numbers.

- Given "1", return '("1" . single).
- Given a string such as "1-2", "1--2" (two hyphens) or "1–2" (Unicode en-dash), return '("1" . "2").
- Given "1-" or "1+", return '("1" . inf).

If the argument is not a string, or if there are no digits present, return #f.

Argument strings such as "x1-2" or "1-2-3" are invalid as a page range and will produce `#f`.

### titlecase-string/bst

`(titlecase-string/bst us)` : return a copy of the ustring `us`, converted to titlecase. This version is intended to be compatible with the definition of titlecasing for BibTeX `.bst` files, the documentation for which describes a slightly idiosyncratic definition of ‘titlecase’. The key peculiarities are:

- This changes only characters at brace-level 0.
- For titlecase, the `btxhak.pdf` document says: ‘If the first literal is the string ‘t’, it converts to lower case all letters except the very first character in the string, which it leaves alone, and except the first character following any colon and then nonnull white space, which it also leaves alone.’

That is, for titlecase, the function will not uppercase anything, since the BibTeX specification implies that entries are created in uppercase or titlecase, so that titlecasing consists only of lowercasing selected letters.

For consistency, if the argument is `#f`, then this returns `#f`, and if the function is passed a string?, then (for convenience/consistency) it will be converted to a ustring? before being processed.

### uppercase-string/bst

`(uppercase-string/bst us)` : Uppercase a ustring, returning a copy. The function will mutate characters, using `uchar-upcase` at brace level 0 only, passing unchanged any characters enclosed within braces.

This version is intended to be compatible with the `.bst` definition of uppercasing. See also `titlecase-string/bst`.

### write/bstscm!

A still-rudimentary prettyprinter for a bstscm program (really for internal use only at present)

Norman
2026 August 02