Definition: object res = trim(object source, object what={' ','\t','\r','\n'}, bool return_index=false)
or ...
object res = trim_head(object source, object what={' ','\t','\r','\n'}, bool return_index=false)
-- or --
object res = trim_tail(object source, object what={' ','\t','\r','\n'}, bool return_index=false)
Description: Trim whitespace from strings.

source: object (string) to be trimmed.
what: elements (characters) to be removed.
return_index: if true return {startpos,endpos} (trim), startpos (trim_head), or endpos (trim_tail) respectively.
Comments: Can theoretically be used for other purposes besides trimming whitespace, perhaps to trim unused entries from a table.

When return_index is true, the result is {startpos,endpos} (trim), startpos (trim_head), or endpos (trim_tail).

To simplify processing, if source is not a sequence/string, but instead something like EOF (ie -1), it is returned unaltered.
Note however that feature is certainly not intended for use when working with indexes (return_index=true), since treating the -1 (or whatever!) result as an index would probably be quite wrong! Instead it is usually easier to avoid the call when source is not a sequence, rather than struggle to interpret the result correctly.
In other words, integer {s,e} = trim(5,x,true) will fail trying to extract {s,e} from 5, and likewise(-ish) integer e = trim_head/tail(5,x,true) will succeed however some subsequent [5] usage will almost certainly fail.
In both cases it is simply easier to avoid the call rather than test/ignore the bogus results.

Prior to version 1.0.0, what defaulted to " \t\r\n", but that is incompatible with pwa/p2js, and changing it to a dword-sequence does not affect the functionality on the desktop (however you simply cannot have tab characters in strings in JavaScript, see Incompatibilities).
?trim(" abc ")          -- prints "abc"
?trim(`"abc"`)          -- prints `"abc"`
?trim(`"abc"`,'\"')     -- prints "abc" (not ""abc"" nor `"abc"`)
?trim(table,{{}})       -- removes s[i]={} entries from start and end (note the extra {})
?trim(table,{{},0})     -- removes s[i]={} or 0 ""
?trim(gets(fn))         -- trim returns eof (-1) unaltered.
Ancilliary function: string res = shorten(sequence s, string what="digits", integer ml=20)

Crops longer output, eg shorten(repeat('1',9999)) returns "1111111111111111111...1111111111111111111 (9,999 digits)".
The original text is returned unaltered if it is already shorter than 2*ml, or if it would be longer with "..." and the suffix.
Obviously you might want to replace "digits" with "chars"/"elements"/etc, and keep more/less of the first/last,
eg shorten(repeat('1',9999),"ones",9) returns "111111111...111111111 (9,999 ones)".
If what is specified as "" then there is no suffix, eg shorten("0123456789","",1) returns "0...9".

If s is not a string then a sequence of strings is assumed, the "..." and final suffix are inserted as string elements, more suitable for say join() or join_by(), and giving a default (unflattened) max result length of 42.
Implementation: See builtins\ptrim.e (an autoinclude) for details of the actual implementation.