+#define R_NOMEM return adns_s_nolocalmem
+#define CSP_ADDSTR(s) if (!adns__vbuf_appendstr(vb,(s))) R_NOMEM; else;
+
+/*
+ * order of sections:
+ *
+ * _textdata, _qstring (csp)
+ * _str (mf,cs)
+ * _intstr (mf,cs)
+ * _manyistr (mf,cs)
+ * _txt (pa)
+ * _inaddr (pa,dip,di)
+ * _addr (pa,di,csp,cs)
+ * _domain (pap)
+ * _host_raw (pa)
+ * _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs)
+ * _mx_raw (pa,di)
+ * _mx (pa,di)
+ * _inthostaddr (mf,cs)
+ * _flat (mf)
+ *
+ * within each section:
+ * pap_*
+ * pa_*
+ * dip_*
+ * di_*
+ * mfp_*
+ * mf_*
+ * csp_*
+ * cs_*
+ */
+
+/*
+ * _textdata, _qstring (csp)
+ */
+
+static adns_status csp_textdata(vbuf *vb, const char *dp, int len) {
+ unsigned char ch;
+ char buf[10];
+ int cn;
+
+ CSP_ADDSTR("\"");
+ for (cn=0; cn<len; cn++) {
+ ch= *dp++;
+ if (ch >= 32 && ch <= 126 && ch != '"' && ch != '\\') {
+ if (!adns__vbuf_append(vb,&ch,1)) R_NOMEM;
+ } else {
+ sprintf(buf,"\\%02x",ch);
+ CSP_ADDSTR(buf);
+ }
+ }
+ CSP_ADDSTR("\"");
+
+ return adns_s_ok;
+}
+
+static adns_status csp_qstring(vbuf *vb, const char *dp) {
+ return csp_textdata(vb, dp, strlen(dp));
+}
+
+/*
+ * _str (mf,cs)
+ */
+
+static void mf_str(adns_query qu, void *datap) {
+ char **rrp= datap;
+
+ adns__makefinal_str(qu,rrp);
+}
+
+static adns_status cs_str(vbuf *vb, const void *datap) {
+ const char *const *rrp= datap;
+
+ return csp_qstring(vb,*rrp);
+}
+
+/*
+ * _intstr (mf,cs)
+ */
+
+static void mf_intstr(adns_query qu, void *datap) {
+ adns_rr_intstr *rrp= datap;
+
+ adns__makefinal_str(qu,&rrp->str);
+}
+
+static adns_status cs_intstr(vbuf *vb, const void *datap) {
+ const adns_rr_intstr *rrp= datap;
+ char buf[10];
+
+ sprintf(buf,"%u ",rrp->i);
+ CSP_ADDSTR(buf);
+ return csp_qstring(vb,rrp->str);
+}
+
+/*
+ * _manyistr (mf,cs)
+ */
+
+static void mf_manyistr(adns_query qu, void *datap) {
+ adns_rr_intstr **rrp= datap;
+ adns_rr_intstr *te, *table;
+ void *tablev;
+ int tc;
+
+ for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
+ tablev= *rrp;
+ adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
+ *rrp= table= tablev;
+ for (te= *rrp; te->i >= 0; te++)
+ adns__makefinal_str(qu,&te->str);
+}
+
+static adns_status cs_manyistr(vbuf *vb, const void *datap) {
+ const adns_rr_intstr *const *rrp= datap;
+ const adns_rr_intstr *current;
+ adns_status st;
+ int spc;
+
+ for (spc=0, current= *rrp; current->i >= 0; current++) {
+ if (spc) CSP_ADDSTR(" ");
+ st= csp_textdata(vb,current->str,current->i); if (st) return st;
+ }
+ return adns_s_ok;
+}
+
+/*
+ * _txt (pa)
+ */
+
+static adns_status pa_txt(const parseinfo *pai, int cbyte, int max, void *datap) {
+ adns_rr_intstr **rrp= datap, *table, *te;
+ const byte *dgram= pai->dgram;
+ int ti, tc, l, startbyte;
+
+ startbyte= cbyte;
+ if (cbyte >= max) return adns_s_invaliddata;
+ tc= 0;
+ while (cbyte < max) {
+ GET_B(cbyte,l);
+ cbyte+= l;
+ }
+ if (cbyte != max) return adns_s_invaliddata;
+
+ table= adns__alloc_interim(pai->qu,sizeof(*table)*(tc+1));
+ if (!table) R_NOMEM;
+
+ for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
+ GET_B(cbyte,l);
+ te->str= adns__alloc_interim(pai->qu, l+1);
+ if (!te->str) R_NOMEM;
+ te->str[l]= 0;
+ memcpy(te->str,dgram+cbyte,l);
+ te->i= l;
+ }
+ assert(cbyte == max);
+
+ te->i= -1;
+ te->str= 0;