// ==========================================================================
//
//      serial.c
//
//      Public Domain Curses for eCos
//
// ===========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
//
// eCos 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 2 or (at your option) any later      
// version.                                                                 
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
// ===========================================================================
// ===========================================================================
// #####DESCRIPTIONBEGIN####
//
// Author(s):    Sergei Gavrikov
// Contributors: Sergei Gavrikov
// Date:         2009-04-24
// Purpose:      PDCurses driver for a serial device
// Description:
//
// ####DESCRIPTIONEND####
//
// ========================================================================*/

#include <cyg/kernel/kapi.h>           // cyg_thread_delay
#include <cyg/infra/diag.h>            // diagnostic routings
#include <stdlib.h>                    // free, calloc

// eCos serial devices
#include <cyg/io/io.h>
#include <pkgconf/io_serial.h>
#include <cyg/io/serialio.h>
#include <cyg/io/config_keys.h>

// PDCurses
#include <pkgconf/pdcurses.h>
#include <curspriv.h>

#define NDEBUG

#if CYGDAT_PDCURSES_DRIVER_USE_VT100_ATTR
# define ENABLE_VT100_ATTR
#endif
#if CYGDAT_PDCURSES_DRIVER_USE_ANSI_COLORS
# define ENABLE_COLOR
#endif
#if CYGDAT_PDCURSES_DRIVER_USE_KEYPAD_KEYS
# define ENABLE_KEYPAD
#endif

static char     device[] = CYGDAT_PDCURSES_DRIVER_SERIAL_DEV;
static cyg_io_handle_t handle = NULL;

// ---------------------------------------------------------------------------
// acs_map --
//
// A port of PDCurses must provide acs_map[], a 128-element array of chtypes,
// with values laid out based on the Alternate Character Set of the VT100
// (see curses.h). PDC_transform_line() must use this table; when it
// encounters a chtype with the A_ALTCHARSET flag set. For far details reffer
// to a pdcurses/IMPLEMNT document.

chtype          acs_map[128];
// ---------------------------------------------------------------------------

unsigned long   pdc_key_modifiers = 0L;

// ---------------------------------------------------------------------------
// atrtab --
//
// An attibutes table (it is used internally for the port's PDC_init_pair(),
// PDC_pair_content().

static struct {
    short           f,
                    b;
} atrtab[PDC_COLOR_PAIRS];
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// __gotoyx --
//
static void
__gotoyx(int y, int x)
{
    char            buf[8] = { '\033', '[', '0', '0', ';', '0', '0', 'H' };
    unsigned int    len = sizeof(buf);

    buf[2] = ((y + 1) / 10) + '0';
    buf[3] = ((y + 1) % 10) + '0';
    buf[5] = ((x + 1) / 10) + '0';
    buf[6] = ((x + 1) % 10) + '0';

    cyg_io_write(handle, buf, &len);
}

// ---------------------------------------------------------------------------
// PDC_gotoyx --
//
// Move the physical cursor (as opposed to the logical cursor affected by
// wmove()) to the given location. This is called mainly from doupdate(). In
// general, this function need not compare the old location with the new one,
// and should just move the cursor unconditionally.
// ---------------------------------------------------------------------------

void
PDC_gotoyx(int y, int x)
{

#ifdef DEBUG
    diag_printf("PDC_gotoyx called: x %d y %d\n", x, y);
#endif

    __gotoyx(y, x);

    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, NULL,
                      NULL);
}

// ---------------------------------------------------------------------------
// PDC_transform_line --
//
// The core output routine. It takes len chtype entities from srcp (a pointer
// into curscr) and renders them to the physical screen at line lineno,
// column x. It must also translate characters 0-127 via acs_map[], if
// they're flagged with A_ALTCHARSET in the attribute portion of the chtype.
// ---------------------------------------------------------------------------

