"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/var.h" (8 May 2021, 46454 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "var.h" see the Fossies "Dox" file reference documentation.

    1 /*
    2 AutoHotkey
    3 
    4 Copyright 2003-2009 Chris Mallett (support@autohotkey.com)
    5 
    6 This program is free software; you can redistribute it and/or
    7 modify it under the terms of the GNU General Public License
    8 as published by the Free Software Foundation; either version 2
    9 of the License, or (at your option) any later version.
   10 
   11 This program is distributed in the hope that it will be useful,
   12 but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 GNU General Public License for more details.
   15 */
   16 
   17 #ifndef var_h
   18 #define var_h
   19 
   20 #include "defines.h"
   21 #include "SimpleHeap.h"
   22 #include "clipboard.h"
   23 #include "util.h" // for strlcpy() & snprintf()
   24 EXTERN_CLIPBOARD;
   25 extern BOOL g_WriteCacheDisabledInt64;
   26 extern BOOL g_WriteCacheDisabledDouble;
   27 
   28 #define MAX_ALLOC_SIMPLE 64  // Do not decrease this much since it is used for the sizing of some built-in variables.
   29 #define SMALL_STRING_LENGTH (MAX_ALLOC_SIMPLE - 1)  // The largest string that can fit in the above.
   30 #define DEREF_BUF_EXPAND_INCREMENT (16 * 1024) // Reduced from 32 to 16 in v1.0.46.07 to reduce the memory utilization of deeply recursive UDFs.
   31 #define ERRORLEVEL_NONE _T("0")
   32 #define ERRORLEVEL_ERROR _T("1")
   33 #define ERRORLEVEL_ERROR2 _T("2")
   34 
   35 enum AllocMethod {ALLOC_NONE, ALLOC_SIMPLE, ALLOC_MALLOC};
   36 enum VarTypes
   37 {
   38   // The following must all be LOW numbers to avoid any realistic chance of them matching the address of
   39   // any function (namely a BIV_* function).
   40   VAR_ALIAS  // VAR_ALIAS must always have a non-NULL mAliasFor.  In other ways it's the same as VAR_NORMAL.  VAR_ALIAS is never seen because external users call Var::Type(), which automatically resolves ALIAS to some other type.
   41 , VAR_NORMAL // Most variables, such as those created by the user, are this type.
   42 , VAR_CLIPBOARD
   43 , VAR_LAST_WRITABLE = VAR_CLIPBOARD  // Keep this in sync with any changes to the set of writable variables.
   44 #define VAR_IS_READONLY(var) ((var).Type() > VAR_LAST_WRITABLE)
   45 , VAR_CLIPBOARDALL // Must be read-only because it's not designed to be writable.
   46 , VAR_BUILTIN
   47 , VAR_LAST_TYPE = VAR_BUILTIN
   48 };
   49 
   50 typedef UCHAR VarTypeType;     // UCHAR vs. VarTypes to save memory.
   51 typedef UCHAR AllocMethodType; // UCHAR vs. AllocMethod to save memory.
   52 typedef UCHAR VarAttribType;   // Same.
   53 typedef UINT_PTR VarSizeType;  // jackieku(2009-10-23): Change this to UINT_PTR to ensure its size is the same with a pointer.
   54 #define VARSIZE_MAX ((VarSizeType) ~0)
   55 #define VARSIZE_ERROR VARSIZE_MAX
   56 
   57 class Var; // Forward declaration.
   58 // #pragma pack(4) not used here because although it would currently save 4 bytes per VarBkp struct (28 vs. 32),
   59 // it would probably reduce performance since VarBkp items are stored in contiguous array rather than a
   60 // linked list (which would cause every other struct in the array to have an 8-byte member than stretches
   61 // across two 8-byte regions in memory).
   62 struct VarBkp // This should be kept in sync with any changes to the Var class.  See Var for comments.
   63 {
   64     union
   65     {
   66         __int64 mContentsInt64; // 64-bit members kept at the top of the struct to reduce the chance that they'll span 2 vs. 1 64-bit regions.
   67         double mContentsDouble;
   68         IObject *mObject;
   69     };
   70     Var *mVar; // Used to save the target var to which these backed up contents will later be restored.
   71     union
   72     {
   73         char *mByteContents;
   74         TCHAR *mCharContents;
   75     };
   76     union
   77     {
   78         VarSizeType mByteLength;
   79         Var *mAliasFor;
   80     };
   81     VarSizeType mByteCapacity;
   82     AllocMethodType mHowAllocated;
   83     VarAttribType mAttrib;
   84     VarTypeType mType;
   85     // Not needed in the backup:
   86     //bool mIsLocal;
   87     //TCHAR *mName;
   88 
   89     void ToToken(ExprTokenType &aValue);
   90 };
   91 
   92 #pragma warning(push)
   93 #pragma warning(disable: 4995 4996)
   94 
   95 // Concerning "#pragma pack" below:
   96 // Default pack would otherwise be 8, which would cause the 64-bit mContentsInt64 member to increase the size
   97 // of the struct from 20 to 32 (instead of 28).  Benchmarking indicates that there's no significant performance
   98 // loss from doing this, perhaps because variables are currently stored in a linked list rather than an
   99 // array. (In an array, having the struct size be a multiple of 8 would prevent every other struct in the array
  100 // from having its 64-bit members span more than one 64-bit region in memory, which might reduce performance.)
  101 #ifdef _WIN64
  102 #pragma pack(push, 8)
  103 #else
  104 #pragma pack(push, 4) // 32-bit vs. 64-bit. See above.
  105 #endif
  106 typedef VarSizeType (* BuiltInVarType)(LPTSTR aBuf, LPTSTR aVarName);
  107 class Var
  108 {
  109 private:
  110     // Keep VarBkp (above) in sync with any changes made to the members here.
  111     union // 64-bit members kept at the top of the struct to reduce the chance that they'll span 2 64-bit regions.
  112     {
  113         // Although the 8-byte members mContentsInt64 and mContentsDouble could be hung onto the struct
  114         // via a 4-byte-pointer, thus saving 4 bytes for each variable that never uses a binary number,
  115         // it doesn't seem worth it because the percentage of variables in typical scripts that will
  116         // acquire a cached binary number at some point seems likely to be high. A percentage of only
  117         // 50% would be enough to negate the savings because half the variables would consume 12 bytes
  118         // more than the version of AutoHotkey that has no binary-number caching, and the other half
  119         // would consume 4 more (due to the unused/empty pointer).  That would be an average of 8 bytes
  120         // extra; i.e. exactly the same as the 8 bytes used by putting the numbers directly into the struct.
  121         // In addition, there are the following advantages:
  122         // 1) Code less complicated, more maintainable, faster.
  123         // 2) Caching of binary numbers works even in recursive script functions.  By contrast, if the
  124         //    binary number were allocated on demand, recursive functions couldn't use caching because the
  125         //    memory from SimpleHeap could never be freed, thus producing a memory leak.
  126         // The main drawback is that some scripts are known to create a million variables or more, so the
  127         // extra 8 bytes per variable would increase memory load by 8+ MB (possibly with a boost in
  128         // performance if those variables are ever numeric).
  129         __int64 mContentsInt64;
  130         double mContentsDouble;
  131         IObject *mObject; // L31
  132     };
  133     union
  134     {
  135         char *mByteContents;
  136         LPTSTR mCharContents;
  137     };
  138     union
  139     {
  140         VarSizeType mByteLength;  // How much is actually stored in it currently, excluding the zero terminator.
  141         Var *mAliasFor;           // The variable for which this variable is an alias.
  142     };
  143     union
  144     {
  145         VarSizeType mByteCapacity; // In bytes.  Includes the space for the zero terminator.
  146         BuiltInVarType mBIV;
  147     };
  148     AllocMethodType mHowAllocated; // Keep adjacent/contiguous with the below to save memory.
  149     #define VAR_ATTRIB_BINARY_CLIP          0x01
  150     #define VAR_ATTRIB_OBJECT               0x02 // mObject contains an object; mutually exclusive of the cache attribs.
  151     #define VAR_ATTRIB_UNINITIALIZED        0x04 // Var requires initialization before use.
  152     #define VAR_ATTRIB_CONTENTS_OUT_OF_DATE 0x08
  153     #define VAR_ATTRIB_HAS_VALID_INT64      0x10 // Cache type 1. Mutually exclusive of the other two.
  154     #define VAR_ATTRIB_HAS_VALID_DOUBLE     0x20 // Cache type 2. Mutually exclusive of the other two.
  155     #define VAR_ATTRIB_NOT_NUMERIC          0x40 // Cache type 3. Some sections might rely these being mutually exclusive.
  156     #define VAR_ATTRIB_CACHE_DISABLED       0x80 // If present, indicates that caching of the above 3 is disabled.
  157     #define VAR_ATTRIB_CACHE (VAR_ATTRIB_HAS_VALID_INT64 | VAR_ATTRIB_HAS_VALID_DOUBLE | VAR_ATTRIB_NOT_NUMERIC)
  158     #define VAR_ATTRIB_OFTEN_REMOVED (VAR_ATTRIB_CACHE | VAR_ATTRIB_BINARY_CLIP | VAR_ATTRIB_CONTENTS_OUT_OF_DATE)
  159     VarAttribType mAttrib;  // Bitwise combination of the above flags.
  160     #define VAR_GLOBAL          0x01
  161     #define VAR_LOCAL           0x02
  162     #define VAR_FORCE_LOCAL     0x04 // Flag reserved for force-local mode in functions (not used in Var::mScope).
  163     #define VAR_LOCAL_FUNCPARAM 0x10 // Indicates this local var is a function's parameter.  VAR_LOCAL_DECLARED should also be set.
  164     #define VAR_LOCAL_STATIC    0x20 // Indicates this local var retains its value between function calls.
  165     #define VAR_DECLARED        0x40 // Indicates this var was declared somehow, not automatic.
  166     #define VAR_SUPER_GLOBAL    0x80 // Indicates this global var should be visible in all functions.
  167     UCHAR mScope;  // Bitwise combination of the above flags.
  168     VarTypeType mType; // Keep adjacent/contiguous with the above due to struct alignment, to save memory.
  169     // Performance: Rearranging mType and the other byte-sized members with respect to each other didn't seem
  170     // to help performance.  However, changing VarTypeType from UCHAR to int did boost performance a few percent,
  171     // but even if it's not a fluke, it doesn't seem worth the increase in memory for scripts with many
  172     // thousands of variables.
  173 
  174     friend class Line; // For access to mBIV.
  175 #ifdef CONFIG_DEBUGGER
  176     friend class Debugger;
  177 #endif
  178 
  179     void UpdateBinaryInt64(__int64 aInt64, VarAttribType aAttrib = VAR_ATTRIB_HAS_VALID_INT64)
  180     // When caller doesn't include VAR_ATTRIB_CONTENTS_OUT_OF_DATE in aAttrib, CALLER MUST ENSURE THAT
  181     // mContents CONTAINS A PURE NUMBER; i.e. it mustn't contain something non-numeric at the end such as
  182     // 123abc (but trailing/leading whitespace is okay).  This is because users of the cached binary number
  183     // generally expect mContents to be an accurate reflection of that number.
  184     {
  185         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  186         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  187 
  188         if (var.IsObject()) // L31: mObject will be overwritten below via the union, so release it now.
  189             var.ReleaseObject();
  190 
  191         var.mContentsInt64 = aInt64;
  192         var.mAttrib &= ~(VAR_ATTRIB_CACHE | VAR_ATTRIB_UNINITIALIZED); // But not VAR_ATTRIB_CONTENTS_OUT_OF_DATE because the caller specifies whether or not that gets added.
  193         var.mAttrib |= aAttrib; // Must be done prior to below. Indicate the type of binary number and whether VAR_ATTRIB_CONTENTS_OUT_OF_DATE is present.
  194         if (var.mAttrib & VAR_ATTRIB_CACHE_DISABLED) // Variables marked this way can't use either read or write caching.
  195         {
  196             var.UpdateContents(); // Update contents based on the new binary number just stored above. This call also removes the VAR_ATTRIB_CONTENTS_OUT_OF_DATE flag.
  197             var.mAttrib &= ~VAR_ATTRIB_CACHE; // Must be done after the above: Prevent the cached binary number from ever being used because this variable has been marked volatile (e.g. external changes to clipboard) and the cache can't be trusted.
  198         }
  199         else if (g_WriteCacheDisabledInt64 && (var.mAttrib & VAR_ATTRIB_HAS_VALID_INT64)
  200             || g_WriteCacheDisabledDouble && (var.mAttrib & VAR_ATTRIB_HAS_VALID_DOUBLE))
  201         {
  202             if (var.mAttrib & VAR_ATTRIB_CONTENTS_OUT_OF_DATE) // For performance. See comments below.
  203                 var.UpdateContents();
  204             // But don't remove VAR_ATTRIB_HAS_VALID_INT64/VAR_ATTRIB_HAS_VALID_DOUBLE because some of
  205             // our callers omit VAR_ATTRIB_CONTENTS_OUT_OF_DATE from aAttrib because they already KNOW
  206             // that var.mContents accurately represents the double or int64 in aInt64 (in such cases,
  207             // they also know that the precision of any floating point number in mContents matches the
  208             // precision/rounding that's in the double stored in aInt64).  In other words, unlike
  209             // VAR_ATTRIB_CACHE_DISABLED, only write-caching is disabled in the above cases (not read-caching).
  210             // This causes newly written numbers to be immediately written out to mContents so that the
  211             // SetFormat command works in realtime, for backward compatibility.  Also, even if the
  212             // new/incoming binary number matches the one already in the cache, MUST STILL write out
  213             // to mContents in case SetFormat is now different than it was before.
  214         }
  215     }
  216 
  217     void UpdateBinaryDouble(double aDouble, VarAttribType aAttrib = 0)
  218     // FOR WHAT GOES IN THIS SPOT, SEE IMPORTANT COMMENTS IN UpdateBinaryInt64().
  219     {
  220         // The type-casting below interprets the contents of aDouble as an __int64 without actually converting
  221         // from double to __int64.  Although the generated code isn't measurably smaller, hopefully the compiler
  222         // resolves it into something that performs better than a memcpy into a temporary variable.
  223         // Benchmarks show that the performance is at most a few percent worse than having code similar to
  224         // UpdateBinaryInt64() in here.
  225         UpdateBinaryInt64(*(__int64 *)&aDouble, aAttrib | VAR_ATTRIB_HAS_VALID_DOUBLE);
  226     }
  227 
  228     void UpdateContents() // Supports both VAR_NORMAL and VAR_CLIPBOARD.
  229     // Any caller who (prior to the call) stores a new cached binary number in the variable and also
  230     // sets VAR_ATTRIB_CONTENTS_OUT_OF_DATE must (after the call) remove VAR_ATTRIB_CACHE if the
  231     // variable has the VAR_ATTRIB_CACHE_DISABLED flag.
  232     {
  233         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  234         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  235         if (var.mAttrib & VAR_ATTRIB_CONTENTS_OUT_OF_DATE)
  236         {
  237             // THE FOLLOWING ISN'T NECESSARY BECAUSE THE ASSIGN() CALLS BELOW DO IT:
  238             //var.mAttrib &= ~VAR_ATTRIB_CONTENTS_OUT_OF_DATE;
  239             TCHAR value_string[MAX_NUMBER_SIZE];
  240             if (var.mAttrib & VAR_ATTRIB_HAS_VALID_INT64)
  241             {
  242                 var.Assign(ITOA64(var.mContentsInt64, value_string)); // Return value currently not checked for this or the below.
  243                 var.mAttrib |= VAR_ATTRIB_HAS_VALID_INT64; // Re-enable the cache because Assign() disables it (since all other callers want that).
  244             }
  245             else if (var.mAttrib & VAR_ATTRIB_HAS_VALID_DOUBLE)
  246             {
  247                 // "%0.6f"; %f can handle doubles in MSVC++:
  248                 var.Assign(value_string, sntprintf(value_string, _countof(value_string), g->FormatFloat, var.mContentsDouble));
  249                 // In this case, read-caching should be disabled for scripts that use "SetFormat Float" because
  250                 // they might rely on SetFormat having rounded floats off to FAR fewer decimal places (or
  251                 // even to integers via "SetFormat, Float, 0").  Such scripts can use read-caching only when
  252                 // mContents has been used to update the cache, not vice versa.  This restriction doesn't seem
  253                 // to be necessary for "SetFormat Integer" because there should be no loss of precision when
  254                 // integers are stored as hex vs. decimal:
  255                 if (!g_WriteCacheDisabledDouble) // See comment above for why this is checked for float but not integer.
  256                     var.mAttrib |= VAR_ATTRIB_HAS_VALID_DOUBLE; // Re-enable the cache because Assign() disables it (since all other callers want that).
  257             }
  258             //else nothing to update, which shouldn't happen in this block unless there's a flaw or bug somewhere.
  259         }
  260     }
  261 
  262     VarSizeType _CharLength() { return mByteLength / sizeof(TCHAR); }
  263     VarSizeType _CharCapacity() { return mByteCapacity / sizeof(TCHAR); }
  264 public:
  265     // Testing shows that due to data alignment, keeping mType adjacent to the other less-than-4-size member
  266     // above it reduces size of each object by 4 bytes.
  267     TCHAR *mName;    // The name of the var.
  268 
  269     // sEmptyString is a special *writable* memory area for empty variables (those with zero capacity).
  270     // Although making it writable does make buffer overflows difficult to detect and analyze (since they
  271     // tend to corrupt the program's static memory pool), the advantages in maintainability and robustness
  272     // seem to far outweigh that.  For example, it avoids having to constantly think about whether
  273     // *Contents()='\0' is safe. The sheer number of places that's avoided is a great relief, and it also
  274     // cuts down on code size due to not having to always check Capacity() and/or create more functions to
  275     // protect from writing to read-only strings, which would hurt performance.
  276     // The biggest offender of buffer overflow in sEmptyString is DllCall, which happens most frequently
  277     // when a script forgets to call VarSetCapacity before passing a buffer to some function that writes a
  278     // string to it.  There is now some code there that tries to detect when that happens.
  279     static TCHAR sEmptyString[1]; // See above.
  280 
  281     VarSizeType Get(LPTSTR aBuf = NULL);
  282     ResultType AssignHWND(HWND aWnd);
  283     ResultType Assign(Var &aVar);
  284     ResultType Assign(ExprTokenType &aToken);
  285     static ResultType GetClipboardAll(Var *aOutputVar, void **aData, size_t *aDataSize);
  286     static ResultType SetClipboardAll(void *aData, size_t aDataSize);
  287     ResultType AssignClipboardAll();
  288     ResultType AssignBinaryClip(Var &aSourceVar);
  289     // Assign(char *, ...) has been break into four methods below.
  290     // This should prevent some mistakes, as characters and bytes are not interchangeable in the Unicode build.
  291     // Callers must make sure which one is the right method to call.
  292     ResultType AssignString(LPCTSTR aBuf = NULL, VarSizeType aLength = VARSIZE_MAX, bool aExactSize = false, bool aObeyMaxMem = true);
  293     inline ResultType Assign(LPCTSTR aBuf, VarSizeType aLength = VARSIZE_MAX, bool aExactSize = false, bool aObeyMaxMem = true)
  294     {
  295         ASSERT(aBuf); // aBuf shouldn't be NULL, use SetCapacity([length in bytes]) or AssignString(NULL, [length in characters]) instead.
  296         return AssignString(aBuf, aLength, aExactSize, aObeyMaxMem);
  297     }
  298     inline ResultType Assign()
  299     {
  300         return AssignString();
  301     }
  302     ResultType SetCapacity(VarSizeType aByteLength, bool aExactSize = false, bool aObeyMaxMem = true)
  303     {
  304 #ifdef UNICODE
  305         return AssignString(NULL, (aByteLength >> 1) + (aByteLength & 1), aExactSize, aObeyMaxMem);
  306 #else
  307         return AssignString(NULL, aByteLength, aExactSize, aObeyMaxMem);
  308 #endif
  309     }
  310 
  311     ResultType AssignStringFromCodePage(LPCSTR aBuf, int aLength = -1, UINT aCodePage = CP_ACP);
  312     ResultType AssignStringFromUTF8(LPCSTR aBuf, int aLength = -1)
  313     {
  314         return AssignStringFromCodePage(aBuf, aLength, CP_UTF8);
  315     }
  316     ResultType AssignStringToCodePage(LPCWSTR aBuf, int aLength = -1, UINT aCodePage = CP_ACP, DWORD aFlags = WC_NO_BEST_FIT_CHARS, char aDefChar = '?');
  317     inline ResultType AssignStringW(LPCWSTR aBuf, int aLength = -1)
  318     {
  319 #ifdef UNICODE
  320         // Pass aExactSize=true, aObeyMaxMem=false for consistency with AssignStringTo/FromCodePage/UTF8.
  321         // FileRead() relies on this to disobey #MaxMem:
  322         return AssignString(aBuf, aLength, true, false);
  323 #else
  324         return AssignStringToCodePage(aBuf, aLength);
  325 #endif
  326     }
  327 
  328     inline ResultType Assign(DWORD aValueToAssign) // For some reason, this function is actually faster when not __forceinline.
  329     {
  330         UpdateBinaryInt64(aValueToAssign, VAR_ATTRIB_CONTENTS_OUT_OF_DATE|VAR_ATTRIB_HAS_VALID_INT64);
  331         return OK;
  332     }
  333 
  334     inline ResultType Assign(int aValueToAssign) // For some reason, this function is actually faster when not __forceinline.
  335     {
  336         UpdateBinaryInt64(aValueToAssign, VAR_ATTRIB_CONTENTS_OUT_OF_DATE|VAR_ATTRIB_HAS_VALID_INT64);
  337         return OK;
  338     }
  339 
  340     inline ResultType Assign(__int64 aValueToAssign) // For some reason, this function is actually faster when not __forceinline.
  341     {
  342         UpdateBinaryInt64(aValueToAssign, VAR_ATTRIB_CONTENTS_OUT_OF_DATE|VAR_ATTRIB_HAS_VALID_INT64);
  343         return OK;
  344     }
  345 
  346     inline ResultType Assign(VarSizeType aValueToAssign) // For some reason, this function is actually faster when not __forceinline.
  347     {
  348         UpdateBinaryInt64(aValueToAssign, VAR_ATTRIB_CONTENTS_OUT_OF_DATE|VAR_ATTRIB_HAS_VALID_INT64);
  349         return OK;
  350     }
  351 
  352     inline ResultType Assign(double aValueToAssign)
  353     // It's best to call this method -- rather than manually converting to double -- so that the
  354     // digits/formatting/precision is consistent throughout the program.
  355     // Returns OK or FAIL.
  356     {
  357         UpdateBinaryDouble(aValueToAssign, VAR_ATTRIB_CONTENTS_OUT_OF_DATE); // When not passing VAR_ATTRIB_CONTENTS_OUT_OF_DATE, all callers of UpdateBinaryDouble() must ensure that mContents is a pure number (e.g. NOT 123abc).
  358         return OK;
  359     }
  360 
  361     ResultType AssignSkipAddRef(IObject *aValueToAssign);
  362 
  363     inline ResultType Assign(IObject *aValueToAssign)
  364     {
  365         aValueToAssign->AddRef(); // Must be done before Release() in case the only other reference to this object is already in var.  Such a case seems too rare to be worth optimizing by returning early.
  366         return AssignSkipAddRef(aValueToAssign);
  367     }
  368 
  369     inline IObject *&Object()
  370     {
  371         return (mType == VAR_ALIAS) ? mAliasFor->mObject : mObject;
  372     }
  373 
  374     inline void ReleaseObject() // L31
  375     // Caller has ensured that IsObject() == true, not just HasObject().
  376     {
  377         // Remove the "this is an object" attribute and re-enable binary number caching.
  378         mAttrib &= ~(VAR_ATTRIB_OBJECT | VAR_ATTRIB_CACHE_DISABLED | VAR_ATTRIB_NOT_NUMERIC);
  379         // Release this variable's object.  MUST BE DONE AFTER THE ABOVE IN CASE IT TRIGGERS var.base.__Delete().
  380         mObject->Release();
  381     }
  382 
  383     void DisableCache()
  384     // Callers should be aware that the cache will be re-enabled (except for clipboard) whenever a the address
  385     // of a variable's contents changes, such as when it needs to be expanded to hold more text.
  386     {
  387         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  388         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  389         if (var.mAttrib & VAR_ATTRIB_CACHE_DISABLED) // Already marked correctly (and whoever marked it would have already done the steps further below).
  390             return;
  391         var.UpdateContents(); // Update mContents & mLength. Must be done prior to below (it also removes the VAR_ATTRIB_CONTENTS_OUT_OF_DATE flag, if present).
  392         var.mAttrib &= ~VAR_ATTRIB_CACHE; // Remove all cached attributes.
  393         var.mAttrib |= VAR_ATTRIB_CACHE_DISABLED; // Indicate that in the future, mContents should be kept up-to-date.
  394     }
  395 
  396     SymbolType IsNonBlankIntegerOrFloat(BOOL aAllowImpure = false)
  397     // Supports VAR_NORMAL and VAR_CLIPBOARD.  It would need review if any other types need to be supported.
  398     // Caller must be aware that aAllowFloat==true, aAllowNegative==true, and aAllowAllWhitespace==false
  399     // are in effect for this function.
  400     // If caller passes true for aAllowImpure, no explicit handling seems necessary here because:
  401     // 1) If the text number in mContents is IMPURE, it wouldn't be in the cache in the first place (other
  402     //    logic ensures this) and thus aAllowImpure need only be delegated to and handled by IsPureNumeric().
  403     // 2) If the text number in mContents is PURE, the handling below is correct regardless of whether it's
  404     //    already in the cache.
  405     {
  406         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  407         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  408         switch(var.mAttrib & VAR_ATTRIB_CACHE) // This switch() method should squeeze a little more performance out of it compared to doing "&" for every attribute.  Only works for attributes that are mutually-exclusive, which these are.
  409         {
  410         case VAR_ATTRIB_HAS_VALID_INT64: return PURE_INTEGER;
  411         case VAR_ATTRIB_HAS_VALID_DOUBLE: return PURE_FLOAT;
  412         case VAR_ATTRIB_NOT_NUMERIC: return PURE_NOT_NUMERIC;
  413         }
  414         // Since above didn't return, its numeric status isn't yet known, so determine it.  To conform to
  415         // historical behavior (backward compatibility), the following doesn't check MAX_INEGER_LENGTH.
  416         // So any string of digits that is too long to be a legitimate number is still treated as a number
  417         // anyway (overflow).  Most of our callers are expressions anyway, in which case any unquoted
  418         // series of digits is always a number, never a string.
  419         // Below passes FALSE for aUpdateContents because we've already confirmed this var doesn't contain
  420         // a cached number (so can't need updating) and to suppress an "uninitialized variable" warning.
  421         // The majority of our callers will call ToInt64/Double() or Contents() after we return, which would
  422         // trigger a second warning if we didn't suppress ours and StdOut/OutputDebug warn mode is in effect.
  423         // IF-IS is the only caller that wouldn't cause a warning, but in that case ExpandArgs() would have
  424         // already caused one.
  425         SymbolType is_pure_numeric = IsPureNumeric(var.Contents(FALSE), true, false, true, aAllowImpure); // Contents() vs. mContents to support VAR_CLIPBOARD lvalue in a pure expression such as "clipboard:=1,clipboard+=5"
  426         if (is_pure_numeric == PURE_NOT_NUMERIC && !(var.mAttrib & VAR_ATTRIB_CACHE_DISABLED))
  427             var.mAttrib |= VAR_ATTRIB_NOT_NUMERIC;
  428         //else it may be a pure number, which isn't currently tracked via mAttrib (until a cached number is
  429         // actually stored) because the callers of this function often track it and pass the info on
  430         // to ToInt64() or ToDouble().
  431         return is_pure_numeric;
  432     }
  433 
  434     __int64 ToInt64(BOOL aIsPureInteger)
  435     // Caller should pass FALSE for aIsPureInteger if this variable's mContents is either:
  436     // 1) Not a pure number as defined by IsPureNumeric(), namely that the number has a non-numeric part
  437     //    at the end like 123abc (though pure numbers may have leading and trailing whitespace).
  438     // 2) It isn't known whether it's a pure number.
  439     // 3) It's pure but it's the wrong type of number (e.g. it contains decimal point yet ToInt64() vs.
  440     //    ToDouble() was called).
  441     // The reason for the above is that IsNonBlankIntegerOrFloat() relies on the state of the cache to
  442     // accurately report what's in mContents.
  443     // This function supports VAR_NORMAL and VAR_CLIPBOARD. It would need review to support any other types.
  444     {
  445         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  446         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  447         if (var.mAttrib & VAR_ATTRIB_HAS_VALID_INT64) // aIsPureInteger isn't checked here because although this caller might not know that it's pure, other logic ensures that the one who actually set it in the cache did know it was pure.
  448             return var.mContentsInt64;
  449         //else although the attribute VAR_ATTRIB_HAS_VALID_DOUBLE might be present, casting a double to an __int64
  450         // might produce a different result than ATOI64() in some cases.  So for backward compatibility and
  451         // due to rarity of such a circumstance, VAR_ATTRIB_HAS_VALID_DOUBLE isn't checked.
  452         __int64 int64 = ATOI64(var.Contents()); // Call Contents() vs. using mContents in case of VAR_CLIPBOARD or VAR_ATTRIB_HAS_VALID_DOUBLE, and also for maintainability.
  453         if (aIsPureInteger && !(var.mAttrib & VAR_ATTRIB_CACHE_DISABLED)) // This is checked to avoid the overhead of calling UpdateBinaryInt64() unconditionally because it may do a lot of things internally.
  454             var.UpdateBinaryInt64(int64); // Cache the binary number for future uses.
  455         return int64;
  456     }
  457 
  458     double ToDouble(BOOL aIsPureFloat)
  459     // FOR WHAT GOES IN THIS SPOT, SEE IMPORTANT COMMENTS IN ToInt64().
  460     {
  461         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  462         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  463         if (var.mAttrib & VAR_ATTRIB_HAS_VALID_DOUBLE)  // aIsPureFloat isn't checked here because although this caller might not know that it's pure, other logic ensures that the one who actually set it in the cache did know it was pure.
  464             return var.mContentsDouble;
  465         if (var.mAttrib & VAR_ATTRIB_HAS_VALID_INT64) // If there's already a binary integer stored, don't convert the cache type to "double" because that would cause IsNonBlankIntegerOrFloat() to wrongly return PURE_FLOAT. In addition, float is rarely used and often needed only temporarily, such as x:=VarInt+VarFloat
  466             return (double)var.mContentsInt64; // As expected, testing shows that casting an int64 to a double is at least 100 times faster than calling ATOF() on the text version of that integer.
  467         // Otherwise, neither type of binary number is cached yet.
  468         double d = ATOF(var.Contents()); // Call Contents() vs. using mContents in case of VAR_CLIPBOARD, and also for maintainability and consistency with ToInt64().
  469         if (aIsPureFloat && !(var.mAttrib & VAR_ATTRIB_CACHE_DISABLED)) // This is checked to avoid the overhead of calling UpdateBinaryInt64() unconditionally because it may do a lot of things internally.
  470             var.UpdateBinaryDouble(d); // Cache the binary number for future uses.
  471         return d;
  472     }
  473 
  474     ResultType ToDoubleOrInt64(ExprTokenType &aToken)
  475     // aToken.var is the same as the "this" var. Converts var into a number and stores it numerically in aToken.
  476     // Supports VAR_NORMAL and VAR_CLIPBOARD.  It would need review if any other types need to be supported.
  477     {
  478         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  479         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  480         switch (aToken.symbol = var.IsNonBlankIntegerOrFloat())
  481         {
  482         case PURE_INTEGER:
  483             aToken.value_int64 = var.ToInt64(TRUE);
  484             break;
  485         case PURE_FLOAT:
  486             aToken.value_double = var.ToDouble(TRUE);
  487             break;
  488         default: // Not a pure number.
  489             aToken.marker = _T(""); // For completeness.  Some callers such as BIF_Abs() rely on this being done.
  490             return FAIL;
  491         }
  492         return OK; // Since above didn't return, indicate success.
  493     }
  494 
  495     void ToTokenSkipAddRef(ExprTokenType &aToken)
  496     // See ToDoubleOrInt64 for comments.
  497     {
  498         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  499         // L33: For greater compatibility with the official release and L revisions prior to L31,
  500         // this section was changed to avoid converting numeric strings to SYM_INTEGER/SYM_FLOAT.
  501         switch(var.mAttrib & VAR_ATTRIB_CACHE)
  502         {
  503         case VAR_ATTRIB_HAS_VALID_INT64:
  504             aToken.symbol = SYM_INTEGER;
  505             aToken.value_int64 = var.mContentsInt64;
  506             return;
  507         case VAR_ATTRIB_HAS_VALID_DOUBLE:
  508             aToken.symbol = SYM_FLOAT;
  509             aToken.value_double = var.mContentsDouble;
  510             return;
  511         default:
  512             if (var.IsObject())
  513             {
  514                 aToken.symbol = SYM_OBJECT;
  515                 aToken.object = var.mObject;
  516                 return;
  517             }
  518             //else contains a regular string.
  519             aToken.symbol = SYM_STRING;
  520             aToken.marker = var.Contents();
  521         }
  522     }
  523 
  524     void ToToken(ExprTokenType &aToken)
  525     {
  526         ToTokenSkipAddRef(aToken);
  527         if (aToken.symbol == SYM_OBJECT)
  528             aToken.object->AddRef();
  529     }
  530 
  531     // Not an enum so that it can be global more easily:
  532     #define VAR_ALWAYS_FREE                    0 // This item and the next must be first and numerically adjacent to
  533     #define VAR_ALWAYS_FREE_BUT_EXCLUDE_STATIC 1 // each other so that VAR_ALWAYS_FREE_LAST covers only them.
  534     #define VAR_ALWAYS_FREE_LAST               2 // Never actually passed as a parameter, just a placeholder (see above comment).
  535     #define VAR_NEVER_FREE                     3
  536     #define VAR_FREE_IF_LARGE                  4
  537     void Free(int aWhenToFree = VAR_ALWAYS_FREE, bool aExcludeAliasesAndRequireInit = false);
  538     ResultType AppendIfRoom(LPTSTR aStr, VarSizeType aLength);
  539     void AcceptNewMem(LPTSTR aNewMem, VarSizeType aLength);
  540     void SetLengthFromContents();
  541 
  542     static ResultType BackupFunctionVars(Func &aFunc, VarBkp *&aVarBackup, int &aVarBackupCount);
  543     void Backup(VarBkp &aVarBkp);
  544     void Restore(VarBkp &aVarBkp);
  545     static void FreeAndRestoreFunctionVars(Func &aFunc, VarBkp *&aVarBackup, int &aVarBackupCount);
  546 
  547     #define DISPLAY_NO_ERROR   0  // Must be zero.
  548     #define DISPLAY_VAR_ERROR  1
  549     #define DISPLAY_FUNC_ERROR 2
  550     static ResultType ValidateName(LPCTSTR aName, int aDisplayError = DISPLAY_VAR_ERROR);
  551 
  552     LPTSTR ObjectToText(LPTSTR aName, LPTSTR aBuf, int aBufSize);
  553     LPTSTR ToText(LPTSTR aBuf, int aBufSize, bool aAppendNewline)
  554     // Caller must ensure that Type() == VAR_NORMAL.
  555     // aBufSize is an int so that any negative values passed in from caller are not lost.
  556     // Caller has ensured that aBuf isn't NULL.
  557     // Translates this var into its text equivalent, putting the result into aBuf and
  558     // returning the position in aBuf of its new string terminator.
  559     {
  560         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  561         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  562         // v1.0.44.14: Changed it so that ByRef/Aliases report their own name rather than the target's/caller's
  563         // (it seems more useful and intuitive).
  564         var.UpdateContents(); // Update mContents and mLength for use below.
  565         LPTSTR aBuf_orig = aBuf;
  566         if (var.IsObject())
  567             aBuf = var.ObjectToText(this->mName, aBuf, aBufSize);
  568         else
  569             aBuf += sntprintf(aBuf, BUF_SPACE_REMAINING, _T("%s[%Iu of %Iu]: %-1.60s%s"), mName // mName not var.mName (see comment above).
  570                 , var._CharLength(), var._CharCapacity() ? (var._CharCapacity() - 1) : 0  // Use -1 since it makes more sense to exclude the terminator.
  571                 , var.mCharContents, var._CharLength() > 60 ? _T("...") : _T(""));
  572         if (aAppendNewline && BUF_SPACE_REMAINING >= 2)
  573         {
  574             *aBuf++ = '\r';
  575             *aBuf++ = '\n';
  576             *aBuf = '\0';
  577         }
  578         return aBuf;
  579     }
  580 
  581     __forceinline VarTypeType Type()
  582     {
  583         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  584         return (mType == VAR_ALIAS) ? mAliasFor->mType : mType;
  585     }
  586 
  587     __forceinline bool IsStatic()
  588     {
  589         return (mScope & VAR_LOCAL_STATIC);
  590     }
  591 
  592     __forceinline bool IsLocal()
  593     {
  594         // Since callers want to know whether this variable is local, even if it's a local alias for a
  595         // global, don't use the method below:
  596         //    return (mType == VAR_ALIAS) ? mAliasFor->mIsLocal : mIsLocal;
  597         return (mScope & VAR_LOCAL);
  598     }
  599 
  600     __forceinline bool IsNonStaticLocal()
  601     {
  602         // Since callers want to know whether this variable is local, even if it's a local alias for a
  603         // global, don't resolve VAR_ALIAS.
  604         // Even a ByRef local is considered local here because callers are interested in whether this
  605         // variable can vary from call to call to the same function (and a ByRef can vary in what it
  606         // points to).  Variables that vary can thus be altered by the backup/restore process.
  607         return (mScope & (VAR_LOCAL|VAR_LOCAL_STATIC)) == VAR_LOCAL;
  608     }
  609 
  610     //__forceinline bool IsFuncParam()
  611     //{
  612     //  return (mScope & VAR_LOCAL_FUNCPARAM);
  613     //}
  614 
  615     __forceinline bool IsDeclared()
  616     // Returns true if this is a declared var, such as "local var", "static var" or a func param.
  617     {
  618         return (mScope & VAR_DECLARED);
  619     }
  620 
  621     __forceinline bool IsSuperGlobal()
  622     {
  623         return (mScope & VAR_SUPER_GLOBAL);
  624     }
  625 
  626     __forceinline UCHAR &Scope()
  627     {
  628         return mScope;
  629     }
  630 
  631     __forceinline bool IsBinaryClip()
  632     {
  633         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  634         return (mType == VAR_ALIAS ? mAliasFor->mAttrib : mAttrib) & VAR_ATTRIB_BINARY_CLIP;
  635     }
  636 
  637     __forceinline bool IsObject() // L31: Indicates this var contains an object reference which must be released if the var is emptied.
  638     {
  639         return (mAttrib & VAR_ATTRIB_OBJECT);
  640     }
  641 
  642     __forceinline bool HasObject() // L31: Indicates this var's effective value is an object reference.
  643     {
  644         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  645         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  646         return (var.mAttrib & VAR_ATTRIB_OBJECT);
  647     }
  648 
  649     VarSizeType ByteCapacity() // __forceinline() on Capacity, Length, and/or Contents bloats the code and reduces performance.
  650     // Capacity includes the zero terminator (though if capacity is zero, there will also be a zero terminator in mContents due to it being "").
  651     {
  652         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  653         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  654         // Fix for v1.0.37: Callers want the clipboard's capacity returned, if it has a capacity.  This is
  655         // because Capacity() is defined as being the size available in Contents(), which for the clipboard
  656         // would be a pointer to the clipboard-buffer-to-be-written (or zero if none).
  657         return var.mType == VAR_CLIPBOARD ? g_clip.mCapacity : var.mByteCapacity;
  658     }
  659 
  660     VarSizeType CharCapacity()
  661     {
  662         return ByteCapacity() / sizeof(TCHAR); 
  663     }
  664 
  665     UNICODE_CHECK VarSizeType Capacity()
  666     {
  667         return CharCapacity();
  668     }
  669 
  670     BOOL HasContents()
  671     // A fast alternative to Length() that avoids updating mContents.
  672     // Caller must ensure that Type() is VAR_NORMAL.
  673     {
  674         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  675         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  676         return (var.mAttrib & (VAR_ATTRIB_CONTENTS_OUT_OF_DATE | VAR_ATTRIB_OBJECT)) ? TRUE : !!var.mByteLength; // i.e. the only time var.mLength isn't a valid indicator of an empty variable is when VAR_ATTRIB_CONTENTS_OUT_OF_DATE, in which case the variable is non-empty because there is a binary number in it.
  677     }
  678 
  679     BOOL HasUnflushedBinaryNumber()
  680     {
  681         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  682         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  683         return var.mAttrib & VAR_ATTRIB_CONTENTS_OUT_OF_DATE; // VAR_ATTRIB_CONTENTS_OUT_OF_DATE implies that either VAR_ATTRIB_HAS_VALID_INT64 or VAR_ATTRIB_HAS_VALID_DOUBLE is also present.
  684     }
  685 
  686     VarSizeType &ByteLength() // __forceinline() on Capacity, Length, and/or Contents bloats the code and reduces performance.
  687     // This should not be called to discover a non-NORMAL var's length (nor that of an environment variable)
  688     // because their lengths aren't knowable without calling Get().
  689     // Returns a reference so that caller can use this function as an lvalue.
  690     {
  691         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  692         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  693         if (var.mType == VAR_NORMAL)
  694         {
  695             if (var.mAttrib & VAR_ATTRIB_CONTENTS_OUT_OF_DATE)
  696                 var.UpdateContents();  // Update mContents (and indirectly, mLength).
  697             return var.mByteLength;
  698         }
  699         // Since the length of the clipboard isn't normally tracked, we just return a
  700         // temporary storage area for the caller to use.  Note: This approach is probably
  701         // not thread-safe, but currently there's only one thread so it's not an issue.
  702         // For reserved vars do the same thing as above, but this function should never
  703         // be called for them:
  704         static VarSizeType length; // Must be static so that caller can use its contents. See above.
  705         return length;
  706     }
  707 
  708     VarSizeType SetCharLength(VarSizeType len)
  709     {
  710          ByteLength() = len * sizeof(TCHAR);
  711          return len;
  712     }
  713 
  714     VarSizeType CharLength()
  715     {
  716         return ByteLength() / sizeof(TCHAR);
  717     }
  718 
  719     UNICODE_CHECK VarSizeType Length()
  720     {
  721         return CharLength();
  722     }
  723 
  724     VarSizeType LengthIgnoreBinaryClip()
  725     // Returns 0 for types other than VAR_NORMAL and VAR_CLIPBOARD.
  726     // IMPORTANT: Environment variables aren't supported here, so caller must either want such
  727     // variables treated as blank, or have already checked that they're not environment variables.
  728     {
  729         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  730         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  731         // Return the apparent length of the string (i.e. the position of its first binary zero).
  732         return (var.mType == VAR_NORMAL && !(var.mAttrib & VAR_ATTRIB_BINARY_CLIP))
  733             ? var.Length() // Use Length() vs. mLength so that the length is updated if necessary.
  734             : _tcslen(var.Contents()); // Use Contents() vs. mContents to support VAR_CLIPBOARD.
  735     }
  736 
  737     //BYTE *ByteContents(BOOL aAllowUpdate = TRUE)
  738     //{
  739     //  return (BYTE *) CharContents(aAllowUpdate);
  740     //}
  741 
  742     TCHAR *Contents(BOOL aAllowUpdate = TRUE, BOOL aNoWarnUninitializedVar = FALSE)
  743     // Callers should almost always pass TRUE for aAllowUpdate because any caller who wants to READ from
  744     // mContents would almost always want it up-to-date.  Any caller who wants to WRITE to mContents would
  745     // would almost always have called Assign(NULL, ...) prior to calling Contents(), which would have
  746     // cleared the VAR_ATTRIB_CONTENTS_OUT_OF_DATE flag.
  747     {
  748         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  749         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  750         if ((var.mAttrib & VAR_ATTRIB_CONTENTS_OUT_OF_DATE) && aAllowUpdate) // VAR_ATTRIB_CONTENTS_OUT_OF_DATE is checked here and in the function below, for performance.
  751             var.UpdateContents(); // This also clears the VAR_ATTRIB_CONTENTS_OUT_OF_DATE flag.
  752         if (var.mType == VAR_NORMAL)
  753         {
  754             // If aAllowUpdate is FALSE, the caller just wants to compare mCharContents to another address.
  755             // Otherwise, the caller is probably going to use mCharContents and might want a warning:
  756             if (aAllowUpdate && !aNoWarnUninitializedVar)
  757                 var.MaybeWarnUninitialized();
  758             return var.mCharContents;
  759         }
  760         if (var.mType == VAR_CLIPBOARD)
  761             // The returned value will be a writable mem area if clipboard is open for write.
  762             // Otherwise, the clipboard will be opened physically, if it isn't already, and
  763             // a pointer to its contents returned to the caller:
  764             return g_clip.Contents();
  765         return sEmptyString; // For reserved vars (but this method should probably never be called for them).
  766     }
  767 
  768     __forceinline void ConvertToNonAliasIfNecessary() // __forceinline because it's currently only called from one place.
  769     // When this function actually converts an alias into a normal variable, the variable's old
  770     // attributes (especially mContents and mCapacity) become dominant again.  This prevents a memory
  771     // leak in a case where a UDF is defined to provide a default value for a ByRef parameter, and is
  772     // called both with and without that parameter.
  773     {
  774         mAliasFor = NULL; // This also sets its counterpart in the union (mLength) to zero, which is appropriate because mContents should have been set to blank by a previous call to Free().
  775         mType = VAR_NORMAL; // It might already be this type, so this is just in case it's VAR_ALIAS.
  776     }
  777 
  778     __forceinline Var *ResolveAlias()
  779     {
  780         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  781         return (mType == VAR_ALIAS) ? mAliasFor : this; // Return target if it's an alias, or itself if not.
  782     }
  783 
  784     __forceinline void UpdateAlias(Var *aTargetVar) // __forceinline because it's currently only called from one place.
  785     // Caller must ensure that aTargetVar isn't NULL.
  786     // When this function actually converts a normal variable into an alias , the variable's old
  787     // attributes (especially mContents and mCapacity) are hidden/suppressed by virtue of all Var:: methods
  788     // obeying VAR_ALIAS and resolving it to be the target variable.  This prevents a memory
  789     // leak in a case where a UDF is defined to provide a default value for a ByRef parameter, and is
  790     // called both with and without that parameter.
  791     {
  792         // BELOW IS THE MEANS BY WHICH ALIASES AREN'T ALLOWED TO POINT TO OTHER ALIASES, ONLY DIRECTLY TO
  793         // THE TARGET VAR.
  794         // Resolve aliases-to-aliases for performance and to increase the expectation of
  795         // reliability since a chain of aliases-to-aliases might break if an alias in
  796         // the middle is ever allowed to revert to a non-alias (or gets deleted).
  797         // A caller may ask to create an alias to an alias when a function calls another
  798         // function and passes to it one of its own byref-params.
  799         while (aTargetVar->mType == VAR_ALIAS)
  800             aTargetVar = aTargetVar->mAliasFor;
  801 
  802         // The following is done only after the above in case there's ever a way for the above
  803         // to circle back to become this variable.
  804         // Prevent potential infinite loops in other methods by refusing to change an alias
  805         // to point to itself.
  806         if (aTargetVar == this)
  807             return;
  808 
  809         mAliasFor = aTargetVar; // Should always be non-NULL due to various checks elsewhere.
  810         mType = VAR_ALIAS; // It might already be this type, so this is just in case it's VAR_NORMAL.
  811     }
  812 
  813     ResultType Close(bool aIsBinaryClip = false)
  814     {
  815         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  816         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  817         if (var.mType == VAR_CLIPBOARD && g_clip.IsReadyForWrite())
  818             return g_clip.Commit(); // Writes the new clipboard contents to the clipboard and closes it.
  819         // The binary-clip attribute is also reset here for cases where a caller uses a variable without
  820         // having called Assign() to resize it first, which can happen if the variable's capacity is already
  821         // sufficient to hold the desired contents.  VAR_ATTRIB_CONTENTS_OUT_OF_DATE is also removed below
  822         // for maintainability; it shouldn't be necessary because any caller of Close() should have previously
  823         // called something that updates the flags, such as Contents().
  824         var.mAttrib &= ~VAR_ATTRIB_OFTEN_REMOVED;
  825         if (aIsBinaryClip) // If true, caller should ensure that var.mType isn't VAR_CLIPBOARD because it doesn't seem possible/valid for the clipboard to contain a binary image of the clipboard.
  826             var.mAttrib |= VAR_ATTRIB_BINARY_CLIP;
  827         //else (already done above)
  828         //  var.mAttrib &= ~VAR_ATTRIB_BINARY_CLIP;
  829         return OK; // In all other cases.
  830     }
  831 
  832     // Constructor:
  833     Var(LPTSTR aVarName, void *aType, UCHAR aScope)
  834         // The caller must ensure that aVarName is non-null.
  835         : mCharContents(sEmptyString) // Invariant: Anyone setting mCapacity to 0 must also set mContents to the empty string.
  836         // Doesn't need initialization: , mContentsInt64(NULL)
  837         , mByteLength(0) // This also initializes mAliasFor within the same union.
  838         , mHowAllocated(ALLOC_NONE)
  839         , mAttrib(VAR_ATTRIB_UNINITIALIZED) // Seems best not to init empty vars to VAR_ATTRIB_NOT_NUMERIC because it would reduce maintainability, plus finding out whether an empty var is numeric via IsPureNumeric() is a very fast operation.
  840         , mScope(aScope)
  841         , mName(aVarName) // Caller gave us a pointer to dynamic memory for this (or static in the case of ResolveVarOfArg()).
  842     {
  843         if (aType > (void *)VAR_LAST_TYPE) // Relies on the fact that numbers less than VAR_LAST_TYPE can never realistically match the address of any function.
  844         {
  845             mType = VAR_BUILTIN;
  846             mBIV = (BuiltInVarType)aType; // This also initializes mCapacity within the same union.
  847             mAttrib = 0; // Built-in vars are considered initialized, by definition.
  848         }
  849         else
  850         {
  851             mType = (VarTypeType)(UINT_PTR)aType;
  852             mByteCapacity = 0; // This also initializes mBIV within the same union.
  853             if (mType != VAR_NORMAL)
  854                 mAttrib = 0; // Any vars that aren't VAR_NORMAL are considered initialized, by definition.
  855         }
  856     }
  857 
  858     void *operator new(size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  859     void *operator new[](size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  860     void operator delete(void *aPtr) {}
  861     void operator delete[](void *aPtr) {}
  862 
  863 
  864     __forceinline bool IsUninitializedNormalVar()
  865     {
  866         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  867         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  868         return (var.mAttrib & VAR_ATTRIB_UNINITIALIZED);
  869     }
  870 
  871     __forceinline void MarkInitialized()
  872     {
  873         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  874         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  875         mAttrib &= ~VAR_ATTRIB_UNINITIALIZED;
  876     }
  877 
  878     __forceinline void MaybeWarnUninitialized();
  879 
  880 }; // class Var
  881 #pragma pack(pop) // Calling pack with no arguments restores the default value (which is 8, but "the alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.")
  882 
  883 struct VarEntry
  884 {
  885     LPTSTR name;
  886     BuiltInVarType type; // Function pointer or VarTypes constant.
  887 };
  888 
  889 #pragma warning(pop)
  890 
  891 #endif