Pass PIs to the application + verify that PI name isn't /xml/i
diff --git a/test/pi01.out b/test/pi01.out
new file mode 100644
index 0000000..16f0f79
--- /dev/null
+++ b/test/pi01.out
@@ -0,0 +1,8 @@
+
+pistart SomePI
+data abc?
+piend
+elemstart a
+content
+elemend
+ok
diff --git a/test/pi01.xml b/test/pi01.xml
new file mode 100644
index 0000000..7351b3a
--- /dev/null
+++ b/test/pi01.xml
@@ -0,0 +1 @@
+<?SomePI abc?><a/>
diff --git a/test/pi02.out b/test/pi02.out
new file mode 100644
index 0000000..180f140
--- /dev/null
+++ b/test/pi02.out
@@ -0,0 +1,7 @@
+
+pistart P
+piend
+elemstart a
+content
+elemend
+ok
diff --git a/test/pi02.xml b/test/pi02.xml
new file mode 100644
index 0000000..488f4cd
--- /dev/null
+++ b/test/pi02.xml
@@ -0,0 +1 @@
+<?P?><a/>
diff --git a/test/pi03.out b/test/pi03.out
new file mode 100644
index 0000000..04ebd35
--- /dev/null
+++ b/test/pi03.out
@@ -0,0 +1,8 @@
+
+pistart XMLData
+data <? > <!--abc--> ?
+piend
+elemstart a
+content
+elemend
+ok
diff --git a/test/pi03.xml b/test/pi03.xml
new file mode 100644
index 0000000..3c2b5a9
--- /dev/null
+++ b/test/pi03.xml
@@ -0,0 +1 @@
+<?XMLData <? > <!--abc--> ?><a/>
diff --git a/test/pi04.out b/test/pi04.out
new file mode 100644
index 0000000..71c7761
--- /dev/null
+++ b/test/pi04.out
@@ -0,0 +1,7 @@
+
+pistart XM
+piend
+elemstart a
+content
+elemend
+ok
diff --git a/test/pi04.xml b/test/pi04.xml
new file mode 100644
index 0000000..886e70a
--- /dev/null
+++ b/test/pi04.xml
@@ -0,0 +1 @@
+<?xml version="1.1"?><?XM?><a/>
diff --git a/test/pi_err01.out b/test/pi_err01.out
new file mode 100644
index 0000000..9456d41
--- /dev/null
+++ b/test/pi_err01.out
@@ -0,0 +1,2 @@
+
+error
diff --git a/test/pi_err01.xml b/test/pi_err01.xml
new file mode 100644
index 0000000..f1edf92
--- /dev/null
+++ b/test/pi_err01.xml
@@ -0,0 +1 @@
+<?XML?><a/>
diff --git a/test/pi_err02.out b/test/pi_err02.out
new file mode 100644
index 0000000..9456d41
--- /dev/null
+++ b/test/pi_err02.out
@@ -0,0 +1,2 @@
+
+error
diff --git a/test/pi_err02.xml b/test/pi_err02.xml
new file mode 100644
index 0000000..c3f0bf8
--- /dev/null
+++ b/test/pi_err02.xml
@@ -0,0 +1 @@
+<?A9/data?>
diff --git a/test/test.c b/test/test.c
index 1e5aee3..ca272c9 100644
--- a/test/test.c
+++ b/test/test.c
@@ -89,6 +89,13 @@
 		}
 		y_printchar(x->data);
 		break;
+	case YXML_PISTART:
+		y_printtoken(x, "pistart ");
+		y_printstring(x->pi);
+		break;
+	case YXML_PIEND:
+		y_printtoken(x, "piend");
+		break;
 	default:
 		y_printtoken(x, "error\n");
 		exit(0);