static short    curstoansi[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
static chtype   prev_attr = A_PROTECT;

void
PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
{
    int             i;
    chtype          attr;

#ifdef DEBUG
    diag_printf("PDC_transform_line called: lineno %d curpos %d len %d\n",
                lineno, x, len);
#endif

    __gotoyx(lineno, x);

    for (i = 0; i < len; i++) {
        unsigned char   byte;
        chtype          ch = srcp[i];
        unsigned int    single = 1;

#if defined(ENABLE_COLOR) || defined(ENABLE_VT100_ATTR)
        attr = ch & A_ATTRIBUTES;
        // <ESC>[#; ... m
        if (prev_attr != attr) {
            short           fg,
                            bg,
                            pair;
            char            escape[32];
            unsigned int    count;

            count = 0;
            escape[count++] = '\x1b';
            escape[count++] = '[';
            escape[count++] = '0';
# ifdef ENABLE_COLOR
            pair = PAIR_NUMBER(attr);
            fg = curstoansi[atrtab[pair].f];
            bg = curstoansi[atrtab[pair].b];
            escape[count++] = ';';
            escape[count++] = '3';
            escape[count++] = '0' + fg;
            escape[count++] = ';';
            escape[count++] = '4';
            escape[count++] = '0' + bg;
# endif                         // ENABLE_COLOR
# ifdef ENABLE_VT100_ATTR
            if (attr & A_BOLD) {
                escape[count++] = ';';
                escape[count++] = '1';
            }
            if (attr & A_UNDERLINE) {
                escape[count++] = ';';
                escape[count++] = '4';
            }
            if (attr & A_BLINK) {
                escape[count++] = ';';
                escape[count++] = '5';
            }
            if (attr & A_REVERSE) {
                escape[count++] = ';';
                escape[count++] = '7';
            }
            if (attr & A_INVIS) {
                escape[count++] = ';';
                escape[count++] = '8';
            }
# endif                         // ENABLE_VT100_ATTR
            escape[count++] = 'm';
            cyg_io_write(handle, escape, &count);

            prev_attr = attr;
        }
#endif                          // ENABLE_COLOR || ENABLE_VT100_ATTR
#ifdef CHTYPE_LONG
        if (ch & A_ALTCHARSET && !(ch & 0xff80))
            ch = acs_map[ch & 0x7f];
#endif
        ch &= 0xff;
        byte = (unsigned char) ch;
        cyg_io_write(handle, &byte, &single);
    }

    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, NULL,
                      NULL);
}

// ---------------------------------------------------------------------------
// PDC_get_columns --
//
// Returns the size of the screen in columns. It's used in resize_term() to
// set the new value of COLS. (Some existing implementations also call it
// internally from PDC_scr_open(), but this is not required.)
// ---------------------------------------------------------------------------

int
PDC_get_columns(void)
{
    return CYGDAT_PDCURSES_DRIVER_SCREEN_COLUMNS;
}

// ---------------------------------------------------------------------------
// PDC_get_cursor_mode --
//
// Returns the size/shape of the cursor. The format of the result is
// unspecified, except that it must be returned as an int. This function is
// called from initscr(), and the result is stored in SP->orig_cursor, which
// is used by PDC_curs_set() to determine the size/shape of the cursor in
// normal visibility mode (curs_set(1)).
// ---------------------------------------------------------------------------

int
PDC_get_cursor_mode(void)
{
    return 0;
}

// ---------------------------------------------------------------------------
// PDC_get_rows --
//
// Returns the size of the screen in rows. It's used in resize_term() to set
// the new value of LINES. (Some existing implementations also call it
// internally from PDC_scr_open(), but this is not required.)
// ---------------------------------------------------------------------------

int
PDC_get_rows(void)
{
    return CYGDAT_PDCURSES_DRIVER_SCREEN_ROWS;
}

// ---------------------------------------------------------------------------
// PDC_check_key --
//
// Keyboard/mouse event check, called from wgetch(). Returns TRUE if there's
// an event ready to process. This function must be non-blocking.
// ---------------------------------------------------------------------------

static int      key_code = ERR;
static unsigned char keystroke[4] = { '\0', '\0', '\0', '\0' };

#define _FLSH_KEY() *(unsigned int *) &keystroke[0] = 0;
#if (CYG_BYTEORDER == CYG_LSBFIRST)
// Little endian
# define _UNGET_KEY(_n_)  *(unsigned int *) &keystroke[0] >>= 8*(_n_)
#elif (CYG_BYTEORDER == CYG_MSBFIRST)
// Big endian
# define _UNGET_KEY(_n_)  *(unsigned int *) &keystroke[0] <<= 8*(_n_)
#endif

