Skip to content

Commit 2047189

Browse files
authored
Merge pull request livecode#6782 from montegoulding/log
[[ Log ]] log command and logMessage global property
2 parents 8d5bb4b + 318de49 commit 2047189

File tree

19 files changed

+403
-6
lines changed

19 files changed

+403
-6
lines changed

docs/dictionary/command/log.lcdoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Name: log
2+
3+
Type: command
4+
5+
Syntax: log [ <argumentList> ]
6+
7+
Summary:
8+
Invokes the <logMessage> if it is not empty.
9+
10+
Introduced: 9.5
11+
12+
OS: mac, windows, linux, ios, android, html5
13+
14+
Platforms: desktop, server, mobile
15+
16+
Example:
17+
on preOpenStack
18+
-- uBuildMode property set before building standalone
19+
if the uBuildMode of this stack is "release" then
20+
set the logMessage to empty
21+
end if
22+
23+
loadResources
24+
end preOpenStack
25+
26+
command loadResources
27+
log "loading resources"
28+
end loadResources
29+
30+
on log pInfo
31+
-- unhandled put will go to system logs
32+
put pInfo
33+
end log
34+
35+
Parameters:
36+
argumentList:
37+
A comma separated list of expressions containing the arguments to send.
38+
Arrays are expressions and are valid to send as arguments.
39+
40+
Description:
41+
The <log> command invokes the <logMessage> handler. When the <logMessage> is the
42+
default value of `log` then the <log> command behaves in the same way as any
43+
other scripted handler. If the <logMessage> is set to empty then the <log>
44+
command does not invoke any handler or evaluate parameters, therefore, allowing
45+
for many logs to be added to scripts for development and an easy low-cost method
46+
to turn the logging off for a release build. The <logMessage> may be set to any
47+
handler name, however, if the handler is not in the message path then use of the
48+
<log> command will throw a `can't find handler` error.
49+
50+
References: log (command), put (command), msgChanged (message)
51+
52+
Tags: debugging
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Name: logMessage
2+
3+
Type: property
4+
5+
Syntax: set the logMessage to <handlerName>
6+
7+
Summary:
8+
The name of the handler that is called by the <log> command.
9+
10+
Introduced: 9.5
11+
12+
OS: mac, windows, linux, ios, android, html5
13+
14+
Platforms: desktop, server, mobile
15+
16+
Example:
17+
on preOpenStack
18+
-- uBuildMode property set before building standalone
19+
if the uBuildMode of this stack is "release" then
20+
set the logMessage to empty
21+
end if
22+
23+
loadResources
24+
end preOpenStack
25+
26+
command loadResources
27+
log "loading resources"
28+
end loadResources
29+
30+
on log pInfo
31+
-- unhandled put will go to system logs
32+
put pInfo
33+
end log
34+
35+
Value:
36+
The <logMessage> is the name of the handler called by the <log> command. The
37+
default <logMessage> is `log`. If set to empty then the <log> command does not
38+
invoke any handler or evaluate parameters, therefore, allowing for many logs to
39+
be added to scripts for development and an easy low-cost method to turn the
40+
logging off for a release build. The <logMessage> may be set to any handler name,
41+
however, if the handler is not in the message path then use of the <log> command
42+
will throw a `can't find handler` error.
43+
44+
References: log (command), put (command), msgChanged (message)
45+
46+
Tags: debugging
47+

docs/notes/feature-log.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# New `log` command and `logMessage` property
2+
3+
A new command (`log`) and global property (`logMessage`) have been added to allow
4+
an easy and low-cost method to disable or redirect script logs.
5+
6+
The `log` command invokes the handler named by the `logMessage` as though the
7+
`logMessage` were directly written in the script. For backwards compatability
8+
the default value of the `logMessage` is `log` so any scripts that currently
9+
have a `log` handler will continue to work. To allow this `log` has been special
10+
cased as both a command name and a permitted handler name.
11+
12+
If the `logMessage` is set to empty then the `log` command will not invoke any
13+
handler or evaluate any of the parameters in the argument list.
14+
15+
In this example the `log` command will not be called with `pInfo` as
16+
`loading resources` when the `uBuildMode` of the stack is `release`:
17+
18+
on preOpenStack
19+
-- uBuildMode property set before building standalone
20+
if the uBuildMode of this stack is "release" then
21+
set the logMessage to empty
22+
end if
23+
24+
loadResources
25+
end preOpenStack
26+
27+
command loadResources
28+
log "loading resources"
29+
end loadResources
30+
31+
on log pInfo
32+
-- unhandled put will go to system logs
33+
put pInfo
34+
end log

