This patch removes the string length limit in convert_aaregex_to_pcre()
usage. One of the benefits to moving to C++ is the ability to use
std::strings, which dynamically resize themselves. While it's a large
patch, a non-trivial amount is due to needing to get a char * string
back out via the c_str() method.

The unit tests are modified to include checks to ensure that
convert_aaregex_to_pcre only appends to the passed pcre string,
it never resets it.

As the test case with overlong alternations added in the previous
patch now passes, the TODO status is removed from it.

(Note: there's a couple of FIXME comments related to converting typebuf
to std::string that are added by this patch that are addressed in the
next patch. I kept that conversion separate to try to reduce the size
of this patch a little.)

Signed-off-by: Steve Beattie <steve@nxnw.org>
---
 parser/parser_regex.c                             |  363 ++++++++++------------
 parser/tst/simple_tests/file/ok_alternations_3.sd |    1 
 2 files changed, 174 insertions(+), 190 deletions(-)

Index: b/parser/parser_regex.c
===================================================================
--- a/parser/parser_regex.c
+++ b/parser/parser_regex.c
@@ -24,6 +24,8 @@
 #include <apparmor.h>
 #define _(s) gettext(s)
 
+#include <string>
+
 /* #define DEBUG */
 
 #include "parser.h"
@@ -81,17 +83,11 @@ static void filter_slashes(char *path)
 	*dptr = 0;
 }
 
+/* converts the apparmor regex in aare and appends pcre regex output
+ * to pcre string */
 static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
-					 char *pcre, size_t pcre_size,
-					 int *first_re_pos)
+					 std::string& pcre, int *first_re_pos)
 {
-#define STORE(_src, _dest, _len) \
-	if ((const char*)_dest + _len > (pcre + pcre_size)){ \
-		error = e_buffer_overflow; \
-	} else { \
-		memcpy(_dest, _src, _len); \
-		_dest += _len; \
-	}
 #define update_re_pos(X) if (!(*first_re_pos)) { *first_re_pos = (X); }
 #define MAX_ALT_DEPTH 50
 	*first_re_pos = 0;
@@ -101,7 +97,6 @@ static pattern_t convert_aaregex_to_pcre
 	enum error_type error;
 
 	const char *sptr;
-	char *dptr;
 	pattern_t ptype;
 
 	BOOL bEscape = 0;	/* flag to indicate escape */
@@ -113,14 +108,13 @@ static pattern_t convert_aaregex_to_pcre
 	ptype = ePatternBasic;	/* assume no regex */
 
 	sptr = aare;
-	dptr = pcre;
 
 	if (dfaflags & DFA_DUMP_RULE_EXPR)
 		fprintf(stderr, "aare: %s   ->   ", aare);
 
 	if (anchor)
 		/* anchor beginning of regular expression */
-		*dptr++ = '^';
+		pcre.append("^");
 
 	while (error == e_no_error && *sptr) {
 		switch (*sptr) {
@@ -135,7 +129,7 @@ static pattern_t convert_aaregex_to_pcre
 			 * this is done by stripping later
 			 */
 			if (bEscape) {
-				STORE("\\\\", dptr, 2);
+				pcre.append("\\\\");
 			} else {
 				bEscape = TRUE;
 				++sptr;
@@ -149,9 +143,9 @@ static pattern_t convert_aaregex_to_pcre
 				 * end up using this regex buffer (i.e another
 				 * non-escaped regex follows)
 				 */
-				STORE("\\*", dptr, 2);
+				pcre.append("\\*");
 			} else {
-				if ((dptr > pcre) &&  *(dptr - 1) == '/') {
+				if ((pcre.length() > 0) && pcre[pcre.length() - 1]  == '/') {
 					#if 0
 					// handle comment containing use
 					// of C comment characters
@@ -177,7 +171,7 @@ static pattern_t convert_aaregex_to_pcre
 					while (*s == '*')
 						s++;
 					if (*s == '/' || !*s) {
-						STORE("[^/\\x00]", dptr, 8);
+						pcre.append("[^/\\x00]");
 					}
 				}
 				if (*(sptr + 1) == '*') {
@@ -195,12 +189,12 @@ static pattern_t convert_aaregex_to_pcre
 						ptype = ePatternRegex;
 					}
 
-					STORE("[^\\x00]*", dptr, 8);
+					pcre.append("[^\\x00]*");
 					sptr++;
 				} else {
 					update_re_pos(sptr - aare);
 					ptype = ePatternRegex;
-					STORE("[^/\\x00]*", dptr, 9);
+					pcre.append("[^/\\x00]*");
 				}	/* *(sptr+1) == '*' */
 			}	/* bEscape */
 
@@ -212,48 +206,48 @@ static pattern_t convert_aaregex_to_pcre
 				 * so no need to escape, just skip
 				 * transform
 				 */
-				STORE(sptr, dptr, 1);
+				pcre.append(1, *sptr);
 			} else {
 				update_re_pos(sptr - aare);
 				ptype = ePatternRegex;
-				STORE("[^/\\x00]", dptr, 8);
+				pcre.append("[^/\\x00]");
 			}
 			break;
 
 		case '[':
 			if (bEscape) {
 				/* [ is a PCRE special character */
-				STORE("\\[", dptr, 2);
+				pcre.append("\\[");
 			} else {
 				update_re_pos(sptr - aare);
 				incharclass = 1;
 				ptype = ePatternRegex;
-				STORE(sptr, dptr, 1);
+				pcre.append(1, *sptr);
 			}
 			break;
 
 		case ']':
 			if (bEscape) {
 				/* ] is a PCRE special character */
-				STORE("\\]", dptr, 2);
+				pcre.append("\\]");
 			} else {
 				if (incharclass == 0) {
 					error = e_parse_error;
 					PERROR(_("%s: Regex grouping error: Invalid close ], no matching open [ detected\n"), progname);
 				}
 				incharclass = 0;
-				STORE(sptr, dptr, 1);
+				pcre.append(1, *sptr);
 			}
 			break;
 
 		case '{':
 			if (bEscape) {
 				/* { is a PCRE special character */
-				STORE("\\{", dptr, 2);
+				pcre.append("\\{");
 			} else {
 				if (incharclass) {
 					/* don't expand inside [] */
-					STORE("{", dptr, 1);
+					pcre.append("{");
 				} else {
 					update_re_pos(sptr - aare);
 					ingrouping++;
@@ -264,7 +258,7 @@ static pattern_t convert_aaregex_to_pcre
 					} else {
 						grouping_count[ingrouping] = 0;
 						ptype = ePatternRegex;
-						STORE("(", dptr, 1);
+						pcre.append("(");
 					}
 				}	/* incharclass */
 			}
@@ -273,11 +267,11 @@ static pattern_t convert_aaregex_to_pcre
 		case '}':
 			if (bEscape) {
 				/* { is a PCRE special character */
-				STORE("\\}", dptr, 2);
+				pcre.append("\\}");
 			} else {
 				if (incharclass) {
 					/* don't expand inside [] */
-					STORE("}", dptr, 1);
+					pcre.append("}");
 				} else {
 					if (grouping_count[ingrouping] == 0) {
 						error = e_parse_error;
@@ -290,7 +284,7 @@ static pattern_t convert_aaregex_to_pcre
 						PERROR(_("%s: Regex grouping error: Invalid close }, no matching open { detected\n"), progname);
 						ingrouping = 0;
 					}
-					STORE(")", dptr, 1);
+					pcre.append(")");
 				}	/* incharclass */
 			}	/* bEscape */
 
@@ -302,20 +296,20 @@ static pattern_t convert_aaregex_to_pcre
 					/* escape inside char class is a
 					 * valid matching char for '\'
 					 */
-					STORE("\\,", dptr, 2);
+					pcre.append("\\,");
 				} else {
 					/* ',' is not a PCRE regex character
 					 * so no need to escape, just skip
 					 * transform
 					 */
-					STORE(sptr, dptr, 1);
+					pcre.append(1, *sptr);
 				}
 			} else {
 				if (ingrouping && !incharclass) {
 					grouping_count[ingrouping]++;
-					STORE("|", dptr, 1);
+					pcre.append("|");
 				} else {
-					STORE(sptr, dptr, 1);
+					pcre.append(1, *sptr);
 				}
 			}
 			break;
