/*
 * 4m v2.15 (set.c)
 * (C) Copyright 1990 by Carrick Sean Casey
 * (C) Copyright 1993 by Scott Chasin and Michaeljon Miller
 *
 * 3-24-93 See file COPYING for copyright information.
 *
 * Internal variable setting
 */

#include "4m.h"
#include "externs.h"

typedef enum {
     V_UNDEF   = 0,
     V_CHAR    = 1,
     V_BOOLEAN = 2,
     V_NONNEG  = 3,
     V_INT     = 4,
     V_STRING  = 5
} VARTYPE;

/* struct for variable table */
typedef struct Variable {
    char *name;
    char *desc;
    VARTYPE type;
    char *address;
}   VARIABLE;


/* list of usable variables */
static VARIABLE vars[] = {
    {"beeps", "Beeps audible?", V_BOOLEAN, (char *) &gv.beeps},
    {"bufferlines", "Retain in buffer", V_NONNEG, (char *) &gv.bufferlines},
    {"commandchar", "Command prefix", V_CHAR, (char *) &gv.cmdchar},
    {"history", "<TAB> history", V_NONNEG, (char *) &gv.phistory},
    {"logfile", "Logging filename", V_STRING, (char *) &gv.logfile},
    {"pagesize", "Terminal lines", V_INT, (char *) &gv.pagesize},
    {"pauseshell", "Pause on shell", V_BOOLEAN, (char *) &gv.pauseonshell},
    {"restricted", "Restrict access?", V_BOOLEAN, (char *) &gv.restricted},
    {"verifyquit", "Verify on quit", V_BOOLEAN, (char *) &gv.verifyquit},
    {"shell", "Desired shell", V_STRING, (char *) &gv.shell},
    {"editorbeep", "Editor beeping", V_BOOLEAN, (char *) &gv.editorbeep},
    {"server", "Default server", V_STRING, (char *) &gv.default_host},
    {"port", "Default port", V_INT, (char *) &gv.default_port},
    {"group", "Default group", V_STRING, (char *) &gv.group},
    {"openmsg", "Open messages", V_STRING, (char *) &gv.o_msgformat},
    {"privmsg", "Private messages", V_STRING, (char *) &gv.p_msgformat},
    {"securemsg", "Secure Messages", V_STRING, (char *)&gv.s_msgformat},
    {"statusbar", "Statusbar", V_STRING, (char *) &gv.statusbar},
    {NULL, NULL, V_UNDEF, NULL}
};


int listvars ();
extern void putl ();
extern int strncmp ();
extern void errormsg ();
void do_restrict ();
int setvar ();
extern int atoi ();
void varsanity ();
void printvar ();


extern void catargs ();


extern void getwinsize ();

void set(argc, argv)
     int argc;
     char **argv;
{
    char str[25];
    int x;

    if (argc == 1) {
        (void) listvars(NULL);
        return;
    } else if (argc == 2) {
        if (listvars(argv[1]) < 0) {
            putl("[Set] No such variable", PL_SCR);
            return;
        } else
            return;
    }
 /* "restricted" is a special case */
    if (!strncmp(argv[1], "res", 3)) {
        if (gv.restricted) {
            errormsg("Restricted mode can't be reset.");
            return;
        } else {
            putl("[Set] You are now in restricted mode.", PL_SCR);
            do_restrict();
            return;
        }
    }
    catargs(&argv[2]);

    for (x = 0; vars[x].name != NULL; x++) {
        if (!strncmp(argv[1], vars[x].name, 3)) {
            if (setvar(x, vars[x].type,
                       vars[x].address, mbuf) < 0)
                return;
            else
                break;
        }
    }

    if (vars[x].name == NULL) {
        sprintf(str, "[Set] No such variable \"%s\".", argv[1]);
        putl(str, PL_SCR);
        return;
    }
    return;
}


