langsystypes.c

Go to the documentation of this file.
00001 
00002 /*  $Id: langsystypes.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 "strings.h"
00033 #include "ops.h"
00034 #include "error.h"
00035 #include "file.h"
00036 #include "lang.h"
00037 #include "langinternal.h"
00038 #include "langipc.h"
00039 #include "langsystem7.h"
00040 #include "oplist.h"
00041 #include "tableinternal.h" /*for hdltablevariable; so we can avoid loading unloaded tables*/
00042 #include "tablestructure.h"
00043 
00044 #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
00045     #include "aeutils.h"
00046 #endif
00047 
00048 #ifdef MACVERSION
00049     static byte bsellipses [] = "\x01";
00050 #else
00051     static byte bsellipses [] = "\x03...";
00052 #endif
00053 
00054 static byte filerecordpath [] = "\x04" "path";
00055 
00056 static byte filerecordalias [] = "\x05" "alias";
00057 
00058 static byte filerecordmachine [] = "\x07" "machine";
00059 
00060 static byte filerecordplatform [] = "\x04" "plat";
00061 
00062 static byte bsplatformmac [] = "\x03" "mac";
00063 
00064 static byte bsplatformwin [] = "\x03" "win";
00065 
00066 
00067 #ifdef MACVERSION
00068 
00069 static boolean langgestaltcheck (OSType selector, short stringnum) {
00070     
00071     long result;
00072     
00073     if (!gestalt (selector, &result) || (result == 0)) {
00074         
00075         langerror (stringnum);
00076         
00077         return (false);
00078         }
00079     
00080     return (true);
00081     } /*langgestaltcheck*/
00082 
00083 
00084 static boolean equaldescriptors (AEDesc *desc1, AEDesc *desc2) {
00085     
00086     register AEDesc *d1 = desc1;
00087     register AEDesc *d2 = desc2;
00088     register DescType t1;
00089     
00090     if (desc1 == nil) /*7.1b24 PBS: sometimes it's nil, and that's okay, but crashes are bad.*/
00091         return (desc1 == desc2);
00092     
00093     t1 = (*d1).descriptorType;
00094     
00095     if (t1 != (*d2).descriptorType)
00096         return (false);
00097     
00098     if ((t1 == typeAERecord) || (t1 == typeAEList)) {
00099         #ifdef oplanglists
00100             tyvaluerecord v1, v2, vequal;
00101             
00102             if (!langipcconvertaelist (d1, &v1) || !langipcconvertaelist (d2, &v2))
00103                 return (false);
00104             
00105             return (EQvalue (v1, v2, &vequal) && vequal.data.flvalue);
00106         #else
00107             return (comparelists (d1, d2, EQop));
00108         #endif
00109         }
00110     else
00111     
00112         #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
00113         
00114             {
00115             Handle hcopy1, hcopy2;
00116             boolean fl = false;
00117             
00118             copydatahandle (d1, &hcopy1);
00119             
00120             copydatahandle (d2, &hcopy2);
00121             
00122             fl = equalhandles (hcopy1, hcopy2);
00123             
00124             disposehandle (hcopy1);
00125             
00126             disposehandle (hcopy2);
00127             
00128             return (fl);
00129             }
00130                 
00131         #else
00132         
00133             return (equalhandles ((*d1).dataHandle, (*d2).dataHandle));
00134         
00135         #endif
00136     } /*equaldescriptors*/
00137 
00138 #endif
00139 
00140 
00141 boolean langcanusealiases (void) {
00142     
00143     #ifdef MACVERSION
00144     
00145         return (langgestaltcheck (gestaltAliasMgrAttr, cantusealiaseserror));
00146     
00147     #else
00148     
00149         return (false);
00150     
00151     #endif
00152     } /*langcanusealiases*/
00153 
00154 
00155 
00156 static boolean findvaluevisit (bigstring bs, hdlhashnode hnode, tyvaluerecord val, ptrvoid valfind) {
00157 #pragma unused (bs, hnode)
00158 
00159     return (val.data.longvalue == (long) valfind);  //.data.longvalue
00160     } /*findvaluevisit*/
00161 
00162 
00163 static boolean langfindvalue (tyvaluerecord val, hdlhashtable *htable, bigstring bsname) {
00164     
00165     /*
00166     search through the stack of symbol tables until you find a value that 
00167     matches val.  return the name of the matching value.
00168     */
00169     
00170     register hdlhashtable h = currenthashtable;
00171     register long refcon;
00172     register short n;
00173     long valfind;
00174     hdlhashnode hnode;
00175     
00176     *htable = nil;
00177     
00178     setemptystring (bsname);
00179     
00180     if (h == nil)
00181         return (false);
00182     
00183     refcon = (**h).lexicalrefcon;
00184     
00185     valfind = val.data.longvalue;
00186     
00187     while (true) { /*chain through each linked hash table*/
00188         
00189         if (h == nil) /*symbol not defined*/
00190             return (false);
00191         
00192         if ((!(**h).fllocaltable) || (refcon == 0) || ((**h).lexicalrefcon == refcon)) {
00193             
00194             if (hashinversesearch (h, &findvaluevisit, (ptrvoid) valfind, bsname)) { /*symbol is defined in htable*/
00195                 
00196                 *htable = h;
00197                 
00198                 return (true);
00199                 }
00200             
00201             for (n = (**h).ctwithvalues; n > 0; --n) { /*scan with values*/
00202                 
00203                 tyvaluerecord valwith;
00204                 hdlhashtable hwith;
00205                 bigstring bswith;
00206                 
00207                 langgetwithvaluename (n, bswith);
00208                 
00209                 if (!hashtablelookup (h, bswith, &valwith, &hnode)) /*missing with value; keep going*/
00210                     continue;
00211                 
00212                 if (!getaddressvalue (valwith, &hwith, bswith)) /*error*/
00213                     return (false);
00214                 
00215                 if (hashinversesearch (hwith, &findvaluevisit, (ptrvoid) valfind, bsname)) { /*found symbol*/
00216                     
00217                     *htable = hwith;
00218                     
00219                     return (true);
00220                     }
00221                 }
00222             }
00223         
00224         h = (**h).prevhashtable;
00225         } /*while*/
00226     } /*langfindvalue*/
00227 
00228 
00229 static boolean getostypevalnamevisit (bigstring bsname, hdlhashnode hnode, tyvaluerecord val, ptrvoid refcon) {
00230 #pragma unused (hnode)
00231 
00232     /*
00233     3.0.2b1 dmb: we now look in all loaded app tables for a match when 
00234     converting an terminology value (a string4 value) its name
00235     */
00236     
00237     tyvaluerecord *vallookfor = (tyvaluerecord *) refcon;
00238     register hdltablevariable hv;
00239     register hdlhashtable ht;
00240     register boolean fltempload;
00241     hdlhashtable htable;
00242     hdltablevariable hvariable;
00243     short errorcode;
00244     boolean fl;
00245     
00246     if (!gettablevariable (val, &hvariable, &errorcode))
00247         return (false);
00248     
00249     hv = hvariable;
00250     
00251     fltempload = !(**hv).flinmemory;
00252     
00253     if (fltempload) /*we don't want to search every app table, just those in use*/
00254         return (false);
00255     
00256     /*
00257     if (!tableverbinmemory ((hdlexternalvariable) hv))
00258         return (false);
00259     */
00260     
00261     ht = (hdlhashtable) (**hv).variabledata; 
00262     
00263     if (ht == currenthashtable) /*it's already been searched*/
00264         return (false);
00265     
00266     pushhashtable (ht);
00267     
00268     fl = langfindvalue (*vallookfor, &htable, bsname);
00269     
00270     pophashtable ();
00271     
00272     /*
00273     if (fltempload)
00274         tableverbunload ((hdlexternalvariable) hv);
00275     */
00276     
00277     return (fl);
00278     } /*getostypevalnamevisit*/
00279 
00280 
00281 static boolean getostypedisplaystring (OSType key, bigstring bsdisplay) {
00282     
00283     /*
00284     key is an enum or string4 value that may correspond to a bit of 
00285     object model user terminology. our job is to scan the current context 
00286     for a match, and return the symbolic name if found. otherwise, return 
00287     a string4 in single quotes
00288     
00289     2.1b6 dmb: if result is a quoted literal, add escape sequences
00290     
00291     5.0.2b16 dmb: don't return "id" as a string4 displaystring
00292     */
00293     
00294     tyvaluerecord val;
00295     hdlhashtable htable;
00296     byte bskey [16];
00297     boolean fl;
00298     
00299     setostypevalue (key, &val);
00300     
00301     if (langfindvalue (val, &htable, bsdisplay))
00302         goto exit;
00303     
00304     if (objectmodeltable != nil) {
00305         
00306         pushhashtable (objectmodeltable);
00307         
00308         fl = langfindvalue (val, &htable, bsdisplay);
00309         
00310         pophashtable ();
00311         
00312         if (fl)
00313             goto exit;
00314         }
00315     
00316     if (iacgluetable != nil) {
00317         
00318         //vallookfor = val;
00319         
00320         if (hashinversesearch (iacgluetable, &getostypevalnamevisit, &val, bsdisplay))
00321             goto exit;
00322         }
00323     
00324     exit:
00325     
00326     if (!isemptystring (bsdisplay) && !equalstrings (bsdisplay, BIGSTRING ("\x02" "id")))
00327         return (true);
00328     
00329     ostypetostring (key, bskey);
00330     
00331     langdeparsestring (bskey, chsinglequote); /*add needed escape sequences*/
00332     
00333     parsedialogstring (BIGSTRING ("\x04'^0'"), bskey, nil, nil, nil, bsdisplay);
00334     
00335     return (false);
00336     } /*getostypedisplaystring*/
00337 
00338 
00339 static boolean getlimitedvaluestring (tyvaluerecord *val, short limit, char chquote, bigstring bsvalue) {
00340     
00341     /*
00342     2.1b2 dmb: try using AE coercion for unknown (binary) types
00343     
00344     2.1b3 dmb: if binary ends up needing to be coerced to string, add quotes 
00345     and escape sequences
00346     */
00347     
00348     register tyvaluerecord *v = val;
00349     
00350 #ifdef MACVERSION
00351     AEDesc desc, coerceddesc;
00352     OSErr err;
00353 
00354     if ((*v).valuetype == binaryvaluetype) {
00355         
00356         binarytodesc ((*v).data.binaryvalue, &desc); /*binary handle remains in temp stack*/
00357         
00358         err = AECoerceDesc (&desc, typeChar, &coerceddesc);
00359         
00360         if (err == noErr)
00361             chquote = chdoublequote;
00362         else
00363             err = AECoerceDesc (&desc, typeObjectSpecifier, &coerceddesc);
00364         
00365         if (err != noErr) /*no AE coercion to objspec*/
00366             err = AECoerceDesc (&desc, typeAERecord, &coerceddesc);
00367         
00368         if (err != noErr) { /*no AE coercion to record either*/
00369             
00370             chquote = chdoublequote;
00371             
00372             /*
00373             hashgetvaluestring (*v, bsvalue); /%go with hex string%/
00374             
00375             goto limit;
00376             */
00377             }
00378         else {
00379             
00380             disposevaluerecord (*v, true);
00381             
00382             if (!setdescriptorvalue (coerceddesc, v))
00383                 return (false);
00384             }
00385         }
00386 #endif
00387 
00388     if (!coercetostring (v))
00389         return (false);
00390     
00391     pullstringvalue (v, bsvalue);
00392     
00393     if (chquote != chnul)
00394         langdeparsestring (bsvalue, chquote); /*add needed escape sequences*/
00395     
00396     if (stringlength (bsvalue) > limit) {
00397         
00398         setstringlength (bsvalue, limit - stringlength (bsellipses));
00399         
00400         pushstring (bsellipses, bsvalue);
00401         }
00402     
00403     if (chquote != chnul) {
00404         
00405         insertchar (chquote, bsvalue);
00406         
00407         pushchar (chquote, bsvalue);
00408         }
00409     
00410     return (true);
00411     } /*getlimitedvaluestring*/
00412 
00413 
00414 boolean getobjectmodeldisplaystring (tyvaluerecord *vitem, bigstring bsdisplay) {
00415     
00416     /*
00417     get the value's string representation for inclusion in a list 
00418     or object specifier, adding single or double quotes as necessary, and 
00419     mapping string4 values to identifiers in the current context.
00420     
00421     limit the length of the returned string to 253 characters. if we're returning 
00422     a quoted string and need to add an ellipse, add it inside of the quotes.
00423     
00424     2.1b1 dmb: don't quote objspec values. exported for osacomponent
00425     
00426     5.0b16 dmb: leave addresses as addresses, not strings
00427     */
00428     
00429     register tyvaluerecord *v = vitem;
00430     
00431     switch ((*v).valuetype) {
00432         
00433         case novaluetype:
00434             langgetmiscstring (justnilstring, bsdisplay);
00435             
00436             break;
00437         
00438         case ostypevaluetype:
00439         case enumvaluetype:
00440             getostypedisplaystring ((*v).data.ostypevalue, bsdisplay);
00441             
00442             break;
00443         
00444         case charvaluetype: /*these need single quotes*/
00445             if (!getlimitedvaluestring (v, 251, chsinglequote, bsdisplay))
00446                 return (false);
00447             
00448             break;
00449         
00450         case stringvaluetype: /*these need to be quoted*/
00451     #ifndef version5orgreater
00452         case addressvaluetype:
00453     #endif
00454         case filespecvaluetype:
00455         case aliasvaluetype:
00456         case datevaluetype:
00457             if (!getlimitedvaluestring (v, 251, chdoublequote, bsdisplay))
00458                 return (false);
00459             
00460             break;
00461         
00462     #ifdef version5orgreater
00463         case addressvaluetype:
00464             if (!getlimitedvaluestring (v, 251, chnul, bsdisplay))
00465                 return (false);
00466             
00467             if (isemptystring (bsdisplay))
00468                 langgetmiscstring (justnilstring, bsdisplay);
00469             else
00470                 insertchar ('@', bsdisplay);
00471             
00472             break;
00473     #endif
00474         
00475         case pointvaluetype: /*these should look like lists*/
00476         case rectvaluetype:
00477         case rgbvaluetype:
00478             if (!getlimitedvaluestring (v, 251, chnul, bsdisplay))
00479                 return (false);
00480             
00481             insertchar ('{', bsdisplay);
00482             
00483             pushchar ('}', bsdisplay);
00484             
00485             break;
00486         
00487         case objspecvaluetype:
00488             if (!getlimitedvaluestring (v, 253, chnul, bsdisplay))
00489                 return (false);
00490             
00491             if (isemptystring (bsdisplay))
00492                 copystring (BIGSTRING ("\x02\"\""), bsdisplay);
00493             
00494             break;
00495             
00496         default:
00497             if (!getlimitedvaluestring (v, 253, chnul, bsdisplay))
00498                 return (false);
00499             
00500             break;
00501         }
00502     
00503     return (true);
00504     } /*getobjectmodeldisplaystring*/
00505 
00506 
00507 #ifdef MACVERSION
00508 
00509 static boolean stringtoalias (tyvaluerecord *val) {
00510     
00511     /*
00512     10/7/91 dmb: make sure we're actually passing a full path to the NewAlias routine
00513     
00514     7/2/92 dmb: don't call getfullfilepath; makes it impossible to create aliases of 
00515     not-yet-existing files, or offline volumes
00516     
00517     7/23/92 dmb: OK, try to getfullfilepath, but with errors disabled
00518     
00519     2.1b2 dmb: try converting to a filespec first to ensure that partial path or 
00520     drive number if processed properly. also, in the filespec case, the alias isn't 
00521     minimal
00522     */
00523     
00524     register Handle htext;
00525     bigstring bspath;
00526     tyfilespec fs;
00527     AliasHandle halias;
00528     boolean flfolder;
00529     OSErr errcode;
00530     
00531     if (!langcanusealiases ())
00532         return (false);
00533     
00534     htext = (*val).data.stringvalue;
00535     
00536     texthandletostring (htext, bspath);
00537     
00538     if (pathtofilespec (bspath, &fs) && fileexists (&fs, &flfolder))
00539         errcode = NewAlias (nil, &fs, &halias);
00540     else
00541         errcode = NewAliasMinimalFromFullPath (stringlength (bspath), bspath + 1, nil, nil, &halias);
00542     
00543     if (oserror (errcode))
00544         return (false);
00545     
00546     if (!setheapvalue ((Handle) halias, aliasvaluetype, val))
00547         return (false);
00548     
00549     releaseheaptmp ((Handle) htext);
00550     
00551     return (true);
00552     } /*stringtoalias*/
00553 
00554 #endif
00555 
00556 boolean filespectoalias (const tyfilespec *fs, boolean flminimal, AliasHandle *halias) {
00557     
00558 #ifdef MACVERSION
00559     bigstring bs;
00560     OSErr err;
00561     
00562     if (flminimal)
00563         err = NewAliasMinimal (fs, halias);
00564     else
00565         err = NewAlias (nil, fs, halias);
00566     
00567     if (err == fnfErr) { /*alias manager isn't friendly enough to do anything for us here*/
00568         
00569         if (filespectopath (fs, bs))
00570             err = NewAliasMinimalFromFullPath (stringlength (bs), bs + 1, nil, nil, halias);
00571         }
00572     
00573     if (err == noErr)
00574         return (true);
00575     
00576     if (langerrorenabled ()) {
00577         
00578         setoserrorparam ((ptrstring) (*fs).name);
00579         
00580         oserror (err);
00581         }
00582     
00583     return (false);
00584 #endif
00585 
00586 #ifdef WIN95VERSION
00587     langparamerror (unimplementedverberror, bsfunctionname);
00588     
00589     return (false);
00590 #endif
00591     } /*filespectoalias*/
00592 
00593 
00594 #ifdef MACVERSION
00595 
00596 static boolean filespecvaltoalias (tyvaluerecord *val) {
00597     
00598     register FSSpecHandle hfs;
00599     FSSpec fs;
00600     AliasHandle halias;
00601     
00602     if (!langcanusealiases ())
00603         return (false);
00604     
00605     hfs = (FSSpecHandle) (*val).data.filespecvalue;
00606     
00607     fs = **hfs;
00608     
00609     if (!filespectoalias (&fs, false, &halias))
00610         return (false);
00611     
00612     if (!setheapvalue ((Handle) halias, aliasvaluetype, val))
00613         return (false);
00614     
00615     releaseheaptmp ((Handle) hfs);
00616     
00617     return (true);
00618     } /*filespecvaltoalias*/
00619 
00620 #endif
00621 
00622 
00623 boolean aliastostring (Handle halias, bigstring bs) {
00624 
00625 #ifdef MACVERSION
00626     
00627     /*
00628     10/4/91 dmb: if alias can't be resolved, just say what volume it's on.
00629     
00630     4/12/93 dmb: accept fnfErr result from ResolveAlias
00631     
00632     2.1b9 dmb: use FollowFinderAlias to avoid mounting volumes during 
00633     alias resolution
00634     
00635     4.0b6 4/26/96 dmb: restored FollowFinderAlias code; must use if we get fnfErr.
00636     */
00637     
00638     register AliasHandle h = (AliasHandle) halias;
00639     short flchanged;
00640     FSSpec fs;
00641     bigstring bsinfo;
00642     AliasInfoType ix = asiAliasName;
00643     OSErr err;
00644     
00645     if (!langcanusealiases ())
00646         return (false);
00647     
00648     err = FollowFinderAlias (nil, h, false, &fs, (Boolean *) &flchanged);
00649     
00650     if ((err == noErr) /*|| (err == fnfErr)*/ ) {
00651         
00652         if (flchanged)
00653             UpdateAlias (nil, &fs, h, (Boolean *) &flchanged);
00654         
00655         return (filespectopath (&fs, bs));
00656         }
00657     
00658     langgettypestring (aliasvaluetype, bs);
00659     
00660     /*
00661     if (GetAliasInfo (h, asiVolumeName, bsinfo) == noErr) { //add the volume name
00662         
00663         bigstring bsaliasondisk;
00664         
00665         langgetstringlist (unresolvedaliasstring, bsaliasondisk);
00666         
00667         parsedialogstring (bsaliasondisk, bs, bsinfo, nil, nil, bsaliasondisk);
00668         
00669         copystring (bsaliasondisk, bs);
00670         }
00671     */
00672     
00673     setemptystring (bs);
00674     
00675     // get each path element out of the alias
00676     while (GetAliasInfo (h, ix, bsinfo) == noErr) {
00677         
00678         if (isemptystring (bsinfo)) // reached top of path hierarchy
00679             break;
00680         
00681         if (ix > asiAliasName)
00682             pushchar (':', bsinfo);
00683         
00684         if (!insertstring (bsinfo, bs))
00685             break;
00686         
00687         ++ix;
00688         }
00689     
00690     // add the volume name
00691     GetAliasInfo (h, asiVolumeName, bsinfo);
00692     
00693     pushchar (':', bsinfo);
00694     
00695     insertstring (bsinfo, bs);
00696     
00697     return (true);
00698 #endif
00699 
00700 #ifdef WIN95VERSION
00701     langparamerror (unimplementedverberror, bsfunctionname);
00702 
00703     return (false);
00704 #endif
00705     } /*aliastostring*/
00706 
00707 
00708 boolean aliastofilespec (AliasHandle halias, tyfilespec *fs) {
00709     
00710     /*
00711     2.1a6 dmb: ignore fnfErr
00712     
00713     2.1b2 dmb: on error, try to get as much info from the alias as possible, 
00714     & just return false to caller
00715     
00716     2.1b9 dmb: use FollowFinderAlias to avoid mounting volumes during 
00717     alias resolution
00718     
00719     7.0b34 PBS: Can't use ResolveAliasWithMountFlags on pre-Carbon Macs reliably,
00720     so fall back to FollowFinderAlias.
00721     */
00722     
00723 #ifdef MACVERSION
00724     Boolean flchanged;
00725     bigstring bs;
00726     OSErr err;
00727     
00728     if (!langcanusealiases ())
00729         return (false);
00730         
00731     #if TARGET_API_MAC_CARBON == 1
00732     
00733         err = ResolveAliasWithMountFlags(nil, halias, fs, &flchanged, kARMNoUI);
00734         //old stupid code.
00735         //Code change by Timothy Paustian Tuesday, May 16, 2000 8:54:03 PM
00736         //why was this used. Maybe before there was the other APIs, anyhow, 
00737         //it breaks on OS X so use the above, correct routine instead
00738     
00739     #else /*7.0b32 PBS: fall back to FollowFinderAlias on pre-Carbon Macs*/
00740         
00741         err = FollowFinderAlias (nil, halias, false, fs, &flchanged);
00742     
00743     #endif
00744     
00745     if ((err == noErr) || (err == fnfErr))
00746         return (true);
00747     
00748     (*fs).parID = 0;
00749     
00750     (*fs).vRefNum = 0;
00751     
00752     if (GetAliasInfo (halias, asiVolumeName, bs) == noErr) /*try to get vol info*/
00753         fileparsevolname (bs, &(*fs).vRefNum, nil);
00754     
00755     if (GetAliasInfo (halias, asiAliasName, (*fs).name) != noErr) /*try to set file name*/
00756         langgetmiscstring (unknownstring, (*fs).name);
00757     
00758     if (langerrorenabled ()) {
00759         
00760         setoserrorparam ((*fs).name);
00761         
00762         oserror (err);
00763         }
00764     
00765     return (false);
00766 #endif
00767 
00768 #ifdef WIN95VERSION
00769     langparamerror (unimplementedverberror, bsfunctionname);
00770 
00771     return (false);
00772 #endif
00773     } /*aliastofilespec*/
00774 
00775 
00776 boolean coercetoalias (tyvaluerecord *v) {
00777     
00778     /*
00779     10/4/91 dmb: when v is novaluetype, fail silently so the new verb 
00780     will just return false.  a specific error message might be better, but 
00781     I don't expect this to come up much, if at all.
00782     */
00783     
00784 #ifdef MACVERSION
00785     switch ((*v).valuetype) {
00786         
00787         case aliasvaluetype:
00788             return (true);
00789         
00790         case novaluetype: /*easy way is via file spec to make alias of default folder*/
00791             if (flinhibitnilcoercion)
00792                 return (false);
00793             
00794             if (!coercetofilespec (v))
00795                 return (false);
00796             
00797             return (filespecvaltoalias (v));
00798         
00799         case stringvaluetype:
00800             return (stringtoalias (v));
00801         
00802         case binaryvaluetype:
00803             return (coercebinaryval (v, aliasvaluetype, 0L, aliasvaluetype));
00804         
00805         case filespecvaluetype:
00806             return (filespecvaltoalias (v));
00807         
00808         case listvaluetype:
00809         case recordvaluetype:
00810             return (coercelistvalue (v, aliasvaluetype));
00811         
00812         default:
00813             langcoerceerror (v, aliasvaluetype);
00814             
00815             return (false);
00816         } /*switch*/
00817 #endif
00818 
00819 #ifdef WIN95VERSION
00820     langparamerror (unimplementedverberror, bsfunctionname);
00821 
00822     return (false);
00823 #endif
00824     } /*coercetoalias*/
00825 
00826 
00827 boolean filespecaddvalue (tyvaluerecord *v1, tyvaluerecord *v2, tyvaluerecord *vreturned) {
00828 
00829     /*
00830     add v2 to the filespec v1 by using it as a partial path. if anything bug a valid 
00831     fspec results, return a string value that is simple concatenation
00832     
00833     2.1b3 dmb: if resulting path is to a non-existent folder, don't return a filespec 
00834     
00835     2.1b6 dmb: if resulting specifier exists, but doesn't agree with bsadd as far as 
00836     whether or not it's a folder, return a string.
00837     */
00838     
00839 #ifdef MACVERSION
00840     tyfilespec fs;
00841     bigstring bsadd;
00842     boolean fl, flfolder;
00843     boolean flfolderpath;
00844     OSErr err;
00845         
00846     #if TARGET_API_MAC_CARBON == 1
00847     
00848         fs.vRefNum = (**(*v1).data.filespecvalue).vRefNum;
00849         
00850         fs.parID = (**(*v1).data.filespecvalue).parID;
00851         
00852         copystring ((**(*v1).data.filespecvalue).name, fs.name);
00853         
00854     #else
00855     
00856         fs = **(*v1).data.filespecvalue;
00857         
00858     #endif
00859     
00860     if (!coercetostring (v2))
00861         return (false);
00862     
00863 //  fs = **(*v1).data.filespecvalue;
00864     
00865     pullstringvalue (v2, bsadd);
00866     
00867     if (fileexists (&fs, &flfolder)) {
00868         
00869     //  fileisfolder (&fs, &flfolder);
00870         
00871         if (flfolder)
00872             pushchar (':', fs.name);
00873         }
00874     
00875     insertstring (fs.name, bsadd);
00876     
00877     if (stringfindchar (':', bsadd)) /*will be interpreted as full path, so make it partial*/
00878         insertchar (':', bsadd);
00879     
00880     err = FSMakeFSSpec (fs.vRefNum, fs.parID, bsadd, &fs);
00881     
00882     flfolderpath = lastchar (bsadd) == ':';
00883     
00884     switch (err) {
00885         
00886         case noErr: /*valid spec, file exists*/
00887             
00888             fileisfolder (&fs, &flfolder);
00889             
00890             fl = flfolder == flfolderpath; /*make sure endings match*/
00891             
00892             break;
00893         
00894         case fnfErr: /*valid spec, file doesn't exist*/
00895             
00896             fl = !flfolderpath;
00897             
00898             break;
00899         
00900         default:
00901             fl = false;
00902             
00903             break;
00904         }
00905     
00906     if (!fl) { /*couldn't extend filespec*/
00907         
00908         if (!coercetostring (v1))
00909             return (false);
00910         
00911         return (addvalue (*v1, *v2, vreturned));
00912         }
00913     
00914     return (setfilespecvalue (&fs, vreturned));
00915 #endif
00916 
00917 #ifdef WIN95VERSION
00918     if (!coercetostring (v2))
00919         return (false);
00920     
00921     if (!coercetostring (v1))
00922         return (false);
00923     
00924     return (addvalue (*v1, *v2, vreturned));
00925 #endif
00926     } /*filespecaddvalue*/
00927 
00928 
00929 boolean filespecsubtractvalue (tyvaluerecord *v1, tyvaluerecord *v2, tyvaluerecord *vreturned) {
00930 
00931     /*
00932     subtract v2 from the filespec v1's file name, iff v2 is a simple string (no 
00933     colons). otherwise, return a string value that is simple string subtraction
00934     */
00935     
00936 #ifdef MACVERSION
00937     tyfilespec fs;
00938     bigstring bssub;
00939     boolean fl;
00940     Str63 bsname;
00941     OSErr err;
00942     
00943     if (!coercetostring (v2))
00944         return (false);
00945     
00946     fs = **(*v1).data.filespecvalue;
00947     
00948     pullstringvalue (v2, bssub);
00949     
00950     fl = !stringfindchar (':', bssub);
00951     
00952     if (fl) {
00953         
00954         subtractstrings (fs.name, bssub, bsname);
00955         
00956         err = FSMakeFSSpec (fs.vRefNum, fs.parID, bsname, &fs);
00957         
00958         fl = (err == noErr) || (err == fnfErr);
00959         }
00960     
00961     if (!fl) { /*couldn't extend filespec*/
00962     
00963         if (!coercetostring (v1))
00964             return (false);
00965         
00966         return (subtractvalue (*v1, *v2, vreturned));
00967         }
00968     
00969     return (setfilespecvalue (&fs, vreturned));
00970 #endif
00971 
00972 #ifdef WIN95VERSION
00973     if (!coercetostring (v2))
00974         return (false);
00975     
00976     if (!coercetostring (v1))
00977         return (false);
00978     
00979     return (subtractvalue (*v1, *v2, vreturned));
00980 #endif
00981     } /*filespecsubtractvalue*/
00982 
00983 
00984 boolean langpackfileval (const tyvaluerecord *vfile, Handle *hpacked) {
00985     
00986     /*
00987     5.0a24 dmb: new format for storing filespec and alias values 
00988     in the odb.
00989 
00990     we create a record containing an alias to the file (Mac only), 
00991     the full path to the file (as a URL), and the machine name (for
00992     future use).
00993     */
00994     
00995     hdllistrecord hlist;
00996     bigstring bspath, bsmachine;
00997     tyfilespec fs;
00998     Handle halias = nil;
00999     boolean fl = false;
01000     
01001     if (!opnewlist (&hlist, true))
01002         return (false);
01003     
01004     switch ((*vfile).valuetype) {
01005         
01006         case aliasvaluetype:
01007             if (!copyhandle ((*vfile).data.aliasvalue, &halias))
01008                 goto exit;
01009             
01010             aliastostring (halias, bspath);
01011             
01012             break;
01013         
01014         case filespecvaluetype: {
01015         
01016             #if TARGET_API_MAC_CARBON == 1
01017     
01018                 fs.vRefNum = (**(*vfile).data.filespecvalue).vRefNum;
01019                 fs.parID = (**(*vfile).data.filespecvalue).parID;
01020                 
01021                 copystring ((**(*vfile).data.filespecvalue).name, fs.name);
01022     
01023             #else
01024             
01025                 fs = **(*vfile).data.filespecvalue;
01026             
01027             #endif
01028             
01029             disablelangerror ();
01030             
01031             if (!filespectoalias (&fs, true, (AliasHandle *) &halias))
01032                 halias = nil;
01033 
01034             enablelangerror ();
01035             
01036             fl = filespectopath (&fs, bspath);
01037             
01038             break;
01039             }
01040         
01041         default:
01042             assert (false);
01043 
01044             goto exit;
01045         }
01046     
01047     // *** should converr path to URL ***
01048     
01049     if (!oppushstring (hlist, filerecordpath, bspath))
01050         goto exit;
01051     
01052     if (halias != nil)
01053         if (!oppushhandle (hlist, filerecordalias, halias))
01054             goto exit;
01055     
01056     //5.0a24 rab: adding platform indicator rather then converting to URL - URL's have as much difference as
01057     //just indicating what platform the path is specific to.
01058 
01059     #ifdef MACVERSION
01060         if (!oppushstring (hlist, filerecordplatform, bsplatformmac))
01061             goto exit;
01062     #endif
01063 
01064     #ifdef WIN95VERSION
01065         if (!oppushstring (hlist, filerecordplatform, bsplatformwin))
01066             goto exit;
01067     #endif
01068 
01069     // *** could push machine name too
01070     if (getmachinename (bsmachine))
01071         if (!oppushstring (hlist, filerecordmachine, bsmachine))
01072             goto exit;
01073     
01074     fl = oppacklist (hlist, hpacked);
01075     
01076   exit:
01077     
01078     opdisposelist (hlist);
01079     
01080     return (fl);
01081     } /*langpackfileval*/
01082 
01083 
01084 boolean langunpackfileval (Handle hpacked, tyvaluerecord *vfile) {
01085     
01086     /*
01087     5.0fc2 dmb: unpacking an alias on the pc, go straight for the path string
01088     */
01089 
01090     hdllistrecord hlist;
01091     Handle halias;
01092     bigstring bspath, bsplat;
01093     tyfilespec fs;
01094     boolean fl = false;
01095 
01096     if (!opunpacklist (hpacked, &hlist))
01097         return (false);
01098     
01099     switch ((*vfile).valuetype) {
01100         
01101         case aliasvaluetype:
01102             #ifdef MACVERSION
01103                 fl = opgetlisthandle (hlist, -1, filerecordalias, &halias);
01104 
01105                 if (fl)
01106                     fl = copyhandle (halias, &(*vfile).data.aliasvalue);
01107             #endif
01108 
01109             #ifdef WIN95VERSION
01110                 fl = opgetliststring (hlist, -1, filerecordpath, bspath);
01111                 
01112                 if (fl) {
01113 
01114                     (*vfile).valuetype = stringvaluetype;
01115 
01116                     fl = newtexthandle (bspath, &(*vfile).data.stringvalue);
01117                     }
01118             #endif
01119             
01120             break;
01121 
01122         case filespecvaluetype:
01123             fl = opgetlisthandle (hlist, -1, filerecordalias, &halias);
01124 
01125             if (fl) {
01126                 
01127                 disablelangerror ();
01128                 
01129                 fl = aliastofilespec ((AliasHandle) halias, &fs);
01130                 
01131                 enablelangerror ();
01132                 }
01133 
01134             if (!fl) {
01135                 
01136                 fl = opgetliststring (hlist, -1, filerecordpath, bspath);
01137                 
01138                 if (fl) {
01139                     // here we should check to see if the file path is from the correct platform???
01140                     if (opgetliststring (hlist, -1, filerecordplatform, bsplat)) {
01141                         #ifdef MACVERSION
01142                             if (equalidentifiers (bsplat, bsplatformwin)) {
01143                                 /* ERROR or Conversion HERE! */
01144                                 }
01145                         #endif
01146 
01147                         #ifdef WIN95VERSION
01148                             if (equalidentifiers (bsplat, bsplatformmac)) {
01149                                 /* ERROR or Conversion HERE! */
01150                                 }
01151                         #endif
01152                         }
01153                     
01154                     fl = pathtofilespec (bspath, &fs);
01155                     }
01156                 }
01157             
01158             if (fl)
01159                 fl = newfilledhandle (&fs, filespecsize (fs), (Handle *) &(*vfile).data.filespecvalue);
01160             else {
01161                 // *** once we make tyfilespec the new record on both platforms, this will be ok
01162                 // *** but for now, we need to make a string value
01163                 (*vfile).valuetype = stringvaluetype;
01164 
01165                 fl = newtexthandle (bspath, &(*vfile).data.stringvalue);
01166                 }
01167 
01168             break;
01169         
01170         default:
01171             assert (false);
01172             break;
01173         }
01174     
01175     opdisposelist (hlist);
01176 
01177     return (fl);
01178     } /*langunpackfileval*/
01179 
01180 
01181 #ifdef WIN95VERSION
01182 
01183 boolean objspectoaddress (tyvaluerecord *val) {
01184 
01185     langparamerror (unimplementedverberror, bsfunctionname);
01186 
01187     return (false);
01188     } /*objspectoaddress*/
01189 
01190 
01191 boolean objspectofilespec (tyvaluerecord *val) {
01192 
01193     langparamerror (unimplementedverberror, bsfunctionname);
01194 
01195     return (false);
01196     } /*objspectofilespec*/
01197 
01198 
01199 boolean filespectoobjspec (tyvaluerecord *val) {
01200 
01201     langparamerror (unimplementedverberror, bsfunctionname);
01202 
01203     return (false);
01204     } /*filespectoobjspec*/
01205 
01206 
01207 boolean objspectostring (Handle hobjspec, bigstring bs) {
01208 
01209     copystring ("\x09" "<objspec>", bs);
01210 
01211     return (true);
01212     } /*objspectostring*/
01213 
01214 
01215 boolean coercetoobjspec (tyvaluerecord *v) {
01216 
01217     langparamerror (unimplementedverberror, bsfunctionname);
01218 
01219     return (false);
01220     } /*coercetoobjspec*/
01221 
01222 
01223 boolean setobjspecverb (hdltreenode hparam1, tyvaluerecord *val) {
01224 
01225     langparamerror (unimplementedverberror, bsfunctionname);
01226 
01227     return (false);
01228     } /*setobjspecverb*/
01229 
01230 
01231 boolean isobjspectree (hdltreenode htree) {
01232     return (false);
01233     } /*isobjspectree*/
01234 
01235 
01236 boolean evaluateobjspec (hdltreenode htree, tyvaluerecord *vreturned) {
01237 
01238     langparamerror (unimplementedverberror, bsfunctionname);
01239 
01240     return (false);
01241     } /*evaluateobjspec*/
01242 
01243 #endif
01244 
01245 #ifdef MACVERSION
01246 
01247 static pascal OSErr langsystem7accessobject (
01248                         DescType    classWanted,
01249                         AEDesc      *container,
01250                         DescType    containerClass, 
01251                         DescType    keyform,
01252                         AEDesc      *keydesc,
01253                         AEDesc      *resultToken,
01254                         long        theRefCon) {
01255     
01256     #pragma unused (classWanted,container,containerClass,theRefCon)
01257     
01258     AEDesc tempdesc;
01259     hdlhashtable htable;
01260     bigstring bs;
01261     register OSErr err;
01262     
01263     switch (keyform) {
01264         
01265         case formName:
01266             err = AECoerceDesc (keydesc, typeChar, &tempdesc);
01267             
01268             if (err != noErr)
01269                 return (err);
01270             
01271             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01272             
01273                 datahandletostring (keydesc, bs);
01274                 
01275             #else
01276             
01277                 texthandletostring ((*keydesc).dataHandle, bs);
01278             
01279             #endif
01280             
01281             if (!langexpandtodotparams (bs, &htable, bs)) {
01282                 
01283                 AEDisposeDesc (&tempdesc);
01284                 
01285                 return(errAENoSuchObject);
01286                 }
01287             
01288             *resultToken = tempdesc;
01289             
01290             return (noErr);
01291         
01292         /*
01293         case formAbsolutePosition:
01294             err = AECoerceDesc (keydesc, typeLongInteger, &tempdesc);
01295             
01296             if (err != noErr)
01297                 return (err);
01298             
01299             return (errAEEventNotHandled);      // I've got no clue of how to access files by number.
01300         */
01301         
01302         default:                                // I don't handle any other key forms.
01303             return (errAEEventNotHandled);
01304         }
01305     } /*langsystem7accessobject*/
01306 
01307 
01308 static void setupdescriptor (Handle hdata, AEDesc *desc) {
01309     
01310     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01311     
01312         DescType type = typeObjectSpecifier;
01313         
01314         if (hdata == nil)
01315             type = typeNull;
01316         
01317         newdescwithhandle (desc, type, hdata);
01318     
01319     #else
01320     
01321         register AEDesc *d = desc;
01322     
01323         (*d).dataHandle = hdata;
01324         
01325         if ((*d).dataHandle == nil)
01326             (*d).descriptorType = typeNull;
01327         else
01328             (*d).descriptorType = typeObjectSpecifier;
01329         
01330     #endif
01331     } /*setupdescriptor*/
01332 
01333 
01334 static OSErr langsystem7parseobject (const AEDesc *object, DescType *class, AEDesc *container, DescType *keyform, AEDesc *keydata) {
01335     
01336     AEDesc objdesc;
01337     DescType type;
01338     long size;
01339     register OSErr err;
01340     
01341     err = AECoerceDesc (object, typeAERecord, &objdesc);
01342     
01343     if (err != noErr)
01344         return (err);
01345     
01346     setupdescriptor (nil, container);
01347     
01348     setupdescriptor (nil, keydata);
01349     
01350     err = AEGetKeyPtr (&objdesc, keyAEDesiredClass, typeType, &type, (Ptr) class, sizeof (class), &size);
01351     
01352     if (err != noErr)
01353         goto exit;
01354     
01355     err = AEGetKeyPtr (&objdesc, keyAEKeyForm, typeEnumerated, &type, (Ptr) keyform, sizeof (keyform), &size);
01356     
01357     if (err != noErr)
01358         goto exit;
01359     
01360     err = AEGetKeyDesc (&objdesc, keyAEContainer, typeWildCard, container);
01361     
01362     if (err != noErr)
01363         goto exit;
01364     
01365     err = AEGetKeyDesc (&objdesc, keyAEKeyData, typeWildCard, keydata);
01366     
01367     exit:
01368     
01369     AEDisposeDesc (&objdesc);
01370     
01371     if (err != noErr) {
01372         
01373         AEDisposeDesc (container);
01374         
01375         AEDisposeDesc (keydata);
01376         }
01377     
01378     return (err);
01379     } /*langsystem7parseobject*/
01380 
01381 
01382 static OSErr langsystem7resolve (const AEDesc *object, AEDesc *resultdesc) {
01383     
01384     DescType class;
01385     DescType keyform;
01386     AEDesc keydata;
01387     AEDesc container;
01388     register OSErr err;
01389     
01390     err = langsystem7parseobject (object, &class, &container, &keyform, &keydata);
01391     
01392     if (err != noErr)
01393         return (err);
01394     
01395     if (container.descriptorType != typeNull)
01396         err = errAEEventNotHandled;
01397     else
01398         err = langsystem7accessobject (cCell, &container, cApplication, keyform, &keydata, resultdesc, 0);
01399     
01400     AEDisposeDesc (&container);
01401     
01402     AEDisposeDesc (&keydata);
01403     
01404     return (err);
01405     } /*langsystem7resolve*/
01406 
01407 
01408 boolean objspectoaddress (tyvaluerecord *val) {
01409     
01410     /*
01411     9/23/92 dmb: turn the objspec value into an address value.
01412     
01413     this will only work if the object specification is for a cell 
01414     in the data. currently, that means it must be a formName 
01415     specifier of a cCell element with a null container
01416     */
01417     
01418     register tyvaluerecord *v = val;
01419     AEDesc objdesc;
01420     AEDesc token;
01421     OSErr errcode;
01422     
01423     setupdescriptor ((*v).data.objspecvalue, &objdesc);
01424     
01425     errcode = langsystem7resolve (&objdesc, &token);
01426     
01427     if (errcode != noErr)
01428         return (false);
01429     
01430     disposevaluerecord (*v, true);
01431     
01432     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01433     
01434         {
01435         Handle h;
01436         
01437         copydatahandle (&token, &h);
01438         
01439         if (!setheapvalue (h, stringvaluetype, v))
01440             return (false);
01441         }
01442     
01443     #else
01444     
01445         if (!setheapvalue (token.dataHandle, stringvaluetype, v)) /*consumes handle*/
01446             return (false);
01447             
01448     #endif
01449     
01450     return (stringtoaddress (v));
01451     } /*objspectoaddress*/
01452 
01453 
01454 boolean objspectofilespec (tyvaluerecord *val) {
01455     
01456     /*
01457     2.1b5 dmb: added for AppleScript compatibility
01458     */
01459     
01460     register tyvaluerecord *v = val;
01461     AEDesc objdesc;
01462     DescType class;
01463     DescType containertype;
01464     DescType keyform;
01465     AEDesc keydata;
01466     AEDesc container;
01467     
01468     setupdescriptor ((*v).data.objspecvalue, &objdesc);
01469     
01470     if (oserror (langsystem7parseobject (&objdesc, &class, &container, &keyform, &keydata)))
01471         return (false);
01472     
01473     containertype = container.descriptorType;
01474     
01475     AEDisposeDesc (&container);
01476     
01477     if ((containertype == typeNull) && (class == cFile) && (keyform == formName)) {
01478         
01479         disposevaluerecord (*v, true); /*dispose orig value which is also objdesc*/
01480         
01481         if (!setdescriptorvalue (keydata, v)) /*keydata is on temp stack, or disposed on error*/
01482             return (false);
01483         
01484         if (!coercetostring (v))
01485             return (false);
01486         
01487         return (coercetofilespec (v)); /*a little recursion here, since that's probably our caller*/
01488         }
01489     else {
01490         
01491         AEDisposeDesc (&keydata);
01492         
01493         langcoerceerror (v, filespecvaluetype);
01494         
01495         return (false);
01496         }
01497     } /*objspectofilespec*/
01498 
01499 
01500 boolean filespectoobjspec (tyvaluerecord *val) {
01501     
01502     /*
01503     2.1b5 dmb: added for AppleScript compatibility
01504     */
01505     
01506     register tyvaluerecord *v = val;
01507     AEDesc objdesc;
01508     AEDesc keydata;
01509     tyfilespec fs = **(*v).data.filespecvalue;
01510     bigstring bs;
01511     AEDesc container = {typeNull, nil};
01512     OSErr err;
01513     
01514     filespectopath (&fs, bs);
01515     
01516     err = AECreateDesc (typeChar, (Ptr) bs + 1, stringlength (bs), &keydata);
01517     
01518     if (err == noErr)
01519         err = CreateObjSpecifier (cFile, &container, formName, &keydata, true, &objdesc);
01520     
01521     if (oserror (err))
01522         return (false);
01523     
01524     disposevaluerecord (*v, true);
01525     
01526     
01527     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01528     
01529         {
01530         Handle h;
01531         
01532         copydatahandle (&objdesc, &h);
01533         
01534         return (setheapvalue (h, objspecvaluetype, v));
01535         }
01536     
01537     #else
01538     
01539         return (setheapvalue (objdesc.dataHandle, objspecvaluetype, v));
01540     
01541     #endif
01542     
01543     } /*filespectoobjspec*/
01544 
01545 
01546 static boolean stringtoobjspec (tyvaluerecord *val) {
01547     
01548     /*
01549     2.1b2 dmb: fixed bug where true would be returned for a bad objspec.
01550     
01551     2.1b2 dmb: added special case for empty strings
01552     
01553     2.1b6 dmb: fixed error offset maintenance
01554     */
01555     
01556     Handle htext;
01557     hdltreenode hmodule;
01558     boolean fl = false;
01559     unsigned short savelines;
01560     unsigned short savechars;
01561     
01562     if (gethandlesize ((*val).data.stringvalue) == 0) { /*empty string -> null spec*/
01563         
01564         disposevaluerecord (*val, true);
01565         
01566         (*val).valuetype = objspecvaluetype;
01567         
01568         (*val).data.objspecvalue = nil;
01569         
01570         return (true);
01571         }
01572     
01573     if (!copyhandle ((*val).data.stringvalue, &htext))
01574         return (false);
01575     
01576     savelines = ctscanlines;
01577     
01578     savechars = ctscanchars;
01579     
01580     disablelangerror ();
01581     
01582     fl = langcompiletext (htext, false, &hmodule); /*always disposes htext*/
01583     
01584     enablelangerror ();
01585     
01586     if (fl) {
01587         
01588         register hdltreenode h = (**hmodule).param1; /*copy into register*/
01589         
01590         fl = isobjspectree (h);
01591         
01592         if (fl) {
01593             
01594             disposevaluerecord (*val, true);
01595             
01596             disablelangerror (); /*we'll generate own error w/correct position*/
01597             
01598             fl = evaluateobjspec (h, val);
01599             
01600             enablelangerror ();
01601             }
01602         
01603         langdisposetree (hmodule);
01604         }
01605     
01606     ctscanlines = savelines;
01607     
01608     ctscanchars = savechars;
01609     
01610     if (!fl)
01611         langerror (badobjectspecificationerror);
01612     
01613     return (fl);
01614     } /*stringtoobjspec*/
01615 
01616 
01617 static boolean objtostring (AEDesc *, boolean, DescType, AEDesc *, bigstring); /*forward*/
01618 
01619 
01620 typedef struct tyobjspecitem { /*data within special object specifier structures*/
01621     
01622     AEKeyword key;
01623     
01624     DescType type;
01625     
01626     long size;
01627     
01628     /*data follows*/
01629     } tyobjspecitem;
01630 
01631 
01632 static boolean getobjspeckeydesc (AEDesc *objdata, OSType desiredkey, AEDesc *keydata) {
01633 
01634     #if TARGET_API_MAC_CARBON == 1
01635     // MJL 17/08/05: As of Jaguar the AEDesc datahandle is opaque so use toolbox accessor functions rather
01636     //  than trying to parse the data structure.
01637     AEKeyword       curKeyWord;
01638     OSErr           err;
01639     SInt32          i, numItems;
01640     
01641     err = AECountItems((AEDescList *)objdata, &numItems);
01642     if (err != noErr)
01643         goto exit;
01644     
01645     for (i = 1; i <= numItems; i++) {
01646         err = AEGetNthDesc((AEDescList *)objdata, i, typeWildCard, &curKeyWord, keydata);
01647         
01648         if (err != noErr)
01649             goto exit;
01650         
01651         if (curKeyWord == desiredkey) {
01652             goto exit;
01653         }
01654         AEDisposeDesc(keydata);
01655     }
01656     
01657     err = errAEDescNotFound;
01658     
01659     exit:
01660     return (!oserror (err));
01661     
01662     #else  // #if TARGET_API_MAC_CARBON == 1
01663     
01664     register Handle h = (*objdata).dataHandle;
01665     register byte *p;
01666     long ctitems;
01667     tyobjspecitem objspecitem;
01668     OSErr err;
01669     
01670     HLock (h);
01671     //Code change by Timothy Paustian Saturday, April 29, 2000 11:00:17 PM
01672     //Changed to dereference h instead of the AEDesc directly.
01673     p = (byte *)*h;
01674     //old code
01675     //p = (byte *) *(*objdata).dataHandle;
01676     
01677     if (*(OSType *)p == (*objdata).descriptorType) /*data begins with redundant type; skip it*/
01678         p += 4;
01679     
01680     BlockMove (p, &ctitems, 4);
01681     
01682     p += 8;
01683     
01684     while (--ctitems >= 0) {
01685         
01686         BlockMove (p, &objspecitem, sizeof (tyobjspecitem));
01687         
01688         p += sizeof (objspecitem);
01689         
01690         if (objspecitem.key == desiredkey) {
01691             
01692             err = AECreateDesc (objspecitem.type, (Ptr) p, objspecitem.size, keydata);
01693             
01694             goto exit;
01695             }
01696         
01697         p += objspecitem.size;
01698         
01699         if (odd (objspecitem.size))
01700             ++p;
01701         }
01702     
01703     err = errAEDescNotFound;
01704     
01705     exit:
01706     
01707     HUnlock (h);
01708     
01709     return (!oserror (err));
01710 
01711     #endif // #if !TARGET_API_MAC_CARBON == 1
01712     } /*getobjspeckeydesc*/
01713 
01714 
01715 static void operatortostring (OSType op, bigstring bsop) {
01716     
01717     byte *p;
01718     
01719     switch (op) {
01720         
01721         case kAEEquals:
01722             p = "\p==";
01723             
01724             break;
01725         
01726         case kAEGreaterThan:
01727             p = "\p>";
01728             
01729             break;
01730         
01731         case kAELessThan:
01732             p = "\p<";
01733             
01734             break;
01735         
01736         case kAEGreaterThanEquals:
01737             p = "\p>=";
01738             
01739             break;
01740         
01741         case kAELessThanEquals:
01742             p = "\p<=";
01743             
01744             break;
01745         
01746         case kAEBeginsWith:
01747             p = "\pbeginsWith";
01748             
01749             break;
01750         
01751         case kAEEndsWith:
01752             p = "\pendsWith";
01753             
01754             break;
01755         
01756         case kAEContains:
01757             p = "\pcontains";
01758             
01759             break;
01760         
01761         case '<>  ':
01762         case '!=  ':
01763             p = "\p!=";
01764             
01765             break;
01766         
01767         case kAENOT:
01768             p = "\pnot";
01769         
01770             break;
01771         
01772         case kAEAND:
01773             p = "\pand";
01774         
01775             break;
01776         
01777         case kAEOR:
01778             p = "\por";
01779             
01780             break;
01781         
01782         default:
01783             p = "\p";
01784             assert(false);  /* 2006-02-08 aradke: this should never happen, but if it does we set p to the empty string */
01785             break;
01786         }
01787     
01788     copystring (p, bsop);
01789     } /*operatortostring*/
01790 
01791 
01792 static boolean testtostring (AEDesc *testdata, bigstring bstest) {
01793     
01794     bigstring bs1, bs2;
01795     byte bsop [16];
01796     AEDesc desc;
01797     DescType type;
01798     boolean fl = false;
01799     OSType op;
01800     
01801     setemptystring (bstest);
01802     
01803     type = (*testdata).descriptorType;
01804     
01805     switch (type) {
01806         
01807         case typeLogicalDescriptor: {
01808             AEDesc itemdesc;
01809             OSType key;
01810             long n, ctitems;
01811             
01812             if (!getobjspeckeydesc (testdata, keyAELogicalOperator, &desc))
01813                 goto exit;
01814             
01815             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01816             
01817                 {
01818                 Handle hcopy;
01819                 
01820                 copydatahandle (&desc, &hcopy);
01821                 
01822                 op = **(OSType **)hcopy;
01823                 
01824                 disposehandle (hcopy);
01825                 }
01826 
01827             #else
01828             
01829                 op = **(OSType **)desc.dataHandle;
01830             
01831             #endif
01832             
01833             operatortostring (op, bsop);
01834             
01835             AEDisposeDesc (&desc);
01836             
01837             if (!getobjspeckeydesc (testdata, keyAELogicalTerms, &desc))
01838                 goto exit;
01839             
01840             if (oserror (AECountItems (&desc, &ctitems)))
01841                 goto exit;
01842             
01843             for (n = 1; n <= ctitems; ++n) {
01844                 
01845                 if (oserror (AEGetNthDesc (&desc, n, typeWildCard, &key, &itemdesc)))
01846                     goto exit;
01847                 
01848                 if (!testtostring (&itemdesc, bs1))
01849                     goto exit;
01850                 
01851                 AEDisposeDesc (&itemdesc);
01852                 
01853                 if (n == 1) {
01854                     
01855                     copystring (bs1, bstest);
01856                     
01857                     if (op == kAENOT) { /*special case -- not infix, only 1 comparison*/
01858                         
01859                         short ix = patternmatch ("\p==", bstest); /*'nother special case*/
01860                         
01861                         if (ix > 0)
01862                             bstest [ix] = '!';
01863                         else
01864                             parsedialogstring ("\p^0 (^1)", bsop, bs1, nil, nil, bstest);
01865                         }
01866                     }
01867                 else {
01868                     copystring (bstest, bs2);
01869                     
01870                     parsedialogstring ("\p^0 ^1 ^2", bs2, bsop, bs1, nil, bstest);
01871                     }
01872                 }
01873             
01874             AEDisposeDesc (&desc);
01875             
01876             break;
01877             }
01878         
01879         case typeCompDescriptor:
01880             
01881             if (!getobjspeckeydesc (testdata, keyAECompOperator, &desc))
01882                 goto exit;
01883             
01884             
01885                 #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
01886             
01887                 {
01888                 Handle hcopy;
01889                 
01890                 copydatahandle (&desc, &hcopy);
01891                 
01892                 op = **(OSType **)hcopy;
01893                 
01894                 disposehandle (hcopy);
01895                 }
01896 
01897                 #else
01898             
01899                     op = **(OSType **)desc.dataHandle;
01900             
01901                 #endif
01902 
01903             operatortostring (op, bsop);
01904             
01905             AEDisposeDesc (&desc);
01906             
01907             if (!getobjspeckeydesc (testdata, keyAEObject1, &desc))
01908                 goto exit;
01909             
01910             if (!objtostring (&desc, true, 0, nil, bs1))
01911                 goto exit;
01912             
01913             if (!getobjspeckeydesc (testdata, keyAEObject2, &desc))
01914                 goto exit;
01915             
01916             if (!objtostring (&desc, true, 0, nil, bs2))
01917                 goto exit;
01918             
01919             parsedialogstring ("\p^0 ^1 ^2", bs1, bsop, bs2, nil, bstest);
01920             
01921             break;
01922         
01923         default:
01924             return (false);
01925         }
01926     
01927     fl = true;
01928     
01929     exit:
01930     
01931     return (fl);
01932     } /*testtostring*/
01933 
01934 
01935 static boolean rangetostring (DescType rangeclass, AEDesc *rangecontainer, AEDesc *rangedata, bigstring bsrange) {
01936     
01937     bigstring bs1, bs2;
01938     AEDesc desc;
01939     boolean fl = false;
01940     
01941     if (!getobjspeckeydesc (rangedata, keyAERangeStart, &desc))
01942         goto exit;
01943     
01944     if (!objtostring (&desc, true, rangeclass, rangecontainer, bs1))
01945         goto exit;
01946     
01947     if (!getobjspeckeydesc (rangedata, keyAERangeStop, &desc))
01948         goto exit;
01949     
01950     if (!objtostring (&desc, true, rangeclass, rangecontainer, bs2))
01951         goto exit;
01952     
01953     parsedialogstring ("\p^0 to ^1", bs1, bs2, nil, nil, bsrange);
01954     
01955     fl = true;
01956     
01957     exit:
01958     
01959     return (fl);
01960     } /*rangetostring*/
01961 
01962 
01963 static boolean getostypeidentifier (OSType id, bigstring bsidentifier) {
01964     
01965     if (getostypedisplaystring (id, bsidentifier)) /*found name for ostype*/
01966         return (true);
01967     
01968     insertchar ('[', bsidentifier); /*must bracket string4 to make it an identifier*/
01969     
01970     pushchar (']', bsidentifier);
01971     
01972     return (false);
01973     } /*getostypeidentifier*/
01974 
01975 
01976 static boolean objtostring (AEDesc *objdesc, boolean fldisposeobj, DescType examinedclass, AEDesc *examinedcontainer, bigstring bsobj) {
01977     
01978     /*
01979     create a string representation of objdesc.
01980     
01981     examinedclass isusually 0, but if we're being called while parsing a range, it's 
01982     the class of the object being examined, in which case we can potentially omit 
01983     redundant class specification of this element
01984     
01985     2.1b1 dmb: supplementing examinedclass, we now take examinedcontainer as well to 
01986     avoid redundancy.
01987     
01988     2.1b4 dmb: check for typeNull before getobjectmodeldisplaystring to avoid 
01989     infinite recursion
01990     */
01991     
01992     DescType class;
01993     DescType keyform;
01994     AEDesc keydata;
01995     AEDesc container;
01996     tyvaluerecord vobj;
01997     tyvaluerecord vkey;
01998     byte bsclass [64];
01999     bigstring bsitem;
02000     boolean fl;
02001     AEDesc tempDesc, *tempDescPtr;  // MJL 17/08/05: Temp desc and ptr so we can compile for both 9 & X
02002     
02003     setemptystring (bsobj);
02004     
02005     if ((*objdesc).descriptorType != typeObjectSpecifier) {
02006         
02007         switch ((*objdesc).descriptorType) {
02008             
02009             case typeObjectBeingExamined:
02010                 copystring ("\pit", bsobj);
02011                 
02012                 AEDisposeDesc (objdesc);
02013                 
02014                 break;
02015             
02016             case typeNull:
02017                 AEDisposeDesc (objdesc); /*leave string empty*/
02018                 
02019                 break;
02020             
02021             default:
02022                 if (!setdescriptorvalue (*objdesc, &vobj))
02023                     return (false);
02024                 
02025                 if (!getobjectmodeldisplaystring (&vobj, bsobj))
02026                     return (false);
02027                 
02028                 disposevaluerecord (vobj, false);
02029                 
02030                 break;
02031             }
02032         
02033         return (true);
02034         }
02035     
02036     fl = false;
02037     
02038     while (true) {
02039         
02040         if (oserror (langsystem7parseobject (objdesc, &class, &container, &keyform, &keydata)))
02041             goto exit;
02042         
02043 #if TARGET_API_MAC_CARBON == 1
02044         // MJL 17/08/05: On X we cannot keep a lazy handle in the AEDesc to the keydata datahandle that gets 
02045         //  pushed onto the Frontier temp stack in the vkey. As we need it later we must duplicate the AEDesc before pushing it.
02046         tempDescPtr = &tempDesc;
02047         AEDuplicateDesc (&keydata, tempDescPtr);
02048 #else
02049         tempDescPtr = &keydata;
02050 #endif
02051         if (!setdescriptorvalue (*tempDescPtr, &vkey)) /*if successful, keydata is on temp stack*/
02052             goto exit;
02053         
02054         getostypeidentifier (class, bsclass);
02055         
02056         switch (keyform) {
02057             
02058             case formTest: {
02059                 bigstring bstest;
02060                 
02061                 if (!testtostring (&keydata, bstest))
02062                     goto exit;
02063                 
02064                 parsedialogstring ("\p^0 [^1]", bsclass, bstest, nil, nil, bsitem);
02065                 
02066                 break;
02067                 }
02068             
02069             case formRange: {
02070                 bigstring bsrange;
02071                 
02072                 if (!rangetostring (class, &container, &keydata, bsrange))
02073                     goto exit;
02074                 
02075                 parsedialogstring ("\p^0 [^1]", bsclass, bsrange, nil, nil, bsitem);
02076                 
02077                 break;
02078                 }
02079             
02080             case formPropertyID: {
02081                 if (!coercetoostype (&vkey))
02082                     goto exit;
02083                 
02084                 getostypeidentifier (vkey.data.ostypevalue, bsitem);
02085                 
02086                 break;
02087                 }
02088             
02089             case formName:
02090             case formAbsolutePosition:
02091             case formRelativePosition: {
02092                 bigstring bskey;
02093                 
02094                 if (!getobjectmodeldisplaystring (&vkey, bskey))
02095                     goto exit;
02096                 
02097                 if (equaldescriptors (examinedcontainer, &container)) {
02098                     
02099                     AEDisposeDesc (&container);
02100                     
02101                     container.descriptorType = typeCurrentContainer;
02102                     }
02103                 
02104                 if ((examinedclass == class) && (container.descriptorType == typeCurrentContainer))
02105                     copystring (bskey, bsitem);
02106                 else
02107                     parsedialogstring ("\p^0 [^1]", bsclass, bskey, nil, nil, bsitem);
02108                 
02109                 break;
02110                 }
02111             
02112             default: {
02113                 byte bsform [64];
02114                 bigstring bskey;
02115                 
02116                 if (!getobjectmodeldisplaystring (&vkey, bskey))
02117                     goto exit;
02118                 
02119                 getostypedisplaystring (keyform, bsform);
02120                 
02121                 parsedialogstring ("\p^0 [^1:^2]", bsclass, bsform, bskey, nil, bsitem);
02122                 
02123                 break;
02124                 }
02125             }
02126         
02127         disposevaluerecord (vkey, false);
02128         
02129 #if TARGET_API_MAC_CARBON == 1
02130         AEDisposeDesc (&keydata);   // MJL 17/08/05 dispose of our duplicated temp AEDesc. On 9 the dataHandle belongs also to the vkey which is disposed above so we don't need to explicitly dispose the AEDesc
02131 #endif
02132         if (fldisposeobj)
02133             AEDisposeDesc (objdesc);
02134         
02135         *objdesc = container;
02136         
02137         fldisposeobj = true;
02138         
02139         if (!isemptystring (bsobj))
02140             insertchar ('.', bsobj);
02141         
02142         if (!insertstring (bsitem, bsobj)) {
02143             
02144             insertchar ('', bsobj);
02145             
02146             break;
02147             }
02148         
02149         if ((*objdesc).descriptorType != typeObjectSpecifier)
02150             break;
02151         }
02152     
02153     fl = true;
02154     
02155     exit:
02156     
02157     if (fldisposeobj)
02158         AEDisposeDesc (objdesc);
02159     
02160     return (fl);
02161     } /*objtostring*/
02162 
02163 
02164 boolean objspectostring (Handle hobjspec, bigstring bs) {
02165     
02166     AEDesc objdesc;
02167     
02168     setupdescriptor (hobjspec, &objdesc);
02169     
02170     return (objtostring (&objdesc, false, 0, nil, bs));
02171     } /*objspectostring*/
02172 
02173 
02174 static void getdefaultcontainer (OSType nulltype, AEDesc *containerdesc, boolean fluseexternalcontainer) {
02175     
02176     /*
02177     8/13/92 dmb: create a container descriptor based on nulltype.
02178     
02179     the smarts: if nulltype is typeNull, and there is a with statement that 
02180     defines a container value, then use that container. otherwise, a normal
02181     null container is returned.
02182     
02183     3.0.3 dmb: added fluseexternalcontainer parameter. if true, allow
02184     "with" statements in external contexts to show through by setting the 
02185     flfindanyspecialsymbol global to true. in practice, we're allowing 
02186     string4 property values to be coerced to objspecs in glue scripts with 
02187     the caller's "with <obj>" statement respected. at the same time, fully-
02188     formed object specifications don't erroniously pick up a parent 
02189     container from a calling script. so, we've created an inconsistency 
02190     that suites our needs and will create expected behavior in most scripts.
02191     */
02192     
02193     hdlhashnode hnode;
02194 
02195     if (nulltype == typeNull) { /*not a special type of null container*/
02196         
02197         tyvaluerecord containerval;
02198         boolean fl;
02199         
02200         flfindanyspecialsymbol = fluseexternalcontainer;
02201         
02202         fl = langgetsymbolval (bscontainername, &containerval, &hnode);
02203         
02204         flfindanyspecialsymbol = false; /*restore to default*/
02205                 
02206         if (fl) { /*got container*/
02207             
02208             setupdescriptor (containerval.data.objspecvalue, containerdesc);
02209             
02210             return;
02211             }
02212         }
02213     
02214     #if TARGET_API_MAC_CARBON == 1
02215         
02216         newdescnull (containerdesc, nulltype);
02217     
02218     #else
02219     
02220         (*containerdesc).descriptorType = nulltype;
02221     
02222         (*containerdesc).dataHandle = nil;
02223     
02224     #endif
02225     } /*getdefaultcontainer*/
02226 
02227 
02228 static boolean createpropertyspecifier (AEDesc *containerdesc, OSType propkey, AEDesc *objectdesc) {
02229     
02230     AEDesc keydatadesc;
02231     OSErr errcode;
02232     
02233     errcode = AECreateDesc (typeType, (Ptr) &propkey, longsizeof (propkey), &keydatadesc);
02234     
02235     if (oserror (errcode))
02236         return (false);
02237     
02238     errcode = CreateObjSpecifier (cProperty, containerdesc, formPropertyID, &keydatadesc, false, objectdesc);
02239     
02240     AEDisposeDesc (&keydatadesc);
02241     
02242     return (!oserror (errcode));
02243     } /*createpropertyspecifier*/
02244 
02245 
02246 static boolean valtoobjspec (tyvaluerecord *val, OSType nulltype, AEDesc *objectdesc) {
02247     
02248     /*
02249     return an object specifier interpretation of the given value record. 
02250     val should be a temporary value. object is returned free & clear; the 
02251     caller is responsible for its handle.
02252     
02253     12/24/91 dmb: when coercing from binary, make sure we form null spec
02254     properly with nil handle.
02255     
02256     6/24/92 dmb: fixed heap bug in binary-to-objspec coercion (when null)
02257     
02258     9/14/92 dmb: finalized treatment of null objects.
02259     */
02260     
02261     register tyvaluerecord *v = val;
02262     register AEDesc *obj = objectdesc;
02263     OSType id;
02264     AEDesc containerdesc;
02265     Handle x;
02266     
02267     switch ((*v).valuetype) {
02268         
02269         case objspecvaluetype:
02270             x = (*v).data.objspecvalue;
02271             
02272             break;
02273         
02274         case binaryvaluetype:
02275             if (!coercebinaryval (v, objspecvaluetype, 0L, objspecvaluetype))
02276                 return (false);
02277             
02278             x = (*v).data.objspecvalue;
02279             
02280             if (gethandlesize (x) == 0) { /*null spec; special case*/
02281                 
02282                 releaseheaptmp (x);
02283                 
02284                 x = nil;
02285                 }
02286             
02287             break;
02288         
02289         case recordvaluetype: {
02290             
02291             AEDesc desc;
02292             
02293             if (!langipcconvertoplist (v, &desc))
02294                 return (false);
02295             
02296             if (oserror (AECoerceDesc (&desc, typeObjectSpecifier, obj)))
02297                 return (false);
02298             
02299             exemptfromtmpstack (v);
02300             
02301             return (true);
02302             }
02303         
02304         case ostypevaluetype:
02305             id = (*v).data.ostypevalue;
02306             
02307             getdefaultcontainer (nulltype, &containerdesc, true);
02308             
02309             if (id == typeObjectBeingExamined) /*special "it" value*/
02310                 return (!oserror (AEDuplicateDesc (&containerdesc, obj)));
02311             
02312             return (createpropertyspecifier (&containerdesc, id, obj));
02313         
02314         default:
02315             if ((*v).data.longvalue == 0) { /*a nil value -- special case*/
02316                 
02317                 x = nil;
02318                 
02319                 break;
02320                 }
02321             
02322             langcoerceerror (v, objspecvaluetype);
02323             
02324             return (false);
02325         } /*switch*/
02326     
02327     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02328     
02329         if (x == nil)
02330         
02331             newdescwithhandle (obj, typeNull, x);
02332         
02333         else {
02334         
02335             exemptfromtmpstack (v);
02336             
02337             newdescwithhandle (obj, typeObjectSpecifier, x);
02338             } /*else*/
02339     
02340     #else
02341     
02342         (*obj).dataHandle = x;
02343     
02344         
02345         if (x == nil) {
02346             
02347             (*obj).descriptorType = typeNull; /*don't use nulltype here; nil spec is always typeNull*/
02348             }
02349         else {
02350             
02351             exemptfromtmpstack (v);
02352             
02353             (*obj).descriptorType = typeObjectSpecifier;
02354             }
02355         
02356     #endif
02357     return (true);
02358     } /*valtoobjspec*/
02359 
02360 
02361 boolean coercetoobjspec (tyvaluerecord *v) {
02362     
02363     /*
02364     9/14/92 dmb: this guy's guts have been moved into valtoobjspec
02365     
02366     2.1b2 dmb: added missing case for list->objspec
02367     
02368     2.1b5 dmb: added support for filespec->objspec
02369     */
02370     
02371     AEDesc objectdesc;
02372     
02373     switch ((*v).valuetype) {
02374         
02375         case objspecvaluetype:
02376             return (true);
02377         
02378         case stringvaluetype:
02379             return (stringtoobjspec (v));
02380         
02381         case listvaluetype:
02382             return (coercelistvalue (v, objspecvaluetype));
02383         
02384         case filespecvaluetype:
02385             return (filespectoobjspec (v));
02386         
02387         default:
02388             if (!valtoobjspec (v, typeNull, &objectdesc))
02389                 return (false);
02390             
02391             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02392             
02393                 {
02394                 Handle h;
02395                 
02396                 copydatahandle (&objectdesc, &h);
02397                 
02398                 return (setheapvalue (h, objspecvaluetype, v));
02399                 }           
02400             
02401             #else
02402             
02403                 return (setheapvalue (objectdesc.dataHandle, objspecvaluetype, v));
02404             
02405             #endif
02406         } /*switch*/
02407     } /*coercetoobjspec*/
02408 
02409 
02410 boolean setobjspecverb (hdltreenode hparam1, tyvaluerecord *val) {
02411     
02412     /*
02413     a brute-force verb to building object specifiers.
02414     
02415     8/31/92 dmb: if the keyform isn't one of the three simple grammar forms, 
02416     assume that the script writer is trying to do a custom keyform, and 
02417     take the keydata literally. with this change, setobj continues to offer 
02418     functionality that isn't otherwise available.
02419     */
02420     
02421     OSType class;
02422     tyvaluerecord container;
02423     OSType keyform;
02424     long longkey;
02425     bigstring bskey;
02426     OSType propkey;
02427     tyvaluerecord customkey;
02428     AEDesc containerdesc;
02429     AEDesc keydatadesc;
02430     AEDesc objspecdesc;
02431     OSErr errcode = noErr;
02432     
02433     
02434     #ifdef flsystem6
02435     
02436     if (!langcanuseappleevents ())
02437         return (false);
02438     
02439     #endif
02440     
02441     if (!getostypevalue (hparam1, 1, &class))
02442         return (false);
02443     
02444     if (!getobjspecparam (hparam1, 2, &container))
02445         return (false);
02446     
02447     if (!getostypevalue (hparam1, 3, &keyform))
02448         return (false);
02449     
02450     flnextparamislast = true;
02451     
02452     switch (keyform) {
02453         
02454         case formName:
02455             if (!getstringvalue (hparam1, 4, bskey))
02456                 return (false);
02457             
02458             errcode = AECreateDesc (typeChar, (Ptr) bskey + 1, (long) stringlength (bskey), &keydatadesc);
02459             
02460             break;
02461         
02462         case formAbsolutePosition:
02463             if (!getlongvalue (hparam1, 4, &longkey))
02464                 return (false);
02465             
02466             errcode = AECreateDesc (typeLongInteger, (Ptr) &longkey, longsizeof (longkey), &keydatadesc);
02467             
02468             break;
02469         
02470         case formPropertyID:
02471             if (!getostypevalue (hparam1, 4, &propkey))
02472                 return (false);
02473             
02474             errcode = AECreateDesc (typeType, (Ptr) &propkey, longsizeof (propkey), &keydatadesc);
02475             
02476             break;
02477         
02478         default:
02479             if (!getparamvalue (hparam1, 4, &customkey))
02480                 return (false);
02481             
02482             if (!valuetodescriptor (&customkey, &keydatadesc)) /*consumes customkey*/
02483                 return (false);
02484             
02485             break;
02486             
02487         }
02488     
02489     if (oserror (errcode))
02490         return (false);
02491     
02492     setupdescriptor (container.data.objspecvalue, &containerdesc);
02493     
02494     errcode = CreateObjSpecifier (class, &containerdesc, keyform, &keydatadesc, false, &objspecdesc);
02495     
02496     AEDisposeDesc (&keydatadesc);
02497     
02498     if (oserror (errcode))
02499         return (false);
02500 
02501     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02502 
02503         {
02504         Handle h;
02505         
02506         copydatahandle (&objspecdesc, &h);
02507         
02508         return (setheapvalue (h, objspecvaluetype, val));
02509         }           
02510 
02511     #else
02512 
02513         return (setheapvalue (objspecdesc.dataHandle, objspecvaluetype, val));
02514     
02515     #endif
02516     } /*setobjspecverb*/
02517 
02518 
02519 static boolean getclassvalue (hdltreenode htree, OSType *class) {
02520     
02521     tyvaluerecord val;
02522     
02523     if ((**htree).nodetype == bracketop) /*shed brackets if present*/
02524         htree = (**htree).param1;
02525     
02526     if (!evaluatetree (htree, &val))
02527         return (false);
02528     
02529     if (!coercetoostype (&val))
02530         return (false);
02531     
02532     *class = val.data.ostypevalue;
02533     
02534     return (true);
02535     } /*getclassvalue*/
02536 
02537 
02538 static boolean evaluateobject (hdltreenode htree, OSType nulltype, AEDesc *objectdesc); /*forward*/
02539 
02540 
02541 static boolean evaluateproperty (hdltreenode htree, OSType nulltype, AEDesc *objectdesc) {
02542     
02543     /*
02544     1/25/93 dmb: keep track of tmps and dispose if created (to avoid tmpstack overflow)
02545     */
02546     
02547     register hdltreenode h = htree;
02548     register hdltreenode hp1;
02549     register tytreetype op;
02550     AEDesc containerdesc;
02551     OSType propkey;
02552     boolean fltmp = false;
02553     
02554     #if TARGET_API_MAC_CARBON == 1
02555     
02556         Handle hcopy;
02557         
02558     #endif
02559     
02560     assert (h != nil);
02561     
02562     langseterrorline (h); /*set globals for error reporting*/
02563     
02564     op = (**h).nodetype; /*copy into register*/
02565     
02566     hp1 = (**h).param1;
02567     
02568     switch (op) {
02569         
02570         case identifierop:
02571         case bracketop:
02572             if (!getclassvalue (h, &propkey))
02573                 return (false);
02574             
02575             getdefaultcontainer (nulltype, &containerdesc, true);
02576             
02577             break;
02578         
02579         case dotop:
02580             if (!evaluateobject ((**h).param1, nulltype, &containerdesc)) /*daisy-chain recursion*/
02581                 return (false);
02582             
02583             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02584             
02585                 copydatahandle (&containerdesc, &hcopy);
02586                 
02587                 pushtmpstack (hcopy);
02588                         
02589             #else
02590             
02591                 pushtmpstack (containerdesc.dataHandle); /*until it's merged*/
02592             
02593             #endif
02594             
02595             fltmp = true;
02596             
02597             if (!getclassvalue ((**h).param2, &propkey))
02598                 return (false);
02599             
02600             break;
02601         
02602         default:
02603             langerror (badobjectspecificationerror);
02604             
02605             return (false);
02606         }
02607     
02608     if (!createpropertyspecifier (&containerdesc, propkey, objectdesc))
02609         return (false);
02610     
02611     if (fltmp)
02612     
02613         #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02614         
02615             releaseheaptmp (hcopy);
02616 
02617         #else
02618     
02619             releaseheaptmp (containerdesc.dataHandle);
02620     
02621         #endif
02622         
02623     return (true);
02624     } /*evaluateproperty*/
02625 
02626 
02627 static boolean evaluatesimplekey (hdltreenode htree, OSType *keyform, AEDesc *keydatadesc) {
02628     
02629     /*
02630     8/10/92 dmb: fixed constants for formRelativePosition specifiers
02631     */
02632     
02633     bigstring bskey;
02634     DescType type;
02635     long longkey;
02636     tyvaluerecord keyval;
02637     OSErr errcode;
02638     
02639     if (!evaluatetree (htree, &keyval))
02640         return (false);
02641     
02642     switch (keyval.valuetype) {
02643         
02644         case stringvaluetype:
02645             pullstringvalue (&keyval, bskey);
02646             
02647             errcode = AECreateDesc (typeChar, (Ptr) bskey + 1, (long) stringlength (bskey), keydatadesc);
02648             
02649             *keyform = formName;
02650             
02651             break;
02652         
02653         case ostypevaluetype:
02654             longkey = (long) keyval.data.ostypevalue;
02655             
02656             if ((longkey == kAENext) || (longkey == kAEPrevious)) {
02657                 
02658                 type = typeEnumeration;
02659                 
02660                 *keyform = formRelativePosition;
02661                 }
02662             else {
02663                 
02664                 type = typeAbsoluteOrdinal;
02665                 
02666                 *keyform = formAbsolutePosition;
02667                 }
02668             
02669             errcode = AECreateDesc (type, (Ptr) &longkey, longsizeof (longkey), keydatadesc);
02670             
02671             break;
02672         
02673         default:
02674             if (!coercetolong (&keyval))
02675                 return (false);
02676             
02677             longkey = keyval.data.longvalue;
02678             
02679             errcode = AECreateDesc (typeLongInteger, (Ptr) &longkey, longsizeof (longkey), keydatadesc);
02680             
02681             *keyform = formAbsolutePosition;
02682             
02683             break;
02684         }
02685     
02686     return (!oserror (errcode));
02687     } /*evaluatesimplekey*/
02688 
02689 
02690 static boolean evaluatefield (hdltreenode htree, OSType *key, AEDesc *data) {
02691     
02692     /*
02693     3/23/93 dmb: htree is a x:y field specification. return the field key, 
02694     and the field data as a descriptor record whose dataHandle is not on the 
02695     temp stack.
02696     */
02697     
02698     register hdltreenode h = htree;
02699     tyvaluerecord keyval;
02700     tyvaluerecord itemval;
02701     
02702     assert ((**h).nodetype == fieldop);
02703     
02704     if (!evaluatetree ((**h).param1, &keyval))
02705         return (false);
02706     
02707     if (!coercetoostype (&keyval))
02708         return (false);
02709     
02710     if (!evaluatetree ((**h).param2, &itemval))
02711         return (false);
02712     
02713     if (!valuetodescriptor (&itemval, data)) /*consumes itemval*/
02714         return (false);
02715     
02716     *key = keyval.data.ostypevalue;
02717     
02718     return (true);
02719     } /*evaluatefield*/
02720 
02721 
02722 static boolean evaluatecustomkey (hdltreenode htree, OSType *keyform, AEDesc *keydatadesc) {
02723     
02724     /*
02725     3/23/93 dmb: a custom key looks like a single field in a record, 
02726     an x:y field specification. our job is to return the keyform and keydata, without anything on 
02727     the temp stack
02728     */
02729     
02730     if (!evaluatefield (htree, keyform, keydatadesc))
02731         return (false);
02732     
02733     /*
02734     removeheaptmp ((*keydatadesc).dataHandle);
02735     */
02736     
02737     return (true);
02738     } /*evaluatecustomkey*/
02739 
02740 
02741 static boolean evaluatecomparison (hdltreenode htree, DescType operator, AEDesc *keydatadesc) {
02742     
02743     /*
02744     1/25/93 dmb: dispose tmps (to avoid tmpstack overflow)
02745     */
02746     
02747     register hdltreenode h = htree;
02748     AEDesc objectdesc;
02749     tyvaluerecord val;
02750     AEDesc valdesc;
02751     OSErr errcode;
02752     
02753     #if TARGET_API_MAC_CARBON == 1
02754     
02755         Handle hcopy;
02756     
02757     #endif
02758     
02759     if (!evaluateobject ((**h).param1, typeObjectBeingExamined, &objectdesc))
02760         return (false);
02761     
02762     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02763     
02764         copydatahandle (&objectdesc, &hcopy);
02765         
02766         pushtmpstack (hcopy);
02767     
02768     #else
02769     
02770         pushtmpstack (objectdesc.dataHandle); /*until it's merged*/
02771     
02772     #endif
02773     
02774     if (!evaluatetree ((**h).param2, &val))
02775         return (false);
02776     
02777     if (!valuetodescriptor (&val, &valdesc))
02778         return (false);
02779     
02780     errcode = CreateCompDescriptor (operator, &objectdesc, &valdesc, false, keydatadesc);
02781     
02782     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
02783 
02784         releaseheaptmp (hcopy);
02785     
02786     #else
02787         
02788         releaseheaptmp (objectdesc.dataHandle); /*keep tmpstack cleared out*/
02789     
02790     #endif
02791     
02792     AEDisposeDesc (&valdesc);
02793     
02794     return (!oserror (errcode));
02795     } /*evaluatecomparison*/
02796 
02797 
02798 static boolean evaluatetest (hdltreenode, tytreetype, AEDesc *);
02799 
02800 
02801 static boolean evaluatelogical (hdltreenode hcomp1, tytreetype op1, hdltreenode hcomp2, tytreetype op2, DescType operator, AEDesc *keydatadesc) {
02802     
02803     AEDesc compdesc1, compdesc2;
02804     AEDesc listdesc;
02805     
02806     if (oserror (AECreateList (nil, 0, false, &listdesc)))
02807         return (false);
02808     
02809     if (!evaluatetest (hcomp1, op1, &compdesc1))
02810         goto error;
02811     
02812     if (oserror (AEPutDesc (&listdesc, 0, &compdesc1)))
02813         goto error;
02814     
02815     AEDisposeDesc (&compdesc1);
02816     
02817     if (hcomp2 != nil) {
02818         
02819         if (!evaluatetest (hcomp2, op2, &compdesc2))
02820             goto error;
02821         
02822         if (oserror (AEPutDesc (&listdesc, 0, &compdesc2)))
02823             goto error;
02824         
02825         AEDisposeDesc (&compdesc2);
02826         }
02827     
02828     return (!oserror (CreateLogicalDescriptor (&listdesc, operator, true, keydatadesc)));
02829     
02830     error: {
02831         
02832         AEDisposeDesc (&listdesc);
02833         
02834         return (false);
02835         }
02836     } /*evaluatelogical*/
02837 
02838 
02839 static boolean evaluatetest (hdltreenode htree, tytreetype op, AEDesc *keydatadesc) {
02840     
02841     /*
02842     12/8/92 dmb: created this routine to dispath logical & comarison ops, so 
02843     that logical operands can in turn be any kind of test, not just comparisons. 
02844     this removes the 2-criteria limiation of the 1st release of 2.0.
02845     
02846     not: the reason that op is passed in is to support the handling of NEop, since 
02847     there is not corresponding AE comparison operator. instead, if must be forced 
02848     to EQop, and put inside of a logical NOT expression.
02849     */
02850     
02851     register hdltreenode h = htree;
02852     register DescType operator;
02853     hdltreenode hp1 = (**h).param1;
02854     
02855     if (op == noop) /*not pre-determined*/
02856         
02857         op = (**h).nodetype;
02858     
02859     switch (op) {
02860         
02861         case EQop:
02862             operator = kAEEquals;
02863             
02864             break;
02865         
02866         case GTop:
02867             operator = kAEGreaterThan;
02868             
02869             break;
02870         
02871         case LTop:
02872             operator = kAELessThan;
02873             
02874             break;
02875         
02876         case GEop:
02877             operator = kAEGreaterThanEquals;
02878             
02879             break;
02880         
02881         case LEop:
02882             operator = kAELessThanEquals;
02883             
02884             break;
02885         
02886         case beginswithop:
02887             operator = kAEBeginsWith;
02888             
02889             break;
02890         
02891         case endswithop:
02892             operator = kAEEndsWith;
02893             
02894             break;
02895         
02896         case containsop:
02897             operator = kAEContains;
02898             
02899             break;
02900         
02901         case NEop:
02902             return (evaluatelogical (h, EQop, nil, (tytreetype) 0, kAENOT, keydatadesc));
02903         
02904         case notop:
02905             return (evaluatelogical (hp1, noop, nil, (tytreetype) 0, kAENOT, keydatadesc));
02906         
02907         case andandop:
02908             return (evaluatelogical (hp1, noop, (**h).param2, (tytreetype) 0, kAEAND, keydatadesc));
02909         
02910         case ororop:
02911             return (evaluatelogical (hp1, noop, (**h).param2, (tytreetype) 0, kAEOR, keydatadesc));
02912         
02913         default:
02914             langlongparamerror (badobjectspecificationerror, (long) op);
02915             
02916             return (false);
02917         }
02918     
02919     /*common code for comarisons*/
02920     
02921     return (evaluatecomparison (h, operator, keydatadesc));
02922     } /*evaluatetest*/
02923 
02924 
02925 static boolean evaluateboundryobject (hdltreenode htree, OSType rangeclass, AEDesc *objectdesc) {
02926     
02927     register hdltreenode h = htree;
02928     OSType keyform;
02929     AEDesc containerdesc;
02930     AEDesc keydatadesc;
02931     OSErr errcode;
02932     
02933     if (isobjspectree (h))
02934         return (evaluateobject (h, typeCurrentContainer, objectdesc));
02935     
02936     if (!evaluatesimplekey (h, &keyform, &keydatadesc))
02937         return (false);
02938         
02939     #if TARGET_API_MAC_CARBON == 1
02940     
02941         nildatahandle (&containerdesc);
02942     
02943     #else
02944         
02945         containerdesc.dataHandle = nil;
02946     
02947     #endif
02948 
02949     containerdesc.descriptorType = typeCurrentContainer;
02950     
02951     errcode = CreateObjSpecifier (rangeclass, &containerdesc, keyform, &keydatadesc, true, objectdesc);
02952     
02953     return (!oserror (errcode));
02954     } /*evaluateboundryobject*/
02955 
02956 
02957 static boolean evaluaterange (hdltreenode htree, OSType class, AEDesc *keydatadesc) {
02958     
02959     register hdltreenode h = htree;
02960     AEDesc rangedesc1, rangedesc2;
02961     OSErr errcode;
02962     
02963     if (!evaluateboundryobject ((**h).param1, class, &rangedesc1))
02964         return (false);
02965     
02966     if (!evaluateboundryobject ((**h).param2, class, &rangedesc2)) {
02967         
02968         AEDisposeDesc (&rangedesc1);
02969         
02970         return (false);
02971         }
02972     
02973     errcode = CreateRangeDescriptor (&rangedesc1, &rangedesc2, true, keydatadesc);
02974     
02975     return (!oserror (errcode));
02976     } /*evaluaterange*/
02977 
02978 
02979 static boolean evaluateelement (hdltreenode htree, OSType nulltype, OSType *elementclass, AEDesc *objectdesc) {
02980     
02981     /*
02982     9/14/92 dmb: interpret double-array operations has specifying the same class as the 
02983     container, so that:
02984         
02985         word [it beginsWith "foo"] [last]
02986         
02987     means "the last word that begins with "foo". assuming, of course, that the app 
02988     knows how to resolve such a specifier
02989     
02990     1/25/93 dmb: keep track of tmps and dispose if created (to avoid tmpstack overflow)
02991     */
02992     
02993     register hdltreenode h = htree;
02994     register hdltreenode hp1, hp2;
02995     register tytreetype op;
02996     OSType keyform;
02997     AEDesc containerdesc;
02998     AEDesc keydatadesc;
02999     OSType class;
03000     OSErr errcode;
03001     boolean fltmp = false;
03002     
03003     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
03004     
03005         Handle hcopy;
03006     
03007     #endif
03008     
03009     assert (h != nil);
03010     
03011     langseterrorline (h); /*set globals for error reporting*/
03012     
03013     op = (**h).nodetype; /*copy into register*/
03014     
03015     assert (op == arrayop);
03016     
03017     hp1 = (**h).param1;
03018     
03019     op = (**hp1).nodetype;
03020     
03021     switch (op) {
03022         
03023         case identifierop:
03024         case bracketop:
03025             if (!getclassvalue (hp1, &class))
03026                 return (false);
03027             
03028             getdefaultcontainer (nulltype, &containerdesc, false);
03029             
03030             break;
03031         
03032         case dotop:
03033             if (!evaluateobject ((**hp1).param1, nulltype, &containerdesc)) /*daisy-chain recursion*/
03034                 return (false);
03035             
03036             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
03037             
03038                 copydatahandle (&containerdesc, &hcopy);
03039                 
03040                 pushtmpstack (hcopy);
03041             
03042             #else
03043             
03044                 pushtmpstack (containerdesc.dataHandle); /*until it's merged*/
03045             
03046             #endif
03047             
03048             fltmp = true;
03049             
03050             if (!getclassvalue ((**hp1).param2, &class))
03051                 return (false);
03052             
03053             break;
03054         
03055         case arrayop:
03056             if (!evaluateelement (hp1, nulltype, &class, &containerdesc))
03057                 return (false);
03058 
03059             #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
03060             
03061                 copydatahandle (&containerdesc, &hcopy);
03062                 
03063                 pushtmpstack (hcopy);
03064             
03065             #else
03066             
03067                 pushtmpstack (containerdesc.dataHandle); /*until it's merged*/
03068                 
03069             #endif
03070             
03071             fltmp = true;
03072             
03073             break;
03074         
03075         default:
03076             langlongparamerror (badobjectspecificationerror, (long) op);
03077             
03078             return (false);
03079         }
03080     
03081     hp2 = (**h).param2;
03082     
03083     op = (**hp2).nodetype;
03084     
03085     switch (op) {
03086         
03087         case EQop:
03088         case GTop:
03089         case LTop:
03090         case GEop:
03091         case LEop:
03092         case beginswithop:
03093         case endswithop:
03094         case containsop:
03095         case NEop:
03096         case notop:
03097         case andandop:
03098         case ororop:
03099             if (!evaluatetest (hp2, op, &keydatadesc))
03100                 return (false);
03101             
03102             keyform = formTest;
03103             
03104             break;
03105         
03106         case rangeop:
03107             if (!evaluaterange (hp2, class, &keydatadesc))
03108                 return (false);
03109             
03110             keyform = formRange;
03111             
03112             break;
03113         
03114         case fieldop:
03115             if (!evaluatecustomkey (hp2, &keyform, &keydatadesc))
03116                 return (false);
03117             
03118             break;
03119         
03120         default:
03121             if (!evaluatesimplekey (hp2, &keyform, &keydatadesc))
03122                 return (false);
03123             
03124             break;
03125         }
03126     
03127     errcode = CreateObjSpecifier (class, &containerdesc, keyform, &keydatadesc, false, objectdesc);
03128     
03129     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
03130     
03131         if (fltmp)
03132             releaseheaptmp (hcopy);
03133     
03134     #else
03135     
03136         if (fltmp)
03137             releaseheaptmp (containerdesc.dataHandle);
03138     
03139     #endif
03140     
03141     AEDisposeDesc (&keydatadesc);
03142     
03143     *elementclass = class;
03144     
03145     return (!oserror (errcode));
03146     } /*evaluateelement*/
03147 
03148 
03149 static boolean evaluateobject (hdltreenode htree, OSType nulltype, AEDesc *objectdesc) {
03150     
03151     /*
03152     evaluate an object specifier code tree
03153     
03154     3/18/93 dmb: added stack space check
03155     */
03156     
03157     register hdltreenode h = htree;
03158     register tytreetype op;
03159     OSType class;
03160     tyvaluerecord val;
03161     
03162     if (fllangerror) { /*a language error dialog has appeared, unwind*/
03163         
03164         return (false); /*return false, aid in the unwinding process*/
03165         }
03166     
03167     if (!langcheckstackspace ())
03168         return (false);
03169     
03170     assert (h != nil);
03171     
03172     op = (**h).nodetype; /*copy into register*/
03173     
03174     //langseterrorline (h); /*set globals for error reporting*/
03175     
03176     switch (op) {
03177         
03178         case identifierop:
03179             if (!evaluatetree (h, &val))
03180                 return (false);
03181             
03182             if (!valtoobjspec (&val, nulltype, objectdesc))
03183                 return (false);
03184             
03185             break;
03186             
03187         case bracketop:
03188             if (!evaluatetree ((**h).param1, &val))
03189                 return (false);
03190             
03191             if (!valtoobjspec (&val, nulltype, objectdesc))
03192                 return (false);
03193             
03194             break;
03195         
03196         case dotop:
03197             if (!evaluateproperty (h, nulltype, objectdesc))
03198                 return (false);
03199             
03200             break;
03201         
03202         case arrayop:
03203             if (!evaluateelement (h, nulltype, &class, objectdesc))
03204                 return (false);
03205             
03206             break;
03207         
03208         default:
03209             langlongparamerror (badobjectspecificationerror, (long) op);
03210             
03211             return (false);
03212         }
03213     
03214     return (true);
03215     } /*evaluateobject*/
03216 
03217 
03218 boolean evaluateobjspec (hdltreenode htree, tyvaluerecord *vreturned) {
03219     
03220     AEDesc objectdesc;
03221     
03222     if (!evaluateobject (htree, typeNull, &objectdesc))
03223         return (false);
03224     
03225     #if TARGET_API_MAC_CARBON == 1 /*PBS 03/14/02: AE OS X fix.*/
03226     
03227         {
03228         Handle h;
03229         
03230         copydatahandle (&objectdesc, &h);
03231         
03232         return (setheapvalue (h, objspecvaluetype, vreturned));
03233         }
03234     
03235     #else
03236     
03237         return (setheapvalue (objectdesc.dataHandle, objspecvaluetype, vreturned));
03238 
03239     #endif
03240     } /*evaluateobjspec*/
03241 
03242 
03243 static boolean getidvalue (hdltreenode htree, tyvaluerecord *val) {
03244     
03245     /*
03246     just like idvalue, but we don't make a copy
03247     
03248     2.1b2 dmb: dive into bracketops to more closely simulate objspec evaluation
03249     
03250     7.2.97 dmb: prevent extended symbol searching in langgetsymbolval
03251     */
03252     
03253     register hdltreenode h = htree;
03254     bigstring bs;
03255     hdlhashtable htable;
03256     boolean fl = false;
03257     hdlhashnode hnode;
03258     
03259     switch ((**h).nodetype) {
03260         
03261         case bracketop: /*look for string4 literal only*/
03262             
03263             h = (**h).param1;
03264             
03265             if ((**h).nodetype != constop)
03266                 break;
03267             
03268             *val = (**h).nodeval;
03269             
03270             fl = true;
03271             
03272             break;
03273         
03274         case identifierop:
03275             
03276             if (!langgetidentifier (h, bs))
03277                 break;
03278             
03279             langsearchpathlookup (bs, &htable);
03280             
03281             pushhashtable (htable);
03282             
03283             fl = langgetsymbolval (bs, val, &hnode);
03284             
03285             pophashtable ();
03286             
03287             break;
03288         
03289         default:
03290             break;
03291         }
03292     
03293     return (fl);
03294     } /*getidvalue*/
03295 
03296 
03297 boolean isobjspectree (hdltreenode htree) {
03298     
03299     /*
03300     determine whether the given code tree appears to be an object specification.
03301     
03302     at this point we're observing the following rule: an objspec expression may 
03303     be a dotted id or an array operation (which yeild properties & elements 
03304     respectively), and the root of the tree must be an objspec or a string4 (a 
03305     class id).  any such expression is likely to be intended as an objspec, and 
03306     will certainly fail when evaluated normally.
03307     
03308     note that the objspec verb can always be used to force an expression to be 
03309     evaluated as an object specifier.
03310     
03311     also note that we don't call idvalue at the end to avoid creating a copy of 
03312     the value record.
03313     
03314     special note: for performance, we currently assume that we're only being called 
03315     by dotvalue and arrayvalue, so we can go directly to param1.
03316     
03317     1/13/93 dmb: if param2 of a dotop is an undefined identifier, keep scanning so 
03318     param1 can be checked. this allows the appropriate error message to be generated.
03319     */
03320     
03321     register hdltreenode h = htree;
03322     register tytreetype op;
03323     tyvaluerecord val;
03324     
03325     while (true) {
03326         
03327         op = (**h).nodetype;
03328         
03329         switch (op) {
03330             
03331             case dotop: { /*verify current dot node, then continue scanning tree*/
03332                 
03333                 register hdltreenode hp2 = (**h).param2;
03334                 
03335                 if (true /*(**hp2).nodetype == identifierop*/) { /*a node we can check quickly w/no side-effects*/
03336                     
03337                     if (getidvalue (hp2, &val)) {
03338                         
03339                         if (val.valuetype != ostypevaluetype)
03340                             return (false);
03341                         }
03342                     }
03343                 
03344                 break;
03345                 }
03346             
03347             case arrayop: /*continue scanning tree*/
03348                 break;
03349             
03350             case bracketop:
03351             case identifierop:
03352                 if (!getidvalue (h, &val))
03353                     return (false);
03354                 
03355                 return ((val.valuetype == objspecvaluetype) || (val.valuetype == ostypevaluetype));
03356                 
03357             default:
03358                 return (false);
03359             }
03360         
03361         h = (**h).param1;
03362         }
03363     } /*isobjspectree*/
03364 
03365 #endif
03366 
03367 

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