diff --git a/examples/dns.c b/examples/dns.c
index e3c8bd977f90151849e20b091fdd76752db21d52..3f4ed9b1178722ba00ace45070cd592e748fd633 100644
--- a/examples/dns.c
+++ b/examples/dns.c
@@ -46,13 +46,6 @@ bool validate_message(HParseResult *p) {
 // Semantic Actions
 ///
 
-uint8_t* get_cs(const HCountedArray *arr) {
-  uint8_t *ret = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->used);
-  for (size_t i=0; i<arr->used; ++i)
-    ret[i] = arr->elements[i]->uint;
-  return ret;
-}
-
 void set_rdata(struct dns_rr rr, HCountedArray *rdata) {
   uint8_t *data = h_arena_malloc(rdata->arena, sizeof(uint8_t)*rdata->used);
   for (size_t i=0; i<rdata->used; ++i)
@@ -120,8 +113,8 @@ void set_rdata(struct dns_rr rr, HCountedArray *rdata) {
     rr.ptr = *(dns_domain_t *)p->ast->user;
     break;
   case 13: // HINFO
-    rr.hinfo.cpu = get_cs(p->ast->seq->elements[0]->seq);
-    rr.hinfo.os = get_cs(p->ast->seq->elements[1]->seq);
+    rr.hinfo.cpu = *H_FIELD(dns_cstr_t, 0);
+    rr.hinfo.os  = *H_FIELD(dns_cstr_t, 1);
     break;
   case 14: // MINFO
     rr.minfo.rmailbx = *H_FIELD(dns_domain_t, 0);
diff --git a/examples/dns.h b/examples/dns.h
index f3e023ca04a7ffc029e1a410c5257e8cd0f83d13..2cff91633d347feff85d4ed549a9801762caaa38 100644
--- a/examples/dns.h
+++ b/examples/dns.h
@@ -13,9 +13,13 @@ enum DNSTokenType_ {
   TT_dns_rr_mx_t,
   TT_dns_rr_soa_t,
   TT_dns_rr_wks_t,
-  TT_dns_domain_t
+  TT_dns_domain_t,
+  TT_dns_cstr_t
 };
 
+typedef char *dns_domain_t;
+typedef uint8_t *dns_cstr_t;
+
 typedef struct dns_header {
   uint16_t id;
   bool qr, aa, tc, rd, ra;
@@ -43,8 +47,8 @@ typedef struct dns_question {
 } dns_question_t;
 
 typedef struct {
-  uint8_t* cpu;
-  uint8_t* os;
+  dns_cstr_t cpu;
+  dns_cstr_t os;
 } dns_rr_hinfo_t;
 
 typedef struct {
@@ -105,8 +109,6 @@ typedef struct dns_rr {
   };
 } dns_rr_t;
 
-typedef char *dns_domain_t;
-
 typedef struct dns_message {
   dns_header_t header;
   dns_question_t *questions;
diff --git a/examples/rr.c b/examples/rr.c
index 3619ca1f4ee7ca2f5ac837d993bc00f42cca8eb2..42b46481e6c8b3b83058071bea463a33da692302 100644
--- a/examples/rr.c
+++ b/examples/rr.c
@@ -15,7 +15,7 @@ bool validate_null(HParseResult *p) {
 const HParsedToken *act_txt(const HParseResult *p) {
   dns_rr_txt_t *txt = H_MAKE(dns_rr_txt_t);
 
-  const HCountedArray *arr = p->ast->seq->elements[0]->seq;
+  const HCountedArray *arr = p->ast->seq;
   uint8_t **ret = h_arena_malloc(arr->arena, sizeof(uint8_t*)*arr->used);
   for (size_t i=0; i<arr->used; ++i) {
     uint8_t *tmp = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->elements[i]->seq->used);
@@ -30,6 +30,19 @@ const HParsedToken *act_txt(const HParseResult *p) {
   return H_MAKE_TOKEN(dns_rr_txt_t, txt);
 }
 
+const HParsedToken* act_cstr(const HParseResult *p) {
+  dns_cstr_t *cs = H_MAKE(dns_cstr_t);
+
+  const HCountedArray *arr = p->ast->seq;
+  uint8_t *ret = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->used);
+  for (size_t i=0; i<arr->used; ++i)
+    ret[i] = arr->elements[i]->uint;
+  assert(ret[arr->used-1] == '\0'); // XXX Is this right?! If so, shouldn't it be a validation?
+  *cs = ret;
+
+  return H_MAKE_TOKEN(dns_cstr_t, cs);
+}
+
 #define RDATA_TYPE_MAX 16
 const HParser* init_rdata(uint16_t type) {
   static const HParser *parsers[RDATA_TYPE_MAX+1];
@@ -43,7 +56,7 @@ const HParser* init_rdata(uint16_t type) {
 
 
   H_RULE (domain, init_domain());
-  H_RULE (cstr,   init_character_string());
+  H_ARULE(cstr,   init_character_string());
 
   H_RULE (a,      h_uint32());
   H_RULE (ns,     domain);