/*
 * Copyright (c) 2005 by Wayne C. Gramlich.
 * All rights reserved.
 */

/*
 * This module implements interfaces to the Unix terminal I/O system.
 */

#ifdef LINUX

#include "termios.h"
#include <unistd.h>
#include <string.h>
#include "stheaders.h"

enum fields {
    iflags,
    oflags,
    cflags,
    lflags,
    ctlflags,
    baudflags,
    optflags,
    flowflags,
    flushflags,
};

typedef struct termios Termios_struct, *TermIOS;
typedef struct name_value Name_value_struct, *Name_value;
typedef void *String;
typedef char *Str;

struct name_value {
    const char *name;
    unsigned value;
    enum fields field;
};

Name_value_struct name_values[] = {
    "IGNBRK", IGNBRK, iflags,
    "BRKINT", BRKINT, iflags,
    "IGNPAR", IGNPAR, iflags,
    "PARMRK", PARMRK, iflags,
    "INPCK", INPCK, iflags,
    "ISTRIP", ISTRIP, iflags,
    "INLCR", INLCR, iflags,
    "IGNCR", IGNCR, iflags,
    "ICRNL", ICRNL, iflags,
    "IUCLC", IUCLC, iflags,
    "IXON", IXON, iflags,
    "IXANY", IXANY, iflags,
    "IXOFF", IXOFF, iflags,
    "IMAXBEL", IMAXBEL, iflags,
    "OPOST", OPOST, oflags,
    "OLCUC", OLCUC, oflags,
    "ONLCR", ONLCR, oflags,
    "OCRNL", OCRNL, oflags,
    "ONOCR", ONOCR, oflags,
    "ONLRET", ONLRET, oflags,
    "OFILL", OFILL, oflags,
    "OFDEL", OFDEL, oflags,
    "NLDLY", NLDLY, oflags,
    "NL0", NL0, oflags,
    "NL1", NL1, oflags,
    "CRDLY", CRDLY, oflags,
    "CR0", CR0, oflags,
    "CR1", CR1, oflags,
    "CR2", CR2, oflags,
    "CR3", CR3, oflags,
    "TABDLY", TABDLY, oflags,
    "TAB0", TAB0, oflags,
    "TAB1", TAB1, oflags,
    "TAB2", TAB2, oflags,
    "TAB3", TAB3, oflags,
    "BSDLY", BSDLY, oflags,
    "BS0", BS0, oflags,
    "BS1", BS1, oflags,
    "VTDLY", VTDLY, oflags,
    "VT0", VT0, oflags,
    "VT1", VT1, oflags,
    "FFDLY", FFDLY, oflags,
    "FF0", FF0, oflags,
    "FF1", FF1, oflags,
    "CBAUD", CBAUD, cflags,
    "CBAUDEX", CBAUDEX, cflags,
    "CSIZE", CSIZE, cflags,
    "CS5", CS5, cflags,
    "CS6", CS6, cflags,
    "CS7", CS7, cflags,
    "CS8", CS8, cflags,
    "CSTOPB", CSTOPB, cflags,
    "CREAD", CREAD, cflags,
    "PARENB", PARENB, cflags,
    "PARODD", PARODD, cflags,
    "HUPCL", HUPCL, cflags,
    "CLOCAL", CLOCAL, cflags,
    /* "LOBLK", LOBLK, cflags, */
    "CIBAUD", CIBAUD, cflags,
    "CRTSCTS", CRTSCTS, cflags,
    "ISIG", ISIG, lflags,
    "ICANON", ICANON, lflags,
    "XCASE", XCASE, lflags,
    "ECHO", ECHO, lflags,
    "ECHOE", ECHOE, lflags,
    "ECHOK", ECHOK, lflags,
    "ECHONL", ECHONL, lflags,
    "ECHOCTL", ECHOCTL, lflags,
    "ECHOPRT", ECHOPRT, lflags,
    "ECHOKE", ECHOKE, lflags,
    /* "DEFECHO", DEFECHO, lflags, */
    "FLUSHO", FLUSHO, lflags,
    "NOFLSH", NOFLSH, lflags,
    "TOSTOP", TOSTOP, lflags,
    "PENDIN", PENDIN, lflags,
    "IEXTEN", IEXTEN, lflags,
    "VINTR", VINTR, ctlflags,
    "VQUIT", VQUIT, ctlflags,
    "VERASE", VERASE, ctlflags,
    "VKILL", VKILL, ctlflags,
    "VEOF", VEOF, ctlflags,
    "VMIN", VMIN, ctlflags,
    "VTIME", VTIME, ctlflags,
    "VEOL2", VEOL2, ctlflags,
    /* "VSWTCH", VSWTCH, ctlflags, */
    "VSTART", VSTART, ctlflags,
    "VSTOP", VSTOP, ctlflags,
    "VSUSP", VSUSP, ctlflags,
    /* "VDSUSP", VDSUSP, ctlflags, */
    "VLNEXT", VLNEXT, ctlflags,
    "VWERASE", VWERASE, ctlflags,
    "VREPRINT", VREPRINT, ctlflags,
    "VDISCARD", VDISCARD, ctlflags,
    /* "VSTATUS", VSTATUS, ctlflags, */
    "TCSANOW", TCSANOW, optflags,
    "TCSADRAIN", TCSADRAIN, optflags,
    "TCSAFLUSH", TCSAFLUSH, optflags,
    "TCIFLUSH", TCIFLUSH, flushflags,
    "TCOFLUSH", TCOFLUSH, flushflags,
    "TCIOFLUSH", TCIOFLUSH, flushflags,
    "TCOOFF", TCOOFF, flowflags,
    "TCOON", TCOON, flowflags,
    "TCIOFF", TCIOFF, flowflags,
    "TCION", TCION, flowflags,
    "B0", B0, baudflags,
    "B50", B50, baudflags,
    "B75", B75, baudflags,
    "B110", B110, baudflags,
    "B134", B134, baudflags,
    "B150", B150, baudflags,
    "B200", B200, baudflags,
    "B300", B300, baudflags,
    "B600", B600, baudflags,
    "B1200", B1200, baudflags,
    "B1800", B1800, baudflags,
    "B2400", B2400, baudflags,
    "B4800", B4800, baudflags,
    "B9600", B9600, baudflags,
    "B19200", B19200, baudflags,
    "B38400", B38400, baudflags,
    "B57600", B57600, baudflags,
    "B115200", B115200, baudflags,
    "B230400", B230400, baudflags,
    (char *)0, 0, 0,
};

