lang.c

Go to the documentation of this file.
00001 
00002 /*  $Id: lang.c 1328 2006-04-24 20:02:59Z sethdill $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "db.h"
00033 #include "error.h"
00034 #include "cursor.h"
00035 #include "kb.h"
00036 #include "font.h"
00037 #include "resources.h"
00038 #include "strings.h"
00039 #include "threads.h"
00040 #include "ops.h"
00041 #include "lang.h"
00042 #include "langexternal.h"
00043 #include "langinternal.h"
00044 #include "langparser.h"
00045 #include "langsystem7.h"
00046 #include "op.h"
00047 #include "shell.rsrc.h"
00048 #include "shellhooks.h"
00049 #include "timedate.h" /* for the milliseconds function */
00050 
00051 #include "process.h"
00052 #include "tablestructure.h"
00053 
00054 
00055 
00056 
00057 byte bstrue [] = "\x04" "true"; /*so we don't replicate this constant*/
00058 
00059 byte bsfalse [] = "\x05" "false"; /*or this one, either*/
00060 
00061 
00062 hdlhashtable hmagictable = nil; /*for communication with evaluatelist*/
00063 
00064 hdlhashtable hkeywordtable; /*holds the language's keywords*/
00065 
00066 hdlhashtable hbuiltinfunctions; /*holds the names of the built-in functions*/
00067 
00068 hdlhashtable hconsttable; /*holds the names of built-in constants, like true and up*/
00069 
00070 boolean flbreak = false; /*for loop and break ops*/
00071 
00072 boolean flcontinue = false; /*for loops*/
00073 
00074 boolean flreturn = false; /*for return op*/
00075 
00076 boolean flscriptrunning = false; /*for nesting within thread*/
00077 
00078 boolean flscriptresting = false; /*for being friendly, performance-wise*/
00079 
00080 hdltreenode herrornode = nil;
00081 
00082 tylangcallbacks langcallbacks; /*routines that wire the language into environment*/
00083 
00084 boolean flcominitialized = false;
00085 
00086 
00087 
00088 static short ctrootchains = 0; /*number of hashtable chains that include the root*/
00089 
00090 static boolean flevaluateglobalwith = false; /*dmb 4.1b12 - new flag for langcard support*/
00091 
00092 
00093 
00094 static boolean langtracktimeslice (tyerrorrecord *slice) {
00095     
00096     hdlerrorstack hs = langcallbacks.scripterrorstack;
00097     hdlprocessrecord hp = currentprocess;
00098     hdlhashtable hprofiledata;
00099     tyerrorrecord *pe = slice;
00100     hdlhashtable htable;
00101     bigstring bsname, bspath;
00102     hdlhashnode hnode;
00103     tyvaluerecord val;
00104     
00105     if (hp == nil)
00106         return (false);
00107     
00108     if (hs == nil)
00109         return (false);
00110     
00111     hprofiledata = (hdlhashtable) (**(**hp).hprofiledata).variabledata;
00112     
00113     if (hprofiledata == nil)
00114         return (false);
00115     
00116     if ((*pe).errorcallback == nil
00117          || !(*(*pe).errorcallback) ((*pe).errorrefcon, 0, 0, &htable, bsname)) {
00118     
00119         langgetstringlist (anomynousthreadstring, bspath);
00120         }
00121     else {
00122         if (htable == nil)
00123             copystring (bsname, bspath);
00124         else
00125             langexternalgetfullpath (htable, bsname, bspath, nil);
00126         }
00127     
00128     if (hashtablelookupnode (hprofiledata, bspath, &hnode)) {
00129         
00130         (**hnode).val.data.longvalue += (*pe).profiletotal;
00131         }
00132     else {
00133         setlongvalue ((*pe).profiletotal, &val);
00134         
00135         hashtableassign (hprofiledata, bspath, val);
00136         }
00137         
00138     return (true);
00139     } /*langtracktimeslice*/
00140 
00141 
00142 boolean langstartprofiling (void) {
00143     
00144     /*
00145     5.0.2b15 dmb: initialize profiling stats for current source frame
00146     */
00147     
00148     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00149     register hdlprocessrecord hp = currentprocess;
00150     //short ix, ixtop;
00151     tyerrorrecord *pe;
00152     /*unsigned long ticksnow = gettickcount ();*/
00153     unsigned long msnow = getmilliseconds ();
00154     
00155     if ((hs == nil) || ((**hs).toperror <= 0))
00156         return (false);
00157     
00158     if (hp && (**hp).flprofiling) { // should always be true
00159         
00160         /*
00161         ixtop = (**hs).toperror;
00162         
00163         for (ix = 0; ix < ixtop; ++ix) {
00164             
00165             pe = &(**hs).stack [ix];
00166             
00167             (*pe).profilebase = ticksnow;
00168             
00169             (*pe).profiletotal = 0;
00170             }
00171         */
00172         pe = &(**hs).stack [(**hs).toperror - 1];
00173         
00174         (*pe).profilebase = msnow;
00175         
00176         (*pe).profiletotal = 0;
00177         }
00178     
00179     return (true);
00180     } /*langstartprofiling*/
00181 
00182 
00183 boolean langstopprofiling (void) {
00184     
00185     /*
00186     5.0.2b15 dmb: grab profiling stats for current source frame
00187     */
00188     
00189     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00190     register hdlprocessrecord hp = currentprocess;
00191     short ix;
00192     tyerrorrecord item;
00193     /*unsigned long ticksnow = gettickcount ();*/
00194     unsigned long msnow = getmilliseconds ();
00195     
00196     if ((hs == nil) || ((**hs).toperror <= 0))
00197         return (false);
00198     
00199     if (hp && (**hp).flprofiling) {
00200         
00201         for (ix = (**hs).toperror - 1; ix >= 0; --ix) {
00202             
00203             item = (**hs).stack [ix];
00204             
00205             if (item.profilebase != 0) { // included in profile
00206             
00207                 item.profiletotal += msnow - item.profilebase;
00208                 
00209                 langtracktimeslice (&item);
00210                 }
00211             }
00212         }
00213     
00214     return (true);
00215     } /*langstopprofiling*/
00216 
00217 
00218 boolean langpusherrorcallback (langerrorcallback errorroutine, long errorrefcon) {
00219     
00220     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00221     register hdlprocessrecord hp = currentprocess;
00222     tyerrorrecord *pe;
00223     tyerrorrecord item;
00224     
00225     if (hs == nil)
00226         return (false);
00227     
00228     if (!langcheckstacklimit (iderrorcallbackstack, (**hs).toperror, cterrorcallbacks)) /*overflow!*/
00229         return (false);
00230     
00231     item.errorcallback = errorroutine;
00232     
00233     item.errorline = ctscanlines;
00234     
00235     item.errorchar = ctscanchars;   
00236     
00237     item.errorrefcon = errorrefcon;
00238     
00239     #ifdef flnewfeatures
00240     
00241     item.profilebase = 0;
00242     
00243     if (hp && (**hp).flprofiling) {
00244         
00245         /* item.profilebase = gettickcount (); */
00246         item.profilebase = getmilliseconds ();
00247         
00248         item.profiletotal = 0;
00249     
00250         if ((**hp).flprofilesliced && ((**hs).toperror > 0)) { // add sliced time to previous function
00251             
00252             pe = &(**hs).stack [(**hs).toperror - 1];
00253             
00254             (*pe).profiletotal += item.profilebase - (*pe).profilebase;
00255             }
00256         }
00257     
00258     #endif
00259     
00260     (**hs).stack [(**hs).toperror++] = item;
00261     
00262     return (true);
00263     } /*langpusherrorcallback*/
00264 
00265 
00266 boolean langpoperrorcallback (void) {
00267     
00268     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00269     register hdlprocessrecord hp = currentprocess;
00270     tyerrorrecord *pe;
00271     short ixtop;
00272     
00273     if (hs == nil)
00274         return (false);
00275     
00276     if ((**hs).toperror <= 0)
00277         return (false);
00278     
00279     ixtop = --(**hs).toperror;
00280     
00281     #ifdef flnewfeatures
00282     
00283     if (hp && (**hp).flprofiling) {
00284     
00285         tyerrorrecord item;
00286         boolean flsliced = (**hp).flprofilesliced;
00287         
00288         item = (**hs).stack [ixtop]; // the one we just popped
00289         
00290         /* item.profiletotal += gettickcount () - item.profilebase; */
00291         item.profiletotal += getmilliseconds () - item.profilebase;
00292         
00293         pe = &(**hs).stack [ixtop - 1]; // new new current top item
00294         
00295         if (flsliced || ixtop == 0 || (*pe).errorrefcon != item.errorrefcon)
00296             langtracktimeslice (&item);
00297         
00298         if ((**hp).flprofilesliced && (ixtop > 0)) // restart previous function timer
00299             /* (*pe).profilebase = gettickcount (); */
00300             (*pe).profilebase = getmilliseconds ();
00301         }
00302     
00303     #endif
00304     
00305     return (true);
00306     } /*langpoperrorcallback*/
00307 
00308 
00309 #ifdef flnewfeatures    // flstacktrace
00310 
00311 boolean langseterrorcallbackline (void) {
00312     
00313     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00314     tyerrorrecord *pe;
00315     
00316     if (hs == nil)
00317         return (false);
00318     
00319     if ((**hs).toperror <= 0)
00320         return (false);
00321     
00322     pe = &(**hs).stack [(**hs).toperror - 1];
00323     
00324     (*pe).errorline = ctscanlines;
00325     
00326     (*pe).errorchar = ctscanchars;
00327     
00328     return (true);
00329     } /*langpoperrorcallback*/
00330 
00331 #endif
00332 
00333 
00334 unsigned long langgetsourceoffset (unsigned long lnum, unsigned short charnum) {
00335 
00336     return (parsegetscanoffset (lnum, charnum));
00337     } /*langgetsourceoffset*/
00338 
00339 
00340 void langsetsourceoffset (unsigned long offset) {
00341 
00342     parsesetscanoffset (offset);
00343     } /*langsetsourceoffset*/
00344 
00345 
00346 boolean langfinderrorrefcon (long errorrefcon, langerrorcallback *errorcallback) {
00347     
00348     /*
00349     return true if the errorrefcon is found in the scripterror stack.
00350     
00351     this is used to determine if a piece of code is in use.
00352     
00353     2.1b3 dmb: return the callback associated with the refcon; scripts.c 
00354     uses this routine for tracking local subroutine calls
00355     */
00356     
00357     register hdlerrorstack hs = langcallbacks.scripterrorstack;
00358     register short ix;
00359     register short ixtop;
00360     register long refcon = errorrefcon;
00361     
00362     if (hs == nil)
00363         return (false);
00364     
00365     ixtop = (**hs).toperror;
00366     
00367     for (ix = 0; ix < ixtop; ++ix) {
00368         
00369         if ((**hs).stack [ix].errorrefcon == refcon) { /*found it*/
00370             
00371             *errorcallback = (**hs).stack [ix].errorcallback;
00372             
00373             return (true);
00374             }
00375         }
00376     
00377     return (false);
00378     } /*langfinderrorrefcon*/
00379 
00380 
00381 static void langprescript (void) {
00382     
00383     /*
00384     run this code once each time you are about to run or compile a script.
00385     
00386     1/9/91 dmb: used to call cleartmpstack from here.  presumably, the intention 
00387     was to start with a clean slate, and to avoid accumlating stuff in the 
00388     root table's temp stack.  however, this routine can be called pretty much 
00389     asynchonously with repect to language execution, so we don't know which 
00390     hash table is current, let alone whether stuff in the temp stack is still 
00391     needed.  therefore, it seems that the right place to make this call is 
00392     in langpopscopechain (a recently-added routine), when popping the last chain.
00393     
00394     1/25/91 dmb: also need to clear return & break globals here, or else 
00395     script may not run properly
00396     */
00397     
00398     fllangerror = false; /*the user hasn't seen an error dialog yet*/
00399     
00400     flreturn = false;
00401     
00402     flbreak = false;
00403     
00404     flcontinue = false;
00405     } /*langprescript*/
00406 
00407 
00408 static void langpostscript (void) {
00409     
00410     /*
00411     call this after you've finished evaluating a tree or evaluating a list,
00412     but are not recursively inside the tree interpreter.
00413     */
00414     
00415     flreturn = false;
00416     
00417     flbreak = false;
00418     
00419     flcontinue = false;
00420     } /*langpostscript*/
00421 
00422 
00423 static bigstring bsparsererror;
00424 
00425 static long lnumerror, cnumerror;
00426 
00427 static ptrvoid refconerror;
00428 
00429 
00430 static boolean langcompileerror (bigstring bs, ptrvoid refcon) {
00431 
00432     /*
00433     5.1.2 dmb: added refconerror to capture refcon value for orig callback
00434     */
00435 
00436     if (isemptystring (bsparsererror)) { /*1st error reported*/
00437         
00438         copystring (bs, bsparsererror); 
00439         
00440         lnumerror = ctscanlines;
00441         
00442         cnumerror = ctscanchars;
00443 
00444         refconerror = refcon;
00445         }
00446     
00447     return (true);
00448     } /*langcompileerror*/
00449 
00450 
00451 boolean langcompiletext (Handle htext, boolean fllinebased, hdltreenode *hcode) {
00452     
00453     /*
00454     parse the program text in htext and return true if it was free of 
00455     syntax errors.
00456     
00457     in either case, we dispose of the text, assuming that the caller has 
00458     no more need of it.
00459     
00460     12/26/91 dmb: if yyparse return val is 2, don't dispose yy vals
00461     
00462     6/23/92 dmb: moved parseerror here from langerror.c; now just set 
00463     global string & check it after yyparse completes.  this allows error 
00464     handler to not have to worry about parser reentrancy (not!)
00465     
00466     5/7/93 dmb: added fllinebased parameter. when false, ctscanlines/ctscanchars 
00467     are really the high & low words of an absolute offset.
00468     */
00469     
00470     register hdltreenode h;
00471     int yyresult;
00472     langerrormessagecallback savecallback;
00473     
00474     *hcode = nil; /*default, no code generated*/
00475     
00476     parsesetscanstring (htext, fllinebased);  /*the scanner sets its globals with this text*/
00477     
00478     setemptystring (bsparsererror);
00479     
00480     langstarttrace (); /*prepare the trace dialog, if it's active*/
00481     
00482     savecallback = langcallbacks.errormessagecallback;
00483     
00484     langcallbacks.errormessagecallback = &langcompileerror;
00485     
00486     yyresult = yyparse (); /*parse the text, producing parsetree -- if no syntax errors*/
00487     
00488     langcallbacks.errormessagecallback = savecallback;
00489     
00490     langendtrace (); /*close the tracing dialog box*/
00491     
00492     disposehandle (htext); 
00493     
00494     h = yyval; /*copy into register*/ /*parseresult.parsetree*/
00495     
00496     if (yyresult != 0) { /*an error occurred*/
00497         
00498         if (yyresult != 2) { /*not an out-of-mem error*/
00499             
00500             if (h && *h) //Win safety
00501                 langdisposetree (h); /*dispose whatever was built...*/
00502             
00503             langdisposetree (yylval); /*...including this piece*/
00504             }
00505         
00506         if (!isemptystring (bsparsererror)) {
00507             
00508             ctscanlines = lnumerror;
00509             
00510             ctscanchars = cnumerror;
00511             
00512             (*savecallback) (bsparsererror, refconerror);
00513             }
00514         
00515         return (false);
00516         }
00517     
00518     if (h == nil) /*syntax error, or system error*/
00519         return (false);
00520     
00521     *hcode = h; 
00522     
00523     return (true);
00524     } /*langcompiletext*/
00525 
00526 
00527 boolean langbuildtree (Handle htext, boolean fllinebased, hdltreenode *hcode) {
00528     
00529     /*
00530     wrapper around langcompiletext, resets lang globals, clears error window
00531     */
00532     
00533     langprescript (); /*initialize lang globals, about to compile a script*/
00534     
00535     return (langcompiletext (htext, fllinebased, hcode)); /*disposes htext*/
00536     } /*langbuildtree*/
00537 
00538 
00539 boolean langdefaultpushtable (hdlhashtable *htable) {
00540     
00541     register hdlhashtable ht;
00542     
00543     if (!newhashtable (htable))
00544         return (false);
00545         
00546     ht = *htable; /*copy into register*/
00547     
00548     (**ht).fllocaltable = true;
00549     
00550     chainhashtable (ht); /*link it into the runtime stack*/
00551     
00552     return (true);
00553     } /*langdefaultpushtable*/
00554     
00555     
00556 boolean langdefaultpoptable (hdlhashtable htable) {
00557 #pragma unused (htable)
00558 
00559     register hdlhashtable ht = currenthashtable;
00560     
00561     unchainhashtable ();
00562     
00563     disposehashtable (ht, false);
00564     
00565     return (true);
00566     } /*langdefaultpoptable*/
00567 
00568 
00569 static boolean langerrorhook (bigstring bs) {
00570     
00571     langerrormessage (bs);
00572     
00573     return (false); /*consume the error*/
00574     } /*langerrorhook*/
00575 
00576 
00577 void langhookerrors (void) {
00578 
00579     /*
00580     5.1.3 dmb: export this functionality: hook shell errors into lang error system
00581     */
00582     
00583     shellpusherrorhook (&langerrorhook);
00584     } /*langhookerrors*/
00585 
00586 
00587 void langunhookerrors (void) {
00588 
00589     shellpoperrorhook ();
00590     } /*langunhookerrors*/
00591 
00592 
00593 static boolean langtraperrormessage (bigstring bsmsg, ptrstring perrorstring) {
00594     
00595     /*
00596     5.0a25 dmb: trap errors so caller can 
00597     make a better message that includes the more information
00598     */
00599     
00600     copystring (bsmsg, perrorstring);
00601     
00602     return (true);
00603     } /*langtraperrormessage*/
00604 
00605 
00606 void langtraperrors (bigstring bserror, langerrormessagecallback *savecallback, ptrvoid *saverefcon) {
00607     
00608     /*
00609     hook errors into bserror so caller can embellish
00610     */
00611 
00612     setemptystring (bserror);
00613     
00614     *saverefcon = langcallbacks.errormessagerefcon;
00615     
00616     *savecallback = langcallbacks.errormessagecallback;
00617     
00618     langcallbacks.errormessagerefcon = bserror;
00619     
00620     langcallbacks.errormessagecallback = (langerrormessagecallback) &langtraperrormessage;
00621     } /*langtraperrors*/
00622 
00623 
00624 void languntraperrors (langerrormessagecallback savecallback, ptrvoid saverefcon, boolean flerror) {
00625 
00626     /*
00627     unhook errors. if flerror is true, then the caller wants some sort of error 
00628     message in the old error string (that we have set as the errormessagerefcon)
00629     */
00630     
00631     ptrstring bserror = (ptrstring) langcallbacks.errormessagerefcon;
00632     
00633     if (flerror) {
00634         
00635         if (isemptystring (bserror))
00636         {
00637             if (getoserror () != noErr)
00638                 getsystemerrorstring (getoserror (), bserror);
00639             else
00640                 getstringlist (langerrorlist, undefinederror, bserror);
00641         }
00642     }
00643 
00644     langcallbacks.errormessagecallback = savecallback;
00645     
00646     langcallbacks.errormessagerefcon = saverefcon;
00647     } /*languntraperrors*/
00648 
00649 
00650 void langpushscopechain (void) {
00651     
00652     /*
00653     1/8/91 dmb: since language execution threads can be stacked (i.e. 
00654     one process can run through the background task while another is 
00655     evaluating), we must always make sure to start a new hash table 
00656     chain for variable scoping.
00657     
00658     we push the nil table so we don't pick up the local chain of something 
00659     that's already running
00660     
00661     we call chainhashtable for the global table (root) so that its flchained 
00662     flag will be set to protect it from untimely disposal
00663     
00664     note that we no longer attempt to set a global "current" hash table from the 
00665     upper layers (cancoon.c, tablestructure.c), so when nothing is pushed, the 
00666     current hash table is nil.
00667     */
00668     
00669     pushhashtable (nil); /*clean slate*/
00670     
00671     chainhashtable (roottable); /*establishes new chain; sets flchained bit*/
00672     
00673     ++ctrootchains;
00674     } /*langpushscopechain*/
00675 
00676 
00677 void langpopscopechain (void) {
00678     
00679     register hdlhashtable ht = currenthashtable;
00680     
00681     unchainhashtable ();
00682     
00683     pophashtable (); /*restore original*/
00684     
00685     --ctrootchains;
00686     
00687     if (ctrootchains == 0) { /*we've popped the last scope chain*/
00688         
00689         if ((**ht).fldisposewhenunchained) /*file was probably closed*/
00690             disposehashtable (ht, false);
00691         
00692         else {
00693             pushhashtable (ht);
00694             
00695             cleartmpstack (); /*see comment in langprescript*/
00696             
00697             pophashtable ();
00698             }
00699         }
00700     else
00701         (**ht).flchained = true; /*this guy is still at the end of another chain*/
00702     } /*langpopscopechain*/
00703 
00704 
00705 static boolean renumberlinesvisit (hdltreenode hnode, ptrvoid refcon) {
00706 #pragma unused (refcon)
00707 
00708     /*
00709     when langrun executes code from within a script, it tries to preserve 
00710     the ability to locate errors and step in the debugger.  from the 
00711     point of view of the running script, the code about to be executed 
00712     is on the line that triggered the call to langrun.  our job is to 
00713     patch the code tree so that every node points to the current line and 
00714     character position
00715     */
00716     
00717     (**hnode).lnum = ctscanlines;
00718     
00719     (**hnode).charnum = ctscanchars;
00720     
00721     return (true);
00722     } /*renumberlinesvisit*/
00723 
00724 
00725 boolean langrun (Handle htext, tyvaluerecord *val) {
00726     
00727     /*
00728     compile and run the program source in htext.  if the syntax checks, and
00729     the program runs without error, return the result as a value record.
00730     
00731     we consume the text handle -- it is disposed before we return.
00732     
00733     1/3/90 dmb: temporarily patch out most langcallbacks, both for speed 
00734     and to avoid interference with the current process, which may be 
00735     being debugged.
00736     
00737     1/8/91 dmb: see comment in pushscopechain
00738     
00739     1/14/91 dmb: make sure that the value is maintained in a temp stack if 
00740     one is available.  if not, caller is reponsible for disposal
00741     
00742     10/23/91 dmb: reworked handling of flscriptalreadyrunning case.  we now 
00743     try to preserve the execution environment as much as possible so that 
00744     mechanisms in place in the parent script continue to function, like 
00745     error reporting and debugging.
00746     
00747     11/5/91 dmb: don't clear langerror window if script is being run with 
00748     errors disabled.
00749     
00750     3/30/93 dmb: process.c no longer keeps it's callbacks set up in the main 
00751     thread, so when a script isn't already running we don't have to undo them.
00752     
00753     also, if a table is already pushed when a script isn't running, we assume 
00754     our caller is in control and doesn't want us to push a scope chain.
00755     
00756     3.0.2 dmb: if a script is already running, pass a refcon of -1 along with 
00757     nil so that a "with" statement in the evaluated text won't carry through 
00758     to subroutine calls
00759 
00760     4.1b4 dmb: if a script is not already running, push a normal nil callback;
00761     initlang in langstartup.c no longer does this
00762     
00763     4.1b11 dmb: use new flevaluateglobalwith flag to avoid passing this as 
00764     a parameter everywhere. Running card scripts needs it.
00765     */
00766     
00767     register boolean fl;
00768     hdltreenode hcode;
00769     /*tylangcallbacks savecallbacks;*/
00770     boolean fltmpval;
00771     register boolean flscriptalreadyrunning = flscriptrunning;
00772     register boolean fltablealreadypushed = false;
00773     unsigned short savelines = ctscanlines;
00774     unsigned short savechars = ctscanchars;
00775     
00776 #ifdef WIN95VERSION
00777 checkthreadglobals ();
00778 #endif
00779 
00780     setbooleanvalue (false, val);
00781     
00782     flscriptrunning = true;
00783     
00784     if (flscriptalreadyrunning && !flevaluateglobalwith) /*4.1b12 dmb*/
00785         langpusherrorcallback (nil, -1L);
00786     else
00787         langpusherrorcallback (nil, 0L);
00788     
00789     flevaluateglobalwith = false; /*reset every time*/
00790     
00791     fl = langbuildtree (htext, true, &hcode);
00792     
00793     if (!fl)
00794         goto exit;
00795     
00796     if (flscriptalreadyrunning) { /*make nodes of this code tree point to current position*/
00797         
00798         ctscanlines = savelines;
00799         
00800         ctscanchars = savechars;
00801         
00802         langvisitcodetree (hcode, &renumberlinesvisit, nil);
00803         }
00804     
00805     else {
00806         
00807         fltablealreadypushed = currenthashtable != nil;
00808         
00809         if (!fltablealreadypushed)
00810             langpushscopechain ();
00811         
00812         if (langerrorenabled ()) /*compilation produced no error, be sure error window is empty*/
00813             langerrorclear ();
00814         
00815         langhookerrors ();
00816         }
00817     
00818     fl = evaluatelist ((**hcode).param1, val);
00819     
00820     if (!flscriptalreadyrunning) {
00821         
00822         langunhookerrors ();
00823         
00824         if (!fltablealreadypushed) {
00825         
00826             fltmpval = exemptfromtmpstack (val); /*must survive disposing of local scope chain*/
00827             
00828             langpopscopechain (); /*pop the runtime stack*/
00829             
00830             if (fltmpval) /*insert into the next-most-global tmpstack, if one exists*/
00831                 pushvalueontmpstack (val);
00832             }
00833         }
00834     
00835     langpostscript ();
00836     
00837     langdisposetree (hcode);
00838     
00839     exit:
00840     
00841     /*
00842     if (flscriptalreadyrunning)
00843     */
00844         langpoperrorcallback ();
00845     
00846     flscriptrunning = flscriptalreadyrunning;
00847     
00848     return (fl);
00849     } /*langrun*/
00850 
00851 
00852 boolean langrunhandle (Handle htext, bigstring bsresult) {
00853     
00854     /*
00855     compile and run the program source in bsprogram.  if the syntax checks, and
00856     the program runs without error, return the result as a string.
00857     
00858     we consume the text handle -- it is disposed by langrun
00859     */
00860     
00861     register boolean fl;
00862     register boolean flpushpop = !flscriptrunning;
00863     tyvaluerecord val;
00864     boolean flpushroot;
00865     
00866     setemptystring (bsresult);
00867     
00868     if (flpushpop)
00869         flpushpop = pushprocess (nil);
00870     
00871     fl = langrun (htext, &val);
00872     
00873     if (flpushpop)
00874         popprocess ();
00875     
00876     if (!fl)
00877         return (false);
00878     
00879     fl = false;
00880     
00881     flpushroot = currenthashtable == nil;
00882     
00883     if (flpushroot) {
00884         
00885         pushhashtable (roottable); /*need temp stack services*/
00886         
00887         pushvalueontmpstack (&val);
00888         }
00889     
00890     if (coercetostring (&val)) {
00891         
00892         texthandletostring (val.data.stringvalue, bsresult);
00893         
00894         fl = true; /*it worked, we'll return true*/
00895         }
00896     
00897     cleartmpstack ();
00898     
00899     if (flpushroot)
00900         pophashtable ();
00901     
00902     return (fl);
00903     } /*langrunhandle*/
00904 
00905 
00906 static boolean langtraperror (bigstring bsmsg, ptrstring perrorstring) {
00907     
00908     /*
00909     6/25/92 dmb: when an error occurs during a try block, we stash it in 
00910     the tryerror handle.  it is later placed in the stack frame of the 
00911     else statement, if it exists, by evaluatelist
00912     */
00913     
00914     assert (perrorstring != nil);
00915     
00916     copystring (bsmsg, perrorstring);
00917     
00918     return (true);
00919     } /*langtraperror*/
00920 
00921 
00922 boolean langruntraperror (Handle htext, tyvaluerecord *v, bigstring bserror) {
00923     
00924     /*
00925     for langhtml.c: closely an evaluate under a try statement
00926     */
00927     
00928     boolean fl;
00929     langerrormessagecallback savecallback;
00930     ptrvoid saverefcon;
00931     
00932     savecallback = langcallbacks.errormessagecallback;
00933     
00934     saverefcon = langcallbacks.errormessagerefcon;
00935     
00936     langcallbacks.errormessagecallback = (langerrormessagecallback) &langtraperror;
00937     
00938     langcallbacks.errormessagerefcon = bserror;
00939     
00940     fl = langrun (htext, v);
00941     
00942     langcallbacks.errormessagecallback = savecallback;
00943     
00944     langcallbacks.errormessagerefcon = saverefcon;
00945     
00946     fllangerror = false;
00947     
00948     return (fl);
00949     } /*langrunhandletraperror*/
00950 
00951 
00952 boolean langrunhandletraperror (Handle htext, bigstring bsresult, bigstring bserror) {
00953     
00954     /*
00955     for iowascript.c: more closely emulate the effect of doing 
00956     an OSA DoScript.
00957     */
00958 #ifdef MACVERSION   
00959     boolean fl;
00960     langerrormessagecallback savecallback;
00961     ptrvoid saverefcon;
00962     GrafPtr saveport;
00963     //Code change by Timothy Paustian Wednesday, June 14, 2000 4:32:31 PM
00964     //Changed to Opaque call for Carbon
00965     #if TARGET_API_MAC_CARBON == 1
00966     saveport = GetQDGlobalsThePort();
00967     #else
00968     saveport = quickdrawglobal (thePort);
00969     #endif
00970     
00971     savecallback = langcallbacks.errormessagecallback;
00972     
00973     saverefcon = langcallbacks.errormessagerefcon;
00974     
00975     langcallbacks.errormessagecallback = (langerrormessagecallback) &langtraperror;
00976     
00977     langcallbacks.errormessagerefcon = bserror;
00978     
00979     flevaluateglobalwith = true;
00980     
00981     fl = langrunhandle (htext, bsresult);
00982     
00983     langcallbacks.errormessagecallback = savecallback;
00984     
00985     langcallbacks.errormessagerefcon = saverefcon;
00986     
00987     fllangerror = false;
00988     
00989     //Code change by Timothy Paustian Wednesday, June 14, 2000 4:35:24 PM
00990     //Changed to Opaque call for Carbon
00991     {
00992     GrafPtr thePort;
00993     #if TARGET_API_MAC_CARBON == 1
00994     thePort = GetQDGlobalsThePort();
00995     #else
00996     thePort = quickdrawglobal (thePort);
00997     #endif
00998     
00999     if (thePort != saveport)
01000         SetPort (saveport);
01001     }
01002     return (fl);
01003 #endif
01004 
01005 #ifdef WIN95VERSION
01006     return (false);
01007 #endif
01008     } /*langrunhandletraperror*/
01009 
01010 
01011 boolean langrunstring (const bigstring bsprogram, bigstring bsresult) {
01012     
01013     /*
01014     compile and run the program source in bsprogram.  if the syntax checks, and
01015     the program runs without error, return the result as a string.
01016     */
01017     
01018     Handle htext;
01019     register boolean fl;
01020     
01021     if (!newtexthandle (bsprogram, &htext))
01022         return (false);
01023         
01024     fl = langrunhandle (htext, bsresult);
01025     
01026     return (fl);
01027     } /*langrunstring*/
01028 
01029 
01030 boolean langrunstringnoerror (const bigstring bsprogram, bigstring bsresult) {
01031     
01032     /*
01033     use this entrypoint when evaluating something that appears inside a document,
01034     e.g. a wp variable or a pict expression.  an error message would be very hard
01035     to relate to something in the document, we think.
01036     
01037     3/5/97 dmb: instead of disabling langerror, try errors with a noop. this 
01038     allows try/else blocks to execute normally
01039     */
01040     
01041     langerrormessagecallback saveerrormessage;
01042     langvoidcallback saveerrorclear;
01043     boolean fl;
01044     
01045     // 3/5/97 dmb: disablelangerror ();
01046     
01047         saveerrormessage = langcallbacks.errormessagecallback;
01048         
01049         saveerrorclear = langcallbacks.clearerrorcallback;
01050         
01051         langcallbacks.errormessagecallback = (langerrormessagecallback) &truenoop;
01052         
01053         langcallbacks.clearerrorcallback = &truenoop;
01054         
01055         ++fldisableyield;
01056         
01057     fl = langrunstring (bsprogram, bsresult);
01058         
01059     // 3/5/97 dmb: enablelangerror ();
01060     
01061         --fldisableyield;
01062         
01063         langcallbacks.errormessagecallback = saveerrormessage;
01064         
01065         langcallbacks.clearerrorcallback = saveerrorclear;
01066         
01067         fllangerror = false;
01068     
01069     return (fl);
01070     } /*langrunstringnoerror*/
01071 
01072 
01073 boolean langreduceformula (bigstring bs) {
01074     
01075     /*
01076     returns true if bs changed -- it was a formula and was correctly reduced.
01077     
01078     6/1/93 dmb: agentsdisable is defunct.
01079     */
01080     
01081     bigstring bscopy;
01082     register boolean fl;
01083     bigstring bsresult;
01084     
01085     if (isemptystring (bs)) /*not a formula*/
01086         return (false);
01087     
01088     if (bs [1] != '=') /*not a formula*/
01089         return (false);
01090     
01091     copystring (bs, bscopy); /*we work with a copy*/
01092     
01093     deletestring (bscopy, 1, 1); /*pop off the = sign*/
01094     
01095     if (isemptystring (bscopy)) /*nothing but an = sign, not a formula*/
01096         return (false);
01097     
01098     //agentsdisable (true); /*temporarily disable agents*/
01099     
01100     fl = langrunstringnoerror (bscopy, bsresult);
01101     
01102     //agentsdisable (false); /*restore*/
01103     
01104     if (!fl) /*syntax or runtime error*/
01105         return (false);
01106     
01107     copystring (bsresult, bs); /*result replaces the input string*/
01108     
01109     return (true);
01110     } /*langreduceformula*/
01111 
01112 
01113 boolean langruncode (hdltreenode htree, hdlhashtable hcontext, tyvaluerecord *vreturned) {
01114     
01115     /*
01116     1/8/91 dmb: since the current hash table is the base of the 
01117     locals chain during execution, it must be protected from disposal 
01118     with the flchained flag.
01119     
01120     5/21/91 dmb: now return result value to caller
01121     
01122     5/20/93 dmb: preserve flscriptrunning; nesting can occur when sending an 
01123     event to self that is handled by a trap script.
01124     
01125     2.1b4 dmb: if hcontext is already chained, just push it instead of 
01126     overriding its current chain. (our own scope chain becomes superflous.)
01127     */
01128     
01129     register boolean flscriptwasrunning = flscriptrunning;
01130     register hdlhashtable ht = hcontext;
01131     register boolean fl;
01132     register boolean flchained = false;
01133     
01134     if (htree == nil) /*defensive driving*/
01135         return (false);
01136     
01137     langprescript (); /*initialize lang globals, about to run a script*/
01138     
01139     langpushscopechain ();
01140     
01141     if (ht != nil) {
01142         
01143         flchained = (**ht).flchained;
01144         
01145         if (flchained)
01146             pushhashtable (ht);
01147         else
01148             chainhashtable (ht); /*establishes outer local context*/
01149         }
01150     
01151     langhookerrors ();
01152     
01153     flscriptrunning = true; /*this routine is not nestable*/
01154     
01155     fl = evaluatelist ((**htree).param1, vreturned);
01156     
01157     flscriptrunning = flscriptwasrunning;
01158     
01159     exemptfromtmpstack (vreturned);
01160     
01161     langunhookerrors ();
01162     
01163     if (ht != nil) {
01164         
01165         if (flchained)
01166             pophashtable ();
01167         else
01168             unchainhashtable ();
01169         }
01170     
01171     langpopscopechain ();
01172     
01173     langpostscript ();
01174     
01175     return (fl);
01176     } /*langruncode*/
01177 
01178 
01179 boolean langopruncallbackscripts (short idscript) {
01180 
01181     /*
01182     7.0d5 AR: Generalized from langopstruct2click and langopreturnkey.
01183 
01184     7.0b10 PBS: set and restore outlinedata, in case callback destroys it.
01185     */
01186 
01187     boolean fl, flresult = false;
01188     bigstring bsscript, bsresult;
01189 
01190     if (getsystemtablescript (idscript, bsscript)) {
01191 
01192         grabthreadglobals ();
01193 
01194         oppushoutline (outlinedata); /*7.0b10 PBS: make sure the current outline gets saved.*/
01195 
01196         fl = langrunstringnoerror (bsscript, bsresult);
01197 
01198         oppopoutline (); /*7.0b10 PBS: restore the current outline*/
01199 
01200         releasethreadglobals ();
01201 
01202         if (fl)
01203             stringisboolean (bsresult, &flresult);
01204         }
01205 
01206     return (flresult);
01207     } /*langopruncallbackscripts */
01208 
01209 
01210 boolean langzoomobject (const bigstring bsobject) {
01211     
01212     /*
01213     locate the indicated database object, and open an editing window to 
01214     display it.
01215     
01216     9/11/91 dmb: call control2click () when control key is down
01217     
01218     7/8/92 dmb: call option2click () when the option key is down
01219     */
01220     
01221     bigstring bsscript, bsresult;
01222     short idscript;
01223     boolean fl;
01224     
01225     if (!keyboardstatus.flcmdkey && !keyboardstatus.flcontrolkey && !keyboardstatus.floptionkey)
01226         return (false);
01227     
01228     if (keyboardstatus.flcontrolkey)
01229         idscript = idcontrol2clickscript;
01230     
01231     else if (keyboardstatus.flcmdkey)
01232         idscript = idcommand2clickscript;
01233     
01234     else
01235         idscript = idoption2clickscript;
01236     
01237     fl = getsystemtablescript (idscript, bsscript);
01238     
01239     if (fl) {
01240         
01241         parsedialogstring (bsscript, (ptrstring) bsobject, nil, nil, nil, bsscript);
01242         
01243         grabthreadglobals ();
01244 
01245         fl = langrunstringnoerror (bsscript, bsresult);
01246 
01247         releasethreadglobals ();
01248         }
01249     
01250     if (!fl) /*couldn't find it*/
01251         sysbeep ();
01252     
01253     return (fl);
01254     } /*langzoomobject*/
01255 
01256 
01257 static boolean langbuildnamedparamlist (tyvaluerecord * listval, hdltreenode *hparams) {
01258     
01259     /*
01260     take all of the parameters in the incoming verb hverb and build a code 
01261     tree for the corresponding lang paramter list
01262     
01263     7.0b41 PBS: new routine, respects the named items in the record, matches to named
01264     params in the script.
01265     */
01266     
01267     register short i;
01268     long ctparams;
01269     hdltreenode hlist = nil;
01270     tyvaluerecord val, vkey;
01271     hdltreenode hparam, hname;
01272     boolean flpushedroot;
01273     register boolean fl = false;
01274     
01275     if (currenthashtable == nil)
01276         flpushedroot = pushhashtable (roottable);
01277     else
01278         flpushedroot = false;
01279     
01280     if (!langgetlistsize (listval, &ctparams))
01281         goto exit;
01282     
01283     for (i = 1; i <= ctparams; i++) {
01284 
01285         bigstring bskey;
01286 
01287         if (!langgetlistitem (listval, i, bskey, &val))
01288             goto exit;
01289 
01290         exemptfromtmpstack (&val); /*its data is about to belong to code tree*/
01291         
01292         if (!newconstnode (val, &hparam))
01293             goto exit;
01294 
01295         if (!setstringvalue (bskey, &vkey) || !newidnode (vkey, &hname)) {
01296 
01297             langdisposetree (hparam);
01298 
01299             goto exit;
01300             }
01301 
01302         exemptfromtmpstack (&vkey);
01303 
01304         if (!pushbinaryoperation (fieldop, hname, hparam, &hparam))
01305             goto exit;
01306         
01307         if (hlist == nil)
01308             hlist = hparam;
01309         else
01310             pushlastlink (hparam, hlist);
01311         } /*for*/
01312     
01313     fl = true;
01314     
01315     exit:
01316     
01317     if (flpushedroot)
01318         pophashtable ();
01319     
01320     if (fl)
01321         *hparams = hlist; /*nil if there weren't any params*/
01322     else
01323         langdisposetree (hlist); /*checks for nil*/
01324     
01325     return (fl);
01326     } /*langbuildnamedparamlist*/
01327 
01328 
01329 boolean langbuildparamlist (tyvaluerecord * listval, hdltreenode *hparams) {
01330     
01331     /*
01332     take all of the parameters in the incoming verb hverb and build a code 
01333     tree for the corresponding lang paramter list
01334     
01335     2.1b5 dmb: special case for subroutine events
01336     
01337     2.1b12 dmb: push the root table to make sure address values will work
01338     
01339     3.0.1b2 dmb: for subroutine events, the direct parameter is optional
01340     
01341     5.0d14 dmb: take hcode parameter, so we can see of trap script takes 
01342     parameters by name. the first (direct) parameter can have any name. if
01343     all others are 4 characters long, and appear in the event, we use names.
01344     */
01345     
01346     register short i;
01347     long ctparams;
01348     hdltreenode hlist = nil;
01349     tyvaluerecord val;
01350     hdltreenode hparam;
01351     boolean flpushedroot;
01352     register boolean fl = false;
01353 
01354     if ((*listval).valuetype == recordvaluetype) /*7.0b41 PBS: build named param list if a record*/
01355         return (langbuildnamedparamlist (listval, hparams));
01356     
01357     if (currenthashtable == nil)
01358         flpushedroot = pushhashtable (roottable);
01359     else
01360         flpushedroot = false;
01361     
01362     if (!langgetlistsize (listval, &ctparams))
01363         goto exit;
01364     
01365     for (i = 1; i <= ctparams; i++) {
01366 
01367         if (!langgetlistitem (listval, i, NULL, &val))
01368             goto exit;
01369 
01370         exemptfromtmpstack (&val); /*its data is about to belong to code tree*/
01371         
01372         if (!newconstnode (val, &hparam))
01373             goto exit;
01374         
01375         if (hlist == nil)
01376             hlist = hparam;
01377         else
01378             pushlastlink (hparam, hlist);
01379         } /*for*/
01380     
01381     fl = true;
01382     
01383     exit:
01384     
01385     if (flpushedroot)
01386         pophashtable ();
01387     
01388     if (fl)
01389         *hparams = hlist; /*nil if there weren't any params*/
01390     else
01391         langdisposetree (hlist); /*checks for nil*/
01392     
01393     return (fl);
01394     } /*langbuildparamlist*/
01395 
01396 
01397 boolean langrunscriptcode (hdlhashtable htable, bigstring bsverb, hdltreenode hcode, tyvaluerecord *vparams, hdlhashtable hcontext, tyvaluerecord *vreturned) {
01398     
01399     /*
01400     02/04/02 dmb: the guts of langrunscript
01401 
01402     2004-11-03 aradke: Accept nil for vparams, meaning the function
01403     doesn't take any parameters, so we simply bypass langbuildparamlist.
01404     */
01405     
01406     boolean fl = false;
01407     boolean flchained;
01408     tyvaluerecord val;
01409     hdltreenode hfunctioncall;
01410     hdltreenode hparamlist = nil;
01411     boolean fltmpval;
01412     
01413     if (!setaddressvalue (htable, bsverb, &val))
01414         goto exit;
01415     
01416     if (!pushfunctionreference (val, &hfunctioncall))
01417         goto exit;
01418     
01419 /*  if (hcontext != nil)
01420         pushhashtable (hcontext);
01421 */
01422     flchained = (hcontext != nil) && (**hcontext).flchained;
01423 
01424     if (vparams != nil) {
01425 
01426         if (hcontext != nil) {
01427                         
01428             if (flchained)
01429                 pushhashtable (hcontext);
01430             else
01431                 chainhashtable (hcontext); /*establishes outer local context*/
01432             }
01433         
01434         fl = langbuildparamlist (vparams, &hparamlist);
01435         
01436         if (hcontext != nil) {
01437             
01438             if (flchained)
01439                 pophashtable ();
01440             else
01441                 unchainhashtable ();
01442             }
01443         
01444         if (!fl) {
01445             
01446             langdisposetree (hfunctioncall);
01447             
01448             goto exit;
01449             }
01450         }
01451     
01452     if (!pushfunctioncall (hfunctioncall, hparamlist, &hcode)) /*consumes input parameters*/
01453         goto exit;
01454         
01455     if (hcontext != nil) {
01456 
01457         if (flchained)
01458             pushhashtable (hcontext);
01459         else
01460             chainhashtable (hcontext); /*establishes outer local context*/
01461         }
01462     
01463     fl = evaluatelist (hcode, vreturned);
01464     
01465     fltmpval = exemptfromtmpstack (vreturned); /*must survive disposing of local scope chain*/
01466     
01467     if (hcontext != nil) {
01468 
01469         if (flchained)
01470             pophashtable ();
01471         else
01472             unchainhashtable ();
01473         }
01474     
01475     if (fltmpval) /*insert into the next-most-global tmpstack, if one exists*/
01476         pushvalueontmpstack (vreturned);
01477 
01478     langdisposetree (hcode);
01479 
01480     exit:
01481     
01482     return (fl);
01483     } /*langrunscriptcode*/
01484 
01485 
01486 boolean langrunscript (bigstring bsscriptname, tyvaluerecord *vparams, hdlhashtable hcontext, tyvaluerecord *vreturned) {
01487     
01488     /*
01489     5.0.2b6 rab/dmb: new verb
01490     
01491     5.0.2b7 dmb: preserve errormessagecallback through the call
01492     
01493     6.0a9 dmb: was langipcrunscript, moved here and don't create new process
01494 
01495     6.0a14 dmb: fixed potential memory leak in error case.
01496 
01497     7.0b41 pbs: if passed a record instead of a list, call the script with named parameters.
01498 
01499     8.0.4 dmb: handle running code values
01500     */
01501     
01502     bigstring bsverb;
01503     boolean fl = false;
01504     hdltreenode hcode;
01505     hdlhashtable htable;
01506     tyvaluerecord vhandler;
01507     hdlhashnode handlernode;
01508     
01509     pushhashtable (roottable);
01510     
01511     fl = langexpandtodotparams (bsscriptname, &htable, bsverb);
01512 
01513     if (fl) {
01514     
01515         if (htable == nil)
01516             langsearchpathlookup (bsverb, &htable);
01517         }
01518     
01519     pophashtable();
01520     
01521     if (!fl)
01522         return (false);
01523     
01524     if (!hashtablelookupnode (htable, bsverb, &handlernode)) {
01525         
01526         langparamerror (unknownfunctionerror, bsverb);
01527         
01528         return (false);
01529         }
01530     
01531     vhandler = (**handlernode).val;
01532     
01533     /*build a code tree and call the handler, with our error hook in place*/
01534     
01535     hcode = nil;
01536     
01537     if (vhandler.valuetype == codevaluetype) {
01538 
01539         hcode = vhandler.data.codevalue;
01540     }
01541     else if ((**htable).valueroutine == nil) { /*not a kernel table*/
01542         
01543         if (!langexternalvaltocode (vhandler, &hcode)) {
01544 
01545             langparamerror (notfunctionerror, bsverb);
01546 
01547             return (false);
01548             }
01549         
01550         if (hcode == nil) { /*needs compilation*/
01551             
01552             if (!langcompilescript (handlernode, &hcode))
01553                 return (false);
01554             }
01555         }
01556     
01557     return (langrunscriptcode (htable, bsverb, hcode, vparams, hcontext, vreturned));
01558     } /*langrunscript*/
01559 
01560 /*
01561     boolean flchained;
01562     tyvaluerecord val;
01563     hdltreenode hfunctioncall;
01564     hdltreenode hparamlist;
01565     boolean fltmpval;
01566 
01567     if (!setaddressvalue (htable, bsverb, &val))
01568         goto exit;
01569     
01570     if (!pushfunctionreference (val, &hfunctioncall))
01571         goto exit;
01572     
01573     if (hcontext != nil) {
01574         
01575         flchained = (**hcontext).flchained;
01576         
01577         if (flchained)
01578             pushhashtable (hcontext);
01579         else
01580             chainhashtable (hcontext); //establishes outer local context
01581         }
01582     
01583     fl = langbuildparamlist (vparams, &hparamlist);
01584     
01585     if (hcontext != nil) {
01586         
01587         if (flchained)
01588             pophashtable ();
01589         else
01590             unchainhashtable ();
01591         }
01592     
01593     if (!fl) {
01594         
01595         langdisposetree (hfunctioncall);
01596         
01597         goto exit;
01598         }
01599     
01600     if (!pushfunctioncall (hfunctioncall, hparamlist, &hcode)) //consumes input parameters
01601         goto exit;
01602         
01603     if (hcontext != nil) {
01604 
01605         if (flchained)
01606             pushhashtable (hcontext);
01607         else
01608             chainhashtable (hcontext); //establishes outer local context
01609         }
01610     
01611     fl = evaluatelist (hcode, vreturned);
01612     
01613     fltmpval = exemptfromtmpstack (vreturned); //must survive disposing of local scope chain
01614     
01615     if (hcontext != nil) {
01616 
01617         if (flchained)
01618             pophashtable ();
01619         else
01620             unchainhashtable ();
01621         }
01622     
01623     if (fltmpval) //insert into the next-most-global tmpstack, if one exists
01624         pushvalueontmpstack (vreturned);
01625 
01626     langdisposetree (hcode);
01627 
01628     exit:
01629     
01630     return (fl);
01631     } /%langrunscript%/
01632 */
01633 

Generated on Wed May 31 18:19:50 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6