root/usr.sbin/nsd/zparser.y
%{
/*
 * zyparser.y -- yacc grammar for (DNS) zone files
 *
 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
 *
 * See LICENSE for the license.
 *
 */

#include "config.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "dname.h"
#include "namedb.h"
#include "zonec.h"

/* these need to be global, otherwise they cannot be used inside yacc */
zparser_type *parser;

#ifdef __cplusplus
extern "C"
#endif /* __cplusplus */
int yywrap(void);

/* this hold the nxt bits */
static uint8_t nxtbits[16];
static int dlv_warn = 1;

/* 256 windows of 256 bits (32 bytes) */
/* still need to reset the bastard somewhere */
static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];

/* hold the highest rcode seen in a NSEC rdata , BUG #106 */
uint16_t nsec_highest_rcode;

void yyerror(const char *message);

#ifdef NSEC3
/* parse nsec3 parameters and add the (first) rdata elements */
static void
nsec3_add_params(const char* hash_algo_str, const char* flag_str,
        const char* iter_str, const char* salt_str, int salt_len);
#endif /* NSEC3 */

%}
%union {
        domain_type      *domain;
        const dname_type *dname;
        struct lex_data   data;
        uint32_t          ttl;
        uint16_t          klass;
        uint16_t          type;
        uint16_t         *unknown;
}

/*
 * Tokens to represent the known RR types of DNS.
 */
%token <type> T_A T_NS T_MX T_TXT T_CNAME T_AAAA T_PTR T_NXT T_KEY T_SOA T_SIG
%token <type> T_SRV T_CERT T_LOC T_MD T_MF T_MB T_MG T_MR T_NULL T_WKS T_HINFO
%token <type> T_MINFO T_RP T_AFSDB T_X25 T_ISDN T_RT T_NSAP T_NSAP_PTR T_PX
%token <type> T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK
%token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR
%token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY
%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA T_URI
%token <type> T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY
%token <type> T_OPENPGPKEY T_CSYNC T_ZONEMD T_AVC T_SMIMEA T_SVCB T_HTTPS

/* other tokens */
%token         DOLLAR_TTL DOLLAR_ORIGIN NL SP
%token <data>  QSTR STR PREV BITLAB
%token <ttl>   T_TTL
%token <klass> T_RRCLASS

/* unknown RRs */
%token         URR
%token <type>  T_UTYPE

%type <type>    type_and_rdata
%type <domain>  owner dname abs_dname
%type <dname>   rel_dname label
%type <data>    wire_dname wire_abs_dname wire_rel_dname wire_label
%type <data>    str concatenated_str_seq str_sp_seq str_dot_seq
%type <data>    unquoted_dotted_str dotted_str svcparam svcparams
%type <data>    nxt_seq nsec_more
%type <unknown> rdata_unknown

%%
lines:  /* empty file */
    |   lines line
    ;

line:   NL
    |   sp NL
    |   PREV NL         {}    /* Lines containing only whitespace.  */
    |   ttl_directive
        {
            region_free_all(parser->rr_region);
            parser->current_rr.type = 0;
            parser->current_rr.rdata_count = 0;
            parser->current_rr.rdatas = parser->temporary_rdatas;
            parser->error_occurred = 0;
    }
    |   origin_directive
        {
            region_free_all(parser->rr_region);
            parser->current_rr.type = 0;
            parser->current_rr.rdata_count = 0;
            parser->current_rr.rdatas = parser->temporary_rdatas;
            parser->error_occurred = 0;
    }
    |   rr
    {   /* rr should be fully parsed */
            if (!parser->error_occurred) {
                            parser->current_rr.rdatas
                                    =(rdata_atom_type *)region_alloc_array_init(
                                            parser->region,
                                            parser->current_rr.rdatas,
                                            parser->current_rr.rdata_count,
                                            sizeof(rdata_atom_type));

                            process_rr();
            }

            region_free_all(parser->rr_region);

            parser->current_rr.type = 0;
            parser->current_rr.rdata_count = 0;
            parser->current_rr.rdatas = parser->temporary_rdatas;
            parser->error_occurred = 0;
    }
    |   error NL
    ;

/* needed to cope with ( and ) in arbitrary places */
sp:     SP
    |   sp SP
    ;

str:    STR | QSTR;

trail:  NL
    |   sp NL
    ;

ttl_directive:  DOLLAR_TTL sp str trail
    {
            parser->default_ttl = zparser_ttl2int($3.str, &(parser->error_occurred));
            if (parser->error_occurred == 1) {
                    parser->default_ttl = DEFAULT_TTL;
                        parser->error_occurred = 0;
            }
    }
    ;

