⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 screen.c

📁 The main purpose of this project is to add a new scheduling algorithm to GeekOS and to implement a s
💻 C
字号:
/* * GeekOS text screen output * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu> * $Revision: 1.24 $ *  * This is free software.  You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". */#include <stdarg.h>#include <geekos/kassert.h>#include <geekos/ktypes.h>#include <geekos/io.h>#include <geekos/int.h>#include <geekos/fmtout.h>#include <geekos/screen.h>/* * Information sources for VT100 and ANSI escape sequences: * - http://www.lns.cornell.edu/~pvhp/dcl/vt100.html * - http://en.wikipedia.org/wiki/ANSI_escape_code *//* ---------------------------------------------------------------------- * Private functions and data * ---------------------------------------------------------------------- */#define ESC ((char) 0x1B)#define DEFAULT_ATTRIBUTE ATTRIB(BLACK, GRAY)enum State {    S_NORMAL,		/* Normal state - output is echoed verbatim */    S_ESC,		/* Saw ESC character - begin output escape sequence */    S_ESC2,		/* Saw '[' character - continue output escape sequence */    S_ARG,		/* Scanning a numeric argument */    S_CMD,		/* Command */};#define MAXARGS 8	/* Max args that can be passed to esc sequence */struct Console_State {    /* Current state information */    int row, col;    int saveRow, saveCol;    uchar_t currentAttr;    /* Working variables for processing escape sequences. */    enum State state;    int argList[MAXARGS];    int numArgs;};static struct Console_State s_cons;#define NUM_SCREEN_DWORDS ((NUMROWS * NUMCOLS * 2) / 4)#define NUM_SCROLL_DWORDS (((NUMROWS-1) * NUMCOLS * 2) / 4)#define NUM_DWORDS_PER_LINE ((NUMCOLS*2)/4)#define FILL_DWORD (0x00200020 | (s_cons.currentAttr<<24) | (s_cons.currentAttr<<8))/* * Scroll the display one line. * We speed things up by copying 4 bytes at a time. */static void Scroll(void){    uint_t* v;    int i, n = NUM_SCROLL_DWORDS;    uint_t fill = FILL_DWORD;    /* Move lines 1..NUMROWS-1 up one position. */    for (v = (uint_t*)VIDMEM, i = 0; i < n; ++i) {	*v = *(v + NUM_DWORDS_PER_LINE);	++v;    }    /* Clear out last line. */    for (v = (uint_t*)VIDMEM + n, i = 0; i < NUM_DWORDS_PER_LINE; ++i)	*v++ = fill;}/* * Clear current cursor position to end of line using * current attribute. */static void Clear_To_EOL(void){    int n = (NUMCOLS - s_cons.col);    uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;    while (n-- > 0) {	*v++ = ' ';	*v++ = s_cons.currentAttr;    }}/* * Move to the beginning of the next line, scrolling * if necessary. */static void Newline(void){    ++s_cons.row;    s_cons.col = 0;    if (s_cons.row == NUMROWS) {	Scroll();	s_cons.row = NUMROWS - 1;    }}/* * Write the graphic representation of given character to the screen * at current position, with current attribute, scrolling if * necessary. */static void Put_Graphic_Char(int c){    uchar_t* v = VIDMEM + s_cons.row*(NUMCOLS*2) + s_cons.col*2;    /* Put character at current position */    *v++ = (uchar_t) c;    *v = s_cons.currentAttr;    if (s_cons.col < NUMCOLS - 1)	++s_cons.col;    else	Newline();}/* * Put one character to the screen using the current cursor position * and attribute, scrolling if needed.  The caller should update * the cursor position once all characters have been written. */static void Output_Literal_Character(int c){    int numSpaces;    switch (c) {    case '\n':	Clear_To_EOL();	Newline();	break;    case '\t':	numSpaces = TABWIDTH - (s_cons.col % TABWIDTH);	while (numSpaces-- > 0)	    Put_Graphic_Char(' ');	break;    default:	Put_Graphic_Char(c);	break;    }#ifndef NDEBUG    /*     * When compiled with --enable-port-e9-hack, Bochs will send writes     * to port E9 to the console.  This helps tremendously with debugging,     * because it allows debug Print() statements to be visible after     * Bochs has exited.     */    Out_Byte(0xE9, c);#endif}/* * Move the cursor to a new position, stopping at the screen borders. */static void Move_Cursor(int row, int col){    if (row < 0)	row = 0;    else if (row >= NUMROWS)	row = NUMROWS - 1;    if (col < 0)	col = 0;    else if (col >= NUMCOLS)	col = NUMCOLS - 1;    s_cons.row = row;    s_cons.col = col;}/* * Table mapping ANSI colors to VGA text mode colors. */static const uchar_t s_ansiToVgaColor[] = {    BLACK,RED,GREEN,AMBER,BLUE,MAGENTA,CYAN,GRAY};/* * Update the attributes specified by the arguments * of the escape sequence. */static void Update_Attributes(void){    int i;    int attr = s_cons.currentAttr & ~(BRIGHT);    for (i = 0; i < s_cons.numArgs; ++i) {	int value = s_cons.argList[i];	if (value == 0)	    attr = DEFAULT_ATTRIBUTE;	else if (value == 1)	    attr |= BRIGHT;	else if (value >= 30 && value <= 37)	    attr = (attr & ~0x7) | s_ansiToVgaColor[value - 30];	else if (value >= 40 && value <= 47)	    attr = (attr & ~(0x7 << 4)) | (s_ansiToVgaColor[value - 40] << 4);    }    s_cons.currentAttr = attr;}/* Reset to cancel or finish processing an escape sequence. */static void Reset(void){    s_cons.state = S_NORMAL;    s_cons.numArgs = 0;}/* Start an escape sequence. */static void Start_Escape(void){    s_cons.state = S_ESC;    s_cons.numArgs = 0;}/* Start a numeric argument to an escape sequence. */static void Start_Arg(int argNum){    KASSERT(s_cons.numArgs == argNum);    s_cons.numArgs++;    s_cons.state = S_ARG;    if (argNum < MAXARGS)	s_cons.argList[argNum] = 0;}/* Save current cursor position. */static void Save_Cursor(void){    s_cons.saveRow = s_cons.row;    s_cons.saveCol = s_cons.col;}/* Restore saved cursor position. */static void Restore_Cursor(void){    s_cons.row = s_cons.saveRow;    s_cons.col = s_cons.saveCol;}/* Add a digit to current numeric argument. */static void Add_Digit(int c){    KASSERT(ISDIGIT(c));    if (s_cons.numArgs < MAXARGS) {	int argNum = s_cons.numArgs - 1;	s_cons.argList[argNum] *= 10;	s_cons.argList[argNum] += (c - '0');    }}/* * Get a numeric argument. * Returns zero if that argument was not actually specified. */static int Get_Arg(int argNum){    return argNum < s_cons.numArgs ? s_cons.argList[argNum] : 0;}/* * The workhorse output function. * Depending on the current console output state, * does literal character output or processes part of * an escape sequence. */static void Put_Char_Imp(int c){again:    switch (s_cons.state) {    case S_NORMAL:	if (c == ESC)	    Start_Escape();	else	    Output_Literal_Character(c);	break;    case S_ESC:	if (c == '[')	    s_cons.state = S_ESC2;	else	    Reset();	break;    case S_ESC2:	if (ISDIGIT(c)) {	    Start_Arg(0);	    goto again;	} else if (c == ';') {	    /* Special case: for "n;m" commands, "n" is implicitly 1 if omitted */	    Start_Arg(0);	    Add_Digit('1');	    Start_Arg(1);	} else {	    s_cons.state = S_CMD;	    goto again;	}	break;    case S_ARG:	if (ISDIGIT(c))	    Add_Digit(c);	else if (c == ';')	    Start_Arg(s_cons.numArgs);	else {	    s_cons.state = S_CMD;	    goto again;	}	break;    case S_CMD:	switch (c) {	case 'K': Clear_To_EOL(); break;	case 's': Save_Cursor(); break;	case 'u': Restore_Cursor(); break;	case 'A': Move_Cursor(s_cons.row - Get_Arg(0), s_cons.col); break;	case 'B': Move_Cursor(s_cons.row + Get_Arg(0), s_cons.col); break;	case 'C': Move_Cursor(s_cons.row, s_cons.col + Get_Arg(0)); break;	case 'D': Move_Cursor(s_cons.row, s_cons.col - Get_Arg(0)); break;	case 'm': Update_Attributes(); break;	case 'f': case 'H':	    if (s_cons.numArgs == 2) Move_Cursor(Get_Arg(0)-1, Get_Arg(1)-1); break;	case 'J':	    if (s_cons.numArgs == 1 && Get_Arg(0) == 2) {		Clear_Screen();		Put_Cursor(0, 0);	    }	    break;	default: break;	}	Reset();	break;    default:	KASSERT(false);    }}/* * Update the location of the hardware cursor. */static void Update_Cursor(void){    /*     * The cursor location is a character offset from the beginning     * of page memory (I think).     */    uint_t characterPos = (s_cons.row * NUMCOLS) + s_cons.col;    uchar_t origAddr;    /*     * Save original contents of CRT address register.     * It is considered good programming practice to restore     * it to its original value after modifying it.     */    origAddr = In_Byte(CRT_ADDR_REG);    IO_Delay();    /* Set the high cursor location byte */    Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG);    IO_Delay();    Out_Byte(CRT_DATA_REG, (characterPos>>8) & 0xff);    IO_Delay();    /* Set the low cursor location byte */    Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG);    IO_Delay();    Out_Byte(CRT_DATA_REG, characterPos & 0xff);    IO_Delay();    /* Restore contents of the CRT address register */    Out_Byte(CRT_ADDR_REG, origAddr);}/* ---------------------------------------------------------------------- * Public functions * ---------------------------------------------------------------------- *//* * Initialize the screen module. */void Init_Screen(void){    bool iflag = Begin_Int_Atomic();    s_cons.row = s_cons.col = 0;    s_cons.currentAttr = DEFAULT_ATTRIBUTE;    Clear_Screen();    End_Int_Atomic(iflag);}/* * Clear the screen using the current attribute. */void Clear_Screen(void){    uint_t* v = (uint_t*)VIDMEM;    int i;    uint_t fill = FILL_DWORD;    bool iflag = Begin_Int_Atomic();    for (i = 0; i < NUM_SCREEN_DWORDS; ++i)	*v++ = fill;    End_Int_Atomic(iflag);}/* * Get current cursor position. */void Get_Cursor(int* row, int* col){    bool iflag = Begin_Int_Atomic();    *row = s_cons.row;    *col = s_cons.col;    End_Int_Atomic(iflag);}/* * Set the current cursor position. * Return true if successful, or false if the specified * cursor position is invalid. */bool Put_Cursor(int row, int col){    bool iflag;    if (row < 0 || row >= NUMROWS || col < 0 || col >= NUMCOLS)	return false;    iflag = Begin_Int_Atomic();    s_cons.row = row;    s_cons.col = col;    Update_Cursor();    End_Int_Atomic(iflag);    return true;}/* * Get the current character attribute. */uchar_t Get_Current_Attr(void){    return s_cons.currentAttr;}/* * Set the current character attribute. */void Set_Current_Attr(uchar_t attrib){    bool iflag = Begin_Int_Atomic();    s_cons.currentAttr = attrib;    End_Int_Atomic(iflag);}/* * Write a single character to the screen at current position * using current attribute, handling scrolling, special characters, etc. */void Put_Char(int c){    bool iflag = Begin_Int_Atomic();    Put_Char_Imp(c);    Update_Cursor();    End_Int_Atomic(iflag);}/* * Write a string of characters to the screen at current cursor * position using current attribute. */void Put_String(const char* s){    bool iflag = Begin_Int_Atomic();    while (*s != '\0')	Put_Char_Imp(*s++);    Update_Cursor();    End_Int_Atomic(iflag);}/* * Write a buffer of characters at current cursor position * using current attribute. */void Put_Buf(const char* buf, ulong_t length){    bool iflag = Begin_Int_Atomic();    while (length > 0) {	Put_Char_Imp(*buf++);	--length;    }    Update_Cursor();    End_Int_Atomic(iflag);}/* Support for Print(). */static void Print_Emit(struct Output_Sink *o, int ch) { Put_Char_Imp(ch); }static void Print_Finish(struct Output_Sink *o) { Update_Cursor(); }static struct Output_Sink s_outputSink = { &Print_Emit, &Print_Finish };/* * Print to console using printf()-style formatting. * Calls into Format_Output in common library. */void Print(const char *fmt, ...){    va_list args;    bool iflag = Begin_Int_Atomic();    va_start(args, fmt);    Format_Output(&s_outputSink, fmt, args);    va_end(args);    End_Int_Atomic(iflag);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -