/* Copyright (C) 2003-2015 LiveCode Ltd.
This file is part of LiveCode.
LiveCode is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License v3 as published by the Free
Software Foundation.
LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with LiveCode. If not see . */
#include "prefix.h"
#include "globdefs.h"
#include "objdefs.h"
#include "parsedef.h"
#include "filedefs.h"
#include "globals.h"
//#include "execpt.h"
#include "handler.h"
#include "scriptpt.h"
#include "newobj.h"
#include "chunk.h"
#include "param.h"
#include "mcerror.h"
#include "property.h"
#include "object.h"
#include "button.h"
#include "field.h"
#include "image.h"
#include "card.h"
#include "eps.h"
#include "graphic.h"
#include "group.h"
#include "scrolbar.h"
#include "player.h"
#include "aclip.h"
#include "vclip.h"
#include "stack.h"
#include "dispatch.h"
#include "stacklst.h"
#include "sellst.h"
#include "undolst.h"
#include "util.h"
#include "date.h"
#include "printer.h"
#include "debug.h"
#include "cmds.h"
#include "mode.h"
#include "osspec.h"
#include "hndlrlst.h"
#include "securemode.h"
#include "syntax.h"
#include "stacksecurity.h"
#include "license.h"
#ifdef _SERVER
#include "srvscript.h"
#endif
#include "exec.h"
MCChoose::~MCChoose()
{
delete etool;
}
Parse_stat MCChoose::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
sp.skip_token(SP_FACTOR, TT_THE);
if (sp.next(type) != PS_NORMAL)
{
MCperror->add(PE_CHOOSE_NOTOKEN, sp);
return PS_ERROR;
}
if (sp.lookup(SP_TOOL, te) != PS_NORMAL)
{
sp.backup();
if (sp.parseexp(False, True, &etool) != PS_NORMAL)
{
MCperror->add(PE_CHOOSE_BADEXP, sp);
return PS_ERROR;
}
sp.skip_token(SP_TOOL, TT_END);
return PS_NORMAL;
}
else
{
littool = (Tool)te->which;
while (sp.skip_token(SP_TOOL, TT_TOOL) == PS_NORMAL)
;
sp.skip_token(SP_TOOL, TT_END);
}
return PS_NORMAL;
}
void MCChoose::exec_ctxt(MCExecContext &ctxt)
{
#ifdef /* MCChoose */ LEGACY_EXEC
if (etool != NULL)
if (etool->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_CHOOSE_BADEXP, line, pos);
return ES_ERROR;
}
return MCU_choose_tool(ep, littool, line, pos);
#endif /* MCChoose */
MCAutoStringRef t_string;
if (!ctxt . EvalOptionalExprAsStringRef(etool, kMCEmptyString, EE_CHOOSE_BADEXP, &t_string))
return;
MCInterfaceExecChooseTool(ctxt, *t_string, littool);
}
void MCChoose::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (etool != nil)
etool -> compile(ctxt);
else
MCSyntaxFactoryEvalConstantNil(ctxt);
MCSyntaxFactoryEvalConstantInt(ctxt, littool);
MCSyntaxFactoryExecMethodWithArgs(ctxt, kMCInterfaceExecChooseToolMethodInfo, 1);
MCSyntaxFactoryEndStatement(ctxt);
}
MCConvert::~MCConvert()
{
delete container;
delete source;
}
Parse_stat MCConvert::parse(MCScriptPoint &sp)
{
initpoint(sp);
MCerrorlock++;
container = new MCChunk(True);
MCScriptPoint tsp(sp);
if (container->parse(sp, False) != PS_NORMAL)
{
sp = tsp;
MCerrorlock--;
delete container;
container = NULL;
if (sp.parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add
(PE_CONVERT_NOCONTAINER, sp);
return PS_ERROR;
}
}
else
MCerrorlock--;
if (sp.skip_token(SP_FACTOR, TT_FROM) == PS_NORMAL)
{
if (parsedtformat(sp, fform, fsform) != PS_NORMAL)
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_TO) != PS_NORMAL)
{
MCperror->add
(PE_CONVERT_NOTO, sp);
return PS_ERROR;
}
if (parsedtformat(sp, pform, sform) != PS_NORMAL)
return PS_ERROR;
return PS_NORMAL;
}
Parse_stat MCConvert::parsedtformat(MCScriptPoint &sp, Convert_form &firstform,
Convert_form &secondform)
{
const LT *te;
Symbol_type type;
Boolean needformat = True;
Convert_form localeform = CF_UNDEFINED;
while (True)
{
if (sp.next(type) != PS_NORMAL)
{
if (needformat)
{
MCperror->add
(PE_CONVERT_NOFORMAT, sp);
return PS_ERROR;
}
else
return PS_NORMAL;
}
if (sp.lookup(SP_CONVERT, te) != PS_NORMAL)
{
if (needformat)
{
MCperror->add
(PE_CONVERT_NOTFORMAT, sp);
return PS_ERROR;
}
else
{
sp.backup();
break;
}
}
switch (te->which)
{
case CF_ABBREVIATED:
case CF_SHORT:
case CF_LONG:
case CF_INTERNET:
if (firstform == CF_UNDEFINED)
firstform = (Convert_form)te->which;
else
secondform = (Convert_form)te->which;
break;
case CF_SYSTEM:
case CF_ENGLISH:
localeform = (Convert_form)te->which;
break;
case CF_DATE:
case CF_TIME:
if (firstform == CF_UNDEFINED)
firstform = (Convert_form)(te->which + 1 + localeform);
else
if (firstform > CF_INTERNET)
{
if (secondform == CF_UNDEFINED)
secondform = (Convert_form)(te->which + 1 + localeform);
else
{
uint2 dummy = secondform;
dummy += te->which + localeform;
secondform = (Convert_form)dummy;
}
}
else
{
uint2 dummy = firstform;
dummy += te->which + localeform;
firstform = (Convert_form)dummy;
}
needformat = False;
break;
default:
firstform = (Convert_form)te->which;
return PS_NORMAL;
}
if (sp.skip_token(SP_FACTOR, TT_BINOP, O_AND) == PS_NORMAL)
{
if (needformat)
{
MCperror->add
(PE_CONVERT_BADAND, sp);
return PS_ERROR;
}
else
needformat = True;
}
else
if (!needformat)
break;
}
return PS_NORMAL;
}
void MCConvert::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCConvert */ LEGACY_EXEC
MCresult->clear(False);
if (container != NULL)
{
if (container->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_CONVERT_CANTGET, line, pos);
return ES_ERROR;
}
}
else
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_CONVERT_CANTGET, line, pos);
return ES_ERROR;
}
if (!MCD_convert(ep, fform, fsform, pform, sform))
{
MCresult->sets("invalid date");
return ES_NORMAL;
}
Exec_stat stat;
if (container == NULL)
stat = ep . getit() -> set(ep);
else
stat = container->set(ep, PT_INTO);
if (stat != ES_NORMAL)
{
MCeerror->add
(EE_CONVERT_CANTSET, line, pos, ep.getsvalue());
return ES_ERROR;
}
return ES_NORMAL;
#endif /* MCConvert */
MCAutoStringRef t_input;
MCAutoStringRef t_output;
if (container != NULL)
{
if (!ctxt . EvalExprAsStringRef(container, EE_CONVERT_CANTGET, &t_input))
return;
}
else
{
if (!ctxt . EvalExprAsStringRef(source, EE_CONVERT_CANTGET, &t_input))
return;
}
if (container == NULL)
MCDateTimeExecConvertIntoIt(ctxt, *t_input, fform, fsform, pform, sform);
else
{
MCDateTimeExecConvert(ctxt, *t_input, fform, fsform, pform, sform, &t_output);
container -> set(ctxt, PT_INTO, *t_output);
if (ctxt . HasError())
ctxt . LegacyThrow(EE_CONVERT_CANTSET, *t_output);
}
}
void MCConvert::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (container == nil)
source -> compile(ctxt);
else
container -> compile_inout(ctxt);
MCSyntaxFactoryEvalConstantInt(ctxt, fform);
MCSyntaxFactoryEvalConstantInt(ctxt, fsform);
MCSyntaxFactoryEvalConstantInt(ctxt, pform);
MCSyntaxFactoryEvalConstantInt(ctxt, sform);
if (container == nil)
MCSyntaxFactoryExecMethod(ctxt, kMCDateTimeExecConvertIntoItMethodInfo);
else
MCSyntaxFactoryExecMethodWithArgs(ctxt, kMCDateTimeExecConvertMethodInfo, 0, 1, 2, 3, 4, 0);
MCSyntaxFactoryEndStatement(ctxt);
}
MCDo::~MCDo()
{
delete source;
delete alternatelang;
delete widget;
}
Parse_stat MCDo::parse(MCScriptPoint &sp)
{
initpoint(sp);
if (sp.parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add(PE_DO_BADEXP, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_IN, PT_IN) == PS_NORMAL)
{
if (sp.skip_token(SP_SUGAR, TT_UNDEFINED, SG_BROWSER) == PS_NORMAL)
browser = True;
else if (sp.skip_token(SP_SUGAR, TT_UNDEFINED, SG_CALLER) == PS_NORMAL)
caller = true;
else
{
widget = new MCChunk(False);
if (widget->parse(sp, False) != PS_NORMAL)
{
MCperror->add(PE_DO_BADENV, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
if (sp.skip_token(SP_FACTOR, TT_PREP, PT_AS) == PS_NORMAL)
{
if (sp.parseexp(False, True, &alternatelang) != PS_NORMAL)
{
MCperror->add(PE_DO_BADLANG, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
void MCDo::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCDo */ LEGACY_EXEC
MCExecPoint *epptr;
if (browser)
{
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_DO_BADEXP, line, pos);
return ES_ERROR;
}
return MCModeExecuteScriptInBrowser(ep . getsvalue());
}
if (alternatelang != NULL)
{
if (alternatelang->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_DO_BADLANG, line, pos);
return ES_ERROR;
}
char *langname = ep.getsvalue().clone();
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_DO_BADEXP, line, pos);
return ES_ERROR;
}
if (!MCSecureModeCheckDoAlternate(line, pos))
return ES_ERROR;
MCString s = ep.getsvalue();
MCS_doalternatelanguage(s, langname);
delete langname;
return ES_NORMAL;
}
Boolean added = False;
if (MCnexecutioncontexts < MAX_CONTEXTS)
{
ep.setline(line);
MCexecutioncontexts[MCnexecutioncontexts++] = &ep;
added = True;
}
if (debug)
{
if (MCdebugcontext >= MCnexecutioncontexts)
MCdebugcontext = MCnexecutioncontexts - 1;
epptr = MCexecutioncontexts[MCdebugcontext];
}
else
{
if (caller)
{
if (MCnexecutioncontexts < 2)
{
if (added)
MCnexecutioncontexts--;
MCeerror -> add(EE_DO_NOCALLER, line, pos);
return ES_ERROR;
}
epptr = MCexecutioncontexts[MCnexecutioncontexts - 2];
}
else
epptr = &ep;
}
if (source->eval(*epptr) != ES_NORMAL)
{
if (added)
MCnexecutioncontexts--;
MCeerror->add(EE_DO_BADEXP, line, pos);
return ES_ERROR;
}
// MW-2013-11-15: [[ Bug 11277 ]] If no handler, then evaluate in context of the
// server script object.
Exec_stat stat;
stat = ep.doscript(*epptr, line, pos);
if (added)
MCnexecutioncontexts--;
return stat;
#endif /* MCDo */
MCAutoStringRef t_script;
if (!ctxt . EvalExprAsStringRef(source, EE_DO_BADEXP, &t_script))
return;
if (widget)
{
MCObject *t_object;
uint32_t t_parid;
if (!widget->getobj(ctxt, t_object, t_parid, True) || t_object->gettype() != CT_WIDGET)
{
ctxt.LegacyThrow(EE_DO_BADWIDGETEXP);
return;
}
MCInterfaceExecDoInWidget(ctxt, *t_script, (MCWidget*)t_object);
return;
}
if (browser)
{
MCLegacyExecDoInBrowser(ctxt, *t_script);
return;
}
if (alternatelang != NULL)
{
MCAutoStringRef t_language;
if (!ctxt . EvalExprAsStringRef(alternatelang, EE_DO_BADLANG, &t_language))
return;
MCScriptingExecDoAsAlternateLanguage(ctxt, *t_script, *t_language);
return;
}
if (debug)
{
MCDebuggingExecDebugDo(ctxt, *t_script, line, pos);
return;
}
// AL-2014-11-17: [[ Bug 14044 ]] Do in caller not implemented
if (caller)
{
MCEngineExecDoInCaller(ctxt, *t_script, line, pos);
return;
}
MCEngineExecDo(ctxt, *t_script, line, pos);
}
void MCDo::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
source -> compile(ctxt);
if (widget != nil)
{
widget->compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecDoInWidgetMethodInfo);
}
else if (browser)
MCSyntaxFactoryExecMethod(ctxt, kMCLegacyExecDoInBrowserMethodInfo);
else if (alternatelang != nil)
{
alternatelang -> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCScriptingExecDoAsAlternateLanguageMethodInfo);
}
else
{
MCSyntaxFactoryEvalConstantInt(ctxt, line);
MCSyntaxFactoryEvalConstantInt(ctxt, pos);
if (debug)
MCSyntaxFactoryExecMethod(ctxt, kMCDebuggingExecDebugDoMethodInfo);
else
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecDoMethodInfo);
}
MCSyntaxFactoryEndStatement(ctxt);
}
typedef struct
{
const char *token;
const char *command;
}
DT;
static DT domenu_table[] = {
{"new stack...", "create stack\n\
set the mainStack of the topStack to \"Home\"\n\
modal \"Stack Properties\""},
{"open stack...", "answer file \"Choose a stack to open...\"\n\
if it is not empty then\n\
set the cursor to watch\n\
topLevel it\n\
end if"},
{"close stack", "close this stack"},
{"compact stack", "compact stack"},
{"print card", "print this card"},
{"print stack...", "print this stack"},
{"quit hypercard", "quit"},
{"quit", "quit"},
{"undo", "undo"},
{"cut", "cut"},
{"copy", "copy"},
{"paste", "paste"},
{"new card", "create card"},
{"delete card", "delete this card"},
{"cut card", "cut this card"},
{"copy card", "copy this card"},
{"background", "edit background"},
{"back", "go back"},
{"home", "go home"},
{"help", "help"},
{"recent", "go recent"},
{"first", "go to first card"},
{"prev", "go to prev card"},
{"next", "go to next card"},
{"last", "go to last card"},
{"find...", "modeless \"Find\""},
{"message", "modeless \"Message Box\""},
{"bring closer", "set the layer of the selobj to the layer of the selobj+1"},
{"send farther", "set the layer of the selobj to the layer of the selobj-1"},
{"new button", "create button"},
{"new field", "create field"},
{"new background", "create background"},
};
/* doMenu items
About Hypercard..., New Stack..., Open Stack..., Close Stack, Save A
Copy..., Compact Stack, Protect Stack..., Delete Stack..., Page
Setup..., Print Field..., Print Card, Print Stack..., Print Report...,
Quit Hypercard, Undo, Cut, Copy, Paste, New Card, Delete Card, Cut
Card, Copy Card, Text Style..., Background, Icon..., Back, Home, Help,
recent, First, Prev, Next, Last, Find..., Message, Scroll, Next
Window, Button Info..., Field Info..., Card Info..., Bkgnd Info...,
Stack Info..., Bring Closer, Send Farther, New Button, New Field, New
Background, Plain, Bold, Italic, Underline, Outline, Shadow, Condense,
Extend, Group, Other..., Select, Select All, Fill, Invert, Pickup,
Darken, Lighten, Trace Edges, Rotate Left, Rotate Right, Flip
Vertical, Flip Horizontal, Opaque, Transparent, Keep, Revert, grid,
Fatbits, Power Keys, Line Size..., brush Shape..., Edit pattern...,
Polygon Sides..., Draw filled, Draw centered, Draw multiple, Rotate,
Slant, distort, Perspective, Import Paint..., Export Paint..., New
Icon, Close Icon Editor, Duplicate Icon, Cut Icon, Copy Icon, Erase,
Frame, Gray, Mirror Horizontal, Mirror Vertical, Rotate 90, Shadow,
Delete Report, Cut Report, Copy Report, Report Items..., Report
Name..., New Report, New Item, Item Info..., Close Script, Save
Script, Revert To Saved, Print Script, Find Again, Find Selection,
Scroll To Selection, Replace..., Replace Again, Comment, Uncomment,
Set Checkpoint, Step, Step Into, Trace, Go, Trace Delay..., Abort,
Variable Watcher, Message Watcher
*/
const char *MCDoMenu::lookup(MCStringRef s)
{
uint2 size = ELEMENTS(domenu_table);
while(size--)
if (MCStringIsEqualToCString(s, domenu_table[size].token, kMCCompareCaseless))
return domenu_table[size].command;
return NULL;
}
MCDoMenu::~MCDoMenu()
{
delete source;
}
Parse_stat MCDoMenu::parse(MCScriptPoint &sp)
{
initpoint(sp);
if (sp.parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add
(PE_DOMENU_BADEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
void MCDoMenu::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCDoMenu */ LEGACY_EXEC
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_DOMENU_BADEXP, line, pos);
return ES_ERROR;
}
const char *dstring = lookup(ep.getsvalue());
if (dstring == NULL)
{
char *tptr = ep.getsvalue().clone();
ep.setstringf("doMenu \"%s\" not implemented", tptr);
delete tptr;
MCresult->sets(ep.getsvalue());
}
else
{
ep.getobj()->domess(dstring);
}
return ES_NORMAL;
#endif /* MCDoMenu */
MCAutoStringRef t_option;
if (!ctxt . EvalExprAsStringRef(source, EE_DOMENU_BADEXP, &t_option))
return;
MCLegacyExecDoMenu(ctxt, *t_option);
}
void MCDoMenu::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
source-> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCLegacyExecDoMenuMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCEdit::~MCEdit()
{
delete target;
delete m_at;
}
Parse_stat MCEdit::parse(MCScriptPoint &sp)
{
initpoint(sp);
sp.skip_token(SP_FACTOR, TT_THE);
if (sp.skip_token(SP_FACTOR, TT_PROPERTY) != PS_NORMAL)
{
MCperror->add(PE_EDIT_NOSCRIPT, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_OF) != PS_NORMAL)
{
MCperror->add(PE_EDIT_NOOF, sp);
return PS_ERROR;
}
target = new MCChunk(False);
if (target->parse(sp, False) != PS_NORMAL)
{
MCperror->add(PE_EDIT_NOTARGET, sp);
return PS_ERROR;
}
// MERG 2013-9-13: [[ EditScriptChunk ]] Added line and column
if (sp.skip_token(SP_FACTOR, TT_PREP, PT_AT) == PS_NORMAL)
{
if (sp.parseexp(False, True, &m_at) != PS_NORMAL)
{
MCperror->add(PE_EDIT_NOAT, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
void MCEdit::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCEdit */ LEGACY_EXEC
MCObject *optr;
uint4 parid;
if (target->getobj(ep, optr, parid, True) != ES_NORMAL)
{
MCeerror->add(EE_EDIT_BADTARGET, line, pos);
return ES_ERROR;
}
// MERG 2013-9-13: [[ EditScriptChunk ]] Added at expression that's passed through as a second parameter to editScript
MCString t_at;
t_at = NULL;
if (m_at != NULL)
{
if (m_at->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_EDIT_BADAT, line, pos);
return ES_ERROR;
}
t_at = ep.getsvalue();
}
// MW-2010-10-13: [[ Bug 7476 ]] Make sure we temporarily turn off lock messages
// before invoking the method - since it requires message sending to work!
Boolean t_old_lock;
t_old_lock = MClockmessages;
MClockmessages = False;
optr->editscript(t_at);
MClockmessages = t_old_lock;
return ES_NORMAL;
#endif /* MCEdit */
MCObject *optr;
uint4 parid;
if (!target->getobj(ctxt, optr, parid, True))
{
ctxt . LegacyThrow(EE_EDIT_BADTARGET);
return;
}
// MERG 2013-9-13: [[ EditScriptChunk ]] Added at expression that's passed through as a second parameter to editScript
MCAutoStringRef t_at;
if (!ctxt . EvalOptionalExprAsNullableStringRef(m_at, EE_EDIT_BADAT, &t_at))
return;
MCIdeExecEditScriptOfObject(ctxt, optr, *t_at);
}
void MCEdit::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
target -> compile_object_ptr(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCIdeExecEditScriptOfObjectMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCFind::~MCFind()
{
delete tofind;
delete field;
}
Parse_stat MCFind::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_FIND_NOSTRING, sp);
return PS_ERROR;
}
if (sp.lookup(SP_FIND, te) == PS_NORMAL)
mode = (Find_mode)te->which;
else
sp.backup();
if (sp.parseexp(False, True, &tofind) != PS_NORMAL)
{
MCperror->add
(PE_FIND_BADSTRING, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_IN) == PS_NORMAL)
{
field = new MCChunk(False);
if (field->parse(sp, False) != PS_NORMAL)
{
MCperror->add
(PE_FIND_BADFIELD, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
void MCFind::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCFind */ LEGACY_EXEC
if (tofind->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_FIND_BADSTRING, line, pos);
return ES_ERROR;
}
if (ep.getsvalue().getlength() == 0)
{
if (MCfoundfield != NULL)
MCfoundfield->clearfound();
MCresult->sets(MCnotfoundstring);
return ES_NORMAL;
}
MCdefaultstackptr->find(ep, mode, ep.getsvalue(), field);
return ES_NORMAL;
#endif /* MCFind */
MCAutoStringRef t_needle;
if (!ctxt . EvalExprAsStringRef(tofind, EE_FIND_BADSTRING, &t_needle))
return;
MCInterfaceExecFind(ctxt, mode, *t_needle, field);
// SN-2014-03-21: [[ Bug 11949 ]] 'find' shouldn't throw an error on a failure
// but MCInterfaceExecFind would cause the context to be set on error if finding fails
ctxt . IgnoreLastError();
}
void MCFind::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
MCSyntaxFactoryEvalConstantInt(ctxt, mode);
tofind -> compile(ctxt);
field -> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecFindMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCGet::~MCGet()
{
delete value;
}
Parse_stat MCGet::parse(MCScriptPoint &sp)
{
initpoint(sp);
if (sp.parseexp(False, True, &value) != PS_NORMAL)
{
MCperror->add
(PE_GET_BADEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
void MCGet::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCGet */ LEGACY_EXEC
if (value->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_GET_BADEXP, line, pos);
return ES_ERROR;
}
if (ep.getit()->set(ep) != ES_NORMAL)
{
MCeerror->add(EE_GET_CANTSET, line, pos, ep.getsvalue());
return ES_ERROR;
}
return ES_NORMAL;
#endif /* MCGet */
MCExecValue t_value;
if (!ctxt . EvaluateExpression(value, EE_GET_BADEXP, t_value))
return;
MCEngineExecGet(ctxt, t_value);
}
void MCGet::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
value -> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecGetMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCMarking::~MCMarking()
{
delete where;
delete tofind;
delete field;
delete card;
}
Parse_stat MCMarking::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOCARDS, sp);
return PS_ERROR;
}
if (sp.lookup(SP_MARK, te) != PS_NORMAL)
{
sp.backup();
card = new MCChunk(False);
if (card->parse(sp, False) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOTCARDS, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
if (te->which == MC_ALL)
{
if (sp.skip_token(SP_MARK, TT_UNDEFINED, MC_CARDS) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOCARDS, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
if (te->which != MC_CARDS)
{
MCperror->add
(PE_MARK_NOCARDS, sp);
return PS_ERROR;
}
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOBYORWHERE, sp);
return PS_ERROR;
}
if (sp.lookup(SP_MARK,te) != PS_NORMAL
|| (te->which != MC_BY && te->which != MC_WHERE))
{
MCperror->add
(PE_MARK_NOTBYORWHERE, sp);
return PS_ERROR;
}
if (te->which == MC_WHERE)
{
if (sp.parseexp(False, True, &where) != PS_NORMAL)
{
MCperror->add
(PE_MARK_BADWHEREEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
if (sp.skip_token(SP_MARK, TT_UNDEFINED, MC_FINDING) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOFINDING, sp);
return PS_ERROR;
}
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_MARK_NOSTRING, sp);
return PS_ERROR;
}
if (sp.lookup(SP_FIND, te) == PS_NORMAL)
mode = (Find_mode)te->which;
else
sp.backup();
if (sp.parseexp(False, True, &tofind) != PS_NORMAL)
{
MCperror->add
(PE_MARK_BADSTRING, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_IN) == PS_NORMAL)
{
field = new MCChunk(False);
if (field->parse(sp, False) != PS_NORMAL)
{
MCperror->add
(PE_MARK_BADFIELD, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
void MCMarking::exec_ctxt(MCExecContext &ctxt)
{
#ifdef /* MCMarking */ LEGACY_EXEC
if (card != NULL)
{
MCObject *optr;
uint4 parid;
if (card->getobj(ep, optr, parid, True) != ES_NORMAL
|| optr->gettype() != CT_CARD)
{
MCeerror->add
(EE_MARK_BADCARD, line, pos);
return ES_ERROR;
}
ep.setboolean(mark);
return optr->setprop(0, P_MARKED, ep, False);
}
if (tofind == NULL)
MCdefaultstackptr->mark(ep, where, mark);
else
{
if (tofind->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_MARK_BADSTRING, line, pos);
return ES_ERROR;
}
MCdefaultstackptr->markfind(ep, mode, ep.getsvalue(), field, mark);
}
return ES_NORMAL;
#endif /* MCMarking */
if (card != NULL)
{
MCObjectPtr t_object;
if (!card->getobj(ctxt, t_object, True)
|| t_object . object -> gettype() != CT_CARD)
{
ctxt . LegacyThrow(EE_MARK_BADCARD);
return;
}
if (mark)
MCInterfaceExecMarkCard(ctxt, t_object);
else
MCInterfaceExecUnmarkCard(ctxt, t_object);
}
// SN-2014-03-21 [[ Bug 11950 ]]: 'mark' shouldn't throw an error when failing to mark when card is nil
// Any error set is discarded in the end of this block - unless is was triggered by a bad string.
else
{
if (tofind == nil)
{
if (mark)
{
if (where != nil)
MCInterfaceExecMarkCardsConditional(ctxt, where);
else
MCInterfaceExecMarkAllCards(ctxt);
}
else
{
if (where != nil)
MCInterfaceExecUnmarkCardsConditional(ctxt, where);
else
MCInterfaceExecUnmarkAllCards(ctxt);
}
}
else
{
MCAutoStringRef t_needle;
if (!ctxt . EvalExprAsStringRef(tofind, EE_MARK_BADSTRING, &t_needle))
return;
if (mark)
MCInterfaceExecMarkFind(ctxt, mode, *t_needle, field);
else
MCInterfaceExecUnmarkFind(ctxt, mode, *t_needle, field);
}
ctxt . IgnoreLastError();
}
}
MCPut::~MCPut()
{
delete source;
delete dest;
// cookie
delete name;
delete domain;
delete path;
delete expires;
}
// put [ unicode | binary ]
// put [ unicode ] ( content | markup )
// put [ new ] header
// put [ secure ] [ httponly ] cookie [ for ] [ on ] to [ until ]
// put ( into | after | before ) message [ box ]
// put ( into | after | before )
//
Parse_stat MCPut::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
// IM-2011-08-22: [[ SERVER ]] Add support for new put variant.
// Parse: put [ secure ] [ httponly ] cookie [ for path ] [ on domain ] with [ until expires ]
if (sp . skip_token(SP_SERVER, TT_SERVER, SK_SECURE) == PS_NORMAL)
is_secure = true;
if (sp . skip_token(SP_SERVER, TT_SERVER, SK_HTTPONLY) == PS_NORMAL)
is_httponly = true;
if (sp . skip_token(SP_SERVER, TT_PREP, PT_COOKIE) == PS_NORMAL)
{
prep = PT_COOKIE;
if (sp . parseexp(True, False, &name) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
if (sp . skip_token(SP_REPEAT, TT_UNDEFINED, RF_FOR) == PS_NORMAL)
{
if (sp . parseexp(True, False, &path) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
}
if (sp . skip_token(SP_FACTOR, TT_OF, PT_ON) == PS_NORMAL)
{
if (sp . parseexp(True, False, &domain) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
}
sp . skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH);
if (sp . parseexp(True, False, &source) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
if (sp . skip_token(SP_REPEAT, TT_UNDEFINED, RF_UNTIL) == PS_NORMAL)
{
if (sp . parseexp(True, False, &expires) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
}
return PS_NORMAL;
}
if (is_secure || is_httponly)
{
MCperror->add(PE_PUT_BADPREP, sp);
return PS_ERROR;
}
// MW-2011-06-22: [[ SERVER ]] Add support for new put variant.
// Parse: put new header
if (sp.skip_token(SP_SERVER, TT_SERVER, SK_NEW) == PS_NORMAL)
{
if (sp.skip_token(SP_SERVER, TT_PREP, PT_HEADER) == PS_NORMAL)
{
prep = PT_NEW_HEADER;
if (sp . parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
else
sp.backup();
}
// MW-2012-02-23: [[ UnicodePut ]] Store whether 'unicode' was present
// in the ast.
if (sp . skip_token(SP_SERVER, TT_SERVER, SK_UNICODE) == PS_NORMAL)
is_unicode = true;
// MW-2011-06-22: [[ SERVER ]] Add support for new put variant.
// Parse: put [ unicode ] ( header | content | markup )
if (sp.next(type) == PS_NORMAL)
{
if (type == ST_ID && sp.lookup(SP_SERVER, te) == PS_NORMAL && te -> type == TT_PREP)
{
prep = (Preposition_type)te -> which;
if (is_unicode && (prep == PT_HEADER || prep == PT_BINARY))
{
MCperror->add(PE_PUT_BADPREP, sp);
return PS_ERROR;
}
if (sp . parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
else
sp.backup();
}
if (sp.parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADEXP, sp);
return PS_ERROR;
}
if (sp.next(type) != PS_NORMAL)
return PS_NORMAL;
if (sp.lookup(SP_FACTOR, te) != PS_NORMAL || te->type != TT_PREP)
{
sp.backup();
return PS_NORMAL;
}
prep = (Preposition_type)te->which;
if (prep != PT_BEFORE && prep != PT_INTO && prep != PT_AFTER)
{
MCperror->add(PE_PUT_BADPREP, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_SHOW, TT_UNDEFINED, SO_MESSAGE) == PS_NORMAL)
{
sp.skip_token(SP_SHOW, TT_UNDEFINED, SO_MESSAGE); // "box"
return PS_NORMAL;
}
dest = new MCChunk(True);
if (dest->parse(sp, False) != PS_NORMAL)
{
MCperror->add(PE_PUT_BADCHUNK, sp);
return PS_ERROR;
}
MCVarref *t_src_ref, *t_dst_ref;
t_src_ref = source -> getrootvarref();
t_dst_ref = dest -> getrootvarref();
overlap = t_src_ref != NULL && t_dst_ref != NULL && t_src_ref -> rootmatches(t_dst_ref);
return PS_NORMAL;
}
void MCPut::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCPut */ LEGACY_EXEC
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_PUT_BADEXP, line, pos);
return ES_ERROR;
}
if (dest != NULL)
{
if (overlap)
ep . grab();
Exec_stat t_stat;
if (!is_unicode)
t_stat = dest -> set(ep, prep);
else
t_stat = dest -> setunicode(ep, prep);
if (t_stat != ES_NORMAL)
{
MCeerror->add(EE_PUT_CANTSET, line, pos);
return ES_ERROR;
}
return ES_NORMAL;
}
else
{
// MW-2011-06-22: [[ SERVER ]] Handle the non-dest forms of put.
MCSPutKind t_kind;
switch(prep)
{
case PT_UNDEFINED:
t_kind = is_unicode ? kMCSPutUnicodeOutput : kMCSPutOutput;
break;
case PT_INTO:
t_kind = kMCSPutIntoMessage;
break;
case PT_AFTER:
t_kind = kMCSPutAfterMessage;
break;
case PT_BEFORE:
t_kind = kMCSPutBeforeMessage;
break;
case PT_HEADER:
t_kind = kMCSPutHeader;
break;
case PT_NEW_HEADER:
t_kind = kMCSPutNewHeader;
break;
case PT_CONTENT:
t_kind = is_unicode ? kMCSPutUnicodeContent : kMCSPutContent;
break;
case PT_MARKUP:
t_kind = is_unicode ? kMCSPutUnicodeMarkup : kMCSPutMarkup;
break;
case PT_BINARY:
t_kind = kMCSPutBinaryOutput;
break;
case PT_COOKIE:
return exec_cookie(ep);
default:
t_kind = kMCSPutNone;
break;
}
if (!MCS_put(ep, t_kind, ep . getsvalue()))
{
MCeerror->add(EE_PUT_CANTSETINTO, line, pos);
return ES_ERROR;
}
return ES_NORMAL;
}
#endif /* MCPut */
MCExecValue t_value;
if (!ctxt . EvaluateExpression(source, EE_PUT_BADEXP, t_value))
return;
if (dest != nil)
{
// MCAutoValueRef t_valueref;
// MCExecTypeConvertAndReleaseAlways(ctxt, t_value . type, &t_value, kMCExecValueTypeValueRef, &(&t_valueref));
// dest -> set(ctxt, prep, *t_valueref, is_unicode);
dest -> set(ctxt, prep, t_value, is_unicode);
}
else
{
if (ctxt . HasError())
return;
MCAutoValueRef t_val;
if (is_unicode && (prep == PT_UNDEFINED || prep == PT_CONTENT || prep == PT_MARKUP))
{
MCExecTypeConvertAndReleaseAlways(ctxt, t_value . type, &t_value, kMCExecValueTypeDataRef, &(&t_val));
if (ctxt . HasError())
{
ctxt . LegacyThrow(EE_CHUNK_CANTSETDEST);
return;
}
}
else
{
MCExecTypeConvertAndReleaseAlways(ctxt, t_value . type, &t_value, kMCExecValueTypeStringRef, &(&t_val));
if (ctxt . HasError())
{
ctxt . LegacyThrow(EE_CHUNK_CANTSETDEST);
return;
}
}
// Defined for convenience
MCStringRef t_string = (MCStringRef)*t_val;
MCDataRef t_data = (MCDataRef)*t_val;
if (prep == PT_COOKIE)
{
MCAutoStringRef t_name;
if (!ctxt . EvalOptionalExprAsStringRef(name, kMCEmptyString, EE_PUT_CANTSETINTO, &t_name))
return;
uinteger_t t_expires;
if (!ctxt . EvalOptionalExprAsUInt(expires, 0, EE_PUT_CANTSETINTO, t_expires))
return;
MCAutoStringRef t_path;
if (!ctxt . EvalOptionalExprAsStringRef(path, kMCEmptyString, EE_PUT_CANTSETINTO, &t_path))
return;
MCAutoStringRef t_domain;
if (!ctxt . EvalOptionalExprAsStringRef(domain, kMCEmptyString, EE_PUT_CANTSETINTO, &t_domain))
return;
MCServerExecPutCookie(ctxt, *t_name, t_string, t_expires, *t_path, *t_domain, is_secure, is_httponly);
}
else if (prep == PT_UNDEFINED)
{
if (is_unicode)
MCEngineExecPutOutputUnicode(ctxt, t_data);
else
MCEngineExecPutOutput(ctxt, t_string);
}
else if (prep == PT_INTO || prep == PT_AFTER || prep == PT_BEFORE)
MCIdeExecPutIntoMessage(ctxt, t_string, prep);
else if (prep == PT_HEADER || prep == PT_NEW_HEADER)
MCServerExecPutHeader(ctxt, t_string, prep == PT_NEW_HEADER);
else if (prep == PT_CONTENT)
{
if (is_unicode)
MCServerExecPutContentUnicode(ctxt, t_data);
else
MCServerExecPutContent(ctxt, t_string);
}
else if (prep == PT_MARKUP)
{
if (is_unicode)
MCServerExecPutMarkupUnicode(ctxt, t_data);
else
MCServerExecPutMarkup(ctxt, t_string);
}
else if (prep == PT_BINARY)
MCServerExecPutBinaryOutput(ctxt, t_data);
}
}
void MCPut::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (dest != nil)
{
source -> compile(ctxt);
MCSyntaxFactoryEvalConstantInt(ctxt, prep);
dest -> compile_out(ctxt);
MCSyntaxFactoryEvalConstantBool(ctxt, is_unicode);
MCSyntaxFactoryExecMethodWithArgs(ctxt, kMCEngineExecPutIntoVariableMethodInfo, 0, 1, 2);
MCSyntaxFactoryExecMethodWithArgs(ctxt, kMCNetworkExecPutIntoUrlMethodInfo, 0, 1, 2);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecPutIntoFieldMethodInfo);
MCSyntaxFactoryExecMethodWithArgs(ctxt, kMCInterfaceExecPutIntoObjectMethodInfo, 0, 1, 2);
}
else if (prep == PT_COOKIE)
{
name -> compile(ctxt);
source -> compile(ctxt);
if (expires != nil)
expires -> compile(ctxt);
else
MCSyntaxFactoryEvalConstantUInt(ctxt, 0);
if (path != nil)
path -> compile(ctxt);
else
MCSyntaxFactoryEvalConstantNil(ctxt);
if (domain != nil)
domain -> compile(ctxt);
else
MCSyntaxFactoryEvalConstantNil(ctxt);
MCSyntaxFactoryEvalConstantBool(ctxt, is_secure);
MCSyntaxFactoryEvalConstantBool(ctxt, is_httponly);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecPutCookieMethodInfo);
}
else
{
source -> compile(ctxt);
switch (prep)
{
case PT_UNDEFINED:
MCSyntaxFactoryEvalConstantBool(ctxt, is_unicode);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecPutOutputMethodInfo);
break;
case PT_INTO:
case PT_AFTER:
case PT_BEFORE:
MCSyntaxFactoryEvalConstantInt(ctxt, prep);
MCSyntaxFactoryExecMethod(ctxt, kMCIdeExecPutIntoMessageMethodInfo);
break;
case PT_HEADER:
case PT_NEW_HEADER:
MCSyntaxFactoryEvalConstantBool(ctxt, prep == PT_NEW_HEADER);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecPutHeaderMethodInfo);
break;
case PT_CONTENT:
MCSyntaxFactoryEvalConstantBool(ctxt, is_unicode);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecPutContentMethodInfo);
break;
case PT_MARKUP:
MCSyntaxFactoryEvalConstantBool(ctxt, is_unicode);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecPutMarkupMethodInfo);
break;
case PT_BINARY:
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecPutBinaryOutputMethodInfo);
break;
default:
break;
}
}
MCSyntaxFactoryEndStatement(ctxt);
}
#ifdef LEGACY_EXEC
#if defined(_SERVER)
bool MCServerSetCookie(const MCString &p_name, const MCString &p_value, uint32_t p_expires, const MCString &p_path, const MCString &p_domain, bool p_secure, bool p_http_only);
Exec_stat MCPut::exec_cookie(MCExecPoint &ep)
{
char *t_name = NULL;
char *t_value = NULL;
char *t_path = NULL;
char *t_domain = NULL;
uint32_t t_name_len = 0;
uint32_t t_value_len = 0;
uint32_t t_path_len = 0;
uint32_t t_domain_len = 0;
uint32_t t_expires = 0;
bool t_success = true;
t_value = ep.getsvalue().clone();
t_value_len = ep.getsvalue().getlength();
t_success = (ES_NORMAL == name->eval(ep));
if (t_success)
{
t_name = ep.getsvalue().clone();
t_name_len = ep.getsvalue().getlength();
if (expires != NULL)
t_success = expires->eval(ep);
}
if (t_success && expires)
t_success = ep.isempty() || MCU_stoui4(ep.getsvalue(), t_expires);
if (t_success && path)
{
t_success = path->eval(ep);
if (t_success)
{
t_path = ep.getsvalue().clone();
t_path_len = ep.getsvalue().getlength();
}
}
if (t_success && domain)
{
t_success = domain->eval(ep);
if (t_success)
{
t_domain = ep.getsvalue().clone();
t_domain_len = ep.getsvalue().getlength();
}
}
if(t_success)
t_success = MCServerSetCookie(MCString(t_name, t_name_len), MCString(t_value, t_value_len), t_expires, MCString(t_path, t_path_len), MCString(t_domain, t_domain_len), is_secure, is_httponly);
MCCStringFree(t_name);
MCCStringFree(t_value);
MCCStringFree(t_path);
MCCStringFree(t_domain);
if (!t_success)
{
MCeerror->add(EE_PUT_CANTSETINTO, line, pos);
return ES_ERROR;
}
ep.clear();
return ES_NORMAL;
}
#else // !defined(_SERVER)
Exec_stat MCPut::exec_cookie(MCExecPoint &ep)
{
MCeerror->add(EE_PUT_CANTSET, line, pos);
return ES_ERROR;
}
#endif
#endif
MCQuit::~MCQuit()
{
delete retcode;
}
Parse_stat MCQuit::parse(MCScriptPoint &sp)
{
initpoint(sp);
MCerrorlock++;
sp.parseexp(False, True, &retcode);
MCerrorlock--;
return PS_NORMAL;
}
void MCQuit::exec_ctxt(MCExecContext& ctxt)
{
#ifdef LEGACY_EXEC
// MW-2011-06-22: [[ SERVER ]] Don't send messages in server-mode.
#ifndef _SERVER
switch(MCdefaultstackptr->getcard()->message(MCM_shut_down_request))
{
case ES_PASS:
case ES_NOT_HANDLED:
break;
default:
return ES_NORMAL;
}
// IM-2013-05-01: [[ BZ 10586 ]] remove #ifdefs so this message is sent
// here on Android in the same place as (almost) everything else
MCdefaultstackptr->getcard()->message(MCM_shut_down);
#endif
if (retcode != NULL && retcode->eval(ep) == ES_NORMAL
&& ep.ton() == ES_NORMAL)
MCretcode = ep.getint4();
MCquit = True;
MCquitisexplicit = True;
MCexitall = True;
MCtracestackptr = NULL;
MCtraceabort = True;
MCtracereturn = True;
return ES_NORMAL;
#endif
integer_t t_retcode;
if (!ctxt . EvalOptionalExprAsInt(retcode, 0, EE_UNDEFINED, t_retcode))
return;
MCEngineExecQuit(ctxt, t_retcode);
}
void MCQuit::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (retcode != nil)
retcode -> compile(ctxt);
else
MCSyntaxFactoryEvalConstantInt(ctxt, 0);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecQuitMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
Parse_stat MCReset::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
sp.skip_token(SP_FACTOR, TT_THE);
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_CHOOSE_NOTOKEN, sp);
return PS_ERROR;
}
if (sp.lookup(SP_RESET, te) != PS_NORMAL)
{
MCperror->add
(PE_RESET_NOTYPE, sp);
return PS_ERROR;
}
which = (Reset_type)te->which;
return PS_NORMAL;
}
void MCReset::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCReset */ LEGACY_EXEC
switch (which)
{
case RT_CURSORS:
MCModeResetCursors();
break;
case RT_PAINT:
MCeditingimage = nil;
MCbrush = 8;
MCspray = 31;
MCeraser = 2;
MCcentered = False;
MCfilled = False;
MCgrid = False;
MCgridsize = 8;
MClinesize = 1;
MCmultiple = False;
MCmultispace = 1;
MCpattern = 1;
MCpolysides = 4;
MCroundends = False;
MCslices = 16;
MCmagnification = 8;
MCpatternlist->freepat(MCpenpattern);
MCpencolor.red = MCpencolor.green = MCpencolor.blue = 0x0;
MCscreen->alloccolor(MCpencolor);
MCpatternlist->freepat(MCbrushpattern);
MCbrushcolor.red = MCbrushcolor.green = MCbrushcolor.blue = 0xFFFF;
MCscreen->alloccolor(MCbrushcolor);
break;
case RT_PRINTING:
MCprinter -> Reset();
if (MCprinter != MCsystemprinter)
{
delete MCprinter;
MCprinter = MCsystemprinter;
}
break;
case RT_TEMPLATE_AUDIO_CLIP:
delete MCtemplateaudio;
MCtemplateaudio = new MCAudioClip;
break;
case RT_TEMPLATE_BUTTON:
delete MCtemplatebutton;
MCtemplatebutton = new MCButton;
break;
case RT_TEMPLATE_CARD:
delete MCtemplatecard;
MCtemplatecard = new MCCard;
break;
case RT_TEMPLATE_EPS:
delete MCtemplateeps;
MCtemplateeps = new MCEPS;
break;
case RT_TEMPLATE_FIELD:
delete MCtemplatefield;
MCtemplatefield = new MCField;
break;
case RT_TEMPLATE_GRAPHIC:
delete MCtemplategraphic;
MCtemplategraphic = new MCGraphic;
break;
case RT_TEMPLATE_GROUP:
delete MCtemplategroup;
MCtemplategroup = new MCGroup;
break;
case RT_TEMPLATE_IMAGE:
delete MCtemplateimage;
MCtemplateimage = new MCImage;
break;
case RT_TEMPLATE_SCROLLBAR:
delete MCtemplatescrollbar;
MCtemplatescrollbar = new MCScrollbar;
break;
case RT_TEMPLATE_PLAYER:
delete MCtemplateplayer;
MCtemplateplayer = new MCPlayer;
break;
case RT_TEMPLATE_STACK:
delete MCtemplatestack;
/* UNCHECKED */ MCStackSecurityCreateStack(MCtemplatestack);
break;
case RT_TEMPLATE_VIDEO_CLIP:
delete MCtemplatevideo;
MCtemplatevideo = new MCVideoClip;
break;
default:
break;
}
return ES_NORMAL;
#endif /* MCReset */
switch (which)
{
case RT_CURSORS:
MCInterfaceExecResetCursors(ctxt);
break;
case RT_PAINT:
MCGraphicsExecResetPaint(ctxt);
break;
case RT_PRINTING:
MCPrintingExecResetPrinting(ctxt);
break;
default:
MCInterfaceExecResetTemplate(ctxt, which);
break;
}
return;
}
void MCReset::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
switch (which)
{
case RT_CURSORS:
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecResetCursorsMethodInfo);
break;
case RT_PAINT:
MCSyntaxFactoryExecMethod(ctxt, kMCGraphicsExecResetPaintMethodInfo);
break;
case RT_PRINTING:
MCSyntaxFactoryExecMethod(ctxt, kMCPrintingExecResetPrintingMethodInfo);
break;
default:
MCSyntaxFactoryEvalConstantInt(ctxt, which);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecResetTemplateMethodInfo);
break;
}
MCSyntaxFactoryEndStatement(ctxt);
}
MCReturn::~MCReturn()
{
delete source;
delete url;
delete var;
}
Parse_stat MCReturn::parse(MCScriptPoint &sp)
{
initpoint(sp);
if (sp.parseexp(False, True, &source) != PS_NORMAL)
{
MCperror->add
(PE_RETURN_BADEXP, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH) == PS_NORMAL)
{
if (sp.skip_token(SP_FACTOR, TT_CHUNK, CT_URL))
{
// MW-2011-06-22: [[ SERVER ]] Update to use SP findvar method to take into account
// execution outwith a handler.
Symbol_type type;
if (sp.next(type) != PS_NORMAL || sp.findvar(sp.gettoken_nameref(), &var) != PS_NORMAL)
sp.backup();
else
var->parsearray(sp);
}
if (var == NULL)
{
sp.skip_token(SP_FACTOR, TT_FUNCTION, F_CACHED_URLS);
if (sp.parseexp(False, True, &url) != PS_NORMAL)
{
MCperror->add
(PE_RETURN_BADEXP, sp);
return PS_ERROR;
}
}
}
return PS_NORMAL;
}
// MW-2007-07-03: [[ Bug 4570 ]] - Using the return command now causes a
// RETURN_HANDLER status rather than EXIT_HANDLER. This is used to not
// clear the result in this case. (see MCHandler::exec).
void MCReturn::exec_ctxt(MCExecContext &ctxt)
{
#ifdef /* MCReturn */ LEGACY_EXEC
if (source->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_RETURN_BADEXP, line, pos);
return ES_ERROR;
}
MCresult -> store(ep, False);
if (url != NULL)
{
if (url->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_RETURN_BADEXP, line, pos);
return ES_ERROR;
}
MCurlresult -> store(ep, False);
}
else
if (var != NULL)
{
if (var->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_RETURN_BADEXP, line, pos);
return ES_ERROR;
}
MCurlresult->store(ep, False);
var->dofree(ep);
}
return ES_RETURN_HANDLER;
#endif /* MCReturn */
MCAutoValueRef t_result;
if (!ctxt . EvalExprAsValueRef(source, EE_RETURN_BADEXP, &t_result))
return;
if (url != nil)
{
MCAutoValueRef t_url_result;
if (!ctxt . EvalExprAsValueRef(url, EE_RETURN_BADEXP, &t_url_result))
return;
MCNetworkExecReturnValueAndUrlResult(ctxt, *t_result, *t_url_result);
}
else if (var != nil)
{
MCNetworkExecReturnValueAndUrlResultFromVar(ctxt, *t_result, var);
}
else
{
MCEngineExecReturnValue(ctxt, *t_result);
}
if (!ctxt . HasError())
ctxt . SetIsReturnHandler();
}
uint4 MCReturn::linecount()
{
return 0;
}
void MCReturn::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
source -> compile(ctxt);
if (url != nil)
{
url -> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCNetworkExecReturnValueAndUrlResultMethodInfo);
}
else if (var != nil)
{
MCSyntaxFactoryEvalConstant(ctxt, var);
MCSyntaxFactoryExecMethod(ctxt, kMCNetworkExecReturnValueAndUrlResultFromVarMethodInfo);
}
else
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecReturnValueMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
Parse_stat MCScriptError::parse(MCScriptPoint &sp)
{
return PS_ERROR; // catch on/function/getprop/setprop
}
MCSet::~MCSet()
{
delete target;
delete value;
}
Parse_stat MCSet::parse(MCScriptPoint &sp)
{
initpoint(sp);
if (sp.skip_token(SP_FACTOR, TT_THE) == PS_ERROR)
{
MCperror->add(PE_SET_NOTHE, sp);
return PS_ERROR;
}
target = new MCProperty;
if (target->parse(sp, True) != PS_NORMAL)
{
MCperror->add(PE_SET_NOPROP, sp);
return PS_ERROR;
}
if (sp.skip_token(SP_FACTOR, TT_TO) != PS_NORMAL)
{
MCperror->add(PE_SET_NOTO, sp);
return PS_ERROR;
}
if (sp.parseexp(False, True, &value) != PS_NORMAL)
{
MCperror->add(PE_SET_BADEXP, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
void MCSet::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCSet */ LEGACY_EXEC
if (value->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_SET_BADEXP, line, pos);
return ES_ERROR;
}
ep.grabsvalue();
MCresult->clear(False);
if (target->set
(ep) != ES_NORMAL)
{
MCeerror->add
(EE_SET_BADSET, line, pos, ep.getsvalue());
return ES_ERROR;
}
return ES_NORMAL;
#endif /* MCSet */
MCAutoValueRef t_value;
if (!ctxt . EvalExprAsValueRef(value, EE_SET_BADEXP, &t_value))
return;
ctxt . SetTheResultToEmpty();
MCEngineExecSet(ctxt, target, *t_value);
}
/*void MCSet::compile(MCSyntaxFactoryRef ctxt)
{
}*/
MCSort::~MCSort()
{
delete of;
delete by;
}
Parse_stat MCSort::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
while (True)
{
if (sp.next(type) != PS_NORMAL)
{
if (of == NULL && chunktype == CT_FIELD)
{
MCperror->add
(PE_SORT_NOTARGET, sp);
return PS_ERROR;
}
else
break;
}
if (sp.lookup(SP_SORT, te) == PS_NORMAL)
{
switch (te->which)
{
case ST_OF:
of = new MCChunk(True);
if (of->parse(sp, False) != PS_NORMAL)
{
MCperror->add
(PE_SORT_BADTARGET, sp);
return PS_ERROR;
}
break;
case ST_BY:
if (chunktype == CT_FIELD && of == NULL)
chunktype = CT_CARD;
if (sp.parseexp(False, True, &by) != PS_NORMAL)
{
MCperror->add
(PE_SORT_BADEXPRESSION, sp);
return PS_ERROR;
}
if (of == NULL && chunktype == CT_FIELD)
{
MCperror->add
(PE_SORT_NOTARGET, sp);
return PS_ERROR;
}
return PS_NORMAL;
case ST_LINES:
chunktype = CT_LINE;
break;
case ST_ITEMS:
chunktype = CT_ITEM;
break;
case ST_MARKED:
chunktype = CT_MARKED;
break;
case ST_CARDS:
if (chunktype != CT_MARKED)
chunktype = CT_CARD;
break;
case ST_TEXT:
case ST_BINARY:
case ST_NUMERIC:
case ST_INTERNATIONAL:
case ST_DATETIME:
format = (Sort_type)te->which;
break;
case ST_ASCENDING:
case ST_DESCENDING:
direction = (Sort_type)te->which;
break;
}
}
else
{
sp.backup();
if (of == NULL)
{
of = new MCChunk(True);
if (of->parse(sp, False) != PS_NORMAL)
{
MCperror->add
(PE_SORT_BADTARGET, sp);
return PS_ERROR;
}
}
else
break;
}
}
return PS_NORMAL;
}
#ifdef LEGACY_EXEC
Exec_stat MCSort::sort_container(MCExecPoint &p_exec_point, Chunk_term p_type, Sort_type p_direction, Sort_type p_form, MCExpression *p_by)
{
MCSortnode *t_items;
uint4 t_item_count;
t_item_count = 0;
// If sorting items of the container, then we use the current itemDelimiter to split each item,
// all other forms of search default to the lineDelimiter for now. Note that this is a slight
// change of behavior as previously sorting containers by line ignored the lineDelimiter and
// always delimited by ascii 10.
char t_delimiter;
if (p_type == CT_ITEM)
t_delimiter = p_exec_point . getitemdel();
else
t_delimiter = p_exec_point . getlinedel();
if (t_delimiter == '\0')
return ES_NORMAL;
// Calculate the number of items we need to sort, store this in t_item_count.
uint4 t_item_size;
t_item_size = p_exec_point . getsvalue() . getlength();
char *t_item_text;
t_item_text = p_exec_point . getsvalue() . clone();
char *t_string_pointer;
t_string_pointer = t_item_text;
char *t_end_pointer;
bool t_trailing_delim = false;
while ((t_end_pointer = strchr(t_string_pointer, t_delimiter)) != NULL)
{
// knock out last delim for lines with a trailing return char
if (p_type != CT_ITEM && t_end_pointer[1] == '\0')
{
t_end_pointer[0] = '\0';
t_trailing_delim = true;
}
else
t_item_count++;
t_string_pointer = t_end_pointer + 1;
}
// OK-2008-12-11: [[Bug 7503]] - If there are 0 items in the string, don't carry out the search,
// this keeps the behavior consistent with previous versions of LiveCode.
if (t_item_count < 1)
{
delete t_item_text;
return ES_NORMAL;
}
// Now we know the item count, we can allocate an array of MCSortnodes to store them.
t_items = new MCSortnode[t_item_count + 1];
t_item_count = 0;
t_string_pointer = t_item_text;
// Next, populate the MCSortnodes with all the items to be sorted
MCString t_string;
do
{
if ((t_end_pointer = strchr(t_string_pointer, t_delimiter)) != NULL)
{
*t_end_pointer++ = '\0';
t_string . set(t_string_pointer, t_end_pointer - t_string_pointer - 1);
}
else
t_string . set(t_string_pointer, strlen(t_string_pointer));
MCExecPoint t_exec_point2(p_exec_point);
additem(t_exec_point2, t_items, t_item_count, p_form, t_string, p_by);
t_items[t_item_count - 1] . data = (void *)t_string_pointer;
t_string_pointer = t_end_pointer;
}
while (t_end_pointer != NULL);
// Sort the array
MCU_sort(t_items, t_item_count, p_direction, p_form);
// Build the output string
char *t_output;
t_output = new char[t_item_size + 1];
*t_output = '\0';
uint4 t_length;
t_length = 0;
for (unsigned int i = 0; i < t_item_count; i++)
{
uint4 t_item_length;
t_item_length = strlen((const char *)t_items[i] . data);
strncpy(&t_output[t_length], (const char *)t_items[i] . data, t_item_length);
t_length = t_length + t_item_length;
if ((p_form == ST_INTERNATIONAL || p_form == ST_TEXT) && (!p_exec_point . getcasesensitive() || p_by != NULL))
delete t_items[i] . svalue;
if (t_trailing_delim || i < t_item_count - 1)
t_output[t_length++] = t_delimiter;
}
t_output[t_length] = '\0';
p_exec_point . grabbuffer(t_output, t_length);
delete t_item_text;
delete t_items;
return ES_NORMAL;
}
#endif
void MCSort::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCSort */ LEGACY_EXEC
if (of == NULL && chunktype == CT_FIELD)
{
MCeerror->add
(EE_SORT_NOTARGET, line, pos);
return ES_ERROR;
}
MCObject *optr = NULL;
uint4 parid;
if (of != NULL)
{
MCerrorlock++;
if (of->getobj(ep, optr, parid, False) != ES_NORMAL
|| optr->gettype() == CT_BUTTON)
{
MCerrorlock--;
if (of->eval(ep) != ES_NORMAL)
{
MCeerror->add
(EE_SORT_BADTARGET, line, pos);
return ES_ERROR;
}
}
else
MCerrorlock--;
if (optr != NULL && optr->gettype() > CT_GROUP && chunktype <= CT_GROUP)
chunktype = CT_LINE;
}
else
optr = MCdefaultstackptr;
if (chunktype == CT_CARD || chunktype == CT_MARKED)
{
MCStack *sptr = (MCStack *)optr;
if (optr == NULL || optr->gettype() != CT_STACK
|| sptr->sort(ep, direction, format, by,
chunktype == CT_MARKED) != ES_NORMAL)
{
MCeerror->add
(EE_SORT_CANTSORT, line, pos);
return ES_ERROR;
}
}
else
{
if (optr == NULL || optr->gettype() == CT_BUTTON)
{
if (sort_container(ep, chunktype, direction, format, by) != ES_NORMAL)
{
MCeerror->add(EE_SORT_CANTSORT, line, pos);
return ES_ERROR;
}
of -> set(ep, PT_INTO);
}
else
{
MCField *fptr = (MCField *)optr;
if (optr->gettype() != CT_FIELD || !of->nochunks()
|| fptr->sort(ep, parid, chunktype, direction,
format, by) != ES_NORMAL)
{
MCeerror->add
(EE_SORT_CANTSORT, line, pos);
return ES_ERROR;
}
}
}
return ES_NORMAL;
#endif /* MCSort */
MCObjectPtr t_object;
MCAutoStringRef t_target;
// SN-2014-03-21: [[ Bug 11953 ]] sort card does not work
t_object . object = nil;
t_object . part_id = 0;
if (of != NULL)
{
MCerrorlock++;
of->getoptionalobj(ctxt, t_object, False);
if (t_object . object == nil || t_object . object->gettype() == CT_BUTTON)
{
MCerrorlock--;
if (!ctxt . EvalExprAsStringRef(of, EE_SORT_BADTARGET, &t_target))
return;
}
else
{
MCerrorlock--;
}
if (t_object . object != nil && t_object . object->gettype() > CT_GROUP && chunktype <= CT_GROUP)
chunktype = CT_LINE;
}
// SN-2015-04-01: [[ Bug 14885 ]] Make sure that the default stack is used
// if none is specified.
else
t_object . object = MCdefaultstackptr;
if (chunktype == CT_CARD || chunktype == CT_MARKED)
{
if (t_object . object == nil ||
t_object . object -> gettype() != CT_STACK)
{
ctxt . LegacyThrow(EE_SORT_CANTSORT);
return;
}
MCInterfaceExecSortCardsOfStack(ctxt, (MCStack *)t_object . object, direction == ST_ASCENDING, format, by, chunktype == CT_MARKED);
}
else if (t_object . object == nil || t_object . object->gettype() == CT_BUTTON)
{
MCStringRef t_sorted_target;
if (*t_target == nil)
t_sorted_target = MCValueRetain(kMCEmptyString);
else
t_sorted_target = MCValueRetain(*t_target);
MCInterfaceExecSortContainer(ctxt, t_sorted_target, chunktype, direction == ST_ASCENDING, format, by);
if (!ctxt . HasError())
of -> set(ctxt, PT_INTO, t_sorted_target);
MCValueRelease(t_sorted_target);
}
else
{
if (t_object . object->gettype() != CT_FIELD || !of->nochunks())
{
ctxt . LegacyThrow(EE_SORT_CANTSORT);
return;
}
MCInterfaceExecSortField(ctxt, t_object, chunktype, direction == ST_ASCENDING, format, by);
}
}
void MCSort::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (chunktype == CT_CARD || chunktype == CT_MARKED)
{
of -> compile_object_ptr(ctxt);
MCSyntaxFactoryEvalConstantBool(ctxt, direction == ST_ASCENDING);
MCSyntaxFactoryEvalConstantInt(ctxt, format);
by -> compile(ctxt);
MCSyntaxFactoryEvalConstantBool(ctxt, chunktype == CT_MARKED);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecSortCardsOfStackMethodInfo);
}
else
{
of -> compile_inout(ctxt);
if (chunktype <= CT_GROUP)
MCSyntaxFactoryEvalConstantInt(ctxt, CT_LINE);
else
MCSyntaxFactoryEvalConstantInt(ctxt, chunktype);
MCSyntaxFactoryEvalConstantBool(ctxt, direction == ST_ASCENDING);
MCSyntaxFactoryEvalConstantInt(ctxt, format);
by -> compile(ctxt);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecSortFieldMethodInfo);
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecSortContainerMethodInfo);
}
MCSyntaxFactoryEndStatement(ctxt);
}
MCWait::~MCWait()
{
delete duration;
}
Parse_stat MCWait::parse(MCScriptPoint &sp)
{
Symbol_type type;
const LT *te;
initpoint(sp);
if (sp.next(type) != PS_NORMAL)
{
MCperror->add
(PE_WAIT_NODURATION, sp);
return PS_ERROR;
}
if (sp.lookup(SP_REPEAT, te) == PS_NORMAL)
condition = (Repeat_form)te->which;
else
{
condition = RF_FOR;
sp.backup();
}
if (sp.skip_token(SP_MOVE, TT_UNDEFINED, MM_MESSAGES) == PS_NORMAL)
messages = True;
else
{
if (sp.parseexp(False, True, &duration) != PS_NORMAL)
{
MCperror->add
(PE_WAIT_BADCOND, sp);
return PS_ERROR;
}
if (condition == RF_FOR)
{
if (sp.skip_token(SP_FACTOR, TT_FUNCTION, F_MILLISECS) == PS_NORMAL)
units = F_MILLISECS;
else if (sp.skip_token(SP_FACTOR, TT_FUNCTION, F_SECONDS) == PS_NORMAL
|| sp.skip_token(SP_FACTOR, TT_CHUNK, CT_SECOND) == PS_NORMAL)
units = F_SECONDS;
else if (sp.skip_token(SP_FACTOR, TT_FUNCTION, F_TICKS) == PS_NORMAL)
units = F_TICKS;
else
units = F_TICKS;
}
if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH) == PS_NORMAL)
{
sp.skip_token(SP_MOVE, TT_UNDEFINED, MM_MESSAGES);
messages = True;
}
}
return PS_NORMAL;
}
void MCWait::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCWait */ LEGACY_EXEC
while (True)
{
MCU_play();
if (duration == NULL)
{
if (MCscreen->wait(MCmaxwait, messages, messages) || MCabortscript)
{
MCeerror->add(EE_WAIT_ABORT, line, pos);
return ES_ERROR;
}
break;
}
else
{
if (duration->eval(ep) != ES_NORMAL)
{
MCeerror->add(EE_WAIT_BADEXP, line, pos);
return ES_ERROR;
}
switch (condition)
{
case RF_FOR:
real8 delay;
if (ep.getreal8(delay, line, pos, EE_WAIT_NAN) != ES_NORMAL)
return ES_ERROR;
switch (units)
{
case F_MILLISECS:
delay /= 1000.0;
break;
case F_TICKS:
delay /= 60.0;
break;
default:
break;
}
if (MCscreen->wait(delay, messages, False))
{
MCeerror->add(EE_WAIT_ABORT, line, pos);
return ES_ERROR;
}
return ES_NORMAL;
case RF_UNTIL:
if (ep.getsvalue() == MCtruemcstring)
return ES_NORMAL;
if (MCscreen->wait(WAIT_INTERVAL, messages, True))
{
MCeerror->add(EE_WAIT_ABORT, line, pos);
return ES_ERROR;
}
break;
case RF_WHILE:
if (ep.getsvalue() == MCfalsemcstring)
return ES_NORMAL;
if (MCscreen->wait(WAIT_INTERVAL, messages, True))
{
MCeerror->add(EE_WAIT_ABORT, line, pos);
return ES_ERROR;
}
break;
default:
return ES_ERROR;
}
}
}
return ES_NORMAL;
#endif /* MCWait */
if (duration == NULL)
MCEngineExecWaitFor(ctxt, MCmaxwait, F_UNDEFINED, messages == True);
else
{
switch (condition)
{
case RF_FOR:
{
double t_delay;
if (!ctxt . EvalExprAsDouble(duration, EE_WAIT_BADEXP, t_delay))
return;
MCEngineExecWaitFor(ctxt, t_delay, units, messages == True);
break;
}
case RF_UNTIL:
MCEngineExecWaitUntil(ctxt, duration, messages == True);
break;
case RF_WHILE:
MCEngineExecWaitWhile(ctxt, duration, messages == True);
break;
default:
return;
}
}
}
void MCWait::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
if (duration == nil)
{
MCSyntaxFactoryEvalConstantDouble(ctxt, MCmaxwait);
MCSyntaxFactoryEvalConstantInt(ctxt, F_UNDEFINED);
MCSyntaxFactoryEvalConstantBool(ctxt, messages == True);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecWaitForMethodInfo);
}
else
{
duration -> compile(ctxt);
switch (condition)
{
case RF_FOR:
MCSyntaxFactoryEvalConstantInt(ctxt, units);
MCSyntaxFactoryEvalConstantBool(ctxt, messages == True);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecWaitForMethodInfo);
break;
case RF_UNTIL:
MCSyntaxFactoryEvalConstantBool(ctxt, messages == True);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecWaitUntilMethodInfo);
break;
case RF_WHILE:
MCSyntaxFactoryEvalConstantBool(ctxt, messages == True);
MCSyntaxFactoryExecMethod(ctxt, kMCEngineExecWaitWhileMethodInfo);
break;
default:
break;
}
}
}
MCInclude::~MCInclude(void)
{
delete filename;
}
Parse_stat MCInclude::parse(MCScriptPoint& sp)
{
initpoint(sp);
if (sp . parseexp(False, True, &filename) != PS_NORMAL)
{
MCperror -> add(PE_INCLUDE_BADFILENAME, sp);
return PS_ERROR;
}
return PS_NORMAL;
}
void MCInclude::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCInclude */ LEGACY_EXEC
if (filename -> eval(ep) != ES_NORMAL)
{
MCeerror -> add(EE_INCLUDE_BADFILENAME, line, pos);
return ES_ERROR;
}
#ifdef _SERVER
MCServerScript *t_script;
t_script = static_cast(ep . getobj());
if (t_script -> GetIncludeDepth() > 16)
{
MCeerror -> add(EE_INCLUDE_TOOMANY, line, pos);
return ES_ERROR;
}
if (!t_script -> Include(ep, ep . getcstring(), is_require))
{
MCeerror -> add(EE_SCRIPT_ERRORPOS, line, pos);
return ES_ERROR;
}
return ES_NORMAL;
#else
MCeerror -> add(is_require ? EE_REQUIRE_BADCONTEXT : EE_INCLUDE_BADCONTEXT, line, pos);
return ES_ERROR;
#endif
#endif /* MCInclude */
MCAutoStringRef t_filename;
if (!ctxt . EvalExprAsStringRef(filename, EE_INCLUDE_BADFILENAME, &t_filename))
return;
MCServerExecInclude(ctxt, *t_filename, is_require);
}
void MCInclude::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
filename -> compile(ctxt);
MCSyntaxFactoryEvalConstantBool(ctxt, is_require);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecIncludeMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCEcho::~MCEcho(void)
{
if (data != nil)
MCValueRelease(data);
}
Parse_stat MCEcho::parse(MCScriptPoint& sp)
{
initpoint(sp);
data = MCValueRetain(sp . gettoken_stringref());
return PS_NORMAL;
}
void MCEcho::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCEcho */ LEGACY_EXEC
if (!MCS_put(ep, kMCSPutBinaryOutput, data) != IO_NORMAL)
MCexitall = True;
return ES_NORMAL;
#endif /* MCEcho */
MCServerExecEcho(ctxt, data);
return;
}
void MCEcho::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
MCSyntaxFactoryEvalConstant(ctxt, data);
MCSyntaxFactoryExecMethod(ctxt, kMCServerExecEchoMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
MCResolveImage::~MCResolveImage(void)
{
delete m_relative_object;
delete m_id_or_name;
}
Parse_stat MCResolveImage::parse(MCScriptPoint &p_sp)
{
Parse_stat t_stat;
t_stat = PS_NORMAL;
if (t_stat == PS_NORMAL)
t_stat = p_sp.skip_token(SP_FACTOR, TT_CHUNK, CT_IMAGE);
// Parse the optional 'id' token
m_is_id = (PS_NORMAL == p_sp . skip_token(SP_FACTOR, TT_PROPERTY, P_ID));
// Parse the id_or_name expression
if (t_stat == PS_NORMAL)
t_stat = p_sp . parseexp(False, True, &m_id_or_name);
if (t_stat != PS_NORMAL)
{
MCperror->add
(PE_RESOLVE_BADIMAGE, p_sp);
return PS_ERROR;
}
// Parse the 'relative to' tokens
if (t_stat == PS_NORMAL)
t_stat = p_sp . skip_token(SP_FACTOR, TT_TO, PT_RELATIVE);
if (t_stat == PS_NORMAL)
t_stat = p_sp . skip_token(SP_FACTOR, TT_TO, PT_TO);
// Parse the target object clause
if (t_stat == PS_NORMAL)
{
m_relative_object = new MCChunk(false);
t_stat = m_relative_object -> parse(p_sp, False);
}
else
{
MCperror->add
(PE_RESOLVE_BADOBJECT, p_sp);
return PS_ERROR;
}
return t_stat;
}
void MCResolveImage::exec_ctxt(MCExecContext &ctxt)
{
#ifdef /* MCResolveImage */ LEGACY_EXEC
Exec_stat t_stat;
t_stat = ES_NORMAL;
uint4 t_part_id;
MCObject *t_relative_object;
if (t_stat == ES_NORMAL)
t_stat = m_relative_object -> getobj(p_ep, t_relative_object, t_part_id, True);
if (t_stat == ES_NORMAL)
t_stat = m_id_or_name -> eval(p_ep);
MCImage *t_found_image;
t_found_image = nil;
if (t_stat == ES_NORMAL)
{
if (m_is_id)
{
if (p_ep . ton() == ES_ERROR)
{
MCeerror -> add(EE_VARIABLE_NAN, line, pos);
return ES_ERROR;
}
t_found_image = t_relative_object -> resolveimageid(p_ep . getuint4());
}
else
{
MCAutoStringRef t_name;
/* UNCHECKED */ p_ep . copyasstringref(&t_name);
t_found_image = t_relative_object -> resolveimagename(*t_name);
}
if (t_found_image != nil)
t_stat = t_found_image -> getprop(0, P_LONG_ID, p_ep, False);
else
p_ep . clear();
}
if (t_stat == ES_NORMAL)
t_stat = p_ep.getit() -> set(p_ep);
return t_stat;
#endif /* MCResolveImage */
uint4 t_part_id;
MCObject *t_relative_object;
if (!m_relative_object -> getobj(ctxt, t_relative_object, t_part_id, True))
{
ctxt . Throw();
return;
}
if (m_is_id)
{
uinteger_t t_id;
if (!ctxt . EvalExprAsUInt(m_id_or_name, EE_RESOLVE_IMG_BADEXP, t_id))
return;
MCInterfaceExecResolveImageById(ctxt, t_relative_object, t_id);
}
else
{
MCAutoStringRef t_name;
if (!ctxt . EvalExprAsStringRef(m_id_or_name, EE_RESOLVE_IMG_BADEXP, &t_name))
return;
MCInterfaceExecResolveImageByName(ctxt, t_relative_object, *t_name);
}
}
void MCResolveImage::compile(MCSyntaxFactoryRef ctxt)
{
MCSyntaxFactoryBeginStatement(ctxt, line, pos);
m_relative_object -> compile_object_ptr(ctxt);
m_id_or_name -> compile(ctxt);
if (m_is_id)
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecResolveImageByIdMethodInfo);
else
MCSyntaxFactoryExecMethod(ctxt, kMCInterfaceExecResolveImageByNameMethodInfo);
MCSyntaxFactoryEndStatement(ctxt);
}
////////////////////////////////////////////////////////////////////////////////
//
// MW-2013-11-14: [[ AssertCmd ]] Implementation of 'assert' command.
//
MCAssertCmd::~MCAssertCmd(void)
{
delete m_expr;
}
// assert
// assert true
// assert false
// assert success
// assert failure
Parse_stat MCAssertCmd::parse(MCScriptPoint& sp)
{
initpoint(sp);
// See if there is a type token
MCScriptPoint temp_sp(sp);
if (sp . skip_token(SP_SUGAR, TT_UNDEFINED, SG_TRUE) == PS_NORMAL)
m_type = TYPE_TRUE;
else if (sp . skip_token(SP_SUGAR, TT_UNDEFINED, SG_FALSE) == PS_NORMAL)
m_type = TYPE_FALSE;
else if (sp . skip_token(SP_SUGAR, TT_UNDEFINED, SG_SUCCESS) == PS_NORMAL)
m_type = TYPE_SUCCESS;
else if (sp . skip_token(SP_SUGAR, TT_UNDEFINED, SG_FAILURE) == PS_NORMAL)
m_type = TYPE_FAILURE;
else
m_type = TYPE_NONE;
// Now try to parse an expression
if (sp.parseexp(False, True, &m_expr) == PS_NORMAL)
return PS_NORMAL;
// Now if we are not of NONE type, then backup and try for just an
// expression (TYPE_NONE).
if (m_type != TYPE_NONE)
{
MCperror -> clear();
sp = temp_sp;
}
// Parse the expression again (if not NONE, otherwise we already have
// a badexpr error to report).
if (m_type == TYPE_NONE ||
sp.parseexp(False, True, &m_expr) != PS_NORMAL)
{
MCperror -> add(PE_ASSERT_BADEXPR, sp);
return PS_ERROR;
}
// We must be of type none.
m_type = TYPE_NONE;
return PS_NORMAL;
}
void MCAssertCmd::exec_ctxt(MCExecContext& ctxt)
{
#ifdef /* MCAssertCmd */ LEGACY_EXEC
Exec_stat t_stat;
t_stat = ES_NORMAL;
t_stat = m_expr -> eval(ep);
switch(m_type)
{
case TYPE_NONE:
case TYPE_TRUE:
// If the expression threw an error, then just throw.
if (t_stat != ES_NORMAL)
return ES_ERROR;
// If the expression is true, we are done.
if (ep.getsvalue() == MCtruemcstring)
return ES_NORMAL;
break;
case TYPE_FALSE:
// If the expression threw an error, then just throw.
if (t_stat != ES_NORMAL)
return ES_ERROR;
// If the expression is not true, we are done. (this uses the same logic as if).
if (ep.getsvalue() != MCtruemcstring)
return ES_NORMAL;
break;
case TYPE_SUCCESS:
if (t_stat == ES_NORMAL)
return ES_NORMAL;
break;
case TYPE_FAILURE:
if (t_stat == ES_ERROR)
return ES_NORMAL;
break;
default:
assert(false);
break;
}
// Clear the execution error.
MCeerror -> clear();
// Dispatch 'assertError , , ,