BOOL C4UpdatePackageCore::Save(C4Group &hGroup) { try { // decompile data StdStrBuf Core = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*this, "Update")); char *stupid_buffer = new char[Core.getLength() + 1]; memcpy(stupid_buffer, Core.getMData(), Core.getLength() + 1); // add to group return hGroup.Add(C4CFN_UpdateCore, stupid_buffer, Core.getLength(), FALSE, TRUE); } catch (StdCompiler::Exception *pExc) { delete pExc; return FALSE; } }
StdStrBuf C4FileSelDlg::GetSelection(const char *szFixedSelection, bool fFilenameOnly) const { StdStrBuf sResult; if (!IsMultiSelection()) { // get single selected file for single selection dlg if (pSelection) sResult.Copy(fFilenameOnly ? GetFilename(pSelection->GetFilename()) : pSelection->GetFilename()); } else { // force fixed selection first if (szFixedSelection) sResult.Append(szFixedSelection); // get ';'-seperated list for multi selection dlg for (ListItem *pFileItem = static_cast<ListItem *>(pFileListBox->GetFirst()); pFileItem; pFileItem = static_cast<ListItem *>(pFileItem->GetNext())) if (pFileItem->IsChecked()) { const char *szAppendFilename = pFileItem->GetFilename(); if (fFilenameOnly) szAppendFilename = GetFilename(szAppendFilename); // prevent adding entries twice (especially those from the fixed // selection list) if (!SIsModule(sResult.getData(), szAppendFilename)) { if (sResult.getLength()) sResult.AppendChar(';'); sResult.Append(szAppendFilename); } } } return sResult; }
size_t C4Network2IRCClient::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) { // Find line seperation const char *pSep = reinterpret_cast<const char *>(memchr(rInBuf.getData(), '\n', rInBuf.getSize())); if(!pSep) return 0; // Check if it's actually correct seperation (rarely the case) int iSize = pSep - getBufPtr<char>(rInBuf) + 1, iLength = iSize - 1; if(iLength && *(pSep - 1) == '\r') iLength--; // Copy the line StdStrBuf Buf; Buf.Copy(getBufPtr<char>(rInBuf), iLength); // Ignore prefix const char *pMsg = Buf.getData(); StdStrBuf Prefix; if(*pMsg == ':') { Prefix.CopyUntil(pMsg + 1, ' '); pMsg += Prefix.getLength() + 1; } // Strip whitespace while(*pMsg == ' ') pMsg++; // Ignore empty message if(!*pMsg) return iSize; // Get command StdStrBuf Cmd; Cmd.CopyUntil(pMsg, ' '); // Precess command const char *szParameters = SSearch(pMsg, " "); OnCommand(Prefix.getData(), Cmd.getData(), szParameters ? szParameters : ""); // Consume the line return iSize; }
bool C4TextureMap::SaveMap(C4Group &hGroup, const char *szEntryName) { #ifdef C4ENGINE // build file in memory StdStrBuf sTexMapFile; // add desc sTexMapFile.Append("# Automatically generated texture map" LineFeed); sTexMapFile.Append("# Contains material-texture-combinations added at runtime" LineFeed); // add overload-entries if (fOverloadMaterials) sTexMapFile.Append("# Import materials from global file as well" LineFeed "OverloadMaterials" LineFeed); if (fOverloadTextures) sTexMapFile.Append("# Import textures from global file as well" LineFeed "OverloadTextures" LineFeed); sTexMapFile.Append(LineFeed); // add entries for (int32_t i = 0; i < C4M_MaxTexIndex; i++) if (!Entry[i].isNull()) { // compose line sTexMapFile.AppendFormat("%d=%s-%s" LineFeed, i, Entry[i].GetMaterialName(), Entry[i].GetTextureName()); } // create new buffer allocated with new [], because C4Group cannot handle StdStrBuf-buffers size_t iBufSize = sTexMapFile.getLength(); BYTE *pBuf = new BYTE[iBufSize]; memcpy(pBuf, sTexMapFile.getData(), iBufSize); // add to group bool fSuccess = !!hGroup.Add(szEntryName, pBuf, iBufSize, false, true); if (!fSuccess) delete [] pBuf; // done return fSuccess; #else return FALSE; #endif }
// Helper for IRC command parameter parsing StdStrBuf ircExtractPar(const char **ppPar) { // No parameter left? if(!ppPar || !*ppPar || !**ppPar) return StdStrBuf(""); // Last parameter? StdStrBuf Result; if(**ppPar == ':') { // Reference everything after the double-colon Result.Ref(*ppPar + 1); *ppPar = NULL; } else { // Copy until next space (or end of string) Result.CopyUntil(*ppPar, ' '); // Go over parameters *ppPar += Result.getLength(); if(**ppPar == ' ') (*ppPar)++; else *ppPar = NULL; } // Done return Result; }
StdStrBuf C4Shader::Build(const ShaderSliceList &Slices, bool fDebug) { // At the start of the shader set the #version and number of // available uniforms StdStrBuf Buf; #ifndef USE_CONSOLE GLint iMaxFrags = 0, iMaxVerts = 0; glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &iMaxFrags); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &iMaxVerts); #else int iMaxFrags = INT_MAX, iMaxVerts = INT_MAX; #endif Buf.Format("#version %d\n" "#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n" "#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n", C4Shader_Version, iMaxFrags, iMaxVerts); // Put slices int iPos = -1, iNextPos = -1; do { iPos = iNextPos; iNextPos = C4Shader_LastPosition+1; // Add all slices at the current level if (fDebug && iPos > 0) Buf.AppendFormat("\t// Position %d:\n", iPos); for (ShaderSliceList::const_iterator pSlice = Slices.begin(); pSlice != Slices.end(); pSlice++) { if (pSlice->Position < iPos) continue; if (pSlice->Position > iPos) { iNextPos = Min(iNextPos, pSlice->Position); continue; } // Same position - add slice! if (fDebug) { if (pSlice->Source.getLength()) Buf.AppendFormat("\t// Slice from %s:\n", pSlice->Source.getData()); else Buf.Append("\t// Built-in slice:\n"); } Buf.Append(pSlice->Text); if (Buf[Buf.getLength()-1] != '\n') Buf.AppendChar('\n'); } // Add seperator - only priority (-1) is top-level if (iPos == -1) { Buf.Append("void main() {\n"); } } while (iNextPos <= C4Shader_LastPosition); // Terminate Buf.Append("}\n"); return Buf; }
bool C4Network2IRCClient::Send(const char *szCommand, const char *szParameters) { if(!fConnected) { SetError("not connected"); return false; } // Create message StdStrBuf Msg; if(szParameters) Msg.Format("%s %s", szCommand, szParameters); else Msg.Ref(szCommand); // Send return C4NetIOTCP::Send(C4NetIOPacket(Msg.getData(), Msg.getLength(), false, PeerAddr)); }
bool C4RoundResults::Save(C4Group &hGroup, const char *szFilename) { // remove previous entry from group hGroup.DeleteEntry(szFilename); // decompile try { StdStrBuf Buf = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*this, "RoundResults")); // save it, if not empty if (Buf.getLength()) if (!hGroup.Add(szFilename, Buf, false, true)) return false; } catch (StdCompiler::Exception *) { return false; } // done, success return true; }
StdStrBuf C4KeyCodeEx::ToString(bool fHumanReadable, bool fShort) const { static StdStrBuf sResult; sResult.Clear(); // Add shift for (DWORD dwShiftCheck = KEYS_First; dwShiftCheck <= KEYS_Max; dwShiftCheck <<= 1) if (dwShiftCheck & dwShift) { sResult.Append(KeyShift2String((C4KeyShiftState) dwShiftCheck)); sResult.AppendChar('+'); } // Add key if (sResult.getLength()) { sResult.Append(KeyCode2String(Key, fHumanReadable, fShort)); return sResult; } else { return KeyCode2String(Key, fHumanReadable, fShort); } }
bool LogSilent(const char *szMessage, bool fConsole) { if (!Application.AssertMainThread()) return false; // security if (!szMessage) return false; // add timestamp time_t timenow; time(&timenow); StdStrBuf TimeMessage; TimeMessage.SetLength(11 + SLen(szMessage) + 1); strftime(TimeMessage.getMData(), 11 + 1, "[%H:%M:%S] ", localtime(&timenow)); // output until all data is written const char *pSrc = szMessage; do { // timestamp will always be that length char *pDest = TimeMessage.getMData() + 11; // copy rest of message, skip tags C4Markup Markup(false); while (*pSrc) { Markup.SkipTags(&pSrc); // break on crlf while (*pSrc == '\r') pSrc++; if (*pSrc == '\n') { pSrc++; break; } // copy otherwise if (*pSrc) *pDest++ = *pSrc++; } *pDest++='\n'; *pDest = '\0'; // Save into log file if (C4LogFile) { fputs(TimeMessage.getData(),C4LogFile); fflush(C4LogFile); } // Save into record log file, if available if(Control.GetRecord()) { Control.GetRecord()->GetLogFile()->Write(TimeMessage.getData(), TimeMessage.getLength()); #ifdef IMMEDIATEREC Control.GetRecord()->GetLogFile()->Flush(); #endif } // Write to console if (fConsole) { #if defined(_WIN32) // debug: output to VC console OutputDebugString(TimeMessage.GetWideChar()); #endif #if !defined(_WIN32) || defined(USE_CONSOLE) fputs(TimeMessage.getData(),stdout); fflush(stdout); #endif } } while (*pSrc); return true; }
bool CStdGL::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat) { // TODO: If a technique is not available, show an error message what the problem is // select context, if not already done if (!pCurrCtx) return false; for (unsigned int i = 0; i < mat.Techniques.size(); ++i) { StdMeshMaterialTechnique& technique = mat.Techniques[i]; technique.Available = true; for (unsigned int j = 0; j < technique.Passes.size(); ++j) { StdMeshMaterialPass& pass = technique.Passes[j]; GLint max_texture_units; glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units); // OpenGL 3.x guarantees at least 16 TIUs. If the above returns // less it's probably a driver bug. So just keep going. assert(max_texture_units >= 16); max_texture_units = std::min<GLint>(max_texture_units, 16); unsigned int active_texture_units = 0; for(unsigned int k = 0; k < pass.TextureUnits.size(); ++k) if(pass.TextureUnits[k].HasTexture()) ++active_texture_units; if (active_texture_units > static_cast<unsigned int>(max_texture_units)) technique.Available = false; for (unsigned int k = 0; k < pass.TextureUnits.size(); ++k) { StdMeshMaterialTextureUnit& texunit = pass.TextureUnits[k]; for (unsigned int l = 0; l < texunit.GetNumTextures(); ++l) { const C4TexRef& texture = texunit.GetTexture(l); glBindTexture(GL_TEXTURE_2D, texture.texName); switch (texunit.TexAddressMode) { case StdMeshMaterialTextureUnit::AM_Wrap: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); break; case StdMeshMaterialTextureUnit::AM_Border: glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, texunit.TexBorderColor); // fallthrough case StdMeshMaterialTextureUnit::AM_Clamp: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); break; case StdMeshMaterialTextureUnit::AM_Mirror: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); break; } switch (texunit.Filtering[0]) // min { case StdMeshMaterialTextureUnit::F_None: technique.Available = false; break; case StdMeshMaterialTextureUnit::F_Point: switch (texunit.Filtering[2]) // mip { case StdMeshMaterialTextureUnit::F_None: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break; case StdMeshMaterialTextureUnit::F_Point: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); break; case StdMeshMaterialTextureUnit::F_Linear: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); break; case StdMeshMaterialTextureUnit::F_Anisotropic: technique.Available = false; // invalid break; } break; case StdMeshMaterialTextureUnit::F_Linear: switch (texunit.Filtering[2]) // mip { case StdMeshMaterialTextureUnit::F_None: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break; case StdMeshMaterialTextureUnit::F_Point: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); break; case StdMeshMaterialTextureUnit::F_Linear: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break; case StdMeshMaterialTextureUnit::F_Anisotropic: technique.Available = false; // invalid break; } break; case StdMeshMaterialTextureUnit::F_Anisotropic: // unsupported technique.Available = false; break; } switch (texunit.Filtering[1]) // max { case StdMeshMaterialTextureUnit::F_None: technique.Available = false; // invalid break; case StdMeshMaterialTextureUnit::F_Point: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case StdMeshMaterialTextureUnit::F_Linear: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case StdMeshMaterialTextureUnit::F_Anisotropic: // unsupported technique.Available = false; break; } } // loop over textures } // loop over texture units // Create fragment and/or vertex shader // if a custom shader is not provided. // Re-use existing programs if the generated // code is the same (determined by SHA1 hash). bool custom_shader = true; if(!pass.VertexShader.Shader) { StdStrBuf buf = GetVertexShaderCodeForPass(pass, Workarounds.LowMaxVertexUniformCount); StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength()); pass.VertexShader.Shader = mat_manager.AddShader("auto-generated vertex shader", hash.getData(), "glsl", SMMS_VERTEX, buf.getData(), StdMeshMatManager::SMM_AcceptExisting); custom_shader = false; } if(!pass.FragmentShader.Shader) { // TODO: Should use shared_params once we introduce them StdStrBuf buf = GetFragmentShaderCodeForPass(pass, pass.FragmentShader.Parameters); StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength()); pass.FragmentShader.Shader = mat_manager.AddShader("auto-generated fragment shader", hash.getData(), "glsl", SMMS_FRAGMENT, buf.getData(), StdMeshMatManager::SMM_AcceptExisting); } // Then, link the program, and resolve parameter locations StdStrBuf name(FormatString("%s:%s:%s", mat.Name.getData(), technique.Name.getData(), pass.Name.getData())); const StdMeshMaterialProgram* added_program = mat_manager.AddProgram(name.getData(), loader, pass.FragmentShader, pass.VertexShader, pass.GeometryShader); if(!added_program) { // If the program could not be compiled, try again with the LowMaxVertexUniformCount workaround. // See bug #1368. if (!custom_shader && !Workarounds.LowMaxVertexUniformCount) { StdStrBuf buf = GetVertexShaderCodeForPass(pass, true); StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength()); pass.VertexShader.Shader = mat_manager.AddShader("auto-generated vertex shader", hash.getData(), "glsl", SMMS_VERTEX, buf.getData(), StdMeshMatManager::SMM_AcceptExisting); added_program = mat_manager.AddProgram(name.getData(), loader, pass.FragmentShader, pass.VertexShader, pass.GeometryShader); if(added_program) { // If this actually work, cache the result, so we don't // need to fail again next time before trying the workaround. Workarounds.LowMaxVertexUniformCount = true; Log(" gl: Enabling low max vertex uniform workaround"); } } } if (!added_program) { technique.Available = false; } else { std::unique_ptr<StdMeshMaterialPass::ProgramInstance> program_instance(new StdMeshMaterialPass::ProgramInstance(added_program, &pass.FragmentShader, &pass.VertexShader, &pass.GeometryShader)); pass.Program = std::move(program_instance); } } if (technique.Available && mat.BestTechniqueIndex == -1) mat.BestTechniqueIndex = i; } return mat.BestTechniqueIndex != -1; }
C4AulDebug::ProcessLineResult C4AulDebug::ProcessLine(const StdStrBuf &Line) { // Get command StdStrBuf Cmd; Cmd.CopyUntil(Line.getData(), ' '); // Get data const char *szData = Line.getPtr(Cmd.getLength()); if (*szData) szData++; // Identify command const char *szCmd = Cmd.getData(); if (SEqualNoCase(szCmd, "HELP")) return ProcessLineResult(false, "Yeah, like I'm going to explain that /here/"); else if (SEqualNoCase(szCmd, "BYE") || SEqualNoCase(szCmd, "QUIT")) C4NetIOTCP::Close(PeerAddr); else if (SEqualNoCase(szCmd, "SAY")) ::Control.DoInput(CID_Message, new C4ControlMessage(C4CMT_Normal, szData), CDT_Direct); else if (SEqualNoCase(szCmd, "CMD")) ::MessageInput.ProcessCommand(szData); else if (SEqualNoCase(szCmd, "STP") || SEqualNoCase(szCmd, "S")) eState = DS_Step; else if (SEqualNoCase(szCmd, "GO") || SEqualNoCase(szCmd, "G")) eState = DS_Go; else if (SEqualNoCase(szCmd, "STO") || SEqualNoCase(szCmd, "O")) eState = DS_StepOver; else if (SEqualNoCase(szCmd, "STR") || SEqualNoCase(szCmd, "R")) eState = DS_StepOut; else if (SEqualNoCase(szCmd, "EXC") || SEqualNoCase(szCmd, "E")) { C4AulScriptContext* context = pExec->GetContext(pExec->GetContextDepth()-1); int32_t objectNum = C4ControlScript::SCOPE_Global; if (context && context->Obj && context->Obj->GetObject()) objectNum = context->Obj->GetObject()->Number; ::Control.DoInput(CID_Script, new C4ControlScript(szData, objectNum, true), CDT_Decide); } else if (SEqualNoCase(szCmd, "PSE")) if (Game.IsPaused()) { Game.Unpause(); return ProcessLineResult(true, "Game unpaused."); } else { Game.Pause(); return ProcessLineResult(true, "Game paused."); } else if (SEqualNoCase(szCmd, "LST")) { for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next) { SendLine(RelativePath(script->ScriptName)); } } // toggle breakpoint else if (SEqualNoCase(szCmd, "TBR")) { using namespace std; // FIXME: this doesn't find functions which were included/appended string scriptPath = szData; size_t colonPos = scriptPath.find(':'); if (colonPos == string::npos) return ProcessLineResult(false, "Missing line in breakpoint request"); int line = atoi(&scriptPath[colonPos+1]); scriptPath.erase(colonPos); C4AulScript *script; for (script = ScriptEngine.Child0; script; script = script->Next) { if (SEqualNoCase(RelativePath(script->ScriptName), scriptPath.c_str())) break; } auto sh = script ? script->GetScriptHost() : NULL; if (sh) { C4AulBCC * found = NULL; for (auto script = ::ScriptEngine.Child0; script; script = script->Next) for (C4PropList *props = script->GetPropList(); props; props = props->GetPrototype()) for (auto fname = props->EnumerateOwnFuncs(); fname; fname = props->EnumerateOwnFuncs(fname)) { C4Value val; if (!props->GetPropertyByS(fname, &val)) continue; auto func = val.getFunction(); if (!func) continue; auto sfunc = func->SFunc(); if (!sfunc) continue; if (sfunc->pOrgScript != sh) continue; for (auto chunk = sfunc->GetCode(); chunk->bccType != AB_EOFN; chunk++) { if (chunk->bccType == AB_DEBUG) { int lineOfThisOne = sfunc->GetLineOfCode(chunk); if (lineOfThisOne == line) { found = chunk; goto Found; } } } } Found: if (found) found->Par.i = !found->Par.i; // activate breakpoint else return ProcessLineResult(false, "Can't set breakpoint (wrong line?)"); } else return ProcessLineResult(false, "Can't find script"); } else if (SEqualNoCase(szCmd, "SST")) { std::list<StdStrBuf*>::iterator it = StackTrace.begin(); for (it++; it != StackTrace.end(); it++) { SendLine("AT", (*it)->getData()); } SendLine("EST"); } else if (SEqualNoCase(szCmd, "VAR")) { C4Value *val = NULL; int varIndex; C4AulScriptContext* pCtx = pExec->GetContext(pExec->GetContextDepth() - 1); if (pCtx) { if ((varIndex = pCtx->Func->ParNamed.GetItemNr(szData)) != -1) { val = &pCtx->Pars[varIndex]; } else if ((varIndex = pCtx->Func->VarNamed.GetItemNr(szData)) != -1) { val = &pCtx->Vars[varIndex]; } } const char* typeName = val ? GetC4VName(val->GetType()) : "any"; StdStrBuf output = FormatString("%s %s %s", szData, typeName, val ? val->GetDataString().getData() : "Unknown"); SendLine("VAR", output.getData()); } else return ProcessLineResult(false, "Can't do that"); return ProcessLineResult(true, ""); }
bool C4ChatControl::ProcessInput(const char *szInput, ChatSheet *pChatSheet) { CStdLock Lock(pIRCClient->getCSec()); // process chat input - return false if no more pasting is to be done (i.e., // on /quit or /part in channel) bool fResult = true; bool fIRCSuccess = true; // not connected? if (!pIRCClient->IsConnected()) { pChatSheet->DoError(LoadResStr("IDS_ERR_NOTCONNECTEDTOSERVER")); return fResult; } // safety if (!szInput || !*szInput || !pChatSheet) return fResult; // command? if (*szInput == '/' && !SEqual2NoCase(szInput + 1, "me ")) { StdStrBuf sCommand, sParam(""); ; sCommand.Copy(szInput + 1); sCommand.SplitAtChar(' ', &sParam); if (SEqualNoCase(sCommand.getData(), "quit")) { // query disconnect from IRC server fIRCSuccess = pIRCClient->Quit(sParam.getData()); fResult = false; } else if (SEqualNoCase(sCommand.getData(), "part")) { // part channel. Default to current channel if typed within a channel if (!sParam.getLength() && pChatSheet->GetSheetType() == ChatSheet::CS_Channel) { sParam.Copy(pChatSheet->GetIdent()); fResult = false; } fIRCSuccess = pIRCClient->Part(sParam.getData()); } else if (SEqualNoCase(sCommand.getData(), "join") || SEqualNoCase(sCommand.getData(), "j")) { if (!sParam.getLength()) sParam.Copy(Config.IRC.Channel); fIRCSuccess = pIRCClient->Join(sParam.getData()); } else if (SEqualNoCase(sCommand.getData(), "notice") || SEqualNoCase(sCommand.getData(), "msg")) { bool fMsg = SEqualNoCase(sCommand.getData(), "msg"); StdStrBuf sMsg; if (!sParam.SplitAtChar(' ', &sMsg) || !sMsg.getLength()) { pChatSheet->DoError( FormatString(LoadResStr("IDS_ERR_INSUFFICIENTPARAMETERS"), sCommand.getData()).getData()); } else { if (fMsg) fIRCSuccess = pIRCClient->Message(sParam.getData(), sMsg.getData()); else fIRCSuccess = pIRCClient->Notice(sParam.getData(), sMsg.getData()); } } else if (SEqualNoCase(sCommand.getData(), "raw")) { if (!sParam.getLength()) pChatSheet->DoError( FormatString(LoadResStr("IDS_ERR_INSUFFICIENTPARAMETERS"), sCommand.getData()).getData()); else fIRCSuccess = pIRCClient->Send(sParam.getData()); } else if (SEqualNoCase(sCommand.getData(), "ns") || SEqualNoCase(sCommand.getData(), "cs") || SEqualNoCase(sCommand.getData(), "ms")) { if (!sParam.getLength()) pChatSheet->DoError( FormatString(LoadResStr("IDS_ERR_INSUFFICIENTPARAMETERS"), sCommand.getData()).getData()); else { const char *szMsgTarget; if (SEqualNoCase(sCommand.getData(), "ns")) szMsgTarget = "NickServ"; else if (SEqualNoCase(sCommand.getData(), "cs")) szMsgTarget = "ChanServ"; else szMsgTarget = "MemoServ"; fIRCSuccess = pIRCClient->Message(szMsgTarget, sParam.getData()); } } else if (SEqualNoCase(sCommand.getData(), "query") || SEqualNoCase(sCommand.getData(), "q")) { if (!sParam.getLength()) pChatSheet->DoError( FormatString(LoadResStr("IDS_ERR_INSUFFICIENTPARAMETERS"), sCommand.getData()).getData()); else OpenQuery(sParam.getData(), true, NULL); } else if (SEqualNoCase(sCommand.getData(), "nick")) { if (C4InVal::ValidateString(sParam, C4InVal::VAL_IRCName)) pChatSheet->DoError(FormatString(LoadResStr("IDS_ERR_INVALIDNICKNAME2"), sCommand.getData()).getData()); else fIRCSuccess = pIRCClient->ChangeNick(sParam.getData()); } else { // unknown command pChatSheet->DoError(FormatString(LoadResStr("IDS_ERR_UNKNOWNCMD"), sCommand.getData()).getData()); } } else { // regular chat input: Send as message to current channel/user const char *szMsgTarget; ChatSheet::SheetType eSheetType = pChatSheet->GetSheetType(); if (eSheetType == ChatSheet::CS_Server) { pChatSheet->DoError(LoadResStr("IDS_ERR_NOTONACHANNEL")); } else { szMsgTarget = pChatSheet->GetTitle(); if (*szInput == '/') // action fIRCSuccess = pIRCClient->Action(szMsgTarget, szInput + 4); else fIRCSuccess = pIRCClient->Message(szMsgTarget, szInput); } } // IRC sending error? log it if (!fIRCSuccess) { pChatSheet->DoError(pIRCClient->GetError()); } return fResult; }
bool ValidateString(StdStrBuf &rsString, ValidationOption eOption) { bool fValid = true; // validation depending on option // check min length if (!rsString.getLength()) { // empty if not allowed? if (eOption != VAL_NameAllowEmpty && eOption != VAL_NameExAllowEmpty && eOption != VAL_Comment) { rsString.Copy("empty"); fValid = false; } } switch (eOption) { case VAL_Filename: // regular filenames only // absolutely no directory traversal if (rsString.ReplaceChar('/', '_')) fValid = false; if (rsString.ReplaceChar('\\', '_')) fValid = false; // fallthrough to general file name validation case VAL_SubPathFilename: // filenames and optional subpath // do not traverse upwards in file hierarchy if (rsString.Replace("..", "__")) fValid = false; if (*rsString.getData() == '/' || *rsString.getData() == '\\') { *rsString.getMData() = '_'; fValid = false; } // fallthrough to general file name validation case VAL_FullPath: // full filename paths // some characters are prohibited in filenames in general if (rsString.ReplaceChar('*', '_')) fValid = false; if (rsString.ReplaceChar('?', '_')) fValid = false; if (rsString.ReplaceChar('<', '_')) fValid = false; if (rsString.ReplaceChar('>', '_')) fValid = false; // ';' and '|' is never allowed in filenames, because it would cause problems in many engine internal file lists if (rsString.ReplaceChar(';', '_')) fValid = false; if (rsString.ReplaceChar('|', '_')) fValid = false; // the colon is generally prohibited except at pos 2 (C:\...), because it could lead to creation of (invisible) streams on NTFS if (rsString.ReplaceChar(':', '_', 2)) fValid = false; if (*rsString.getData() == ':') { *rsString.getMData() = '_'; fValid = false; } // validate drive letter if (rsString.getLength()>=2 && *rsString.getPtr(1) == ':') { if (eOption != VAL_FullPath) { *rsString.getMPtr(1)='_'; fValid = false; } else if (!isalpha((unsigned char)*rsString.getData()) || (*rsString.getPtr(2)!='\\' && *rsString.getPtr(2)!='/')) { *rsString.getMData()=*rsString.getMPtr(1)='_'; fValid = false; } } break; case VAL_NameNoEmpty: case VAL_NameAllowEmpty: // no markup if (CMarkup::StripMarkup(&rsString)) { fValid = false; } // trim spaces if (rsString.TrimSpaces()) fValid = false; // min length if (eOption == VAL_NameNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); } // max length if (rsString.getLength() > C4MaxName) { fValid = false; rsString.SetLength(C4MaxName); } break; case VAL_NameExNoEmpty: case VAL_NameExAllowEmpty: // trim spaces if (rsString.TrimSpaces()) fValid = false; // min length if (eOption == VAL_NameExNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); } // max length if (rsString.getLength() > C4MaxLongName) { fValid = false; rsString.SetLength(C4MaxLongName); } break; case VAL_IRCName: // nickname for IRC. a-z, A-Z, _^{[]} only; 0-9|- inbetween; max 30 characters if (rsString.getLength() > 30) fValid = false; if (rsString.getLength() < 2) fValid = false; if (!rsString.ValidateChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}0123456789|-")) { fValid = false; rsString.Copy("Guest"); } if (SEqualNoCase(rsString.getData(), "NickServ") || SEqualNoCase(rsString.getData(), "ChanServ") || SEqualNoCase(rsString.getData(), "MemoServ") || SEqualNoCase(rsString.getData(), "OperServ") || SEqualNoCase(rsString.getData(), "HelpServ")) fValid = false; if (!fValid) rsString.Copy("Guest"); break; case VAL_IRCPass: // password for IRC; max 31 characters // max length; no spaces if (rsString.getLength() > 31) { fValid = false; rsString.SetLength(31); } if (rsString.getLength() < 2) { fValid = false; rsString.Copy("secret"); } if (rsString.ReplaceChar(' ', '_')) fValid = false; break; case VAL_IRCChannel: // IRC channel name if (rsString.getLength() > 32) { fValid = false; rsString.SetLength(32); } else if (rsString.getLength() < 2) { fValid = false; rsString.Copy("#clonken"); } else if (*rsString.getData() != '#' && *rsString.getData() != '+') { fValid = false; *rsString.getMData() = '#'; } if (rsString.ReplaceChar(' ', '_')) fValid = false; break; case VAL_Comment: // comment - just limit length if (rsString.getLength() > C4MaxComment) { fValid = false; rsString.SetLength(C4MaxComment); } break; default: assert(!"not yet implemented"); } // issue warning for invalid adjustments if (!fValid) { const char *szOption = "unknown"; switch (eOption) { case VAL_Filename: szOption = "filename"; break; case VAL_SubPathFilename: szOption = "(sub-)filename"; break; case VAL_FullPath: szOption = "free filename"; break; case VAL_NameNoEmpty: szOption = "strict name"; break; case VAL_NameExNoEmpty: szOption = "name"; break; case VAL_NameAllowEmpty: szOption = "strict name*"; break; case VAL_NameExAllowEmpty: szOption = "name*"; break; case VAL_IRCName: szOption = "IRC nick"; break; case VAL_IRCPass: szOption = "IRC password"; break; case VAL_IRCChannel: szOption = "IRC channel"; break; case VAL_Comment: szOption = "Comment"; break; } //LogF("WARNING: Adjusted invalid user input for \"%s\" to \"%s\"", szOption, rsString.getData()); } return !fValid; }
StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort) { // Gamepad keys if (Key_IsGamepad(wCode)) { int iGamepad = Key_GetGamepad(wCode); int gamepad_event = Key_GetGamepadEvent(wCode); switch (gamepad_event) { case KEY_JOY_Left: return FormatString("Joy%dLeft", iGamepad+1); case KEY_JOY_Up: return FormatString("Joy%dUp", iGamepad+1); case KEY_JOY_Down: return FormatString("Joy%dDown", iGamepad+1); case KEY_JOY_Right: return FormatString("Joy%dRight", iGamepad+1); default: if (Key_IsGamepadAxis(wCode)) { if (fHumanReadable) // This is still not great, but it is not really possible to assign unknown axes to "left/right" "up/down"... return FormatString("[%d] %s", int(1 + Key_GetGamepadAxisIndex(wCode)), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min"); else return FormatString("Joy%dAxis%d%s", iGamepad+1, static_cast<int>(Key_GetGamepadAxisIndex(wCode)+1), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min"); } else { // button if (fHumanReadable) // If there should be gamepads around with A B C D... on the buttons, we might create a display option to show letters instead... return FormatString("< %d >", int(1 + Key_GetGamepadButtonIndex(wCode))); else return FormatString("Joy%d%c", iGamepad+1, static_cast<char>(Key_GetGamepadButtonIndex(wCode) + 'A')); } } } // Mouse keys if (Key_IsMouse(wCode)) { int mouse_id = Key_GetMouse(wCode); int mouse_event = Key_GetMouseEvent(wCode); const char *mouse_str = "Mouse"; switch (mouse_event) { case KEY_MOUSE_Move: return FormatString("%s%dMove", mouse_str, mouse_id); case KEY_MOUSE_Wheel1Up: return FormatString("%s%dWheel1Up", mouse_str, mouse_id); case KEY_MOUSE_Wheel1Down: return FormatString("%s%dWheel1Down", mouse_str, mouse_id); case KEY_MOUSE_ButtonLeft: return FormatString("%s%dLeft", mouse_str, mouse_id); case KEY_MOUSE_ButtonRight: return FormatString("%s%dRight", mouse_str, mouse_id); case KEY_MOUSE_ButtonMiddle: return FormatString("%s%dMiddle", mouse_str, mouse_id); case KEY_MOUSE_ButtonLeftDouble: return FormatString("%s%dLeftDouble", mouse_str, mouse_id); case KEY_MOUSE_ButtonRightDouble: return FormatString("%s%dRightDouble", mouse_str, mouse_id); case KEY_MOUSE_ButtonMiddleDouble: return FormatString("%s%dMiddleDouble", mouse_str, mouse_id); default: // extended mouse button { uint8_t btn = Key_GetMouseEvent(wCode); if (btn >= KEY_MOUSE_Button1Double) return FormatString("%s%dButton%dDouble", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1Double)); else return FormatString("%s%dButton%d", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1)); } } } // it's a keyboard key if (!fHumanReadable) { // for config files and such: dump scancode return FormatString("$%x", static_cast<unsigned int>(wCode)); } #if defined(USE_WIN32_WINDOWS) || (defined(_WIN32) && defined(USE_GTK)) // Query map const C4KeyCodeMapEntry *pCheck = KeyCodeMap; while (pCheck->szName) if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName); else ++pCheck; // TODO: Works? // StdStrBuf Name; Name.SetLength(1000); // int res = GetKeyNameText(wCode, Name.getMData(), Name.getSize()); // if(!res) // // not found: Compose as direct code // return FormatString("\\x%x", (DWORD) wCode); // // Set size // Name.SetLength(res); // return Name; wchar_t buf[100]; int len = GetKeyNameText(wCode<<16, buf, 100); if (len > 0) { // buf is nullterminated name return StdStrBuf(buf); } #elif defined (USE_COCOA) // query map const C4KeyCodeMapEntry *pCheck = KeyCodeMap; while (pCheck->szName) if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName); else ++pCheck; // not found: Compose as direct code return FormatString("\\x%x", static_cast<unsigned int>(wCode)); #elif defined(USE_GTK) Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default()); KeySym keysym = (KeySym)XkbKeycodeToKeysym(dpy,wCode+8,0,0); char* name = NULL; if (keysym != NoSymbol) { // is the keycode without shift modifiers mapped to a symbol? name = gtk_accelerator_get_label_with_keycode(gdk_display_get_default(), keysym, wCode+8, (GdkModifierType)0); } if (name) { // is there a string representation of the keysym? // prevent memleak StdStrBuf buf; buf.Copy(name); g_free(name); return buf; } #elif defined(USE_SDL_MAINLOOP) StdStrBuf buf; buf.Copy(SDL_GetScancodeName(static_cast<SDL_Scancode>(wCode))); if (!buf.getLength()) buf.Format("\\x%x", wCode); return buf; #endif return FormatString("$%x", static_cast<unsigned int>(wCode)); }
C4KeyCode C4KeyCodeEx::String2KeyCode(const StdStrBuf &sName) { // direct key code? if (sName.getLength() > 2) { unsigned int dwRVal; if (sscanf(sName.getData(), "\\x%x", &dwRVal) == 1) return dwRVal; // scan code if (*sName.getData() == '$') return GetKeyByScanCode(sName.getData()); // direct gamepad code #ifdef _WIN32 if (!strnicmp(sName.getData(), "Joy", 3)) #else if (!strncasecmp(sName.getData(), "Joy", 3)) #endif { int iGamepad; if (sscanf(sName.getData(), "Joy%d", &iGamepad) == 1) { // skip Joy[number] const char *key_str = sName.getData()+4; while (isdigit(*key_str)) ++key_str; // check for button (single, uppercase letter) (e.g. Joy1A) if (*key_str && !key_str[1]) { char cGamepadButton = toupper(*key_str); if (Inside(cGamepadButton, 'A', 'Z')) { cGamepadButton = cGamepadButton - 'A'; return KEY_Gamepad(iGamepad-1, KEY_JOY_Button(cGamepadButton)); } } else { // check for standard axis (e.g. Joy1Left) if (!stricmp(key_str, "Left")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Left); if (!stricmp(key_str, "Up")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Up); if (!stricmp(key_str, "Down")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Down); if (!stricmp(key_str, "Right")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Right); // check for specific axis (e.g. Joy1Axis1Min) int iAxis; if (sscanf(key_str, "Axis%d", &iAxis) == 1 && iAxis>0) { --iAxis; // axis is 0-based internally but written 1-based in config key_str += 5; while (isdigit(*key_str)) ++key_str; if (!stricmp(key_str, "Min")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Axis(iAxis, false)); if (!stricmp(key_str, "Max")) return KEY_Gamepad(iGamepad-1, KEY_JOY_Axis(iAxis, true)); } } } } bool is_mouse_key; #ifdef _WIN32 is_mouse_key = !strnicmp(sName.getData(), "Mouse", 5); #else is_mouse_key = !strncasecmp(sName.getData(), "Mouse", 5); #endif if (is_mouse_key) { // skip Mouse/GameMouse const char *key_str = sName.getData()+5; int mouse_id; if (sscanf(key_str, "%d", &mouse_id) == 1) { // skip number while (isdigit(*key_str)) ++key_str; // check for known mouse events (e.g. Mouse1Move or GameMouse1Wheel) if (!stricmp(key_str, "Move")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Move); if (!stricmp(key_str, "Wheel1Up")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Wheel1Up); if (!stricmp(key_str, "Wheel1Down")) return KEY_Mouse(mouse_id-1, KEY_MOUSE_Wheel1Down); if (SEqualNoCase(key_str, "Button", 6)) // e.g. Mouse1ButtonLeft or GameMouse1ButtonRightDouble { // check for known mouse button events uint8_t mouseevent_id = 0; key_str += 6; if (SEqualNoCase(key_str, "Left",4)) { mouseevent_id=KEY_MOUSE_ButtonLeft; key_str += 4; } else if (SEqualNoCase(key_str, "Right",5)) { mouseevent_id=KEY_MOUSE_ButtonRight; key_str += 5; } else if (SEqualNoCase(key_str, "Middle",6)) { mouseevent_id=KEY_MOUSE_ButtonMiddle; key_str += 6; } else if (isdigit(*key_str)) { // indexed mouse button (e.g. Mouse1Button4 or Mouse1Button4Double) int button_index; if (sscanf(key_str, "%d", &button_index) == 1) { mouseevent_id=static_cast<uint8_t>(KEY_MOUSE_Button1+button_index-1); while (isdigit(*key_str)) ++key_str; } } if (mouseevent_id) { // valid event if finished or followed by "Double" if (!*key_str) return KEY_Mouse(mouse_id-1, mouseevent_id); if (!stricmp(key_str, "Double")) return KEY_Mouse(mouse_id-1, mouseevent_id+(KEY_MOUSE_Button1Double-KEY_MOUSE_Button1)); // invalid mouse key... } } } } } // query map const C4KeyCodeMapEntry *pCheck = KeyCodeMap; while (pCheck->szName) { if (SEqualNoCase(sName.getData(), pCheck->szName)) { return(pCheck->wCode); } ++pCheck; } #if defined(USE_SDL_MAINLOOP) SDL_Scancode s = SDL_GetScancodeFromName(sName.getData()); if (s != SDL_SCANCODE_UNKNOWN) return s; #endif return KEY_Undefined; }
// Copy the text to the clipboard or the primary selection bool C4AbstractApp::Copy(const StdStrBuf & text, bool fClipboard) { gtk_clipboard_set_text(gtk_clipboard_get(fClipboard ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY), text.getData(), text.getLength()); return true; }
void C4Network2IRCClient::OnNumericCommand(const char *szSender, int iCommand, const char *szParameters) { bool fShowMessage = true; // Get target StdStrBuf Target = ircExtractPar(&szParameters); // Handle command switch(iCommand) { case 433: // Nickname already in use { StdStrBuf DesiredNick = ircExtractPar(&szParameters); // Automatically try to choose a new one DesiredNick.AppendChar('_'); Send("NICK", DesiredNick.getData()); break; } case 376: // End of MOTD case 422: // MOTD missing // Let's take this a sign that the connection is established. OnConnected(); break; case 331: // No topic set case 332: // Topic notify / change { // Get Channel name and topic StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Topic = (iCommand == 332 ? ircExtractPar(&szParameters) : StdStrBuf("")); // Set it AddChannel(Channel.getData())->OnTopic(Topic.getData()); // Log if(Topic.getLength()) PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_TOPICIN"), Channel.getData(), Topic.getData()).getData()); } break; case 333: // Last topic change fShowMessage = false; // ignore break; case 353: // Names in channel { // Get Channel name and name list StdStrBuf Junk = ircExtractPar(&szParameters); // ??! StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Names = ircExtractPar(&szParameters); // Set it AddChannel(Channel.getData())->OnUsers(Names.getData(), Prefixes.getData()); fShowMessage = false; } break; case 366: // End of names list { // Get Channel name StdStrBuf Channel = ircExtractPar(&szParameters); // Finish AddChannel(Channel.getData())->OnUsersEnd(); fShowMessage = false; // Notify if(pNotify) pNotify->PushEvent(Ev_IRC_Message, this); } break; case 4: // Server version fShowMessage = false; // ignore break; case 5: // Server support string { while(szParameters && *szParameters) { // Get support-token. StdStrBuf Token = ircExtractPar(&szParameters); StdStrBuf Parameter; Parameter.CopyUntil(Token.getData(), '='); // Check if it's interesting and safe data if so. if(SEqualNoCase(Parameter.getData(), "PREFIX")) Prefixes.Copy(SSearch(Token.getData(), "=")); } fShowMessage = false; } break; } // Show embedded message, if any? if(fShowMessage) { // Check if first parameter is some sort of channel name C4Network2IRCChannel *pChannel = NULL; if(szParameters && *szParameters && *szParameters != ':') pChannel = getChannel(ircExtractPar(&szParameters).getData()); // Go over other parameters const char *pMsg = szParameters; while(pMsg && *pMsg && *pMsg != ':') pMsg = SSearch(pMsg, " "); // Show it if(pMsg && *pMsg) if(!pChannel) PushMessage(MSG_Server, szSender, Nick.getData(), pMsg + 1); else PushMessage(MSG_Status, szSender, pChannel->getName(), pMsg + 1); } }
void C4KeyCodeEx::CompileFunc(StdCompiler *pComp, StdStrBuf *pOutBuf) { if (pComp->isCompiler()) { // reading from file StdStrBuf sCode; bool is_scan_code; // read shifts DWORD dwSetShift = 0; for (;;) { is_scan_code = pComp->Separator(StdCompiler::SEP_DOLLAR); if (!is_scan_code) pComp->NoSeparator(); pComp->Value(mkParAdapt(sCode, StdCompiler::RCT_Idtf)); if (is_scan_code) // scan codes start with $. Reassamble the two tokens that were split by StdCompiler { sCode.Take(FormatString("$%s", sCode.getData())); break; } if (!pComp->Separator(StdCompiler::SEP_PLUS)) break; // no more separator: Parse this as keyboard code // try to convert to shift state C4KeyShiftState eAddState = String2KeyShift(sCode); if (eAddState == KEYS_Undefined) pComp->excCorrupt("undefined key shift state: %s", sCode.getData()); dwSetShift |= eAddState; } // any code given? Otherwise, keep default if (sCode.getLength()) { // last section: convert to key code C4KeyCode eCode = String2KeyCode(sCode); if (eCode == KEY_Undefined) { if (pOutBuf) { // unknown key, but an output buffer for unknown keys was provided. No failure; caller might resolve key. eCode = KEY_Default; } else { pComp->excCorrupt("undefined key code: %s", sCode.getData()); } } dwShift = dwSetShift; Key = eCode; if (pOutBuf) pOutBuf->Take(std::move(sCode)); } } else { // write shift states for (DWORD dwShiftCheck = KEYS_First; dwShiftCheck <= KEYS_Max; dwShiftCheck <<= 1) if (dwShiftCheck & dwShift) { pComp->Value(mkDecompileAdapt(KeyShift2String((C4KeyShiftState) dwShiftCheck))); pComp->Separator(StdCompiler::SEP_PLUS); } // write key pComp->Value(mkDecompileAdapt(KeyCode2String(Key, false, false))); } }