@@ -325,10 +319,10 @@ static pattern_t convert_aaregex_to_pcre
 		case '^':
 		case '$':
 			if (incharclass) {
-				STORE(sptr, dptr, 1);
+				pcre.append(1, *sptr);
 			} else {
-				STORE("\\", dptr, 1);
-				STORE(sptr, dptr, 1);
+				pcre.append("\\");
+				pcre.append(1, *sptr);
 			}
 			break;
 
@@ -343,7 +337,7 @@ static pattern_t convert_aaregex_to_pcre
 		case '|':
 		case '(':
 		case ')':
-			STORE("\\", dptr, 1);
+			pcre.append("\\");
 			// fall through to default
 
 		default:
@@ -353,7 +347,7 @@ static pattern_t convert_aaregex_to_pcre
 				pwarn("Character %c was quoted unnecessarily, "
 				      "dropped preceding quote ('\\') character\n", *sptr);
 			}
-			STORE(sptr, dptr, 1);
+			pcre.append(1, *sptr);
 			break;
 		}	/* switch (*sptr) */
 
@@ -376,10 +370,7 @@ static pattern_t convert_aaregex_to_pcre
 	}
 	/* anchor end and terminate pattern string */
 	if ((error == e_no_error) && anchor) {
-		STORE("$" , dptr, 1);
-	}
-	if (error == e_no_error) {
-		STORE("", dptr, 1);
+		pcre.append("$");
 	}
 	/* check error  again, as above STORE may have set it */
 	if (error != e_no_error) {
@@ -400,7 +391,7 @@ out:
 		ptype = ePatternInvalid;
 
 	if (dfaflags & DFA_DUMP_RULE_EXPR)
-		fprintf(stderr, "%s\n", pcre);
+		fprintf(stderr, "%s\n", pcre.c_str());
 
 	return ptype;
 }
