- diff --git a/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh b/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
 - index c1dc4b5..be96ec0 100644
 - --- a/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
 - +++ b/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
 - @@ -240,6 +240,16 @@ function netstat_find_next_free_local_tcp_port
 - }
 - +function urldecodestr
 - +{
 - + nameref out=$1
 - + typeset s="$2"
 - + s="${s//$'\\'/$'\\\\'}"
 - + s="${s//+/ }"
 - + out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + return 0
 - +}
 - +
 - #
 - # parse_rfc1738_url - parse RFC 1838 URLs
 - #
 - @@ -253,6 +263,7 @@ function parse_rfc1738_url
 - typeset url="$2"
 - typeset leftover
 - nameref data="$1" # output compound variable
 - + typeset url_param_str
 - # ~(E) is POSIX extended regular expression matching (instead
 - # of shell pattern), "x" means "multiline", "l" means "left
 - @@ -271,7 +282,9 @@ function parse_rfc1738_url
 - (?::([[:digit:]]+))? # port (optional)
 - )
 - )
 - - (?:\/(.*?))?/X}" # path (optional)
 - + (?:\/(.*?))? # path (optional)
 - + (?:\?(.*?))? # URL parameters (optional)
 - + /X}"
 - # All parsed data should be captured via eregex in .sh.match - if
 - # there is anything left (except the 'X') then the input string did
 - @@ -291,8 +304,34 @@ function parse_rfc1738_url
 - [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
 - [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
 - + if [[ "${.sh.match[9]-}" != '' ]] ; then
 - + compound -a data.parameters
 - +
 - + url_param_str="${.sh.match[9]-}"
 - +
 - + while [[ "$url_param_str" != '' ]] ; do
 - + leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
 - +
 - + # save matches because urldecodestr uses .sh.match, too
 - + typeset dp_name
 - + typeset dp_value
 - + typeset dp_next="${.sh.match[3]-}"
 - +
 - + urldecodestr dp_name "${.sh.match[1]-}"
 - + urldecodestr dp_value "${.sh.match[1]-}"
 - +
 - + data.parameters+=(
 - + name="${dp_name}"
 - + value="${dp_value}"
 - + )
 - +
 - + # next parameter
 - + url_param_str="${dp_next}"
 - + done
 - + fi
 - +
 - if [[ -v data.uripath ]] ; then
 - - data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + urldecodestr data.path "${data.uripath}"
 - fi
 - return 0
 - @@ -367,7 +406,7 @@ function cmd_mount
 - # fixme: Need better text layout for $ mount_sshnfs mount --man #
 - typeset -r mount_sshnfs_cmdmount_usage=$'+
 - - [-?\n@(#)\$Id: mount_sshnfs mount (Roland Mainz) 2024-01-31 \$\n]
 - + [-?\n@(#)\$Id: mount_sshnfs mount (Roland Mainz) 2024-07-08 \$\n]
 - [-author?Roland Mainz <roland.mainz@nrubsig.org>]
 - [+NAME?mount_sshnfs mount - mount NFSv4 filesystem through ssh
 - tunnel]
 - @@ -733,7 +772,7 @@ function cmd_umount
 - typeset mydebug=false # fixme: should be "bool" for ksh93v
 - # fixme: Need better text layout for $ mount_sshnfs mount --man #
 - typeset -r mount_sshnfs_cmdumount_usage=$'+
 - - [-?\n@(#)\$Id: mount_sshnfs umount (Roland Mainz) 2024-01-31 \$\n]
 - + [-?\n@(#)\$Id: mount_sshnfs umount (Roland Mainz) 2024-07-08 \$\n]
 - [-author?Roland Mainz <roland.mainz@nrubsig.org>]
 - [+NAME?mount_sshnfs umount - unmount NFSv4 filesystem mounted
 - via mount_sshnfs mount]
 - @@ -837,7 +876,7 @@ function main
 - # fixme: Need better text layout for $ mount_sshnfs --man #
 - typeset -r mount_sshnfs_usage=$'+
 - - [-?\n@(#)\$Id: mount_sshnfs (Roland Mainz) 2024-01-31 \$\n]
 - + [-?\n@(#)\$Id: mount_sshnfs (Roland Mainz) 2024-07-08 \$\n]
 - [-author?Roland Mainz <roland.mainz@nrubsig.org>]
 - [+NAME?mount_sshnfs - mount/umount NFSv4 filesystem via ssh
 - tunnel]
 - diff --git a/cygwin/utils/nfsurlconv/nfsurlconv.ksh b/cygwin/utils/nfsurlconv/nfsurlconv.ksh
 - index 97db401..1a28bfe 100644
 - --- a/cygwin/utils/nfsurlconv/nfsurlconv.ksh
 - +++ b/cygwin/utils/nfsurlconv/nfsurlconv.ksh
 - @@ -38,6 +38,16 @@ function usage
 - return 2
 - }
 - +function urldecodestr
 - +{
 - + nameref out=$1
 - + typeset s="$2"
 - + s="${s//$'\\'/$'\\\\'}"
 - + s="${s//+/ }"
 - + out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + return 0
 - +}
 - +
 - #
 - # parse_rfc1738_url - parse RFC 1838 URLs
 - #
 - @@ -51,6 +61,7 @@ function parse_rfc1738_url
 - typeset url="$2"
 - typeset leftover
 - nameref data="$1" # output compound variable
 - + typeset url_param_str
 - # ~(E) is POSIX extended regular expression matching (instead
 - # of shell pattern), "x" means "multiline", "l" means "left
 - @@ -69,7 +80,9 @@ function parse_rfc1738_url
 - (?::([[:digit:]]+))? # port (optional)
 - )
 - )
 - - (?:\/(.*?))?/X}" # path (optional)
 - + (?:\/(.*?))? # path (optional)
 - + (?:\?(.*?))? # URL parameters (optional)
 - + /X}"
 - # All parsed data should be captured via eregex in .sh.match - if
 - # there is anything left (except the 'X') then the input string did
 - @@ -89,8 +102,34 @@ function parse_rfc1738_url
 - [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
 - [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
 - + if [[ "${.sh.match[9]-}" != '' ]] ; then
 - + compound -a data.parameters
 - +
 - + url_param_str="${.sh.match[9]-}"
 - +
 - + while [[ "$url_param_str" != '' ]] ; do
 - + leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
 - +
 - + # save matches because urldecodestr uses .sh.match, too
 - + typeset dp_name
 - + typeset dp_value
 - + typeset dp_next="${.sh.match[3]-}"
 - +
 - + urldecodestr dp_name "${.sh.match[1]-}"
 - + urldecodestr dp_value "${.sh.match[1]-}"
 - +
 - + data.parameters+=(
 - + name="${dp_name}"
 - + value="${dp_value}"
 - + )
 - +
 - + # next parameter
 - + url_param_str="${dp_next}"
 - + done
 - + fi
 - +
 - if [[ -v data.uripath ]] ; then
 - - data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + urldecodestr data.path "${data.uripath}"
 - fi
 - return 0
 - @@ -207,7 +246,7 @@ function main
 - # fixme: Need better text layout for $ nfsurlconv --man #
 - typeset -r nfsurlconv_usage=$'+
 - - [-?\n@(#)\$Id: nfsurlconv (Roland Mainz) 2024-01-31 \$\n]
 - + [-?\n@(#)\$Id: nfsurlconv (Roland Mainz) 2024-07-08 \$\n]
 - [-author?Roland Mainz <roland.mainz@nrubsig.org>]
 - [+NAME?nfsurlconv - convert hostname,port,path from/to a nfs://-URL]
 - [+DESCRIPTION?\bnfsurlconv\b convert { hostname, port, path } from/to a nfs://-URL.]
 - @@ -238,6 +277,14 @@ path=/a/b/c
 - hostport=bbb
 - path=/a/b/c
 - ]
 - +}
 - + [+?Example 4:][+?Convert URL nfs://bbb:12049//a/b/c?param1=pvalue1¶m2=pvalue2 to ( hostport=, path=, urlparameter= )]{
 - +[+\n$ nfsurlconv.ksh url2hostportpath "nfs:://bbb::12049//a/b/c??param1=pvalue1¶m2=pvalue2"
 - +hostport=bbb::12049
 - +path=/a/b/c
 - +urlparameter=( name=param1 value=pvalue1 )
 - +urlparameter=( name=param2 value=pvalue2 )
 - +]
 - }
 - }
 - [+SEE ALSO?\bksh93\b(1),\bssh\b(1),\bmount.nfs\b(8),\bnfs\b(5)]
 - @@ -299,6 +346,13 @@ path=/a/b/c
 - printf 'hostname=%s\n' "${urldata.host}"
 - printf 'port=%s\n' "${urldata.port-2049}"
 - printf 'path=%s\n' "${urldata.path-}"
 - + if [[ -v urldata.parameters ]] ; then
 - + for (( i=0 ; i < ${#urldata.parameters[@]} ; i++ )) ; do
 - + printf 'urlparameter=( name=%q value=%q )\n' \
 - + "${urldata.parameters[i].name}" \
 - + "${urldata.parameters[i].value}"
 - + done
 - + fi
 - return 0
 - ;;
 - 'url2hostportpath')
 - @@ -307,6 +361,13 @@ path=/a/b/c
 - parse_sshnfs_url urldata "${@:2:1}" || return 1
 - printf 'hostport=%s\n' "${urldata.hostport}"
 - printf 'path=%s\n' "${urldata.path-}"
 - + if [[ -v urldata.parameters ]] ; then
 - + for (( i=0 ; i < ${#urldata.parameters[@]} ; i++ )) ; do
 - + printf 'urlparameter=( name=%q value=%q )\n' \
 - + "${urldata.parameters[i].name}" \
 - + "${urldata.parameters[i].value}"
 - + done
 - + fi
 - return 0
 - ;;
 - 'url2compound')
 - diff --git a/cygwin/utils/sshnfs/sshnfs.ksh b/cygwin/utils/sshnfs/sshnfs.ksh
 - index bfccabb..21d08f0 100644
 - --- a/cygwin/utils/sshnfs/sshnfs.ksh
 - +++ b/cygwin/utils/sshnfs/sshnfs.ksh
 - @@ -222,6 +222,16 @@ function netstat_find_next_free_local_tcp_port
 - }
 - +function urldecodestr
 - +{
 - + nameref out=$1
 - + typeset s="$2"
 - + s="${s//$'\\'/$'\\\\'}"
 - + s="${s//+/ }"
 - + out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + return 0
 - +}
 - +
 - #
 - # parse_rfc1738_url - parse RFC 1838 URLs
 - #
 - @@ -235,6 +245,7 @@ function parse_rfc1738_url
 - typeset url="$2"
 - typeset leftover
 - nameref data="$1" # output compound variable
 - + typeset url_param_str
 - # ~(E) is POSIX extended regular expression matching (instead
 - # of shell pattern), "x" means "multiline", "l" means "left
 - @@ -253,7 +264,9 @@ function parse_rfc1738_url
 - (?::([[:digit:]]+))? # port (optional)
 - )
 - )
 - - (?:\/(.*?))?/X}" # path (optional)
 - + (?:\/(.*?))? # path (optional)
 - + (?:\?(.*?))? # URL parameters (optional)
 - + /X}"
 - # All parsed data should be captured via eregex in .sh.match - if
 - # there is anything left (except the 'X') then the input string did
 - @@ -273,8 +286,34 @@ function parse_rfc1738_url
 - [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
 - [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
 - + if [[ "${.sh.match[9]-}" != '' ]] ; then
 - + compound -a data.parameters
 - +
 - + url_param_str="${.sh.match[9]-}"
 - +
 - + while [[ "$url_param_str" != '' ]] ; do
 - + leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
 - +
 - + # save matches because urldecodestr uses .sh.match, too
 - + typeset dp_name
 - + typeset dp_value
 - + typeset dp_next="${.sh.match[3]-}"
 - +
 - + urldecodestr dp_name "${.sh.match[1]-}"
 - + urldecodestr dp_value "${.sh.match[1]-}"
 - +
 - + data.parameters+=(
 - + name="${dp_name}"
 - + value="${dp_value}"
 - + )
 - +
 - + # next parameter
 - + url_param_str="${dp_next}"
 - + done
 - + fi
 - +
 - if [[ -v data.uripath ]] ; then
 - - data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
 - + urldecodestr data.path "${data.uripath}"
 - fi
 - return 0
 - diff --git a/mount/mount.c b/mount/mount.c
 - index 67b011a..06a0c35 100644
 - --- a/mount/mount.c
 - +++ b/mount/mount.c
 - @@ -71,6 +71,7 @@ static VOID PrintUsage(LPTSTR pProcess)
 - {
 - (void)_tprintf(
 - TEXT("Usage: %s [options] <drive letter|*> <hostname>:<path>\n")
 - +
 - TEXT("* Options:\n")
 - TEXT("\t-h\thelp\n")
 - TEXT("\t/?\thelp\n")
 - @@ -82,6 +83,7 @@ static VOID PrintUsage(LPTSTR pProcess)
 - " (Linux compat)\n")
 - TEXT("\t-p\tmake the mount persist over reboots\n")
 - TEXT("\t-o <comma-separated mount options>\n")
 - +
 - TEXT("* Mount options:\n")
 - TEXT("\tro\tmount as read-only\n")
 - TEXT("\trw\tmount as read-write (default)\n")
 - @@ -100,23 +102,33 @@ static VOID PrintUsage(LPTSTR pProcess)
 - "\t\tif this value is prefixed with 'nfsv3attrmode+'\n"
 - "\t\tthe mode value from a \"NfsV3Attributes\" EA will be used\n"
 - "\t\t(defaults \"nfsv3attrmode+0o%o\").\n")
 - +
 - + TEXT("* URL parameters:\n")
 - + TEXT("\tro=1\tmount as read-only\n")
 - + TEXT("\trw=1\tmount as read-write (default)\n")
 - +
 - TEXT("* Hostname:\n")
 - TEXT("\tDNS name, or hostname in domain\n")
 - TEXT("\tentry in C:\\Windows\\System32\\drivers\\etc\\hosts\n")
 - TEXT("\tIPv4 address\n")
 - TEXT("\tIPv6 address within '[', ']' "
 - "(will be converted to *.ipv6-literal.net)\n")
 - +
 - TEXT("* Examples:\n")
 - TEXT("\tnfs_mount.exe -p -o rw 'H' derfwpc5131_ipv4:/export/home2/rmainz\n")
 - TEXT("\tnfs_mount.exe -o rw '*' bigramhost:/tmp\n")
 - + TEXT("\tnfs_mount.exe -o ro '*' archive1:/tmp\n")
 - + TEXT("\tnfs_mount.exe '*' archive1:/tmp?ro=1\n")
 - TEXT("\tnfs_mount.exe -o rw,sec=sys,port=30000 T grendel:/net_tmpfs2\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//net_tmpfs2/test2\n")
 - + TEXT("\tnfs_mount.exe -o sec=sys S nfs://myhost1//net_tmpfs2/test2?rw=1\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1:1234//net_tmpfs2/test2\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw,port=1234 S nfs://myhost1//net_tmpfs2/test2\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw '*' [fe80::21b:1bff:fec3:7713]://net_tmpfs2/test2\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw '*' nfs://[fe80::21b:1bff:fec3:7713]//net_tmpfs2/test2\n")
 - TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir%%20space/test2\n")
 - - TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir+space/test2\n"),
 - + TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir+space/test2\n")
 - + TEXT("\tnfs_mount.exe -o sec=sys S nfs://myhost1//dirwithspace/dir+space/test2?rw=1\n"),
 - pProcess, (int)NFS41_DRIVER_DEFAULT_CREATE_MODE);
 - }
 - @@ -404,6 +416,65 @@ static DWORD ParseRemoteName(
 - goto out;
 - }
 - + if (uctx->num_parameters > 0) {
 - + int pi;
 - + const char *pname;
 - + const char *pvalue;
 - +
 - + /*
 - + * FIXME: Values added here based on URL parameters
 - + * should be added at the front of the list of options,
 - + * so users can override the nfs://-URL given default.
 - + * Right now this does not work, e.g.
 - + * $ nfs_mount.exe -o rw nfs://foo//bar?ro=1 # will
 - + * result in a read-only mount, while the expectation
 - + * is that -o overrides URL settings.
 - + */
 - + for (pi = 0; pi < uctx->num_parameters ; pi++) {
 - + pname = uctx->parameters[pi].name;
 - + pvalue = uctx->parameters[pi].value;
 - +
 - + if (!strcmp(pname, "rw")) {
 - + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
 - + (void)InsertOption(TEXT("rw"), TEXT("1"), pOptions);
 - + }
 - + else if (!strcmp(pvalue, "0")) {
 - + (void)InsertOption(TEXT("ro"), TEXT("1"), pOptions);
 - + }
 - + else {
 - + result = ERROR_BAD_ARGUMENTS;
 - + (void)_ftprintf(stderr,
 - + TEXT("Unsupported nfs://-URL parameter ")
 - + TEXT("'%S' value '%S'.\n"),
 - + pname, pvalue);
 - + goto out;
 - + }
 - + }
 - + else if (!strcmp(pname, "ro")) {
 - + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
 - + (void)InsertOption(TEXT("ro"), TEXT("1"), pOptions);
 - + }
 - + else if (!strcmp(pvalue, "0")) {
 - + (void)InsertOption(TEXT("rw"), TEXT("1"), pOptions);
 - + }
 - + else {
 - + result = ERROR_BAD_ARGUMENTS;
 - + (void)_ftprintf(stderr,
 - + TEXT("Unsupported nfs://-URL parameter ")
 - + TEXT("'%S' value '%S'.\n"),
 - + pname, pvalue);
 - + goto out;
 - + }
 - + }
 - + else {
 - + result = ERROR_BAD_ARGUMENTS;
 - + (void)_ftprintf(stderr,
 - + TEXT("Unsupported nfs://-URL parameter '%S'.\n"), pname);
 - + goto out;
 - + }
 - + }
 - + }
 - +
 - if (uctx->hostport.port != -1)
 - port = uctx->hostport.port;
 - diff --git a/mount/urlparser1.c b/mount/urlparser1.c
 - index a90d1e2..8fcae52 100644
 - --- a/mount/urlparser1.c
 - +++ b/mount/urlparser1.c
 - @@ -28,10 +28,23 @@
 - #include <stdlib.h>
 - #include <stdbool.h>
 - #include <string.h>
 - +#include <ctype.h>
 - #include <stdio.h>
 - +// #define TEST_URLPARSER 1
 - +
 - #include "urlparser1.h"
 - +typedef struct _url_parser_context_private {
 - + url_parser_context c;
 - +
 - + /* Private data */
 - + char *parameter_string_buff;
 - +} url_parser_context_private;
 - +
 - +#define MAX_URL_PARAMETERS 256
 - +
 - +#ifdef _MSC_VER
 - /*
 - * Disable "warning C4996: 'wcscpy': This function or variable may be
 - * unsafe." because in this case the buffers are properly sized,
 - @@ -43,6 +56,7 @@
 - * because it is safe to use in our code.
 - */
 - #pragma warning (disable : 4706)
 - +#endif /* _MSC_VER */
 - /*
 - * Original extended regular expression:
 - @@ -62,69 +76,61 @@
 - * ")"
 - * ")"
 - * "(?:/(.*?))?" // path (optional)
 - + * "(?:\?(.*?))?" // URL parameters (optional)
 - * "$"
 - */
 - #define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
 - -#if 0
 - +#if 0 || defined(TEST_URLPARSER)
 - #define D(x) x
 - #else
 - #define D(x)
 - #endif
 - static
 - -void urldecodestr(char *dst, const char *src, size_t len)
 - +void urldecodestr(char *outbuff, const char *buffer, size_t len)
 - {
 - - /*
 - - * Unicode characters with a code point > 255 are encoded
 - - * as UTF-8 bytes
 - - */
 - -#define isurlxdigit(c) \
 - - (((c) >= '0' && (c) <= '9') || \
 - - ((c) >= 'a' && (c) <= 'f') || \
 - - ((c) >= 'A' && (c) <= 'F'))
 - - char a, b;
 - - while (*src && len--) {
 - - if (len > 2) {
 - - if ((*src == '%') &&
 - - (a = src[1]) && (b = src[2])) {
 - - if ((isurlxdigit(a) &&
 - - isurlxdigit(b))) {
 - - if (a >= 'a')
 - - a -= 'a'-'A';
 - - if (a >= 'A')
 - - a -= ('A' - 10);
 - - else
 - - a -= '0';
 - -
 - - if (b >= 'a')
 - - b -= 'a'-'A';
 - - if (b >= 'A')
 - - b -= ('A' - 10);
 - - else
 - - b -= '0';
 - -
 - - *dst++ = 16*a+b;
 - -
 - - src+=3;
 - - len-=2;
 - - continue;
 - - }
 - + size_t i, j;
 - +
 - + for (i = j = 0 ; i < len ; ) {
 - + switch (buffer[i]) {
 - + case '%':
 - + if ((i + 2) < len) {
 - + if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
 - + const char hexstr[3] = {
 - + buffer[i+1],
 - + buffer[i+2],
 - + '\0'
 - + };
 - + outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
 - + i += 3;
 - + } else {
 - + /* invalid hex digit */
 - + outbuff[j++] = buffer[i];
 - + i++;
 - }
 - + } else {
 - + /* incomplete hex digit */
 - + outbuff[j++] = buffer[i];
 - + i++;
 - }
 - - if (*src == '+') {
 - - *dst++ = ' ';
 - - src++;
 - - continue;
 - + break;
 - + case '+':
 - + outbuff[j++] = ' ';
 - + i++;
 - + break;
 - + default:
 - + outbuff[j++] = buffer[i++];
 - + break;
 - }
 - - *dst++ = *src++;
 - }
 - - *dst++ = '\0';
 - +
 - + outbuff[j] = '\0';
 - }
 - url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
 - {
 - - url_parser_context *uctx;
 - + url_parser_context_private *uctx;
 - char *s;
 - size_t in_url_len;
 - size_t context_len;
 - @@ -137,30 +143,36 @@ url_parser_context *url_parser_create_context(const char *in_url, unsigned int f
 - in_url_len = strlen(in_url);
 - - context_len = sizeof(url_parser_context) +
 - - ((in_url_len+1)*5);
 - + context_len = sizeof(url_parser_context_private) +
 - + ((in_url_len+1)*6) +
 - + (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
 - uctx = malloc(context_len);
 - if (!uctx)
 - return NULL;
 - s = (void *)(uctx+1);
 - - uctx->in_url = s; s+= in_url_len+1;
 - - (void)strcpy(uctx->in_url, in_url);
 - - uctx->scheme = s; s+= in_url_len+1;
 - - uctx->login.username = s; s+= in_url_len+1;
 - - uctx->hostport.hostname = s; s+= in_url_len+1;
 - - uctx->path = s; s+= in_url_len+1;
 - - uctx->hostport.port = -1;
 - -
 - - return uctx;
 - + uctx->c.in_url = s; s+= in_url_len+1;
 - + (void)strcpy(uctx->c.in_url, in_url);
 - + uctx->c.scheme = s; s+= in_url_len+1;
 - + uctx->c.login.username = s; s+= in_url_len+1;
 - + uctx->c.hostport.hostname = s; s+= in_url_len+1;
 - + uctx->c.path = s; s+= in_url_len+1;
 - + uctx->c.hostport.port = -1;
 - + uctx->c.num_parameters = -1;
 - + uctx->c.parameters = (void *)s; s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
 - + uctx->parameter_string_buff = s; s+= in_url_len+1;
 - +
 - + return &uctx->c;
 - }
 - -int url_parser_parse(url_parser_context *uctx)
 - +int url_parser_parse(url_parser_context *ctx)
 - {
 - - D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->in_url));
 - + url_parser_context_private *uctx = (url_parser_context_private *)ctx;
 - +
 - + D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
 - char *s;
 - - const char *urlstr = uctx->in_url;
 - + const char *urlstr = uctx->c.in_url;
 - size_t slen;
 - s = strstr(urlstr, "://");
 - @@ -170,57 +182,120 @@ int url_parser_parse(url_parser_context *uctx)
 - }
 - slen = s-urlstr;
 - - (void)memcpy(uctx->scheme, urlstr, slen);
 - - uctx->scheme[slen] = '\0';
 - + (void)memcpy(uctx->c.scheme, urlstr, slen);
 - + uctx->c.scheme[slen] = '\0';
 - urlstr += slen + 3;
 - - D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->scheme, urlstr));
 - + D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
 - s = strstr(urlstr, "@");
 - if (s) {
 - /* URL has user/password */
 - slen = s-urlstr;
 - - urldecodestr(uctx->login.username, urlstr, slen);
 - + urldecodestr(uctx->c.login.username, urlstr, slen);
 - urlstr += slen + 1;
 - - s = strstr(uctx->login.username, ":");
 - + s = strstr(uctx->c.login.username, ":");
 - if (s) {
 - /* found passwd */
 - - uctx->login.passwd = s+1;
 - + uctx->c.login.passwd = s+1;
 - *s = '\0';
 - }
 - else
 - {
 - - uctx->login.passwd = NULL;
 - + uctx->c.login.passwd = NULL;
 - }
 - /* catch password-only URLs */
 - - if (uctx->login.username[0] == '\0')
 - - uctx->login.username = NULL;
 - + if (uctx->c.login.username[0] == '\0')
 - + uctx->c.login.username = NULL;
 - }
 - else
 - {
 - - uctx->login.username = NULL;
 - - uctx->login.passwd = NULL;
 - + uctx->c.login.username = NULL;
 - + uctx->c.login.passwd = NULL;
 - }
 - D((void)fprintf(stdout, "login='%s', passwd='%s', rest='%s'\n",
 - - DBGNULLSTR(uctx->login.username),
 - - DBGNULLSTR(uctx->login.passwd),
 - + DBGNULLSTR(uctx->c.login.username),
 - + DBGNULLSTR(uctx->c.login.passwd),
 - DBGNULLSTR(urlstr)));
 - + char *raw_parameters;
 - +
 - + uctx->c.num_parameters = 0;
 - + raw_parameters = strstr(urlstr, "?");
 - + if (raw_parameters) {
 - + *raw_parameters++ = '\0';
 - + D((void)fprintf(stdout, "raw parameters = '%s'\n", raw_parameters));
 - +
 - + char *ps = raw_parameters;
 - + char *pv; /* parameter value */
 - + char *na; /* next '&' */
 - + char *pb = uctx->parameter_string_buff;
 - + char *pname;
 - + char *pvalue;
 - + ssize_t pi;
 - +
 - + for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
 - + pname = ps;
 - +
 - + /*
 - + * Handle parameters without value,
 - + * e.g. "path?name1&name2=value2"
 - + */
 - + na = strstr(ps, "&");
 - + pv = strstr(ps, "=");
 - + if (pv && (na?(na > pv):true)) {
 - + *pv++ = '\0';
 - + pvalue = pv;
 - + ps = pv;
 - + }
 - + else {
 - + pvalue = NULL;
 - + }
 - +
 - + if (na) {
 - + *na++ = '\0';
 - + }
 - +
 - + /* URLDecode parameter name */
 - + urldecodestr(pb, pname, strlen(pname));
 - + uctx->c.parameters[pi].name = pb;
 - + pb += strlen(uctx->c.parameters[pi].name)+1;
 - +
 - + /* URLDecode parameter value */
 - + if (pvalue) {
 - + urldecodestr(pb, pvalue, strlen(pvalue));
 - + uctx->c.parameters[pi].value = pb;
 - + pb += strlen(uctx->c.parameters[pi].value)+1;
 - + }
 - + else {
 - + uctx->c.parameters[pi].value = NULL;
 - + }
 - +
 - + /* Next '&' ? */
 - + if (!na)
 - + break;
 - +
 - + ps = na;
 - + }
 - +
 - + uctx->c.num_parameters = pi+1;
 - + }
 - +
 - s = strstr(urlstr, "/");
 - if (s) {
 - /* URL has hostport */
 - slen = s-urlstr;
 - - urldecodestr(uctx->hostport.hostname, urlstr, slen);
 - + urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
 - urlstr += slen + 1;
 - /*
 - * check for addresses within '[' and ']', like
 - * IPv6 addresses
 - */
 - - s = uctx->hostport.hostname;
 - + s = uctx->c.hostport.hostname;
 - if (s[0] == '[')
 - s = strstr(s, "]");
 - @@ -232,29 +307,41 @@ int url_parser_parse(url_parser_context *uctx)
 - s = strstr(s, ":");
 - if (s) {
 - /* found port number */
 - - uctx->hostport.port = atoi(s+1);
 - + uctx->c.hostport.port = atoi(s+1);
 - *s = '\0';
 - }
 - }
 - else
 - {
 - - (void)strcpy(uctx->hostport.hostname, urlstr);
 - - uctx->path = NULL;
 - + (void)strcpy(uctx->c.hostport.hostname, urlstr);
 - + uctx->c.path = NULL;
 - urlstr = NULL;
 - }
 - - D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s'\n",
 - - DBGNULLSTR(uctx->hostport.hostname),
 - - uctx->hostport.port,
 - - DBGNULLSTR(urlstr)));
 - + D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s', num_parameters=%d\n",
 - + DBGNULLSTR(uctx->c.hostport.hostname),
 - + uctx->c.hostport.port,
 - + DBGNULLSTR(urlstr),
 - + (int)uctx->c.num_parameters));
 - +
 - + D(
 - + ssize_t dpi;
 - + for (dpi = 0 ; dpi < uctx->c.num_parameters ; dpi++) {
 - + (void)fprintf(stdout, "param[%d]: name='%s'/value='%s'\n",
 - + (int)dpi,
 - + uctx->c.parameters[dpi].name,
 - + DBGNULLSTR(uctx->c.parameters[dpi].value));
 - + }
 - + );
 - if (!urlstr) {
 - - return 0;
 - + goto done;
 - }
 - - urldecodestr(uctx->path, urlstr, strlen(urlstr));
 - - D((void)fprintf(stdout, "path='%s'\n", uctx->path));
 - + urldecodestr(uctx->c.path, urlstr, strlen(urlstr));
 - + D((void)fprintf(stdout, "path='%s'\n", uctx->c.path));
 - +done:
 - return 0;
 - }
 - @@ -301,7 +388,16 @@ int main(int ac, char *av[])
 - (void)test_url_parser("nfs://hostbar:93//absolutepath/a");
 - (void)test_url_parser("nfs://hostbar:93//absolutepath/blank%20path/a");
 - (void)test_url_parser("nfs://hostbar:93//absolutepath/blank+path/a");
 - -
 - + (void)test_url_parser("foo://hostbar:93?param1");
 - + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1");
 - + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pname2=pvalue2");
 - + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pvalue2=v2&n3=v3");
 - + (void)test_url_parser("foo://hostbar:93?pname1¶m2=p2");
 - + (void)test_url_parser("foo://hostbar:93?pname1=¶m2=p2");
 - + (void)test_url_parser("foo://hostbar:93//path/path2?param1=p1");
 - + (void)test_url_parser("foo://hostbar:93//path/path2?param1¶m2=p2");
 - + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=u+n2&n3=v3");
 - + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=%E2%82%AC&n3=v3");
 - (void)test_url_parser("foo://");
 - (void)test_url_parser("typo:/hostbar");
 - diff --git a/mount/urlparser1.h b/mount/urlparser1.h
 - index 8ed0f91..4526f1c 100644
 - --- a/mount/urlparser1.h
 - +++ b/mount/urlparser1.h
 - @@ -26,8 +26,16 @@
 - #include <stdlib.h>
 - -typedef
 - -struct _url_parser_context {
 - +#ifdef _MSC_VER
 - +typedef signed long long ssize_t;
 - +#endif
 - +
 - +typedef struct _url_parser_name_value {
 - + char *name;
 - + char *value;
 - +} url_parser_name_value;
 - +
 - +typedef struct _url_parser_context {
 - char *in_url;
 - char *scheme;
 - @@ -40,6 +48,9 @@ struct _url_parser_context {
 - signed int port;
 - } hostport;
 - char *path;
 - +
 - + ssize_t num_parameters;
 - + url_parser_name_value *parameters;
 - } url_parser_context;
 - /* Prototypes */
 
URL parameter work backup 2024-07-08
Posted by Anonymous on Mon 8th Jul 2024 17:43
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
 nrubsig.kpaste.net RSS