origin_directive:       DOLLAR_ORIGIN sp abs_dname trail
    {
            /* if previous origin is unused, remove it, do not leak it */
            if(parser->origin != error_domain && parser->origin != $3) {
                /* protect $3 from deletion, because deldomain walks up */
                $3->usage ++;
                domain_table_deldomain(parser->db, parser->origin);
                $3->usage --;
            }
            parser->origin = $3;
    }
    |   DOLLAR_ORIGIN sp rel_dname trail
    {
            zc_error_prev_line("$ORIGIN directive requires absolute domain name");
    }
    ;

rr:     owner classttl type_and_rdata
    {
            parser->current_rr.owner = $1;
            parser->current_rr.type = $3;
    }
    ;

owner:  dname sp
    {
            parser->prev_dname = $1;
            $$ = $1;
    }
    |   PREV
    {
            $$ = parser->prev_dname;
    }
    ;

classttl:       /* empty - fill in the default, def. ttl and IN class */
    {
            parser->current_rr.ttl = parser->default_ttl;
            parser->current_rr.klass = parser->default_class;
    }
    |   T_RRCLASS sp            /* no ttl */
    {
            parser->current_rr.ttl = parser->default_ttl;
            parser->current_rr.klass = $1;
    }
    |   T_TTL sp                /* no class */
    {
            parser->current_rr.ttl = $1;
            parser->current_rr.klass = parser->default_class;
    }
    |   T_TTL sp T_RRCLASS sp   /* the lot */
    {
            parser->current_rr.ttl = $1;
            parser->current_rr.klass = $3;
    }
    |   T_RRCLASS sp T_TTL sp   /* the lot - reversed */
    {
            parser->current_rr.ttl = $3;
            parser->current_rr.klass = $1;
    }
    ;

dname:  abs_dname
    |   rel_dname
    {
            if ($1 == error_dname) {
                    $$ = error_domain;
            } else if(parser->origin == error_domain) {
                    zc_error("cannot concatenate origin to domain name, because origin failed to parse");
                    $$ = error_domain;
            } else if ($1->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
                    zc_error("domain name exceeds %d character limit", MAXDOMAINLEN);
                    $$ = error_domain;
            } else {
                    $$ = domain_table_insert(
                            parser->db->domains,
                            dname_concatenate(
                                    parser->rr_region,
                                    $1,
                                    domain_dname(parser->origin)));
            }
    }
    ;

abs_dname:      '.'
    {
            $$ = parser->db->domains->root;
    }
    |   '@'
    {
            $$ = parser->origin;
    }
    |   rel_dname '.'
    {
            if ($1 != error_dname) {
                    $$ = domain_table_insert(parser->db->domains, $1);
            } else {
                    $$ = error_domain;
            }
    }
    ;

label:  str
    {
            if ($1.len > MAXLABELLEN) {
                    zc_error("label exceeds %d character limit", MAXLABELLEN);
                    $$ = error_dname;
            } else if ($1.len <= 0) {
                    zc_error("zero label length");
                    $$ = error_dname;
            } else {
                    $$ = dname_make_from_label(parser->rr_region,
                                               (uint8_t *) $1.str,
                                               $1.len);
            }
    }
    |   BITLAB
    {
            zc_error("bitlabels are now deprecated. RFC2673 is obsoleted.");
            $$ = error_dname;
    }
    ;

rel_dname:      label
    |   rel_dname '.' label
    {
            if ($1 == error_dname || $3 == error_dname) {
                    $$ = error_dname;
            } else if ($1->name_size + $3->name_size - 1 > MAXDOMAINLEN) {
                    zc_error("domain name exceeds %d character limit",
                             MAXDOMAINLEN);
                    $$ = error_dname;
            } else {
                    $$ = dname_concatenate(parser->rr_region, $1, $3);
            }
    }
    ;

/*
 * Some dnames in rdata are handled as opaque blobs
 */

wire_dname:     wire_abs_dname
    |   wire_rel_dname
    {
            /* terminate in root label and copy the origin in there */
            if(parser->origin && domain_dname(parser->origin)) {
                    $$.len = $1.len + domain_dname(parser->origin)->name_size;
                    if ($$.len > MAXDOMAINLEN)
                            zc_error("domain name exceeds %d character limit",
                                     MAXDOMAINLEN);
                    $$.str = (char *) region_alloc(parser->rr_region, $$.len);
                    memmove($$.str, $1.str, $1.len);
                    memmove($$.str + $1.len, dname_name(domain_dname(parser->origin)),
                        domain_dname(parser->origin)->name_size);
            } else {
                    $$.len = $1.len + 1;
                    if ($$.len > MAXDOMAINLEN)
                            zc_error("domain name exceeds %d character limit",
                                     MAXDOMAINLEN);
                    $$.str = (char *) region_alloc(parser->rr_region, $$.len);
                    memmove($$.str, $1.str, $1.len);
                    $$.str[ $1.len ] = 0;
            }
    }
    ;

