// ────────────────────────────────────────────────────────────────────────── int main() { try { load_fonts(); if(!graf_init_lfb()) return -1; EventManager ev; Event e; boxframe(0,0,799,599, true); buttonframe(515,3,796,514,false); AddHandler(new OpenFileHandler); AddHandler(new SaveFileHandler); AddHandler(new SaveFileAsHandler); AddHandler(new ExitHandler); AddHandler(new PaintImageHandler); e.what = ev_null; // init handlers CallHandlers(e); while(going) { ev.get_event(e); if(e.what != ev_null) CallHandlers(e); } graf_close(); } catch(Exception& e) { graf_close(); printf("Exception! %s\n", e.reason()); } return 0; }
/***************************************************** NAME : PerformMessage DESCRIPTION : Calls core framework for a message INPUTS : 1) Caller's result buffer 2) Message argument expressions (including implicit object) 3) Message name RETURNS : Nothing useful SIDE EFFECTS : Any side-effects of message execution and caller's result buffer set NOTES : None *****************************************************/ static void PerformMessage( DATA_OBJECT *result, EXPRESSION *args, SYMBOL_HN *mname) { int oldce; HANDLER_LINK *oldCore; DEFCLASS *cls = NULL; INSTANCE_TYPE *ins = NULL; SYMBOL_HN *oldName; #if PROFILING_FUNCTIONS struct profileFrameInfo profileFrame; #endif result->type = SYMBOL; result->value = FalseSymbol; EvaluationError = FALSE; if (HaltExecution) return; oldce = ExecutingConstruct(); SetExecutingConstruct(TRUE); oldName = CurrentMessageName; CurrentMessageName = mname; CurrentEvaluationDepth++; PushProcParameters(args,CountArguments(args), ValueToString(CurrentMessageName),"message", UnboundHandlerErr); if (EvaluationError) { CurrentEvaluationDepth--; CurrentMessageName = oldName; PeriodicCleanup(FALSE,TRUE); SetExecutingConstruct(oldce); return; } if (ProcParamArray->type == INSTANCE_ADDRESS) { ins = (INSTANCE_TYPE *) ProcParamArray->value; if (ins->garbage == 1) { StaleInstanceAddress("send",0); SetEvaluationError(TRUE); } else if (DefclassInScope(ins->cls,(struct defmodule *) GetCurrentModule()) == FALSE) NoInstanceError(ValueToString(ins->name),"send"); else { cls = ins->cls; ins->busy++; } } else if (ProcParamArray->type == INSTANCE_NAME) { ins = FindInstanceBySymbol((SYMBOL_HN *) ProcParamArray->value); if (ins == NULL) { PrintErrorID("MSGPASS",2,FALSE); PrintRouter(WERROR,"No such instance "); PrintRouter(WERROR,ValueToString((SYMBOL_HN *) ProcParamArray->value)); PrintRouter(WERROR," in function send.\n"); SetEvaluationError(TRUE); } else { ProcParamArray->value = (void *) ins; ProcParamArray->type = INSTANCE_ADDRESS; cls = ins->cls; ins->busy++; } } else if ((cls = PrimitiveClassMap[ProcParamArray->type]) == NULL) { SystemError("MSGPASS",1); ExitRouter(EXIT_FAILURE); } if (EvaluationError) { PopProcParameters(); CurrentEvaluationDepth--; CurrentMessageName = oldName; PeriodicCleanup(FALSE,TRUE); SetExecutingConstruct(oldce); return; } oldCore = TopOfCore; TopOfCore = FindApplicableHandlers(cls,mname); if (TopOfCore != NULL) { HANDLER_LINK *oldCurrent,*oldNext; oldCurrent = CurrentCore; oldNext = NextInCore; #if IMPERATIVE_MESSAGE_HANDLERS if (TopOfCore->hnd->type == MAROUND) { CurrentCore = TopOfCore; NextInCore = TopOfCore->nxt; #if DEBUGGING_FUNCTIONS if (WatchMessages) WatchMessage(WTRACE,BEGIN_TRACE); if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,BEGIN_TRACE); #endif if (CheckHandlerArgCount()) { #if PROFILING_FUNCTIONS StartProfile(&profileFrame, &CurrentCore->hnd->usrData, ProfileConstructs); #endif EvaluateProcActions(CurrentCore->hnd->cls->header.whichModule->theModule, CurrentCore->hnd->actions, CurrentCore->hnd->localVarCount, result,UnboundHandlerErr); #if PROFILING_FUNCTIONS EndProfile(&profileFrame); #endif } #if DEBUGGING_FUNCTIONS if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,END_TRACE); if (WatchMessages) WatchMessage(WTRACE,END_TRACE); #endif } else #endif /* IMPERATIVE_MESSAGE_HANDLERS */ { CurrentCore = NULL; NextInCore = TopOfCore; #if DEBUGGING_FUNCTIONS if (WatchMessages) WatchMessage(WTRACE,BEGIN_TRACE); #endif CallHandlers(result); #if DEBUGGING_FUNCTIONS if (WatchMessages) WatchMessage(WTRACE,END_TRACE); #endif } DestroyHandlerLinks(TopOfCore); CurrentCore = oldCurrent; NextInCore = oldNext; } TopOfCore = oldCore; ReturnFlag = FALSE; if (ins != NULL) ins->busy--; /* ================================== Restore the original calling frame ================================== */ PopProcParameters(); CurrentEvaluationDepth--; CurrentMessageName = oldName; PropagateReturnValue(result); PeriodicCleanup(FALSE,TRUE); SetExecutingConstruct(oldce); if (EvaluationError) { result->type = SYMBOL; result->value = FalseSymbol; } }
/******************************************************** NAME : CallNextHandler DESCRIPTION : This function allows around-handlers to execute the rest of the core frame. It also allows primary handlers to execute shadowed primaries. The original handler arguments are left intact. INPUTS : The caller's result-value buffer RETURNS : Nothing useful SIDE EFFECTS : The core frame is called and any appropriate changes are made when used in an around handler See CallHandlers() But when call-next-handler is called from a primary, the same shadowed primary is called over and over again for repeated calls to call-next-handler. NOTES : H/L Syntax: (call-next-handler) OR (override-next-handler <arg> ...) ********************************************************/ globle void CallNextHandler( DATA_OBJECT *result) { EXPRESSION args; int overridep; HANDLER_LINK *oldNext,*oldCurrent; #if PROFILING_FUNCTIONS struct profileFrameInfo profileFrame; #endif SetpType(result,SYMBOL); SetpValue(result,FalseSymbol); EvaluationError = FALSE; if (HaltExecution) return; if (NextHandlerAvailable() == FALSE) { PrintErrorID("MSGPASS",1,FALSE); PrintRouter(WERROR,"Shadowed message-handlers not applicable in current context.\n"); SetEvaluationError(TRUE); return; } if (CurrentExpression->value == (void *) FindFunction("override-next-handler")) { overridep = 1; args.type = (short) ProcParamArray[0].type; if (args.type != MULTIFIELD) args.value = (void *) ProcParamArray[0].value; else args.value = (void *) &ProcParamArray[0]; args.nextArg = GetFirstArgument(); args.argList = NULL; PushProcParameters(&args,CountArguments(&args), ValueToString(CurrentMessageName),"message", UnboundHandlerErr); if (EvaluationError) { ReturnFlag = FALSE; return; } } else overridep = 0; oldNext = NextInCore; oldCurrent = CurrentCore; if (CurrentCore->hnd->type == MAROUND) { if (NextInCore->hnd->type == MAROUND) { CurrentCore = NextInCore; NextInCore = NextInCore->nxt; #if DEBUGGING_FUNCTIONS if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,BEGIN_TRACE); #endif if (CheckHandlerArgCount()) { #if PROFILING_FUNCTIONS StartProfile(&profileFrame, &CurrentCore->hnd->usrData, ProfileConstructs); #endif EvaluateProcActions(CurrentCore->hnd->cls->header.whichModule->theModule, CurrentCore->hnd->actions, CurrentCore->hnd->localVarCount, result,UnboundHandlerErr); #if PROFILING_FUNCTIONS EndProfile(&profileFrame); #endif } #if DEBUGGING_FUNCTIONS if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,END_TRACE); #endif } else CallHandlers(result); } else { CurrentCore = NextInCore; NextInCore = NextInCore->nxt; #if DEBUGGING_FUNCTIONS if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,BEGIN_TRACE); #endif if (CheckHandlerArgCount()) { #if PROFILING_FUNCTIONS StartProfile(&profileFrame, &CurrentCore->hnd->usrData, ProfileConstructs); #endif EvaluateProcActions(CurrentCore->hnd->cls->header.whichModule->theModule, CurrentCore->hnd->actions, CurrentCore->hnd->localVarCount, result,UnboundHandlerErr); #if PROFILING_FUNCTIONS EndProfile(&profileFrame); #endif } #if DEBUGGING_FUNCTIONS if (CurrentCore->hnd->trace) WatchHandler(WTRACE,CurrentCore,END_TRACE); #endif } NextInCore = oldNext; CurrentCore = oldCurrent; if (overridep) PopProcParameters(); ReturnFlag = FALSE; }
bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnection *pConn, bool fThread) { // security: add connection reference if (!pConn) return false; pConn->AddRef(); // accept only PID_Conn and PID_Ping on non-accepted connections if(!pConn->isHalfAccepted()) if(rPacket.getStatus() != PID_Conn && rPacket.getStatus() != PID_Ping && rPacket.getStatus() != PID_ConnRe) return false; // unpack packet (yet another no-idea-why-it's-needed-cast) C4IDPacket Pkt; C4PacketBase &PktB = Pkt; try { PktB.unpack(rPacket); } catch (StdCompiler::Exception *pExc) { Application.InteractiveThread.ThreadLog("Network: error: Failed to unpack packet id %02x: %s", rPacket.getStatus(), pExc->Msg.getData()); delete pExc; #ifndef _DEBUG pConn->Close(); #endif return false; } // dump packet (network thread only) #if(C4NET2IO_DUMP_LEVEL > 0) if (Config.Network.PacketLogging && fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData) { // StdStrBuf PacketDump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdaptrPacket); StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s:%d (%lu bytes, counter %d)", C4TimeMilliseconds::Now().AsString().getData(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), static_cast<unsigned long>(rPacket.getSize()), pConn->getInPacketCounter()); StdStrBuf Dump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(Pkt, PacketHeader.getData())); // Put it directly. The standard functions behind StdBuf.Format seem to choke when you pass them too much data. Application.InteractiveThread.PushEvent(Ev_LogSilent, Dump.GrabPointer()); } #endif // search packet handling data bool fSendToMainThread = false, fHandled = false; for (const C4PktHandlingData *pHData = PktHandlingData; pHData->ID != PID_None; pHData++) if (pHData->ID == rPacket.getStatus()) { // correct thread? if (!pHData->ProcByThread == !fThread) { // connection accepted? if (pHData->AcceptedOnly || pConn->isAccepted() || pConn->isClosed()) { fHandled = true; #if(C4NET2IO_DUMP_LEVEL > 2) C4TimeMilliseconds tStart = C4TimeMilliseconds::Now(); #endif // call handler(s) CallHandlers(pHData->HandlerID, &Pkt, pConn, fThread); #if(C4NET2IO_DUMP_LEVEL > 2) uint32_t iBlockedTime = C4TimeMilliseconds::Now() - tStart; if (fThread && iBlockedTime > 100) { Application.InteractiveThread.ThreadLogS("HandlePacket: ... blocked for %u ms!", iBlockedTime); } #endif } } // transfer to main thread? else if (!pHData->ProcByThread && fThread) { fHandled = true; fSendToMainThread = true; } } // send to main thread? if (fSendToMainThread) { // create data NetEvPacketData *pEvData = new NetEvPacketData; pEvData->Packet.Take(rPacket.Duplicate()); pEvData->Conn = pConn; pConn->AddRef(); // trigger event if (!Application.InteractiveThread.PushEvent(Ev_Net_Packet, pEvData)) Application.InteractiveThread.ThreadLogS("...push event "); } // unhandled? if (!fHandled && !pConn->isClosed()) Application.InteractiveThread.ThreadLog("Network: Unhandled packet (status %02x)", rPacket.getStatus()); // remove connection reference pConn->DelRef(); return fHandled; }