bool
PDC_check_key(void)
{
    unsigned int    len,
                    count;
    cyg_serial_buf_info_t dev_buf_conf;

    len = sizeof(dev_buf_conf);
    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
                      &dev_buf_conf, &len);

#ifndef ENABLE_KEYPAD
    return (dev_buf_conf.rx_count > 0);
#else
    if ((count = dev_buf_conf.rx_count) > 0) {
        if (keystroke[0] == '\0') {
            count = min(count, 4);
            cyg_io_read(handle, &keystroke[0], &count);
        } else if (keystroke[1] == '\0') {
            count = min(count, 3);
            cyg_io_read(handle, &keystroke[1], &count);
        } else if (keystroke[2] == '\0') {
            count = min(count, 2);
            cyg_io_read(handle, &keystroke[2], &count);
        } else if (keystroke[3] == '\0') {
            count = min(count, 1);
            cyg_io_read(handle, &keystroke[3], &count);
        }
    }
    if (keystroke[0] == '\0')
        return FALSE;
    switch (keystroke[0]) {
    case '\x1b':
        switch (keystroke[1]) {
        case '[':
            switch (keystroke[2]) {
                // ^[[A -- KEY_UP
            case 'A':
                key_code = KEY_UP;
                _UNGET_KEY(3);
                return TRUE;
                // ^[[B -- KEY_DOWN
            case 'B':
                key_code = KEY_DOWN;
                _UNGET_KEY(3);
                return TRUE;
                // ^[[C -- KEY_RIGHT
            case 'C':
                key_code = KEY_RIGHT;
                _UNGET_KEY(3);
                return TRUE;
                // ^[[D -- KEY_LEFT
            case 'D':
                key_code = KEY_LEFT;
                _UNGET_KEY(3);
                return TRUE;
            case '1':
            case '4':
            case '5':
            case '6':
                switch (keystroke[3]) {
                case '~':
                    switch (keystroke[2]) {
                        // ^[[1~ -- KEY_HOME
                    case '1':
                        key_code = KEY_HOME;
                        _FLSH_KEY();
                        return TRUE;
                        // ^[[4~ -- KEY_END
                    case '4':
                        key_code = KEY_END;
                        _FLSH_KEY();
                        return TRUE;
                        // ^[[5~ -- KEY_PPAGE
                    case '5':
                        key_code = KEY_PPAGE;
                        _FLSH_KEY();
                        return TRUE;
                        // ^[[6~ -- KEY_NPAGE
                    case '6':
                        key_code = KEY_NPAGE;
                        _FLSH_KEY();
                        return TRUE;
                    }
                default:
                    break;
                }
            default:
                break;
            }
        case 'O':
            switch (keystroke[2]) {
                // ^[OF -- KEY_END
            case 'F':
                key_code = KEY_END;
                _UNGET_KEY(3);
                return TRUE;
                // ^[OH -- KEY_HOME
            case 'H':
                key_code = KEY_HOME;
                _UNGET_KEY(3);
                return TRUE;
            default:
                break;
            }
        default:
            break;
        }
    default:
        break;
    }
    key_code = keystroke[0];
    _UNGET_KEY(1);
    return TRUE;
#endif                          // ENABLE_KEYPAD
}

// ---------------------------------------------------------------------------
// PDC_flushinp --
//
// This is the core of flushinp(). It discards any pending key or mouse
// events, removing them from any internal queue and from the OS queue, if
// applicable.
// ---------------------------------------------------------------------------

void
PDC_flushinp(void)
{
    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH, NULL,
                      NULL);
#ifdef ENABLE_KEYPAD
    _FLSH_KEY();
#endif
}

// ---------------------------------------------------------------------------
// PDC_get_key --
//
// Get the next available key, or mouse event (indicated by a return of
// KEY_MOUSE), and remove it from the OS' input queue, if applicable. This
// function is called from wgetch(). This function may be blocking, and
// traditionally is; but it need not be. If a valid key or mouse event cannot
// be returned, for any reason, this function returns -1. For more details
// read `pdcurses/IMPLEMNT' document.
// ---------------------------------------------------------------------------

