URLs: changed paramter delimiter from / to ? and & as it is usual for URLs, update docs
diff --git a/serial/urlhandler/protocol_loop.py b/serial/urlhandler/protocol_loop.py
index 02167e5..10dedeb 100644
--- a/serial/urlhandler/protocol_loop.py
+++ b/serial/urlhandler/protocol_loop.py
@@ -102,26 +102,20 @@
     def fromURL(self, url):
         """extract host and port from an URL string"""
         parts = urlparse.urlsplit(url)
-        if parts.scheme.lower() != "loop":
-            raise SerialException('expected a string in the form "loop://[option[/option...]]": not starting with loop:// (%r)' % (parts.scheme,))
+        if parts.scheme != "loop":
+            raise SerialException('expected a string in the form "loop://[?logging={debug|info|warning|error}]": not starting with loop:// (%r)' % (parts.scheme,))
         try:
             # process options now, directly altering self
-            for option in parts.path.split('/'):
-                if '=' in option:
-                    option, value = option.split('=', 1)
-                else:
-                    value = None
-                if not option:
-                    pass
-                elif option == 'logging':
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'logging':
                     logging.basicConfig()   # XXX is that good to call it here?
                     self.logger = logging.getLogger('pySerial.loop')
-                    self.logger.setLevel(LOGGER_LEVELS[value])
+                    self.logger.setLevel(LOGGER_LEVELS[values[0]])
                     self.logger.debug('enabled logging')
                 else:
                     raise ValueError('unknown option: %r' % (option,))
         except ValueError as e:
-            raise SerialException('expected a string in the form "[loop://][option[/option...]]": %s' % e)
+            raise SerialException('expected a string in the form "loop://[?logging={debug|info|warning|error}]": %s' % e)
 
     #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
 
diff --git a/serial/urlhandler/protocol_socket.py b/serial/urlhandler/protocol_socket.py
index 4538e17..3dedb48 100644
--- a/serial/urlhandler/protocol_socket.py
+++ b/serial/urlhandler/protocol_socket.py
@@ -104,21 +104,15 @@
     def fromURL(self, url):
         """extract host and port from an URL string"""
         parts = urlparse.urlsplit(url)
-        if parts.scheme.lower() != "socket":
-            raise SerialException('expected a string in the form "socket://<host>:<port>[/option[/option...]]": not starting with socket:// (%r)' % (parts.scheme,))
+        if parts.scheme != "socket":
+            raise SerialException('expected a string in the form "socket://<host>:<port>[?logging={debug|info|warning|error}]": not starting with socket:// (%r)' % (parts.scheme,))
         try:
             # process options now, directly altering self
-            for option in parts.path.lower().split('/'):
-                if '=' in option:
-                    option, value = option.split('=', 1)
-                else:
-                    value = None
-                if not option:
-                    pass
-                elif option == 'logging':
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'logging':
                     logging.basicConfig()   # XXX is that good to call it here?
                     self.logger = logging.getLogger('pySerial.socket')
-                    self.logger.setLevel(LOGGER_LEVELS[value])
+                    self.logger.setLevel(LOGGER_LEVELS[values[0]])
                     self.logger.debug('enabled logging')
                 else:
                     raise ValueError('unknown option: %r' % (option,))
@@ -126,7 +120,7 @@
             host, port = parts.hostname, parts.port
             if not 0 <= port < 65536: raise ValueError("port not in range 0...65535")
         except ValueError as e:
-            raise SerialException('expected a string in the form "socket://<host>:<port>[/option[/option...]]": %s' % e)
+            raise SerialException('expected a string in the form "socket://<host>:<port>[?logging={debug|info|warning|error}]": %s' % e)
         return (host, port)
 
     #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
diff --git a/serial/urlhandler/protocol_spy.py b/serial/urlhandler/protocol_spy.py
index a4deaef..d6ed458 100644
--- a/serial/urlhandler/protocol_spy.py
+++ b/serial/urlhandler/protocol_spy.py
@@ -165,13 +165,18 @@
         formatter = FormatHexdump
         color = False
         output = sys.stderr
-        for option, values in urlparse.parse_qs(parts.query, True).items():
-            if option == 'dev':
-                output = open(values[0], 'w')
-            elif option == 'color':
-                color = True
-            elif option == 'raw':
-                formatter = FormatRaw
+        try:
+            for option, values in urlparse.parse_qs(parts.query, True).items():
+                if option == 'dev':
+                    output = open(values[0], 'w')
+                elif option == 'color':
+                    color = True
+                elif option == 'raw':
+                    formatter = FormatRaw
+                else:
+                    raise ValueError('unknown option: %r' % (option,))
+        except ValueError as e:
+            raise SerialException('expected a string in the form "spy://port[?option[=value][&option[=value]]]": %s' % e)
         self.formatter = formatter(output, color)
         return ''.join([parts.netloc, parts.path])