U8_EXPORT /* u8_string_subst: Arguments: returns a copy of its argument with all occurrences of one string replaced with another Returns: the concatenation of the strings */ u8_string u8_string_subst(u8_string input,u8_string key,u8_string replace) { const u8_byte *scan=input, *next=strstr(scan,key); if (next==NULL) return u8_strdup(input); else { struct U8_OUTPUT out; int key_len=u8_bytelen(key), replace_len=u8_bytelen(replace); U8_INIT_STATIC_OUTPUT(out,u8_bytelen(input)+(replace_len*4)+2); while (next) { u8_putn(&out,scan,next-scan); u8_putn(&out,replace,replace_len); scan=next+key_len; next=strstr(scan,key);} u8_puts(&out,scan); return (u8_string) out.u8_outbuf;} }
/* ==================== Interactive line editing and console scrollback ==================== */ static void Key_Console (int key, int unicode) { // LordHavoc: copied most of this from Q2 to improve keyboard handling 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 ((key == 'v' && keydown[K_CTRL]) || ((key == K_INS || key == K_KP_INS) && keydown[K_SHIFT])) { char *cbd, *p; if ((cbd = Sys_GetClipboardData()) != 0) { int i; #if 1 p = cbd; while (*p) { if (*p == '\r' && *(p+1) == '\n') { *p++ = ';'; *p++ = ' '; } else if (*p == '\n' || *p == '\r' || *p == '\b') *p++ = ';'; p++; } #else strtok(cbd, "\n\r\b"); #endif i = (int)strlen(cbd); if (i + key_linepos >= MAX_INPUTLINE) i= MAX_INPUTLINE - key_linepos - 1; if (i > 0) { // terencehill: insert the clipboard text between the characters of the line /* char *temp = (char *) Z_Malloc(MAX_INPUTLINE); cbd[i]=0; temp[0]=0; if ( key_linepos < (int)strlen(key_line) ) strlcpy(temp, key_line + key_linepos, (int)strlen(key_line) - key_linepos +1); key_line[key_linepos] = 0; strlcat(key_line, cbd, sizeof(key_line)); if (temp[0]) strlcat(key_line, temp, sizeof(key_line)); Z_Free(temp); key_linepos += i; */ // blub: I'm changing this to use memmove() like the rest of the code does. cbd[i] = 0; memmove(key_line + key_linepos + i, key_line + key_linepos, sizeof(key_line) - key_linepos - i); memcpy(key_line + key_linepos, cbd, i); key_linepos += i; } Z_Free(cbd); } return; } if (key == 'l' && keydown[K_CTRL]) { Cbuf_AddText ("clear\n"); return; } if (key == 'u' && keydown[K_CTRL]) // like vi/readline ^u: delete currently edited line { // clear line key_line[0] = ']'; key_line[1] = 0; key_linepos = 1; return; } if (key == 'q' && keydown[K_CTRL]) // like zsh ^q: push line to history, don't execute, and clear { // clear line Key_History_Push(); key_line[0] = ']'; key_line[1] = 0; key_linepos = 1; return; } if (key == K_ENTER || key == K_KP_ENTER) { Cbuf_AddText (key_line+1); // skip the ] Cbuf_AddText ("\n"); Key_History_Push(); key_line[0] = ']'; key_line[1] = 0; // EvilTypeGuy: null terminate key_linepos = 1; // force an update, because the command may take some time if (cls.state == ca_disconnected) CL_UpdateScreen (); return; } if (key == K_TAB) { if(keydown[K_CTRL]) // append to the cvar its value { int cvar_len, cvar_str_len, chars_to_move; char k; char cvar[MAX_INPUTLINE]; const char *cvar_str; // go to the start of the variable while(--key_linepos) { k = key_line[key_linepos]; if(k == '\"' || k == ';' || k == ' ' || k == '\'') break; } key_linepos++; // save the variable name in cvar for(cvar_len=0; (k = key_line[key_linepos + cvar_len]) != 0; cvar_len++) { if(k == '\"' || k == ';' || k == ' ' || k == '\'') break; cvar[cvar_len] = k; } if (cvar_len==0) return; cvar[cvar_len] = 0; // go to the end of the cvar key_linepos += cvar_len; // save the content of the variable in cvar_str cvar_str = Cvar_VariableString(cvar); cvar_str_len = strlen(cvar_str); if (cvar_str_len==0) return; // insert space and cvar_str in key_line chars_to_move = strlen(&key_line[key_linepos]); if (key_linepos + 1 + cvar_str_len + chars_to_move < MAX_INPUTLINE) { if (chars_to_move) memmove(&key_line[key_linepos + 1 + cvar_str_len], &key_line[key_linepos], chars_to_move); key_line[key_linepos++] = ' '; memcpy(&key_line[key_linepos], cvar_str, cvar_str_len); key_linepos += cvar_str_len; key_line[key_linepos + chars_to_move] = 0; } else Con_Printf("Couldn't append cvar value, edit line too long.\n"); return; } // Enhanced command completion // by EvilTypeGuy [email protected] // Thanks to Fett, Taniwha Con_CompleteCommandLine(); return; } // Advanced Console Editing by Radix [email protected] // Added/Modified by EvilTypeGuy [email protected] // Enhanced by [515] // Enhanced by terencehill // move cursor to the previous character if (key == K_LEFTARROW || key == K_KP_LEFTARROW) { if (key_linepos < 2) return; if(keydown[K_CTRL]) // move cursor to the previous word { int pos; char k; pos = key_linepos-1; if(pos) // skip all "; ' after the word while(--pos) { k = key_line[pos]; if (!(k == '\"' || k == ';' || k == ' ' || k == '\'')) break; } if(pos) while(--pos) { k = key_line[pos]; if(k == '\"' || k == ';' || k == ' ' || k == '\'') break; } key_linepos = pos + 1; } else if(keydown[K_SHIFT]) // move cursor to the previous character ignoring colors { int pos; size_t inchar = 0; pos = u8_prevbyte(key_line, key_linepos); while (pos) if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && isdigit(key_line[pos])) pos-=2; else if(pos-4 > 0 && key_line[pos-4] == STRING_COLOR_TAG && key_line[pos-3] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos-2]) && isxdigit(key_line[pos-1]) && isxdigit(key_line[pos])) pos-=5; else { if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && key_line[pos] == STRING_COLOR_TAG) // consider ^^ as a character pos--; pos--; break; } // we need to move to the beginning of the character when in a wide character: u8_charidx(key_line, pos + 1, &inchar); key_linepos = pos + 1 - inchar; } else { key_linepos = u8_prevbyte(key_line, key_linepos); } return; } // delete char before cursor if (key == K_BACKSPACE || (key == 'h' && keydown[K_CTRL])) { if (key_linepos > 1) { int newpos = u8_prevbyte(key_line, key_linepos); strlcpy(key_line + newpos, key_line + key_linepos, sizeof(key_line) + 1 - key_linepos); key_linepos = newpos; } return; } // delete char on cursor if (key == K_DEL || key == K_KP_DEL) { size_t linelen; linelen = strlen(key_line); if (key_linepos < (int)linelen) memmove(key_line + key_linepos, key_line + key_linepos + u8_bytelen(key_line + key_linepos, 1), linelen - key_linepos); return; } // move cursor to the next character if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW) { if (key_linepos >= (int)strlen(key_line)) return; if(keydown[K_CTRL]) // move cursor to the next word { int pos, len; char k; len = (int)strlen(key_line); pos = key_linepos; while(++pos < len) { k = key_line[pos]; if(k == '\"' || k == ';' || k == ' ' || k == '\'') break; } if (pos < len) // skip all "; ' after the word while(++pos < len) { k = key_line[pos]; if (!(k == '\"' || k == ';' || k == ' ' || k == '\'')) break; } key_linepos = pos; } else if(keydown[K_SHIFT]) // move cursor to the next character ignoring colors { int pos, len; len = (int)strlen(key_line); pos = key_linepos; // go beyond all initial consecutive color tags, if any if(pos < len) while (key_line[pos] == STRING_COLOR_TAG) { if(isdigit(key_line[pos+1])) pos+=2; else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4])) pos+=5; else break; } // skip the char if (key_line[pos] == STRING_COLOR_TAG && key_line[pos+1] == STRING_COLOR_TAG) // consider ^^ as a character pos++; pos += u8_bytelen(key_line + pos, 1); // now go beyond all next consecutive color tags, if any if(pos < len) while (key_line[pos] == STRING_COLOR_TAG) { if(isdigit(key_line[pos+1])) pos+=2; else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4])) pos+=5; else break; } key_linepos = pos; } else key_linepos += u8_bytelen(key_line + key_linepos, 1); return; } if (key == K_INS || key == K_KP_INS) // toggle insert mode { key_insert ^= 1; return; } // End Advanced Console Editing if (key == K_UPARROW || key == K_KP_UPARROW || (key == 'p' && keydown[K_CTRL])) { Key_History_Up(); return; } if (key == K_DOWNARROW || key == K_KP_DOWNARROW || (key == 'n' && keydown[K_CTRL])) { Key_History_Down(); return; } // ~1.0795 = 82/76 using con_textsize 64 76 is height of the char, 6 is the distance between 2 lines if (key == K_PGUP || key == K_KP_PGUP) { if(keydown[K_CTRL]) { con_backscroll += ((vid_conheight.integer >> 2) / con_textsize.integer)-1; } else con_backscroll += ((vid_conheight.integer >> 1) / con_textsize.integer)-3; return; }