scripts.c

Go to the documentation of this file.
00001 
00002 /*  $Id: scripts.c 1254 2006-04-12 20:27:14Z 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 "cursor.h"
00033 #include "dialogs.h"
00034 #include "file.h"
00035 #include "font.h"
00036 #include "kb.h"
00037 #include "mouse.h"
00038 #include "ops.h"
00039 #include "popup.h"
00040 #include "quickdraw.h"
00041 #include "scrap.h"
00042 #include "search.h"
00043 #include "strings.h"
00044 #include "frontierwindows.h"
00045 #include "db.h"
00046 #include "shell.h"
00047 #include "shell.rsrc.h"
00048 #include "shellbuttons.h"
00049 #include "shellhooks.h"
00050 #include "shellprivate.h"
00051 #include "lang.h"
00052 #include "langinternal.h"
00053 #include "langexternal.h"
00054 #include "op.h"
00055 #include "opinternal.h"
00056 #include "opverbs.h"
00057 #include "menueditor.h"
00058 #include "meprograms.h"
00059 #include "process.h"
00060 #include "processinternal.h"
00061 #include "tablestructure.h"
00062 #include "tableinternal.h"
00063 #include "tableverbs.h"
00064 #include "scripts.h"
00065 #ifdef flcomponent
00066 #include "osacomponent.h"
00067 #endif
00068 #include "error.h"
00069 
00070 static boolean scriptdebuggereventloop (void);
00071 
00072 #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
00073     #include "aeutils.h"
00074 #endif
00075 
00076 
00077 enum {
00078     runbutton = 1,
00079     
00080     debugbutton,
00081     
00082     recordbutton,
00083 
00084     stepbutton,
00085     
00086     inbutton,
00087     
00088     outbutton,
00089     
00090     followbutton,
00091     
00092     gobutton,
00093     
00094     stopbutton,
00095     
00096     killbutton,
00097     
00098     localsbutton,
00099     
00100     installbutton
00101     };
00102 
00103 
00104 
00105 //#define maxchainedlocals 80 /*limit for local table nesting in debugged process*/
00106 
00107 #define maxchainedlocals 200 /*6.1d19 AR*/
00108 
00109 //#define maxnestedsources 40 /*local handlers count as nested sources*/
00110 
00111 #define maxnestedsources 200 /*6.1d19 AR*/
00112 
00113 
00114 typedef struct tysourcerecord {
00115     
00116     WindowPtr pwindow; /*window containing running script; nil if closed or unknown*/
00117     
00118     hdlhashnode hnode; /*hash node containing script variable*/
00119     
00120     hdloutlinerecord houtline; /*script outline itself*/
00121     } tysourcerecord;
00122 
00123 
00124 typedef struct tydebuggerrecord {
00125     
00126     hdlprocessrecord scriptprocess;
00127     
00128     tysourcerecord scriptsourcestack [maxnestedsources]; /*for stepping other scripts*/
00129     
00130     short topscriptsource; /*source stack pointer*/
00131     
00132     short sourcesteplevel; /*level in source stack at which we suspend after step/in/out*/
00133     
00134     tydirection stepdir; /*left,right,down & flatdown for out,in,step & trace*/
00135     
00136     long lastlnum; /*the last line number stepped onto*/
00137     
00138     hdlhashtable hlocaltable; /*the most local table in our process*/
00139     
00140     hdlhashnode localtablestack [maxchainedlocals]; /*nodes of tables in the runtimestack*/
00141     
00142     //Handle localtableformatsstack [maxchainedlocals]; /*nodes of tables in the runtimestack*/
00143     
00144     short toplocaltable; /*table stack pointer*/
00145     
00146     //short deferredbuttonnum; /*see scriptdeferbutton*/
00147     
00148     //WindowPtr deferredwindow; /*ditto*/
00149     
00150     hdlheadrecord hbarcursor; /*the headline we've most recently shown*/
00151     
00152 #ifdef flcomponent
00153     
00154     ComponentInstance servercomp; /*component that we have open for this script*/
00155     
00156     OSType servertype; /*the component's type*/
00157     
00158     OSAID idscript; /*while recording, this is the id of the script*/
00159     
00160 #endif
00161     
00162     short lastindent;
00163     
00164     boolean flscriptsuspended: 1; /*user is debugging a script*/
00165     
00166     boolean flstepping: 1; /*single-stepping thru scripts*/
00167     
00168     boolean flfollowing: 1; /*does the bar cursor follow the interpreter?*/
00169     
00170     boolean flscriptkilled: 1; /*true if the script has been killed*/
00171     
00172     boolean flscriptrunning: 1; /*true when the script is running*/
00173     
00174     boolean flwindowclosed: 1; /*false if script's window is open*/
00175     
00176     boolean fllangerror: 1; /*are we stopped with an error?*/
00177     
00178     boolean flrecording: 1; /*are we recording into this script?*/
00179     
00180     boolean flcontextlocked: 1; /*is out context being operated on externally?*/
00181     
00182     long scriptrefcon; /*copied from outline refcon*/
00183     } tydebuggerrecord, *ptrdebuggerrecord, **hdldebuggerrecord;
00184 
00185 
00186 static hdldebuggerrecord debuggerdata = nil;
00187 
00188 //static boolean flenablemenus = false;
00189 
00190 //static short scriptbackgrounddisable = 0; /*it's possible to temporarily disable backgrounding*/
00191 
00192 //static long scriptbackgroundtime = 0;
00193 
00194 static hdloutlinerecord scriptdataholder = nil;
00195 
00196 
00197 static boolean scriptsetglobals (void) {
00198     
00199     /*
00200     5.1.5b7 dmb: added this layer so we can trap the setting of outlinedata
00201     */
00202     
00203     opsetoutline (scriptdataholder);
00204     
00205     return (opeditsetglobals ());
00206     } /*scriptsetglobals*/
00207 
00208 
00209 /*
00210 disablescriptbackground (void) {
00211     
00212     ++scriptbackgrounddisable;
00213     } /%disablescriptbackground%/
00214 
00215 
00216 enablescriptbackground (void) {
00217     
00218     --scriptbackgrounddisable;
00219     } /%enablescriptbackground%/
00220 */
00221 
00222 
00223 static boolean scriptbackgroundenabled (void) {
00224     
00225     /*
00226     return (scriptbackgrounddisable == 0);
00227     */
00228     
00229     return (shellwindow == nil); /*don't background while window globals are pushed*/
00230     } /*scriptbackgroundenabled*/
00231 
00232 
00233 /*static void scriptresetbackgroundtime (void) {
00234     
00235     scriptbackgroundtime = gettickcount ();
00236     } /%scriptresetbackgroundtime%/
00237 */
00238 
00239 static boolean isheadrecordhandle (long refcon) {
00240     
00241     /*
00242     1/14/91 dmb: there are a few places in this file where we need to 
00243     distinguish between a hdlheadrecord and a hdlhashnode stored as a 
00244     refcon.  ugly as it may be, testing the handle size seems fairly 
00245     foolproof.  if we wanted to, we could look into the record itself 
00246     for other evidence, but it doesn't seem neccessary
00247     
00248     6/4/92 dmb: now that we place the headstring and hashkey strings at 
00249     the end of their respective records, the old check no longer works.
00250     now we make sure that the size of the record is inconsistent with assuming 
00251     that it is a hashnode, which is reasonable safe so long as the hashkey field 
00252     lines up with the beginning of the headlevel field, which we check for.  to 
00253     add extra assurance, we do two checks; first for a hashnode (which is shorter), 
00254     second for a headrecord.  note that hdlexternalvariables are also passed to 
00255     this routine
00256     */
00257     
00258     register Handle h = (Handle) refcon;
00259     register long size = gethandlesize (h);
00260     
00261     if (odd (refcon) || refcon == 0)
00262         return (false);
00263     
00264 //  assert ((long) &(**(hdlheadrecord) h).headlevel == (long) &(**(hdlhashnode) h).hashkey); /*extra assurance*/
00265     
00266     if ((unsigned) size == sizeof (tyhashnode) + stringsize ((**(hdlhashnode) h).hashkey))
00267         return (false);
00268     
00269     if ((unsigned) size == sizeof (tyheadrecord))
00270         return (true);
00271     
00272     return (false);
00273     } /*isheadrecordhandle*/
00274 
00275 
00276 boolean scriptbuildtree (Handle htext, long signature, hdltreenode *hcode) {
00277     
00278     /*
00279     2.1b11 dmb: don't compile osa scripts execute-only, because some 
00280     scripting systems (e.g. AppleScript) needs to be able to get the 
00281     source in order to report runtime error offsets
00282     */
00283     
00284     hdltreenode hstub;
00285     tyvaluerecord codeval;
00286     boolean fl;
00287     
00288     if (signature == typeLAND)
00289         return (langbuildtree (htext, true, hcode));
00290     
00291 #ifdef flcomponent
00292     fl = osagetcode (htext, signature, false, &codeval);
00293 #else
00294     fl = false;
00295 #endif
00296     disposehandle (htext);
00297     
00298     if (!fl)
00299         return (false);
00300     
00301     exemptfromtmpstack (&codeval);
00302     
00303     if (!newconstnode (codeval, &hstub))
00304         return (false);
00305     
00306     (**hstub).nodetype = osascriptop;
00307     
00308     /*
00309     *hcode = hstub;
00310     
00311     return (true);
00312     */
00313     
00314     return (pushbinaryoperation (moduleop, hstub, nil, hcode));
00315     } /*scriptbuildtree*/
00316 
00317 
00318 static boolean scriptgetcode (hdlhashnode hnode, hdltreenode *hcode) {
00319     
00320     /*
00321     give me a node, I'll get you the code.
00322     
00323     5/19/92 dmb: stashes a link to the source node in the nodeval at the top of 
00324     the code tree.  see comment in opverbdisposecode.
00325     */
00326     
00327     tyvaluerecord val;
00328     register hdlexternalvariable hv;
00329     Handle htext;
00330     long signature;
00331     register boolean fl;
00332     
00333     *hcode = nil; /*default return*/
00334     
00335     val = (**hnode).val;
00336     
00337     if (val.valuetype != externalvaluetype) /*not a script*/
00338         return (false);
00339     
00340     hv = (hdlexternalvariable) val.data.externalvalue;
00341     
00342     if ((**hv).id != idscriptprocessor) /*not a script*/
00343         return (false);
00344     
00345     if (!opverbgetlangtext (hv, false, &htext, &signature))
00346         return (false);
00347     
00348     fl = scriptbuildtree (htext, signature, hcode);
00349     
00350     
00351     /*7/9/90 DW: langbuildtree disposes of htext, not a memory leak*/
00352     
00353     if (fl) {
00354         
00355         assert ((***hcode).nodeval.data.longvalue == 0);
00356         
00357         (***hcode).nodeval.data.longvalue = (long) hnode; /*5/19/92 dmb: point back at node*/
00358         }
00359     
00360     return (fl);
00361     } /*scriptgetcode*/
00362 
00363 
00364 static boolean scriptzoomscript (hdlhashnode hnode, WindowPtr *w) {
00365     
00366     /*
00367     hnode is a hash table node containing a script variable.  zoom its 
00368     window and return the windowptr in w
00369     
00370     7/4/91 dmb: langexternalzoom now take table parameter.  we don't know 
00371     what table the node is in, so we pass nil.
00372     */
00373     
00374     register hdlhashnode h = hnode;
00375     bigstring bs;
00376     hdlwindowinfo hinfo;
00377     
00378     gethashkey (h, bs);
00379     
00380     if (!langexternalzoom ((**h).val, nil, bs)) 
00381         return (false);
00382     
00383     if (!langexternalwindowopen ((**h).val, &hinfo))
00384         return (false);
00385     
00386     *w = (**hinfo).macwindow;
00387     
00388     return (true);
00389     } /*scriptzoomscript*/
00390 
00391 
00392 static boolean systemscripterrorroutine (long scripterrorrefcon, long lnum, short charnum, hdlhashtable *htable, bigstring bsname) {
00393     
00394     /*
00395     display an error for a system script -- a handler, agent or startup script.
00396     
00397     called back from langerror.c.  we receive a handle to the table node that
00398     made the error, and we zoom out a window that displays the attached script,
00399     in text mode, with the character cursor pointing to line number lnum at
00400     offset charnum -- the exact spot where the error occured, we hope...
00401     
00402     2/4/91 dmb: allow hdlheadrecords to end up here too
00403     
00404     4.0b8 dmb: if caller provides non-null htable, don't show error, just return 
00405     its location. bsname better be non-null too!
00406 
00407     4/7/97 dmb: handle standalone scripts
00408 
00409     5.0.2b21 dmb: for Win, nil check must cover dereferenced handle too
00410     */
00411     
00412     register hdlhashnode h = (hdlhashnode) scripterrorrefcon;
00413     hdlwindowinfo hinfo;
00414     hdlexternalvariable hv;
00415     WindowPtr w;
00416     register boolean fl;
00417     
00418     if (h == nil || *h == nil) /*defensive driving*/
00419         return (false);
00420     
00421     if (isheadrecordhandle ((long) h))
00422         return (mescripterrorroutine ((long) h, lnum, charnum, htable, bsname));
00423     
00424     if (shellfinddatawindow ((Handle) h, &hinfo)) { // 4/7/97 dmb: standalone
00425 
00426         if (htable != nil) { /*caller wants table, name*/
00427             
00428             if (shellgetexternaldata (hinfo, &hv))
00429                 return (langexternalfindvariable (hv, htable, bsname));
00430             
00431             return (false);
00432             }
00433         
00434         shellbringtofront (hinfo);
00435         
00436         w = (**hinfo).macwindow;
00437 
00438         goto exit;
00439         }
00440     
00441     if (htable != nil) { /*caller wants table, name*/
00442         
00443         hv = (hdlexternalvariable) (**h).val.data.externalvalue;
00444         
00445         return (langexternalfindvariable (hv, htable, bsname));
00446         }
00447     
00448     if (!scriptzoomscript (h, &w))
00449         return (false);
00450     
00451 exit:
00452 
00453     shellpushglobals (w);
00454     
00455     fl = opshowerror (lnum, charnum);
00456     
00457     shellpopglobals ();
00458     
00459     return (fl);
00460     } /*systemscripterrorroutine*/
00461 
00462 
00463 static boolean scriptcompiler (hdlhashnode hnode, hdltreenode *hcode) {
00464     
00465     /*
00466     7/1/91 dmb: don't return true on failure to continue visit; we now have 
00467     a wrapper for visiting.  also, langternalvaltocode returns false only 
00468     when val isn't a script, and may return true with holdcode nil if there's 
00469     no existing code.
00470     
00471     7/3/91 dmb: let processreplacecode manage old code, in case it's running now.
00472     
00473     5/14/93 dmb: added hcode parameter; caller often wants to grab it.
00474     */
00475     
00476     hdltreenode hnewcode;
00477     hdltreenode holdcode;
00478     register hdlexternalvariable hv;
00479     register boolean fl;
00480     
00481     if (!langexternalvaltocode ((**hnode).val, &holdcode))
00482         return (false);
00483     
00484     langpusherrorcallback (&systemscripterrorroutine, (long) hnode);
00485     
00486     fl = scriptgetcode (hnode, &hnewcode);
00487     
00488     langpoperrorcallback ();
00489     
00490     if (!fl)
00491         return (false);
00492     
00493     hv = (hdlexternalvariable) (**hnode).val.data.externalvalue;
00494     
00495     opverblinkcode (hv, (Handle) hnewcode); /*link code into the outline variable record*/
00496     
00497     /*
00498     if (hashnodeintable (hnode, agentstable)) { /%special stuff for agents%/
00499         
00500         if (!processreplacecode (holdcode, hnewcode)) { /%no replacement, add new process%/
00501             
00502             langdisposetree (holdcode);
00503             
00504             addnewprocess (hnewcode, false, &systemscripterrorroutine, (long) hnode);
00505             }
00506         }
00507     else
00508         langdisposetree (holdcode);
00509     */
00510     
00511     if (processreplacecode (holdcode, hnewcode))
00512         return (true);
00513     
00514     processcodedisposed ((long) hnode);
00515     
00516     langdisposetree (holdcode);
00517     
00518     if (hashnodeintable (hnode, agentstable)) /*special stuff for agents*/
00519         addnewprocess (hnewcode, false, &systemscripterrorroutine, (long) hnode);
00520     
00521     *hcode = hnewcode;
00522     
00523     return (true);
00524     } /*scriptcompiler*/
00525 
00526 
00527 static boolean installscriptvisit (hdlhashnode hnode, ptrvoid refcon) {
00528 #pragma unused (refcon)
00529 
00530     hdltreenode hcode;
00531     
00532     scriptcompiler (hnode, &hcode);
00533     
00534     return (true); /*continue visit unconditionally*/
00535     } /*installscriptvisit*/
00536 
00537 
00538 static boolean scriptinstallscripts (hdlhashtable htable) {
00539     
00540     if (htable == nil) /*defensive driving*/
00541         return (false);
00542     
00543     return (hashtablevisit (htable, &installscriptvisit, nil));
00544     } /*scriptinstallscripts*/
00545 
00546 
00547 boolean scriptinstallagent (hdlhashnode hnode) {
00548     
00549     hdltreenode hcode;
00550     
00551     return (scriptcompiler (hnode, &hcode));
00552     } /*scriptinstallagent*/
00553 
00554 
00555 boolean scriptremoveagent (hdlhashnode hnode) {
00556     
00557     hdltreenode hcode;
00558     
00559     if (!langexternalvaltocode ((**hnode).val, &hcode))
00560         return (false);
00561     
00562     if (hcode != nil)
00563         processdisposecode (hcode);
00564     
00565     return (true);
00566     } /*scriptremoveagent*/
00567 
00568 
00569 static boolean scriptloadagents (void) {
00570     
00571     return (scriptinstallscripts (agentstable));
00572     } /*scriptloadagents*/
00573     
00574 
00575 static long ctspecialprocessesrunning = 0;
00576 
00577 
00578 static boolean specialscriptkilled (void) {
00579     
00580     --ctspecialprocessesrunning;
00581     
00582     return (true);
00583     } /*specialscriptkilled*/
00584 
00585 
00586 static boolean newprocessvisit (hdlhashnode hnode, ptrvoid refcon) {
00587 #pragma unused (refcon)
00588 
00589     hdltreenode hcode;
00590     hdlprocessrecord hprocess;
00591     boolean fl;
00592     
00593     langpusherrorcallback (&systemscripterrorroutine, (long) hnode);
00594     
00595     fl = scriptgetcode (hnode, &hcode);
00596     
00597     langpoperrorcallback ();
00598     
00599     if (!fl)
00600         return (true);
00601     
00602     #ifdef version5orgreater
00603         if (!newprocess (hcode, true, &systemscripterrorroutine, (long) hnode, &hprocess))
00604             return (false);
00605         
00606         (**hprocess).processkilledroutine = &specialscriptkilled;
00607         
00608         addprocess (hprocess);
00609         
00610         ++ctspecialprocessesrunning;
00611         
00612         return (true);
00613     #else
00614         return (addnewprocess (hcode, true, &systemscripterrorroutine, (long) hnode));
00615     #endif
00616     } /*newprocessvisit*/
00617 
00618 
00619 static boolean scriptrunspecialscripts (bigstring bsspecialtable) {
00620     
00621     /*
00622     run all the scripts in the startup table.
00623     */
00624     
00625     hdlhashtable htable;
00626     
00627     ctspecialprocessesrunning = 0;
00628     
00629     if (!findnamedtable (systemtable, bsspecialtable, &htable))
00630         return (true);
00631     
00632     return (hashtablevisit (htable, &newprocessvisit, nil));
00633     } /*scriptrunspecialscripts*/
00634 
00635 
00636 boolean scriptrunstartupscripts (void) {
00637     
00638     /*
00639     run all the scripts in the startup table.
00640     */
00641     
00642     return (scriptrunspecialscripts (namestartuptable));
00643     } /*scriptrunstartupscripts*/
00644 
00645 
00646 boolean scriptrunsuspendscripts (void) {
00647     
00648     /*
00649     run all the scripts in the suspend table.
00650     
00651     5.0a3 dmb: no; just run the single system.callbacks.suspend script
00652     */
00653     
00654     // return (scriptrunspecialscripts (namesuspendtable));
00655     
00656     bigstring bsscript;
00657     
00658     getsystemtablescript (idsuspendscript, bsscript);
00659     
00660     return (processrunstringnoerrorclear (bsscript));
00661     } /*scriptrunsuspendscripts*/
00662 
00663 
00664 long specialoneshotscriptsrunning (void) {
00665     
00666     return (ctspecialprocessesrunning);
00667     } /*specialoneshotscriptsrunning*/
00668 
00669 
00670 boolean scriptrunresumescripts (void) {
00671     
00672     /*
00673     run all the scripts in the resume table.
00674     
00675     5.0a3 dmb: no; just run the single system.callbacks.suspend script
00676     */
00677     
00678     // return (scriptrunspecialscripts (nameresumetable));
00679     
00680     bigstring bsscript;
00681     
00682     getsystemtablescript (idresumescript, bsscript);
00683     
00684     return (processrunstringnoerrorclear (bsscript));
00685     } /*scriptrunresumescripts*/
00686 
00687 
00688 boolean loadsystemscripts (void) {
00689     
00690     /*
00691     6/19/92 dmb: load agents last, so that a startup script can 
00692     disable them effectively
00693     
00694     2.1b4 dmb: disabled calls to preload stuff in builtins, apps & traps. 
00695     it this stuff isn't used, why force it into memory?
00696     */
00697     
00698     scriptrunstartupscripts (); /*run all scripts in startup table*/
00699     
00700     scriptloadagents (); /*load all scripts in agents table*/
00701     
00702     return (true);
00703     } /*loadsystemscripts*/
00704 
00705 
00706 static boolean runprocessvisit (hdlhashnode hnode, ptrvoid refcon) {
00707 #pragma unused (refcon)
00708 
00709     hdltreenode hcode;
00710     hdlprocessrecord hprocess;
00711     tyvaluerecord val;
00712     boolean fl;
00713     
00714     langpusherrorcallback (&systemscripterrorroutine, (long) hnode);
00715     
00716     fl = scriptgetcode (hnode, &hcode);
00717     
00718     langpoperrorcallback ();
00719     
00720     if (!fl)
00721         return (true);
00722     
00723     if (!newprocess (hcode, true, nil, 0L, &hprocess)) {
00724         
00725         langdisposetree (hcode);
00726         
00727         return (false);
00728         }
00729     
00730     fl = processruncode (hprocess, &val);
00731     
00732     disposeprocess (hprocess);
00733     
00734     if (fl)
00735         disposetmpvalue (&val);
00736     
00737     return (true);
00738     } /*runprocessvisit*/
00739 
00740 
00741 boolean runshutdownscripts (void) {
00742     
00743     /*
00744     run all the scripts in the shutdown table.
00745     */
00746     
00747     hdlhashtable htable;
00748     
00749     if (!findnamedtable (systemtable, nameshutdowntable, &htable))
00750         return (true);
00751     
00752     return (hashtablevisit (htable, &runprocessvisit, nil));
00753     } /*runshutdownscripts*/
00754 
00755 
00756 static void scriptgetpopuprect (Rect *rpopup) {
00757     
00758     register hdlwindowinfo hw = outlinewindowinfo;
00759     register Rect *r = rpopup;
00760     
00761     *r = (**hw).messagerect;
00762     
00763     (*r).left = (*r).right - 1;
00764     
00765     (*r).right = (*r).left + 73;
00766     
00767     /*
00768     (*r).right = (*r).left + 1;
00769     
00770     (*r).left = (**hw).contentrect.left - 1;
00771     */
00772     
00773     } /*scriptgetpopuprect*/
00774 
00775 
00776 static boolean scriptinvalbuttonsvisit (WindowPtr w, ptrvoid refcon) {
00777 #pragma unused (refcon)
00778 
00779     /*
00780     7.0b42 PBS: If Mac OS X, re-draw the script buttons right away, because
00781     otherwise the window doesn't get updated until it's activated.
00782     */
00783 
00784     Rect r;
00785     
00786     shellpushglobals (w);
00787     
00788     shellinvalbuttons (); 
00789     
00790     scriptgetpopuprect (&r);
00791     
00792     invalwindowrect (shellwindow, r);
00793     
00794     #if TARGET_API_MAC_CARBON == 1
00795     
00796         GetPortBounds (GetWindowPort (w), &r);  
00797     
00798         pushclip (r);
00799     
00800         shelldrawbuttons ();
00801         
00802         popclip ();
00803         
00804     #endif
00805         
00806     shellpopglobals ();
00807     
00808     return (true);
00809     } /*scriptinvalbuttonsvisit*/
00810 
00811 
00812 static void scriptinvalbuttons (void) {
00813     
00814     shellvisittypedwindows (idscriptconfig, &scriptinvalbuttonsvisit, nil);
00815     } /*scriptinvalbuttons*/
00816 
00817 
00818 static boolean scriptfindhashnode (hdlexternalvariable hvariable, hdlhashnode *hnode) {
00819     
00820     hdlhashtable htable;
00821     bigstring bsname;
00822     boolean fl;
00823     
00824     if (!langexternalfindvariable (hvariable, &htable, bsname))
00825         return (false);
00826     
00827     pushhashtable (htable);
00828     
00829     fl = hashlookupnode (bsname, hnode);
00830     
00831     pophashtable ();
00832     
00833     return (fl);
00834     } /*scriptfindhashnode*/
00835 
00836 
00837 boolean scriptinmenubar (void) {
00838     
00839     /*
00840     12/31/90 dmb: for menubar scripts, we now stick the hdlheadrecord of 
00841     owning headline in the refcon of the script outline.  sadly, we have to 
00842     rely on the handle size to tell what kind of handle it is
00843     
00844     7/16/91 dmb: removed staticness for "temporary" call from shellwindowverbs.c
00845     */
00846     
00847 //  return (isheadrecordhandle ((**outlinedata).outlinerefcon));
00848     return ((**outlinedata).outlinetype == outlineismenubarscript);
00849     } /*scriptinmenubar*/
00850 
00851 
00852 static boolean scriptindatabase (void) {
00853     
00854     /*
00855     12/31/90 dmb: for menubar scripts, we now stick the hdlheadrecord of 
00856     owning headline in the refcon of the script outline.  sadly, we have to 
00857     rely on the handle size to tell what kind of handle it is
00858     
00859     7/16/91 dmb: removed staticness for "temporary" call from shellwindowverbs.c
00860     */
00861     
00862     return ((**outlinedata).outlinetype == outlineisdatabasescript);
00863     } /*scriptindatabase*/
00864 
00865 
00866 static boolean scriptinruntimestack (void) {
00867     
00868     /*
00869     is the current script part of the current process?
00870     
00871     6/24/92 dmb: compare outlines in loop, not windows; windows may not yet 
00872     be assigned into stack (if opened manaually or by Error Info)
00873     */
00874     
00875     register hdldebuggerrecord hd = debuggerdata;
00876     register short ix;
00877     
00878     for (ix = 0; ix < (**hd).topscriptsource; ix++) { /*visit every window in stack*/
00879         
00880         /*
00881         if (outlinewindow == (**hd).scriptsourcestack [ix].pwindow) {
00882         */
00883         
00884         if (outlinedata == (**hd).scriptsourcestack [ix].houtline) {
00885             
00886             if (ix == 0) /*main source window.  make sure same script is displayed*/
00887             
00888                 return ((**hd).scriptrefcon == (**outlinedata).outlinerefcon);
00889             
00890             return (true);
00891             }
00892         }
00893     
00894     return (false);
00895     } /*scriptinruntimestack*/
00896 
00897 
00898 static boolean scriptinstallable (void) {
00899     
00900     /*
00901     8/26/90 DW:
00902     
00903     this is separated out into a separate function so that our method is easily
00904     visible, and can easily be changed.
00905     
00906     we want to know if the script lives in the menubar structure or in the symbol
00907     table structure.  we observe that the outline record's refcon field will point
00908     to a variable record if it lives in the symbol table -- and it's nil if it 
00909     lives in the menubar.
00910     
00911     if you allocate a refcon for menubar scripts all of a sudden they will appear
00912     to be installable.
00913     
00914     11/19/90 DW: no longer depend on the outline being dirty -- allow the user
00915     to install the script, even when it isn't dirty.
00916     
00917     12/31/90 dmb: refcon is no longer nil for menubar scripts -- see commment 
00918     in scriptinmenubar
00919     */
00920     
00921     return (scriptindatabase ());
00922     } /*scriptinstallable*/
00923 
00924 
00925 #ifdef flcomponent
00926 
00927 static boolean scriptrecordable (void) {
00928     
00929     register ComponentInstance comp;
00930     
00931     if (!havecomponentmanager ())
00932         return (false);
00933     
00934     comp = getosaserver ((**outlinedata).outlinesignature);
00935     
00936     if (comp == nil)
00937         return (false);
00938     
00939     return (ComponentFunctionImplemented (comp, kOSASelectStartRecording));
00940     } /*scriptrecordable*/
00941 
00942 #endif
00943 
00944 static boolean scriptpushsourcerecord (tysourcerecord source) {
00945     
00946     register hdldebuggerrecord hd = debuggerdata;
00947     
00948     if (!langcheckstacklimit (idsourcestack, (**hd).topscriptsource, maxnestedsources)) /*overflow!*/
00949         return (false);
00950     
00951     (**hd).scriptsourcestack [(**hd).topscriptsource++] = source;
00952     
00953     return (true);
00954     } /*scriptpushsourcerecord*/
00955 
00956 
00957 static boolean scriptpopsourcerecord (tysourcerecord *source) {
00958     
00959     register hdldebuggerrecord hd = debuggerdata;
00960     
00961     *source = (**hd).scriptsourcestack [--(**hd).topscriptsource];
00962     
00963     return (true);
00964     } /*scriptpopsourcerecord*/
00965 
00966 
00967 static boolean scriptgetsourcerecord (hdlhashnode hnode, tysourcerecord *source) {
00968     
00969     /*
00970     look for a source code record for the indicated hashnode.
00971     */
00972     
00973     register hdldebuggerrecord hd = debuggerdata;
00974     register short ix;
00975     
00976     for (ix = 0; ix < (**hd).topscriptsource; ix++) { /*visit every window in stack*/
00977         
00978         if (hnode == (**hd).scriptsourcestack [ix].hnode) {
00979             
00980             *source = (**hd).scriptsourcestack [ix];
00981             
00982             return (true);
00983             }
00984         }
00985     
00986     return (false);
00987     } /*scriptgetsourcerecord*/
00988 
00989 
00990 static boolean scriptprocessstarted (void) {
00991     
00992     //scriptresetbackgroundtime ();
00993     
00994     return (true);
00995     } /*scriptprocessstarted*/
00996 
00997 
00998 static boolean scriptprocesskilled (void) {
00999     
01000     /*
01001     12/31/90 dmb: don't clear all debugger globals -- may be needed for error
01002     
01003     10/29/91 dmb: must clear flscriptsuspended flag to ensure proper button handling
01004     
01005     8/12/92 dmb: set scriptprocess to nil to as not to confuse scriptgettargetdata
01006     
01007     5.0d19 dmb: now that it's all in one window, close the runtime stack table.
01008 
01009     5.0.1 dmb: use tablefinddatawindow to find runtimestacktable. avoids rare crash.
01010     */
01011     
01012     register hdldebuggerrecord hd = debuggerdata;
01013     
01014     (**hd).scriptprocess = nil;
01015     
01016     (**hd).flscriptrunning = false;
01017     
01018     (**hd).flscriptsuspended = false;
01019     
01020     (**hd).topscriptsource = 0; /*cheap pop of original source record*/
01021     
01022     scriptinvalbuttons ();
01023     
01024     /*close the runtime stack window*/ {
01025         
01026         hdlwindowinfo hinfo;
01027         
01028         if (tablefinddatawindow (runtimestacktable, &hinfo))
01029             shellclosewindow ((**hinfo).macwindow);
01030         }
01031     
01032     return (true);
01033     } /*scriptprocesskilled*/
01034 
01035 
01036 static boolean scriptmainexists (hdltreenode hcode, bigstring bsmodule) {
01037     
01038     /*
01039     skip over local subroutines and declarations and verify that at 
01040     least one line of executable code exists in the code tree
01041     */
01042     
01043     register hdltreenode hp1 = (**(hcode)).param1;
01044     
01045     setemptystring (bsmodule);
01046     
01047     while (hp1) {
01048         
01049         switch ((**hp1).nodetype) {
01050             
01051             case noop:
01052             case localop:
01053                 break;
01054             
01055             case moduleop: { /*grab name*/
01056                 register hdltreenode hp2 = (**hp1).param2; /*should be procop*/
01057                 
01058                 assert (hp2 && ((**hp2).nodetype == procop));
01059                 
01060                 hp2 = (**hp2).param1;
01061                 
01062                 if (!langgetidentifier (hp2, bsmodule))
01063                     return (false);
01064 
01065                 /*
01066                 if ((**hp2).nodetype == identifierop))
01067                     pullstringvalue (&(**(**hp2).param1).nodeval, bsmodule);
01068                 */
01069                 
01070                 break;
01071                 }
01072             
01073             default:
01074                 return (true);
01075             }
01076         
01077         hp1 = (**hp1).link;
01078         }
01079     
01080     return (false); /*no meaty lines found*/
01081     } /*scriptmainexists*/
01082 
01083 
01084 static boolean scriptdebugerrormessage (bigstring bsmsg, ptrvoid refcon) {
01085     
01086     /*
01087     6/23/92 dmb: new feature: we invoke the debugger at the current line 
01088     when an error is encountered, before allowing execution thread to 
01089     unwind.  this allows stack values to be examined.
01090     */
01091     
01092     langerrordialog (bsmsg, refcon);
01093     
01094     (**currentprocess).errormessagecallback = &langerrordialog; /*prevent reentrance*/
01095     
01096     scriptdebugger (herrornode);
01097     
01098     return (true);
01099     } /*scriptdebugerrormessage*/
01100 
01101 
01102 static boolean scriptdebugtraperror (hdltreenode hnode) {
01103     
01104     /*
01105     6.0a9 dmb: short form of scriptbugger, we unconditionally stop on the 
01106     error line, but don't flag it as an error
01107     */
01108     
01109     register hdldebuggerrecord hd = debuggerdata;
01110     short topscriptsource;
01111     tysourcerecord source;
01112     long lnum = (**hnode).lnum;
01113     
01114     topscriptsource = (**hd).topscriptsource; /*move into local*/
01115     
01116     source = (**hd).scriptsourcestack [topscriptsource - 1]; /*move into local*/
01117     
01118     if (source.houtline == nil) /*an error occured when source was pushed*/
01119         return (true);
01120     
01121     if (source.pwindow == nil) { /*closed, or never opened*/
01122     
01123         if (!systemscripterrorroutine ((long) source.hnode, lnum, -1, nil, nil))
01124             return (true);
01125         
01126         source.pwindow = getfrontwindow ();
01127         
01128         /*put updated version on stack*/
01129         
01130         (**hd).scriptsourcestack [topscriptsource - 1].pwindow = source.pwindow;
01131         }
01132     
01133     windowbringtofront (source.pwindow);
01134     
01135     shellpushglobals (source.pwindow);
01136     
01137     opshowerror (lnum, -1);
01138     
01139     (**hd).lastlnum = lnum;
01140     
01141     (**hd).hbarcursor = (**outlinedata).hbarcursor;
01142     
01143     shellpopglobals ();
01144     
01145     (**hd).flscriptsuspended = true;
01146     
01147     (**hd).flstepping = true;
01148     
01149     (**hd).flfollowing = false;
01150     
01151     scriptinvalbuttons ();
01152     
01153     return (true);
01154     } /*scriptdebugtraperror*/
01155 
01156 
01157 static boolean scriptdebugerrordebugger (bigstring bsmsg, ptrvoid refcon) {
01158     
01159     /*
01160     6/23/92 dmb: new feature: we invoke the debugger at the current line 
01161     when an error is encountered, before allowing execution thread to 
01162     unwind.  this allows stack values to be examined.
01163     */
01164     
01165     hdlhashtable hdebugprefs;
01166     hdltreenode hnode = herrornode;
01167     tyvaluerecord val;
01168     bigstring bstrap;
01169     boolean fl;
01170     //static boolean scriptdebuggereventloop (void); /* 2006-02-04 aradke: declare at top of file */
01171     hdlhashnode hhashnode;
01172     #define str_userdebugprefs (BIGSTRING ("\x10" "user.prefs.debug"))
01173     
01174     if (langcallbacks.errormessagecallback == scriptdebugerrormessage) //errors aren't being trapped
01175         return (true);
01176     
01177     if (hnode == nil)
01178         return (true);
01179     
01180     disablelangerror ();
01181     
01182     fl = langfastaddresstotable (roottable, str_userdebugprefs, &hdebugprefs) &&
01183         
01184         hashtablelookup (hdebugprefs, BIGSTRING ("\x0a" "trapErrors"), &val, &hhashnode) &&
01185         
01186         copyvaluerecord (val, &val) && 
01187         
01188         coercetoboolean (&val) &&
01189         
01190         val.data.flvalue;
01191     
01192     enablelangerror ();
01193     
01194     if (!fl) //we're not trapping errors
01195         return (true);
01196     
01197     disablelangerror ();
01198     
01199     if (hashtablelookup (hdebugprefs, BIGSTRING ("\x0f" "trapErrorString"), &val, &hhashnode) &&
01200         
01201         val.valuetype == stringvaluetype) {
01202         
01203         pullstringvalue (&val, bstrap);
01204         
01205         fl = isemptystring (bstrap) || patternmatch (bstrap, bsmsg);
01206         }
01207     
01208     enablelangerror ();
01209     
01210     if (!fl) //we're not trapping errors
01211         return (true);
01212     
01213     if (!scriptdebugtraperror (hnode))
01214         return (true);
01215     
01216     langerrordialog (bsmsg, refcon);
01217     
01218     scriptdebuggereventloop ();
01219     
01220     fllangerror = true; //in case it's been cleared by our actions
01221     
01222     return (!(**debuggerdata).flscriptkilled);
01223     } /*scriptdebugerrordebugger*/
01224 
01225 
01226 static long getscriptparentrefcon (hdloutlinerecord ho) {
01227 
01228     /*
01229     4/7/97 dmb: there are now three possiblities for the source 
01230     of a script being run:
01231 
01232     1 - it's a menubar script. ho.refcon is the hdlheadrecord of menubar item
01233     2 - it's an odb script. ho.refcon is the hdlhashnode of the table value
01234     3 - it's a starndalone script. ho.refcon is zero, ho it it's own parent
01235     */
01236 
01237     long refcon = (**ho).outlinerefcon; /*default: use outline's refcon*/
01238 
01239     switch ((**ho).outlinetype) {
01240 
01241         case outlineisdatabasescript: { /*script comes from a table*/
01242             
01243             hdlexternalvariable hvariable = (hdlexternalvariable) refcon;
01244             hdlhashnode hnode;
01245             
01246             assert (gethandlesize ((Handle) hvariable) == (sizeof (tyexternalvariable) + 4));
01247             
01248             if (!scriptfindhashnode (hvariable, &hnode))
01249                 return (false);
01250             
01251             return ((long) hnode);
01252             }
01253         
01254         case outlineisstandalonescript:
01255             return ((long) ho);
01256         
01257         case outlineismenubarscript:
01258         default:
01259             return (refcon);
01260         }
01261     } /*getscriptparentrefcon*/
01262 
01263 
01264 static boolean scriptnewprocess (short buttonnum) {
01265     
01266     /*
01267     2/5/91 dmb, on refcons: as discussed in scriptinmenubar, a outline's 
01268     refcon can be either a hdlexternalvariable or a hdlheadrecord.  while 
01269     debugging, we want to identify source by a hdlheadrecord or a 
01270     hdlhashnode.  we do the conversion from hdlexternalvariable to 
01271     hdlhashnode here so that no one else has to.
01272     */
01273     
01274     register hdldebuggerrecord hd = debuggerdata;
01275     hdloutlinerecord ho = outlinedata;
01276     Handle htext;
01277     hdltreenode hcode;
01278     hdlprocessrecord hprocess;
01279     register hdlprocessrecord hp;
01280     tysourcerecord source;
01281     register boolean fl;
01282     register long refcon;
01283     bigstring bsmodule;
01284     
01285     setcursortype (cursoriswatch);
01286     
01287     if (!opgetlangtext (ho, false, &htext))
01288         return (false);
01289     
01290     refcon = getscriptparentrefcon (ho);
01291 
01292     langpusherrorcallback (&systemscripterrorroutine, refcon);
01293     
01294     fl = scriptbuildtree (htext, (**ho).outlinesignature, &hcode);
01295     
01296     langpoperrorcallback ();
01297     
01298     if (!fl) /*syntax error detected by compiler*/
01299         return (false);
01300     
01301     langerrorclear (); /*compilation produced no error, be sure error window is empty*/
01302     
01303     if (!scriptmainexists (hcode, bsmodule)) {
01304         bigstring bs;
01305         byte bsbutton [16];
01306         
01307         langdisposetree (hcode);
01308         
01309         shellgetbuttonstring (buttonnum, bsbutton);
01310         
01311         alllower (bsbutton);
01312         
01313         if (isemptystring (bsmodule))
01314             langgetstringlist (nomaintorunstring, bs);
01315         else
01316             langgetstringlist (needmodulecallstring, bs);
01317         
01318         parsedialogstring (bs, bsbutton, bsmodule, nil, nil, bs);
01319         
01320         shellerrormessage (bs);
01321         
01322         return (false);
01323         }
01324     
01325     if (!newprocess (hcode, true, &systemscripterrorroutine, refcon, &hprocess))
01326         return (false);
01327     
01328     hp = hprocess; /*copy into register*/
01329     
01330     (**hp).processstartedroutine = &scriptprocessstarted;
01331     
01332     (**hp).processkilledroutine = &scriptprocesskilled;
01333     
01334     addprocess (hp); /*insert in process list*/
01335     
01336     if (buttonnum == debugbutton) {
01337         
01338         (**hp).fldebugging = true;
01339     
01340         (**hp).errormessagecallback = &scriptdebugerrormessage;
01341     
01342         (**hp).debugerrormessagecallback = &scriptdebugerrordebugger;
01343         }
01344     
01345     clearhandle ((Handle) hd);
01346     
01347     bundle { /*initial debugger fields*/
01348         
01349         register ptrdebuggerrecord pd = *debuggerdata;
01350         
01351         (*pd).scriptprocess = hp;
01352         
01353         (*pd).flscriptrunning = true;
01354         
01355         (*pd).scriptrefcon = (**outlinedata).outlinerefcon; /*for later identification*/
01356         
01357         /* clearhandle gets all these
01358         
01359         (*pd).flscriptkilled = false;
01360         
01361         (*pd).flscriptsuspended = false;
01362         
01363         (*pd).flstepping = false;
01364         
01365         (*pd).flfollowing = false;
01366         
01367         (*pd).flwindowclosed = false;
01368         
01369         (*pd).fllangerror = false;
01370         
01371         (*pd).topscriptsource = 0;
01372         
01373         (*pd).sourcesteplevel = 0;
01374         
01375         (*pd).stepdir = nodirection;
01376         
01377         (*pd).lastlnum = 0;
01378         
01379         (*pd).hlocaltable = nil;
01380         
01381         (*pd).toplocaltable = 0;
01382         
01383         (*pd).hbarcursor = nil;
01384         */
01385         }
01386     
01387     source.pwindow = outlinewindow; /*the main source window*/
01388     
01389     source.hnode = (hdlhashnode) refcon;
01390     
01391     source.houtline = outlinedata;
01392     
01393     scriptinvalbuttons ();
01394     
01395     return (scriptpushsourcerecord (source));
01396     } /*scriptnewprocess*/
01397 
01398 
01399 static void scriptstepbutton (tydirection dir) {
01400     
01401     /*
01402     resume script execution until the source stack level changes 
01403     by the indicated amount.
01404     */
01405     
01406     register hdldebuggerrecord hd = debuggerdata;
01407     
01408     (**hd).flscriptsuspended = false; /*allow the script to resume*/
01409     
01410     (**hd).flstepping = true;
01411     
01412     (**hd).flfollowing = keyboardstatus.floptionkey;
01413     
01414     (**hd).sourcesteplevel = (**hd).topscriptsource;
01415     
01416     (**hd).stepdir = dir;
01417     } /*scriptstepbutton*/
01418 
01419 
01420 static void scriptgobutton (void) {
01421     
01422     register hdldebuggerrecord hd = debuggerdata;
01423     
01424     (**hd).flscriptsuspended = false; /*allow the script to resume*/
01425     
01426     (**hd).flstepping = false; /*don't halt after every line of code*/
01427     
01428     (**hd).flfollowing = false; 
01429     
01430     (**hd).sourcesteplevel = (**hd).topscriptsource;
01431     } /*scriptgobutton*/
01432 
01433 
01434 static void scriptkillbutton (void) {
01435     
01436     /*
01437     11/5/91 dmb: use new scriptprocess field to make kill more explicit
01438     */
01439     
01440     register hdldebuggerrecord hd = debuggerdata;
01441     
01442     processkill ((**hd).scriptprocess);
01443     
01444     (**hd).flscriptkilled = true;
01445     
01446     (**hd).flscriptsuspended = false; /*allow script to resume, so it can die*/
01447     } /*scriptkillbutton*/
01448 
01449 
01450 #ifdef flcomponent
01451 
01452 static pascal OSErr handlerecordedtext (const AppleEvent *event, AppleEvent *reply, SInt32 refcon) {
01453 #pragma unused (reply, refcon)
01454 
01455     /*
01456     2.1b3 dmb: ignore extra syntax/lines needed for text-based recording
01457     
01458     2.1b4 dmb: special case leading comment character
01459     
01460     2.1b5 dmb: use opinserthandle logic to add text from other scripting systems.
01461     this handles multiple lines, which QuicKeys dishes out.
01462     
01463     2.1b8 dmb: strip nul characters from recorded text (QuicKeys again)
01464     
01465     2.1b9 dmb: don't call opinserthandle for non-outline text, or leading 
01466     tabs won't be stripped.
01467     */
01468     
01469     register hdldebuggerrecord hd = debuggerdata;
01470     register WindowPtr w = (**hd).scriptsourcestack [0].pwindow;
01471     AEDesc desc;
01472     boolean flfrontierserver;
01473     boolean floutline;
01474     tydirection dir;
01475     bigstring bs;
01476     Handle hstring;
01477     short indent;
01478     short diff;
01479     boolean flcomment = false;
01480     OSErr err;
01481     
01482     err = AEGetParamDesc (event, keyDirectObject, typeChar, &desc);
01483     
01484     if (err != noErr)
01485         return (err);
01486     
01487     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01488     
01489         datahandletostring (&desc, bs);
01490     
01491     #else
01492     
01493         texthandletostring (desc.dataHandle, bs);
01494     
01495     #endif
01496     
01497     stringdeletechars (bs, chnul);
01498     
01499     if (isemptystring (bs))
01500         goto exit;
01501     
01502     indent = popleadingchars (bs, chtab);
01503     
01504     flfrontierserver = (**hd).servertype == typeLAND;
01505     
01506     if (flfrontierserver) { /*strip text-based syntax*/
01507         
01508         floutline = false; /*we'll strip trailing return*/
01509         
01510         if (bs [1] == chcomment) {
01511             
01512             deletefirstchar (bs);
01513             
01514             flcomment = true;
01515             }
01516         else {
01517             short len = stringlength (bs);
01518             
01519             if (lastchar (bs) == chreturn) /*strip trailing return*/
01520                 len -= 1;
01521             
01522             switch (bs [len]) { /*look at the last char*/
01523                 
01524                 case '{':
01525                     len -= 2;
01526                     
01527                     break;
01528                 
01529                 case ';':
01530                     len -= 1;
01531                     
01532                     break;
01533                 }
01534             
01535             if (bs [len] == '}')
01536                 goto exit;
01537             
01538             setstringlength (bs, len);
01539             }
01540         }
01541     else
01542         
01543         #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01544         
01545             {
01546             Handle hcopy;
01547             
01548             copydatahandle (&desc, &hcopy);
01549             
01550             floutline = isoutlinetext (hcopy);
01551             
01552             disposehandle (hcopy);
01553             }
01554         
01555         #else
01556         
01557             floutline = isoutlinetext (desc.dataHandle);
01558     
01559         #endif
01560         
01561     diff = indent - (**hd).lastindent;
01562     
01563     if (shellpushglobals (w)) {
01564         
01565         if (diff > 0)
01566             dir = right;
01567         else {
01568             
01569             if (diff < 0)
01570                 opmotionkey (left, -diff, false);
01571             
01572             dir = down;
01573             }
01574         
01575         if (floutline)
01576             
01577             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01578             
01579                 {
01580                 Handle hcopy;
01581                 
01582                 copydatahandle (&desc, &hcopy);
01583                 
01584                 opinserthandle (hcopy, dir);
01585                 }
01586             
01587             #else
01588             
01589                 opinserthandle (desc.dataHandle, dir);
01590         
01591             #endif
01592             
01593         else {
01594             
01595             if (newtexthandle (bs, &hstring))
01596                 if (opinsertheadline (hstring, dir, flcomment))
01597                     shellcheckdirtyscrollbars ();
01598             }
01599         
01600         shellpopglobals ();
01601         }
01602     
01603     (**hd).lastindent = indent;
01604     
01605     exit:
01606     
01607     AEDisposeDesc (&desc);
01608     
01609     return (noErr);
01610     } /*handlerecordedtext*/
01611 
01612 
01613 static boolean openservercomp (void) {
01614 
01615     register hdldebuggerrecord hd = debuggerdata;
01616     ComponentInstance comp = (**hd).servercomp;
01617     OSType servertype;
01618     
01619     servertype = (**outlinedata).outlinesignature;
01620     
01621     comp = getosaserver (servertype);
01622     
01623     if (comp == nil)
01624         return (false);
01625     
01626     (**hd).servercomp = comp;
01627     
01628     (**hd).servertype = servertype;
01629     
01630     return (true);
01631     } /*openservercomp*/
01632 
01633 
01634 static void scriptrecordbutton (void) {
01635     
01636     register hdldebuggerrecord hd = debuggerdata;
01637     OSAID idscript = kOSANullScript;
01638     tysourcerecord source;
01639     
01640     if (!openservercomp ())
01641         return;
01642     
01643     setcursortype (cursoriswatch);
01644     
01645     if (oserror (OSAStartRecording ((**hd).servercomp, &idscript)))
01646         return;
01647     
01648     (**hd).idscript = idscript;
01649     
01650     (**hd).flrecording = true;
01651     
01652     assert ((**hd).topscriptsource == 0);
01653     
01654     source.pwindow = outlinewindow; /*the main source window*/
01655     
01656     source.hnode = nil;
01657     
01658     source.houtline = outlinedata;
01659     
01660     scriptpushsourcerecord (source);
01661     } /*scriptrecordbutton*/
01662 
01663 
01664 static void scriptstoprecordbutton (void) {
01665     
01666     /*
01667     2.1b5 dmb: don't forget to dispose the recorded script id
01668     */
01669     
01670     register hdldebuggerrecord hd = debuggerdata;
01671     ComponentInstance comp = (**hd).servercomp;
01672     OSAID idscript = (**hd).idscript;
01673     tysourcerecord source;
01674     OSAError err;
01675     
01676     setcursortype (cursoriswatch);
01677     
01678     err = OSAStopRecording (comp, idscript);
01679     
01680     if ((err != badComponentInstance) && oserror (err))
01681         return;
01682     
01683     scriptpopsourcerecord (&source);
01684     
01685     OSADispose (comp, idscript);
01686     
01687     (**hd).idscript = kOSANullScript;
01688     
01689     (**hd).flrecording = false;
01690     } /*scriptstoprecordbutton*/
01691 
01692 
01693 static pascal OSErr handlestoprecording (const AppleEvent *event, AppleEvent *reply, SInt32 refcon) {
01694 #pragma unused (event, reply, refcon)
01695 
01696     /*
01697     2.1b5 dmb: special event handler for QuicKeys recording panel
01698     */
01699     
01700     register hdldebuggerrecord hd = debuggerdata;
01701     
01702     if ((**hd).flrecording) {
01703         
01704         scriptstoprecordbutton ();
01705         
01706         scriptinvalbuttons ();
01707         }
01708     
01709     return (noErr);
01710     } /*handlestoprecording*/
01711 
01712 #endif  // flcomponent
01713 
01714 static boolean scriptstringlookup (bigstring bs, hdlhashtable *htable, bigstring bsname) {
01715     
01716     /*
01717     if the text in bs (a text selection) is something identifiable as 
01718     a language element, try to display the corresponding table entry
01719     */
01720     
01721     Handle htext;
01722     hdltreenode hmodule;
01723     register boolean fl = false;
01724     register hdltreenode h;
01725     
01726     copystring (bs, bsname); /*start with literal interpretation*/
01727     
01728     if (langtablelookup (hkeywordtable, bsname, htable)) /*it's a keyword*/
01729         return (true);
01730     
01731     if (langtablelookup (hbuiltinfunctions, bsname, htable)) /*it's a build-in*/
01732         return (true);
01733     
01734     if (langtablelookup (hconsttable, bsname, htable)) /*it's a constant*/
01735         return (true);
01736     
01737     /*try to compile it for interpretation*/
01738     
01739     if (!newtexthandle (bs, &htext))
01740         return (false);
01741     
01742     if (!langcompiletext (htext, false, &hmodule)) /*always disposes htext*/
01743         return (false);
01744     
01745     h = (**hmodule).param1;
01746     
01747     fl = langgetdotparams (h, htable, bsname);
01748     
01749     langdisposetree (hmodule);
01750     
01751     if (!fl)
01752         return (false);
01753     
01754     if (*htable == nil)
01755         return (langsearchpathlookup (bsname, htable));
01756     
01757     return (langtablelookup (*htable, bsname, htable)); /*must already exist*/
01758     } /*scriptstringlookup*/
01759 
01760 
01761 static boolean scriptzoomdotparams (bigstring bs) {
01762     
01763     /*
01764     bs should be an expression that resolves to an identifier or 
01765     dotparam pair.  if it is, locate the indicated hash node in its 
01766     table.  otherwise, beep
01767     
01768     9/1/92 dmb: push the top locals table here so we don't rely on being 
01769     called withing the script's context. allows us to get rid of the 
01770     deferredbutton stuff.
01771     
01772     9/11/92 dmb: for global external values, open the value's window rather 
01773     than selecting the value in its parent window. this is what is normally 
01774     desired, and allows scriptdoubleclick to use this w/out special-case code 
01775     */
01776     
01777     register hdlhashtable ht = (**debuggerdata).hlocaltable;
01778     bigstring bsname;
01779     hdlhashtable htable;
01780     tyvaluerecord val;
01781     boolean fl;
01782     hdlhashnode hnode;
01783     
01784     disablelangerror ();
01785     
01786     if (ht != nil)
01787         pushhashtable (ht);
01788     
01789     fl = scriptstringlookup (bs, &htable, bsname);
01790     
01791     if (ht != nil)
01792         pophashtable ();
01793     
01794     enablelangerror ();
01795     
01796     if (!fl)
01797         return (false);
01798     
01799     /*
01800     if (flzoomlocalonly && !(**htable).fllocaltable)
01801         return (false);
01802     */
01803     
01804     if ((**htable).fllocaltable) {  /*local value -- open stack window*/
01805     
01806         if (!tablezoomfromtable (runtimestacktable))
01807             return (false);
01808         }
01809     else {                          /*global value -- open window of externals*/
01810         
01811         hashtablelookup (htable, bsname, &val, &hnode);
01812         
01813         if (val.valuetype == externalvaluetype)
01814             return (langexternalzoom (val, htable, bsname));
01815         }
01816     
01817     if (!tablezoomtoname (htable, bsname))
01818         return (false);
01819     
01820     return (true);
01821     } /*scriptzoomdotparams*/
01822 
01823 
01824 static boolean scriptlocalsbutton (void) {
01825     
01826     /*
01827     5.0d18 dmb: we can now show whatever we zoom within the 
01828     context of the whole stack table, by zooming the latter first
01829     */
01830     
01831     register hdldebuggerrecord hd = debuggerdata;
01832     hdlhashtable ht;
01833     bigstring bs;
01834     
01835     if ((**outlinedata).fltextmode) {
01836         
01837         opeditgetseltext (bs);
01838         
01839         if (!isemptystring (bs))
01840             return (scriptzoomdotparams (bs));
01841         }
01842     
01843     if (!tablezoomfromtable (runtimestacktable))
01844         return (false);
01845     
01846     if ((**hd).toplocaltable > 0 && // some locals are pushed
01847         findinparenttable ((**hd).hlocaltable, &ht, bs)) { // looked up ok
01848         
01849         if (!tablezoomtoname (ht, bs))
01850             return (false);
01851         
01852         shellpushfrontglobals ();
01853         
01854         if (outlinedata) // should be there
01855             opexpand ((**outlinedata).hbarcursor, 1, false);
01856         
01857         shellpopglobals ();
01858         }
01859         
01860         //  return (tablezoomfromtable ((**hd).hlocaltable));
01861     
01862 //  return (tablezoomfromtable (runtimestacktable));
01863 
01864     return (true);
01865     } /*scriptlocalsbutton*/
01866 
01867 
01868 static boolean scriptinstallbutton (void) {
01869     
01870     hdlexternalvariable hvariable;
01871     hdlhashnode hnode;
01872     hdltreenode hcode;
01873     
01874     hvariable = (hdlexternalvariable) (**outlinedata).outlinerefcon;
01875     
01876     if (!scriptfindhashnode (hvariable, &hnode))
01877         return (false);
01878     
01879     langerrorclear (); /*be sure error window is empty*/
01880     
01881     /*
01882     if (!processyieldtoagents ()) /%file closed while agents were finishing up%/
01883         return (false);
01884     */
01885     
01886     if (!scriptcompiler (hnode, &hcode))
01887         return (false);
01888     
01889     scriptinvalbuttons (); // 5.28.97 dmb: compile button will dim now
01890         
01891     return (true);
01892     } /*scriptinstallbutton*/
01893 
01894 
01895 static boolean scriptbutton (short buttonnum) {
01896     
01897     /*
01898     1/14/91 dmb: for the locals button, we act on the text selection, 
01899     if one exists.  for all other buttons, exit edit mode before 
01900     proceeding
01901     
01902     1/29/91 dmb: some button hits (Step, Locals) can't be handled reliably 
01903     when a background process is executing.  if the main process is 
01904     suspended (i.e. this is a background event) but isn't running now, 
01905     defer the button hit until control is returned to main process.  
01906     scriptdebuggereventloop watches for this condition
01907     
01908     6/23/92 dmb: don't defer install button hits; it never applies to the 
01909     currently-running script.  handling the install button in the debugged 
01910     script's thread is a strain on stack space, and can cause reentrancy if 
01911     an error is being handled and a compilation error occurs.
01912     
01913     9/1/92 dmb: as it turns out, the process/thread architecture has changed so 
01914     much since 1/29/91 that we really don't need the deferred button stuff at 
01915     all, which does indeed stress stack space -- especially when debugging after 
01916     a stack overflow error! the one thing we do have to do is push the current 
01917     locals table while handling the locals button in scriptzoomdotparams
01918     
01919     2.1b1 dmb: added recording logic
01920     */
01921     
01922     register hdldebuggerrecord hd = debuggerdata;
01923     
01924     if (buttonnum != localsbutton) /*exit edit mode on any button hit except locals*/
01925         opsettextmode (false);
01926     
01927     /*
01928     if ((**hd).flscriptsuspended && !debuggingcurrentprocess ()) { /%defer background hits%/
01929         
01930         if (buttonnum != installbutton) {
01931             
01932             (**hd).deferredbuttonnum = buttonnum;
01933             
01934             (**hd).deferredwindow = shellwindow;
01935             
01936             return (true);
01937             }
01938         }
01939     */
01940     
01941     switch (buttonnum) {
01942         
01943     #ifdef flcomponent
01944         case recordbutton:
01945             scriptrecordbutton ();
01946             
01947             scriptinvalbuttons ();
01948             
01949             return (true);
01950     #endif      
01951         case runbutton:
01952             if (scriptnewprocess (runbutton))
01953                 shellupdatenow (outlinewindow);
01954             
01955             return (true);
01956         
01957         case debugbutton:
01958             if (scriptnewprocess (debugbutton))
01959                 scriptstepbutton (down); 
01960             
01961             return (true);
01962         
01963         case gobutton:
01964             scriptgobutton ();
01965             
01966             scriptinvalbuttons ();
01967             
01968             return (true);
01969         
01970         case followbutton:
01971             scriptstepbutton (nodirection); /*proceed as if stepping...*/
01972             
01973             (**hd).flfollowing = true; /*...but the cursor follows the interpreter*/
01974             
01975             scriptinvalbuttons ();
01976             
01977             return (true);
01978         
01979         case stepbutton:
01980             scriptstepbutton (down);
01981             
01982             return (true);
01983         
01984         case inbutton:
01985             scriptstepbutton (right);
01986             
01987             return (true);
01988         
01989         case outbutton:
01990             scriptstepbutton (left);
01991             
01992             return (true);
01993         
01994         case stopbutton:
01995     #ifdef flcomponent
01996             if ((**hd).flrecording)
01997                 scriptstoprecordbutton ();
01998             else
01999     #endif
02000              {
02001                 
02002                 scriptstepbutton (down); /*we're going to single-step thru scripts*/
02003                 
02004                 (**hd).flfollowing = false; 
02005                 }
02006             
02007             scriptinvalbuttons ();
02008             
02009             return (true);
02010             
02011         case killbutton:
02012             scriptkillbutton ();
02013             
02014             return (true);
02015         
02016         case localsbutton:
02017             if (!scriptlocalsbutton ())
02018                 sysbeep ();
02019             
02020             return (true);
02021         
02022         case installbutton:
02023             scriptinstallbutton (); 
02024             
02025             return (true);
02026         } /*switch*/
02027     
02028     return (true);
02029     } /*scriptbutton*/
02030 
02031 
02032 static boolean scripthascleancode () {
02033 
02034     register hdloutlinerecord ho = outlinedata;
02035     hdlexternalvariable hvariable;
02036     hdlhashnode hnode;
02037     hdltreenode hcode;
02038     
02039     if ((**ho).flrecentlychanged)
02040         return (false);
02041     
02042     hvariable = (hdlexternalvariable) (**ho).outlinerefcon;
02043     
02044     if (!scriptfindhashnode (hvariable, &hnode))
02045         return (false);
02046     
02047     if (!langexternalvaltocode ((**hnode).val, &hcode)) /*doesn't contain code*/
02048         return (false);
02049     
02050     return (hcode != nil);
02051     } /*scripthasdirtycode*/
02052 
02053 
02054 static boolean scriptbuttonenabled (short buttonnum) {
02055     
02056     /*
02057     return true if the button is enabled.
02058     
02059     1. if no script is running, then only the debug button is enabled.
02060     
02061     2. the "step button klooge" -- when the user presses the step button
02062     the first thing that happens is the button gets redrawn.  naturally,
02063     we're asked if it should be enabled.  by all logic, it should not be,
02064     since the program is not suspended, stepping isn't really a possibility.
02065     but, we know that the very next time around thru the debugger (which
02066     shouldn't be too long from now), it will make sense.  so to avoid an
02067     intermediate and distracting graying of the step button, we say 
02068     that it's enabled if the flag is set.
02069     
02070     8/26/90 DW: the klooge prevents the Install button from being properly
02071     enabled.  so we klooge around the klooge.
02072     
02073     1/2/91 dmb: rule 3. if a script is running, but isn't the current script, 
02074     don't enable anything except the install and kill buttons
02075     
02076     1/3/91 dmb: don't allow a script to be run when there's a one-shot 
02077     processing already running
02078     
02079     2/5/91 dmb: disable all buttons when script is blocked, even install & kill
02080     
02081     8/14/91 dmb: disable some buttons when script isn't suspended
02082     
02083     2.1b1 dmb: added recording logic
02084     
02085     2.1b4 dmb: can't do anything if context is locked
02086     */
02087     
02088     register short x = buttonnum;
02089     register hdldebuggerrecord hd = debuggerdata;
02090     register boolean lflscriptrunning = (**hd).flscriptrunning;
02091     register boolean flscriptsuspended = (**hd).flscriptsuspended;
02092     register boolean flrunningthisscript;
02093     
02094     flrunningthisscript = lflscriptrunning && scriptinruntimestack ();
02095     
02096     if (lflscriptrunning) {
02097         
02098         if ((x != installbutton) && (x != killbutton)) /*rule 3*/
02099             if (!flrunningthisscript)
02100                 return (false);
02101         }
02102     
02103     if ((**hd).flrecording)
02104         return (x == stopbutton);
02105     
02106     if ((**hd).flcontextlocked)
02107         return (false);
02108     
02109     /*
02110     else {
02111         
02112         if ((x != runbutton) && (x != debugbutton) && (x != installbutton)) /%rule 1%/
02113             return (false);
02114         }
02115     */
02116     
02117     switch (x) {
02118         
02119         case recordbutton:
02120         #ifdef flcomponent
02121             return (!lflscriptrunning && scriptrecordable ());
02122         #else
02123             return (false);
02124         #endif
02125         
02126         case runbutton:
02127             return (!lflscriptrunning);
02128         
02129         case debugbutton:
02130             return (!lflscriptrunning && ((**outlinedata).outlinesignature == typeLAND));
02131         
02132         case stopbutton:
02133             return (!flscriptsuspended);
02134         
02135         case gobutton:
02136             return ((flscriptsuspended || (**hd).flfollowing) && !(**hd).fllangerror);
02137         
02138         case followbutton:
02139         case stepbutton:
02140         case inbutton:
02141         case outbutton:
02142             return (lflscriptrunning && flscriptsuspended && !(**hd).fllangerror);
02143         
02144         case localsbutton:
02145             return (lflscriptrunning && flscriptsuspended); /*(**hd).flstepping && (!(**hd).flfollowing))*/
02146         
02147         case killbutton:
02148             return (lflscriptrunning);
02149         
02150         case installbutton:
02151             return (!flrunningthisscript && scriptinstallable () && !scripthascleancode ());
02152         } /*switch*/
02153     
02154     return (true);
02155     } /*scriptbuttonenabled*/
02156 
02157 
02158 static boolean scriptbuttondisplayed (short buttonnum) {
02159     
02160     /*
02161     return true if the button should be displayed.
02162     
02163     1. if no script is running, then display the run button, and 
02164     maybe the install button
02165     
02166     2. if a script is running, don't show the run button or the 
02167     install button, but show everything else
02168     
02169     1/2/91 dmb: if this script isn't in the run-time stack, we're not
02170     "running"
02171     
02172     1/14/91 dmb: it's deathly to install a script when it's running, 
02173     since the currently-running code tree will be disposed.  modified 
02174     rule 2 above accordingly
02175     
02176     2/1/91 dmb: if a script is running, show the kill button in all script 
02177     windows (not just those in the run-time stack) and never show the run
02178     button
02179     
02180     2.1b1 dmb: added recording logic
02181     */
02182     
02183     register hdldebuggerrecord hd = debuggerdata;
02184     register hdlprocessrecord hp = (**hd).scriptprocess;
02185     register boolean lflscriptrunning = (**hd).flscriptrunning;
02186     register boolean flrunningthisscript;
02187     register boolean fldebuggingthisscript;
02188     register short x = buttonnum;
02189     
02190     flrunningthisscript = lflscriptrunning && scriptinruntimestack (); /*1/2/91*/
02191     
02192     fldebuggingthisscript = flrunningthisscript && (**hp).fldebugging;
02193     
02194 #ifdef flcomponent
02195     if ((**hd).flrecording)
02196         return ((x == recordbutton) || (x == stopbutton));
02197 #endif
02198     
02199     switch (x) {
02200         
02201         case recordbutton:
02202         #ifndef flcomponent
02203             return (false);
02204         #endif
02205         
02206         #if TARGET_API_MAC_CARBON == 1 /*PBS 7.0b43: no record button in OS X*/
02207         
02208             return (false);
02209         
02210         #endif
02211         
02212         case runbutton:
02213         case debugbutton:
02214             return (!lflscriptrunning);
02215         
02216         case installbutton:
02217             return (!fldebuggingthisscript && scriptinstallable ());
02218         
02219         case stopbutton:
02220             return (fldebuggingthisscript && !(**hd).flscriptsuspended);
02221         
02222         case gobutton:
02223             return (fldebuggingthisscript && (**hd).flscriptsuspended);
02224         
02225         case followbutton:
02226         case stepbutton:
02227         case inbutton:
02228         case outbutton:
02229         case localsbutton:
02230             return (fldebuggingthisscript);
02231         
02232         case killbutton:
02233             return (lflscriptrunning);
02234         } /*switch*/
02235     
02236     return (true);
02237     } /*scriptbuttondisplayed*/
02238 
02239 
02240 static boolean scriptbuttonstatus (short buttonnum, tybuttonstatus *status) {
02241     
02242     /*
02243     boolean fldisplay = scriptbuttondisplayed (buttonnum);
02244     
02245     (*status).fldisplay = fldisplay;
02246     
02247     (*status).flenabled = fldisplay && scriptbuttonenabled (buttonnum);
02248     */
02249     if (outlinedata == NULL)
02250         return (false);
02251 
02252     (*status).flenabled = scriptbuttonenabled (buttonnum);
02253     
02254     (*status).fldisplay = scriptbuttondisplayed (buttonnum);
02255     
02256     (*status).flbold = false; /*our buttons are never bold*/
02257     
02258     return (true);
02259     } /*scriptbuttonstatus*/
02260 
02261 
02262 #if 0
02263 
02264 boolean scriptkilled (void) {
02265     
02266     /*
02267     returns true if the current running script should be killed by the
02268     interpreter.  it's called back from within the interpreter.
02269     
02270     7/2/91 dmb: no longer check the scriptkilled debuggerdata flag here; 
02271     it's handled by returning false from the debugger routine.  checking 
02272     it here will wrongly terminate some other process
02273     */
02274     
02275     register hdldebuggerrecord hd = debuggerdata;
02276     
02277     /*
02278     if ((**hd).flscriptkilled) {
02279         
02280         if (processisoneshot (false)) { /%we're running a one-shot process%/
02281             
02282             (**hd).flscriptkilled = false; /%consume it%/
02283             
02284             scriptprocesskilled ();
02285             
02286             return (true);
02287             }
02288         }
02289     */
02290     
02291     if (keyboardescape ()) { /*user pressed cmd-period or something like that*/
02292         
02293         if (processisoneshot (true)) { /*cmd-period doesn't kill background tasks*/
02294             
02295             keyboardclearescape (); /*consume it*/
02296             
02297             return (true);
02298             }
02299         }
02300         
02301     return (false);
02302     } /*scriptkilled*/
02303 
02304 #endif
02305 
02306 
02307 static boolean scriptdebuggercallback (void) {
02308     
02309     register hdldebuggerrecord hd = debuggerdata;
02310     
02311     if (keyboardescape ()) /*user pressed cmd-period*/
02312         scriptkillbutton ();
02313     
02314     if (!(**hd).flscriptsuspended) /*get ready to resume running the script*/
02315         return (false);
02316     
02317     assert (!(**hd).flwindowclosed); /*if it was closed, script shouldn't be suspended*/
02318     
02319     /*
02320     if ((**hd).deferredbuttonnum > 0) /%a script button hit was deferred%/
02321         return (false);
02322     */
02323     
02324     return (true); /*keep getting events from the user*/
02325     } /*scriptdebuggercallback*/
02326 
02327 
02328 static boolean scriptdebuggereventloop (void) {
02329     
02330     /*
02331     8/12/91 dmb: make sure menus aren't dimmed
02332     
02333     2.1b3 dmb: handle not having threads
02334 
02335     5.0a19 dmb: sleep instead of yielding
02336     */
02337     
02338     register hdldebuggerrecord hd = debuggerdata;
02339     
02340     processnotbusy (); /*un-dim menus*/
02341     
02342     while ((**hd).flscriptsuspended) {
02343         
02344         if (flcanusethreads) {
02345             
02346             while (scriptdebuggercallback ())
02347                 if (!processsleep (getcurrentthreadglobals (), 10))
02348                     return (false);
02349             }
02350         else
02351             shelleventloop (&scriptdebuggercallback);
02352         
02353         /*
02354         if ((**hd).deferredbuttonnum > 0) { /%a background button click was deferred%/
02355             
02356             shellpushglobals ((**hd).deferredwindow);
02357             
02358             scriptbutton ((**hd).deferredbuttonnum);
02359             
02360             shellpopglobals ();
02361             
02362             (**hd).deferredbuttonnum = 0; /%consume it%/
02363             }
02364         */
02365         }
02366     
02367     return (true);
02368     } /*scriptdebuggereventloop*/
02369 
02370 
02371 static boolean scriptwindowmessage (bigstring bs) {
02372     
02373     /*
02374     display the message in the active script source window.
02375     */
02376     
02377     register hdldebuggerrecord hd = debuggerdata;
02378     register WindowPtr w = (**hd).scriptsourcestack [(**hd).topscriptsource - 1].pwindow;
02379     
02380     if (w == nil)
02381         return (false);
02382     
02383     if (!shellpushglobals (w))
02384         return (false);
02385     
02386     shellwindowmessage (bs);
02387     
02388     shellpopglobals ();
02389     
02390     return (true);
02391     } /*scriptwindowmessage*/
02392 
02393 
02394 boolean scriptdebugger (hdltreenode hnode) {
02395     
02396     /*
02397     allow the user to sniff around while a script is running.
02398     
02399     the interpreter is running the script linked into the indicated headrecord
02400     at the indicated line number.
02401     
02402     we won't automatically zoom the script window open, assume if it's closed
02403     the user isn't interested in debugging.
02404     
02405     returns false if the user pressed the Kill button, a signal to the
02406     interpreter to shut down the script.
02407     
02408     1/14/91 dmb: no longer bring script windows to front when following.  added 
02409     support for breakpoints in handlers.
02410     
02411     1/22/91 dmb: don't call shellshorteventloop at beginning.  we're already 
02412     doing enough background tasking, and we need to save and restore globals 
02413     around such calls (as is now done at the end of this routine).
02414     
02415     8/14/91 dmb: attempt to prevent multiple steps on single line when there's 
02416     more than one statement on it.
02417     
02418     5/20/92 dmb: now take hdltreenode parameter instead of its lnum, cnum pair.
02419     
02420     6/23/92 dmb: treat fllangerror as unconditional stop; this new case 
02421     can occur with the addition of scriptdebugerror routine
02422     */
02423     
02424     register hdldebuggerrecord hd = debuggerdata;
02425     register hdltreenode hn = hnode;
02426     register tytreetype op;
02427     register boolean flshowline = false;
02428     register boolean lflcontinue = true;
02429     short topscriptsource;
02430     tysourcerecord source;
02431     boolean flbreakpoint = false;
02432     long lastlnum = (**hd).lastlnum;
02433     long lnum = (**hn).lnum;
02434     short diff = 0;
02435     
02436     //shellshorteventloop (); /*suck up and process any waiting events*/
02437     
02438     if (languserescaped (true)) /*stop running the script immediately*/
02439         return (false);
02440     
02441     if ((**hd).flscriptkilled) /*user pressed kill button*/
02442         return (false);
02443     
02444     if ((**hd).flwindowclosed)
02445         return (true);
02446     
02447     op = (**hn).nodetype; /*test for "meaty" op*/
02448     
02449     if ((op == moduleop) || (op == noop) || (op == bundleop) || (op == localop)) /*never stop on these*/
02450         return (true);
02451     
02452     topscriptsource = (**hd).topscriptsource; /*move into local*/
02453     
02454     source = (**hd).scriptsourcestack [topscriptsource - 1]; /*move into local*/
02455     
02456     if (source.houtline == nil) /*an error occured when source was pushed*/
02457         return (true);
02458     
02459     if (fllangerror) {
02460         
02461         (**hd).fllangerror = true; /*for button updating*/
02462         
02463         flshowline = true;
02464         
02465         lflcontinue = false;
02466         }
02467     else {
02468         
02469         diff = topscriptsource - (**hd).sourcesteplevel;
02470         
02471         if ((diff == 0) && (lnum == lastlnum)) /*we haven't moved off of previous line*/
02472             return (scriptbackgroundtask (false));
02473         }
02474     
02475     if (diff <= 0)
02476         (**hd).lastlnum = lnum;
02477     
02478     if ((**hd).flstepping && !flshowline) { /*the debugger is turned on*/
02479         
02480         /*
02481         short diff = topscriptsource - (**hd).sourcesteplevel;
02482         */
02483         
02484         switch ((**hd).stepdir) {
02485                 
02486             case down:
02487                 if (diff == 0)
02488                     flshowline = lnum != lastlnum;
02489                 else
02490                     flshowline = diff < 0;
02491                 break;
02492             
02493             case right:
02494                 flshowline = diff != 0; /*if less then zero, In step fails and stops*/
02495                 break;
02496             
02497             case left:
02498                 flshowline = diff < 0;
02499                 break;
02500             
02501             case nodirection: /*following*/
02502                 flshowline = false;
02503                 break;
02504             
02505             default:
02506                 /* do nothing for up, flatup, flatdown, sorted, pageup, pagedown, pageleft, pageright */
02507                 break;
02508             }
02509         
02510         lflcontinue = !flshowline; /*continue if we aren't going to show this line*/
02511         
02512         if ((**hd).flfollowing)
02513             flshowline = true; /*show every line when following*/
02514         }
02515     
02516     if (lflcontinue) { /*so far, nothing is suspending the processor*/
02517         
02518         hdlheadrecord hnoderec;
02519         
02520         oppushoutline (source.houtline); /*set globals for breakpoint check*/
02521         
02522         if (opgetnthnode (lnum, &hnoderec) && (**hnoderec).flbreakpoint) /*breakpoint*/
02523             
02524             if (!opnestedincomment (hnoderec)) {
02525                 
02526                 flbreakpoint = true;
02527                 
02528                 flshowline = true;
02529                 
02530                 lflcontinue = false;
02531                 }
02532         
02533         oppopoutline ();
02534         }
02535     
02536     if (flshowline) {
02537         
02538         if (source.pwindow == nil) { /*closed, or never opened*/
02539             
02540             if (lflcontinue || fllangerror) { /*show line if window is open; don't bring to front*/
02541                 
02542                 hdlwindowinfo hinfo;
02543                 
02544                 /*
02545                 if (!langexternalwindowopen ((**source.hnode).val))
02546                 */
02547                 if (!(**source.houtline).flwindowopen)
02548                     goto exit;
02549                 
02550                 if (!shellfinddatawindow ((Handle) source.houtline, &hinfo))
02551                     goto exit;
02552                 
02553                 source.pwindow = (**hinfo).macwindow;
02554                 }
02555             else { /*we're stopping, so open window and bring to front*/
02556                 /*  
02557                 if (!scriptzoomscript (source.hnode, &source.pwindow))
02558                     return (true);
02559                 */
02560                 
02561                 if (!systemscripterrorroutine ((long) source.hnode, lnum, -1, nil, nil))
02562                     return (true);
02563                 
02564                 source.pwindow = getfrontwindow ();
02565                 }
02566             
02567             /*put updated version on stack*/
02568             
02569             (**hd).scriptsourcestack [topscriptsource - 1].pwindow = source.pwindow;
02570             }
02571         
02572         if (!lflcontinue && !fllangerror)
02573             windowbringtofront (source.pwindow);
02574         
02575         shellpushglobals (source.pwindow);
02576         
02577         opshowerror (lnum, -1);
02578         
02579         (**hd).lastlnum = lnum;
02580         
02581         (**hd).hbarcursor = (**outlinedata).hbarcursor;
02582         
02583         shellpopglobals ();
02584         }
02585     
02586     exit:
02587     
02588     if (lflcontinue) /*don't drop into event loop, continue running script*/
02589         return (scriptbackgroundtask (false));
02590     
02591     (**hd).flscriptsuspended = true;
02592     
02593     (**hd).flstepping = true;
02594     
02595     (**hd).flfollowing = false;
02596     
02597     scriptinvalbuttons ();
02598     
02599     if (flbreakpoint) {
02600         bigstring bs;
02601         
02602         langgetmiscstring (breakpointstring, bs);
02603         
02604         scriptwindowmessage (bs);
02605         }
02606     
02607     scriptdebuggereventloop ();
02608     
02609     if (flbreakpoint)
02610         scriptwindowmessage ((ptrstring) zerostring);
02611     
02612     return (!(**hd).flscriptkilled);
02613     } /*scriptdebugger*/
02614 
02615 
02616 boolean scriptpushsourcecode (hdlhashtable htable, hdlhashnode hnode, bigstring bsname) {
02617 #pragma unused (bsname)
02618 
02619     /*
02620     code execution is about to move into a new script.  hnode should be the 
02621     node in htable containing the script (external variable).
02622     
02623     2/4/91 dmb: hnode can now contain code -- a local handler.  we need to 
02624     use htable and the localtablestack to figure out which source the 
02625     code came from.  kind of ugly.
02626     
02627     2/5/91 dmb: too ugly, and incomplete.  yesterday's hack only worked 
02628     under the script debugger; we need to keep the langerrorcallbacks 
02629     consistant at all times.  new method: langaddhandler stuffs the error
02630     refcon into the code tree's value field, which is otherwise unused.
02631     
02632     4/8/93 dmb: make sure htable is local before assuming codevalue is local
02633     
02634     2.1b3 dmb: when synthesizing an errorrefcon for a code module, lookup 
02635     the associated error routine.
02636     */
02637     
02638     register hdlhashnode h = hnode;
02639     langerrorcallback errorcallback;
02640     
02641     errorcallback = &systemscripterrorroutine;
02642     
02643     if (h != nil)
02644         
02645         if (((**h).val.valuetype == codevaluetype) && (**htable).fllocaltable) { /*a local handler*/
02646             
02647             register hdltreenode hmodule = (**h).val.data.codevalue;
02648             
02649             h = (hdlhashnode) (**hmodule).nodeval.data.longvalue;
02650             
02651             langfinderrorrefcon ((long) h, &errorcallback);
02652             }
02653     
02654     if (debuggingcurrentprocess ()) {
02655         
02656         tysourcerecord source;
02657         boolean fljustloaded; /***needs memory management*/
02658         hdlwindowinfo hinfo;
02659         
02660         if (!scriptgetsourcerecord (h, &source)) {
02661             
02662             source.hnode = h;
02663 
02664             source.pwindow = nil; /*no window that we know about yet*/
02665             
02666             source.houtline = nil;
02667             
02668             if (h != nil) {
02669                 
02670                 if (shellfinddatawindow ((Handle) h, &hinfo)) {
02671 
02672                     source.pwindow = (**hinfo).macwindow;
02673 
02674                     source.houtline = (hdloutlinerecord) h;
02675                     }
02676                 else {
02677                 
02678                     if (isheadrecordhandle ((long) h))
02679                         meloadscriptoutline (menudata, (hdlheadrecord) h, &source.houtline, &fljustloaded);
02680                     else
02681                         opvaltoscript ((**h).val, &source.houtline);
02682                     }
02683                 }
02684             }
02685         
02686         if (!scriptpushsourcerecord (source))
02687             return (false);
02688         }
02689     
02690     return (langpusherrorcallback (errorcallback, (long) h));
02691     } /*scriptpushsourcecode*/
02692 
02693 
02694 boolean scriptpopsourcecode (void) {
02695     
02696     tysourcerecord source;
02697     
02698     if (debuggingcurrentprocess ()) {
02699         
02700         scriptpopsourcerecord (&source);
02701         
02702         if (source.pwindow != nil)
02703             scriptinvalbuttonsvisit (source.pwindow, nil);
02704         }
02705     
02706     return (langpoperrorcallback ());
02707     } /*scriptpopsourcecode*/
02708 
02709 
02710 static void scriptgetlevelname (bigstring bs) {
02711     
02712     /*
02713     1/8/91 dmb: if we're going to add the node name onto the table name, 
02714     we need to keep a handle to the node itself (or something) around so 
02715     that we can reliably delete the table, even after the code node is gone 
02716     and we can't regenerate the name.
02717     
02718     10/6/91 dmb make sure level names have two digits so they sort nicely.
02719     */
02720     
02721     register hdldebuggerrecord hd = debuggerdata;
02722     hdlhashnode h;
02723     short level = hashgetstackdepth ();
02724     hdlwindowinfo hinfo;
02725     bigstring title;
02726     
02727     langgetmiscstring (levelstring, bs);
02728     
02729     if (level <= 9) /*single digit; pad with 0*/
02730         pushchar ('0', bs);
02731     
02732     pushint (level, bs);
02733     
02734     pushstring (BIGSTRING ("\x02" ": "), bs); /*prepare to append script name*/
02735     
02736     h = (**hd).scriptsourcestack [(**hd).topscriptsource - 1].hnode;
02737     
02738     if (isheadrecordhandle ((long) h)) {
02739         
02740         opgetheadstring ((hdlheadrecord) h, title);
02741         
02742         pushstring (title, bs);
02743         }
02744     else if (shellfinddatawindow ((Handle) h, &hinfo)) {
02745 
02746         shellgetwindowtitle (hinfo, title); // 7.24.97 dmb: was windowgettitle
02747 
02748         pushstring (title, bs);
02749         }
02750     else if (h != nil)
02751         pushstring ((**h).hashkey, bs);
02752     else
02753         langgetmiscstring (unknownstring, bs);
02754     } /*scriptgetlevelname*/
02755 
02756 
02757 boolean scriptpushtable (hdlhashtable *htable) {
02758     
02759     /*
02760     1/23/91 dmb: use tablenewsystemtable instead of tablenewsubtable.  
02761     we want the dontsave flag set, and protection from user deletion
02762     */
02763     
02764     register hdldebuggerrecord hd = debuggerdata;
02765     register hdlhashtable ht;
02766     register boolean fl;
02767     bigstring bs;
02768     hdlhashnode hnode;
02769     
02770     if (!langcheckstacklimit (idlocalsstack, (**hd).toplocaltable, maxchainedlocals)) /*overflow!*/
02771         return (false);
02772     
02773     scriptgetlevelname (bs);
02774     
02775     pushhashtable (runtimestacktable);
02776     
02777     assert (!hashsymbolexists (bs));
02778     
02779     fl = tablenewsystemtable (runtimestacktable, bs, htable);
02780     
02781     if (fl)
02782         fl = hashlookupnode (bs, &hnode); /*should never fail if last call succeeded*/
02783     
02784     pophashtable ();
02785     
02786     if (!fl)
02787         return (false);
02788     
02789     ht = *htable; /*copy into register*/
02790     
02791     (**ht).fllocaltable = true;
02792     
02793     chainhashtable (ht); /*link it into the runtime stack*/
02794     
02795     (**hd).hlocaltable = ht;
02796     
02797     /*
02798     (**ht).hashtableformats = (**hd).localtableformatsstack [(**hd).toplocaltable];
02799     */
02800     
02801     (**hd).localtablestack [(**hd).toplocaltable++] = hnode;
02802     
02803     return (true);
02804     } /*scriptpushtable*/
02805 
02806 
02807 boolean scriptpoptable (hdlhashtable htable) {
02808 #pragma unused (htable)
02809 
02810     /*
02811     1/9/91 dmb: see comment in scriptgetlevelname...
02812     
02813     decided to keep a handle to the hash node key stored in a
02814     stack in debuggerdata.  this should be pretty fast, but the down side 
02815     is that the stack has an upper limit (not enforced -- potential crash), 
02816     while the locals chain doesn't.  there are at least three ways to avoid 
02817     this limit:
02818         
02819         1.  make the local name stack dynamically-sized.  since speed is
02820             important, handle resizing is best avoided.  a hassle.
02821         
02822         2.  use hashtablevisit to locate the value in runtimestacktable
02823             containing currenthashtable, and delete the node using its key.
02824         
02825         3.  use hashinversesearch to locate the node whose name begins 
02826             with "level xx", ignoring the rest of the string
02827     
02828     the current implementation is the easiest, and perhaps the fastest
02829     */
02830     
02831     register hdldebuggerrecord hd = debuggerdata;
02832     register hdlhashnode hnode;
02833     bigstring bs;
02834     
02835     hnode = (**hd).localtablestack [--(**hd).toplocaltable];
02836     
02837     /*
02838     (**hd).localtableformatsstack [(**hd).toplocaltable] = (**htable).hashtableformats;
02839     */
02840     
02841     gethashkey (hnode, bs);
02842     
02843     /*
02844     hashtablevisit (runtimestacktable, &scriptpoptablevisit);
02845     */
02846     
02847     unchainhashtable ();
02848     
02849     pushhashtable (runtimestacktable);
02850     
02851     if (!hashdelete (bs, true, false)) /*also disposes of the hashtable*/
02852         shellinternalerror (idscriptpoptablefailed, BIGSTRING ("\x15" "scriptpoptable failed"));
02853     
02854     pophashtable ();
02855     
02856     (**hd).hlocaltable = currenthashtable;
02857     
02858     return (true);
02859     } /*scriptpoptable*/
02860 
02861 
02862 static void scriptgetwindowtitle (hdlheadrecord hnode, bigstring bs) {
02863     
02864     bigstring bshead;
02865     
02866     getheadstring (hnode, bshead);
02867     
02868     setparseparams (bshead, nil, nil, nil);
02869         
02870     shellgetstring (scriptforstring, bs);
02871     
02872     parseparamstring (bs); /*insert script name into window title string*/
02873     } /*scriptgetwindowtitle*/ 
02874 
02875 
02876 boolean scriptgetdebuggingcontext (hdlhashtable *hcontext) {
02877     
02878     /*
02879     2.1b4: make our context available, if a script is suspended in the 
02880     debugger. it becomes locked until freed by the caller.  (this may 
02881     not be strictly necessary, but it seems prudent
02882     */
02883     
02884     register hdldebuggerrecord hd = debuggerdata;
02885     
02886     if (!(**hd).flscriptsuspended || !(**hd).flscriptrunning)
02887         return (false);
02888     
02889     *hcontext = (**hd).hlocaltable;
02890     
02891     if (*hcontext == nil)
02892         return (false);
02893     
02894     (**hd).flcontextlocked = true;
02895     
02896     scriptinvalbuttons ();
02897     
02898     return (true);
02899     } /*scriptgetdebuggingcontext*/
02900 
02901 
02902 void scriptunlockdebuggingcontext (void) {
02903     
02904     register hdldebuggerrecord hd = debuggerdata;
02905     
02906     (**hd).flcontextlocked = false;
02907     
02908     scriptinvalbuttons ();
02909     
02910     } /*scriptunlockdebuggingcontext*/
02911 
02912 
02913 boolean scriptzoomwindow (Rect rwindow, Rect rzoom, hdlheadrecord hcursor, WindowPtr *w) {
02914     
02915     /*
02916     5.0a10 dmb: don't zoom now. window isn't all the way set up.
02917     under windows, it matters.
02918     */
02919     
02920     bigstring bs; 
02921     
02922     scriptgetwindowtitle (hcursor, bs);
02923     
02924     if (!newchildwindow (idscriptconfig, menuwindowinfo, &rwindow, &rzoom, bs, w))
02925         return (false);
02926     
02927     return (true); //windowzoom (*w));
02928     } /*scriptzoomwindow*/
02929 
02930 
02931 #if 0
02932 
02933 static boolean scripthaslinkedtextroutine (hdlheadrecord hnode) {
02934     
02935     return (false); /*no linked text for script lines*/
02936     } /*scripthaslinkedtextroutine*/
02937 
02938 #endif
02939 
02940 
02941 static boolean optogglebreakpoint (hdlheadrecord hnode) {
02942     
02943     /*
02944     2.1b2 dmb: return new state
02945     
02946     5.0a25 dmb: dirty the outline...
02947 
02948     5.0.1 dmb: ...but clear the recently changed bit to avoid recompilation
02949     
02950     5.0.2 dmb: don't clear the recently changed bit; restore it.
02951     */
02952     
02953     boolean lflbreak = !(**hnode).flbreakpoint;
02954     boolean flrecentlychanged = (**outlinedata).flrecentlychanged;
02955     
02956     (**hnode).flbreakpoint = lflbreak;
02957     
02958     opinvalnode (hnode); /*inval the dirty line*/
02959     
02960     opdirtyoutline ();
02961     
02962     (**outlinedata).flrecentlychanged = flrecentlychanged;
02963     
02964     opupdatenow ();
02965     
02966     return (lflbreak);
02967     } /*optogglebreakpoint*/
02968 
02969 
02970 static boolean scriptcmdclick (hdlheadrecord hnode) {
02971     
02972     /*
02973     5.0a25 dmb: shift key will Go if enabled. return true if we consume
02974     the click
02975     
02976     5.0.2b19 dmb: preserve outline's text mode
02977     */
02978     
02979     hdloutlinerecord ho = outlinedata;
02980     
02981     if (keyboardstatus.floptionkey) {
02982     
02983         (**ho).fltextmode = (**ho).hbuffer != nil; //preserve text mode
02984         
02985         if (optogglebreakpoint (hnode)) { /*breakpoint set*/
02986             
02987             if (keyboardstatus.flshiftkey && scriptbuttonenabled (gobutton))
02988                 scriptgobutton ();
02989             }
02990         
02991         return (true);
02992         }
02993     
02994     return (false);
02995     } /*scriptcmdclick*/
02996 
02997 
02998 static boolean scriptdoubleclick (void) {
02999     
03000     /*
03001     12/9/91 dmb: new hook to make cmd-doubleclick behave like locals button
03002     */
03003     
03004     if (keyboardstatus.flcmdkey && !keyboardstatus.flcontrolkey)
03005         
03006         if (scriptbuttonenabled (localsbutton)) {
03007             
03008             register hdlhashtable ht = (**debuggerdata).hlocaltable;
03009             register boolean fl;
03010             
03011             if (ht != nil) {
03012                 
03013                 /*
03014                 flzoomlocalonly = true;
03015                 
03016                 pushhashtable (ht);
03017                 */
03018                 
03019                 fl = scriptlocalsbutton ();
03020                 
03021                 /*
03022                 pophashtable ();
03023                 
03024                 flzoomlocalonly = false;
03025                 */
03026                 
03027                 if (fl)
03028                     return (false); /*don't process click any further*/
03029                 }
03030             }
03031     
03032     return (true); /*process click normally*/
03033     } /*scriptdoubleclick*/
03034 
03035 
03036 static void scriptdisposescrap (hdloutlinerecord houtline) {
03037     
03038     opdisposeoutline (houtline, false);
03039     } /*scriptdisposescrap*/
03040 
03041 
03042 static boolean scriptexportscrap (hdloutlinerecord houtline, tyscraptype totype, Handle *hexport, boolean *fltempscrap) {
03043     
03044     *fltempscrap = true; /*usually the case*/
03045     
03046     switch (totype) {
03047         
03048         case scriptscraptype: /*export flat version for system scrap*/
03049             return (oppackoutline (houtline, hexport));
03050             
03051         case opscraptype:
03052             *hexport = (Handle) houtline; /*op and script scraps are the same*/
03053             
03054             *fltempscrap = false; /*it's the original, not a copy*/
03055             
03056             return (true);
03057         
03058         case textscraptype:
03059             /*
03060             return (opoutlinetonewtextscrap (houtline, hexport));
03061             */
03062             return (opgetlangtext (houtline, true, hexport));
03063             
03064         default:
03065             return (false);
03066         }
03067     } /*scriptexportscrap*/
03068 
03069 
03070 static boolean scriptsetscraproutine (hdloutlinerecord houtline) {
03071     
03072     return (shellsetscrap ((Handle) houtline, scriptscraptype, 
03073                 (shelldisposescrapcallback) &scriptdisposescrap,
03074                 (shellexportscrapcallback) &scriptexportscrap));
03075     } /*scriptsetscraproutine*/
03076 
03077 
03078 static boolean scriptgetscraproutine (hdloutlinerecord *houtline, boolean *fltempscrap) {
03079     
03080     Handle hscrap;
03081     tyscraptype scraptype;
03082     
03083     if (!shellgetscrap (&hscrap, &scraptype))
03084         return (false);
03085     
03086     if (scraptype == scriptscraptype) {
03087         
03088         *houtline = (hdloutlinerecord) hscrap;
03089         
03090         *fltempscrap = false; /*we're returning a handle to the actual scrap*/
03091         
03092         return (true);
03093         }
03094     
03095     return (shellconvertscrap (opscraptype, (Handle *) houtline, fltempscrap));
03096     } /*scriptgetscraproutine*/
03097 
03098 
03099 static boolean scriptcommentvisit (hdlheadrecord hnode, void *refcon) {
03100 #pragma unused (refcon)
03101 
03102     register hdlheadrecord h = hnode;
03103     bigstring bs;
03104     
03105     getheadstring (h, bs);
03106     
03107     if (!isemptystring (bs) && bs [1] == chcomment) {
03108         
03109         pullfromhandle ((**h).headstring, 0, 1, nil); /*don't use opsetheadstring; don't want callbacks invoked*/
03110         
03111         if (!opnestedincomment (h))
03112             (**h).flcomment = true;
03113         }
03114     
03115     return (true);
03116     } /*scriptcommentvisit*/
03117 
03118 
03119 static boolean scripttexttooutlineroutine (hdloutlinerecord houtline, Handle hscrap, hdlheadrecord *hnode) {
03120     
03121     /*
03122     2.1b4 dmb: new feature: we strip braces and semicolons out of pasted (or inserted) 
03123     text automatically using langstriptextsyntax. then we convert comment lines to 
03124     true comments.
03125     */
03126     
03127     boolean flusertalk = (**houtline).outlinesignature == typeLAND;
03128     
03129     if (flusertalk)
03130         langstriptextsyntax (hscrap);
03131     
03132     if (!optextscraptooutline (houtline, hscrap, hnode))
03133         return (false);
03134     
03135     if (flusertalk)
03136         opsiblingvisiter (*hnode, false, &scriptcommentvisit, nil);
03137     
03138     return (true);
03139     } /*scripttexttooutlineroutine*/
03140 
03141 
03142 static boolean scriptscraphook (Handle hscrap) {
03143     
03144     /*
03145     if our private type is on the external clipboard, set the internal 
03146     scrap to it.
03147     */
03148     
03149     if (getscrap (scriptscraptype, hscrap)) {
03150         
03151         hdloutlinerecord houtline;
03152         
03153         if (opunpackoutline (hscrap, &houtline))
03154             scriptsetscraproutine (houtline);
03155         
03156         return (false); /*don't call any more hooks*/
03157         }
03158     
03159     return (true); /*keep going*/
03160     } /*scriptscraphook*/
03161 
03162 
03163 void scriptsetcallbacks (hdloutlinerecord houtline) {
03164     
03165     /*
03166     1/31/97 dmb: don't need to set setscrollbarsroutine anymore
03167     */
03168     
03169     register hdloutlinerecord ho = houtline;
03170     
03171     /*
03172     (**ho).setscrollbarsroutine = (callback) &scriptsetscrollbarsroutine;
03173     
03174     (**ho).drawlinecallback = &scriptdrawline;
03175     
03176     (**ho).postdrawlinecallback = &truenoop;
03177     
03178     (**ho).haslinkedtextcallback = &scripthaslinkedtextroutine;
03179     */
03180     
03181     (**ho).cmdclickcallback = &scriptcmdclick;
03182     
03183     (**ho).doubleclickcallback = &scriptdoubleclick;
03184     
03185     (**ho).setscrapcallback = (opsetscrapcallback) &scriptsetscraproutine;
03186     
03187     (**ho).getscrapcallback = (opgetscrapcallback) &scriptgetscraproutine;
03188     
03189     (**ho).texttooutlinecallback = (optexttooutlinecallback) &scripttexttooutlineroutine;
03190 
03191     } /*scriptsetcallbacks*/
03192 
03193 
03194 boolean scriptsetdata (WindowPtr w, hdlheadrecord hnode, hdloutlinerecord houtline) {
03195     
03196     /*
03197     called by the menu editor to establish script content
03198     
03199     2/28/91 dmb: outline must inherit activeness from windowinfo
03200     */
03201     
03202     register hdloutlinerecord ho = houtline;
03203     hdlwindowinfo hinfo;
03204     bigstring bs;
03205     
03206     getwindowinfo (w, &hinfo);
03207     
03208     (**hinfo).hdata = (Handle) ho;
03209     
03210     (**ho).outlinerect = (**hinfo).contentrect;
03211     
03212     (**ho).flactive = (**hinfo).flwindowactive;
03213     
03214     scriptsetcallbacks (ho);
03215     
03216     shellpushglobals (w);
03217     
03218     pushemptyclip ();
03219     
03220     /*
03221     opgetdisplayinfo ();
03222     */
03223     
03224     opdirtymeasurements (); //6.0a14 dmb
03225     
03226     opsetctexpanded (ho); //6.0a14 dmb
03227     
03228     opredrawscrollbars ();  // 1/31/97 dmb - was: scriptsetscrollbarsroutine ();
03229     
03230     opschedulevisi ();
03231     
03232     opactivate ((**hinfo).flwindowactive);
03233     
03234     popclip ();
03235     
03236     invalrect ((**ho).outlinerect);
03237     
03238     eraserect ((**ho).outlinerect);
03239     
03240     shellpopglobals ();
03241     
03242     scriptgetwindowtitle (hnode, bs);
03243     
03244     shellsetwindowtitle (hinfo, bs); // 7.24.97 dmb: was windowsettitle
03245     
03246     return (true);
03247     } /*scriptsetdata*/
03248 
03249 
03250 static void scriptresize (void) {
03251     
03252     opresize ((**outlinewindowinfo).contentrect);
03253     
03254     #ifdef WIN95VERSION
03255         opupdatenow ();
03256     #endif
03257     } /*scriptresize*/
03258 
03259 
03260 static boolean scriptgetvariablepath (hdlexternalvariable hvariable, bigstring bspath) {
03261     
03262     /*
03263     return the full path to the given variable
03264     */
03265     
03266     hdlhashtable htable;
03267     bigstring bsname;
03268     
03269     if (!langexternalfindvariable (hvariable, &htable, bsname))
03270         return (false);
03271     
03272     return (langexternalgetquotedpath (htable, bsname, bspath));
03273     } /*scriptgetvariablepath*/
03274 
03275 
03276 static boolean scriptverifycompilation () {
03277     
03278     /*
03279     9/25/91 dmb: new feature -- when a script window is closed, we give the 
03280     call a special script in the database.  if the script is there and 
03281     returns true, we'll try to recompile the script.
03282     
03283     if compilation is attempted but fails, return false; otherwise return true.
03284     
03285     10/1/91 dmb: don't need to do anything if script hasn't yet been compiled.
03286     */
03287     
03288     register hdloutlinerecord ho = outlinedata;
03289     hdlexternalvariable hvariable;
03290     hdlhashnode hnode;
03291     hdltreenode hcode;
03292     bigstring bspath;
03293     bigstring bsscript;
03294     bigstring bsresult;
03295     
03296     if (flinhibitclosedialogs) /*not allowed to do verification*/
03297         return (true);
03298     
03299     if (!(**ho).flrecentlychanged) /*no changes to compile*/
03300         return (true);
03301     
03302     hvariable = (hdlexternalvariable) (**ho).outlinerefcon;
03303     
03304     if (!scriptfindhashnode (hvariable, &hnode))
03305         return (true);
03306     
03307     if (!langexternalvaltocode ((**hnode).val, &hcode)) /*doesn't contain code*/
03308         return (true);
03309     
03310     if (hcode == nil) /*never been compiled; don't need to re-compile*/
03311         return (true);
03312     
03313     if (!scriptgetvariablepath (hvariable, bspath))
03314         return (true);
03315     
03316     /*
03317     parsedialogstring (bsclosescript, bspath, nil, nil, nil, bsscript);
03318     */
03319     if (!getsystemtablescript (idcompilewindowscript, bsscript))
03320         return (true);
03321     
03322     parsedialogstring (bsscript, bspath, nil, nil, nil, bsscript);
03323     
03324     if (!langrunstringnoerror (bsscript, bsresult)) /*couldn't find/run the script*/
03325         return (true);
03326     
03327     if (equalstrings (bsresult, BIGSTRING ("\x01" "3"))) /*yes/no/cancel was cancelled*/
03328         return (false);
03329     
03330     if (!equalstrings (bsresult, bstrue) && !equalstrings (bsresult, BIGSTRING ("\x01" "1"))) /*script didn't ask for compilation*/
03331         return (true);
03332     
03333     langerrorclear (); /*be sure error window is empty*/
03334     
03335     /*
03336     if (!processyieldtoagents ()) /%file closed while agents were finishing up%/
03337         return (false);
03338     */
03339     
03340     return (scriptcompiler (hnode, &hcode)); /*try to recompile*/
03341     } /*scriptverifycompilation*/
03342 
03343 
03344 static boolean scriptclose (void) {
03345     
03346     /*
03347     12/28/90 dmb: new logic includes support for script source stack:
03348     
03349     if the main script window is closed, and we're suspended, we kill 
03350     the script.  if we're not suspended, we keep going but don't follow
03351     
03352     if any other script window in the current stack is closed, we keep 
03353     going.
03354     
03355     6/20/92 dmb: search scriptsourcestack for the outline, not the window; 
03356     houtline is set in every frame & must be checked; pwindow may still be nil.
03357     
03358     2.1b1 dmb: make sure we stop recording as necessary
03359 
03360     5.0b11 dmb: don't call mescriptwindowclosed from here. the globals 
03361     aren't set.
03362     */
03363     
03364     register hdldebuggerrecord hd = debuggerdata;
03365     register short ix;
03366     register boolean flinmenubar;
03367     
03368     flinmenubar = scriptinmenubar ();
03369     
03370     if (scriptinstallable ()) {
03371         
03372         if (!scriptverifycompilation ())
03373             return (false);
03374         }
03375     
03376     for (ix = 0; ix < (**hd).topscriptsource; ix++) { /*see if it's any window in stack*/
03377         
03378         if ((**hd).scriptsourcestack [ix].houtline == outlinedata) { /*yup*/
03379             
03380             (**hd).scriptsourcestack [ix].pwindow = nil; /*clear it*/
03381             
03382             if (!(**outlinedata).fldirty) /*outline is about to be disposed*/
03383                 (**hd).scriptsourcestack [ix].houtline = nil;
03384             
03385             if (ix == 0) { /*user is closing main source window*/
03386                 
03387                 if ((**hd).flscriptsuspended)
03388                     scriptkillbutton ();
03389                 else
03390                     scriptgobutton ();
03391                 
03392             #ifdef flcomponent
03393                 if ((**hd).flrecording)
03394                     scriptstoprecordbutton ();
03395             #endif
03396             
03397                 (**hd).flwindowclosed = true;
03398                 }
03399             }
03400         }
03401     
03402     if (flinmenubar)
03403         return (true);
03404     else
03405         return (opverbclose ());
03406     } /*scriptclose*/
03407 
03408 
03409 static boolean scriptgetundoglobals (long *globals) {
03410     
03411     return (opeditgetundoglobals (globals));
03412     } /*scriptgetundoglobals*/
03413 
03414 
03415 static boolean scriptsetundoglobals (long globals, boolean flundo) {
03416     
03417     return (opeditsetundoglobals (globals, flundo));
03418     } /*scriptsetundoglobals*/
03419 
03420 
03421 static void scriptidle (void) {
03422     
03423     opidle ();
03424     } /*scriptidle*/
03425 
03426 
03427 static boolean scriptadjustcursor (Point pt) {
03428     
03429     return (opsetcursor (pt));
03430     } /*scriptadjustcursor*/
03431 
03432 
03433 static boolean scriptsetfont (void) {
03434     
03435     return (opsetfont ((**outlinewindowinfo).selectioninfo.fontnum));
03436     } /*scriptsetfont*/
03437     
03438 
03439 static boolean scriptsetsize (void) {
03440     
03441     return (opsetsize ((**outlinewindowinfo).selectioninfo.fontsize));
03442     } /*scriptsetsize*/
03443 
03444 
03445 static boolean scriptsetselectioninfo (void) {
03446     
03447     return (opsetselectioninfo ());
03448     } /*scriptsetselectioninfo*/
03449 
03450 
03451 static boolean scriptsearch (void) {
03452     
03453     long refcon = (**outlinedata).outlinerefcon;
03454     
03455     startingtosearch (refcon);
03456     
03457     if (opflatfind (false, searchshouldwrap (refcon)))
03458         return (true);
03459     
03460     if (!searchshouldcontinue (refcon))
03461         return (false);
03462     
03463     if (scriptindatabase ()) /*lives in symbol table -- see scriptinstallable*/
03464         return (langexternalcontinuesearch ((hdlexternalvariable) refcon));
03465     
03466     if (scriptinmenubar ())
03467         return (mecontinuesearch ((**outlinewindowinfo).parentwindow, (hdlheadrecord) refcon));
03468 
03469     return (false);
03470     } /*scriptsearch*/
03471 
03472 
03473 static boolean scriptruncursor (void) {
03474     
03475     return (opverbruncursor ());
03476     } /*scriptruncursor*/
03477 
03478 
03479 static boolean scriptgetoutinesize (long *width, long *height) {
03480     
03481     short buttonswidth;
03482     
03483     opgetoutinesize (width, height);
03484     
03485     shellbuttongetoptimalwidth (&buttonswidth);
03486     
03487     *width = max (*width, buttonswidth);
03488     
03489     return (true);
03490     } /*scriptgetoutinesize*/
03491 
03492 
03493 static boolean scriptkeystroke (void) {
03494     
03495     /*
03496     4/7/97 dmb: handle standalone scripts
03497     */
03498 
03499     register hdloutlinerecord ho = outlinedata;
03500     
03501     if (scriptindatabase ()) { /*lives in symbol table -- see scriptinstallable*/
03502         
03503         if (langexternalsurfacekey ((hdlexternalvariable) (**ho).outlinerefcon))
03504             return (true);
03505         }
03506 
03507     if (scriptinmenubar ()) { /*lives in menubar*/
03508         
03509         #ifdef MACVERSION
03510         if (keyboardstatus.chkb == chenter)
03511             
03512             if (keyboardstatus.flcmdkey && keyboardstatus.flshiftkey) {
03513         #endif
03514         #ifdef WIN95VERSION
03515         if (keyboardstatus.chkb == chbackspace)
03516             
03517             if (keyboardstatus.flshiftkey) {
03518         #endif
03519                 shellbringtofront ((**outlinewindowinfo).parentwindow);
03520                 
03521                 if (keyboardstatus.floptionkey)
03522                     shellclosewindow (outlinewindow);
03523                 
03524                 return (true);
03525                 }
03526         }
03527     
03528     return (opkeystroke ()); /*this operation may dirty the outlinerecord*/
03529     } /*scriptkeystroke*/
03530 
03531 
03532 static boolean scripttitleclick (Point pt) {
03533     
03534     if (scriptindatabase ()) /*lives in symbol table -- see scriptinstallable*/
03535         return (langexternaltitleclick (pt, (hdlexternalvariable) (**outlinedata).outlinerefcon));
03536     
03537     if ((**outlinewindowinfo).parentwindow == nil)
03538         return (false);
03539 
03540     if (scriptinmenubar ()) { /*do same popup as parent window would*/
03541         
03542         if (cmdkeydown () || ismouserightclick()) {
03543         
03544             if (shellpushglobals ((**(**outlinewindowinfo).parentwindow).macwindow)) {
03545                 
03546                 hdlexternalvariable hv = (hdlexternalvariable) (**menudata).menurefcon;
03547                 
03548                 shellpopglobals ();
03549                 
03550                 pt.v += 50; /*hack: this signals special case*/
03551                 
03552                 tableclienttitlepopuphit (pt, hv);
03553                 
03554                 return (true);
03555                 }
03556             }
03557         }
03558     
03559     if (!mousedoubleclick ())
03560         return (false);
03561     
03562     shellbringtofront ((**outlinewindowinfo).parentwindow);
03563     
03564     if (keyboardstatus.floptionkey)
03565         shellclosewindow (outlinewindow);
03566     
03567     return (true); /*consumed*/
03568     } /*scripttitleclick*/
03569 
03570 
03571 #ifdef flcomponent
03572 
03573 typedef boolean (*tyscriptvisitcallback) (OSType, bigstring, long);
03574 
03575 
03576 static boolean scriptvisitservers (tyscriptvisitcallback visit, long refcon) {
03577     
03578     ComponentDescription desc, info;
03579     Component comp = nil;
03580     Handle hname;
03581     bigstring bsname;
03582     
03583     if (!havecomponentmanager ())
03584         return (false);
03585     
03586     if (!newemptyhandle (&hname))
03587         return (false);
03588     
03589     clearbytes (&desc, longsizeof (desc));
03590     
03591     desc.componentType = kOSAComponentType;
03592     
03593     desc.componentFlags = kOSASupportsCompiling;
03594     
03595     desc.componentFlagsMask = kOSASupportsCompiling;
03596     
03597     while (true) {
03598         
03599         comp = FindNextComponent (comp, &desc);
03600         
03601         if (comp == nil)
03602             break;
03603         
03604         if (GetComponentInfo (comp, &info, hname, nil, nil) != noErr)
03605             continue;
03606         
03607         if (info.componentSubType == kOSAGenericScriptingComponentSubtype)
03608             continue;
03609         
03610         copyheapstring ((hdlstring) hname, bsname);
03611         
03612         if (!(*visit) (info.componentSubType, bsname, refcon)) /*terminate visit*/
03613             break;
03614         }
03615     
03616     disposehandle (hname);
03617     
03618     return (comp == nil); /*true if all components visited*/
03619     } /*scriptvisitservers*/
03620 
03621 
03622 static long *serverarray;
03623 
03624 
03625 typedef struct tyfillservercallbackdata {
03626     
03627     hdlmenu hmenu;
03628     
03629     short checkeditem;
03630     
03631     long ctmenus;
03632     
03633     long signature;
03634     } tyfillservercallbackdata;
03635 
03636 
03637 static boolean scriptfillservervisit (OSType subtype, bigstring bsname, long refcon) {
03638     
03639     tyfillservercallbackdata *cbd = (tyfillservercallbackdata *) refcon;
03640 
03641     if (!pushpopupitem ((*cbd).hmenu, bsname, true, 0)) /*terminate visit on error*/
03642         return (false);
03643     
03644     serverarray [(*cbd).ctmenus++] = subtype;
03645     
03646     if (subtype == (OSType)(*cbd).signature)
03647         (*cbd).checkeditem = (*cbd).ctmenus;
03648     
03649     return (true);
03650     } /*scriptfillservervisit*/
03651 
03652 
03653 static boolean scriptserverpopupselect (hdlmenu hmenu, short itemselected) {
03654 #pragma unused (hmenu)
03655 
03656     /*
03657     2.1b11 dmb: dirty the outline
03658     */
03659     
03660     register hdloutlinerecord ho = outlinedata;
03661     register OSType signature = serverarray [itemselected - 1];
03662     
03663     if ((**ho).outlinesignature != signature) {
03664         
03665         (**ho).outlinesignature = signature;
03666         
03667         opdirtyoutline ();
03668         }
03669     
03670     return (true);
03671     } /*scriptserverpopupselect*/
03672 
03673 
03674 static boolean scriptfillserverpopup (hdlmenu hmenu, short *checkeditem) {
03675     
03676     tyfillservercallbackdata cbd;
03677     
03678     cbd.hmenu = hmenu;
03679     
03680     cbd.checkeditem = -1; /*default*/
03681     
03682     cbd.ctmenus = 0;
03683     
03684     cbd.signature = (**outlinedata).outlinesignature;
03685     
03686     if (!scriptvisitservers (&scriptfillservervisit, (long) &cbd))
03687         return (false);
03688     
03689     *checkeditem = cbd.checkeditem;
03690     
03691     return (true);
03692     } /*scriptfillserverpopup*/
03693 
03694 #endif
03695 
03696 #define flstacktrace 0
03697 
03698 #if flstacktrace
03699 
03700 static boolean scripterrorpopupselect (hdlmenu hmenu, short itemselected) {
03701     
03702     /*
03703     register hdlerrorstack hs = langerrorgetstack ();
03704     */
03705     register hdlerrorstack hs = langcallbacks.scripterrorstack;
03706     register short ix = itemselected - 1;
03707     tyerrorrecord *pe;
03708     
03709     if (hs == nil)
03710         return (false);
03711     
03712     pe = &(**hs).stack [ix];
03713     
03714     return ((*(*pe).errorcallback) ((*pe).errorrefcon, 0, 0, nil, nil));
03715     } /*scripterrorpopupselect*/
03716 
03717 
03718 static boolean scriptfillerrorpopup (hdlmenu hmenu, short *checkeditem) {
03719     
03720     /*
03721     register hdlerrorstack hs = langerrorgetstack ();
03722     */
03723     register hdlerrorstack hs = langcallbacks.scripterrorstack;
03724     register short ix;
03725     register short ixtop;
03726     hdlhashtable htable;
03727     bigstring bsname;
03728     
03729     if (hs == nil)
03730         return (false);
03731     
03732     ixtop = (**hs).toperror;
03733     
03734     for (ix = 0; ix < ixtop; ++ix) {
03735         
03736         tyerrorrecord *pe = &(**hs).stack [ix];
03737         
03738         if ((*pe).errorcallback == nil)
03739             copystring (BIGSTRING ("\x02" "(-"), bsname);
03740         else
03741             if (!(*(*pe).errorcallback) ((*pe).errorrefcon, 0, 0, &htable, bsname))
03742                 return (false);
03743         
03744         if (!pushpopupitem (hmenu, bsname, true)) /*terminate visit on error*/
03745             return (false);
03746         }
03747     
03748     *checkeditem = ixtop;
03749     
03750     return (true);
03751     } /*scriptfillerrorpopup*/
03752 #endif
03753 
03754 
03755 static void scriptupdateserverpopup (void) {
03756     
03757     Rect r;
03758     bigstring bs;
03759     long signature;
03760     
03761     scriptgetpopuprect (&r);
03762     
03763     framerect (r);
03764     
03765     insetrect (&r, 1, 1);
03766     
03767     eraserect (r);
03768     
03769     #if flstacktrace
03770     //hs = langcallbacks.scripterrorstack; /*langerrorgetstack ();*/
03771     
03772     if (scriptinruntimestack () /*hs != nil*/ ) /*popup is stack, not language*/
03773         copystring (BIGSTRING ("\x06" "Stack:"), bs);
03774     else {
03775     #endif
03776     
03777     signature = (**outlinedata).outlinesignature;
03778     
03779     if (!scriptgettypename (signature, bs)) { /*didn't find it*/
03780         
03781         if (signature == typeLAND)
03782             langgetstringlist (usertalkcomponentstring, bs);
03783         else
03784             langgetstringlist (unavailablestring, bs);
03785         }
03786     
03787     pushstyle (geneva, 9, 0);
03788     
03789     centerstring (r, bs);
03790     
03791     popstyle ();
03792     } /*scriptupdateserverpopup*/
03793 
03794 
03795 static boolean scriptmousedown (Point pt, tyclickflags flags) {
03796     
03797     /*
03798     12/12/91 dmb: click in message area restores PC in debugger.  for now, 
03799     we don't bother making sure that the current script window is the one 
03800     that the PC is in, since we make sure that the node is safe before trying 
03801     to move to it.  a nice addition to this feature would be to bring the PC 
03802     window to the front and select the cursor.
03803     
03804     2.1b8 dmb: use opexpandto, not opmoveto when user clicks in message area.
03805     
03806     5.0b10 dmb: update server popup display after its clicked
03807     */
03808     
03809     Rect rmsg;
03810     boolean flgeneva9 = false;
03811     
03812     #if TARGET_API_MAC_CARBON == 1
03813     
03814         flgeneva9 = true;
03815         
03816     #endif
03817     
03818     scriptgetpopuprect (&rmsg);
03819     
03820     if (pointinrect (pt, rmsg)) { /*click in message area*/
03821         
03822         register hdldebuggerrecord hd = debuggerdata;
03823         
03824         if ((**hd).flscriptsuspended) { /*we're in debugger waiting for input*/
03825             
03826             if (opnodeinoutline ((**hd).hbarcursor)) { /*very safely determined that node is valid*/
03827                 
03828                 opexpandto ((**hd).hbarcursor);
03829                 
03830                 opsettextmode (false);
03831                 }
03832             }
03833         
03834         bundle {
03835             
03836         #if flstacktrace
03837             if (scriptinruntimestack ()) /*popup is of stack, not language*/
03838                             
03839                 popupmenuhit (rmsg, flgeneva9, &scriptfillerrorpopup, &scripterrorpopupselect);
03840                 
03841             else {
03842         #endif
03843         
03844             #ifdef flcomponent
03845                 serverarray = (long *) NewPtr (sizeof (long) * 100);
03846                 
03847                 if (popupmenuhit (rmsg, flgeneva9, &scriptfillserverpopup, &scriptserverpopupselect)) {
03848                     
03849                     scriptinvalbuttons ();
03850                     
03851                     scriptupdateserverpopup (); 
03852                     }
03853                 
03854                 DisposePtr ((Ptr) serverarray);
03855             #endif
03856                 }
03857         #if flstacktrace
03858             }
03859         #endif
03860         
03861         return (true);
03862         }
03863     
03864     opmousedown (pt, flags);
03865     
03866     return (true);
03867     } /*scriptmousedown*/
03868     
03869 
03870 static boolean scriptcmdkeyfilter (char chkb) {
03871 
03872     return (opcmdkeyfilter (chkb)); /*this operation may dirty the outlinerecord*/
03873     } /*scriptcmdkeyfilter*/
03874     
03875     
03876 static boolean scriptcut (void) {
03877 
03878     return (opcut ()); /*this operation may dirty the outlinerecord*/
03879     } /*scriptcut*/
03880     
03881     
03882 static boolean scriptpaste (void) {
03883 
03884     return (oppaste ()); /*this operation may dirty the outlinerecord*/
03885     } /*scriptpaste*/
03886     
03887     
03888 static boolean scriptclear (void) {
03889 
03890     return (opclear ()); /*this operation may dirty the outlinerecord*/
03891     } /*scriptclear*/
03892 
03893 
03894 static boolean scriptgetvariable (hdlexternalvariable *hvariable) {
03895     
03896     /*
03897     if (!scriptindatabase ())
03898         return (false);
03899     */
03900     
03901     return (opverbgetvariable (hvariable));
03902     } /*scriptgetvariable*/
03903 
03904 
03905 static boolean scriptgettargetdata (short id) {
03906     
03907     /*
03908     don't allow verbs that are being executed by the debugger script being 
03909     debugged to act on itself
03910     
03911     12/13/91 dmb: updated to handle case where Run button has been hit.  we 
03912     still want to exclude ourselves from being the target
03913     */
03914     
03915     /*
03916     if (debuggingcurrentprocess () && scriptinruntimestack())
03917         return (false);
03918     */
03919     
03920     if (processisoneshot (false) && (currentprocess == (**debuggerdata).scriptprocess))
03921         if (scriptinruntimestack ())
03922             return (false);
03923     
03924     return (opverbgettargetdata (id));
03925     } /*scriptgettargetdata*/
03926 
03927 
03928 boolean scriptbackgroundtask (boolean flresting) {
03929     
03930     /*
03931     1/22/91 dmb: a new approach to dealing with massive context changes in 
03932     background tasks.  we try to save and restore context globals (via 
03933     langcallbacks) around the backgrounding calls.  so even if another 
03934     file is opened or brought to the front, the current process will retain 
03935     its context.  if the context can't be restored (i.e. the file was closed), 
03936     we return false and the execution thread will return quickly.
03937 
03938     5.1.5 dmb: yield if a new thread is waiting
03939     */
03940     
03941     boolean fldialogrunning;
03942     boolean fl = true;
03943     
03944     if (scriptbackgroundenabled () && (flresting || processtimesliceelapsed () || (threadiswaiting () && processthreadcount () < 7))) {
03945         
03946         fldialogrunning = langdialogrunning ();
03947         
03948         if (fldialogrunning) /*modal dialogs need to get all events*/
03949             shellblockevents ();
03950         
03951         flscriptresting = flresting;
03952         
03953         fl = processyield ();
03954         
03955         flscriptresting = false;
03956         
03957         if (fldialogrunning)
03958             shellpopevents ();
03959         
03960     //  scriptresetbackgroundtime ();
03961         }
03962     
03963     return (fl);
03964     } /*scriptbackgroundtask*/
03965 
03966 
03967 static boolean scriptresetrects (hdlwindowinfo hinfo) {
03968     
03969     register hdlwindowinfo hw = hinfo;
03970     Rect rmsg;
03971     short width;
03972     
03973     shellresetwindowrects (hw);
03974     
03975     rmsg = (**hw).messagerect;
03976     
03977     width = rmsg.right - rmsg.left;
03978     
03979     if (width > 100)
03980         /*
03981         (**hw).messagerect.left += 72;
03982         */
03983         (**hw).messagerect.right -= 72;
03984         
03985     return (true);
03986     } /*scriptresetrects*/
03987 
03988 
03989 typedef struct tyfindservercallbackdata {
03990     
03991     ptrstring pname;
03992     
03993     long signature;
03994     } tyfindservercallbackdata;
03995 
03996 
03997 static boolean scriptfindsubtypevisit (OSType subtype, bigstring bsname, long refcon) {
03998     
03999     tyfindservercallbackdata *cbd = (tyfindservercallbackdata *) refcon;
04000     
04001     if (subtype == (OSType) (*cbd).signature) {
04002         
04003         copystring (bsname, (*cbd).pname);
04004         
04005         return (false); /*terminate visit*/
04006         }
04007     
04008     return (true); /*keep visiting*/
04009     } /*scriptfindsubtypevisit*/
04010 
04011 
04012 boolean scriptgettypename (long signature, bigstring bsname) {
04013     
04014     /*
04015     2006-02-22 creedon: if flcomponent is false then fallback to hard coded
04016                 values, useful on Windows
04017 
04018     visit all OSA servers and find the name of the one who's subtype 
04019     matches the given signature
04020     */
04021     
04022     tyfindservercallbackdata cbd;
04023     
04024     setemptystring (bsname);
04025     
04026     cbd.pname = bsname;
04027     
04028     cbd.signature = signature;
04029     
04030 #ifdef flcomponent
04031     scriptvisitservers (&scriptfindsubtypevisit, (long) &cbd);
04032 #else
04033     switch (signature) {
04034         case typeLAND:
04035             copystring (BIGSTRING ("\x08" "UserTalk"), bsname);
04036             break;
04037 
04038         case 'ascr':
04039             copystring (BIGSTRING ("\x0B" "AppleScript"), bsname);
04040             break;
04041         } /* switch */
04042 
04043     
04044 #endif
04045     
04046     return (!isemptystring (bsname));
04047     } /*scriptgettypename*/
04048 
04049 
04050 static boolean scriptfindnamevisit (OSType subtype, bigstring bsname, long refcon) {
04051     
04052     tyfindservercallbackdata *cbd = (tyfindservercallbackdata *) refcon;
04053     
04054     if (equalidentifiers (bsname, (*cbd).pname)) {
04055         
04056         (*cbd).signature = subtype;
04057         
04058         return (false); /*terminate visit*/
04059         }
04060     
04061     return (true); /*keep visiting*/
04062     } /*scriptfindnamevisit*/
04063 
04064 
04065 boolean scriptgetnametype (bigstring bsname, long *signature) {
04066     
04067     /*
04068     2006-02-22 creedon: if flcomponent is false then fallback to hard coded
04069                 values, useful on Windows
04070 
04071     visit all OSA servers and find the subtype of the one who's name
04072     matches bsname
04073     */
04074     
04075 #ifdef flcomponent
04076 
04077     tyfindservercallbackdata cbd;
04078     
04079     cbd.pname = bsname;
04080     
04081     cbd.signature = 0;
04082     
04083     scriptvisitservers (&scriptfindnamevisit, (long) &cbd);
04084     
04085     *signature = cbd.signature;
04086     
04087     return (cbd.signature != 0);
04088 #else
04089     if (comparestrings (bsname, BIGSTRING ("\x08" "UserTalk")) == 0) {
04090         *signature = typeLAND;
04091         return (true);
04092     }
04093     else if (comparestrings (bsname, BIGSTRING ("\x0B" "AppleScript")) == 0) {
04094         *signature = 'ascr';
04095         return (true);
04096     }
04097     else
04098         return (false);
04099 #endif
04100     } /*scriptgetnametype*/
04101 
04102 
04103 static void scriptupdate (void) {
04104 
04105     /*
04106     7.0b26 PBS: update the script language popup on Macs only -- since
04107     it doesn't exist on Windows. This was the site of a display glitch on Windows.
04108     */
04109 
04110     #ifdef MACVERSION
04111     
04112         scriptupdateserverpopup ();
04113     
04114     #endif
04115     
04116     opupdate ();
04117     } /*scriptupdate*/
04118 
04119 
04120 static boolean scriptdirtyhook (void) {
04121     
04122     /*
04123     this is where we hook into events that dirty things.  if a langerror 
04124     window is open, we gray out its script button.  the theory is that we
04125     can't handle the world changing **that** much, and as soon as the user
04126     does some editing or cursor moving, we don't want to take any chances
04127     on the callback routine and the data linked into the langerror window.
04128     
04129     7/20/90 DW: it's important to keep the work to an absolute minimum 
04130     when the window is open because the system really bogs down if you
04131     constantly update the script icon in the langerror window.
04132     */
04133     
04134     register hdloutlinerecord ho = outlinedata;
04135 
04136     if ((ho != nil) && (outlinewindow == shellwindow))
04137         if (scriptinstallable ())
04138             if (!(**ho).flrecentlychanged) {
04139                 
04140                 (**ho).flrecentlychanged = true; // set it ourselves now
04141 
04142                 shellinvalbuttons (); // calls us immediately to get status
04143                 }
04144     
04145     return (true);
04146     } /*scriptdirtyhook*/
04147 
04148 
04149 #if 0
04150 
04151 static boolean opwinnewrecord (void) {
04152     
04153     tyvaluerecord val;
04154     hdlexternalvariable hv;
04155     hdloutlinerecord ho;
04156     
04157     if (!langexternalnewvalue (idscriptprocessor, nil, &val))
04158         return (false);
04159     
04160     hv = (hdlexternalvariable) val.data.externalvalue;
04161     
04162     ho = (hdloutlinerecord) (**hv).variabledata;
04163     
04164     (**outlinewindowinfo).hdata = (Handle) ho;
04165     
04166     (**ho).outlinetype = outlineisstandalonescript;
04167 
04168     (**ho).flwindowopen = true;
04169     
04170     (**ho).fldirty = true; /*needs to be saved*/
04171     
04172     scriptsetcallbacks (ho);
04173     
04174     return (true);
04175     } /*opwinnewrecord*/
04176 
04177 
04178 static boolean opwindisposerecord (void) {
04179 
04180     hdloutlinerecord ho = outlinedata; /*copy into local*/
04181     
04182     if ((ho != NULL) && ((**ho).outlinetype == outlineisstandalonescript)) {
04183         
04184         opdisposeoutline (ho, true);
04185         
04186         opsetoutline (nil);
04187         
04188         (**outlinewindowinfo).hdata = nil;
04189         }
04190 
04191     return true;
04192     } /*opwindisposerecord*/
04193 
04194     
04195 static boolean opwinloadfile (hdlfilenum fnum, short rnum) {
04196     
04197     Handle hpackedop;
04198     hdloutlinerecord ho;
04199     boolean fl;
04200     long ixload = 0;
04201     
04202     if (!filereadhandle (fnum, &hpackedop))
04203         return (false);
04204     
04205     fl = opunpack (hpackedop, &ixload, &ho);
04206     
04207     disposehandle (hpackedop);
04208     
04209     if (!fl)
04210         return (false);
04211     
04212     (**outlinewindowinfo).hdata = (Handle) ho;
04213     
04214     (**ho).outlinetype = outlineisstandalonescript;
04215 
04216     (**ho).flwindowopen = true;
04217     
04218     (**ho).fldirty = true; /*never been saved, can't be clean*/
04219     
04220     scriptsetcallbacks (ho);
04221     
04222     return (true);
04223     } /*opwinloadfile*/
04224 
04225 
04226 static boolean opwinsavefile (hdlfilenum fnum, short rnum, boolean flsaveas) {
04227     
04228     Handle hpackedop = nil;
04229     boolean fl;
04230     
04231     if (!oppack (&hpackedop))
04232         return (false);
04233     
04234     fl = 
04235         fileseteof (fnum, 0) &&
04236         
04237         filesetposition (fnum, 0) &&
04238         
04239         filewritehandle (fnum, hpackedop);
04240     
04241     disposehandle (hpackedop);
04242     
04243     return (fl);
04244     } /*opwinsavefile*/
04245 
04246 #endif
04247 
04248 
04249 boolean scriptstart (void) {
04250     
04251     /*
04252     set up callback routines record, and link our data into the shell's  
04253     data structure.
04254     */
04255     
04256     ptrcallbacks scriptcallbacks;
04257     register ptrcallbacks cb;
04258     
04259     shellpushscraphook (&scriptscraphook);
04260     
04261     shellpushdirtyhook (&scriptdirtyhook);
04262     
04263     langcallbacks.scriptcompilecallback = &scriptcompiler;
04264     
04265     shellnewcallbacks (&scriptcallbacks);
04266     
04267     cb = scriptcallbacks; /*copy into register*/
04268     
04269     loadconfigresource (idscriptconfig, &(*cb).config);
04270     
04271     (*cb).config.flnewonlaunch = true; // *** need to update resource
04272 
04273     (*cb).configresnum = idscriptconfig;
04274     
04275     (*cb).windowholder = &outlinewindow;
04276     
04277     (*cb).dataholder = (Handle *) &scriptdataholder;
04278     
04279     (*cb).infoholder = &outlinewindowinfo;
04280     
04281     (*cb).setglobalsroutine = &scriptsetglobals;
04282     
04283     (*cb).pushroutine = &oppushglobals;
04284 
04285     (*cb).poproutine = &oppopglobals;
04286     
04287 #ifdef version42orgreater
04288     
04289     (*cb).saveroutine = ccsavespecialfile;
04290     
04291     (*cb).disposerecordroutine = ccdisposefilerecord;
04292     
04293     /*
04294     (*cb).newrecordroutine = opwinnewrecord;
04295     
04296     (*cb).disposerecordroutine = opwindisposerecord;
04297     
04298     (*cb).loadroutine = opwinloadfile;
04299     
04300     (*cb).backgroundroutine = &ccbackground;
04301 
04302     (*cb).childcloseroutine = &ccchildclose;
04303     */
04304 
04305 #endif
04306     
04307     (*cb).resetrectsroutine = &scriptresetrects;
04308     
04309     (*cb).updateroutine = &scriptupdate;
04310     
04311     (*cb).activateroutine = &opactivate;
04312     
04313     (*cb).getcontentsizeroutine = &scriptgetoutinesize;
04314     
04315     (*cb).resizeroutine = &scriptresize;
04316     
04317     (*cb).scrollroutine = &opscroll;
04318     
04319     (*cb).setscrollbarroutine = &opresetscrollbars;
04320     
04321     (*cb).buttonroutine = &scriptbutton;
04322     
04323     (*cb).buttonstatusroutine = &scriptbuttonstatus;
04324     
04325     (*cb).mouseroutine = &scriptmousedown;
04326 
04327     (*cb).rmouseroutine = &oprmousedown; /*7.0b13 PBS: right-click in scripts*/
04328     
04329     (*cb).keystrokeroutine = &scriptkeystroke;
04330     
04331     (*cb).titleclickroutine = &scripttitleclick;
04332     
04333     (*cb).cmdkeyfilterroutine = &scriptcmdkeyfilter;
04334     
04335     (*cb).cutroutine = &scriptcut;
04336     
04337     (*cb).copyroutine = &opcopy; /*sic -- no need for a script layer here... yet*/
04338     
04339     (*cb).pasteroutine = &scriptpaste;
04340 
04341     (*cb).clearroutine = &scriptclear;
04342     
04343     (*cb).selectallroutine = &opselectall;
04344     
04345     (*cb).closeroutine = &scriptclose;
04346     
04347     (*cb).getundoglobalsroutine = &scriptgetundoglobals;
04348     
04349     (*cb).setundoglobalsroutine = &scriptsetundoglobals;
04350     
04351     (*cb).idleroutine = &scriptidle;
04352     
04353     (*cb).adjustcursorroutine = &scriptadjustcursor;
04354     
04355     (*cb).fontroutine = &scriptsetfont;
04356     
04357     (*cb).sizeroutine = &scriptsetsize;
04358     
04359     (*cb).setselectioninforoutine = &scriptsetselectioninfo;
04360     
04361     (*cb).searchroutine = &scriptsearch;
04362     
04363     (*cb).executeroutine = &scriptruncursor;
04364     
04365     (*cb).gettargetdataroutine = &scriptgettargetdata;
04366     
04367     (*cb).getvariableroutine = (shellgetvariablecallback) &scriptgetvariable;
04368     
04369     (*cb).settextmoderoutine = &opsettextmode;
04370     
04371     (*cb).setprintinfoproutine = &opsetprintinfo;
04372     
04373     (*cb).printroutine = &opprint;
04374     
04375     (*cb).beginprintroutine = &opbeginprint;
04376     
04377     (*cb).endprintroutine = &opendprint;
04378     
04379     return (true);
04380     } /*scriptstart*/
04381 
04382 
04383 boolean initscripts (void) {
04384     
04385     if (!newclearhandle (longsizeof (tydebuggerrecord), (Handle *) &debuggerdata)) /*all fields are cool at 0*/
04386         return (false);
04387     
04388 #ifdef flcomponent
04389 
04390     #if TARGET_API_MAC_CARBON == 1
04391     
04392         AEInstallEventHandler (kOSASuite, kOSARecordedText, NewAEEventHandlerUPP (handlerecordedtext), 0, false);
04393         
04394         AEInstallEventHandler ('ToyS', kAENotifyStopRecording, NewAEEventHandlerUPP (handlestoprecording), 0, false);
04395     
04396     #else
04397 
04398         AEInstallEventHandler (kOSASuite, kOSARecordedText, NewAEEventHandlerProc (handlerecordedtext), 0, false);
04399         
04400         AEInstallEventHandler ('ToyS', kAENotifyStopRecording, NewAEEventHandlerProc (handlestoprecording), 0, false);
04401     
04402     #endif
04403     
04404 #endif
04405     
04406     return (true);
04407     } /*initscripts*/
04408 
04409 
04410 
04411 

Generated on Wed May 31 18:20:00 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6