int
PDC_get_key(void)
{
#ifndef ENABLE_KEYPAD
    int             input = 0;
    unsigned int    count = 1;

    if (ENOERR == cyg_io_read(handle, &input, &count))
        return input;

    return ERR;
#else
    return key_code;
#endif                          // ENABLE_KEYPAD
}

// ---------------------------------------------------------------------------
// PDC_modifiers_set --
//
// Called from PDC_return_key_modifiers(). If your platform needs to do
// anything in response to a change in SP->return_key_modifiers, do it here.
// Returns OK or ERR, which is passed on by the caller.
// ---------------------------------------------------------------------------

int
PDC_modifiers_set(void)
{
    return ERR;
}

// ---------------------------------------------------------------------------
// PDC_mouse_set --
//
// Called by mouse_set(), mouse_on(), and mouse_off() -- all the functions
// that modify SP->_trap_mbe. If your platform needs to do anything in
// response to a change in SP->_trap_mbe (for example, turning the mouse
// cursor on or off), do it here. Returns OK or ERR, which is passed on by
// the caller.
// ---------------------------------------------------------------------------

int
PDC_mouse_set(void)
{
    return ERR;
}

// ---------------------------------------------------------------------------
// PDC_set_keyboard_binary --
//
// Set keyboard input to "binary" mode. If you need to do something to keep
// the OS from processing ^C, etc. on your platform, do it here. TRUE turns
// the mode on; FALSE reverts it. This function is called from raw() and
// noraw().
// ---------------------------------------------------------------------------

void
PDC_set_keyboard_binary(bool on)
{
#ifdef DEBUF
    diag_printf("PDC_set_keyboard_binary() called: on %d\n", on);
#endif
}

// ---------------------------------------------------------------------------
// PDC_can_change_color --
//
// Returns TRUE if init_color() and color_content() give meaningful results,
// FALSE otherwise. Called from can_change_color().
// ---------------------------------------------------------------------------

bool
PDC_can_change_color(void)
{
    return FALSE;
}

// ---------------------------------------------------------------------------
// PDC_color_content --
//
// The core of color_content(). This does all the work of that function,
// except checking for values out of range and null pointers.
// ---------------------------------------------------------------------------

int
PDC_color_content(short color, short *red, short *green, short *blue)
{
    return ERR;
}

// ---------------------------------------------------------------------------
// PDC_init_color --
//
// The core of init_color(). This does all the work of that function, except
// checking for values out of range.
// ---------------------------------------------------------------------------

int
PDC_init_color(short color, short red, short green, short blue)
{
    return ERR;
}

// ---------------------------------------------------------------------------
// PDC_init_pair --
//
// The core of init_pair(). This does all the work of that function, except
// checking for values out of range. The values passed to this function
// should be returned by a call to PDC_pair_content() with the same pair
// number. PDC_transform_line() should use the specified colors when
// rendering a chtype with the given pair number.
// ---------------------------------------------------------------------------

void
PDC_init_pair(short pair, short fg, short bg)
{
#ifdef DEBUG
    diag_printf("PDC_init_pair called: pair %d fg %d bg %d\n", pair, fg,
                bg);
#endif

    atrtab[pair].f = fg;
    atrtab[pair].b = bg;
}

// ---------------------------------------------------------------------------
// PDC_pair_content --
//
// The core of pair_content(). This does all the work of that function,
// except checking for values out of range and null pointers.
// ---------------------------------------------------------------------------

int
PDC_pair_content(short pair, short *fg, short *bg)
{
    *fg = atrtab[pair].f;
    *bg = atrtab[pair].b;

    return OK;
}

// ---------------------------------------------------------------------------
// PDC_reset_prog_mode --
//
// The non-portable functionality of reset_prog_mode() is handled here --
// whatever's not done in _restore_mode(). In current ports: In OS/2, this
// sets the keyboard to binary mode; in Win32, it enables or disables the
// mouse pointer to match the saved mode; in others it does nothing.
// ---------------------------------------------------------------------------

void
PDC_reset_prog_mode(void)
{
}

// ---------------------------------------------------------------------------
// PDC_reset_shell_mode --
//
// The same thing, for reset_shell_mode(). In OS/2 and Win32, it restores the
// default console mode; in others it does nothing.
// ---------------------------------------------------------------------------

