/* $Header: /nw/tony/src/stevie/src/RCS/os2.c,v 1.7 89/08/07 05:49:19 tony Exp $ * * NT System-dependent routines. */ /* * Revision history: * * 6/1/93 - Joe Mitchell * Add support to create a new screen buffer. This fixes the * problem of scrolling the number of lines that "screen buffer size * height" is set to when a vertical scroll bar is present. * Allow filenames longer than 8.3 for use with HPFS/NTFS. */ #include #include #include #include #include #include #include #include #undef max #undef min #include "stevie.h" #define MAX_VK 0x7f #define UCHR unsigned char // so table looks nice UCHR RegularTable[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, /* 20 */ 0x00, K_PU, K_PD, K_EN, K_HO, K_LE, K_UP, K_RI, /* 28 */ K_DO, 0x00, 0x00, 0x00, 0x00, K_IN, K_DE, 0x00, /* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 58 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, /* 78 */ K_F9, K_FA, K_FB, K_FC, 0x00, 0x00, 0x00, 0x00 }; UCHR ShiftedTable[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, /* 20 */ 0x00, K_PU, K_PD, K_EN, K_HO, K_LE, K_UP, K_RI, /* 28 */ K_DO, 0x00, 0x00, 0x00, 0x00, K_IN, K_DE, 0x00, /* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 58 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ K_S1, K_S2, K_S3, K_S4, K_S5, K_S6, K_S7, K_S8, /* 78 */ K_S9, K_SA, K_SB, K_SC, 0x00, 0x00, 0x00, 0x00 }; UCHR ControlTable[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, K_CG, 0x00, /* 20 */ 0x00, K_PU, K_PD, K_EN, K_HO, K_LE, K_UP, K_RI, /* 28 */ K_DO, 0x00, 0x00, 0x00, 0x00, K_IN, K_DE, 0x00, /* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 48 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 50 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 58 */ 0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define ALT_PRESSED (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) #define CTL_PRESSED (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED) #define CONTROL_ALT (ALT_PRESSED | CTL_PRESSED) #define OMODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT) static HANDLE CurrConsole; static HANDLE ViConsole,ConsoleIn; static HANDLE PrevConsole; // [jrm 6/93] Save previous screen buffer static DWORD OldConsoleMode; static DWORD ViConsoleInputMode; /* * inchar() - get a character from the keyboard */ int inchar() { INPUT_RECORD InputRec; DWORD NumRead; got_int = FALSE; flushbuf(); /* flush any pending output */ while(1) { /* loop until we get a valid console event */ ReadConsoleInput(ConsoleIn,&InputRec,1,&NumRead); if((InputRec.EventType == KEY_EVENT) && (InputRec.Event.KeyEvent.bKeyDown)) { KEY_EVENT_RECORD *KE = &InputRec.Event.KeyEvent; unsigned char *Table; if(KE->dwControlKeyState & ALT_PRESSED) { continue; // no ALT keys allowed. } else if(KE->dwControlKeyState & CTL_PRESSED) { Table = ControlTable; } else if(KE->uChar.AsciiChar) { // no control, no alt return(KE->uChar.AsciiChar); } else if(KE->dwControlKeyState & SHIFT_PRESSED) { Table = ShiftedTable; } else { Table = RegularTable; } if((KE->wVirtualKeyCode > MAX_VK) || !Table[KE->wVirtualKeyCode]) { continue; } return(Table[KE->wVirtualKeyCode]); } } } #if 0 switch (c = _getch()) { case 0x1e: return K_CGRAVE; case 0: /* special key */ if (State != NORMAL) { c = _getch(); /* throw away next char */ continue; /* and loop for another char */ } switch (c = _getch()) { case 0x50: return K_DARROW; case 0x48: return K_UARROW; case 0x4b: return K_LARROW; case 0x4d: return K_RARROW; case 0x52: return K_INSERT; case 0x47: stuffin("1G"); return -1; case 0x4f: stuffin("G"); return -1; case 0x51: stuffin(mkstr(CTRL('F'))); return -1; case 0x49: stuffin(mkstr(CTRL('B'))); return -1; /* * Hard-code some useful function key macros. */ case 0x3b: /* F1 */ stuffin(":N\n"); return -1; case 0x54: /* SF1 */ stuffin(":N!\n"); return -1; case 0x3c: /* F2 */ stuffin(":n\n"); return -1; case 0x55: /* SF2 */ stuffin(":n!\n"); return -1; case 0x3d: /* F3 */ stuffin(":e #\n"); return -1; case 0x3e: /* F4 */ stuffin(":rew\n"); return -1; case 0x57: /* SF4 */ stuffin(":rew!\n"); return -1; case 0x3f: /* F5 */ stuffin("[["); return -1; case 0x40: /* F6 */ stuffin("]]"); return -1; case 0x41: /* F7 - explain C declaration */ stuffin("yyp^iexplain \033!!cdecl\n"); return -1; case 0x42: /* F8 - declare C variable */ stuffin("yyp!!cdecl\n"); return -1; case 0x43: /* F9 */ stuffin(":x\n"); return -1; case 0x44: /* F10 */ stuffin(":help\n"); return -1; default: break; } break; default: return c; } } } #endif #define BSIZE 2048 static char outbuf[BSIZE]; static int bpos = 0; DWORD CursorSize; DWORD OrgCursorSize; void flushbuf() { BOOL st; // [jrm 6/93] DWORD count; // [jrm 6/93] // // [jrm 6/93] Use WriteFile rather than "write" to take advantage of // new screen buffer. // if (bpos != 0) { //jrm write(1, outbuf, bpos); st = WriteFile(CurrConsole, outbuf, bpos, &count, NULL); if (!st) { fprintf(stderr, "vi: Error calling WriteFile"); } } bpos = 0; } /* * Macro to output a character. Used within this file for speed. */ #define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() /* * Function version for use outside this file. */ void outchar(c) register char c; { outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf(); } /* * outstr(s) - write a string to the console */ void outstr(s) register char *s; { while (*s) { outone(*s++); } } void beep() { Beep(500,50); // 500Hz for 1/4 sec } void sleep(n) int n; { Sleep(1000L * n); } void delay() { flushbuf(); Sleep(300L); } void sig() { // signal(SIGINT, sig); got_int = TRUE; } WORD Attribute; WORD HighlightAttribute; void useviconsole() { flushbuf(); SetConsoleActiveScreenBuffer(CurrConsole = ViConsole); CursorSize = P(P_CS); VisibleCursor(); FlushConsoleInputBuffer(ConsoleIn); SetConsoleMode(ConsoleIn,ViConsoleInputMode); } void usecmdconsole() { flushbuf(); SetConsoleActiveScreenBuffer(CurrConsole = PrevConsole); CursorSize = OrgCursorSize; VisibleCursor(); FlushConsoleInputBuffer(ConsoleIn); SetConsoleMode(ConsoleIn,OldConsoleMode); } void windinit() { COORD coord; CONSOLE_SCREEN_BUFFER_INFO Info; CONSOLE_CURSOR_INFO Info2; DWORD NumRead; ConsoleIn=GetStdHandle(STD_INPUT_HANDLE); // // [jrm 6/93] Create a new screen buffer. This fixes the scroll problem // when there is a vertical scroll bar. // PrevConsole = GetStdHandle(STD_OUTPUT_HANDLE); CurrConsole = ViConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if (ViConsole == INVALID_HANDLE_VALUE) { printf("CreateConsoleScreenBuffer failed in windinit\n"); printf("LastError = 0x%lx\n", GetLastError()); exit(0); } SetConsoleActiveScreenBuffer(ViConsole); SetConsoleMode(ViConsole, OMODE); GetConsoleScreenBufferInfo(ViConsole,&Info); P(P_CO) = Columns = Info.dwSize.X; P(P_LI) = Rows = Info.dwSize.Y; P(P_SS) = Rows / 2; GetConsoleCursorInfo(ViConsole,&Info2); P(P_CS) = OrgCursorSize = CursorSize = Info2.dwSize; coord.X = coord.Y = 0; ReadConsoleOutputAttribute(ViConsole, &Attribute, sizeof(Attribute)/sizeof(WORD), coord, &NumRead); GetConsoleMode(ConsoleIn,&OldConsoleMode); ViConsoleInputMode = OldConsoleMode & ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT ); SetConsoleMode(ConsoleIn,ViConsoleInputMode); setviconsoletitle(); // signal(SIGINT, sig); // // Calculate a reasonable default search highlight // by flipping colors for the current screen. // HighlightAttribute = ((Attribute & 0xff00) | ((Attribute & 0x00f0) >> 4) | ((Attribute & 0x000f) << 4)); } void setviconsoletitle() { char title[2000]; strcpy(title, Appname); if (Filename) { strcat(title, " "); strcat(title, Filename); } SetConsoleTitle(title); } void wchangescreen(NewRows, NewColumns) int NewRows; int NewColumns; { #if 0 CONSOLE_SCREEN_BUFFER_INFO info; #endif SMALL_RECT screenRect; COORD screenSize; #if 0 GetConsoleScreenBufferInfo(ViConsole,&info); info.dwSize.X = NewRows; info.dwSize.Y = NewColumns; #endif screenSize.X = NewColumns; screenSize.Y = NewRows; SetConsoleScreenBufferSize(ViConsole, screenSize); screenRect.Top = 0; screenRect.Left = 0; screenRect.Right = NewColumns - 1; screenRect.Bottom = NewRows - 1; SetConsoleWindowInfo(ViConsole, TRUE, &screenRect); } void windexit(r) int r; { usecmdconsole(); exit(r); } void windgoto(r, c) register int r, c; { COORD coord; flushbuf(); coord.X = (SHORT)c; coord.Y = (SHORT)r; SetConsoleCursorPosition(ViConsole,coord); } FILE * fopenb(fname, mode) char *fname; char *mode; { FILE *fopen(); char modestr[16]; sprintf(modestr, "%sb", mode); return fopen(fname, modestr); } #define PSIZE 128 /* * fixname(s) - fix up a dos name * * Takes a name like: * * d:\x\y\z\base.ext * * and trims 'base' to 8 characters, and 'ext' to 3. */ char * fixname(s) char *s; { char *strchr(), *strrchr(); static char f[PSIZE]; char base[32]; char ext[32]; char *p; int d = 0; int i; strcpy(f, s); if (f[1] == ':') { if (('a' <= f[0] && f[0] <= 'z') || ('A' <= f[0] && f[0] <= 'Z')) { d = 2; } } for (i=0; i < PSIZE ;i++) if (f[d+i] == '/') f[d+i] = '\\'; /* * Split the name into directory, base, extension. */ if ((p = strrchr(f+d, '\\')) != NULL) { strcpy(base, p+1); p[1] = '\0'; } else { strcpy(base, f+d); f[d] = '\0'; } if ((p = strchr(base, '.')) != NULL) { strcpy(ext, p+1); *p = '\0'; } else ext[0] = '\0'; #if 0 /* [jrm 6/93] Allow longer filenames for HPFS/NTFS */ /* * Trim the base name if necessary. */ if (strlen(base) > 8) base[8] = '\0'; if (strlen(ext) > 3) ext[3] = '\0'; #endif /* * Paste it all back together */ strcat(f, base); strcat(f, "."); strcat(f, ext); return f; } LONG mysystem(cmd, async) char *cmd; int async; { STARTUPINFO si; PROCESS_INFORMATION pi; BOOL ok; DWORD status; char *cmdline; char title[200]; char *title2; char *shell = getenv("SHELL"); if (!shell) { shell = getenv("COMSPEC"); } if (!shell) { shell = "cmd.exe"; } if (!cmd) { return !_access(shell,0); } if (!*cmd) { cmdline = _strdup(shell); } else { cmdline = malloc(strlen(shell) + strlen(cmd) + 5); strcpy(cmdline, shell); strcat(cmdline, " /c "); strcat(cmdline, cmd); } memset(&si, 0, sizeof(si)); si.cb = sizeof(si); if (async) { si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWNA; } if (!async) { GetConsoleTitle(title, sizeof(title)); title2 = malloc(strlen(title) + 4 + strlen(cmdline)); strcpy(title2, title); strcat(title2, " - "); strcat(title2, cmdline); SetConsoleTitle(title2); free(title2); } ok = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | (async ? CREATE_NEW_CONSOLE : 0), NULL, NULL, &si, &pi ); free(cmdline); if (!ok) { status = (DWORD)-1; } else { if (async) { status = 0; } else { SetConsoleCtrlHandler(NULL, TRUE); WaitForSingleObject(pi.hProcess, INFINITE); SetConsoleCtrlHandler(NULL, FALSE); GetExitCodeProcess(pi.hProcess, &status); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } if (!async) { SetConsoleTitle(title); } return (LONG)status; } void doshell(cmd, async) char *cmd; int async; { int c; if (async) { mysystem(cmd? cmd : "", async); } else { usecmdconsole(); if (!cmd) { mysystem("", async); } else { outchar('!'); outstr(cmd); outchar('\n'); flushbuf(); mysystem(cmd, async); } c = wait_return0(); outchar('\n'); useviconsole(); if (c == ':') { outchar(NL); docmdln(getcmdln(c)); } else { screenclear(); } updatescreen(); } } void dochdir(arg) char *arg; { if (_chdir(arg)) { emsg("bad directory"); } } /* NT console stuff */ static DWORD RowSave,ColSave; void Scroll(int t,int l,int b,int r,int Row,int Col) { SMALL_RECT ScrollRect; COORD Coord; CHAR_INFO CharInfo; ScrollRect.Left = (SHORT)l; ScrollRect.Right = (SHORT)r; ScrollRect.Top = (SHORT)t; ScrollRect.Bottom = (SHORT)b; Coord.X = (SHORT)Col; Coord.Y = (SHORT)Row; CharInfo.Char.AsciiChar = ' '; CharInfo.Attributes = Attribute; ScrollConsoleScreenBuffer(ViConsole,&ScrollRect,NULL,Coord,&CharInfo); } void EraseLine(void) { CONSOLE_SCREEN_BUFFER_INFO Info; DWORD NumWritten; flushbuf(); GetConsoleScreenBufferInfo(ViConsole,&Info); Info.dwCursorPosition.X = 0; SetConsoleCursorPosition(ViConsole,Info.dwCursorPosition); FillConsoleOutputCharacter(ViConsole,' ',Columns,Info.dwCursorPosition, &NumWritten); } void EraseNLinesAtRow(int n,int row) { COORD coord; DWORD NumWritten; flushbuf(); coord.X = 0; coord.Y = (short)row; FillConsoleOutputCharacter(ViConsole,' ',n*Columns,coord, &NumWritten); } void ClearDisplay(void) { COORD c; DWORD NumWritten; flushbuf(); c.X = c.Y = 0; SetConsoleCursorPosition(ViConsole,c); FillConsoleOutputCharacter(ViConsole,' ',Rows*Columns,c, &NumWritten); } void SaveCursor(void) { CONSOLE_SCREEN_BUFFER_INFO Info; flushbuf(); GetConsoleScreenBufferInfo(ViConsole,&Info); ColSave = Info.dwCursorPosition.X; RowSave = Info.dwCursorPosition.Y; } void RestoreCursor(void) { COORD c; flushbuf(); c.X = (SHORT)ColSave; c.Y = (SHORT)RowSave; SetConsoleCursorPosition(ViConsole,c); } void InvisibleCursor(void) { CONSOLE_CURSOR_INFO Info; flushbuf(); Info.dwSize = CursorSize; Info.bVisible = FALSE; SetConsoleCursorInfo(CurrConsole,&Info); } void VisibleCursor(void) { CONSOLE_CURSOR_INFO Info; flushbuf(); Info.dwSize = CursorSize; Info.bVisible = TRUE; SetConsoleCursorInfo(CurrConsole,&Info); } int CurHighlightLine = -1; int CurHighlightColumn = -1; int CurHighlightLength = -1; char CurHighlightString[512]; int StrLength(char *cp) { int length = 0; int diff; while (*cp) { if (*cp == '\t') { diff = P(P_TS) - (length % P(P_TS)); length += diff; } else { length++; } cp++; } return length; } void HighlightLine( int col, unsigned long line, char *string ) { COORD dwWriteCoord; DWORD dwNumWritten; int length; if (P(P_HS) == FALSE) return; length = StrLength(string); if (length > Columns) { length = Columns; } if (col >= (Columns - 1)) { col--; } dwWriteCoord.X = CurHighlightColumn = col; dwWriteCoord.Y = CurHighlightLine = line; FillConsoleOutputAttribute(ViConsole, HighlightAttribute, length, dwWriteCoord, &dwNumWritten); updateline(); #if 0 WriteConsoleOutputCharacter(ViConsole, string, length, dwWriteCoord, &dwNumWritten); #endif strcpy(CurHighlightString, string); CurHighlightLength = length; } #define FOREGROUND_WHITE (FOREGROUND_BLUE | \ FOREGROUND_GREEN | \ FOREGROUND_RED | \ FOREGROUND_INTENSITY) void RemoveHighlight( int col, unsigned long line, int length, char *string ) { COORD dwWriteCoord; DWORD dwNumWritten; length = StrLength(string); if (length > Columns) { length = Columns; } dwWriteCoord.X = col; dwWriteCoord.Y = (int)line; FillConsoleOutputAttribute(ViConsole, Attribute, length, dwWriteCoord, &dwNumWritten); updateline(); #if 0 WriteConsoleOutputCharacter(ViConsole, string, length, dwWriteCoord, &dwNumWritten); #endif } void HighlightCheck() { if (P(P_HS) == FALSE) return; if (CurHighlightLine != -1) { RemoveHighlight(CurHighlightColumn, CurHighlightLine, CurHighlightLength, CurHighlightString); CurHighlightLine = -1; CurHighlightColumn = -1; } }