Now a perl script parses our headers and generates glue code, export tables, etc. This automates all the macro nonsense and bridge code, and separates out all the stuff you need for binary compat with OS/2, so you can remove it all from the build if you want to just build native libraries that supply the OS/2 API to native apps (like Winelib vs Wine). This makes upkeep details less nasty, and easier to build native binaries when implementing and improving APIs, so you can debug directly without a lot of drama.
490 lines
15 KiB
C
490 lines
15 KiB
C
/**
|
|
* 2ine; an OS/2 emulator for Linux.
|
|
*
|
|
* Please see the file LICENSE.txt in the source's root directory.
|
|
*
|
|
* This file written by Ryan C. Gordon.
|
|
*/
|
|
|
|
#include "os2native16.h"
|
|
#include "viocalls.h"
|
|
|
|
// os2types.h defines these, but so does curses.
|
|
#undef TRUE
|
|
#undef FALSE
|
|
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
// CMake searches for a whole bunch of different possible curses includes
|
|
#if defined(HAVE_NCURSESW_NCURSES_H)
|
|
#include <ncursesw/ncurses.h>
|
|
#elif defined(HAVE_NCURSESW_CURSES_H)
|
|
#include <ncursesw/curses.h>
|
|
#elif defined(HAVE_NCURSESW_H)
|
|
#include <ncursesw.h>
|
|
#elif defined(HAVE_CURSES_H)
|
|
#include <curses.h>
|
|
#else
|
|
#error ncurses gui enabled, but no known header file found
|
|
#endif
|
|
|
|
#include <locale.h>
|
|
|
|
#include "viocalls-lx.h"
|
|
|
|
enum
|
|
{
|
|
VIOATTR_BACK_BLACK = 0x00,
|
|
VIOATTR_BACK_BLUE = 0x10,
|
|
VIOATTR_BACK_GREEN = 0x20,
|
|
VIOATTR_BACK_CYAN = 0x30,
|
|
VIOATTR_BACK_RED = 0x40,
|
|
VIOATTR_BACK_MAGENTA = 0x50,
|
|
VIOATTR_BACK_YELLOW = 0x60,
|
|
VIOATTR_BACK_BROWN = 0x60,
|
|
VIOATTR_BACK_WHITE = 0x70,
|
|
|
|
VIOATTR_FORE_BLACK = 0x00,
|
|
VIOATTR_FORE_BLUE = 0x01,
|
|
VIOATTR_FORE_GREEN = 0x02,
|
|
VIOATTR_FORE_CYAN = 0x03,
|
|
VIOATTR_FORE_RED = 0x04,
|
|
VIOATTR_FORE_MAGENTA = 0x05,
|
|
VIOATTR_FORE_YELLOW = 0x06,
|
|
VIOATTR_FORE_BROWN = 0x06,
|
|
VIOATTR_FORE_WHITE = 0x07,
|
|
|
|
VIOATTR_INTENSITY = 0x08,
|
|
VIOATTR_BLINK = 0x80
|
|
};
|
|
|
|
|
|
static uint16 *vio_buffer = NULL;
|
|
static uint16 vio_scrw, vio_scrh;
|
|
static uint16 vio_curx, vio_cury;
|
|
static VIOCURSORINFO vio_cursorinfo;
|
|
|
|
static int initNcurses(void)
|
|
{
|
|
if (vio_buffer != NULL)
|
|
return 1;
|
|
|
|
setlocale(LC_CTYPE, ""); // !!! FIXME: we assume you have a UTF-8 terminal.
|
|
if (initscr() == NULL) {
|
|
fprintf(stderr, "ncurses: initscr() failed\n");
|
|
return 0;
|
|
} // if
|
|
|
|
cbreak();
|
|
keypad(stdscr, TRUE);
|
|
noecho();
|
|
start_color();
|
|
use_default_colors();
|
|
|
|
// map to VIO attributes...
|
|
static const short curses_colormap[] = {
|
|
COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
|
|
COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE
|
|
};
|
|
|
|
if (COLORS >= 64) { // foreground and background
|
|
for (uint32 i = 0; i < 8; i++) {
|
|
for (uint32 j = 0; j < 8; j++) {
|
|
const int pair = (int) (i | (j << 3));
|
|
init_pair(pair, curses_colormap[i], (j == 0) ? -1 : curses_colormap[j]);
|
|
} // for
|
|
} // for
|
|
} else if (COLORS >= 8) { // just foregrounds
|
|
for (int i = 0; i < 8; i++)
|
|
init_pair(i, curses_colormap[i], COLOR_BLACK);
|
|
} // else if
|
|
|
|
// (otherwise, we won't set colors at all.)
|
|
|
|
int scrh, scrw;
|
|
getmaxyx(stdscr, scrh, scrw);
|
|
|
|
const size_t buflen = scrw * scrh * sizeof (uint16);
|
|
vio_buffer = malloc(buflen);
|
|
if (!vio_buffer) {
|
|
endwin();
|
|
delwin(stdscr); // not sure if this is safe, but valgrind said it leaks.
|
|
stdscr = NULL;
|
|
return 0;
|
|
} // if
|
|
|
|
memset(vio_buffer, '\0', buflen);
|
|
vio_scrw = (uint16) scrw;
|
|
vio_scrh = (uint16) scrh;
|
|
vio_curx = vio_cury = 0;
|
|
|
|
FIXME("these are just the default values OS/2 4.52 returns");
|
|
vio_cursorinfo.yStart = 15;
|
|
vio_cursorinfo.cEnd = 15;
|
|
vio_cursorinfo.cx = 1;
|
|
vio_cursorinfo.attr = 0;
|
|
|
|
return 1;
|
|
} // initNcurses
|
|
|
|
static void deinitNcurses(void)
|
|
{
|
|
if (!vio_buffer)
|
|
return;
|
|
|
|
// !!! FIXME: this is wrong
|
|
//endwin();
|
|
reset_shell_mode();
|
|
|
|
printf("\n"); fflush(stdout);
|
|
|
|
delwin(stdscr); // not sure if this is safe, but valgrind said it leaks.
|
|
stdscr = NULL;
|
|
free(vio_buffer);
|
|
vio_buffer = NULL;
|
|
vio_curx = vio_cury = vio_scrw = vio_scrh = 0;
|
|
} // deinitNcurses
|
|
|
|
static inline void commitToNcurses(void)
|
|
{
|
|
refresh();
|
|
} // commitToNcurses
|
|
|
|
static void pushToNcurses(const int y, const int x, int numcells, const int commit)
|
|
{
|
|
const uint8 *src = (const uint8 *) (vio_buffer + ((y * vio_scrw) + x));
|
|
const uint32 avail = (((vio_scrh - y) * vio_scrw) - x);
|
|
if (numcells > avail)
|
|
numcells = avail;
|
|
|
|
move(y, x);
|
|
|
|
for (int i = 0; i < numcells; i++) {
|
|
const uint8 viochar = *(src++);
|
|
const uint8 vioattr = *(src++);
|
|
|
|
chtype ch;
|
|
switch (viochar) {
|
|
case 0xC4: ch = ACS_HLINE; break;
|
|
case 0xB3: ch = ACS_VLINE; break;
|
|
case 0xDA: ch = ACS_ULCORNER; break;
|
|
case 0xBF: ch = ACS_URCORNER; break;
|
|
case 0xC0: ch = ACS_LLCORNER; break;
|
|
case 0xD9: ch = ACS_LRCORNER; break;
|
|
default: ch = (chtype) viochar; break;
|
|
} // switch
|
|
|
|
chtype attr = 0;
|
|
|
|
if (COLORS >= 64) { // foreground and background
|
|
const int color = ((vioattr & 0x70) >> 1) | (vioattr & 0x7);
|
|
attr |= COLOR_PAIR(color);
|
|
} else if (COLORS >= 8) { // just foregrounds
|
|
const int color = (vioattr & 0x7);
|
|
attr |= COLOR_PAIR(color);
|
|
} // else if
|
|
|
|
if (vioattr & VIOATTR_INTENSITY)
|
|
attr |= A_BOLD;
|
|
if (vioattr & VIOATTR_BLINK)
|
|
attr |= A_BLINK;
|
|
|
|
addch(ch | attr);
|
|
} // for
|
|
|
|
move(vio_cury, vio_curx);
|
|
|
|
if (commit)
|
|
commitToNcurses();
|
|
} // pushToNcurses
|
|
|
|
APIRET16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetMode(%p, %u)", pvioModeInfo, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pvioModeInfo == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (pvioModeInfo->cb != sizeof (*pvioModeInfo))
|
|
return ERROR_VIO_INVALID_LENGTH;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
memset(pvioModeInfo, '\0', sizeof (*pvioModeInfo));
|
|
pvioModeInfo->cb = sizeof (*pvioModeInfo);
|
|
pvioModeInfo->fbType = VGMT_OTHER;
|
|
pvioModeInfo->color = 4;
|
|
pvioModeInfo->col = vio_scrw;
|
|
pvioModeInfo->row = vio_scrh;
|
|
pvioModeInfo->hres = 640;
|
|
pvioModeInfo->vres = 400;
|
|
pvioModeInfo->fmt_ID = 0;
|
|
pvioModeInfo->attrib = 1;
|
|
FIXME("fill in the rest of these");
|
|
//ULONG buf_addr;
|
|
//ULONG buf_length;
|
|
//ULONG full_length;
|
|
//ULONG partial_length;
|
|
//PCHAR ext_data_addr;
|
|
|
|
return NO_ERROR;
|
|
} // VioGetMode
|
|
|
|
APIRET16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetCurPos(%p, %p, %u)", pusRow, pusColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
if (pusRow)
|
|
*pusRow = vio_cury;
|
|
|
|
if (pusColumn)
|
|
*pusColumn = vio_curx;
|
|
|
|
return NO_ERROR;
|
|
} // VioGetCurPos
|
|
|
|
APIRET16 VioGetBuf(PULONG pLVB, PUSHORT pcbLVB, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetBuf(%p, %p, %u)", pLVB, pcbLVB, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
if (pLVB)
|
|
*pLVB = (ULONG) vio_buffer;
|
|
if (pcbLVB)
|
|
*pcbLVB = vio_scrw * vio_scrh * sizeof (ULONG);
|
|
return NO_ERROR;
|
|
} // VioGetBuf
|
|
|
|
APIRET16 VioGetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetCurType(%p, %u)", pvioCursorInfo, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pvioCursorInfo == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
memcpy(pvioCursorInfo, &vio_cursorinfo, sizeof (*pvioCursorInfo));
|
|
return NO_ERROR;
|
|
} // VioGetCurType
|
|
|
|
APIRET16 VioScrollUp(USHORT usTopRow, USHORT usLeftCol, USHORT usBotRow, USHORT usRightCol, USHORT cbLines, PBYTE pCell, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioScrollUp(%u, %u, %u, %u, %u, %p, %u)", (uint) usTopRow, (uint) usLeftCol, (uint) usBotRow, (uint) usRightCol, (uint) cbLines, pCell, (uint) hvio);
|
|
FIXME("buggy");
|
|
return NO_ERROR; // !!! FIXME: buggy
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pCell == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
if (usLeftCol >= vio_scrw)
|
|
usLeftCol = vio_scrw - 1;
|
|
if (usRightCol >= vio_scrw)
|
|
usRightCol = vio_scrw - 1;
|
|
if (usTopRow >= vio_scrh)
|
|
usTopRow = vio_scrh - 1;
|
|
if (usBotRow >= vio_scrh)
|
|
usBotRow = vio_scrh - 1;
|
|
|
|
if (usLeftCol >= usRightCol)
|
|
return NO_ERROR; // already done.
|
|
else if (usTopRow >= usBotRow)
|
|
return NO_ERROR; // already done.
|
|
else if (cbLines == 0)
|
|
return NO_ERROR; // already done.
|
|
|
|
const uint32 rowlen = (usRightCol - usLeftCol) + 1;
|
|
const uint32 overlines = (cbLines > usTopRow) ? (cbLines - usTopRow) : 0;
|
|
const uint32 collen = ((usBotRow - usTopRow) + 1) - overlines;
|
|
const uint32 adjust = overlines * vio_scrw;
|
|
|
|
uint16 *src = vio_buffer + ((usTopRow * vio_scrw) + usLeftCol) + adjust;
|
|
uint16 *dst = (src - (cbLines * vio_scrw)) + adjust;
|
|
const size_t rowcpylen = rowlen * sizeof (uint16);
|
|
for (uint32 i = 0; i < collen; i++) {
|
|
memcpy(dst, src, rowcpylen);
|
|
src += vio_scrw;
|
|
dst += vio_scrw;
|
|
} // for
|
|
|
|
const uint16 clear_cell = *((uint16 *) pCell);
|
|
for (uint32 i = 0; i < cbLines; i++) {
|
|
if (dst >= (vio_buffer + (vio_scrw * vio_scrh)))
|
|
break; // !!! FIXME: just calculate this outside the loop and adjust cbLines.
|
|
uint16 *origdst = dst;
|
|
for (uint32 j = 0; j < rowlen; j++) {
|
|
*(dst++) = clear_cell;
|
|
}
|
|
dst = origdst + vio_scrw;
|
|
} // for
|
|
|
|
int starty = usTopRow - cbLines;
|
|
if (starty < 0)
|
|
starty = 0;
|
|
int endy = starty + collen + cbLines;
|
|
if (endy >= vio_scrh)
|
|
endy = vio_scrh;
|
|
|
|
for (int y = starty; y < endy; y++)
|
|
pushToNcurses(y, usLeftCol, rowlen, 0);
|
|
commitToNcurses();
|
|
|
|
return NO_ERROR;
|
|
} // VioScrollUp
|
|
|
|
APIRET16 VioSetCurPos(USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioSetCurPos(%u, %u, %u)", (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
vio_cury = usRow;
|
|
vio_curx = usColumn;
|
|
|
|
move(vio_cury, vio_curx);
|
|
refresh();
|
|
|
|
return NO_ERROR;
|
|
} // VioSetCurPos
|
|
|
|
APIRET16 VioSetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioSetCurType(%p, %u)", pvioCursorInfo, (uint) hvio);
|
|
FIXME("write me");
|
|
return NO_ERROR;
|
|
} // VioSetCurType
|
|
|
|
APIRET16 VioReadCellStr(PCH pchCellStr, PUSHORT pcb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioReadCellStr(%p, %p, %u, %u, %u)", pchCellStr, pcb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint32 maxidx = ((uint32)vio_scrh) * ((uint32)vio_scrw);
|
|
const uint32 idx = (((uint32)usRow) * ((uint32)vio_scrw)) + ((uint32)usColumn);
|
|
const uint32 avail = (maxidx - idx) * sizeof (uint16);
|
|
if (((uint32) *pcb) > avail)
|
|
*pcb = (USHORT) avail;
|
|
memcpy(pchCellStr, vio_buffer + idx, (size_t) *pcb);
|
|
return NO_ERROR;
|
|
} // VioReadCellStr
|
|
|
|
APIRET16 VioWrtCellStr(PCH pchCellStr, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtCellStr(%p, %u, %u, %u, %u)", pchCellStr, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint16 *src = (uint16 *) pchCellStr;
|
|
uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn);
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn) * sizeof (uint16);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
memcpy(dst, src, cb); // !!! FIXME: what happens if cb extends into half a cell?
|
|
|
|
pushToNcurses(usRow, usColumn, cb / sizeof (uint16), 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtCellStr
|
|
|
|
APIRET16 VioWrtCharStrAtt(PCH pch, USHORT cb, USHORT usRow, USHORT usColumn, PBYTE pAttr, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtCharStrAtt(%p, %u, %u, %u, %p, %u)", pch, (uint) cb, (uint) usRow, (uint) usColumn, pAttr, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint8 attr = *pAttr;
|
|
const uint8 *src = (uint8 *) pch;
|
|
uint8 *dst = (uint8 *) (vio_buffer + ((usRow * vio_scrw) + usColumn));
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
for (uint32 i = 0; i < cb; i++, src++) {
|
|
*(dst++) = *src;
|
|
*(dst++) = attr;
|
|
} // for
|
|
|
|
pushToNcurses(usRow, usColumn, cb, 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtCharStrAtt
|
|
|
|
APIRET16 VioWrtNCell(PBYTE pCell, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtNCell(%p, %u, %u, %u, %u)", pCell, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint16 cell = *((uint16 *) pCell);
|
|
uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn);
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
for (uint32 i = 0; i < cb; i++)
|
|
*(dst++) = cell;
|
|
|
|
pushToNcurses(usRow, usColumn, cb, 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtNCell
|
|
|
|
LX_NATIVE_DESTRUCTOR(viocalls)
|
|
{
|
|
deinitNcurses();
|
|
}
|
|
|
|
// end of viocalls.c ...
|
|
|