@@ -417,7 +408,7 @@ static const char *local_name(const char
 
 static int process_profile_name_xmatch(Profile *prof)
 {
-	char tbuf[PATH_MAX + 3];	/* +3 for ^, $ and \0 */
+	std::string tbuf;
 	pattern_t ptype;
 	const char *name;
 
@@ -426,7 +417,7 @@ static int process_profile_name_xmatch(P
 		name = prof->attachment;
 	else
 		name = local_name(prof->name);
-	ptype = convert_aaregex_to_pcre(name, 0, tbuf, PATH_MAX + 3,
+	ptype = convert_aaregex_to_pcre(name, 0, tbuf,
 					&prof->xmatch_len);
 	if (ptype == ePatternBasic)
 		prof->xmatch_len = strlen(name);
@@ -444,7 +435,7 @@ static int process_profile_name_xmatch(P
 		aare_ruleset_t *rule = aare_new_ruleset(0);
 		if (!rule)
 			return FALSE;
-		if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
+		if (!aare_add_rule(rule, tbuf.c_str(), 0, AA_MAY_EXEC, 0, dfaflags)) {
 			aare_delete_ruleset(rule);
 			return FALSE;
 		}
@@ -452,15 +443,15 @@ static int process_profile_name_xmatch(P
 			struct alt_name *alt;
 			list_for_each(prof->altnames, alt) {
 				int len;
+				tbuf.clear();
 				ptype = convert_aaregex_to_pcre(alt->name, 0,
 								tbuf,
-								PATH_MAX + 3,
 								&len);
 				if (ptype == ePatternBasic)
 					len = strlen(alt->name);
 				if (len < prof->xmatch_len)
 					prof->xmatch_len = len;
-				if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
+				if (!aare_add_rule(rule, tbuf.c_str(), 0, AA_MAY_EXEC, 0, dfaflags)) {
 					aare_delete_ruleset(rule);
 					return FALSE;
 				}
@@ -478,7 +469,7 @@ static int process_profile_name_xmatch(P
 
 static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
 {
-	char tbuf[PATH_MAX + 3];	/* +3 for ^, $ and \0 */
+	std::string tbuf;
 	pattern_t ptype;
 	int pos;
 
@@ -488,7 +479,7 @@ static int process_dfa_entry(aare_rulese
 
 	if (entry->mode & ~AA_CHANGE_PROFILE)
 		filter_slashes(entry->name);
-	ptype = convert_aaregex_to_pcre(entry->name, 0, tbuf, PATH_MAX+3, &pos);
+	ptype = convert_aaregex_to_pcre(entry->name, 0, tbuf, &pos);
 	if (ptype == ePatternInvalid)
 		return FALSE;
 
@@ -510,30 +501,30 @@ static int process_dfa_entry(aare_rulese
 	 * entry of the pair
 	 */
 	if (entry->deny && (entry->mode & AA_LINK_BITS)) {
-		if (!aare_add_rule(dfarules, tbuf, entry->deny,
+		if (!aare_add_rule(dfarules, tbuf.c_str(), entry->deny,
 				   entry->mode & ~AA_LINK_BITS,
 				   entry->audit & ~AA_LINK_BITS, dfaflags))
 			return FALSE;
 	} else if (entry->mode & ~AA_CHANGE_PROFILE) {
-		if (!aare_add_rule(dfarules, tbuf, entry->deny, entry->mode,
+		if (!aare_add_rule(dfarules, tbuf.c_str(), entry->deny, entry->mode,
 				   entry->audit, dfaflags))
 			return FALSE;
 	}
 
 	if (entry->mode & (AA_LINK_BITS)) {
 		/* add the pair rule */
-		char lbuf[PATH_MAX + 8];
+		std::string lbuf;
 		int perms = AA_LINK_BITS & entry->mode;
 		const char *vec[2];
 		int pos;
-		vec[0] = tbuf;
+		vec[0] = tbuf.c_str();
 		if (entry->link_name) {
-			ptype = convert_aaregex_to_pcre(entry->link_name, 0, lbuf, PATH_MAX + 8, &pos);
+			ptype = convert_aaregex_to_pcre(entry->link_name, 0, lbuf, &pos);
 			if (ptype == ePatternInvalid)
 				return FALSE;
 			if (entry->subset)
 				perms |= LINK_TO_LINK_SUBSET(perms);
-			vec[1] = lbuf;
+			vec[1] = lbuf.c_str();
 		} else {
 			perms |= LINK_TO_LINK_SUBSET(perms);
 			vec[1] = "/[^/].*";
@@ -543,7 +534,7 @@ static int process_dfa_entry(aare_rulese
 	}
 	if (entry->mode & AA_CHANGE_PROFILE) {
 		const char *vec[3];
-		char lbuf[PATH_MAX + 8];
+		std::string lbuf;
 		int index = 1;
 
 		/* allow change_profile for all execs */
@@ -551,10 +542,10 @@ static int process_dfa_entry(aare_rulese
 
 		if (entry->ns) {
 			int pos;
-			ptype = convert_aaregex_to_pcre(entry->ns, 0, lbuf, PATH_MAX + 8, &pos);
-			vec[index++] = lbuf;
+			ptype = convert_aaregex_to_pcre(entry->ns, 0, lbuf, &pos);
+			vec[index++] = lbuf.c_str();
 		}
-		vec[index++] = tbuf;
+		vec[index++] = tbuf.c_str();
 
 		/* regular change_profile rule */
 		if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags))
@@ -639,7 +630,7 @@ out:
 static int build_list_val_expr(char *buffer, int size, struct value_list *list)
 {
 	struct value_list *ent;
-	char tmp[PATH_MAX + 3];
+	std::string tmp;
 	char *p;
 	int len;
 	pattern_t ptype;
@@ -656,28 +647,28 @@ static int build_list_val_expr(char *buf
 	if (p > buffer + size)
 		goto fail;
 
-	ptype = convert_aaregex_to_pcre(list->value, 0, tmp, PATH_MAX+3, &pos);
+	ptype = convert_aaregex_to_pcre(list->value, 0, tmp, &pos);
 	if (ptype == ePatternInvalid)
 		goto fail;
 
-	len = strlen(tmp);
+	len = tmp.length();
 	if (len > size - (p - buffer))
 		goto fail;
-	strcpy(p, tmp);
+	strcpy(p, tmp.c_str());
 	p += len;
 
 	list_for_each(list->next, ent) {
-		ptype = convert_aaregex_to_pcre(ent->value, 0, tmp,
-						PATH_MAX+3, &pos);
+		tmp.clear();
+		ptype = convert_aaregex_to_pcre(ent->value, 0, tmp, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
 
 		strncpy(p, "|", size - (p - buffer));
 		p++;
-		len = strlen(tmp);
+		len = tmp.length();
 		if (len > size - (p - buffer))
 			goto fail;
-		strcpy(p, tmp);
+		strcpy(p, tmp.c_str());
 		p += len;
 	}
 	strncpy(p, ")", size - (p - buffer));
@@ -690,22 +681,19 @@ fail:
 	return FALSE;
 }
 
-static int convert_entry(char *buffer, int size, char *entry)
+static int convert_entry(std::string& buffer, char *entry)
 {
 	pattern_t ptype;
 	int pos;
 
 	if (entry) {
-		ptype = convert_aaregex_to_pcre(entry, 0, buffer, size, &pos);
+		ptype = convert_aaregex_to_pcre(entry, 0, buffer, &pos);
 		if (ptype == ePatternInvalid)
 			return FALSE;
 	} else {
-		/* match any char except \000 0 or more times */
-		if (size < 8)
-			return FALSE;
-
-		strcpy(buffer, "[^\\000]*");
+		buffer.append("[^\\000]*");
 	}
+
 	return TRUE;
 }
 
@@ -750,38 +738,24 @@ static int build_mnt_flags(char *buffer,
 	return TRUE;
 }
 
-static int build_mnt_opts(char *buffer, int size, struct value_list *opts)
+static int build_mnt_opts(std::string& buffer, struct value_list *opts)
 {
 	struct value_list *ent;
-	char tmp[PATH_MAX + 3];
-	char *p;
-	int len;
 	pattern_t ptype;
 	int pos;
 
 	if (!opts) {
-		if (size < 8)
-			return FALSE;
-		strncpy(buffer, "[^\\000]*", size);
+		buffer.append("[^\\000]*");
 		return TRUE;
 	}
 
-	p = buffer;
 	list_for_each(opts, ent) {
-		ptype = convert_aaregex_to_pcre(ent->value, 0, tmp,
-						PATH_MAX+3, &pos);
+		ptype = convert_aaregex_to_pcre(ent->value, 0, buffer, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
 
-		len = strlen(tmp);
-		if (len > size - (p - buffer))
-			goto fail;
-		strcpy(p, tmp);
-		p += len;
-		if (ent->next && size - (p - buffer) > 1) {
-			*p++ = ',';
-			*p = 0;
-		}
+		if (ent->next)
+			buffer.append(",");
 	}
 
 	return TRUE;
@@ -792,16 +766,18 @@ fail:
 
 static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
 {
-	char mntbuf[PATH_MAX + 3];
-	char devbuf[PATH_MAX + 3];
+	std::string mntbuf;
+	std::string devbuf;
 	char typebuf[PATH_MAX + 3];
 	char flagsbuf[PATH_MAX + 3];
-	char optsbuf[PATH_MAX + 3];
-	char *p;
+	std::string optsbuf;
+	char class_mount_hdr[64];
 	const char *vec[5];
 	int count = 0;
 	unsigned int flags, inv_flags;
 
+	sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
+
 	/* a single mount rule may result in multiple matching rules being
 	 * created in the backend to cover all the possible choices
 	 */
@@ -810,25 +786,25 @@ static int process_mnt_entry(aare_rulese
 	    && !entry->device && !entry->dev_type) {
 		int allow;
 		/* remount can't be conditional on device and type */
-		p = mntbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
+		mntbuf.assign(class_mount_hdr);
 		if (entry->mnt_point) {
 			/* both device && mnt_point or just mnt_point */
-			if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+			if (!convert_entry(mntbuf, entry->mnt_point))
 				goto fail;
-			vec[0] = mntbuf;
+			vec[0] = mntbuf.c_str();
 		} else {
-			if (!convert_entry(p, PATH_MAX +3, entry->device))
+			if (!convert_entry(mntbuf, entry->device))
 				goto fail;
-			vec[0] = mntbuf;
+			vec[0] = mntbuf.c_str();
 		}
 		/* skip device */
-		if (!convert_entry(devbuf, PATH_MAX +3, NULL))
+		devbuf.clear();
+		if (!convert_entry(devbuf, NULL))
 			goto fail;
-		vec[1] = devbuf;
+		vec[1] = devbuf.c_str();
 		/* skip type */
-		vec[2] = devbuf;
+		vec[2] = devbuf.c_str();
 
 		flags = entry->flags;
 		inv_flags = entry->inv_flags;
@@ -839,8 +815,6 @@ static int process_mnt_entry(aare_rulese
 		if (!build_mnt_flags(flagsbuf, PATH_MAX, flags, inv_flags))
 			goto fail;
 		vec[3] = flagsbuf;
-		if (!build_mnt_opts(optsbuf, PATH_MAX, entry->opts))
-			goto fail;
 
 		if (entry->opts)
 			allow = AA_MATCH_CONT;
@@ -856,9 +830,10 @@ static int process_mnt_entry(aare_rulese
 
 		if (entry->opts) {
 			/* rule with data match required */
-			if (!build_mnt_opts(optsbuf, PATH_MAX, entry->opts))
+			optsbuf.clear();
+			if (!build_mnt_opts(optsbuf, entry->opts))
 				goto fail;
-			vec[4] = optsbuf;
+			vec[4] = optsbuf.c_str();
 			if (!aare_add_rule_vec(dfarules, entry->deny,
 					       entry->allow,
 					       entry->audit | AA_AUDIT_MNT_DATA,
@@ -870,18 +845,21 @@ static int process_mnt_entry(aare_rulese
 	if ((entry->allow & AA_MAY_MOUNT) && (entry->flags & MS_BIND)
 	    && !entry->dev_type && !entry->opts) {
 		/* bind mount rules can't be conditional on dev_type or data */
-		p = mntbuf;
+		std::string tmpbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
-			goto fail;
-		vec[0] = mntbuf;
-		if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[1] = devbuf;
-		if (!convert_entry(typebuf, PATH_MAX +3, NULL))
+		vec[0] = mntbuf.c_str();
+		devbuf.clear();
+		if (!convert_entry(devbuf, entry->device))
+			goto fail;
+		vec[1] = devbuf.c_str();
+		/* FIXME: when typebuf gets converted to std::string,
+		 * switch tmpbuf back to typebuf */
+		if (!convert_entry(tmpbuf, NULL))
 			goto fail;
-		vec[2] = typebuf;
+		vec[2] = tmpbuf.c_str();
 
 		flags = entry->flags;
 		inv_flags = entry->inv_flags;
@@ -903,17 +881,17 @@ static int process_mnt_entry(aare_rulese
 		/* change type base rules can not be conditional on device,
 		 * device type or data
 		 */
-		p = mntbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[0] = mntbuf;
+		vec[0] = mntbuf.c_str();
 		/* skip device and type */
-		if (!convert_entry(devbuf, PATH_MAX +3, NULL))
+		devbuf.clear();
+		if (!convert_entry(devbuf, NULL))
 			goto fail;
-		vec[1] = devbuf;
-		vec[2] = devbuf;
+		vec[1] = devbuf.c_str();
+		vec[2] = devbuf.c_str();
 
 		flags = entry->flags;
 		inv_flags = entry->inv_flags;
@@ -934,19 +912,22 @@ static int process_mnt_entry(aare_rulese
 		/* mount move rules can not be conditional on dev_type,
 		 * or data
 		 */
-		p = mntbuf;
+		std::string tmpbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[0] = mntbuf;
-		if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
+		vec[0] = mntbuf.c_str();
+		devbuf.clear();
+		if (!convert_entry(devbuf, entry->device))
 			goto fail;
-		vec[1] = devbuf;
+		vec[1] = devbuf.c_str();
 		/* skip type */
-		if (!convert_entry(typebuf, PATH_MAX +3, NULL))
+		/* FIXME: when typebuf gets converted to std::string,
+		 * switch tmpbuf back to typebuf */
+		if (!convert_entry(tmpbuf, NULL))
 			goto fail;
-		vec[2] = typebuf;
+		vec[2] = tmpbuf.c_str();
 
 		flags = entry->flags;
 		inv_flags = entry->inv_flags;
@@ -968,15 +949,15 @@ static int process_mnt_entry(aare_rulese
 		/* generic mount if flags are set that are not covered by
 		 * above commands
 		 */
-		p = mntbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[0] = mntbuf;
-		if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
+		vec[0] = mntbuf.c_str();
+		devbuf.clear();
+		if (!convert_entry(devbuf, entry->device))
 			goto fail;
-		vec[1] = devbuf;
+		vec[1] = devbuf.c_str();
 		if (!build_list_val_expr(typebuf, PATH_MAX+2, entry->dev_type))
 			goto fail;
 		vec[2] = typebuf;
@@ -1005,9 +986,10 @@ static int process_mnt_entry(aare_rulese
 
 		if (entry->opts) {
 			/* rule with data match required */
-			if (!build_mnt_opts(optsbuf, PATH_MAX, entry->opts))
+			optsbuf.clear();
+			if (!build_mnt_opts(optsbuf, entry->opts))
 				goto fail;
-			vec[4] = optsbuf;
+			vec[4] = optsbuf.c_str();
 			if (!aare_add_rule_vec(dfarules, entry->deny,
 					       entry->allow,
 					       entry->audit | AA_AUDIT_MNT_DATA,
@@ -1017,27 +999,26 @@ static int process_mnt_entry(aare_rulese
 		}
 	}
 	if (entry->allow & AA_MAY_UMOUNT) {
-		p = mntbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[0] = mntbuf;
+		vec[0] = mntbuf.c_str();
 		if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
 				       entry->audit, 1, vec, dfaflags))
 			goto fail;
 		count++;
 	}
 	if (entry->allow & AA_MAY_PIVOTROOT) {
-		p = mntbuf;
 		/* rule class single byte header */
-		p += sprintf(p, "\\x%02x", AA_CLASS_MOUNT);
-		if (!convert_entry(p, PATH_MAX +3, entry->mnt_point))
+		mntbuf.assign(class_mount_hdr);
+		if (!convert_entry(mntbuf, entry->mnt_point))
 			goto fail;
-		vec[0] = mntbuf;
-		if (!convert_entry(devbuf, PATH_MAX +3, entry->device))
+		vec[0] = mntbuf.c_str();
+		devbuf.clear();
+		if (!convert_entry(devbuf, entry->device))
 			goto fail;
-		vec[1] = devbuf;
+		vec[1] = devbuf.c_str();
 		if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
 				       entry->audit, 2, vec, dfaflags))
 			goto fail;
@@ -1058,13 +1039,13 @@ fail:
 
 static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry)
 {
-	char busbuf[PATH_MAX + 3];
-	char namebuf[PATH_MAX + 3];
-	char peer_labelbuf[PATH_MAX + 3];
-	char pathbuf[PATH_MAX + 3];
-	char ifacebuf[PATH_MAX + 3];
-	char memberbuf[PATH_MAX + 3];
-	char *p;
+	std::string busbuf;
+	std::string namebuf;
+	std::string peer_labelbuf;
+	std::string pathbuf;
+	std::string ifacebuf;
+	std::string memberbuf;
+	char buffer[128];
 	const char *vec[6];
 
 	pattern_t ptype;
@@ -1073,26 +1054,24 @@ static int process_dbus_entry(aare_rules
 	if (!entry) 		/* shouldn't happen */
 		return TRUE;
 
-	p = busbuf;
-	p += sprintf(p, "\\x%02x", AA_CLASS_DBUS);
+	sprintf(buffer, "\\x%02x", AA_CLASS_DBUS);
+	busbuf.append(buffer);
 
 	if (entry->bus) {
-		ptype = convert_aaregex_to_pcre(entry->bus, 0, p,
-						PATH_MAX+3 - (p - busbuf), &pos);
+		ptype = convert_aaregex_to_pcre(entry->bus, 0, busbuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
 	} else {
 		/* match any char except \000 0 or more times */
-		strcpy(p, "[^\\000]*");
+		busbuf.append("[^\\000]*");
 	}
-	vec[0] = busbuf;
+	vec[0] = busbuf.c_str();
 
 	if (entry->name) {
-		ptype = convert_aaregex_to_pcre(entry->name, 0, namebuf,
-						PATH_MAX+3, &pos);
+		ptype = convert_aaregex_to_pcre(entry->name, 0, namebuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
-		vec[1] = namebuf;
+		vec[1] = namebuf.c_str();
 	} else {
 		/* match any char except \000 0 or more times */
 		vec[1] = "[^\\000]*";
@@ -1100,44 +1079,40 @@ static int process_dbus_entry(aare_rules
 
 	if (entry->peer_label) {
 		ptype = convert_aaregex_to_pcre(entry->peer_label, 0,
-						peer_labelbuf, PATH_MAX+3,
-						&pos);
+						peer_labelbuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
-		vec[2] = peer_labelbuf;
+		vec[2] = peer_labelbuf.c_str();
 	} else {
 		/* match any char except \000 0 or more times */
 		vec[2] = "[^\\000]*";
 	}
 
 	if (entry->path) {
-		ptype = convert_aaregex_to_pcre(entry->path, 0, pathbuf,
-						PATH_MAX+3, &pos);
+		ptype = convert_aaregex_to_pcre(entry->path, 0, pathbuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
-		vec[3] = pathbuf;
+		vec[3] = pathbuf.c_str();
 	} else {
 		/* match any char except \000 0 or more times */
 		vec[3] = "[^\\000]*";
 	}
 
 	if (entry->interface) {
-		ptype = convert_aaregex_to_pcre(entry->interface, 0, ifacebuf,
-						PATH_MAX+3, &pos);
+		ptype = convert_aaregex_to_pcre(entry->interface, 0, ifacebuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
-		vec[4] = ifacebuf;
+		vec[4] = ifacebuf.c_str();
 	} else {
 		/* match any char except \000 0 or more times */
 		vec[4] = "[^\\000]*";
 	}
 
 	if (entry->member) {
-		ptype = convert_aaregex_to_pcre(entry->member, 0, memberbuf,
-						PATH_MAX+3, &pos);
+		ptype = convert_aaregex_to_pcre(entry->member, 0, memberbuf, &pos);
 		if (ptype == ePatternInvalid)
 			goto fail;
-		vec[5] = memberbuf;
+		vec[5] = memberbuf.c_str();
 	} else {
 		/* match any char except \000 0 or more times */
 		vec[5] = "[^\\000]*";
@@ -1305,31 +1280,41 @@ static int test_filter_slashes(void)
 
 #define MY_REGEX_TEST(input, expected_str, expected_type)						\
 	do {												\
-		char tbuf[PATH_MAX + 3];								\
+		std::string tbuf;									\
+		std::string tbuf2 = "testprefix";							\
 		char *test_string;									\
-		char* output_string = NULL;							\
+		char *output_string = NULL;								\
+		std::string expected_str2;								\
 		pattern_t ptype;									\
 		int pos;										\
 													\
 		test_string = strdup((input)); 								\
-		ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, PATH_MAX + 3, &pos);		\
+		ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, &pos);				\
 		asprintf(&output_string, "simple regex conversion for '%s'\texpected = '%s'\tresult = '%s'", \
-				(input), expected_str, tbuf);						\
-		MY_TEST(strcmp(tbuf, (expected_str)) == 0, output_string);				\
+				(input), expected_str, tbuf.c_str());					\
+		MY_TEST(strcmp(tbuf.c_str(), (expected_str)) == 0, output_string);			\
 		MY_TEST(ptype == (expected_type), "simple regex conversion type check for '" input "'"); \
+		free(output_string);									\
+		/* ensure convert_aaregex_to_pcre appends only to passed ref string */			\
+		expected_str2 = tbuf2;									\
+		expected_str2.append((expected_str));							\
+		ptype = convert_aaregex_to_pcre(test_string, 0, tbuf2, &pos);				\
+		asprintf(&output_string, "simple regex conversion for '%s'\texpected = '%s'\tresult = '%s'", \
+				(input), expected_str2.c_str(), tbuf2.c_str());				\
+		MY_TEST((tbuf2 == expected_str2), output_string);					\
 		free(test_string); free(output_string);							\
 	}												\
 	while (0)
 
 #define MY_REGEX_FAIL_TEST(input)						\
 	do {												\
-		char tbuf[PATH_MAX + 3];								\
+		std::string tbuf;									\
 		char *test_string;									\
 		pattern_t ptype;									\
 		int pos;										\
 													\
 		test_string = strdup((input)); 								\
-		ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, PATH_MAX + 3, &pos);		\
+		ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, &pos);				\
 		MY_TEST(ptype == ePatternInvalid, "simple regex conversion invalid type check for '" input "'"); \
 		free(test_string); 									\
 	}												\
Index: b/parser/tst/simple_tests/file/ok_alternations_3.sd
===================================================================
--- a/parser/tst/simple_tests/file/ok_alternations_3.sd
+++ b/parser/tst/simple_tests/file/ok_alternations_3.sd
@@ -1,7 +1,6 @@
 #
 #=Description basic file rule w/large number of alternations
 #=EXRESULT PASS
-#=TODO
 #
 /usr/bin/foo {
   /{a/a,a/b,a/c,a/d,a/e,a/f,a/g,a/h,a/i,a/j,a/k,a/l,a/m,a/n,a/o,a/p,a/q,a/r,a/s,a/t,a/u,a/v,a/w,a/x,a/y,a/z,a/A,a/B,a/C,a/D,a/E,a/F,a/G,a/H,a/I,a/J,a/K,a/L,a/M,a/N,a/O,a/P,a/Q,a/R,a/S,a/T,a/U,a/V,a/W,a/X,a/Y,a/Z,b/a,b/b,b/c,b/d,b/e,b/f,b/g,b/h,b/i,b/j,b/k,b/l,b/m,b/n,b/o,b/p,b/q,b/r,b/s,b/t,b/u,b/v,b/w,b/x,b/y,b/z,b/A,b/B,b/C,b/D,b/E,b/F,b/G,b/H,b/I,b/J,b/K,b/L,b/M,b/N,b/O,b/P,b/Q,b/R,b/S,b/T,b/U,b/V,b/W,b/X,b/Y,b/Z,c/a,c/b,c/c,c/d,c/e,c/f,c/g,c/h,c/i,c/j,c/k,c/l,c/m,c/n,c/o,c/p,c/q,c/r,c/s,c/t,c/u,c/v,c/w,c/x,c/y,c/z,c/A,c/B,c/C,c/D,c/E,c/F,c/G,c/H,c/I,c/J,c/K,c/L,c/M,c/N,c/O,c/P,c/Q,c/R,c/S,c/T,c/U,c/V,c/W,c/X,c/Y,c/Z,d/a,d/b,d/c,d/d,d/e,d/f,d/g,d/h,d/i,d/j,d/k,d/l,d/m,d/n,d/o,d/p,d/q,d/r,d/s,d/t,d/u,d/v,d/w,d/x,d/y,d/z,d/A,d/B,d/C,d/D,d/E,d/F,d/G,d/H,d/I,d/J,d/K,d/L,d/M,d/N,d/O,d/P,d/Q,d/R,d/S,d/T,d/U,d/V,d/W,d/X,d/Y,d/Z,e/a,e/b,e/c,e/d,e/e,e/f,e/g,e/h,e/i,e/j,e/k,e/l,e/m,e/n,e/o,e/p,e/q,e/r,e/s,e/t,e/u,e/v,e/w,e/x,e/y,e/z,e/A,e/B,e/C,e/D,e/E,e/F,e/G,e/H,e/I,e/J,e/K,e/L,e
 /M,e/N,e
 /O,e/P,e/Q,e/R,e/S,e/T,e/U,e/V,e/W,e/X,e/Y,e/Z,f/a,f/b,f/c,f/d,f/e,f/f,f/g,f/h,f/i,f/j,f/k,f/l,f/m,f/n,f/o,f/p,f/q,f/r,f/s,f/t,f/u,f/v,f/w,f/x,f/y,f/z,f/A,f/B,f/C,f/D,f/E,f/F,f/G,f/H,f/I,f/J,f/K,f/L,f/M,f/N,f/O,f/P,f/Q,f/R,f/S,f/T,f/U,f/V,f/W,f/X,f/Y,f/Z,g/a,g/b,g/c,g/d,g/e,g/f,g/g,g/h,g/i,g/j,g/k,g/l,g/m,g/n,g/o,g/p,g/q,g/r,g/s,g/t,g/u,g/v,g/w,g/x,g/y,g/z,g/A,g/B,g/C,g/D,g/E,g/F,g/G,g/H,g/I,g/J,g/K,g/L,g/M,g/N,g/O,g/P,g/Q,g/R,g/S,g/T,g/U,g/V,g/W,g/X,g/Y,g/Z,h/a,h/b,h/c,h/d,h/e,h/f,h/g,h/h,h/i,h/j,h/k,h/l,h/m,h/n,h/o,h/p,h/q,h/r,h/s,h/t,h/u,h/v,h/w,h/x,h/y,h/z,h/A,h/B,h/C,h/D,h/E,h/F,h/G,h/H,h/I,h/J,h/K,h/L,h/M,h/N,h/O,h/P,h/Q,h/R,h/S,h/T,h/U,h/V,h/W,h/X,h/Y,h/Z,i/a,i/b,i/c,i/d,i/e,i/f,i/g,i/h,i/i,i/j,i/k,i/l,i/m,i/n,i/o,i/p,i/q,i/r,i/s,i/t,i/u,i/v,i/w,i/x,i/y,i/z,i/A,i/B,i/C,i/D,i/E,i/F,i/G,i/H,i/I,i/J,i/K,i/L,i/M,i/N,i/O,i/P,i/Q,i/R,i/S,i/T,i/U,i/V,i/W,i/X,i/Y,i/Z,j/a,j/b,j/c,j/d,j/e,j/f,j/g,j/h,j/i,j/j,j/k,j/l,j/m,j/n,j/o,j/p,j/q,j/r,j/s,j/t,j/u,j/v,j/w,j/x,j/y,j/z,j/A,j/
 B,j/C,j/
 D,j/E,j/F,j/G,j/H,j/I,j/J,j/K,j/L,j/M,j/N,j/O,j/P,j/Q,j/R,j/S,j/T,j/U,j/V,j/W,j/X,j/Y,j/Z,k/a,k/b,k/c,k/d,k/e,k/f,k/g,k/h,k/i,k/j,k/k,k/l,k/m,k/n,k/o,k/p,k/q,k/r,k/s,k/t,k/u,k/v,k/w,k/x,k/y,k/z,k/A,k/B,k/C,k/D,k/E,k/F,k/G,k/H,k/I,k/J,k/K,k/L,k/M,k/N,k/O,k/P,k/Q,k/R,k/S,k/T,k/U,k/V,k/W,k/X,k/Y,k/Z,l/a,l/b,l/c,l/d,l/e,l/f,l/g,l/h,l/i,l/j,l/k,l/l,l/m,l/n,l/o,l/p,l/q,l/r,l/s,l/t,l/u,l/v,l/w,l/x,l/y,l/z,l/A,l/B,l/C,l/D,l/E,l/F,l/G,l/H,l/I,l/J,l/K,l/L,l/M,l/N,l/O,l/P,l/Q,l/R,l/S,l/T,l/U,l/V,l/W,l/X,l/Y,l/Z,m/a,m/b,m/c,m/d,m/e,m/f,m/g,m/h,m/i,m/j,m/k,m/l,m/m,m/n,m/o,m/p,m/q,m/r,m/s,m/t,m/u,m/v,m/w,m/x,m/y,m/z,m/A,m/B,m/C,m/D,m/E,m/F,m/G,m/H,m/I,m/J,m/K,m/L,m/M,m/N,m/O,m/P,m/Q,m/R,m/S,m/T,m/U,m/V,m/W,m/X,m/Y,m/Z,n/a,n/b,n/c,n/d,n/e,n/f,n/g,n/h,n/i,n/j,n/k,n/l,n/m,n/n,n/o,n/p,n/q,n/r,n/s,n/t,n/u,n/v,n/w,n/x,n/y,n/z,n/A,n/B,n/C,n/D,n/E,n/F,n/G,n/H,n/I,n/J,n/K,n/L,n/M,n/N,n/O,n/P,n/Q,n/R,n/S,n/T,n/U,n/V,n/W,n/X,n/Y,n/Z,o/a,o/b,o/c,o/d,o/e,o/f,o/g,o/h,o/i,o/j,o/k,o/l,o/m,o/n,o/o,o/p,o/q
 ,o/r,o/s
 ,o/t,o/u,o/v,o/w,o/x,o/y,o/z,o/A,o/B,o/C,o/D,o/E,o/F,o/G,o/H,o/I,o/J,o/K,o/L,o/M,o/N,o/O,o/P,o/Q,o/R,o/S,o/T,o/U,o/V,o/W,o/X,o/Y,o/Z,p/a,p/b,p/c,p/d,p/e,p/f,p/g,p/h,p/i,p/j,p/k,p/l,p/m,p/n,p/o,p/p,p/q,p/r,p/s,p/t,p/u,p/v,p/w,p/x,p/y,p/z,p/A,p/B,p/C,p/D,p/E,p/F,p/G,p/H,p/I,p/J,p/K,p/L,p/M,p/N,p/O,p/P,p/Q,p/R,p/S,p/T,p/U,p/V,p/W,p/X,p/Y,p/Z,q/a,q/b,q/c,q/d,q/e,q/f,q/g,q/h,q/i,q/j,q/k,q/l,q/m,q/n,q/o,q/p,q/q,q/r,q/s,q/t,q/u,q/v,q/w,q/x,q/y,q/z,q/A,q/B,q/C,q/D,q/E,q/F,q/G,q/H,q/I,q/J,q/K,q/L,q/M,q/N,q/O,q/P,q/Q,q/R,q/S,q/T,q/U,q/V,q/W,q/X,q/Y,q/Z,r/a,r/b,r/c,r/d,r/e,r/f,r/g,r/h,r/i,r/j,r/k,r/l,r/m,r/n,r/o,r/p,r/q,r/r,r/s,r/t,r/u,r/v,r/w,r/x,r/y,r/z,r/A,r/B,r/C,r/D,r/E,r/F,r/G,r/H,r/I,r/J,r/K,r/L,r/M,r/N,r/O,r/P,r/Q,r/R,r/S,r/T,r/U,r/V,r/W,r/X,r/Y,r/Z,s/a,s/b,s/c,s/d,s/e,s/f,s/g,s/h,s/i,s/j,s/k,s/l,s/m,s/n,s/o,s/p,s/q,s/r,s/s,s/t,s/u,s/v,s/w,s/x,s/y,s/z,s/A,s/B,s/C,s/D,s/E,s/F,s/G,s/H,s/I,s/J,s/K,s/L,s/M,s/N,s/O,s/P,s/Q,s/R,s/S,s/T,s/U,s/V,s/W,s/X,s/Y,s/Z,t/a,t/b,t/c,t/d,t/e,t/f,
 t/g,t/h,
 t/i,t/j,t/k,t/l,t/m,t/n,t/o,t/p,t/q,t/r,t/s,t/t,t/u,t/v,t/w,t/x,t/y,t/z,t/A,t/B,t/C,t/D,t/E,t/F,t/G,t/H,t/I,t/J,t/K,t/L,t/M,t/N,t/O,t/P,t/Q,t/R,t/S,t/T,t/U,t/V,t/W,t/X,t/Y,t/Z,u/a,u/b,u/c,u/d,u/e,u/f,u/g,u/h,u/i,u/j,u/k,u/l,u/m,u/n,u/o,u/p,u/q,u/r,u/s,u/t,u/u,u/v,u/w,u/x,u/y,u/z,u/A,u/B,u/C,u/D,u/E,u/F,u/G,u/H,u/I,u/J,u/K,u/L,u/M,u/N,u/O,u/P,u/Q,u/R,u/S,u/T,u/U,u/V,u/W,u/X,u/Y,u/Z,v/a,v/b,v/c,v/d,v/e,v/f,v/g,v/h,v/i,v/j,v/k,v/l,v/m,v/n,v/o,v/p,v/q,v/r,v/s,v/t,v/u,v/v,v/w,v/x,v/y,v/z,v/A,v/B,v/C,v/D,v/E,v/F,v/G,v/H,v/I,v/J,v/K,v/L,v/M,v/N,v/O,v/P,v/Q,v/R,v/S,v/T,v/U,v/V,v/W,v/X,v/Y,v/Z,w/a,w/b,w/c,w/d,w/e,w/f,w/g,w/h,w/i,w/j,w/k,w/l,w/m,w/n,w/o,w/p,w/q,w/r,w/s,w/t,w/u,w/v,w/w,w/x,w/y,w/z,w/A,w/B,w/C,w/D,w/E,w/F,w/G,w/H,w/I,w/J,w/K,w/L,w/M,w/N,w/O,w/P,w/Q,w/R,w/S,w/T,w/U,w/V,w/W,w/X,w/Y,w/Z,x/a,x/b,x/c,x/d,x/e,x/f,x/g,x/h,x/i,x/j,x/k,x/l,x/m,x/n,x/o,x/p,x/q,x/r,x/s,x/t,x/u,x/v,x/w,x/x,x/y,x/z,x/A,x/B,x/C,x/D,x/E,x/F,x/G,x/H,x/I,x/J,x/K,x/L,x/M,x/N,x/O,x/P,x/Q,x/R,x/S,x/T,x/U,x
 /V,x/W,x
 /X,x/Y,x/Z,y/a,y/b,y/c,y/d,y/e,y/f,y/g,y/h,y/i,y/j,y/k,y/l,y/m,y/n,y/o,y/p,y/q,y/r,y/s,y/t,y/u,y/v,y/w,y/x,y/y,y/z,y/A,y/B,y/C,y/D,y/E,y/F,y/G,y/H,y/I,y/J,y/K,y/L,y/M,y/N,y/O,y/P,y/Q,y/R,y/S,y/T,y/U,y/V,y/W,y/X,y/Y,y/Z,z/a,z/b,z/c,z/d,z/e,z/f,z/g,z/h,z/i,z/j,z/k,z/l,z/m,z/n,z/o,z/p,z/q,z/r,z/s,z/t,z/u,z/v,z/w,z/x,z/y,z/z} rw,