int setvar(index, type, address, s)
     int index;
     VARTYPE type;
     char *address;
     char *s;
{
    int zero = 0, one = 1;
    int tmp;
    char *p, *malloc(), usagestr[100];

    switch (type) {
        case V_CHAR:
            *address = *s;
            break;
        case V_INT:
            tmp = atoi(s);
            memcpy(address, &tmp, sizeof(int));
            break;
        case V_NONNEG:
            tmp = atoi(s);
            if (tmp < 0) {
                strcpy(usagestr, "[Set] Only non-negative values allowed.");
                putl(usagestr, PL_SCR);
                return (-1);
            }
            memcpy(address, &tmp, sizeof(int));
            break;
        case V_BOOLEAN:
            if (!strncmp(s, "on", 2) ||
                !strncmp(s, "true", 4) ||
                *s == 'y' || *s == '1')
                memcpy(address, &one, sizeof(int));
            else if (!strncmp(s, "off", 2) ||
                     !strncmp(s, "false", 4) ||
                     *s == 'n' || *s == '0')
                memcpy(address, &zero, sizeof(int));
            else {
                strcpy(usagestr, "[Set] Only boolean values allowed.");
                putl(usagestr, PL_SCR);
                return (-1);
            }
            break;
        case V_STRING:
            tmp = strlen(s) + 1;
            if ((p = malloc(tmp)) == NULL) {
                strcpy(usagestr, "[Set] Not enough memory to set string.");
                putl(usagestr, PL_SCR);
                return (-1);
            }
            memcpy(p, s, tmp);
            memcpy(address, &p, sizeof(p));
            break;
        case V_UNDEF:
        default:
            break;
    }
    varsanity();
    sprintf(usagestr, "[Set] Variable \"%s\" changed.", vars[index].name);
    putl(usagestr, PL_SCR);
    return (0);
}

int listvars(name)
     char *name;
{
    int x;

    if (name == NULL) {
        putl("[VARIABLE]    [DESCRIPTION]      [TYPE] [VALUE]", PL_SCR);
        for (x = 0; vars[x].name != NULL; x++)
            printvar(vars[x].name, vars[x].desc, vars[x].type, vars[x].address);
        return (0);
    } else
        for (x = 0; vars[x].name != NULL; x++)
            if (strcmp(name, vars[x].name) == 0) {
                putl("[VARIABLE]     [DESCRIPTION]      [TYPE] [VALUE]", PL_SCR);
                printvar(vars[x].name, vars[x].desc,
                         vars[x].type, vars[x].address);
                break;
            }
    if (vars[x].name == NULL)
        return (-1);
    else
        return (0);
}


void printvar(name, desc, type, address)
     char *name;
     char *desc;
     VARTYPE type;
     char *address;
{
    int ival;

    switch (type) {
        case V_CHAR:
            sprintf(mbuf, " %-12s  %-16s   char   '%c'", name, desc, *address);
            break;
        case V_INT:
            memcpy(&ival, address, sizeof(int));
            sprintf(mbuf, " %-12s  %-16s   int    %d", name, desc, ival);
            break;
        case V_NONNEG:
            memcpy(&ival, address, sizeof(int));
            sprintf(mbuf, " %-12s  %-16s   nneg   %d", name, desc, ival);
            break;
        case V_BOOLEAN:
            memcpy(&ival, address, sizeof(int));
            sprintf(mbuf, " %-12s  %-16s   bool   %s", name, desc,
                    ival == 1 ? "true" : "false");
            break;
        case V_STRING:
            sprintf(mbuf, " %-12s  %-16s   str    \"%s\"", name, desc,
                    *(char **) address);
            break;
        default:
            sprintf(mbuf, "printvar unknown type %d for \"%8s\"", type, name);
            break;
    }
    putl(mbuf, PL_SCR);

    return;
}

/* perform a sanity check on some variables */
void varsanity()
{
    if (gv.pagesize < 0) {
        getwinsize();
        gv.pagesize = ttyinfo.rows - 1;
        if (gv.pagesize < 0)
            gv.pagesize = 0;
    }

    if (gv.pagesize > 500)
        gv.pagesize = 500;

    if (gv.bufferlines > 5000)
        gv.bufferlines = 5000;

    return;
}

void do_restrict()
{
    gv.restricted = TRUE;

    return;
}