void
PDC_reset_shell_mode(void)
{
}

// ---------------------------------------------------------------------------
// PDC_resize_screen --
//
// This does the main work of resize_term(). It may respond to non-zero
// parameters, by setting the screen to the specified size; to zero
// parameters, by setting the screen to a size chosen by the user at runtime,
// in an unspecified way (e.g., by dragging the edges of the window); or
// both. It may also do nothing, if there's no appropriate action for the
// platform.
// ---------------------------------------------------------------------------

int
PDC_resize_screen(int nlines, int ncols)
{
    if (nlines == 0 && ncols == 0)
        return OK;

    SP->resized = FALSE;
    SP->cursrow = SP->curscol = 0;

    return OK;

}

// ---------------------------------------------------------------------------
// PDC_restore_screen_mode --
//
// Called from _restore_mode() in kernel.c, this function does the actual
// mode changing, if applicable. Currently used only in DOS and OS/2.
// ---------------------------------------------------------------------------

void
PDC_restore_screen_mode(int i)
{
}

// ---------------------------------------------------------------------------
// PDC_save_screen_mode --
//
// Called from _save_mode() in kernel.c, this function saves the actual
// screen mode, if applicable. Currently used only in DOS and OS/2.
// ---------------------------------------------------------------------------

void
PDC_save_screen_mode(int i)
{
}

// ---------------------------------------------------------------------------
// PDC_scr_close --
//
// The platform-specific part of endwin(). It may restore the image of the
// original screen saved by PDC_scr_open(), if the PDC_RESTORE_SCREEN
// environment variable is set; either way, if using an existing terminal,
// this function should restore it to the mode it had at startup, and move
// the cursor to the lower left corner. (The X11 port does nothing.)
// ---------------------------------------------------------------------------

void
PDC_scr_close(void)
{
    handle = NULL;
}

// ---------------------------------------------------------------------------
// PDC_scr_free --
//
// Frees the memory for SP allocated by PDC_scr_open(). Called by
// delscreen().
// ---------------------------------------------------------------------------

void
PDC_scr_free(void)
{
#ifdef DEBUG
    diag_printf("PDC_scr_free called\n");
#endif

    if (SP)
        free(SP);
}

// ---------------------------------------------------------------------------
// PDC_scr_open --
//
// The platform-specific part of initscr(). It's actually called from
// Xinitscr(); the arguments, if present, correspond to those used with
// main(), and may be used to set the title of the terminal window, or for
// other, platform-specific purposes.
// ---------------------------------------------------------------------------

int
PDC_scr_open(int argc, char **argv)
{
    static bool     acs_map_init = false;

    int             i = 0;

#ifdef DEBUG
    diag_printf("PDC_scr_open called\n");
#endif

    if (NULL == handle) {
        unsigned int    wait = 0;
        unsigned int    len = sizeof(wait);

        if (ENOERR != cyg_io_lookup(device, &handle))
            return ERR;

        cyg_io_set_config(handle,
                          CYG_IO_SET_CONFIG_READ_BLOCKING, &wait, &len);
    }

    SP = calloc(1, sizeof(SCREEN));

    if (!SP)
        return ERR;

    SP->cols = PDC_get_columns();
    SP->lines = PDC_get_rows();
    SP->cursrow = SP->curscol = 0;
    SP->raw_inp = SP->raw_out = TRUE;

    if (!acs_map_init)
        for (i = 0; i < 128; i++) {
            // Square shapes, no more
            switch (i) {
            case 'j':
            case 'k':
            case 'l':
            case 'm':
                acs_map[i] = '+';
                break;
            case 'q':
                acs_map[i] = '-';
                break;
            case 'x':
                acs_map[i] = '|';
                break;
            default:
                acs_map[i] = (chtype) i | A_ALTCHARSET;
            }
        }

    return OK;
}

// ---------------------------------------------------------------------------
// PDC_curs_set --
//
// Called from curs_set(). Changes the appearance of the cursor -- 0 turns it
// off, 1 is normal (the terminal's default, if applicable, as determined by
// SP->orig_cursor), and 2 is high visibility. The exact appearance of these
// modes is not specified.
// ---------------------------------------------------------------------------

