1
0
Fork
You've already forked postscript-libraries
0
Utility functions for the PostScript programming language
  • PostScript 99.3%
  • Shell 0.7%
2024年04月28日 16:56:02 +01:00
combinatorics.ps Move permute, combinations and cartesianproduct into new combinatorics file. 2023年05月14日 18:16:34 +01:00
combinatorics_test.ps Move permute, combinations and cartesianproduct into new combinatorics file. 2023年05月14日 18:16:34 +01:00
date.ps Remove juliandate 2022年06月08日 22:12:36 +01:00
date_test.ps Remove juliandate 2022年06月08日 22:12:36 +01:00
deepeq.ps fix hash copY 2023年05月08日 12:29:45 +01:00
deepeq_test.ps add deepcopy to deepeq 2023年04月24日 13:28:40 +01:00
file-test-file Add file sublibrary 2022年12月01日 12:25:25 +00:00
file.ps Add file sublibrary 2022年12月01日 12:25:25 +00:00
file_test.ps Add file sublibrary 2022年12月01日 12:25:25 +00:00
iterables.ps Add dget get with default 2023年08月18日 11:30:54 +01:00
iterables_test.ps Add dget get with default 2023年08月18日 11:30:54 +01:00
LICENCE Licence 2022年05月13日 16:05:51 +01:00
maths.ps amend sqrt-cvi to use isqrt 2023年10月24日 12:17:41 +01:00
maths_test.ps Add integer square root 2023年10月24日 12:16:33 +01:00
mergesort.ps Merge sort 2023年10月16日 11:26:28 +01:00
mergesort_test.ps Merge sort 2023年10月16日 11:26:28 +01:00
quicksort.ps Add custom comparator and key sorting functions 2023年05月14日 18:10:13 +01:00
quicksort_test.ps Add custom comparator and key sorting functions 2023年05月14日 18:10:13 +01:00
README.md Add POSIX character class tests 2024年04月28日 16:56:02 +01:00
runps Initial upload 2022年05月13日 15:51:19 +01:00
strings.ps Add POSIX character class tests 2024年04月28日 16:56:02 +01:00
strings_test.ps Add POSIX character class tests 2024年04月28日 16:56:02 +01:00
test.ps Initial upload 2022年05月13日 15:51:19 +01:00
test_test.ps Initial upload 2022年05月13日 15:51:19 +01:00

Postscript Libraries

These library functions add some modern functionality to the admirably lightweight PostScript language.

There are two ways to use them: with the run function, or with direct inclusion. The former is easier with GhostScript, though you'll need to disable the SAFER option, e.g.:

gs -q -dNOSAFER -sDEVICE=txtwrite -o - filename.ps

or using the runps shell script included. Or take each function (and its dependencies) and copy it into your single program file; I'm working on a helper program to do this automatically.

I'm licencing these under GPL v3, but if you do actually get any use out of them, or want any functionality added, I'd love to hear about it.

The Libraries

combinatorics

  • permute

