regexp: Fix issues with character ranges and escapes
diff --git a/result/regexp/issue1103 b/result/regexp/issue1103
new file mode 100644
index 0000000..13ec11b
--- /dev/null
+++ b/result/regexp/issue1103
@@ -0,0 +1,21 @@
+Regexp: [\--A]
+-: Ok
+@: Ok
+A: Ok
+B: Fail
+Regexp: [A-\ud83d\ude0a]
+@: Fail
+A: Ok
+B: Ok
+😊: Ok
+😍: Fail
+Regexp: [\ud83d\ude0a-\ud83d\ude0d]
+A: Fail
+😊: Ok
+😌: Ok
+😍: Ok
+Regexp: [\ud83d\ude0a\-A]
+😊: Ok
+A: Ok
+-: Ok
+😍: Fail
diff --git a/result/regexp/issue1103_err1 b/result/regexp/issue1103_err1
new file mode 100644
index 0000000..ff2b62d
--- /dev/null
+++ b/result/regexp/issue1103_err1
@@ -0,0 +1,2 @@
+Regexp: [--/]
+   failed to compile
diff --git a/result/regexp/issue1103_err1.err b/result/regexp/issue1103_err1.err
new file mode 100644
index 0000000..98c3e7d
--- /dev/null
+++ b/result/regexp/issue1103_err1.err
@@ -0,0 +1 @@
+regexp error : failed to compile: Unescaped '-' can't be the start of a range
diff --git a/result/regexp/issue1103_err2 b/result/regexp/issue1103_err2
new file mode 100644
index 0000000..c6c511c
--- /dev/null
+++ b/result/regexp/issue1103_err2
@@ -0,0 +1,2 @@
+Regexp: [+--]
+   failed to compile
diff --git a/result/regexp/issue1103_err2.err b/result/regexp/issue1103_err2.err
new file mode 100644
index 0000000..dcf8b2a
--- /dev/null
+++ b/result/regexp/issue1103_err2.err
@@ -0,0 +1 @@
+regexp error : failed to compile: Unescaped '-' can't be the end of a range
diff --git a/result/regexp/issue1103_err3 b/result/regexp/issue1103_err3
new file mode 100644
index 0000000..9eb5c27
--- /dev/null
+++ b/result/regexp/issue1103_err3
@@ -0,0 +1,2 @@
+Regexp: [\P{L}-\D]
+   failed to compile
diff --git a/result/regexp/issue1103_err3.err b/result/regexp/issue1103_err3.err
new file mode 100644
index 0000000..5405142
--- /dev/null
+++ b/result/regexp/issue1103_err3.err
@@ -0,0 +1 @@
+regexp error : failed to compile: Multi-character escapes can't be the start of a range
diff --git a/test/regexp/issue1103 b/test/regexp/issue1103
new file mode 100644
index 0000000..7c65943
--- /dev/null
+++ b/test/regexp/issue1103
@@ -0,0 +1,21 @@
+=>[\--A]
+-
+@
+A
+B
+=>[A-\ud83d\ude0a]
+@
+A
+B
+😊
+😍
+=>[\ud83d\ude0a-\ud83d\ude0d]
+A
+😊
+😌
+😍
+=>[\ud83d\ude0a\-A]
+😊
+A
+-
+😍
diff --git a/test/regexp/issue1103_err1 b/test/regexp/issue1103_err1
new file mode 100644
index 0000000..251378b
--- /dev/null
+++ b/test/regexp/issue1103_err1
@@ -0,0 +1 @@
+=>[--/]
diff --git a/test/regexp/issue1103_err2 b/test/regexp/issue1103_err2
new file mode 100644
index 0000000..2d63d45
--- /dev/null
+++ b/test/regexp/issue1103_err2
@@ -0,0 +1 @@
+=>[+--]
diff --git a/test/regexp/issue1103_err3 b/test/regexp/issue1103_err3
new file mode 100644
index 0000000..1b36a04
--- /dev/null
+++ b/test/regexp/issue1103_err3
@@ -0,0 +1 @@
+=>[\P{L}-\D]
diff --git a/xmlregexp.c b/xmlregexp.c
index 0ac874f..fbc2426 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -4978,6 +4978,7 @@
     int cur, len;
     int start = -1;
     int end = -1;
+    int start_escaped = 0;
 
     if (CUR == '\0') {
         ERROR("Expecting ']'");
@@ -4986,6 +4987,7 @@
 
     cur = CUR;
     if (cur == '\\') {
+	start_escaped = 1;
 	NEXT;
 	cur = CUR;
 	switch (cur) {
@@ -5025,7 +5027,7 @@
      * Since we are "inside" a range, we can assume ctxt->cur is past
      * the start of ctxt->string, and PREV should be safe
      */
-    if ((start == '-') && (NXT(1) != ']') && (PREV != '[') && (PREV != '^')) {
+    if ((start == '-') && (!start_escaped) && (NXT(1) != ']') && (PREV != '[') && (PREV != '^')) {
 	NEXTL(len);
 	return;
     }
@@ -5036,6 +5038,10 @@
 		              XML_REGEXP_CHARVAL, start, end, NULL);
 	return;
     }
+    if ((start == '-') && (!start_escaped)) {
+	ERROR("Unescaped '-' can't be the start of a range");
+	return;
+    }
     NEXT;
     cur = CUR;
     if (cur == '\\') {
@@ -5065,6 +5071,10 @@
     } else if ((cur != '\0') && (cur != 0x5B) && (cur != 0x5D)) {
         len = 4;
         end = xmlGetUTF8Char(ctxt->cur, &len);
+        if (end == '-') {
+            ERROR("Unescaped '-' can't be the end of a range");
+            return;
+        }
         if (end < 0) {
             ERROR("Invalid UTF-8");
             return;
@@ -5094,27 +5104,19 @@
     do {
         if (CUR == '\\') {
 	    switch (NXT(1)) {
-		case 'n': case 'r': case 't':
+		case 'n': case 'r': case 't': case 'u':
 		case '\\': case '|': case '.': case '-': case '^': case '?':
 		case '*': case '+': case '{': case '}': case '(': case ')':
 		case '[': case ']': case '!': case '"': case '#': case '$':
 		case '%': case ',': case '/': case ':': case ';': case '=':
 		case '>': case '@': case '`': case '~':
-		    if (NXT(2) == '-') {
-			xmlFAParseCharRange(ctxt);
-		    } else {
-			xmlFAParseCharClassEsc(ctxt);
-		    }
-		    break;
-		case 'u':
-		    if (NXT(6) == '-') {
-			xmlFAParseCharRange(ctxt);
-		    } else {
-			xmlFAParseCharClassEsc(ctxt);
-		    }
+		    xmlFAParseCharRange(ctxt);
 		    break;
 		default:
 		    xmlFAParseCharClassEsc(ctxt);
+		    if ((CUR == '-') && (NXT(1) != '[') && (NXT(1) != ']')) {
+		        ERROR("Multi-character escapes can't be the start of a range");
+		    }
 	    }
 	} else {
 	    xmlFAParseCharRange(ctxt);