extern Str string__unix_string(String);
extern module___object unix_termios__module__object;
extern type___reference unix_system_type_ref;

static Termios_struct termios_struct;
TermIOS termios___initial = &termios_struct;

static object___object termios_initial_object = {
    "",					/* Package name */
    "termios",				/* Type name */
    "??",				/* Object name */
    (type___reference *)0,		/*XXX: Fix me */
    (int *)0,				/* Size of character object */
    0,					/* Static needs count */
    (need___entry *)0,			/*XXX: Fix me Static needs */
    0,					/* Parameter needs count */
    (need___entry *)0,			/* Parameter needs */
    (void **)&termios___initial,	/* Object pointer */
    (instantiation___object *)0		/* Instantiation list */
};
static object___object *object_list[1] = {
	&termios_initial_object,
};

void
termios__external__initialize(void)
{
    extern module___object unix_termios__module__object;

    unix_termios__module__object.object_count = 1;
    unix_termios__module__object.objects = object_list;
}

unsigned
termios__field_lookup(
    String name)
{
    unsigned index;
    Name_value name_value;
    Str str_name;

    str_name = string__unix_string(name);
    for (name_value = &name_values[0];
       name_value->name != (Str)0; name_value++) {
	if (strcmp(name_value->name, str_name) == 0) {
	    return name_value->value;
	}
    }    
    return 0xffffffff;
}

TermIOS
termios__allocate(void)
{
    TermIOS termios;

    termios = (TermIOS)malloc(sizeof(Termios_struct));
    (void)memset((void *)termios, 0, sizeof(TermIOS));
    return termios;
}

unsigned
termios__input_modes_get(
    TermIOS termios)
{
    return termios->c_iflag;
}

unsigned
termios__output_modes_get(
    TermIOS termios)
{
    return termios->c_oflag;
}

unsigned
termios__control_modes_get(
    TermIOS termios)
{
    return termios->c_cflag;
}

unsigned
termios__local_modes_get(
    TermIOS termios)
{
    return termios->c_lflag;
}

unsigned
termios__fetch1(
    TermIOS termios,
    unsigned index)
{
    if (index >= NCCS) {
	return 0;
    }
    return termios->c_cc[index];
}

void
termios__input_modes_set(
    TermIOS termios,
    unsigned input_modes)
{
    termios->c_iflag = input_modes;
}

void
termios__output_modes_set(
    TermIOS termios,
    unsigned output_modes)
{
    termios->c_oflag = output_modes;
}

void
termios__control_modes_set(
    TermIOS termios,
    unsigned control_modes)
{
    termios->c_cflag = control_modes;
}

void
termios__local_modes_set(
    TermIOS termios,
    unsigned local_modes)
{
    termios->c_lflag = local_modes;
}

void
termios__store1(
    TermIOS termios,
    unsigned index,
    unsigned value)
{
    if (index <= NCCS) {
	termios->c_cc[index] = value;
    }
}

unsigned
termios__output_speed_get(
    TermIOS termios)
{
    return (unsigned)cfgetospeed(termios);
}

unsigned
termios__input_speed_get(
    TermIOS termios)
{
    return (unsigned)cfgetispeed(termios);
}

int
termios__output_speed_set(
    TermIOS termios,
    unsigned output_speed)
{
    return cfsetospeed(termios, output_speed);
}

int
termios__input_speed_set(
    TermIOS termios,
    unsigned input_speed)
{
    return (unsigned)cfsetispeed(termios, input_speed);
}

