// macros.h

#if !defined(MACROS_H)
#define MACROS_H

// For strings wrapped in TEXT("") from shared headers
#if !defined(TEXT)
#define TEXT(s)                     s
#endif // TEXT

// For message boxes
#define MB_OK                 1
#define MB_OKCANCEL           2
#define MB_YESNO              3
#define MB_YESNOCANCEL        4
#define MB_RETRYCANCEL        5
#define MB_ABORTRETRYCANCEL   6
   
#define MB_ICONNONE           1
#define MB_ICONINFORMATION    2
#define MB_ICONSTOP           3
#define MB_ICONQUESTION       4
#define MB_ICONEXCLAMATION    5

#define MB_DEFBUTTON1 1
#define MB_DEFBUTTON2 2
#define MB_DEFBUTTON3 3

#if defined(_DEBUG)
#define _DebugStart                 shell "" DebugStart
#define _DebugOutput(Message)       set D_Line = __LINE__ ^^\
                                    set D_Path = __FILE__ ^^\
                                    Split-String $(D_Path) "\\" D_Components ^^\
                                    QueryListSize D_Count $(D_Components) ^^\
                                    set D_File = *($(D_Components), $(D_Count)) ^^\
                                    set-subst D_Output = $(D_File)"("$(D_Line)")\\t: " ^^\
                                    set-subst D_Output = $(D_Output)Message ^^\
                                    Debug-Output $(D_Output)

#define _DebugBreakpoint(Name)      set _Debug_Name = Name ^^\
                                    _DebugOutput("Debug breakpoint hit - "$(_Debug_Name)) ^^\
                                    set DlgType = "MessageBox" ^^\
                                    set STF_MB_TITLE = "Debug Breakpoint" ^^\
                                    set-subst STF_MB_TEXT = $(_Debug_Name)"\\n\\nBreak?" ^^\
                                    set STF_MB_TYPE = MB_YESNO ^^\
                                    set STF_MB_ICON = MB_ICONQUESTION   ^^\
                                    set STF_MB_DEF = MB_DEFBUTTON2 ^^\
                                    ui start "Debug" ^^\
                                    ifstr(i) $(DLGEVENT) == "YES" ^^\
                                       goto _Debug_Exit ^^\
                                    endif

#define _DebugExitPoint             goto _Debug_Over ^^\
                                    _Debug_Exit = + ^^\
                                    _DebugOutput("Debug exit requested") ^^\
                                    _Debug_Over = +

#else
#define _DebugStart
#define _DebugOutput(Message)
#define _DebugBreakpoint(Name)            
#define _DebugExitPoint
#endif

#define DEBUG_LEVEL_ALWAYS    0
#define DEBUG_LEVEL_ERROR     1
#define DEBUG_LEVEL_WARNING   2
#define DEBUG_LEVEL_TRACE     3
#define DEBUG_LEVEL_WHISPER   4

#if defined(_TRACE)
#define _Show1(Var)                 #Var"="$(Var)
#define _Show(Var)                  ", "_Show1(Var)
#define _FormattedOutput(Pre, Msg, Vars)     set-subst F_Msg = Pre ^^\
                                             set-subst F_Msg = $(F_Msg)Msg ^^\
                                             set-subst F_Msg = $(F_Msg)Vars ^^\
                                             _DebugOutput($(F_Msg))
#define _Whisper(Msg, Vars)         ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_WHISPER ^^ _FormattedOutput("Q\\t: ",  Msg,   Vars) ^^ endif
#define _Trace(Msg, Vars)           ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_TRACE   ^^ _FormattedOutput("T\\t: ",  Msg,   Vars) ^^ endif
#define _Enter(Shell, Vars)         ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_TRACE   ^^ _FormattedOutput("I\\t: ",  Shell, Vars) ^^ endif
#define _Exit(Shell, Vars)          ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_TRACE   ^^ _FormattedOutput("O\\t: ",  Shell, Vars) ^^ endif
#define _Call(Shell, Vars)          ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_TRACE   ^^ _FormattedOutput("C\\t: ",  Shell, Vars) ^^ endif
#define _Return(Shell, Vars)        ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_TRACE   ^^ _FormattedOutput("R\\t: ",  Shell, Vars) ^^ endif
#define _Warning(Msg, Vars)         ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_WARNING ^^ _FormattedOutput("W!\\t: ", Msg,   Vars) ^^ endif
#define _Error(Msg, Vars)           ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_ERROR   ^^ _FormattedOutput("E!\\t: ", Msg,   Vars) ^^ endif
#define _Always(Msg, Vars)          ifint $(!DIGI_DebugLevel) >= DEBUG_LEVEL_ALWAYS  ^^ _FormattedOutput("A!\\t: ", Msg,   Vars) ^^ endif
#else
#define _Show1(Var)
#define _Show(Var)                        
#define _FormattedOutput(Pre, Msg, Vars)
#define _Whisper(Msg, Vars)
#define _Trace(Msg, Vars)
#define _Enter(Shell, Vars)                  
#define _Exit(Shell, Vars)                  
#define _Call(Shell, Vars)
#define _Return(Shell, Vars)
#define _Warning(Msg, Vars)
#define _Error(Msg, Vars)
#define _Always(Msg, Vars)
#endif

