#define WIN32_ONLY
#include <posix/sys/types.h>
#include <posix/termios.h>
#include "psxses.h"
#include "ansiio.h"
#include <io.h>
#include <stdio.h>
#include <ctype.h>

extern DWORD OutputModeFlags;        /* Console Output Mode */ 
extern DWORD InputModeFlags;
extern unsigned char AnsiNewMode;
extern struct termios SavedTermios;

/* DFC: New globals (from trans.h) */
WORD  ansi_attr;      /* attribute of TTY */
WORD  ansi_attr1;     /* MSKK : leave space for 3 attr */
WORD  ansi_attr2;     /* MSKK : leave space for 3 attr */
SHORT ScreenColNum;   /* col number */ 
SHORT ScreenRowNum;   /* row number */ 
BYTE  CarriageReturn;

COORD 	TrackedCoord,
	CurrentCoord;

DWORD TTYConBeep(void);

static BYTE ColorTable[8] = { 0,   /* Black   */
                              4,   /* Red     */
                              2,   /* Green   */
                              6,   /* Yellow  */
                              1,   /* Blue    */
                              5,   /* Magenta */
                              3,   /* Cyan    */
                              7};  /* White   */

DWORD
TermioInit(void)
{
    CONSOLE_SCREEN_BUFFER_INFO  ScreenInfo1;
    BOOL Success;

    ansi_state = NOCMD; /* state of machine */
    ignore_next_char = 0;
#if 0
    ansi_base = ansi_attr = 0x07; /* white on black */
#endif
    ansi_reverse = 0;

    InputModeFlags = (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
    OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT;
    AnsiNewMode = FALSE;

    if (!SetConsoleMode(hConsoleInput, InputModeFlags)) {
	KdPrint(("posix - can't set console mode: 0x%x\n", GetLastError()));
    }

    /* Set default termio parameters */
    SavedTermios.c_iflag = BRKINT|ICRNL;
    SavedTermios.c_oflag = OPOST|ONLCR;
    SavedTermios.c_cflag = CREAD|CS8;
    SavedTermios.c_lflag = ICANON|ECHO|ECHOE|ECHOK|ISIG;

    SavedTermios.c_cc[VEOF] = CTRL('Z');
    SavedTermios.c_cc[VEOL] = 0;		// _POSIX_VDISABLE
    SavedTermios.c_cc[VERASE] = CTRL('H');
    SavedTermios.c_cc[VINTR] = CTRL('C');
    SavedTermios.c_cc[VKILL] = CTRL('X');
    SavedTermios.c_cc[VQUIT] = CTRL('\\');
    SavedTermios.c_cc[VSUSP] = CTRL('Y');
    SavedTermios.c_cc[VSTOP] = CTRL('S');
    SavedTermios.c_cc[VSTART] = CTRL('Q');

    SavedTermios.c_ospeed = B9600;
    SavedTermios.c_ispeed = B9600;

    Success = GetConsoleScreenBufferInfo(hConsoleOutput, &ScreenInfo1);
    if (!Success) {
	return Success;
    }
    
    ansi_base = ansi_attr = ScreenInfo1.wAttributes;
    ansi_attr1 = ansi_attr2 = 0;

	ScreenRowNum = ScreenInfo1.dwSize.Y;
	ScreenColNum = ScreenInfo1.dwSize.X;

    CurrentCoord.Y = TrackedCoord.Y = ScreenInfo1.dwCursorPosition.Y + 1;
    CurrentCoord.X = TrackedCoord.X = ScreenInfo1.dwCursorPosition.X + 1;

    return (DWORD) 0;
}

/*
** TermOutput(SourStr, cnt) - pass characters to the finite state machine
**      SourStr points to the array of characters
**      cnt indicates how many characters are being passed.
*/

DWORD
TermOutput(
    IN HANDLE cs,
    IN LPSTR SourStr,
    IN DWORD cnt)
{
    register CHAR c;
    USHORT NewCoord, ToFlash;
    DWORD Rc = 0, orig_cnt = cnt;
    BOOL SetModeOn, OldWrap, NewWrap;
    CONSOLE_SCREEN_BUFFER_INFO ScreenInfo1;

    //
    // Kludge because we don't know how many carriage returns we received
    // as input, thereby impeding TermOutput()'s ability to track the
    // cursor coordinate accurately
    //

    GetConsoleScreenBufferInfo(cs, &ScreenInfo1);
    CurrentCoord.Y = TrackedCoord.Y =  ScreenInfo1.dwCursorPosition.Y + 1;
    CurrentCoord.X = TrackedCoord.X =  ScreenInfo1.dwCursorPosition.X + 1;

    NewCoord = 0;
    CarriageReturn = 0;
    TTYOldCtrlCharInStr = TRUE;
    TTYCtrlCharInStr = FALSE;
    TTYcs = cs;
    TTYTextPtr = SourStr;
    TTYNumBytes = 0;

    //
    // Stop output, if VSTOP has been encountered
    //

    if (bStop) {
	RtlEnterCriticalSection(&StopMutex);
	if (bStop) {
	    RtlLeaveCriticalSection(&StopMutex);
	    WaitForSingleObject(hStopEvent, INFINITE);
	} else {
	    RtlLeaveCriticalSection(&StopMutex);
	}
    }

    while (cnt--) {
        c = *SourStr++;

        switch (ansi_state) {
        case NOCMD:
            if (c == ANSI_ESC) {
                //
                // Make sure buffer is flushed and cursor position is
                // up-to-date before processing next esc-seq
                //
                if ( (Rc = TTYFlushStr(&NewCoord, "1")) != 0 ) {
                        KdPrint(("PSXSES(trans-TTY): failed on "
                          "TTYFlushStr #1\n"));
                        return (DWORD) -1;
                }
                ansi_state = ESCED;
                break;
            } else {
                if (isprint(c)) { /* Printable char found */

                    TTYNumBytes++;
                    TrackedCoord.X++;

                } else {
		    /* Non-printable char found */

                    ToFlash = TRUE;
                    switch ( c ) {
                    case '\n':
new_line:
                        if (SavedTermios.c_oflag & OPOST) {
                            if (c == '\n' &&
                              (SavedTermios.c_oflag & ONLCR)) {
				TrackedCoord.Y++;
                                goto carriage_return;
                            }
			    if (SavedTermios.c_oflag & ONLRET) {
#if 0
                                TrackedCoord.X = 1;
#endif
                                CarriageReturn = 1;
                            }
                        }
                        TrackedCoord.Y++;
                        NewCoord = 1;
                        break;

                    case '\r':
carriage_return:
                        if ( SavedTermios.c_oflag & OPOST ) {
                            if ( c == '\r' &&
                              (SavedTermios.c_oflag & OCRNL) ) {
                                goto new_line;
                            } else if ( ! (SavedTermios.c_oflag & ONOCR) ||
                              TrackedCoord.X != 1 ) {
#if 0
                                TrackedCoord.X = 1;
#endif
                                NewCoord = 1;
                                CarriageReturn = 1;
                            }
                        } else {
                            if ( TrackedCoord.X > 1 ) {
                                TrackedCoord.X = 1;
                                NewCoord = 1;
                                CarriageReturn = 1;
                            }
                        }
                        break;

                    case '\b':
                        if ( TrackedCoord.X > 1 ) {
                            TrackedCoord.X--;
                            NewCoord = 1;
                        }
                        break;

                    case '\t':
                        TrackedCoord.X += (8 - ((TrackedCoord.X - 1) % 8));

			// Handle wrap after tab

			if (TrackedCoord.X > ScreenColNum) {
		            if (OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) {
		                TrackedCoord.Y += ((TrackedCoord.X) / ScreenColNum);
		                TrackedCoord.X = (TrackedCoord.X % ScreenColNum);
		            } else {
		                TrackedCoord.X = ScreenColNum;
		            }
			}
                        NewCoord = 1;
                        break;

                    case '\a':
                        if ( (Rc = TTYConBeep()) != 0 ) {
                            KdPrint(("PSXSES(trans-TTY): failed on "
                                "BEEP\n"));
                            return (DWORD) -1;
                        }
                        break;

                    default:
                        TTYCtrlCharInStr = TRUE;
                        ToFlash = FALSE;
#if 0
                        TTYNumBytes++;
                        TrackedCoord.X++;
#endif
                        break;
                    } /* switch */

                    if ( ToFlash ) { /* Flush */
                        //
                        // Flush carriage control chars to update cursor
                        // position
                        //
                        if ((Rc = TTYFlushStr(&NewCoord, "2")) != 0) {
                            return (DWORD)-1;
                        }

                        TTYTextPtr = SourStr;
                    }
                } /* isprint */
            } /* ANSI_ESC */
            break;

        case ESCED:
            switch ( c ) {
            case '[':
                ansi_state = PARAMS;
                SetModeOn = TRUE;
                clrparam();
                break;

            default:
                ansi_state = NOCMD;
                TTYTextPtr = SourStr - 1;
                cnt++ ;
                SourStr--;
                break;
            }
            break;

        case PARAMS:
            if ( isdigit(c) ) {
                ansi_param[ansi_pnum] *= 10;
                ansi_param[ansi_pnum] += (c - '0');
                SetModeOn = FALSE;
            } else if ( c == ';' ) {
                if ( ansi_pnum < (NPARMS - 1) )
                    ++ansi_pnum;
                else {
                    ansi_state = NOCMD;
                    TTYTextPtr = SourStr;
                }
            } else if ( (c == '=') && SetModeOn ) { /* maybe set/reset mode */
                ansi_state = MODCMD;
            } else {
                ansi_state = NOCMD;
                if ( (Rc = ansicmd(cs, c)) != 0 ) {
                    return (DWORD) -1;
                }
                TTYTextPtr = SourStr;
                NewCoord = 1;
                if ( (Rc = TTYFlushStr(&NewCoord, "3")) != 0 ) {
#if 0
                     return (DWORD) -1;
#endif
                }
            }
            break;

        case MODCMD:
            if ( ansi_pnum == 1 ) {

                if ( c == 'h' || c == 'l' ) {

                    if ( ansi_param[0] == 7 ) {

                        OldWrap = ((OutputModeFlags &
                            ENABLE_WRAP_AT_EOL_OUTPUT) != 0);
                        NewWrap = (c == 'h');

                        if ( OldWrap != NewWrap ) {

                            if ( (Rc = !SetConsoleMode(cs,
                              OutputModeFlags^ENABLE_WRAP_AT_EOL_OUTPUT))
                              != 0 ) {
                                return (DWORD) -1;
                            }

                            OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT;
#if 0
                        } else {
                            OutputModeFlags ~= ENABLE_WRAP_AT_EOL_OUTPUT;
#endif
                        }
                    }

                    TTYTextPtr = SourStr;

                } else {
                    TTYTextPtr = SourStr - 5;
                    TTYNumBytes = 5;
                }

            } else if ( c >= '0' && c <= '7' ) {
                ansi_param[0] = (USHORT) (c - '0');
                ansi_pnum = 1;
                break;
            } else {
                TTYTextPtr = SourStr - 4;
                TTYNumBytes = 4;
            }
            ansi_state = NOCMD;
            break;

        case MODDBCS:
            TTYNumBytes++;
            TrackedCoord.X++;
            ansi_state = NOCMD;
            break;

        } /* switch ansi_state */

    } /* while cnt */

    /* Flush */
    if ( (Rc = TTYFlushStr(&NewCoord, "4")) != 0 ) {
        return (DWORD) -1;
    }

    return(orig_cnt);
}

/*
** clrparam(lp) - clear the parameters for a screen
**      lp points to the screen's crt struct
*/

VOID
clrparam(void)
{
    register int i;

    for ( i = 0; i < NPARMS; i += 1 )
        ansi_param[i] = 0;
    ansi_pnum = 0;
}

//
// lscroll - scroll the sceen
//
void
lscroll(
	HANDLE h,	// handle on the console buffer to scroll
	int lines	// number of lines to scroll (negative means
			//   scroll text down)
	)
{
	COORD coordDest;
	SMALL_RECT ScrollRect;
	CHAR_INFO ScrollChar;
	BOOLEAN Success;

	if (0 == lines) {
		// already done
		return;
	}

	if (lines < 0) {
		// scroll text down
	        ScrollRect.Top = 0;
	        ScrollRect.Bottom = ScreenRowNum + lines;
	        coordDest.X = 0;
	        coordDest.Y = 0 - lines;
	} else {
		// scroll text up
	        ScrollRect.Top = lines;
	        ScrollRect.Bottom = ScreenRowNum;
	        coordDest.X = 0;
	        coordDest.Y = 0;
	}

        ScrollRect.Left = 0;
	ScrollRect.Right = ScreenColNum;

        ScrollChar.Attributes = (ansi_attr);
        ScrollChar.Char.AsciiChar = ' ';

	Success =  ScrollConsoleScreenBufferA(h, &ScrollRect, NULL,
		coordDest, &ScrollChar);
	if (!Success) {
		KdPrint(("POSIX: ScrollConsole: 0x%x\n", GetLastError()));
        }
	return;
}

//
// ansicmd - perform some ANSI 3.64 function, using the parameters
//      we've just gathered.
//
//      c is the character that indicates the function to be performed
//

DWORD
ansicmd(
	IN HANDLE cs,
	IN CHAR c
	)
{
    DWORD NumFilled, Rc = 0;
    USHORT j;
    COORD Coord;

    switch (c) {
    case ANSI_CUB: /* cursor backward */
        TrackedCoord.X -= range(ansi_param[0], 1, 1, TrackedCoord.X - 1);
        break;

    case ANSI_CUF: /* cursor forward */
        TrackedCoord.X += range(ansi_param[0], 1, 1,
          ScreenColNum - TrackedCoord.X );
        break;

    case ANSI_CUU: /* cursor up */
        TrackedCoord.Y -= range(ansi_param[0], 1, 1, TrackedCoord.Y - 1);
        break;

    case ANSI_CUD: /* cursor down */
        TrackedCoord.Y += range(ansi_param[0], 1, 1,
          ScreenRowNum - TrackedCoord.Y);
        break;

    case ANSI_CUP: /* cursor position */
    case ANSI_CUP1:
        TrackedCoord.Y = (USHORT) range(ansi_param[0], 1, 1, ScreenRowNum);
        TrackedCoord.X = (USHORT) range(ansi_param[1], 1, 1, ScreenColNum);
        break;

    case ANSI_ED: /* erase display */
        switch ( ansi_param[0] ) {
        case 2:
            TrackedCoord.Y = TrackedCoord.X = 1;
            Coord.X = (SHORT) (TrackedCoord.X - 1);
            Coord.Y = (SHORT) (TrackedCoord.Y - 1);
            if ( (Rc = (!FillConsoleOutputCharacterA(cs, ' ',
              (DWORD) ScreenRowNum * ScreenColNum, Coord, &NumFilled)))
              != 0 ) {
                return (Rc);
            }

            if ( (Rc = (!FillConsoleOutputAttribute(cs, (ansi_attr),
                NumFilled, Coord, &NumFilled))) != 0 ) {

                return (Rc);
            }
            break;

        default:
            break;
        }
        break;

    case ANSI_EL:
        Coord.X = (SHORT)(TrackedCoord.X - 1);
        Coord.Y = (SHORT)(TrackedCoord.Y - 1);

        switch ( ansi_param[0] ) {
        case 0: /* up to end */
            if ( (Rc = (!FillConsoleOutputCharacterA(cs, ' ',
              (DWORD) (ScreenColNum - Coord.X), Coord, &NumFilled))) != 0 ) {
                return (Rc);
            }

            if ( (Rc = (!FillConsoleOutputAttribute(cs, (ansi_attr),
                NumFilled, Coord, &NumFilled))) != 0 ) {

                return (Rc);
            }
            break;

        default:
            break;
        }
        break;

    case ANSI_SGR:
	// SGR = Select Graphic Rendition

        for ( j = 0; (SHORT) j <= (SHORT) ansi_pnum; j++ ) {
            SetTTYAttr(cs, ansi_param[j]);
        }
        break;

#if 0
    case ANSI_SCP:
        ansi_scp = TrackedCoord;
        break;

    case ANSI_RCP:
        TrackedCoord = ansi_scp;
        break;
    case ANSI_CPL: /* cursor to previous line */
        TrackedCoord.Y -= range(ansi_param[0], 1, 1, ScreenRowNum);
        TrackedCoord.X = 1;
        break;

    case ANSI_CNL: /* cursor to next line */
        TrackedCoord.Y += range(ansi_param[0], 1, 1, ScreenRowNum);
        TrackedCoord.X = 1;
        break;

    case ANSI_CBT: /* tab backwards */
        col = TrackedCoord.X - 1;
        i = range(ansi_param[0], 1, 1, (col + 7) >> 3);
        if ( col & 7 ) {
            TrackedCoord.X = (col & ~7) + 1;
            --i;
        }
        TrackedCoord.X -= (i << 3);
        break;

    case ANSI_DCH: /* delete character */
        ansi_param[0] = range(ansi_param[0], 1, 1,
          (ScreenColNum - TrackedCoord.X) + 1);
        if ( TrackedCoord.X + ansi_param[0] <= ScreenColNum ) {
            lcopy(cs, lp, TrackedCoord.X+ansi_param[0]-1, TrackedCoord.Y-1,
              TrackedCoord.X-1, TrackedCoord.Y-1,
              ScreenColNum-(TrackedCoord.X+ansi_param[0]-1));
        }
        lclear(cs, lp, ScreenColNum-ansi_param[0], TrackedCoord.Y-1,
             ansi_param[0], SA_BONW);
        break;

    case ANSI_DL: /* delete line */
        ansi_param[0] = range(ansi_param[0], 1, 1,
          (ScreenRowNum - TrackedCoord.Y) + 1);
        /* copy lines up */
        if ( TrackedCoord.Y + ansi_param[0] <= ScreenRowNum ) {
            lcopy(cs, lp, 0, TrackedCoord.Y+ansi_param[0]-1, 0,
              TrackedCoord.Y-1,
              ScreenColNum*(ScreenRowNum-(TrackedCoord.Y+ansi_param[0]-1)));
        }
        /* clear new stuff */
        lclear(cs, lp,  0, ScreenRowNum-ansi_param[0],
            ScreenColNum*ansi_param[0], SA_BONW);
        break;

    case ANSI_ECH: /* erase character */
        ansi_param[0] = range( ansi_param[0], 1, 1,
          (ScreenColNum - TrackedCoord.X) + 1);
        lclear(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1, ansi_param[0],
          SA_BONW);
        break;

    case ANSI_ICH: /* insert character */
        ansi_param[0] = range( ansi_param[0], 1, 1,
          (ScreenColNum - TrackedCoord.X) + 1);
        if ( TrackedCoord.X + ansi_param[0] <= ScreenColNum ) {
            lcopy(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1,
              TrackedCoord.X+ansi_param[0]-1, TrackedCoord.Y-1,
              ScreenColNum-(TrackedCoord.X+ansi_param[0]-1));
        }
        lclear(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1, ansi_param[0],
          SA_BONW);
        break;

    case ANSI_IL: /* insert line */
        ansi_param[0] = range(ansi_param[0], 1, 1,
          (ScreenRowNum - TrackedCoord.Y) + 1);
        /* copy lines down */
        if ( TrackedCoord.Y + ansi_param[0] <= ScreenRowNum ) {
            lcopy(cs, lp, 0, TrackedCoord.Y-1, 0,
              TrackedCoord.Y+ansi_param[0]-1,
              ScreenColNum*(ScreenRowNum-(TrackedCoord.Y+ansi_param[0]-1)));
        }
        /* clear new stuff */
        lclear(cs, lp, 0, TrackedCoord.Y-1, ScreenColNum * ansi_param[0],
          SA_BONW);
        break;
#endif

    case ANSI_SU: /* scroll up */
        ansi_param[0] = range(ansi_param[0], 1, 1, ScreenRowNum);
        lscroll(cs, ansi_param[0]);
        break;

    case ANSI_SD: /* scroll down */
	{
        int i = -range(ansi_param[0], 1, 1, ScreenRowNum);
        lscroll(cs, i);
	}
        break;

    default:
       return (DWORD) 0;
    }
    return (Rc);
}

/*
** range(val, default, min, max) - restrict a value to a range, or supply a
**                                                                 default
**      val is the value to be restricted.
**      default is the value to be returned if val is zero
**      min is the minimum value
**      max is the maximum value
*/

int
range(int val, int def, int min, int max)
{
    if ( val == 0 )
        return def;
    if ( val < min )
        return min;
    if ( val > max )
        return max;
    return val;
}

DWORD
SetTTYAttr(IN HANDLE cs, IN USHORT AnsiParm)
{
    WORD NewAttr, LastAttr = ansi_attr; /* attribute of TTY */
    BOOL Rc;

    if ( AnsiParm == 0 ) { // BUGBUG ? or the default is according to Win
        ansi_base = 0x07; /* white on black */
        ansi_reverse = 0x00;
    } else if ( AnsiParm == 7 ) {
        ansi_reverse = 1;
    } else if ( ((AnsiParm >= 30) && (AnsiParm <= 37)) ||
               ((AnsiParm >= 40) && (AnsiParm <= 47)) ) {
        if ( AnsiParm >= 40 )
            ansi_base = (BYTE) ((ansi_base & 0x0F) | ( 4 << ColorTable[AnsiParm%10]));
        else
            ansi_base = (BYTE) ((ansi_base & 0xF0) | ColorTable[AnsiParm%10]);
    } else if ( AnsiParm == 8 ) {
#if 0
        ansi_cancel = 1;
#endif
    } else if ( AnsiParm == 1 ) {
#if 0
        ansi_intensity = 1;
#endif
    } else if ( AnsiParm == 4 ) {
#if 0
        ansi_bold = 1;
#endif
    } else if ( AnsiParm == 5 ) {
#if 0
        ansi_underscore = 1;
#endif
    }

    if ( ansi_reverse )
        NewAttr = (BYTE) (((ansi_base & 0x0F) << 4 ) |
                          ((ansi_base & 0xF0) >> 4 ));
    else
        NewAttr = ansi_base;

    if ( LastAttr != NewAttr ) {
        /* new attribute */
        if ( (Rc = !SetConsoleTextAttribute(cs, (NewAttr))) != 0 ) {
            return (Rc);
        } else {
            ansi_attr = NewAttr;
        }
    }
    return (NO_ERROR);
}

DWORD
TTYConBeep(void)
{
    DWORD NumWritten, Rc;
    CHAR BeepChar = '\a';

    Rc = !WriteConsoleA(TTYcs, &BeepChar, 1, &NumWritten, NULL);

    return(Rc);
}


DWORD
TTYFlushStr(USHORT *newcoord, const char *call)
{
    DWORD NumWritten;
    BOOL Success;
    COORD coordDest, coord;
    SMALL_RECT ScrollRect;
    CHAR_INFO ScrollChar;

    if (TTYNumBytes) {
        if (TrackedCoord.X > ScreenColNum) {

	    // Handle cursor tracking of text wrap-around

            if (OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) {
#if 0
                TrackedCoord.Y += ((CurrentCoord.X + TrackedCoord.X)
			 / ScreenColNum);
#else
                TrackedCoord.Y += ((TrackedCoord.X) / ScreenColNum);
#endif
                TrackedCoord.X = (TrackedCoord.X % ScreenColNum);
            } else {
                TrackedCoord.X = ScreenColNum;
            }
            *newcoord = 1;
        } else if (TrackedCoord.X < 1) {
            TrackedCoord.X = 1;
#if 0
            *newcoord = 1;
#endif
        }
    }

    //
    // Handle scrolling when printing beyond bottom of screen
    //

    if (TrackedCoord.Y > ScreenRowNum) {
#if  0
        ScrollRect.Top = TrackedCoord.Y - ScreenRowNum;
        ScrollRect.Bottom = (SHORT)ScreenRowNum;
        ScrollRect.Left = 0;
        ScrollRect.Right = (SHORT)ScreenColNum;
        coordDest.X = 0;
        coordDest.Y = 0;
        ScrollChar.Attributes = (ansi_attr);
        ScrollChar.Char.AsciiChar = ' ';

	Success =  ScrollConsoleScreenBufferA(TTYcs, &ScrollRect, NULL,
            coordDest, &ScrollChar);
	if (!Success) {
	    KdPrint(("POSIX: ScrollConsole: 0x%x\n", GetLastError()));
            return Success;
        }
#else
	lscroll(TTYcs, TrackedCoord.Y - ScreenRowNum);
#endif

        if (TTYNumBytes) {
            coord.X = CurrentCoord.X - 1;
            coord.Y = ScreenRowNum - (TrackedCoord.Y - ScreenRowNum) - 1;

	    Success = WriteConsoleOutputCharacterA(TTYcs, (LPSTR)TTYTextPtr,
		TTYNumBytes, coord, &NumWritten);
	    if (!Success) {
		KdPrint(("POSIX: WriteConsoleOutputChar: 0x%x\n", GetLastError()));
		return Success;
	    }
 
            TTYNumBytes = 0;
        }
        TrackedCoord.Y = ScreenRowNum;
#if 0
        *newcoord = 1;
#endif
    } else if (TTYNumBytes) {

	// Not printing beyond bottom of screen.

        Success = WriteConsoleA(TTYcs, (LPSTR) TTYTextPtr, TTYNumBytes,
            &NumWritten, NULL);
	if (!Success) {
	    return Success;
	}
        TTYNumBytes = 0;
    }

    if (*newcoord) {
        if (CarriageReturn) {
            CarriageReturn = 0;
            TrackedCoord.X = 1;
        }

        coord.X = TrackedCoord.X - 1;
        coord.Y = TrackedCoord.Y - 1;

	Success = SetConsoleCursorPosition(TTYcs, coord);
	if (!Success) {
		return Success;
	}
        *newcoord = 0;
    }

    CurrentCoord = TrackedCoord;

    return (DWORD)0;
}