X2Go::...ptions(3pm)
πΈ NAME πΈ
X2Go::Server::Agent::NX::Options β the NX Options modification module. π
(Yeah bestie, this is the whole X2Go::...ptions(3pm) page β User Contributed Perl Documentation β and the title got cut off in the header, love that for us.)
π¦ SYNOPSIS π¦
okay so here's the entire flow in one go, read it like a group chat scroll π±β¨
use X2Go::Server::Agent::NX::Options;
# Options string, probably read in from somewhere, but
# hardcoded here.
my $options = 'some=option,another=opt,more=values,some=override,more=data:90';
# Parse into an intermediate form.
my $intermediate = X2Go::Server::Agent::NX::Options::parse_options ($options);
# Check for errors.
die "Unable to parse option string, aborting.\n" unless (defined ($intermediate));
# (Optionally) compact it, this should make the duplicated "some" and "more"
# keys unique.
$intermediate = X2Go::Server::Agent::NX::Options::compact_intermediate ($intermediate);
# Error handling ...
die "Unable to compact intermediate array, aborting.\n" unless (defined ($intermediate));
# Add to options string.
my $transform_op = '+new=value';
# Parse and sanitize transform string.
my $interpreted_transform_ref = X2Go::Server::Agent::NX::Options::interpret_transform ($transform_op);
# Error handling ...
die "Invalid transformation passed, aborting.\n" unless (defined ($interpreted_transform_ref));
# Extract transformation data.
my ($transform_mode, $sanitized_transform) = @{$interpreted_transform_ref};
# Apply transformation.
$intermediate = X2Go::Server::Agent::NX::Options::transform_intermediate ($intermediate, $transform_mode, $sanitized_transform);
# Error handling ...
die "Error while transforming intermediate representation, aborting.\n" unless (defined ($intermediate));
# Try to remove a combination which doesn't exist, this should not modify the
# intermediate.
# No more comments for things that were already explained.
$transform_op = '-another=doesnotexist';
$interpreted_transform_ref = X2Go::Server::Agent::NX::Options::interpret_transform ($transform_op);
die "Invalid transformation passed, aborting.\n" unless (defined ($interpreted_transform_ref));
($transform_mode, $sanitized_transform) = @{$interpreted_transform_ref};
$intermediate = X2Go::Server::Agent::NX::Options::transform_intermediate ($intermediate, $transform_mode, $sanitized_transform);
die "Error while transforming intermediate representation, aborting.\n" unless (defined ($intermediate));
# Remove a key unconditionally, this should change the intermediate.
$transform_op = '-some';
$interpreted_transform_ref = X2Go::Server::Agent::NX::Options::interpret_transform ($transform_op);
die "Invalid transformation passed, aborting.\n" unless (defined ($interpreted_transform_ref));
($transform_mode, $sanitized_transform) = @{$interpreted_transform_ref};
$intermediate = X2Go::Server::Agent::NX::Options::transform_intermediate ($intermediate, $transform_mode, $sanitized_transform);
die "Error while transforming intermediate representation, aborting.\n" unless (defined ($intermediate));
# Modify/update a key.
$transform_op = '+another=newval';
$interpreted_transform_ref = X2Go::Server::Agent::NX::Options::interpret_transform ($transform_op);
die "Invalid transformation passed, aborting.\n" unless (defined ($interpreted_transform_ref));
($transform_mode, $sanitized_transform) = @{$interpreted_transform_ref};
$intermediate = X2Go::Server::Agent::NX::Options::transform_intermediate ($intermediate, $transform_mode, $sanitized_transform);
die "Error while transforming intermediate representation, aborting.\n" unless (defined ($intermediate));
# Extract the "more" key.
my $extract = X2Go::Server::Agent::NX::Options::extract_element ($intermediate, q{more});
# Error handling ...
die "Unable to extract 'more' key from intermediate, aborting.\n" unless defined ($extract);
# Fetching multiple elements could be fine, for instance when the intermediate is not compact.
# Hence, this need not be a general error, but we'll treat it as one here.
die "Extract operation returned more than one element, this should not happen with a compacted intermediate, aborting.\n" if (1 < scalar (@{$extract}));
# Likewise, it would be okay for the result to be empty, but not for us right here.
die "Extract operation returned no result, aborting.\n" if (1 > scalar (@{$extract}));
my $extracted_kv = q{};
# Now, get the actual data in a presentable form.
foreach my $entry (@{$extract}) {
foreach my $key (%{$entry}) {
$extracted_kv .= $key;
my $value = $entry->{$key};
if (defined ($value)) {
$extracted_kv .= q{=} . $value;
}
last;
}
last;
}
# At this point, $extracted_kv should be "more=data".
# Yet again, but this time extracting a key which does not exist.
$extract = X2Go::Server::Agent::NX::Options::extract_element ($intermediate, q{nosuchey});
# Error handling ...
die "Unable to extract 'nosuchkey' key from intermediate, aborting.\n" unless defined ($extract);
# Should be empty.
die "Extract operation returned a result, aborting.\n" if (0 < scalar (@{$extract}));
# Transform back into a string.
my $out = X2Go::Server::Agent::NX::Options::intermediate_to_string ($intermediate);
# Error handling ...
die "Unable to transform intermediate back into string, aborting.\n" unless (defined ($out));
# At this point, $out should be 'another=newval,more=data,new=value:90'.
π DESCRIPTION π
bestie, this module is your girl for modifying or extracting data out of X2Go/NX Agent options strings. and if you want the deep lore on what an options string even is, go read "OPTIONS STRINGS" β it's the in-depth description, I promise it eats. π
First up: you transform the input options string into an intermediate representation using parse_options. One thing you cannot skip β the options string must end with a display specification, aka it has to end in :displaynumber. π¨ If the parse fails you get undef back, that's your error signal. And lowkey about what you actually get back: it is a reference to an array of hash references, but please do not make assumptions about the layout, or even about its actual format. Treat it like a black box, no cap π€. Crucial part though β whenever an intermediate is expected somewhere, that reference is what you pass.
If you wanna strip out redundant or empty entries inside an options string, pass the intermediate to compact_intermediate. This is entirely optional and you can do it at any step, as long as you've got an intermediate sitting there. And if you're planning to extract data, it's recommended β though not necessary β to compact the intermediate first. β¨
Now for pulling out key-value pairs: hand the intermediate plus the key-value pair you want, over to extract_element. What comes back is either undef (error vibes) or a reference to an array of references to hashes. Each one of those hashes holds exactly one key-value pair.
Same extract_element trick works if you just wanna check whether keys β or full key-value pairs β exist at all. If the returned array is empty? Yeah, that element isn't there. π
For compacted intermediates, every extraction gives you back an array with at most one hash reference in it. Non-compacted intermediates, though, can hold a key more than once, so no promises about how big that result is gonna be. π
Parsing transformations? Pass each one to interpret_transform. The transformation formats are documented over in "TRANSFORMATIONS". You'll get either undef on error, or an array of two scalars β the transformation mode (which is an internal number, iykyk) and the sanitized transformation string, which is just the original transformation string with any preceding operator removed. π
Then you pass the intermediate, the transformation mode and the sanitized transformation string to transform_intermediate, and it modifies the intermediate for you. Slay. π
Repeat that whole loop until the intermediate looks exactly how you want it. π
And finally, hand the intermediate to intermediate_to_string to turn it back into a normal string β which is basically the opposite of parse_options. Same deal as always: undef comes back if something goes wrong. π
Here's the cute part π«Ά β generally, parsing an options string into an intermediate via parse_options and then immediately parsing it back into a string via intermediate_to_string should always give you an options string that is identical to the original one (assuming no errors happened along the way).
If that's not what happens, please report a bug. fr fr, we need to know. π
And one more thing, bestie β any subroutines and constants that are not marked as exportable are explicitly not documented and should be treated as internal, so don't use them. There is no guarantee about their behavior or even their existence. π Not me finding out the hard way...
part 2 is coming, don't go anywhere β we're just getting started π
β¨ OPTIONS STRINGS β¨
Okay so first thing, bestie: the actual content of an X2Go/NX Agent options string is fully documented in nxagent's own documentation, plus all the extra linked places in there. This module does not care about the actual content of an options string. It cares about the format. The shape. The vibe check of the string itself, not the lore. π
An options string follows the form [[key[=value,]]:displaynumber.
Which is, ngl, lowkey loaded. Let's unpack it because there are some interesting implications: π
- Key-value pairs are entirely optional. Like, an options string that's literally just
:42is well-formed. Valid. Slaying. β¨ - Options strings must end with a display number separator, i.e., a colon (
:) and a display number.- No parsing is done on the display number, so any string (even the empty string) is valid as far as this module is concerned. Fr fr.
- The display number, however, cannot contain a colon (
:), because that would make it a new display number separator. π - This module will parse the options string from right to left when searching for the display number separator and use the first one it can find. iykyk.
- Key-value pairs are separated via a comma (
,). Hence, this character is not valid in neither keys nor values. As a workaround, it can be URL-encoded, as, e.g.,%2C, and then used as part of either keys or values. π«Ά - Key-value pairs can be empty. This is supported, and empty key-value pairs will be preserved, but will trigger warnings at parse time. π
- An options string such as
,,,:65is hence valid. - To remove such empty elements, use
compact_intermediate. An implicit empty element is added whenever the resulting options string would only contain the display number. This one cannot be removed, but also won't show up anywhere. Adding any non-empty new key will automatically replace such an empty element, without any need for actual compaction. Slay.
- An options string such as
- In a key-value pair, keys and values are separated from each other via an equal sign (
=).- Hence, this character is not a valid part of a key. It can, however, be a valid part of a value.
- To use this character as part of a key, it can be URL-encoded as, e.g.,
%3D. - While it is legal as part of a value, it is recommended to also URL-encode it when used as part of a value in order to not confuse other parsers.
- An options string such as
this%3Dis%3Da=key:38is just as valid asthis=is=a=key:38orthis=is%3Da%3Dkey:38. - However, the semantics differ. While the latter two key-value pairs are logically equivalent to each other, they are very much different from the first one.
- For the first case, the key will be
this%3Dis%3Da(or, logically, alsothis=is=a, which cannot be directly represented), while the value will be justkey. - The latter two will parse into a key
thiswith a value ofis=a=key(or, logically equivalent,is%3Da%3Dkey).
- Quoting with any character is unsupported. Quotes and other grouping characters (like curly braces
{}) are seen verbatim, without any special meaning. π - Since options strings are typically parsed by C applications,
NUL(control) characters are prematurely terminating the string and hence cannot be directly embedded. Indirectly, they can be embedded by URL-encoding them as%00.- There is, however, no guarantee that an application unpacking such a string will be able to scan any data after the first embedded
NULcharacter. - It is highly recommended to avoid using embedded
NULcharacters. Like, just don't. π - This module will not explicitly scan for them, and, hence, also not issue warnings related to those characters.
- There is, however, no guarantee that an application unpacking such a string will be able to scan any data after the first embedded
- There are no provisions (other than the mentioned invalid characters) on the content of keys and values.
- Importantly, this also means that the same key can show up multiple times in the options string. Semantically, this is redundant, since only the last occurrence of a key (assuming the options string is parsed from left to right) will take any effect. Syntactically, it's completely legal, though. Chaotic but legal. π
- It is recommended to avoid duplicate keys in the input options string.
- Note that, due to the nature of the supported transformations, keys cannot be duplicated with this module.
- To remove duplicated keys, use
compact_intermediate. This will preserve the order in a first-seen fashion. - Additionally, most non-printable control characters can be used verbatim. This includes, but is not limited to, characters like
LF(\n),TAB(\t) andVT(\v). - Naturally, it is recommended to avoid such characters.
- A key-value pair with an empty key but a non-empty value is allowed.
- Likewise, a key-value pair with a non-empty key, but an empty value is allowed. In this case, the value will be interpreted as an empty string in order to differentiate it from a non-existent value.
π¦ TRANSFORMATIONS π¦
Transformations follow the form [+]|-key[=value], which means that:
- They can be prefixed with a plus character (
+) to indicate either additions or modifications. A missing prefix character is interpreted like a plus character.- If the given key already exists in the intermediate, the key-value pair will be updated with the provided value (if any), or a new key-value pair added.
- Insertions always take place at the end of the intermediate.
- The value can be omitted, in which case
keywill be added without a value on insertions, or a potentially existing value removed on updates. β¨
- If they are prefixed with a minus character (
-), deletion mode is activated.- If the given key is not part of the intermediate, no deletion will occur.
- Otherwise, the optional value determines deletion: if no value has been provided,
keywill be removed from the intermediate regardless of its value. If the optional value has been provided,keywill only be removed if both values match. π―
π AUTHOR π
This manual has been written by Mihai Moldovan ionic@ionic.de (mailto: ionic@ionic.de) for the X2Go project (https://www.x2go.org). Iconic behavior, honestly. π«Ά
And that's a wrap, bestie!! This wasperl v5.40.1, dated2026-01-29, and you just readX2Go::...ptions(3pm)in full β part 2 of 2, no skips, no summarising, every single detail preserved. You ate. π πΈβ¨
π¦ where this page comes from
- ubuntu resolute: libx2go-server-perl 4.1.0.6-1.1build3 Β· GPL-2.0-or-later
- ubuntu stonking: libx2go-server-perl 4.1.0.6-1.1build3 Β· GPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms