/*
 * dnsutl - utilities to make DNS easier to configure
 * Copyright (C) 1996, 1999, 2006, 2007 Peter Miller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <ac/ctype.h>
#include <ac/string.h>

#include <error.h>
#include <mem.h>
#include <srrf.h>
#include <srrf/origin.h>


static int
needs_quoting(string_ty *sp)
{
    char            *s;

    s = sp->str_text;
    while (*s)
    {
        if (!isprint(*s) || isspace(*s) || strchr("\"\\();", *s))
            return 1;
        ++s;
    }
    return 0;
}


static string_ty *
quote(string_ty *sp)
{
    static char     *buffer;
    static size_t   max;
    static size_t   pos;
    char            *bp;
    char            *s;

    pos = sp->str_length * 4 + 2;
    if (max < pos)
    {
        max = pos;
        buffer = mem_change_size(buffer, max);
    }

    bp = buffer;
    *bp++ = '"';
    s = sp->str_text;
    while (*s)
    {
        int c = (unsigned char)*s++;
        if (isprint(c))
        {
            if (strchr("\"\\", c))
                *bp++ = '\\';
            *bp++ = c;
        }
        else
        {
            /* Sigh.  rfc1035 says decimal */
            sprintf(bp, "\\%03d", c);
            bp += 4;
        }
    }
    *bp++ = '"';
    return str_n_from_c(buffer, bp - buffer);
}


static int
srrf_print_generic(srrf_t *rp, FILE *fp)
{
    int             col;
    string_ty       *tmp;
    const char      *tmp2;
    size_t          j;
    int             nlines;
    int             pos;
    int             single_line;

    /*
     * print the name
     */
    nlines = 1;
    col = 0;
    if (rp->name)
    {
        fprintf(fp, "%s", rp->name->str_text);
        col += rp->name->str_length;
    }

    /*
     * print the time to live
     */
    if (rp->ttl)
    {
        char            ttl[30];

        if (col < 8)
        {
            while (col < 8)
            {
                putc(' ', fp);
                ++col;
            }
        }
        else
        {
            fprintf(fp, " ");
            col++;
        }
        sprintf(ttl, "%ld", rp->ttl);
        fprintf(fp, "%s", ttl);
        col += strlen(ttl);
    }

    /*
     * print the class
     */
    tmp2 = rp->class->name;
    if (col >= 16)
    {
        fprintf(fp, " ");
        col++;
    }
    else
    {
        while (col < 16)
        {
            putc(' ', fp);
            ++col;
        }
    }
    fprintf(fp, "%s", tmp2);
    col += strlen(tmp2);

    /*
     * print the type
     */
    tmp2 = rp->type->name;
    if (col >= 24)
    {
        fprintf(fp, " ");
        col++;
    }
    else
    {
        while (col < 24)
        {
            putc(' ', fp);
            ++col;
        }
    }
    fprintf(fp, "%s", tmp2);
    col += strlen(tmp2);

    /*
     * print the other stuff
     */
    if (rp->arg.nstrings)
    {
        if (col >= 32)
        {
            fprintf(fp, " ");
            col++;
        }
        else
        {
            while (col < 32)
            {
                putc(' ', fp);
                ++col;
            }
        }

        /*
         * see if we need separate line for each entry
         */
        pos = col;
        for (j = 0; j < rp->arg.nstrings; ++j)
        {
            if (j)
                ++pos;
            tmp = rp->arg.string[j];
            if (needs_quoting(tmp))
                tmp = quote(tmp);
            else
                tmp = str_copy(tmp);
            pos += tmp->str_length;
            str_free(tmp);
        }
        single_line = (rp->arg.nstrings < 2) || (pos <= 80);

        if (!single_line)
            fprintf(fp, "("/*)*/);
        for (j = 0; j < rp->arg.nstrings; ++j)
        {
            if (single_line)
            {
                if (j)
                {
                    fprintf(fp, " ");
                    col++;
                }
            }
            else
            {
                if (!j)
                    fprintf(fp, " ");
                else
                {
                    putc('\n', fp);
                    col = 0;
                    ++nlines;
                    while (col < 32)
                    {
                        putc(' ', fp);
                        ++col;
                    }
                }
            }
            tmp = rp->arg.string[j];
            if (needs_quoting(tmp))
                tmp = quote(tmp);
            else
                tmp = str_copy(tmp);
            fprintf(fp, "%s", tmp->str_text);
            col += tmp->str_length;
            str_free(tmp);
        }
        if (!single_line)
            fprintf(fp, " )");
    }

    /*
     * done
     */
    fprintf(fp, "\n");
    return nlines;
}


int
srrf_print(FILE *fp, srrf_t *rp)
{
    srrf_t      *relative;
    int         nlines;
    size_t      j;
    static string_ty *prev_name;

    /*
     * create a bogus relative row
     */
    relative = srrf_alloc();
    if (rp->name)
        relative->name = srrf_absolute_to_relative(rp->name);
    relative->ttl = rp->ttl;
    assert(rp->class);
    relative->class = rp->class;
    assert(rp->type);
    relative->type = rp->type;
    for (j = 0; j < rp->arg.nstrings; ++j)
        strlist_append(&relative->arg, rp->arg.string[j]);
    if (rp->file_name)
        relative->file_name  = str_copy(rp->file_name);
    relative->line_number = rp->line_number;
    if (relative->type->abs_to_rel)
        relative->type->abs_to_rel(relative);
    if (prev_name && str_equal(relative->name, prev_name))
    {
        str_free(relative->name);
        relative->name = 0;
    }

    /*
     * print the row in a special way, if specified
     */
    if (relative->type->print)
        nlines = relative->type->print(relative, fp);
    else
        nlines = srrf_print_generic(relative, fp);

    /*
     * clean up and go home
     */
    if (relative->name)
    {
        if (prev_name)
            str_free(prev_name);
        prev_name = str_copy(relative->name);
    }
    srrf_free(relative);
    return nlines;
}


syntax highlighted by Code2HTML, v. 0.9.1