wire_abs_dname: '.'
    {
            char *result = (char *) region_alloc(parser->rr_region, 1);
            result[0] = 0;
            $$.str = result;
            $$.len = 1;
    }
    |   '@'
    {
            if(parser->origin && domain_dname(parser->origin)) {
                    $$.len = domain_dname(parser->origin)->name_size;
                    $$.str = (char *) region_alloc(parser->rr_region, $$.len);
                    memmove($$.str, dname_name(domain_dname(parser->origin)), $$.len);
            } else {
                    $$.len = 1;
                    $$.str = (char *) region_alloc(parser->rr_region, $$.len);
                    $$.str[0] = 0;
            }
    }
    |   wire_rel_dname '.'
    {
            $$.len = $1.len + 1;
            if ($$.len > MAXDOMAINLEN)
                    zc_error("domain name exceeds %d character limit",
                             MAXDOMAINLEN);
            $$.str = (char *) region_alloc(parser->rr_region, $$.len);
            memcpy($$.str, $1.str, $1.len);
            $$.str[$1.len] = 0;
    }
    ;

wire_label:     str
    {
            char *result = (char *) region_alloc(parser->rr_region,
                                                 $1.len + 1);

            if ($1.len > MAXLABELLEN)
                    zc_error("label exceeds %d character limit", MAXLABELLEN);

            /* make label anyway */
            result[0] = $1.len;
            memmove(result+1, $1.str, $1.len);

            $$.str = result;
            $$.len = $1.len + 1;
    }
    ;

wire_rel_dname: wire_label
    |   wire_rel_dname '.' wire_label
    {
            $$.len = $1.len + $3.len;
            if ($$.len > MAXDOMAINLEN)
                    zc_error("domain name exceeds %d character limit",
                             MAXDOMAINLEN);
            $$.str = (char *) region_alloc(parser->rr_region, $$.len);
            memmove($$.str, $1.str, $1.len);
            memmove($$.str + $1.len, $3.str, $3.len);
    }
    ;

str_seq:        unquoted_dotted_str
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
    }
    |   QSTR
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
    }
    |   QSTR unquoted_dotted_str
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
    }
    |   str_seq QSTR
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
    }
    |   str_seq QSTR unquoted_dotted_str
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
    }
    |   str_seq sp unquoted_dotted_str
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
    }
    |   str_seq sp QSTR
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
    }
    |   str_seq sp QSTR unquoted_dotted_str
    {
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
            zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $4.str, $4.len), 0);
    }
    ;

/*
 * Generate a single string from multiple STR tokens, separated by
 * spaces or dots.
 */
concatenated_str_seq:   str
    |   '.'
    {
            $$.len = 1;
            $$.str = region_strdup(parser->rr_region, ".");
    }
    |   concatenated_str_seq sp str
    {
            $$.len = $1.len + $3.len + 1;
            $$.str = (char *) region_alloc(parser->rr_region, $$.len + 1);
            memcpy($$.str, $1.str, $1.len);
            memcpy($$.str + $1.len, " ", 1);
            memcpy($$.str + $1.len + 1, $3.str, $3.len);
            $$.str[$$.len] = '\0';
    }
    |   concatenated_str_seq '.' str
    {
            $$.len = $1.len + $3.len + 1;
            $$.str = (char *) region_alloc(parser->rr_region, $$.len + 1);
            memcpy($$.str, $1.str, $1.len);
            memcpy($$.str + $1.len, ".", 1);
            memcpy($$.str + $1.len + 1, $3.str, $3.len);
            $$.str[$$.len] = '\0';
    }
    ;

/* used to convert a nxt list of types */
nxt_seq:        str
    {
            uint16_t type = rrtype_from_string($1.str);
            if (type != 0 && type < 128) {
                    set_bit(nxtbits, type);
            } else {
                    zc_error("bad type %d in NXT record", (int) type);
            }
    }
    |   nxt_seq sp str
    {
            uint16_t type = rrtype_from_string($3.str);
            if (type != 0 && type < 128) {
                    set_bit(nxtbits, type);
            } else {
                    zc_error("bad type %d in NXT record", (int) type);
            }
    }
    ;

nsec_more:      SP nsec_more
    {
    }
    |   NL
    {
    }
    |   str nsec_seq
    {
            uint16_t type = rrtype_from_string($1.str);
            if (type != 0) {
                    if (type > nsec_highest_rcode) {
                            nsec_highest_rcode = type;
                    }
                    set_bitnsec(nsecbits, type);
            } else {
                    zc_error("bad type %d in NSEC record", (int) type);
            }
    }
    ;

nsec_seq:       NL
        |       SP nsec_more
        ;

/*
 * Sequence of STR tokens separated by spaces.  The spaces are not
 * preserved during concatenation.
 */
str_sp_seq:     str
    |   str_sp_seq sp str
    {
            char *result = (char *) region_alloc(parser->rr_region,
                                                 $1.len + $3.len + 1);
            memcpy(result, $1.str, $1.len);
            memcpy(result + $1.len, $3.str, $3.len);
            $$.str = result;
            $$.len = $1.len + $3.len;
            $$.str[$$.len] = '\0';
    }
    ;

/*
 * Sequence of STR tokens separated by dots.  The dots are not
 * preserved during concatenation.
 */
str_dot_seq:    str
    |   str_dot_seq '.' str
    {
            char *result = (char *) region_alloc(parser->rr_region,
                                                 $1.len + $3.len + 1);
            memcpy(result, $1.str, $1.len);
            memcpy(result + $1.len, $3.str, $3.len);
            $$.str = result;
            $$.len = $1.len + $3.len;
            $$.str[$$.len] = '\0';
    }
    ;

/*
 * A string that can contain dots.
 */
unquoted_dotted_str:    STR
    |   '.'
    {
        $$.str = ".";
        $$.len = 1;
    }
    |   unquoted_dotted_str '.'
    {
            char *result = (char *) region_alloc(parser->rr_region,
                                                 $1.len + 2);
            memcpy(result, $1.str, $1.len);
            result[$1.len] = '.';
            $$.str = result;
            $$.len = $1.len + 1;
            $$.str[$$.len] = '\0';
    }
    |   unquoted_dotted_str '.' STR
    {
            char *result = (char *) region_alloc(parser->rr_region,
                                                 $1.len + $3.len + 2);
            memcpy(result, $1.str, $1.len);
            result[$1.len] = '.';
            memcpy(result + $1.len + 1, $3.str, $3.len);
            $$.str = result;
            $$.len = $1.len + $3.len + 1;
            $$.str[$$.len] = '\0';
    }
    ;

/*
 * A string that can contain dots or a quoted string.
 */
dotted_str:     unquoted_dotted_str | QSTR

/* define what we can parse */
type_and_rdata:
    /*
     * All supported RR types.  We don't support NULL and types marked obsolete.
     */
        T_A sp rdata_a
    |   T_A sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NS sp rdata_domain_name
    |   T_NS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_MD sp rdata_domain_name { zc_warning_prev_line("MD is obsolete"); }
    |   T_MD sp rdata_unknown
    {
            zc_warning_prev_line("MD is obsolete");
            $$ = $1; parse_unknown_rdata($1, $3);
    }
    |   T_MF sp rdata_domain_name { zc_warning_prev_line("MF is obsolete"); }
    |   T_MF sp rdata_unknown
    {
            zc_warning_prev_line("MF is obsolete");
            $$ = $1;
            parse_unknown_rdata($1, $3);
    }
    |   T_CNAME sp rdata_domain_name
    |   T_CNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SOA sp rdata_soa
    |   T_SOA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_MB sp rdata_domain_name { zc_warning_prev_line("MB is obsolete"); }
    |   T_MB sp rdata_unknown
    {
            zc_warning_prev_line("MB is obsolete");
            $$ = $1;
            parse_unknown_rdata($1, $3);
    }
    |   T_MG sp rdata_domain_name
    |   T_MG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_MR sp rdata_domain_name
    |   T_MR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
      /* NULL */
    |   T_WKS sp rdata_wks
    |   T_WKS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_PTR sp rdata_domain_name
    |   T_PTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_HINFO sp rdata_hinfo
    |   T_HINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_MINFO sp rdata_minfo /* Experimental */
    |   T_MINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_MX sp rdata_mx
    |   T_MX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_TXT sp rdata_txt
    |   T_TXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SPF sp rdata_txt
    |   T_SPF sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_AVC sp rdata_txt
    |   T_AVC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_RP sp rdata_rp                /* RFC 1183 */
    |   T_RP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_AFSDB sp rdata_afsdb  /* RFC 1183 */
    |   T_AFSDB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_X25 sp rdata_x25      /* RFC 1183 */
    |   T_X25 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_ISDN sp rdata_isdn    /* RFC 1183 */
    |   T_ISDN sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_IPSECKEY sp rdata_ipseckey    /* RFC 4025 */
    |   T_IPSECKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_DHCID sp rdata_dhcid
    |   T_DHCID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_RT sp rdata_rt                /* RFC 1183 */
    |   T_RT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NSAP sp rdata_nsap    /* RFC 1706 */
    |   T_NSAP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SIG sp rdata_rrsig
    |   T_SIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_KEY sp rdata_dnskey
    |   T_KEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_PX sp rdata_px                /* RFC 2163 */
    |   T_PX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_AAAA sp rdata_aaaa
    |   T_AAAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_LOC sp rdata_loc
    |   T_LOC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NXT sp rdata_nxt
    |   T_NXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SRV sp rdata_srv
    |   T_SRV sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NAPTR sp rdata_naptr  /* RFC 2915 */
    |   T_NAPTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_KX sp rdata_kx                /* RFC 2230 */
    |   T_KX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_CERT sp rdata_cert    /* RFC 2538 */
    |   T_CERT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_DNAME sp rdata_domain_name /* RFC 2672 */
    |   T_DNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_APL trail             /* RFC 3123 */
    |   T_APL sp rdata_apl      /* RFC 3123 */
    |   T_APL sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_DS sp rdata_ds
    |   T_DS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_DLV sp rdata_dlv { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } }
    |   T_DLV sp rdata_unknown { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SSHFP sp rdata_sshfp
    |   T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); check_sshfp(); }
    |   T_RRSIG sp rdata_rrsig
    |   T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NSEC sp rdata_nsec
    |   T_NSEC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NSEC3 sp rdata_nsec3
    |   T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NSEC3PARAM sp rdata_nsec3_param
    |   T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_DNSKEY sp rdata_dnskey
    |   T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_TLSA sp rdata_tlsa
    |   T_TLSA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SMIMEA sp rdata_smimea
    |   T_SMIMEA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_NID sp rdata_nid
    |   T_NID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_L32 sp rdata_l32
    |   T_L32 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_L64 sp rdata_l64
    |   T_L64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_LP sp rdata_lp
    |   T_LP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_EUI48 sp rdata_eui48
    |   T_EUI48 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_EUI64 sp rdata_eui64
    |   T_EUI64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_CAA sp rdata_caa
    |   T_CAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_CDS sp rdata_ds
    |   T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_CDNSKEY sp rdata_dnskey
    |   T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_OPENPGPKEY sp rdata_openpgpkey
    |   T_OPENPGPKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_CSYNC sp rdata_csync
    |   T_CSYNC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_ZONEMD sp rdata_zonemd
    |   T_ZONEMD sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_SVCB sp rdata_svcb
    |   T_SVCB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_HTTPS sp rdata_svcb
    |   T_HTTPS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_URI sp rdata_uri
    |   T_URI sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
    |   str error NL
    {
            zc_error_prev_line("unrecognized RR type '%s'", $1.str);
    }
    ;

/*
 *
 * below are all the definition for all the different rdata
 *
 */

rdata_a:        dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str));
    }
    ;

rdata_domain_name:      dname trail
    {
            /* convert a single dname record */
            zadd_rdata_domain($1);
    }
    ;

rdata_soa:      dname sp dname sp str sp str sp str sp str sp str trail
    {
            /* convert the soa data */
            zadd_rdata_domain($1);      /* prim. ns */
            zadd_rdata_domain($3);      /* email */
            zadd_rdata_wireformat(zparser_conv_serial(parser->region, $5.str)); /* serial */
            zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* refresh */
            zadd_rdata_wireformat(zparser_conv_period(parser->region, $9.str)); /* retry */
            zadd_rdata_wireformat(zparser_conv_period(parser->region, $11.str)); /* expire */
            zadd_rdata_wireformat(zparser_conv_period(parser->region, $13.str)); /* minimum */
    }
    ;

rdata_wks:      dotted_str sp str sp concatenated_str_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str)); /* address */
            zadd_rdata_wireformat(zparser_conv_services(parser->region, $3.str, $5.str)); /* protocol and services */
    }
    ;

rdata_hinfo:    str sp str trail
    {
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* CPU */
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* OS*/
    }
    ;

rdata_minfo:    dname sp dname trail
    {
            /* convert a single dname record */
            zadd_rdata_domain($1);
            zadd_rdata_domain($3);
    }
    ;

rdata_mx:       str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));  /* priority */
            zadd_rdata_domain($3);      /* MX host */
    }
    ;

rdata_txt:      str_seq trail
    {
        zadd_rdata_txt_clean_wireformat();
    }
    ;

