Files
2ine-tms34010/native/viocalls.c
T
Ryan C. Gordon 6821de5ed7 Automate handling of support code for OS/2 binaries.
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.
2018-02-27 03:25:21 -05:00

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 ...