// Asserts
#if defined(_ASSERT)
#define _AssertMsg(Bool, Msg)             _IfNot(Bool) ^^\
                                             set D_Line = __LINE__ ^^\
                                             set D_Path = __FILE__ ^^\
                                             Split-String $(D_Path) "\\" D_Components ^^\
                                             QueryListSize D_Count $(D_Components) ^^\
                                             set D_File = *($(D_Components), $(D_Count)) ^^\
                                             set A_Bool = #Bool ^^\
                                             set A_Msg = Msg ^^\
                                             set-subst A_Output = "Assertion failed: "$(A_Bool)", "$(D_File)"("$(D_Line)"): "$(A_Msg) ^^\
                                             Debug-Output $(A_Output) ^^\
                                             set DlgType = "MessageBox" ^^\
                                             set STF_MB_TITLE = "Assert!" ^^\
                                             set-subst STF_MB_TEXT = "Assertion failed: "$(A_Bool)", "$(D_File)"("$(D_Line)"):\\n\\n"$(A_Msg)"\\n\\nBreak?" ^^\
                                             set STF_MB_TYPE = MB_YESNO ^^\
                                             set STF_MB_ICON = MB_ICONSTOP   ^^\
                                             set STF_MB_DEF = MB_DEFBUTTON2 ^^\
                                             ui start "Debug" ^^\
                                             ifstr(i) $(DLGEVENT) == "YES" ^^\
                                                Exit ^^\
                                             endif ^^\
                                          endif