/* RFC 1183 */
rdata_rp:       dname sp dname trail
    {
            zadd_rdata_domain($1); /* mbox d-name */
            zadd_rdata_domain($3); /* txt d-name */
    }
    ;

/* RFC 1183 */
rdata_afsdb:    str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* subtype */
            zadd_rdata_domain($3); /* domain name */
    }
    ;

/* RFC 1183 */
rdata_x25:      str trail
    {
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* X.25 address. */
    }
    ;

/* RFC 1183 */
rdata_isdn:     str trail
    {
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */
    }
    |   str sp str trail
    {
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* sub-address */
    }
    ;

/* RFC 1183 */
rdata_rt:       str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
            zadd_rdata_domain($3); /* intermediate host */
    }
    ;

/* RFC 1706 */
rdata_nsap:     str_dot_seq trail
    {
            /* String must start with "0x" or "0X".      */
            if (strncasecmp($1.str, "0x", 2) != 0) {
                    zc_error_prev_line("NSAP rdata must start with '0x'");
            } else {
                    zadd_rdata_wireformat(zparser_conv_hex(parser->region, $1.str + 2, $1.len - 2)); /* NSAP */
            }
    }
    ;

/* RFC 2163 */
rdata_px:       str sp dname sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
            zadd_rdata_domain($3); /* MAP822 */
            zadd_rdata_domain($5); /* MAPX400 */
    }
    ;

rdata_aaaa:     dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $1.str));  /* IPv6 address */
    }
    ;

rdata_loc:      concatenated_str_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_loc(parser->region, $1.str)); /* Location */
    }
    ;

rdata_nxt:      dname sp nxt_seq trail
    {
            zadd_rdata_domain($1); /* nxt name */
            zadd_rdata_wireformat(zparser_conv_nxt(parser->region, nxtbits)); /* nxt bitlist */
            memset(nxtbits, 0, sizeof(nxtbits));
    }
    ;

rdata_srv:      str sp str sp str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* prio */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $5.str)); /* port */
            zadd_rdata_domain($7); /* target name */
    }
    ;

/* RFC 2915 */
rdata_naptr:    str sp str sp str sp str sp str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* order */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* preference */
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $5.str, $5.len)); /* flags */
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $7.str, $7.len)); /* service */
            zadd_rdata_wireformat(zparser_conv_text(parser->region, $9.str, $9.len)); /* regexp */
            zadd_rdata_domain($11); /* target name */
    }
    ;

/* RFC 2230 */
rdata_kx:       str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
            zadd_rdata_domain($3); /* exchanger */
    }
    ;

/* RFC 2538 */
rdata_cert:     str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_certificate_type(parser->region, $1.str)); /* type */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* key tag */
            zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* algorithm */
            zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* certificate or CRL */
    }
    ;

/* RFC 3123 */
rdata_apl:      rdata_apl_seq trail
    ;

rdata_apl_seq:  dotted_str
    {
            zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $1.str));
    }
    |   rdata_apl_seq sp dotted_str
    {
            zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $3.str));
    }
    ;

rdata_ds:       str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */
            zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */
    }
    ;

rdata_dlv:      str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */
            zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */
    }
    ;

rdata_sshfp:    str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* alg */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* fp type */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $5.str, $5.len)); /* hash */
            check_sshfp();
    }
    ;

rdata_dhcid:    str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str)); /* data blob */
    }
    ;

rdata_rrsig:    str sp str sp str sp str sp str sp str sp str sp wire_dname sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_rrtype(parser->region, $1.str)); /* rr covered */
            zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* # labels */
            zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* # orig TTL */
            zadd_rdata_wireformat(zparser_conv_time(parser->region, $9.str)); /* sig exp */
            zadd_rdata_wireformat(zparser_conv_time(parser->region, $11.str)); /* sig inc */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $13.str)); /* key id */
            zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, 
                                (const uint8_t*) $15.str,$15.len)); /* sig name */
            zadd_rdata_wireformat(zparser_conv_b64(parser->region, $17.str)); /* sig data */
    }
    ;

rdata_nsec:     wire_dname nsec_seq
    {
            zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, 
                                (const uint8_t*) $1.str, $1.len)); /* nsec name */
            zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
            memset(nsecbits, 0, sizeof(nsecbits));
            nsec_highest_rcode = 0;
    }
    ;

rdata_nsec3:   str sp str sp str sp str sp str nsec_seq
    {
#ifdef NSEC3
            nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);

            zadd_rdata_wireformat(zparser_conv_b32(parser->region, $9.str)); /* next hashed name */
            zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
            memset(nsecbits, 0, sizeof(nsecbits));
            nsec_highest_rcode = 0;