int
termios__speed_set(
    TermIOS termios,
    unsigned speed)
{
    return (unsigned)cfsetspeed(termios, speed);
}

int
termios__attributes_get(
    TermIOS termios,
    int fd)
{
    return tcgetattr(fd, termios);
}

int
termios__attributes_set(
    TermIOS termios,
    int fd,
    unsigned optional_actions)
{
    return tcsetattr(fd, optional_actions, termios);
}

int
termios__make_raw(
    TermIOS termios)
{
    cfmakeraw(termios);
    /* Man page says that it returns a value and the header file disagrees. */
    return 0;
}

int
termios__send_break(
    int fd,
    int duration)
{
    return tcsendbreak(fd, duration);
}

int
termios__drain(
    int fd)
{
    return tcdrain(fd);
}

int
termios__flush(
    int fd,
    int queue_selector)
{
    return tcflush(fd, queue_selector);
}

int
termios__flow(
    int fd,
    int action)
{
    return tcflow(fd, action);
}

int
termios__process_group_get(
    int fd)
{
    return tcgetpgrp(fd);
}

int
termios__process_group_set(
    int fd,
    int process_group_id)
{
    return tcsetpgrp(fd, process_group_id);
}

#endif /* LINUX */

#ifdef WINDOWS

#include "stheaders.h"
#include <assert.h>

#include "windows.h"

typedef struct termios Termios_struct, *TermIOS;
typedef void *String;
typedef char *Str;

struct termios {
    int zilch;
};

extern Str string__unix_string(String);
extern module___object unix_termios__module__object;
extern type___reference unix_system_type_ref;

static Termios_struct termios_struct;
TermIOS termios___initial = &termios_struct;

static object___object termios_initial_object = {
    "",					/* Package name */
    "termios",				/* Type name */
    "??",				/* Object name */
    (type___reference *)0,		/*XXX: Fix me */
    (int *)0,				/* Size of character object */
    0,					/* Static needs count */
    (need___entry *)0,			/*XXX: Fix me Static needs */
    0,					/* Parameter needs count */
    (need___entry *)0,			/* Parameter needs */
    (void **)&termios___initial,	/* Object pointer */
    (instantiation___object *)0		/* Instantiation list */
};
static object___object *object_list[1] = {
    &termios_initial_object,
};

void
termios__external__initialize(void)
{
    extern module___object unix_termios__module__object;

    unix_termios__module__object.object_count = 1;
    unix_termios__module__object.objects = object_list;
}

unsigned
termios__field_lookup(
    String name)
{
    assert(0);
}

TermIOS
termios__allocate(void)
{
    assert(0);
}

unsigned
termios__input_modes_get(
    TermIOS termios)
{
    assert(0);
}

unsigned
termios__output_modes_get(
    TermIOS termios)
{
    assert(0);
}

unsigned
termios__control_modes_get(
    TermIOS termios)
{
    assert(0);
}

unsigned
termios__local_modes_get(
    TermIOS termios)
{
    assert(0);
}

unsigned
termios__fetch1(
    TermIOS termios,
    unsigned index)
{
    assert(0);
}

void
termios__input_modes_set(
    TermIOS termios,
    unsigned input_modes)
{
    assert(0);
}

void
termios__output_modes_set(
    TermIOS termios,
    unsigned output_modes)
{
    assert(0);
}

void
termios__control_modes_set(
    TermIOS termios,
    unsigned control_modes)
{
    assert(0);
}

void
termios__local_modes_set(
    TermIOS termios,
    unsigned local_modes)
{
    assert(0);
}

void
termios__store1(
    TermIOS termios,
    unsigned index,
    unsigned value)
{
    assert(0);
}

unsigned
termios__output_speed_get(
    TermIOS termios)
{
    assert(0);
}

unsigned
termios__input_speed_get(
    TermIOS termios)
{
    assert(0);
}

int
termios__output_speed_set(
    TermIOS termios,
    unsigned output_speed)
{
    assert(0);
}

int
termios__input_speed_set(
    TermIOS termios,
    unsigned input_speed)
{
    assert(0);
}

int
termios__speed_set(
    TermIOS termios,
    unsigned speed)
{
    assert(0);
}

int
termios__attributes_get(
    TermIOS termios,
    int fd)
{
    assert(0);
}

int
termios__attributes_set(
    TermIOS termios,
    int fd,
    unsigned optional_actions)
{
    assert(0);
}

void
termios__make_raw(
    TermIOS termios)
{
    assert(0);
}

int
termios__send_break(
    int fd,
    int duration)
{
    assert(0);
}

int
termios__drain(
    int fd)
{
    assert(0);
}

int
termios__flush(
    int fd,
    int queue_selector)
{
    assert(0);
}

int
termios__flow(
    int fd,
    int action)
{
    assert(0);
}

int
termios__process_group_get(
    int fd)
{
    assert(0);
}

int
termios__process_group_set(
    int fd,
    int process_group_id)
{
    assert(0);
}

#endif /* WINDOWS */