int
PDC_curs_set(int visibility)
{
    int             vis;
    char            buf[6] = { '\033', '[', '?', '2', '5', 'h' };
    unsigned int    len = sizeof(buf);

#ifdef DEBUG
    diag_printf("PDC_curs_set called: visibility %d\n", visibility);
#endif

    vis = SP->visibility;

    if (visibility)
        // <ESC>[?25h -- show cursor
        buf[5] = 'h';
    else
        // <ESC>[?25l -- hide cursor
        buf[5] = 'l';

    cyg_io_write(handle, buf, &len);
    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, NULL,
                      NULL);

    SP->visibility = vis;

    return vis;
}

// ---------------------------------------------------------------------------
// PDC_beep --
//
// Emits a short audible beep. If this is not possible on your platform, you
// must set SP->audible to FALSE during initialization (i.e., from
// PDC_scr_open() -- not here); otherwise, set it to TRUE. This function is
// called from beep().
// ---------------------------------------------------------------------------

void
PDC_beep(void)
{
    char            buf[1] = { '\007' };
    unsigned int    len = 1;

    cyg_io_write(handle, buf, &len);
    cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, NULL,
                      NULL);
}

// ---------------------------------------------------------------------------
// PDC_napms --
//
// This is the core delay routine, called by napms(). It pauses for about
// (the X/Open spec says "at least") ms milliseconds, then returns. High
// degrees of accuracy and precision are not expected (though desirable, if
// you can achieve them). More important is that this function gives back the
// process' time slice to the OS, so that PDCurses idles at low CPU usage.
// ---------------------------------------------------------------------------

void
PDC_napms(int ms)
{

    // There is alone call of napms() in current PDCurses implementation, its
    // aragument is 50 (50 of 1/20th second ticks).

    cyg_thread_delay(ms / 10);
}

// ---------------------------------------------------------------------------
// PDC_sysname --
//
// Returns a short string describing the platform, such as "DOS" or "X11".
// This is used by longname(). It must be no more than 100 characters; it
// should be much, much shorter (existing platforms use no more than 5).
// ---------------------------------------------------------------------------

const char     *
PDC_sysname(void)
{
    return "ECOS";
}

// ---------------------------------------------------------------------------
// PDC_getclipboard, PDC_clearclipboard, PDC_freeclipboard PDC_setclipboard,
// PDC_get_input_fd, PDC_set_blink, PDC_set_title --
//
// The following functions are implemented in the platform directories, but
// are accessed directly by apps. Refer to the user documentation for their
// descriptions:
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// PDC_getclipboard --
//
int
PDC_getclipboard(char **contents, long *length)
{
    return PDC_CLIP_ACCESS_ERROR;
}

// ---------------------------------------------------------------------------
// PDC_clearclipboard --
//
int
PDC_clearclipboard(void)
{
    return PDC_CLIP_ACCESS_ERROR;
}

// ---------------------------------------------------------------------------
// PDC_freeclipboard --
//
int
PDC_freeclipboard(char *contents)
{
    return PDC_CLIP_ACCESS_ERROR;
}

// ---------------------------------------------------------------------------
// PDC_setclipboard --
//
int
PDC_setclipboard(const char *contents, long length)
{
    return PDC_CLIP_ACCESS_ERROR;
}

// ---------------------------------------------------------------------------
// PDC_get_input_fd --
//
unsigned long
PDC_get_input_fd(void)
{
    return -1;
}

// ---------------------------------------------------------------------------
// PDC_set_blink --
//
int
PDC_set_blink(bool blinkon)
{
#ifdef DEBUG
    diag_printf("PDC_set_blink called: blinkon %d\n", blinkon);
#endif

    // start_color() guides that PDC_set_blink() should also set COLORS, to 8
    // or 16.
#ifdef ENABLE_COLOR
    COLORS = 8;
#else
    COLORS = 0;
#endif

    return blinkon ? ERR : OK;
}

// ---------------------------------------------------------------------------
// PDC_set_title --
//
void
PDC_set_title(const char *title)
{
}

// ---------------------------------------------------------------------------
// EOF serial.c