#else
            zc_error_prev_line("nsec3 not supported");
#endif /* NSEC3 */
    }
    ;

rdata_nsec3_param:   str sp str sp str sp str trail
    {
#ifdef NSEC3
            nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);
#else
            zc_error_prev_line("nsec3 not supported");
#endif /* NSEC3 */
    }
    ;

rdata_tlsa:     str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */
    }
    ;

rdata_smimea:   str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */
    }
    ;

rdata_dnskey:   str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* flags */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* proto */
            zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* alg */
            zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* hash */
    }
    ;

rdata_ipsec_base: str sp str sp str sp dotted_str
    {
            const dname_type* name = 0;
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* precedence */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* gateway type */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* algorithm */
            switch(atoi($3.str)) {
                case IPSECKEY_NOGATEWAY: 
                        zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 0));
                        break;
                case IPSECKEY_IP4:
                        zadd_rdata_wireformat(zparser_conv_a(parser->region, $7.str));
                        break;
                case IPSECKEY_IP6:
                        zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $7.str));
                        break;
                case IPSECKEY_DNAME:
                        /* convert and insert the dname */
                        if(strlen($7.str) == 0)
                                zc_error_prev_line("IPSECKEY must specify gateway name");
                        if(!(name = dname_parse(parser->region, $7.str))) {
                                zc_error_prev_line("IPSECKEY bad gateway dname %s", $7.str);
                                break;
                        }
                        if($7.str[strlen($7.str)-1] != '.') {
                                if(parser->origin == error_domain) {
                                        zc_error("cannot concatenate origin to domain name, because origin failed to parse");
                                        break;
                                } else if(name->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
                                        zc_error("ipsec gateway name exceeds %d character limit",
                                                MAXDOMAINLEN);
                                        break;
                                }
                                name = dname_concatenate(parser->rr_region, name, 
                                        domain_dname(parser->origin));
                        }
                        zadd_rdata_wireformat(alloc_rdata_init(parser->region,
                                dname_name(name), name->name_size));
                        break;
                default:
                        zc_error_prev_line("unknown IPSECKEY gateway type");
            }
    }
    ;

rdata_ipseckey: rdata_ipsec_base sp str_sp_seq trail
    {
           zadd_rdata_wireformat(zparser_conv_b64(parser->region, $3.str)); /* public key */
    }
    | rdata_ipsec_base trail
    ;

/* RFC 6742 */ 
rdata_nid:      str sp dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));  /* preference */
            zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str));  /* NodeID */
    }
    ;

rdata_l32:      str sp dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));  /* preference */
            zadd_rdata_wireformat(zparser_conv_a(parser->region, $3.str));  /* Locator32 */
    }
    ;

rdata_l64:      str sp dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));  /* preference */
            zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str));  /* Locator64 */
    }
    ;

rdata_lp:       str sp dname trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));  /* preference */
            zadd_rdata_domain($3);  /* FQDN */
    }
    ;

rdata_eui48:    str trail
    {
            zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 48));
    }
    ;

rdata_eui64:    str trail
    {
            zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 64));
    }
    ;

/* RFC7553 */
rdata_uri:      str sp str sp dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */
            zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* target */
    }
    ;

/* RFC 6844 */
rdata_caa:      str sp str sp dotted_str trail
    {
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* Flags */
            zadd_rdata_wireformat(zparser_conv_tag(parser->region, $3.str, $3.len)); /* Tag */
            zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* Value */
    }
    ;

/* RFC7929 */
rdata_openpgpkey:       str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str));
    }
    ;

/* RFC7477 */
rdata_csync:    str sp str nsec_seq
    {
            zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str));
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str));
            zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
            memset(nsecbits, 0, sizeof(nsecbits));
            nsec_highest_rcode = 0;
    }
    ;

/* draft-ietf-dnsop-dns-zone-digest */
rdata_zonemd:   str sp str sp str sp str_sp_seq trail
    {
            zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str)); /* serial */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* scheme */
            zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* hash algorithm */
            zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* digest */
    }
    ;

svcparam:       dotted_str QSTR
    {
        zadd_rdata_wireformat(zparser_conv_svcbparam(
                parser->region, $1.str, $1.len, $2.str, $2.len));
    }
    |           dotted_str
    {
        zadd_rdata_wireformat(zparser_conv_svcbparam(
                parser->region, $1.str, $1.len, NULL, 0));
    }
    ;
svcparams:      svcparam
    |           svcparams sp svcparam
    ;
/* draft-ietf-dnsop-svcb-https */
rdata_svcb_base:        str sp dname
    {
            /* SvcFieldPriority */
            zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));
            /* SvcDomainName */
            zadd_rdata_domain($3);
    };
