oracular (3) X2Go::Server::Agent::NX::Options.3pm.gz

Provided by: libx2go-server-perl_4.1.0.6-1.1build1_all bug

NAME

       X2Go::Server::Agent::NX::Options - NX Options modification module

SYNOPSIS

        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

       Use this module to modify or extract data from X2Go/NX Agent options strings.  Refer to "OPTIONS STRINGS"
       for an in-depth description of options strings.

       First, transform the input options string into an intermediate representation via "parse_options".  The
       options string must end with a display specification (i.e., it must end in ":displaynumber").  Parsing
       errors are indicated by it returning "undef".  The returned value is actually a reference to an array of
       hash references, but you should make no assumptions to the layout or even its actual format.  Treat it
       like a black box.  Crucially, whenever an intermediate is expected, such a reference should be passed.

       To remove redundant or empty entries within an options string, pass the intermediate to
       "compact_intermediate".  This is entirely optional and can be done at any step, as long as an
       intermediate is available.  If you intend to extract data, it is recommended, but not necessary, to
       compact the intermediate first.

       In order to extract key-value pairs, supply the intermediate and a key-value pair to extract to
       "extract_element".  Its result will be either undefined on error, or a reference to an array consisting
       of references to hashes.  Each hash contains exactly one key-value pair.

       The same approach using "extract_element" can be used to check for the existence of either keys or full
       key-value pairs.  If the returned array is empty, no such element exists.

       For compacted intermediates, each extraction operation returns an array with at most one hash reference
       entry.  Non-compacted intermediates can contain a key multiple times, so no guarantee regarding the
       result's magnitude can be given.

       To parse transformations, pass each one to "interpret_transform".  Refer to "TRANSFORMATIONS" for
       documentation on transformation formats.  This will either return "undef" on error, or an array of two
       scalars - the transformation mode (an internal number) and the sanitized transformation string (i.e., the
       original transformation string with any preceding operator removed).

       Pass the intermediate, the transformation mode and the sanitized transformation string to
       "transform_intermediate" to modify the intermediate value.

       Repeat this until the intermediate is modified to your liking.

       Finally, pass the intermediate to "intermediate_to_string" in order to parse it back into a normal
       string.  This operation is essentially the opposite of "parse_options".  As usual, "undef" is returned on
       error.

       Generally, parsing an options string to an intermediate via "parse_options" and then immediately parsing
       it back into a string via "intermediate_to_string" should always produce an options string that is
       identical to the original options string (assuming no errors occurred).

       If this is not the case, please report a bug.

       Any subroutines and constants not marked as exportable are explicitly not documented and should be
       regarded as internal and not be used.  There is no guarantee regarding their behavior or existence.

OPTIONS STRINGS

       X2Go/NX Agent options strings are fully documented in nxagent's documentation and additional, linked
       places therein.

       This module is not really concerned with the actual content of an options string, but mostly its format.

       An options string follows the form [[key[=value,]]:displaynumber.

       This has some interesting implications:

       •   Key-value pairs are entirely optional.  For example, an options string like ":42" is well-formed.

       •   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.

           The display number, however, can not contain a colon (":"), since 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.

       •   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 ",,,:65" is 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 can not 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.

       •   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:38" is just as valid as "this=is=a=key:38" or
           "this=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, also "this=is=a", which can not
           be directly represented), while the value will be just "key".

           The latter two will parse into a key "this" with a value of "is=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 "NUL" character.

           It is highly recommended to avoid using embedded "NUL" characters.

           This module will not explicitly scan for them, and, hence, also not issue warnings related to those
           characters.

       •   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.

           It is recommended to avoid duplicate keys in the input options string.

           Note that, due to the nature of the supported transformations, keys can not 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") and "VT" ("\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 key will 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, key will be removed
           from the intermediate regardless of its value.  If the optional value has been provided, key will
           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>).