globle intBool ExecuteIfCommandComplete( void *theEnv) { if ((CompleteCommand(CommandLineData(theEnv)->CommandString) == 0) || (RouterData(theEnv)->CommandBufferInputCount <= 0)) { return FALSE; } FlushPPBuffer(theEnv); SetPPBufferStatus(theEnv,OFF); RouterData(theEnv)->CommandBufferInputCount = -1; RouteCommand(theEnv,CommandLineData(theEnv)->CommandString,TRUE); FlushPPBuffer(theEnv); SetHaltExecution(theEnv,FALSE); SetEvaluationError(theEnv,FALSE); FlushCommandString(theEnv); FlushBindList(theEnv); PeriodicCleanup(theEnv,TRUE,FALSE); PrintPrompt(theEnv); return TRUE; }
LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { char inputBuffer[1024]; switch ( uMsg ) { case WM_KILLFOCUS: if ( ( HWND ) wParam == s_wcd.hWnd || ( HWND ) wParam == s_wcd.hwndErrorBox ) { SetFocus( hWnd ); return 0; } break; case WM_CHAR: if ( wParam == 13 ) { GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) ); strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 ); strcat( s_wcd.consoleText, "\n" ); SetWindowText( s_wcd.hwndInputLine, "" ); Sys_Print( va( "]%s\n", inputBuffer ) ); strcpy(kg.g_consoleField.buffer, inputBuffer); kg.historyEditLines[kg.nextHistoryLine % COMMAND_HISTORY] = kg.g_consoleField; kg.nextHistoryLine++; kg.historyLine = kg.nextHistoryLine; return 0; } else if (wParam == 9 ) { GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) ); strcpy(kg.g_consoleField.buffer, inputBuffer); CompleteCommand(); SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); } case WM_KEYDOWN: if (wParam == VK_UP) { if ( kg.nextHistoryLine - kg.historyLine < COMMAND_HISTORY && kg.historyLine > 0 ) { kg.historyLine--; } kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); return 0; } else if (wParam == VK_DOWN) { if (kg.historyLine == kg.nextHistoryLine) { return 0; } kg.historyLine++; kg.g_consoleField = kg.historyEditLines[ kg.historyLine % COMMAND_HISTORY ]; SetWindowText( s_wcd.hwndInputLine, kg.g_consoleField.buffer); SendMessage(s_wcd.hwndInputLine, EM_SETSEL, strlen(kg.g_consoleField.buffer) , MAKELONG(0xffff, 0xffff) ); return 0; } break; } return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam ); }
// The Simple Query Protocol // Fix mis-split bug: Previously, this function assumes there are multiple // queries in the string and split it by ';', which would cause one containing // ';' being split into multiple queries. // However, the multi-statement queries has been split by the psql client and // there is no need to split the query again. void PacketManager::ExecQueryMessage(InputPacket *pkt, const size_t thread_id) { std::string query; PacketGetString(pkt, pkt->len, query); // pop out the last character if it is ';' if (query.back() == ';') { query.pop_back(); } boost::trim(query); if (!query.empty()) { std::vector<StatementResult> result; std::vector<FieldInfo> tuple_descriptor; std::string error_message; int rows_affected = 0; std::string query_type_string_; Statement::ParseQueryTypeString(query, query_type_string_); QueryType query_type; Statement::MapToQueryType(query_type_string_, query_type); std::stringstream stream(query_type_string_); switch (query_type) { case QueryType::QUERY_PREPARE: { std::string statement_name; stream >> statement_name; std::size_t pos = query.find("AS"); std::string statement_query = query.substr(pos + 3); boost::trim(statement_query); // Prepare statement std::shared_ptr<Statement> statement(nullptr); LOG_DEBUG("PrepareStatement[%s] => %s", statement_name.c_str(), statement_query.c_str()); statement = traffic_cop_->PrepareStatement(statement_name, statement_query, error_message); if (statement.get() == nullptr) { skipped_stmt_ = true; SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); LOG_TRACE("ExecQuery Error"); return; } auto entry = std::make_pair(statement_name, statement); statement_cache_.insert(entry); for (auto table_id : statement->GetReferencedTables()) { table_statement_cache_[table_id].push_back(statement.get()); } break; } case QueryType::QUERY_EXECUTE: { std::string statement_name; std::shared_ptr<Statement> statement; std::vector<type::Value> param_values; bool unnamed = false; std::vector<std::string> tokens; boost::split(tokens, query, boost::is_any_of("(), ")); statement_name = tokens.at(1); auto statement_cache_itr = statement_cache_.find(statement_name); if (statement_cache_itr != statement_cache_.end()) { statement = *statement_cache_itr; } // Did not find statement with same name else { std::string error_message = "The prepared statement does not exist"; LOG_ERROR("%s", error_message.c_str()); SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0); for (std::size_t idx = 2; idx < tokens.size(); idx++) { std::string param_str = tokens.at(idx); boost::trim(param_str); if (param_str.empty()) { continue; } param_values.push_back(type::ValueFactory::GetVarcharValue(param_str)); } if (param_values.size() > 0) { statement->GetPlanTree()->SetParameterValues(¶m_values); } auto status = traffic_cop_->ExecuteStatement(statement, param_values, unnamed, nullptr, result_format, result, rows_affected, error_message, thread_id); if (status == ResultType::SUCCESS) { tuple_descriptor = statement->GetTupleDescriptor(); } else { SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } break; } default: { // execute the query using tcop auto status = traffic_cop_->ExecuteStatement( query, result, tuple_descriptor, rows_affected, error_message, thread_id); // check status if (status == ResultType::FAILURE) { SendErrorResponse( {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}}); SendReadyForQuery(NetworkTransactionStateType::IDLE); return; } } } // send the attribute names PutTupleDescriptor(tuple_descriptor); // send the result rows SendDataRows(result, tuple_descriptor.size(), rows_affected); // The response to the SimpleQueryCommand is the query string. CompleteCommand(query, query_type, rows_affected); } else {
bool BatchStar( Environment *theEnv, const char *fileName) { int inchar; bool done = false; FILE *theFile; char *theString = NULL; size_t position = 0; size_t maxChars = 0; #if (! RUN_TIME) && (! BLOAD_ONLY) char *oldParsingFileName; long oldLineCountValue; #endif /*======================*/ /* Open the batch file. */ /*======================*/ theFile = GenOpen(theEnv,fileName,"r"); if (theFile == NULL) { OpenErrorMessage(theEnv,"batch",fileName); return false; } /*======================================*/ /* Setup for capturing errors/warnings. */ /*======================================*/ #if (! RUN_TIME) && (! BLOAD_ONLY) oldParsingFileName = CopyString(theEnv,GetParsingFileName(theEnv)); SetParsingFileName(theEnv,fileName); CreateErrorCaptureRouter(theEnv); oldLineCountValue = SetLineCount(theEnv,1); #endif /*=====================================*/ /* If embedded, clear the error flags. */ /*=====================================*/ if (EvaluationData(theEnv)->CurrentExpression == NULL) { ResetErrorFlags(theEnv); } /*=============================================*/ /* Evaluate commands from the file one by one. */ /*=============================================*/ while (! done) { inchar = getc(theFile); if (inchar == EOF) { inchar = '\n'; done = true; } theString = ExpandStringWithChar(theEnv,inchar,theString,&position, &maxChars,maxChars+80); if (CompleteCommand(theString) != 0) { FlushPPBuffer(theEnv); SetPPBufferStatus(theEnv,false); RouteCommand(theEnv,theString,false); FlushPPBuffer(theEnv); SetHaltExecution(theEnv,false); SetEvaluationError(theEnv,false); FlushBindList(theEnv,NULL); genfree(theEnv,theString,maxChars); theString = NULL; maxChars = 0; position = 0; #if (! RUN_TIME) && (! BLOAD_ONLY) FlushParsingMessages(theEnv); #endif } if ((inchar == '\r') || (inchar == '\n')) { IncrementLineCount(theEnv); } } if (theString != NULL) { genfree(theEnv,theString,maxChars); } /*=======================*/ /* Close the batch file. */ /*=======================*/ GenClose(theEnv,theFile); /*========================================*/ /* Cleanup for capturing errors/warnings. */ /*========================================*/ #if (! RUN_TIME) && (! BLOAD_ONLY) FlushParsingMessages(theEnv); DeleteErrorCaptureRouter(theEnv); SetLineCount(theEnv,oldLineCountValue); SetParsingFileName(theEnv,oldParsingFileName); DeleteString(theEnv,oldParsingFileName); #endif return true; }
globle int EnvBatchStar( void *theEnv, char *fileName) { int inchar; FILE *theFile; char *theString = NULL; size_t position = 0; size_t maxChars = 0; /*======================*/ /* Open the batch file. */ /*======================*/ theFile = GenOpen(theEnv,fileName,"r"); if (theFile == NULL) { OpenErrorMessage(theEnv,"batch",fileName); return(FALSE); } /*========================*/ /* Reset the error state. */ /*========================*/ SetHaltExecution(theEnv,FALSE); SetEvaluationError(theEnv,FALSE); /*=============================================*/ /* Evaluate commands from the file one by one. */ /*=============================================*/ while ((inchar = getc(theFile)) != EOF) { theString = ExpandStringWithChar(theEnv,inchar,theString,&position, &maxChars,maxChars+80); if (CompleteCommand(theString) != 0) { FlushPPBuffer(theEnv); SetPPBufferStatus(theEnv,OFF); RouteCommand(theEnv,theString,FALSE); FlushPPBuffer(theEnv); SetHaltExecution(theEnv,FALSE); SetEvaluationError(theEnv,FALSE); FlushBindList(theEnv); genfree(theEnv,theString,(unsigned) maxChars); theString = NULL; maxChars = 0; position = 0; } } if (theString != NULL) { genfree(theEnv,theString,(unsigned) maxChars); } /*=======================*/ /* Close the batch file. */ /*=======================*/ GenClose(theEnv,theFile); return(TRUE); }
/* ==================== Key_Console Interactive line editing and console scrollback ==================== */ static void Key_Console (int key) { int history_line_last; size_t len; char *workline = key_lines[edit_line]; switch (key) { case K_ENTER: // backslash text are commands, else chat if (workline[1] == '\\' || workline[1] == '/') Cbuf_AddText (workline + 2); // skip the > else if (CheckForCommand()) Cbuf_AddText (workline + 1); // valid command else { // convert to a chat message if (cls.state >= ca_connected) Cbuf_AddText ("say "); Cbuf_AddText (workline + 1); // skip the > } Cbuf_AddText ("\n"); Con_Printf ("%s\n", workline); edit_line = (edit_line + 1) & 31; history_line = edit_line; key_lines[edit_line][0] = ']'; key_lines[edit_line][1] = 0; key_linepos = 1; if (cls.state == ca_disconnected) SCR_UpdateScreen (); // force an update, because the command // may take some time return; case K_TAB: CompleteCommand (); return; case K_LEFTARROW: if (key_linepos < 2) return; if (keydown[K_CTRL]) { /* ctrl - left, word processor style: first, * move to the ending of previous word, then * move to its beginning */ char *p = workline + key_linepos - 1; while (p != workline && *p == ' ') --p; while (p != workline) { if (*--p == ' ') break; } key_linepos = (int)(p - workline) + 1; } else /* simple cursor-to-left, only. */ { --key_linepos; } return; case K_RIGHTARROW: if (!workline[key_linepos]) return; if (keydown[K_CTRL]) { /* ctrl - right, word processor style: if * we are on a text move to its end, then * move to the beginning of the next word */ char *p = workline + key_linepos; while (*p && *p != ' ') ++p; while (*p && *p == ' ') ++p; key_linepos = (int)(p - workline); } else /* simple cursor-to-right only. */ { ++key_linepos; } return; case K_BACKSPACE: if (key_linepos > 1) { workline += key_linepos - 1; if (workline[1]) { len = strlen(workline); memmove (workline, workline + 1, len); } else *workline = 0; key_linepos--; } return; case K_DEL: workline += key_linepos; if (*workline) { if (workline[1]) { len = strlen(workline); memmove (workline, workline + 1, len); } else *workline = 0; } return; case K_UPARROW: history_line_last = history_line; do { history_line = (history_line - 1) & 31; } while (history_line != edit_line && !key_lines[history_line][1]); if (history_line == edit_line) history_line = history_line_last; strcpy(workline, key_lines[history_line]); key_linepos = strlen(workline); return; case K_DOWNARROW: if (history_line == edit_line) return; do { history_line = (history_line + 1) & 31; } while (history_line != edit_line && !key_lines[history_line][1]); if (history_line == edit_line) { workline[0] = ']'; workline[1] = 0; key_linepos = 1; } else { strcpy(workline, key_lines[history_line]); key_linepos = strlen(workline); } return; case K_PGUP: case K_MWHEELUP: con->display -= 2; return; case K_PGDN: case K_MWHEELDOWN: con->display += 2; if (con->display > con->current) con->display = con->current; return; case K_HOME: if (keydown[K_CTRL]) con->display = con->current - con_totallines + 10; else key_linepos = 1; return; case K_END: if (keydown[K_CTRL]) con->display = con->current; else key_linepos = strlen(workline); return; case K_INS: if (keydown[K_SHIFT]) /* Shift+Ins paste */ PasteToConsole(); else key_insert ^= 1; return; case 'v': case 'V': #if defined(PLATFORM_OSX) || defined(PLATFORM_MAC) if (keydown[K_COMMAND]) { /* Cmd+V paste (Mac-only) */ PasteToConsole(); return; } #endif if (keydown[K_CTRL]) { /* Ctrl+v paste */ PasteToConsole(); return; } break; case 'c': case 'C': if (keydown[K_CTRL]) { /* Ctrl+C: abort the line -- S.A */ Con_Printf ("%s\n", workline); workline[0] = ']'; workline[1] = 0; key_linepos = 1; history_line= edit_line; return; } break; } if (key < 32 || key > 127) return; // non printable if (key_linepos < MAXCMDLINE - 1) { qboolean endpos = !workline[key_linepos]; // if inserting, move the text to the right if (key_insert && !endpos) { workline[MAXCMDLINE - 2] = 0; workline += key_linepos; len = strlen(workline) + 1; memmove (workline + 1, workline, len); *workline = key; } else { workline += key_linepos; *workline = key; // null terminate if at the end if (endpos) workline[1] = 0; } key_linepos++; } }
// check input for console window --------------------------------------------- // PRIVATE bool_t CheckConsoleInput() { // scan keyboardbuffer and process key-presses sequentially dword *pos; bool_t console_input_done = false; while ( *( pos = &KeybBuffer->Data + KeybBuffer->ReadPos ) ) { int curlinelen = strlen( con_lines[ con_bottom ] + PROMPT_SIZE ); if ( await_keypress && com_cont_func ) { // <space> or <enter> continues listing if ( ( *pos == CKC_SPACE ) || ( *pos == CKC_ENTER ) ) { EraseConLine( con_bottom ); strcpy( con_lines[ con_bottom ], con_prompt ); // ensure wait prompt gets overwritten con_bottom = last_con_bottom; con_content = last_con_content; cursor_x = 0; com_cont_func(); // <escape> returns to command prompt immediately } else if ( *pos == CKC_ESCAPE ) { await_keypress = FALSE; com_cont_func = NULL; if ( con_in_talk_mode ) { // restore talkmode prompt CreateSeparatorLine( con_bottom ); CON_AddLineFeed(); con_talk_line = con_bottom; } else { // restore standard prompt EraseConLine( con_bottom ); strcpy( con_lines[ con_bottom ], con_prompt ); } cursor_x = 0; } } else if ( *pos & CKC_CTRL_MASK ) { // control keys (CKC_xx) switch ( *pos ) { // <escape>: erase entire command line case CKC_ESCAPE: EraseConLine( con_bottom ); strcpy( con_lines[ con_bottom ], con_prompt ); history_scan = history_add; cursor_x = 0; con_back_view = 0; break; // <cursor-up>: scroll one line up in history buffer case CKC_CURSORUP: if ( !con_logged_in ) break; if ( *( history_list[ ( history_scan - 1 ) & NUM_HISTORY_LINES_MASK ] ) != 0 ) { history_scan = ( history_scan - 1 ) & NUM_HISTORY_LINES_MASK; FetchHistoryEntry( history_scan ); } break; // <cursor-down>: scroll one line down in history buffer case CKC_CURSORDOWN: if ( !con_logged_in ) break; if ( *( history_list[ ( history_scan + 1 ) & NUM_HISTORY_LINES_MASK ] ) != 0 ) { history_scan = ( history_scan + 1 ) & NUM_HISTORY_LINES_MASK; FetchHistoryEntry( history_scan ); } break; // <cursor-left>: set cursor one position left case CKC_CURSORLEFT: if ( cursor_x > 0 ) cursor_x--; break; // <cursor-right>: set cursor one position right case CKC_CURSORRIGHT: if ( cursor_x < curlinelen ) cursor_x++; break; // <shift + cursor-up>: view one line backward case CKC_CURSORUP_SHIFTED: if ( !con_logged_in || con_in_talk_mode ) break; if ( con_back_view < CONSOLE_MAX_BACK_LINES ) con_back_view++; break; // <shift + cursor-down>: view one line forward case CKC_CURSORDOWN_SHIFTED: if ( !con_logged_in || con_in_talk_mode ) break; if ( con_back_view > 0 ) con_back_view--; break; // <shift + cursor-left>: set cursor one word to the left case CKC_CURSORLEFT_SHIFTED: while ( ( cursor_x > 0 ) && !isalnum( con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x - 1 ] ) ) cursor_x--; while ( ( cursor_x > 0 ) && isalnum( con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x - 1 ] ) ) cursor_x--; break; // <shift + cursor-right>: set cursor one word to the right case CKC_CURSORRIGHT_SHIFTED: while ( ( cursor_x < curlinelen ) && isalnum( con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x ] ) ) cursor_x++; while ( ( cursor_x < curlinelen ) && !isalnum( con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x ] ) ) cursor_x++; break; // <home>: set cursor to first column case CKC_HOME: cursor_x = 0; break; // <end>: set cursor behind last column case CKC_END: cursor_x = curlinelen; break; // <page-up>: view one page backward case CKC_PAGEUP: if ( !con_logged_in || con_in_talk_mode ) break; if ( cur_vis_conlines <= 0 ) break; if ( con_back_view < CONSOLE_MAX_BACK_LINES ) con_back_view += cur_vis_conlines; if ( con_back_view > CONSOLE_MAX_BACK_LINES ) con_back_view = CONSOLE_MAX_BACK_LINES; break; // <page-down>: view one page forward case CKC_PAGEDOWN: if ( !con_logged_in || con_in_talk_mode ) break; if ( cur_vis_conlines <= 0 ) break; if ( con_back_view > 0 ) con_back_view -= cur_vis_conlines; if ( con_back_view < 0 ) con_back_view = 0; break; // <insert>: toggle insert mode case CKC_INSERT: insert_mode = !insert_mode; break; // <del>: delete and shift left case CKC_DELETE: if ( cursor_x < curlinelen ) { strcpy( paste_str, con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x + 1 ); strcpy( con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x, paste_str ); } break; // <tab>: find completion for current input case CKC_TAB: if ( !con_logged_in ) break; CompleteCommand(); break; // <enter>: execute current line case CKC_ENTER: EnterConsoleCommand(); break; // <backspace>: step left and shift righthand side left case CKC_BACKSPACE: if ( cursor_x > 0 ) { if ( cursor_x == curlinelen ) { cursor_x--; con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x ] = 0; } else { cursor_x--; strcpy( paste_str, con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x + 1 ); strcpy( con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x, paste_str ); } } break; } } else { // typeable characters if ( ( ConsoleASCIIValid[ *pos & CON_ASCII_MASK ] ) && ( cursor_x < edit_max_x ) ) { if ( insert_mode && ( cursor_x < curlinelen ) ) { if ( curlinelen < edit_max_x ) { strcpy( paste_str, con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x ); strcpy( con_lines[ con_bottom ] + PROMPT_SIZE + cursor_x + 1, paste_str ); con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x++ ] = (byte)*pos; } } else { con_lines[ con_bottom ][ PROMPT_SIZE + cursor_x++ ] = (byte)*pos; } } } // advance one position in circular keybuffer KeybBuffer->ReadPos = ( KeybBuffer->ReadPos + 1 ) % KEYB_BUFF_SIZ; *pos = 0; console_input_done = true; } return console_input_done; }
/** * \brief Interactive line editing and console scrollback. * \param[in] key Key that has been pressed. */ PRIVATE void Key_Console( int key ) { switch( key ) { case K_KP_SLASH: key = '/'; break; case K_KP_MINUS: key = '-'; break; case K_KP_PLUS: key = '+'; break; case K_KP_HOME: key = '7'; break; case K_KP_UPARROW: key = '8'; break; case K_KP_PGUP: key = '9'; break; case K_KP_LEFTARROW: key = '4'; break; case K_KP_5: key = '5'; break; case K_KP_RIGHTARROW: key = '6'; break; case K_KP_END: key = '1'; break; case K_KP_DOWNARROW: key = '2'; break; case K_KP_PGDN: key = '3'; break; case K_KP_INS: key = '0'; break; case K_KP_DEL: key = '.'; break; } if( ( TOUPPER( key ) == 'V' && keydown[K_CTRL] ) || ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) ) { char *cbd; if( ( cbd = Sys_GetClipboardData() ) != 0 ) { int iStringLength; strtok( cbd, "\n\r\b" ); iStringLength = strlen( cbd ); if( iStringLength + key_linepos >= MAXCMDLINE ) { iStringLength = MAXCMDLINE - key_linepos; } if( iStringLength > 0 ) { cbd[ iStringLength ] = '\0'; com_strlcat( key_lines[ edit_line ], cbd, sizeof( key_lines[ edit_line ] ) ); key_linepos += iStringLength; } MM_FREE( cbd ); } return; } // ctrl-L clears screen if ( key == 'l' && keydown[ K_CTRL ] ) { Cbuf_AddText( "clear\n" ); return; } // enter finishes the line if( key == K_ENTER || key == K_KP_ENTER ) { // backslash text are commands, else chat if( key_lines[ edit_line ][ 1 ] == '\\' || key_lines[ edit_line ][ 1 ] == '/' ) { Cbuf_AddText( key_lines[ edit_line ] + 2 ); // skip the > } else { Cbuf_AddText( key_lines[ edit_line ] + 1 ); // valid command } Cbuf_AddText( "\n" ); Com_Printf( "%s\n",key_lines[ edit_line ] ); edit_line = (edit_line + 1) & 31; history_line = edit_line; key_lines[ edit_line ][ 0 ] = ']'; key_linepos = 1; if( ClientStatic.state == ca_disconnected ) { Client_Screen_UpdateScreen(); // force an update, because the command // may take some time } return; } if( key == K_TAB ) { // command completion CompleteCommand(); return; } if( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[ K_CTRL ] ) ) ) { if( key_linepos > 1 ) { key_linepos--; } return; } if( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) || ( ( key == 'p' ) && keydown[K_CTRL] ) ) { do { history_line = (history_line - 1) & 31; } while( history_line != edit_line && ! key_lines[ history_line ][ 1 ] ); if( history_line == edit_line ) { history_line = (edit_line + 1) & 31; } com_strlcpy( key_lines[ edit_line ], key_lines[ history_line ], sizeof( key_lines[ edit_line ] ) ); key_linepos = strlen(key_lines[edit_line]); return; } if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) || ( ( key == 'n' ) && keydown[K_CTRL] ) ) { if( history_line == edit_line ) { return; } do { history_line = (history_line + 1) & 31; } while (history_line != edit_line && !key_lines[history_line][1]); if (history_line == edit_line) { key_lines[edit_line][0] = ']'; key_linepos = 1; } else { com_strlcpy( key_lines[ edit_line ], key_lines[ history_line ], sizeof( key_lines[ edit_line ] ) ); key_linepos = strlen(key_lines[edit_line]); } return; } // console scrolling if( key == K_PGUP || key == K_KP_PGUP ) { Con_PageUp(); return; } if( key == K_PGDN || key == K_KP_PGDN ) { Con_PageDown(); return; } if ( key == K_MWHEELUP) { Con_PageUp(); if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling Con_PageUp(); Con_PageUp(); } return; } if ( key == K_MWHEELDOWN) { Con_PageDown(); if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling Con_PageDown(); Con_PageDown(); } return; } // ctrl-home = top of console if( key == K_HOME || key == K_KP_HOME ) { Con_Top(); return; } // ctrl-end = bottom of console if( key == K_END || key == K_KP_END ) { Con_Bottom(); return; } if( key < 32 || key > 127 ) { return; // non printable } if (key_linepos < MAXCMDLINE-1) { key_lines[ edit_line ][ key_linepos ] = key; key_linepos++; key_lines[ edit_line ][ key_linepos ] = 0; } }
char *Sys_ConsoleInput() { guard(Sys_ConsoleInput); #if !NO_DEDICATED if (console_drawInput) { // display input line Win32Log.WriteChar(']'); if (console_textlen) { console_text[console_textlen] = 0; Win32Log.WriteStr(console_text); } console_drawInput = false; } while (true) { DWORD numevents, numread; GetNumberOfConsoleInputEvents(hConInput, &numevents); if (numevents <= 0) break; INPUT_RECORD rec; ReadConsoleInput(hConInput, &rec, 1, &numread); if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) { int ch = rec.Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': // ENTER Win32Log.WriteStr("\r\n"); console_drawInput = true; if (console_textlen) { console_textlen = 0; return console_text; } break; case '\b': // BACKSPACE if (console_textlen) { console_text[--console_textlen] = 0; Win32Log.WriteStr("\b \b"); } break; case '\t': // TAB { appSprintf(ARRAY_ARG(editLine), "]%s", console_text); CompleteCommand(); const char *s = editLine; if (s[0] == ']') s++; if (s[0] == '/') s++; int len = strlen(s); if (len > 0) { console_textlen = min(len, sizeof(console_text)-2); appStrncpyz(console_text, s, console_textlen+1); Win32Log.EraseInput(); console_drawInput = true; // next time ... } } break; case '\x1B': // ESC Win32Log.EraseInput(); console_textlen = 0; console_text[0] = 0; break; default: if (ch >= ' ') { if (console_textlen < sizeof(console_text)-2) { Win32Log.WriteChar(ch); console_text[console_textlen++] = ch; console_text[console_textlen] = 0; } } // else // appPrintf("%2X\n",ch); break; } } } #endif return NULL; unguard; }