diff --git a/twander.py b/twander.py index c1bd473..9bdd035 100755 --- a/twander.py +++ b/twander.py @@ -6,7 +6,7 @@ # Program Information PROGNAME = "twander" -RCSID = "$Id: twander.py,v 3.113 2003/02/28 20:05:18 tundra Exp $" +RCSID = "$Id: twander.py,v 3.114 2003/02/28 23:18:55 tundra Exp $" VERSION = RCSID.split()[2] # Copyright Information @@ -304,6 +304,7 @@ SHOWDRIVES = '\\\\' # Logical directory name for Win32 Drive Lists STRICTMATCH = CMDESCAPE # Tells wildcard system to enforce strict matching + # Sort Field Names fNONE = "None" @@ -509,7 +510,7 @@ ##### -# Configuration File-Related Constants +# Configuration File-Related Constants & Globals ##### ASSIGN = "=" # Assignment for variable definitions @@ -518,6 +519,19 @@ ENVVBL = r'$' # Symbol denoting an environment variable +# Names Of Conditional And Pre-Defined Symbols + +CONDENDIF = '.ENDIF' +CONDEQUAL = '==' +CONDIF = '.IF' +SYMOS = '.OS' +SYMPLATFORM = '.PLATFORM' + +# Globals Supporting Configutration File Conditional Processing + +ConditionalStack = [] # Stack for tracking conditional state + + # Variable Name Pattern Matching Stuff DIRSC = "DIRSC" # Directory Shortcut naming @@ -626,6 +640,7 @@ wBADCFGLINE = "Ignoring Line %s.\nBogus Configuration Entry:\n\n%s" wBADDEBUG = "Ignoring Bogus Debug Level! - %s Is Not In Integer Or Hex Format." +wBADENDIF = "No Conditional Block To End!\nIgnoring Line %s:\n\n%s" wBADENVVBL = "Ignoring Line %s.\nEnvironment Variable %s Not Set:\n\n%s" wBADEXE = "Could Not Execute Command:\n\n%s" wBADRHS = "Ignoring Line %s.\nOption Assignment Has Bad Righthand Side:\n\n%s" @@ -696,7 +711,7 @@ dOPTIONWIDTH = 16 dSCWIDTH = 6 dTWOUPWIDTH = 50 -dUSRVBLWIDTH = 16 +dUSRVBLWIDTH = 20 # List of internal program variables to dump during debug sessions @@ -815,14 +830,25 @@ ##### def ParseConfFile(event, DoOptionsProcessing=TRUE): - global CONF, UI + global CONF, UI, ConditionalStack # Cleanout any old configuration data UI.CmdTable = {} UI.DirSCKeys = ["", "", "", "", "", "", "", "", "", "", "", ""] UI.SymTable = {} - linenum = 0 + + + # Initialize internal parsing data structures + + linenum = 0 + ConditionalStack = [TRUE,] + + # Load Symbol Table with predefined symbols + + UI.SymTable[SYMOS] = os.name + UI.SymTable[SYMPLATFORM] = sys.platform + # Unbind all existing key bindings for x in UI.KeyBindings.keys(): @@ -969,8 +995,14 @@ def ParseLine(line, num): - global UI + global UI, ConditionalStack + + ### + # Cleanup the line + ### + # Get rid of trailing newline, if any + if line[-1] == '\n': line = line[:-1] @@ -990,16 +1022,90 @@ dummy.append("") - ##### + # Before going on, make sure we're even supposed to process the line. + # If we are currently in the midst of a *false* conditional + # block, we must throw this line away. The only thing + # we'll accept in that case is more conditional statements. + + if (not ConditionalStack[-1]) and (dummy[0] not in (CONDIF, CONDENDIF)): + return + + ### # Blank Lines - Ignore - ##### + ### if len(fields) == 0: pass - ##### - # Variable Definitions - ##### + ### + # Conditionals + ### + + # Legal conditional statements are in one of several forms: + # + # .IF [SYMBOL] + # .IF [SYMBOL] == string + # .IF [SYMBOL]== string + # .IF [SYMBOL] ==string + # .IF [SYMBOL]==string + # .ENDIF + + # Process conditional beginning-of-block statement + + elif fields[0] == CONDIF: + + # Process beginning of conditional block + if fields[0] == CONDIF: + + # Process string equality checks + if line.count('=='): + pass + + # Process variable existence checks + else: + # Existence checks must be in the form: .IF [VAR] + + if len(fields) != 2: + WrnMsg(wBADCOND) + return + + # Presume 2nd field is in the form: [VAR] + + if UI.SymTable.has_key(fields[1][1:-1]): + conditional = TRUE + else: + conditional = FALSE + + # OK, now we save state of this conditional block + # If this is the first level of conditional, save it directly. + + if len(ConditionalStack) == 1: + ConditionalStack.append(conditional) + + # But, if we're nesting a conditional and the containing + # block is FALSE, so is the new block. + + else: + ConditionalStack.append(ConditionalStack[-1] and conditional) + + # Process conditional end-of-block statement + + elif fields[0] == CONDENDIF: + + # The conditional stack must always have 1 value left in + # it after all conditional processing. If it does not, + # it means there are more ENDIFs than IFs. + + if len(ConditionalStack) > 1: + ConditionalStack.pop() + + else: + WrnMsg(wBADENDIF % (num,line)) + + + ### + # Variable Definitions And Special Assignments + ### # A valid variable definition can # be 1, 2, or 3 fields: @@ -1135,9 +1241,9 @@ else: UI.SymTable[name] = val - ##### + ### # Command Definitions - ##### + ### elif len(fields[0]) == 1: @@ -1440,9 +1546,9 @@ # End of method 'twanderUI.__init__()' - ##### + ### # Bind the relevant event handlers - ##### + ### def BindAllHandlers(self): @@ -1572,9 +1678,9 @@ self.DirList.bind(self.KeyBindings["MOUSESEL"], MouseDblClick) - ##### + ### # Directory Shortcut Keys - All Bound To A Common Handler - ##### + ### self.DirList.bind(self.KeyBindings["KDIRSC1"], lambda event :DirSCKeyPress(event, 1)) self.DirList.bind(self.KeyBindings["KDIRSC2"], lambda event :DirSCKeyPress(event, 2)) @@ -1621,9 +1727,9 @@ self.DirList.bind(self.KeyBindings["MEMSET12"], lambda event : KeyMemHandler(mem=12)) - ##### + ### # Sort Selection Keys - All Bound To A Common Handler - ##### + ### self.DirList.bind(self.KeyBindings["SORTBY0"], lambda event : KeySetSortParm(parm=fNONE)) self.DirList.bind(self.KeyBindings["SORTBY1"], lambda event : KeySetSortParm(parm=fPERMISSIONS))