rdata_svcb:     rdata_svcb_base sp svcparams trail
    {
        zadd_rdata_svcb_check_wireformat();
    }
    |   rdata_svcb_base trail
    ;

rdata_unknown:  URR sp str sp str_sp_seq trail
    {
            /* $2 is the number of octets, currently ignored */
            $$ = zparser_conv_hex(parser->rr_region, $5.str, $5.len);

    }
    |   URR sp str trail
    {
            $$ = zparser_conv_hex(parser->rr_region, "", 0);
    }
    |   URR error NL
    {
            $$ = zparser_conv_hex(parser->rr_region, "", 0);
    }
    ;
%%

int
yywrap(void)
{
        return 1;
}

/*
 * Create the parser.
 */
zparser_type *
zparser_create(region_type *region, region_type *rr_region, namedb_type *db)
{
        zparser_type *result;

        result = (zparser_type *) region_alloc(region, sizeof(zparser_type));
        result->region = region;
        result->rr_region = rr_region;
        result->db = db;

        result->filename = NULL;
        result->current_zone = NULL;
        result->origin = NULL;
        result->prev_dname = NULL;

        result->temporary_rdatas = (rdata_atom_type *) region_alloc_array(
                result->region, MAXRDATALEN, sizeof(rdata_atom_type));

        return result;
}

/*
 * Initialize the parser for a new zone file.
 */
void
zparser_init(const char *filename, uint32_t ttl, uint16_t klass,
             const dname_type *origin)
{
        memset(nxtbits, 0, sizeof(nxtbits));
        memset(nsecbits, 0, sizeof(nsecbits));
        nsec_highest_rcode = 0;

        parser->default_ttl = ttl;
        parser->default_class = klass;
        parser->current_zone = NULL;
        parser->origin = domain_table_insert(parser->db->domains, origin);
        parser->prev_dname = parser->origin;
        parser->error_occurred = 0;
        parser->errors = 0;
        parser->line = 1;
        parser->filename = filename;
        parser->current_rr.rdata_count = 0;
        parser->current_rr.rdatas = parser->temporary_rdatas;
}

void
yyerror(const char *message)
{
        zc_error("%s", message);
}

static void
error_va_list(unsigned line, const char *fmt, va_list args)
{
        if (parser->filename) {
                char message[MAXSYSLOGMSGLEN];
                vsnprintf(message, sizeof(message), fmt, args);
                log_msg(LOG_ERR, "%s:%u: %s", parser->filename, line, message);
        }
        else log_vmsg(LOG_ERR, fmt, args);

        ++parser->errors;
        parser->error_occurred = 1;
}

/* the line counting sux, to say the least
 * with this grose hack we try do give sane
 * numbers back */
void
zc_error_prev_line(const char *fmt, ...)
{
        va_list args;
        va_start(args, fmt);
        error_va_list(parser->line - 1, fmt, args);
        va_end(args);
}

void
zc_error(const char *fmt, ...)
{
        /* send an error message to stderr */
        va_list args;
        va_start(args, fmt);
        error_va_list(parser->line, fmt, args);
        va_end(args);
}

static void
warning_va_list(unsigned line, const char *fmt, va_list args)
{
        if (parser->filename) {
                char m[MAXSYSLOGMSGLEN];
                vsnprintf(m, sizeof(m), fmt, args);
                log_msg(LOG_WARNING, "%s:%u: %s", parser->filename, line, m);
        }
        else log_vmsg(LOG_WARNING, fmt, args);
}

void
zc_warning_prev_line(const char *fmt, ...)
{
        va_list args;
        va_start(args, fmt);
        warning_va_list(parser->line - 1, fmt, args);
        va_end(args);
}

void
zc_warning(const char *fmt, ... )
{
        va_list args;
        va_start(args, fmt);
        warning_va_list(parser->line, fmt, args);
        va_end(args);
}

#ifdef NSEC3
static void
nsec3_add_params(const char* hashalgo_str, const char* flag_str,
        const char* iter_str, const char* salt_str, int salt_len)
{
        zadd_rdata_wireformat(zparser_conv_byte(parser->region, hashalgo_str));
        zadd_rdata_wireformat(zparser_conv_byte(parser->region, flag_str));
        zadd_rdata_wireformat(zparser_conv_short(parser->region, iter_str));

        /* salt */
        if(strcmp(salt_str, "-") != 0) 
                zadd_rdata_wireformat(zparser_conv_hex_length(parser->region, 
                        salt_str, salt_len)); 
        else 
                zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 1));
}
#endif /* NSEC3 */