Permutes an array in place (using Heap's algorithm), applying a procedure to each permutation. Note that this changes the contents of the array, rather than building a new one each time.

[ 1 2 3 ] { [ exch aload pop ] } permute → [1 2 3] [2 1 3] [3 1 2]
 [1 3 2] [2 3 1] [3 2 1]
  • combinations

Given an array and a number, return an aray of all combinations of that size (in Knuth's lexicographic order).

[ 1 2 3 ] 2 combinations → [ [ 2 1 ] [ 3 1 ] [ 3 2 ] ]
  • cartesianproduct

Returns an array of arrays, the n-ary cartesian product of the array of input arrays. So for example an input of

[ [ 1 2 ] [ 3 4 ] ]

would produce

[ [ 1 3 ] [ 1 4 ] [ 2 3 ] [ 2 4 ] ]

deepeq

  • deepeq

Returns true if the two values on the top of the stack are equal – recursively checking strings, arrays and dictionaries for matching values.

[ 1 2 [ 3 4 ] ] [ 1 2 [ 3 4 ] ] deepeq → true
  • deepcopy

Makes a deep (dereferencing) copy of the data structure - values will be identical, but the two structures have no references in common, so that one can be changed without affecting the other.

date

Various date-related calculations. A "ymd" is an array of [ year month day ] values; a "jd" is the integer value of the Julian date at noon GMT of that day.

  • ymd2jd

Converts a year-month-day tuple to a julian date (integer value at noon GMT on that day).

[ 2013 1 1 ] ymd2jd → 2456294
  • jd2ymd

Converts a julian date to year-month-day.

2456294 jd2ymd → [ 2013 1 1 ]
  • jd2dow

Extracts the day of the week from a Julian date (0 = Sunday).

[ 2022 6 13 ] ymd2jd jd2dow → 1
  • lastdayofyear

Calculates the last day of the year (0 = Sunday)

2009 lastdayofyear → 4
  • islongyear

Returns true for an ISO8601 long year.

2009 islongyear → true
  • yearweeks

Returns the number of ISO8601 weeks in the year. (52, 53 if islongyear.)

2009 yearweeks → 53
  • ymd2isoywd

Converts a year-month-day tuple to an ISO8601 year-week-day tuple.

 [ 1978 1 1 ] ymd2isoywd → [ 1977 52 7 ]
  • y2easter

Given a year, returns the year-month-day tuple for Gregorian Easter.

2022 y2easter → [ 2022 4 17 ]

iterables

This is basically for treating arrays as lists, and mangling arrays into dicts and back.

  • keys

Given a dict, return an array of the keys.

<< 1 (a) 2 (b) 3 (c) 4 (d) >> keys → [ 1 2 3 4 ]
  • values

Given a dict, return an array of the values. (This will probably be in the same order as keys.)

<< 1 (a) 2 (b) 3 (c) 4 (d) >> values → [ (a) (b) (c) (d) ]
  • toset

Given an array, deduplicate it and return a dict of (array-value → true) pairs; the opposite of keys.

[ 1 2 3 4 ] toset → << 1 true 2 true 3 true 4 true >>
  • map

Given an array and a procedure, apply the procedure to each array element in turn, returning an array of the output.

[ 1 2 3 ] { 1 add } map → [ 2 3 4 ]
  • filter

Given an array and a procedure that returns a boolean, output an array consisting only of the values that cause a true output.

[ 1 2 3 4 5 ] { 2 mod 0 eq } → [ 2 4 ]
  • reduce

Given an array and a procedure that takes two inputs and leaves one on the stack, apply it repeatedly to reduce the array to a single value.

[ 1 2 3 4 5 ] { add } reduce → 15
  • reduce_init

As above, but with an initial value for the accumulator.

0 [ 1 2 4 5 ] { 1 exch div add } reduce_init → 1.95
  • enumerate

Given an array, produce an array twice the length, consisting of pairs of index and array value.

[ (a) (b) (c) ] enumerate → [ 0 (a) 1 (b) 2 (c) ]
  • enumerate.array

Given an array, produce an array twice the length, consisting of array pairs of index and array value.

[ (a) (b) (c) ] enumerate.array → [ [ 0 (a) ] [ 1 (b) ] [ 2 (c) ] ]

This is probably the more useful form. Where Rust might say

for (i, n) in s.iter().enumerate() { ...

the equivalent here is

s enumerate.array {
 aload pop
 /n exch def
 /i exch def
 ...
} forall
  • apush.right

Create a new array consisting of the input array and a new value. apush is an alias.

[ 1 2 ] 3 apush.right → [ 1 2 3 ]
  • apush.left

As above but inserts a new initial value.

[ 2 3 ] 1 apush.left → [ 1 2 3 ]
  • apop.left

Create a new array consisting of the input array without its initial value, and that value separately.

[ 1 2 3 ] apop.left → [ 2 3 ] 1
  • apop.right

As above but for the final value. apop is an alias.

[ 1 2 3 ] apop.right → [ 1 2 ] 3
  • all

Given an array and a function, return true if all of the values of the function applied to a list member are true, otherwise false.

[ 1 2 3 4 ] { 0 gt } all → true
[ 1 2 3 4 ] { 1 eq } all → false
  • any

Given an array and a function, return true if any of the values of the function applied to a list member are true, otherwise false.

[ 1 2 3 4 ] { 0 eq } any → false
[ 1 2 3 4 ] { 1 eq } any → true
  • listmax, listmin

Given an array, return the maximum or minimum value in it. (This uses the non-standard two-argument max and min extensions in GhostScript.)

[ 6 4 4 5 2 4 ] listmax → 6
[ 4 3 3 2 3 6 ] listmin → 2
  • unique

Given an array which may have duplicate elements, return an array with no duplicates. (In arbitrary order.)

[ 1 1 2 3 4 4 4 ] unique quicksort → [ 1 2 3 4 ]
  • reverse

Given an array, returns that array reversed.

[ 1 2 3 4 ] reverse → [ 4 3 2 1 ]
  • remove

Given an array and a position, return a copy of the array with the element at that position removed.

[ 0 1 2 3 4 ] 2 remove → [ 0 1 3 4 ]
  • dget

Given a dict, key and default, return the dict's value at key if it exists, or the default if not.

<< 1 2 2 4 3 8 4 16 >> 5 0 dget → 0

maths

  • genprimes

Generate an (unsorted) list of prime numbers less than or equal to the parameter. (Often you'll then want to quicksort them.)

20 genprimes quicksort → [ 2 3 5 7 11 13 17 19 ]
  • isprime

Return a boolean value indicating whether the integer argument is prime.

67 isprime → true
  • primefactor

Generate a dict of prime factors and their powers.

75 primefactor → << 3 1 5 2 >>
  • nthprimelimit

Calculate a number which is guaranteed to be no lower than the nth prime. This uses the algorithm of Barkley Rosser as given in Explicit Bounds for Some Functions of Prime Numbers, American Journal of Mathematics, Vol. 63, No. 1 (Jan., 1941), pp. 211-232; the output will typically be fed to genprimes.

25 nthprimelimit → 110
  • gcd

Calculate the greatest common divisor (highest common factor) of two numbers.

8 12 gcd → 4
  • lcm

Calculate the lowest common multiple of two numbers.

4 6 lcm → 12
  • isqrt

Calculate the integer square root of its argument.

19 isqrt → 4

quicksort

  • quicksort

Sorts an array in place.

 [ 4 9 4 7 ] quicksort → [ 4 4 7 9 ]
  • quicksort.with_comparator

Sorts an array with a custom comparison function. This should return, for stack values A B, -1 if A < B, 0 if A == B, 1 if A > B. The quicksort.cmp function will do this evaluation with standard gt/lt tests.

Strings normally sort in ASCIIbetical order:

 [ (4) (10) (4) (7) ] quicksort → [ (10) (4) (4) (7) ]

A custom comparator compares the strings' integer values:

 [ (4) (10) (4) (7) ] {
 cvi exch cvi exch quicksort.cmp
 } quicksort.with_comparator →
 [ (4) (4) (7) (10) ]
  • quicksort.with_keygen

Sorts an array with a key generation function which will be applied to each element. (Calculated just once for each, and cached.)

[ (distressfulness) (this) (fungus) ] { length }
quicksort.with_keygen →
[ (this) (fungus) (distressfulness)]
  • quicksort.with_keylist

Sorts an array with a key list.

[ (a) (b) (c) ] [ 3 1 2 ] quicksort.with_keylist → [ (b) (c) (a) ]

mergesort

As with quicksort methods above, but using a stable merge sort.

(Relies on cmp being undefined - I'll fix that in a future version.)

strings

  • strconcat

Concatenates two strings.

(abc) (def) strconcat (abcdef)
  • strjoin

Joins an array of strings with a joining string.

[ (abc) (def) ] (, ) strjoin (abc, def)
  • strsplit

Breaks down a string into an array of strings (eliding any zero-length output).

(this and that and the other) ( and ) strsplit
→ [ (this) (that) (the other) ]
  • s2a

Converts a string to an array of character values.

(abcdef) s2a → [97 98 99 100 101 102]
  • a2s

Converts an array of character values to a string.

[97 98 99 100 101 102] a2s → (abcdef)
  • safestring

Replaces the string on top of the stack with an unlinked copy, so that you can change the copy without changing the original.

(abcdef) safestring → (abcdef)
  • alloccvs

Like cvs, but allocates a string of appropriate length. Works on positive and negative integers.

555 alloccvs → (555)
  • toupper/tolower

Returns a string with all lower-case characters shifted to upper, or vice versa.

(UPPERlower) tolower → (upperlower)

  • POSIX character classes

Each function is named "c.is" plus the character class: c.isalnum, c.isalpha, etc., and returns a boolean.

These functions all operate on individual characters, not strings. To operate on strings, combine with the iterables library. For example, to verify that every character in a string is upper case:

(string) s2a { c.isupper } all

To extract only the digits from a string and return them as a new string:

(string) s2a { c.isdigit } filter a2s

  • alnum = alpha | digit
  • alpha = "A"-"Z" | "a"-"z"
  • blank = 9 | 32
  • cntrl = 0-31 | 127
  • digit = 48-57
  • graph = alnum | punct
  • lower = "a"-"z"
  • print = alnum | punct | 32
  • punct = ^alnum & ^cntrl & ^32
  • space = tab | nl | vt | ff | cr | 32
  • upper = "A"-"Z"
  • xdigit = digit | "A"-"F" | "a"-"f"

file

  • readlines

Given a text filename, returns an array of strings, one per line in the file.

test

Start a series of tests with (string) test.start.

Build tests to output booleans, and run test on each.

End the series with test.end.

Example:

(Boolean) test.start
true test
false not test
test.end

Output:

Boolean: Passed 2/2 (100%)