#define _Assert(Bool)                     _AssertMsg(Bool, "")
#define _AssertGoto(Bool, Label)          _IfNot(Bool) ^^\
                                             _AssertMsg(Bool, "goto "##Label) ^^\
                                             goto Label ^^\
                                          endif
#define _AssertMsgGoto(Bool, Msg, Label)  _IfNot(Bool) ^^\
                                             _AssertMsg(Bool, Msg) ^^\
                                             goto Label ^^\
                                          endif
#else
#define _AssertMsg(Bool, Msg)
#define _Assert(Bool)
#define _AssertGoto(Bool, Label)          _IfNot(Bool) ^^\
                                             goto Label ^^\
                                          endif
#define _AssertMsgGoto(Bool, Msg, Label)  _IfNot(Bool) ^^\
                                             goto Label ^^\
                                          endif
#endif

// Coding Helpers:

#define _Repeat(Label)              Top_##Label = +
                                    
#define _Until(Label, Conditional)  Continue_##Label = + ^^\
                                    Conditional ^^\
                                       goto Break_##Label ^^\
                                    else ^^\
                                       goto Top_##Label ^^\
                                    endif ^^\
                                    Break_##Label = +

#define _Do(Label)                  goto Continue_##Label ^^\
                                    Top_##Label = +

#define _While(Label, Conditional)  Continue_##Label = + ^^\
                                    Conditional ^^\
                                       goto Top_##Label ^^\
                                    endif ^^\
                                    Break_##Label = +

// _Forever() is to be used only with _Repeat().
#define _Forever(Label)             Continue_##Label = + ^^\
                                    goto Top_##Label ^^\
                                    Break_##Label = +

// _Continue() and _Break() can be used with any looping construct.
#define _Continue(Label)            goto Continue_##Label
#define _Break(Label)               goto Break_##Label

// String Helpers:

#define EMPTY_STR                   ""

#define _IfEmptyStr(Str)            ifstr Str == EMPTY_STR
#define _IfNotEmptyStr(Str)         ifstr Str != EMPTY_STR

// List Helpers:

#define EMPTY_LIST                  {}

#define _IfEmptyList(List)          ifstr List == EMPTY_LIST
#define _IfNotEmptyList(List)       ifstr List != EMPTY_LIST

// INF Helpers:

#define _LocalShell                 shell EMPTY_STR
#define _ExternalShell(File)        shell File
                     
#define _SubroutineShell            _ExternalShell("subroutn.inf")
#define _UtilityShell               _ExternalShell("utility.inf") 
#define _RASShell                   _ExternalShell("oemnsvra.inf")

#define _ShellError(Bool)           _ToBoolean(ifint $($ShellCode) != $(!SHELL_CODE_OK), Bool) ^^\
                                    _If($(Bool)) ^^\
                                       _AssertMsg(FALSE, "Shell code error!") ^^\
	                                    _LocalShell ShellCodeError ^^\
                                    endif

#define _OnShellErrorGoto(Label)    _ShellError(_SE) ^^\
                                    _If($(_SE)) ^^\
                                       goto Label ^^\
                                    endif

#define _UtilityShellError(RegistryErrorIndex, Bool)           _ToBoolean(ifstr(i) RegistryErrorIndex != "NO_ERROR", Bool) ^^\
                                                               _If($(Bool)) ^^\
                                                                  _AssertMsg(FALSE, "Utility shell error!") ^^\
	                                                               _LocalShell GetRegistryErrorString RegistryErrorIndex ^^\
	                                                               _LocalShell SetupMessage "FATAL" $($R0) ^^\
                                                               endif

#define _OnUtilityShellErrorGoto(RegistryErrorIndex, Label)    _UtilityShellError(RegistryErrorIndex, _UE) ^^\
                                                               _If($(_UE)) ^^\
                                                                  goto Label ^^\
                                                               endif

#define _AddValueList               _UtilityShell AddValueList

// Registry Helpers:

#define KEY_NULL                    EMPTY_STR
#define MAXIMUM_ALLOWED             33554432
#define RESERVED_ZERO               0
#define RESERVED_EMPTY              EMPTY_STR

#define _IfValidKey(Key)            ifstr Key != KEY_NULL
#define _IfNotValidKey(Key)         ifstr Key == KEY_NULL

#define _RegValueName(ListData)     *(ListData, 1)
#define _RegValueReserved(ListData) *(ListData, 2)
#define _RegValueType(ListData)     *(ListData, 3)
#define _RegValueValue(ListData)    *(ListData, 4)

#define _RegKeyName(ListData)       *(ListData, 1)
#define _RegKeyReserved(ListData)   *(ListData, 2)
#define _RegKeyClass(ListData)      *(ListData, 3)

#define _MakeValueData(Name, Type, Value)          { Name, RESERVED_ZERO, Type, Value }   

#define _MakeDwordData(Name, Value)                _MakeValueData(Name, $(!REG_VT_DWORD), Value)
#define _MakeSzData(Name, Value)                   _MakeValueData(Name, $(!REG_VT_SZ), Value)
#define _MakeMultiSzData(Name, Value)              _MakeValueData(Name, $(!REG_VT_MULTI_SZ), Value)
#define _MakeExpandSzData(Name, Value)             _MakeValueData(Name, $(!REG_VT_EXPAND_SZ), Value)

#define _MakeKeyData(Name, Class)                  { Name, RESERVED_ZERO, Class }
#define _MakeStdKeyData(Name)                      _MakeKeyData(Name, "GenericClass")

#define _OpenRegKey(Root, Path, Result)            OpenRegKey Root RESERVED_EMPTY Path MAXIMUM_ALLOWED Result
#define _OpenRegKey_HKLM(Path, Result)             _OpenRegKey($(!REG_H_LOCAL), Path, Result)

#define _CreateRegKey(Parent, DataList, Result)    CreateRegKey Parent DataList RESERVED_EMPTY MAXIMUM_ALLOWED RESERVED_EMPTY Result
#define _CreateStdRegKey(Parent, Name, Result)     _CreateRegKey(Parent, _MakeStdKeyData(Name), Result)

#define _MakeStdRegKey(Parent, Name, Result)       _LocalShell MakeRegKey Parent _MakeStdKeyData(Name) ^^\
                                                   set Result = $($R0)

#define _CloseRegKey(Key)                          _LocalShell CloseOpenRegKey Key
#define _CloseRegKeyList(KeyList)                  _LocalShell CloseOpenRegKeyList KeyList


#define _GetRegValueByKey                          _LocalShell GetRegValueByKey
#define _SetRegValueByKey                          _LocalShell SetRegValueByKey

#define _GetRegDwordByKey                          _GetRegValueByKey $(!REG_VT_DWORD)
#define _SetRegDwordByKey                          _SetRegValueByKey $(!REG_VT_DWORD)

#define _GetRegSzByKey                             _GetRegValueByKey $(!REG_VT_SZ)
#define _SetRegSzByKey                             _SetRegValueByKey $(!REG_VT_SZ)

#define _GetRegMultiSzByKey                        _GetRegValueByKey $(!REG_VT_MULTI_SZ)
#define _SetRegMultiSzByKey                        _SetRegValueByKey $(!REG_VT_MULTI_SZ)

#define _GetRegExpandSzByKey                       _GetRegValueByKey $(!REG_VT_EXPAND_SZ)
#define _SetRegExpandSzByKey                       _SetRegValueByKey $(!REG_VT_EXPAND_SZ)


#define _DefaultGetRegValueByKey                   _LocalShell DefaultGetRegValueByKey
#define _DefaultSetRegValueByKey                   _LocalShell DefaultSetRegValueByKey

#define _DefaultGetRegDwordByKey                   _DefaultGetRegValueByKey $(!REG_VT_DWORD)
#define _DefaultSetRegDwordByKey                   _DefaultSetRegValueByKey $(!REG_VT_DWORD)

#define _DefaultGetRegSzByKey                      _DefaultGetRegValueByKey $(!REG_VT_SZ)
#define _DefaultSetRegSzByKey                      _DefaultSetRegValueByKey $(!REG_VT_SZ)

#define _DefaultGetRegMultiSzByKey                 _DefaultGetRegValueByKey $(!REG_VT_MULTI_SZ)
#define _DefaultSetRegMultiSzByKey                 _DefaultSetRegValueByKey $(!REG_VT_MULTI_SZ)

#define _DefaultGetRegExpandSzByKey                _DefaultGetRegValueByKey $(!REG_VT_EXPAND_SZ)
#define _DefaultSetRegExpandSzByKey                _DefaultSetRegValueByKey $(!REG_VT_EXPAND_SZ)


#define _GetRegValueByName                         _LocalShell GetRegValueByName
#define _SetRegValueByName                         _LocalShell SetRegValueByName

#define _GetRegDwordByName                         _GetRegValueByName $(!REG_VT_DWORD)
#define _SetRegDwordByName                         _SetRegValueByName $(!REG_VT_DWORD)

#define _GetRegSzByName                            _GetRegValueByName $(!REG_VT_SZ)
#define _SetRegSzByName                            _SetRegValueByName $(!REG_VT_SZ)

#define _GetRegMultiSzByName                       _GetRegValueByName $(!REG_VT_MULTI_SZ)
#define _SetRegMultiSzByName                       _SetRegValueByName $(!REG_VT_MULTI_SZ)

#define _GetRegExpandSzByName                      _GetRegValueByName $(!REG_VT_EXPAND_SZ)
#define _SetRegExpandSzByName                      _SetRegValueByName $(!REG_VT_EXPAND_SZ)


#define _OpenServiceParamKey(Service, Key)         _LocalShell OpenServiceParamKey Service ^^\
                                                   set Key = $($R0)
// Boolean Helpers:

#define TRUE                        1
#define FALSE                       0

#define _If(Bool)                   ifint Bool == TRUE
#define _IfNot(Bool)                ifint Bool == FALSE

#define _IfAnd(Cond1, Cond2)        _ToBoolean(Cond1, _B1) ^^\
                                    _ToBoolean(Cond2, _B2) ^^\
                                    _AND($(_B1), $(_B2)) ^^\
                                    _If($($R0)) ^^\

#define _EndIfAnd                   endif

#define _IfOr(Cond1, Cond2)         _ToBoolean(Cond1, _B1) ^^\
                                    _ToBoolean(Cond2, _B2) ^^\
                                    _OR($(_B1), $(_B2)) ^^\
                                    _If($($R0)) ^^\

#define _EndIfOr                    endif

#define _IfXor(Cond1, Cond2)        _ToBoolean(Cond1, _B1) ^^\
                                    _ToBoolean(Cond2, _B2) ^^\
                                    _XOR($(_B1), $(_B2)) ^^\
                                    _If($($R0)) ^^\

#define _EndIfXor                   endif

#define _ToBoolean(Cond, Result)    Cond ^^\
                                       set Result = TRUE ^^\
                                    else ^^\
                                       set Result = FALSE ^^\
                                    endif

#define _BooleanShell(Which)        _LocalShell Boolean-##Which

#define _BooleanShell1(Which, A)    _BooleanShell(Which) A
#define _BooleanShell2(Which, A, B) _BooleanShell(Which) A B

#define _SetBoolean(What, Result)   What ^^\
                                    set Result = $($R0)

#define _NOT(A)                     _BooleanShell1(Not, A)
#define _OR(A, B)                   _BooleanShell2(Or, A, B)
#define _AND(A, B)                  _BooleanShell2(And, A, B)
#define _XOR(A, B)                  _BooleanShell2(Xor, A, B)

#define _SetNOT(A, Result)          _SetBoolean(_NOT(A), Result)
#define _SetOR(A, B, Result)        _SetBoolean(_OR(A, B), Result)
#define _SetAND(A, B, Result)       _SetBoolean(_AND(A, B), Result)
#define _SetXOR(A, B, Result)       _SetBoolean(_XOR(A, B), Result)

#endif // MACROS_H