diff --git a/test/xmldecl_err11.out b/test/xmldecl_err11.out
new file mode 100644
index 0000000..9456d41
--- /dev/null
+++ b/test/xmldecl_err11.out
@@ -0,0 +1,2 @@
+
+error
diff --git a/test/xmldecl_err11.xml b/test/xmldecl_err11.xml
new file mode 100644
index 0000000..a7d605f
--- /dev/null
+++ b/test/xmldecl_err11.xml
@@ -0,0 +1 @@
+<?xml version="1.0"?><?xml version="1.0"><a/>
diff --git a/yxml-states b/yxml-states
index 3fa5f76..efdc17b 100644
--- a/yxml-states
+++ b/yxml-states
@@ -75,7 +75,7 @@
 
 lee1       '-' @misc1 comment1; 'D' "OCTYPE" dt0
 lee2       '-' @misc2 comment1; '[' "CDATA[" cd0
-leq0       'x' "ml" xmldecl0; NameStart @misc1 pi1
+leq0       'x' "ml" xmldecl0; NameStart @misc1 pistart pi1
 
 
 # XMLDecl, starting from '<?xml', returns to misc1
@@ -119,12 +119,11 @@
 
 
 # PI, starting from '<?', returns to @
-# TODO: Verify that the PI name isn't /xml/i
-# TODO: Pass the name and contents to the application
-pi0        NameStart pi1
-pi1        Name pi1; SP pi2
-pi2        '?' pi3; Char pi2
-pi3        '>' @; Char pi2
+pi0        NameStart pistart pi1
+pi1        Name piname pi1; '?' pinameend pi4; SP pinameend pi2
+pi2        '?' setdata pi3; Char setdata pi2
+pi3        '>' pivalend @; Char setdata pi2
+pi4        '>' pivalend @
 
 
 # CDSect, starting from '<![DATA[', returns to misc2
diff --git a/yxml.c b/yxml.c
index 581cad6..05bd6de 100644
--- a/yxml.c
+++ b/yxml.c
@@ -74,6 +74,7 @@
 	YXMLS_pi1,
 	YXMLS_pi2,
 	YXMLS_pi3,
+	YXMLS_pi4,
 	YXMLS_std0,
 	YXMLS_std1,
 	YXMLS_std2,
@@ -158,19 +159,10 @@
 }
 
 