engine/src/cmds.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,26 @@ class MCDispatchCmd: public MCStatement
10201020
virtual void exec_ctxt(MCExecContext &ctxt);
10211021
};
10221022

1023+
class MCLogCmd: public MCStatement
1024+
{
1025+
MCParameter *params;
1026+
struct
1027+
{
1028+
unsigned container_count : 16;
1029+
};
1030+
1031+
public:
1032+
MCLogCmd(void)
1033+
{
1034+
params = nullptr;
1035+
container_count = 0;
1036+
}
1037+
~MCLogCmd(void);
1038+
1039+
virtual Parse_stat parse(MCScriptPoint& sp);
1040+
virtual void exec_ctxt(MCExecContext &ctxt);
1041+
};
1042+
10231043
class MCFocus : public MCStatement
10241044
{
10251045
MCChunk *object;

engine/src/cmdse.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,101 @@ void MCDispatchCmd::exec_ctxt(MCExecContext &ctxt)
527527
MCKeywordsExecTeardownCommandOrFunction(params);
528528
}
529529

530+
MCLogCmd::~MCLogCmd(void)
531+
{
532+
while(params != NULL)
533+
{
534+
MCParameter *t_param;
535+
t_param = params;
536+
params = params -> getnext();
537+
delete t_param;
538+
}
539+
}
540+
541+
Parse_stat MCLogCmd::parse(MCScriptPoint& sp)
542+
{
543+
initpoint(sp);
544+
545+
if (getparams(sp, &params) != PS_NORMAL)
546+
{
547+
MCperror -> add(PE_STATEMENT_BADPARAMS, sp);
548+
return PS_ERROR;
549+
}
550+
551+
/* If there are any parameters then compute the number of containers needed
552+
* to execute the command. */
553+
if (params != nullptr)
554+
{
555+
container_count = params->count_containers();
556+
}
557+
558+
return PS_NORMAL;
559+
}
560+
561+
// This method follows along the same lines as MCComref::exec
562+
void MCLogCmd::exec_ctxt(MCExecContext &ctxt)
563+
{
564+
// no-op if logMessage is empty
565+
if (MCNameIsEmpty(MClogmessage))
566+
{
567+
return;
568+
}
569+
570+
/* Attempt to allocate the number of containers needed for the call. */
571+
MCAutoPointer<MCContainer[]> t_containers = new MCContainer[container_count];
572+
if (!t_containers)
573+
{
574+
ctxt.LegacyThrow(EE_NO_MEMORY);
575+
return;
576+
}
577+
578+
/* If the argument list is successfully evaluated, then do the dispatch. */
579+
if (MCKeywordsExecSetupCommandOrFunction(ctxt,
580+
params,
581+
*t_containers,
582+
line,
583+
pos,
584+
false))
585+
{
586+
if (!ctxt.HasError())
587+
{
588+
ctxt.SetLineAndPos(line, pos);
589+
MCHandler * t_handler = nullptr;
590+
MCKeywordsExecResolveCommandOrFunction(ctxt, MClogmessage, false, t_handler);
591+
MCKeywordsExecCommandOrFunction(ctxt, t_handler, params, MClogmessage, line, pos, false, false);
592+
}
593+
}
594+
595+
/* Clean up the evaluated argument list */
596+
MCKeywordsExecTeardownCommandOrFunction(params);
597+
598+
if (MCresultmode == kMCExecResultModeReturn)
599+
{
600+
// Do nothing!
601+
}
602+
else if (MCresultmode == kMCExecResultModeReturnValue)
603+
{
604+
// Set 'it' to the result and clear the result
605+
MCAutoValueRef t_value;
606+
if (!MCresult->eval(ctxt, &t_value))
607+
{
608+
ctxt.Throw();
609+
return;
610+
}
611+
612+
ctxt.SetItToValue(*t_value);
613+
ctxt.SetTheResultToEmpty();
614+
}
615+
else if (MCresultmode == kMCExecResultModeReturnError)
616+
{
617+
// Set 'it' to empty
618+
ctxt.SetItToEmpty();
619+
// Leave the result as is but make sure we reset the 'return mode' to default.
620+
MCresultmode = kMCExecResultModeReturn;
621+
}
622+
}
623+
624+
530625
Parse_stat MCMessage::parse(MCScriptPoint &sp)
531626
{
532627
initpoint(sp);

engine/src/debug.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ MCExecContext *MCexecutioncontexts[MAX_CONTEXTS];
6767
uint2 MCnexecutioncontexts = 0;
6868
uint2 MCdebugcontext = MAXUINT2;
6969
Boolean MCmessagemessages = False;
70+
MCNameRef MClogmessage;
7071

7172
////////////////////////////////////////////////////////////////////////////////
7273

engine/src/debug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ extern MCExecContext *MCexecutioncontexts[MAX_CONTEXTS];
9797
extern uint2 MCnexecutioncontexts;
9898
extern uint2 MCdebugcontext;
9999
extern Boolean MCmessagemessages;
100+
extern MCNameRef MClogmessage;
100101

101102
struct MCExecValue;
102103

engine/src/exec-debugging.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,25 @@ void MCDebuggingSetWatchedVariables(MCExecContext& ctxt, MCStringRef p_value)
369369

370370
////////////////////////////////////////////////////////////////////////////////
371371

372+
void MCDebuggingGetLogMessage(MCExecContext& ctxt, MCStringRef& r_value)
373+
{
374+
r_value = MCValueRetain(MCNameGetString(MClogmessage));
375+
}
376+
377+
void MCDebuggingSetLogMessage(MCExecContext& ctxt, MCStringRef p_value)
378+
{
379+
MCNewAutoNameRef t_logmessage;
380+
if (!MCNameCreate(p_value, &t_logmessage))
381+
{
382+
ctxt.Throw();
383+
return;
384+
}
385+
386+
MCValueAssign(MClogmessage, *t_logmessage);
387+
}
388+
389+
////////////////////////////////////////////////////////////////////////////////
390+
372391
void MCDebuggingExecAssert(MCExecContext& ctxt, int type, bool p_eval_success, bool p_result)
373392
{
374393
switch(type)

engine/src/exec.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3787,6 +3787,8 @@ void MCDebuggingGetExecutionContexts(MCExecContext& ctxt, MCStringRef& r_value);
37873787
void MCDebuggingGetWatchedVariables(MCExecContext& ctxt, MCStringRef& r_value);
37883788
void MCDebuggingSetWatchedVariables(MCExecContext& ctxt, MCStringRef p_value);
37893789
void MCDebuggingExecPutIntoMessage(MCExecContext& ctxt, MCStringRef value, int where);
3790+
void MCDebuggingGetLogMessage(MCExecContext& ctxt, MCStringRef& r_value);
3791+
void MCDebuggingSetLogMessage(MCExecContext& ctxt, MCStringRef p_value);
37903792

37913793
///////////
37923794

engine/src/globals.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,8 @@ void X_clear_globals(void)
886886
#endif
887887

888888
MCDateTimeInitialize();
889+
890+
MClogmessage = MCNAME("log");
889891
}
890892

891893
/* ---------------------------------------------------------------- */
@@ -1546,6 +1548,8 @@ int X_close(void)
15461548
if (MCcmd != nullptr)
15471549
MCValueRelease(MCcmd);
15481550

1551+
MCValueRelease(MClogmessage);
1552+
15491553
return MCretcode;
15501554
}
15511555

0 commit comments

Comments
 (0)