-static inline int yxml_elemstart(yxml_t *x, unsigned ch) {
-	return yxml_pushstack(x, &x->elem, ch);
-}
-
-
-static inline int yxml_elemname(yxml_t *x, unsigned ch) {
-	return yxml_pushstackc(x, ch);
-}
-
-
-static inline int yxml_elemnameend(yxml_t *x, unsigned ch) {
-	return YXML_ELEMSTART;
-}
+static inline int yxml_elemstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->elem, ch); }
+static inline int yxml_elemname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_elemnameend(yxml_t *x, unsigned ch) { return YXML_ELEMSTART; }
+static inline int yxml_content    (yxml_t *x, unsigned ch) { return YXML_CONTENT; }
 
 
 /* Also used in yxml_elemcloseend(), since this function just removes the last
@@ -204,30 +196,18 @@
 }
 
 
-static inline int yxml_attrstart(yxml_t *x, unsigned ch) {
-	return yxml_pushstack(x, &x->attr, ch);
+static inline int yxml_attrstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->attr, ch); }
+static inline int yxml_attrname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_attrnameend(yxml_t *x, unsigned ch) { return YXML_ATTRSTART; }
+static inline int yxml_attrvalend (yxml_t *x, unsigned ch) { yxml_popstack(x); return YXML_ATTREND; }
+
+
+static inline int yxml_pistart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->pi, ch); }
+static inline int yxml_piname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_pinameend(yxml_t *x, unsigned ch) {
+	return (x->pi[0]|32) == 'x' && (x->pi[1]|32) == 'm' && (x->pi[2]|32) == 'l' && !x->pi[3] ? YXML_ESYN : YXML_PISTART;
 }
-
-
-static inline int yxml_attrname(yxml_t *x, unsigned ch) {
-	return yxml_pushstackc(x, ch);
-}
-
-
-static inline int yxml_attrnameend(yxml_t *x, unsigned ch) {
-	return YXML_ATTRSTART;
-}
-
-
-static inline int yxml_attrvalend(yxml_t *x, unsigned ch) {
-	yxml_popstack(x);
-	return YXML_ATTREND;
-}
-
-
-static inline int yxml_content(yxml_t *x, unsigned ch) {
-	return YXML_CONTENT;
-}
+static inline int yxml_pivalend (yxml_t *x, unsigned ch) { yxml_popstack(x); x->pi = (char *)x->stack; return YXML_PIEND; }
 
 
 static inline int yxml_refstart(yxml_t *x, unsigned ch) {
@@ -287,7 +267,7 @@
 	x->stack = (unsigned char *)stack;
 	x->stacksize = stacksize;
 	*x->stack = 0;
-	x->elem = (char *)x->stack;
+	x->elem = x->pi = (char *)x->stack;
 	x->state = YXMLS_init;
 }
 
@@ -723,7 +703,7 @@
 		if(yxml_isNameStart(ch)) {
 			x->state = YXMLS_pi1;
 			x->nextstate = YXMLS_misc1;
-			return YXML_OK;
+			return yxml_pistart(x, ch);
 		}
 		break;
 	case YXMLS_misc0:
@@ -773,33 +753,43 @@
 	case YXMLS_pi0:
 		if(yxml_isNameStart(ch)) {
 			x->state = YXMLS_pi1;
-			return YXML_OK;
+			return yxml_pistart(x, ch);
 		}
 		break;
 	case YXMLS_pi1:
 		if(yxml_isName(ch))
-			return YXML_OK;
+			return yxml_piname(x, ch);
+		if(ch == (unsigned char)'?') {
+			x->state = YXMLS_pi4;
+			return yxml_pinameend(x, ch);
+		}
 		if(yxml_isSP(ch)) {
 			x->state = YXMLS_pi2;
-			return YXML_OK;
+			return yxml_pinameend(x, ch);
 		}
 		break;
 	case YXMLS_pi2:
 		if(ch == (unsigned char)'?') {
 			x->state = YXMLS_pi3;
-			return YXML_OK;
+			return yxml_setdata(x, ch);
 		}
 		if(yxml_isChar(ch))
-			return YXML_OK;
+			return yxml_setdata(x, ch);
 		break;
 	case YXMLS_pi3:
 		if(ch == (unsigned char)'>') {
 			x->state = x->nextstate;
-			return YXML_OK;
+			return yxml_pivalend(x, ch);
 		}
 		if(yxml_isChar(ch)) {
 			x->state = YXMLS_pi2;
-			return YXML_OK;
+			return yxml_setdata(x, ch);
+		}
+		break;
+	case YXMLS_pi4:
+		if(ch == (unsigned char)'>') {
+			x->state = x->nextstate;
+			return yxml_pivalend(x, ch);
 		}
 		break;
 	case YXMLS_std0:
diff --git a/yxml.c.in b/yxml.c.in
index 5ee9cbf..619240c 100644
--- a/yxml.c.in
+++ b/yxml.c.in
@@ -94,19 +94,10 @@
 }
 
 
-static inline int yxml_elemstart(yxml_t *x, unsigned ch) {
-	return yxml_pushstack(x, &x->elem, ch);
-}
-
-
-static inline int yxml_elemname(yxml_t *x, unsigned ch) {
-	return yxml_pushstackc(x, ch);
-}
-
-
-static inline int yxml_elemnameend(yxml_t *x, unsigned ch) {
-	return YXML_ELEMSTART;
-}
+static inline int yxml_elemstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->elem, ch); }
+static inline int yxml_elemname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_elemnameend(yxml_t *x, unsigned ch) { return YXML_ELEMSTART; }
+static inline int yxml_content    (yxml_t *x, unsigned ch) { return YXML_CONTENT; }
 
 
 /* Also used in yxml_elemcloseend(), since this function just removes the last
@@ -140,30 +131,18 @@
 }
 
 
-static inline int yxml_attrstart(yxml_t *x, unsigned ch) {
-	return yxml_pushstack(x, &x->attr, ch);
+static inline int yxml_attrstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->attr, ch); }
+static inline int yxml_attrname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_attrnameend(yxml_t *x, unsigned ch) { return YXML_ATTRSTART; }
+static inline int yxml_attrvalend (yxml_t *x, unsigned ch) { yxml_popstack(x); return YXML_ATTREND; }
+
+
+static inline int yxml_pistart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->pi, ch); }
+static inline int yxml_piname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
+static inline int yxml_pinameend(yxml_t *x, unsigned ch) {
+	return (x->pi[0]|32) == 'x' && (x->pi[1]|32) == 'm' && (x->pi[2]|32) == 'l' && !x->pi[3] ? YXML_ESYN : YXML_PISTART;
 }
-
-
-static inline int yxml_attrname(yxml_t *x, unsigned ch) {
-	return yxml_pushstackc(x, ch);
-}
-
-
-static inline int yxml_attrnameend(yxml_t *x, unsigned ch) {
-	return YXML_ATTRSTART;
-}
-
-
-static inline int yxml_attrvalend(yxml_t *x, unsigned ch) {
-	yxml_popstack(x);
-	return YXML_ATTREND;
-}
-
-
-static inline int yxml_content(yxml_t *x, unsigned ch) {
-	return YXML_CONTENT;
-}
+static inline int yxml_pivalend (yxml_t *x, unsigned ch) { yxml_popstack(x); x->pi = (char *)x->stack; return YXML_PIEND; }
 
 
 static inline int yxml_refstart(yxml_t *x, unsigned ch) {
@@ -223,7 +202,7 @@
 	x->stack = (unsigned char *)stack;
 	x->stacksize = stacksize;
 	*x->stack = 0;
-	x->elem = (char *)x->stack;
+	x->elem = x->pi = (char *)x->stack;
 	x->state = YXMLS_init;
 }
 
diff --git a/yxml.h b/yxml.h
index 611659a..b8c7190 100644
--- a/yxml.h
+++ b/yxml.h
@@ -36,9 +36,11 @@
 	YXML_CONTENT     =  2, /* Start of element content '.. />' or '.. >' */
 	YXML_ELEMSTCONT  =  3, /* Same as YXML_ELEMSTART|YXML_CONTENT  */
 	YXML_ELEMEND     =  4, /* End of an element:     '.. />' or '</Tag>' */
-	YXML_ATTRSTART   =  5, /* Attribute:             'Name=..'           */
-	YXML_ATTREND     =  6, /* End of attribute       '.."'               */
-	YXML_DATA        =  7  /* Attribute value or element contents        */
+	YXML_DATA        =  5, /* Attribute value or element/PI contents     */
+	YXML_ATTRSTART   =  6, /* Attribute:             'Name=..'           */
+	YXML_ATTREND     =  7, /* End of attribute       '.."'               */
+	YXML_PISTART     =  8, /* Start of a processing instruction          */
+	YXML_PIEND       =  9  /* End of a processing instruction            */
 } yxml_ret_t;
 
 /* When, exactly, are tokens returned?
@@ -72,14 +74,23 @@
 	 * including the YXML_ELEMCLOSE for the corresponding element. */
 	char *elem;
 
-	/* The last read character of an attribute value or element data. Changed
-	 * after YXML_DATA and only valid until the next yxml_parse() call. */
+	/* The last read character of an attribute value, element data, or
+	 * processing instruction. Changed after YXML_DATA and only valid until the
+	 * next yxml_parse() call.
+	 * Note: For processing instructions, the last '?' is considered part of
+	 *   the data, unless the PI was empty (e.g. "<?SomePI?>"), in which case
+	 *   no DATA token is emitted at all. */
 	char data;
 
 	/* Name of the current attribute. Changed after YXML_ATTRSTART, valid up to
 	 * and including the next YXML_ATTREND. */
 	char *attr;
 
+	/* Name/target of the current processing instruction, zero-length if not in
+	 * a PI. Changed after YXML_PISTART, valid up to (but excluding)
+	 * the next YXML_PIEND. */
+	char *pi;
+
 	/* Line number, byte offset within that line, and total bytes read. These
 	 * values refer to the position _after_ the last byte given to
 	 * yxml_parse(). These are useful for debugging and error reporting. */
@@ -90,7 +101,7 @@
 
 	/* PRIVATE */
 	int state;
-	unsigned char *stack; /* Stack of element names + attribute name, separated by \0. Also starts with a \0. */
+	unsigned char *stack; /* Stack of element names + attribute/PI name, separated by \0. Also starts with a \0. */
 	size_t stacksize, stacklen;
 	unsigned char ref[8];
 	unsigned reflen;