diff --git a/tconfpy.3 b/tconfpy.3 index 9528bb5..c1e2c37 100644 --- a/tconfpy.3 +++ b/tconfpy.3 @@ -11,16 +11,16 @@ sophisticated applications. This gives the end-user the ability to easily change program options by editing that file. -\*(TC is a Python module for parsing such configuration files. \*(TC +\fCtconfpy\fP is a Python module for parsing such configuration files. \fCtconfpy\fP understands and parses a configuration "language" which has a rich set of string-substitution, variable name, conditional, and validation features. -By using \*(TC, you relieve your program of the major responsibility +By using \fCtconfpy\fP, you relieve your program of the major responsibility of configuration file parsing and validation, while providing your users a rich set of configuration features. -If you run \*(TC directly, it will dump version and copyright +If you run \fCtconfpy\fP directly, it will dump version and copyright information, as well as the value of the current predefined System Variables: @@ -35,7 +35,7 @@ This document is divided into 4 major sections: -.B PROGRAMMING USING THE \*(TC API +.B PROGRAMMING USING THE \fCtconfpy\fP API discusses how to call the configuration file parser, the options available when doing this, and what the parser returns. This is the "Programmer's View" of the module and provides in-depth @@ -44,12 +44,12 @@ .B CONFIGURATION LANGUAGE REFERENCE describes the syntax and semantics of the configuration language -recognized by \*(TC. This is the "User's View" of the package, but +recognized by \fCtconfpy\fP. This is the "User's View" of the package, but both programmers and people writing configuration files will find this helpful. .B ADVANCED TOPICS FOR PROGRAMMERS -describes some ways to combine the various \*(TC features to +describes some ways to combine the various \fCtconfpy\fP features to do some fairly nifty things. .B INSTALLATION @@ -58,10 +58,10 @@ with the package. -.SH PROGRAMMING USING THE \*(TC API +.SH PROGRAMMING USING THE \fCtconfpy\fP API -\*(TC is a Python module and thus available for use by any Python -program. This section discusses how to invoke the \*(TC parser, the +\fCtconfpy\fP is a Python module and thus available for use by any Python +program. This section discusses how to invoke the \fCtconfpy\fP parser, the options available when doing so, and what the parser returns to the calling program. @@ -83,18 +83,114 @@ .fi .ft \" revert -you will have to prepend all references to a \*(TC object with +you will have to prepend all references to a \fCtconfpy\fP object with \fCtconfpy.\fP. So \fCretval=ParseConfig(...\fP becomes \fCretval = tconfpy.ParseConfig(...\fP and so on. -You will also find the test driver code provided in the \*(TC package +You will also find the test driver code provided in the \fCtconfpy\fP package helpful as you read through the following sections. \fCtest-tc.py\fP is -a utility to help you learn and exercise the \*(TC API. Perusing the +a utility to help you learn and exercise the \fCtconfpy\fP API. Perusing the code therein is helpful as an example of the topics discussed below. +.SS Core Objects + +In order to use \fCtconfpy\fP effectively, you need to be familiar with the +objects used to communicate between your program and the parser. +This section provides a brief overview of these objects for +reference use later in the document. + +.TP +.B The Symbol Table Object + +A "symbol table" is a \fCtconfpy\fP object defined to hold the symbol table +proper, the results of the parse (upon return), and some other data +structures used internally by the parser. + +The full Symbol Table object definition and initialization looks +like this: + +.ft C \" Courier +.nf + class SymbolTable(object): + def __init__(self): + self.Symbols = {} + self.DebugMsgs = [] + self.ErrMsgs = [] + self.WarnMsgs = [] + self.LiteralLines = [] + self.Templates = Template() + self.ALLOWNEWVAR = True + self.TEMPONLY = False + self.LITERALVARS = False + self.INLITERAL = False + self.DEBUG = False + self.CondStack = [["", True],] + self.TotalLines = 0 +.fi +.ft \" revert + +This object is optionally passed to the API when beginning a parse, +if you wish to provide an initial symbol table. In this case, +only \fCSymbols\fP need be populated. + +When the parse is complete, an object of this same type is returned. +\fCSymbols\fP, \fCDebugMsgs\fP, \fCErrMsgs\fP, \fCWarnMsgs\fP, and +\fCLiteralLines\fP will be populated with the parse results as +appropriate. + + +.TP +.B The Variable Descriptor Object + +The actual symbol table is kept in the \fCSymbolTable.Symbols\fP +dictionary. There is one entry for each symbol (variable) encountered +in the parse. The symbol's name is used as the dictionary key and an +object of type \fCVarDescriptor\fP as its entry. This "variable +descriptor" is an object that describes the variable's current and +default values, whether it can be modified, and any validation +constraints: + +.ft C \" Courier +.nf + class VarDescriptor(object): + # Default variable type is a writeable string with no constraints + def __init__(self): + self.Value = "" + self.Writeable = True + self.Type = TYPE_STRING + self.Default = "" + self.LegalVals = [] + self.Min = None + self.Max = None +.fi +.ft \" revert + + +.TP +.B The Template Object + +As described later in this document, it is possible to pre-define +a variable's type, default value, and validation contraint(s) +to be applied only if the variable is actually brought into existence +in the configuration file. This is a so-called "template". Templates +have their own object definition: + +.ft C \" Courier +.nf + class Template(object): + def __init__(self): + self.Symbols = {} +.fi +.ft \" revert + +In effect, this is a subset of the \fCSymbolTable\fP object. +\fCTemplate.Symbols\f is populated just like \fCSymbolTable.Symbols\fP +using symbol names and variable descriptors. + + .SS API Overview -The \*(TC API consists of a single call. Only the configuration file +The \fCtconfpy\fP API consists of a single call. Only the configuration file to be processed is a required parameter, all the others are optional and default as described below: @@ -104,9 +200,9 @@ retval = ParseConfig(cfgfile, CallingProgram="tconfpy version-num", - InitialSymTable={}, + InitialSymTable=SymbolTable(), AllowNewVars=True, - Templates={}, + Templates=Template(), TemplatesOnly=False, LiteralVars=True, ReturnPredefs=True, @@ -126,28 +222,32 @@ it is treated as the name of a file to parse. If this parameter is a .B list, -\*(TC presumes this to be an in-memory configuration, and parses the +\fCtconfpy\fP presumes this to be an in-memory configuration, and parses the list in sequential order, treating each entry as a configuration line. -This allows you to use \*(TC for parsing either configuration files or +This allows you to use \fCtconfpy\fP for parsing either configuration files or in-memory configurations. If you pass anything other than a string -or list here, \*(TC will produce an error. +or list here, \fCtconfpy\fP will produce an error. + .TP -.B CallingProgram +.B CallingProgram (\'tconfpy\' + Version Number) -By default, each time \*(TC produces an Error, Warning, or Debug -message, it prepends it with the string \'tconfpy\' followed by -the version number. Since \*(TC is designed to be called from -applications programs, you may wish to substitute your own -program name or other information in these messages. You do so -by setting the \fCCallingProgram\fp keyword to the desired text. +Change the prompt introducer string used for Debug, Error, and Warning +messages. + +By default, each time \fCtconfpy\fP produces an Error, Warning, or Debug +message, it prepends it with the string \'tconfpy\' followed by the +version number. Since \fCtconfpy\fP is designed to be called from +applications programs, you may wish to substitute your own program +name or other information in these messages. You do so by setting the +\fCCallingProgram\fP keyword to the desired text. + .TP -.B InitialSymTable (Default: \fC{}\fP) +.B InitialSymTable (Default: \fCSymbolTable()\fP) -A prepopulated symbol table (a Python dictionary). As described -below, this must contain valid \fCVarDescriptor\fP entries for each -symbol in the table. +Used to pass a pre-initialized Symbol Table from the application to +the parser. .TP .B AllowNewVars (Default: \fCTrue\fP) @@ -156,10 +256,10 @@ .TP -.B Templates (Default: \fC{}\fP) +.B Templates (Default: \fCTemplate()\fP) This option is used to pass variable templates to the parser. If present, -\*(TC expects this option to pass a data structure in the same format as +\fCtconfpy\fP expects this option to pass a data structure in the same format as a symbol table. i.e., You must pass a Python dictonary whose keys are the names of the variable templates and each entry must be a \fCVarDescriptor\fP object. See the section below entitled, @@ -171,8 +271,8 @@ .TP .B TemplatesOnly (Default: \fCFalse\fP) -If this option is set to \fCTrue\fP, \*(TC will not permit a new variable to -be created unless a variable template exists for it. By default, \*(TC will +If this option is set to \fCTrue\fP, \fCtconfpy\fP will not permit a new variable to +be created unless a variable template exists for it. By default, \fCtconfpy\fP will use a variable template if one is present for a new variable, but it does not require one. If a new variable is created, and no Template exists for it, the variable is just created as a string type with no restrictions on @@ -203,33 +303,54 @@ .TP .B Debug (Default: \fCFalse\fP) -If set to \fCTrue\fP, \*(TC will provide detailed debugging information +If set to \fCTrue\fP, \fCtconfpy\fP will provide detailed debugging information about each line processed when it returns. .TP .B retval -An object of type \fCtconfpy.RetObj\fP used to return parsing results. +An object of type \fCSymbolTable\fP used to return parsing results. +The results of the parse will be returned in various data structures: + +.ft C \" Courier +.nf +SymbolTable.Symbols => All symbols and their values as a result of the parse +SymbolTable.DebugMsgs => Any Debug Messages if debug was requested +SymbolTable.ErrMsgs => Any Error Messages +SymbolTable.WarnMsgs => Any Warning Messages +Symboltable.LiteralLines => Any Literal Text found in the configuration file +.fi +.ft \" revert + +You can tell whether a parse was successful by examining \fCErrMsgs\fP. +A successful parse will leave this data structure empty (though there may +well be Warning Messages present in \fCWarnMsgs\fP.) .SS The Initial Symbol Table API Option -The simplest way to parse a configuration file is just to call -the parser with the name of that file: +The simplest way to parse a configuration is just to call +the parser with the name of a file or an in-memory list +containing the configuration statements: .ft C \" Courier .nf retval = ParseConfig("MyConfigFile") + + - OR - + + myconfig = [configline1, configline2, ....] + retval = ParseConfig(myconfig) .fi .ft \" revert -Assuming your configuration file is valid, \fCParseConfig()\fP will +Assuming your configuration is valid, \fCParseConfig()\fP will return a symbol table populated with all the variables defined in the -file and their associated values. This symbol table will have +configuration and their associated values. This symbol table will have .B only -the symbols defined in that file (plus a few built-in and predefined -symbols needed internally by \*(TC). +the symbols defined in that configuration (plus a few built-in and predefined +symbols needed internally by \fCtconfpy\fP). However, the API provides a way for you to pass a "primed" symbol table to the parser that contains predefined symbols/values of @@ -252,7 +373,7 @@ .ft \" revert In this example, only the calling application can know its own -version, so it sets the variable APPVERSION in a symbol table +version, so it sets the variable \fCAPPVERSION\fP in a symbol table which is passed to \fCParseConfig()\fP. .IP \(bu 4 @@ -272,7 +393,7 @@ Variable Templates). But variables that are created by a program have access to the variable's "descriptor". By setting various attribues of the variable descriptor you can control variable type, content, and -range of values. In other words, you can have \*(TC "validate" what +range of values. In other words, you can have \fCtconfpy\fP "validate" what values the user assigns to particular variables. This substantially simplifies your application because no invalid variable value will ever be returned from the parser. @@ -280,11 +401,12 @@ .SS How To Create An Initial Symbol Table -A \*(TC "Symbol Table" is really nothing more than a Python -dictionary. The key for each dictionary entry is the variable's name -and the value is a \*(TC-specific object called a "variable -descriptor". Creating new variables in the symbol table involves -nothing more than this: +A \fCtconfpy\fP "Symbol Table" is really nothing more than a Python +dictionary stored inside a container object. The key for each +dictionary entry is the variable's name and the value is a +\fCtconfpy\fP-specific object called a "variable descriptor". +Creating new variables in the symbol table involves nothing more than +this: .ft C \" Courier .nf @@ -292,7 +414,7 @@ from tconfpy import * # Create an empty symbol table - MySymTable = {} + MySymTable = SymbolTable() # Create descriptor for new variable MyVarDes = VarDescriptor() @@ -301,7 +423,7 @@ MyVarDes.Value = "MyVal" # Now load the variable into the symbol table - MySymTable["MyVariableName"] = MyVarDes + MySymTable.Symbols["MyVariableName"] = MyVarDes # Repeat this process for all variables, then call the parser @@ -328,7 +450,7 @@ .fi .ft \" revert -When \*(TC encounters a new variable in a configuration file, it just +When \fCtconfpy\fP encounters a new variable in a configuration file, it just instantiates one of these descriptor objects with these defaults for that variable. That is, variables newly-defined in a configuration file are entered into the symbol table as string types, with an @@ -337,9 +459,9 @@ But, when you create variables under program control to "prime" an initial symbol table, you can modify the content of any of these attributes for each variable. These descriptor attributes are what -\*(TC uses to validate subsequent attempts to change the variable's +\fCtconfpy\fP uses to validate subsequent attempts to change the variable's value in the configuration file. In other words, modifying a -variable's descriptor tells \*(TC just what you'll accept as "legal" +variable's descriptor tells \fCtconfpy\fP just what you'll accept as "legal" values for that variable. Each attribute has a specific role: @@ -359,13 +481,14 @@ .TP .B VarDescriptor.Type (Default: \fCTYPE_STRING\fP) -One of TYPE_BOOL, TYPE_COMPLEX, TYPE_FLOAT, TYPE_INT, or TYPE_STRING. -This defines the type of the variable. Each time \*(TC sees -a value being assigned to a variable in the configuration file, it -checks to see if that variable already exists in the symbol table. -If it does, the parser checks the value being assigned and makes sure -it matches the type declared for that variable. For example, -suppose you did this when defining the variable, \fCfoo\fP: +One of \fCTYPE_BOOL,\fP \fCTYPE_COMPLEX,\fP \fCTYPE_FLOAT,\fP +\fCTYPE_INT,\fP or \fCTYPE_STRING. This\fP defines the type of the +variable. Each time \fCtconfpy\fP sees a value being assigned to a +variable in the configuration file, it checks to see if that variable +already exists in the symbol table. If it does, the parser checks the +value being assigned and makes sure it matches the type declared for +that variable. For example, suppose you did this when defining the +variable, \fCfoo\fP: .ft C \" Courier .nf @@ -385,7 +508,7 @@ into an integer type - it is a string. -As a general matter, for existing variables, \*(TC attempts to coerce +As a general matter, for existing variables, \fCtconfpy\fP attempts to coerce the right-hand-side of an assignment to the type declared for that variable. The least fussy operation here is when the variable is defined as TYPE_STRING because pretty much everything can be coerced @@ -417,10 +540,10 @@ .B VarDescriptor.Default (Default: \fCEmpty String\fP) This is a place to store the default value for a given variable. When -a variable is newly-defined in a configuration file, \*(TC places the +a variable is newly-defined in a configuration file, \fCtconfpy\fP places the first value assigned to that variable into this attribute. For -variables already in the symbol table, \*(TC does nothing to this -attribute. This attribute is not actually used by \*(TC for anything. +variables already in the symbol table, \fCtconfpy\fP does nothing to this +attribute. This attribute is not actually used by \fCtconfpy\fP for anything. It is provided as a convenience so that the calling program can easily "reset" every variable to its default value if desired. @@ -461,11 +584,11 @@ The general semantic here is "If Legal Vals is not an empty list, the user must assign a value that matches one of the items in LegalVals." -One special note applies to \fCLegalVals\fP for string variables. \*(TC +One special note applies to \fCLegalVals\fP for string variables. \fCtconfpy\fP always assumes that this list contains Python regular expressions. For validation, it grabs each entry in the list, attempts to compile it as a regex, and checks to see if the value the user wants to set -matches. If you define an illegal regular expression here, \*(TC will +matches. If you define an illegal regular expression here, \fCtconfpy\fP will catch it and produce an appropriate error. You may also want to specify a set of legal strings that are @@ -490,7 +613,7 @@ If you want this test to be skipped, then set \fCLegalVals\fP to an empty list, []. (This is the default when you first create an instance of \fCtconfpy.VarDescriptor\fP.) Do not set it to a Python -None or anything else. \*(TC expects this attribute to be a list in +None or anything else. \fCtconfpy\fP expects this attribute to be a list in every case. @@ -525,7 +648,7 @@ AND of the appropriate type AND one of the legal values AND within the min/max range. -\*(TC makes no attempt to harmonize these validation +\fCtconfpy\fP makes no attempt to harmonize these validation conditions with each other. If you specify a value in \fCLegalVals\fP that is, say, lower than allowed by \fCMin\fP you will always get an error when the user sets @@ -541,10 +664,10 @@ user's point-of-view. However, it is useful for the programmer to understand how they are implemented. -\*(TC is written to use a predefined variable named \fCNAMESPACE\fP as +\fCtconfpy\fP is written to use a predefined variable named \fCNAMESPACE\fP as the place where the current namespace is kept. If you do not define this variable in the initial symbol table passed to the parser, -\*(TC will create it automatically with an initial value of "". +\fCtconfpy\fP will create it automatically with an initial value of "". From a programmer's perspective, there are are few important things to know about namespaces and the \fCNAMESPACE\fP variable: @@ -555,10 +678,10 @@ You do this by creating the \fCNAMESPACE\fP variable in the initial symbol table passed to the parser, and setting the \fCValue\fP attribute of its descriptor to whatever you want as the initial namespace. At -startup \*(TC will check this initial value to make sure it conforms +startup \fCtconfpy\fP will check this initial value to make sure it conforms to the rules for properly formed names - i.e., It it will check for blank space, a leading \fC$\fP, the presence of square brackets, and so -on. If the initial namespace value you provide is illegal, \*(TC will +on. If the initial namespace value you provide is illegal, \fCtconfpy\fP will produce an error and reset the initial namespace to "". .IP \(bu 4 @@ -581,25 +704,25 @@ It will contain the last namespace used. -.SS How The \*(TC Parser Validates The Initial Symbol Table +.SS How The \fCtconfpy\fP Parser Validates The Initial Symbol Table -When you pass an initial symbol table to the parser, \*(TC does some +When you pass an initial symbol table to the parser, \fCtconfpy\fP does some basic validation that the table contents properly conform to the \fCVarDescriptor\fP format and generates error messages if it finds problems. However, the program does .B not check your specifications to see if they make sense. For instance if you define an integer with a minimum value of 100 and a maximum -value of 50, \*(TC cheerfully accepts these limits even though they +value of 50, \fCtconfpy\fP cheerfully accepts these limits even though they are impossible. You'll just be unable to do anything with that variable - any attempt to change its value will cause an error to be recorded. Similarly, if you put a value in \fCLegalVals\fP that -is outside the range of \fCMin\fP to \fCMax\fP, \*(TC will accept +is outside the range of \fCMin\fP to \fCMax\fP, \fCtconfpy\fP will accept it quietly. .SS The \fCAllowNewVars\fP API Option -By default, \*(TC lets the user define any new variables they +By default, \fCtconfpy\fP lets the user define any new variables they wish in a configuration file, merely by placing a line in the file in this form: @@ -620,7 +743,7 @@ This means that the configuration file can "reference" any predefined variables, and even change their values -(if they are not Read-Only), but it cannot create +(if they are Writeable), but it cannot create .B new variables. @@ -647,7 +770,7 @@ the desired variable name will be flagged as an error. Note, however, that there is one big drawback to disabling new -variable creation. \*(TC processes the configuration file on a +variable creation. \fCtconfpy\fP processes the configuration file on a line-by-line basis. No line "continuation" is supported. For really long variable values and ease of maintenance, it is sometimes helpful to create "intermediate" variables that hold temporary values used to @@ -678,7 +801,7 @@ in the initial symbol table you pass to the parser. This allows you to define that variable's type and to optionally place various restrictions on the values it may take. In other words, you can "declare" -the variable ahead of time and \*(TC will do so-called "type +the variable ahead of time and \fCtconfpy\fP will do so-called "type and value enforcement". "Variable Templates" are a related kind of idea, with a bit of @@ -696,7 +819,7 @@ are several answers to this: .IP \(bu 4 -The \*(TC configuration language has very powerful "existential" +The \fCtconfpy\fP configuration language has very powerful "existential" conditional tests. These test to see if a variable "exists". If you predefine every variable you will ever need, then the kinds of existential tests you can do will be @@ -749,9 +872,9 @@ .IP \(bu 4 The other reason for Variable Templates is more subtle, but -gives \*(TC tremendous versatility beyond just processing +gives \fCtconfpy\fP tremendous versatility beyond just processing configuration files. Variable Templates give you a way to use -\*(TC to build data validation tools. +\fCtconfpy\fP to build data validation tools. Suppose you have a list of employee records exported in this general format (easy to do with most databases): @@ -785,7 +908,7 @@ contexts, we can .B validate each of them to make sure their content, type, length, and so forth -are correct. This makes it possible to use \*(TC as the underpinnings +are correct. This makes it possible to use \fCtconfpy\fP as the underpinnings of a "data validation" or "cleansing" program. .IP \(bu 4 @@ -853,7 +976,7 @@ \fCVarDescriptor\fPs. You then pass these to the parser via the \fCTemplates=\fP option. -As \*(TC parses the file and encounters the new variables +As \fCtconfpy\fP parses the file and encounters the new variables \fC1234.LastName\fP ... \fC1235.ZIP\fP, it uses the following "rules" when creating new variables: @@ -897,23 +1020,23 @@ They also give you a way to define such restrictions for an entire class of variables without having to explicitly name each such variable ahead of time. Finally, Variable Templates -are an interesting way to use \*(TC as the basis for data +are an interesting way to use \fCtconfpy\fP as the basis for data validation programs. .SS The \fCLiteralVars\fP API Option -\*(TC supports the inclusion of literal text anywhere in a +\fCtconfpy\fP supports the inclusion of literal text anywhere in a configuration file via the \fC.literal\fP directive. This -directive effectively tells the \*(TC parser to pass +directive effectively tells the \fCtconfpy\fP parser to pass every line it encounters "literally" until it sees a corresponding \fC.endlinteral\fP directive. By default, -\*(TC does +\fCtconfpy\fP does .B exactly -this. However, \*(TC has very powerful variable substitution +this. However, \fCtconfpy\fP has very powerful variable substitution mechanisms. You may want to embed variable references in a -"literal" block and have them replaced by \*(TC. +"literal" block and have them replaced by \fCtconfpy\fP. Here is an example: @@ -939,7 +1062,7 @@ would be in the list of literals returned by \fCParseConfig()\fP. -However, we can ask \*(TC to do variable replacement +However, we can ask \fCtconfpy\fP to do variable replacement .B within literal blocks by setting \fCLiteralVars=True\fP in the \fCParseConfig()\fP call: @@ -951,7 +1074,7 @@ .ft \" revert -In this example, \*(TC would return: +In this example, \fCtconfpy\fP would return: .ft C \" Courier .nf @@ -961,11 +1084,11 @@ At first glance this seems only mildly useful, but it is actually very handy. As described later in this document, -\*(TC has a rich set of conditional operators and string +\fCtconfpy\fP has a rich set of conditional operators and string sustitution facilities. You can use these features along with literal block processing and variable substitution within those blocks. This effectively lets you use -\*(TC as a preprocessor for +\fCtconfpy\fP as a preprocessor for .B any other language or text. @@ -1002,7 +1125,7 @@ .SS The \fCDebug\fP API Option -\*(TC has a fairly rich set of debugging features built into its +\fCtconfpy\fP has a fairly rich set of debugging features built into its parser. It can provide some detail about each line parsed as well as overall information about the parse. Be default, debugging is turned off. To enable debugging, merely set \fCDebug=True\fP in the @@ -1014,9 +1137,9 @@ .fi .ft \" revert -.SS How \*(TC Processes Errors +.SS How \fCtconfpy\fP Processes Errors -As a general matter, when \*(TC encounters an error in the +As a general matter, when \fCtconfpy\fP encounters an error in the configuration file currently being parsed, it does two things. First, it adds a descriptive error message into the list of errors returned to the calling program (see the next section). Secondly, in many @@ -1028,16 +1151,16 @@ caused the error and why. -.SS \*(TC Return Values +.SS \fCtconfpy\fP Return Values -When \*(TC is finished processing the configuration file, it returns an +When \fCtconfpy\fP is finished processing the configuration file, it returns an object that contains the entire results of the parse. This includes a symbol table, any relevant error or warning messages, debug information (if you requested this via the API), and any "literal" lines encountred in the configuration. -The return object is an instance of the class \fCtwander.RetObj\fP which is -nothing more than a container to hold return data. In the simplest +The return object is an instance of the class \fCtwander.SymbolTable\fP which has +been populated with the results of the parse. In the simplest case, we can parse and extract results like this: .ft C \" Courier @@ -1050,59 +1173,62 @@ \fCretval\fP now contains the results of the parse: + + .TP -.B retval.Errors +.B retval.Symbols + +A Python dictionary which lists all the defined symbols and their +associated values. A "value" in this case is always an object of type +\fCtconfpy.VarDescriptor\fP (as described above). + +.TP +.B retval.DebugMsgs + +A Python list containing detailed debug information for each line +parsed as well as some brief summary information about the parse. +\fCretval.Debug\fP defaults to an empty list and is only populated if you +set \fCDebug=True\fP in the API call that initiated the parse (as in the +example above). + + +.TP +.B retval.ErrMsgs A Python list containing error messages. If this list is empty, you can infer that there were no parsing errors - i.e., The configuration file was OK. .TP -.B retval.Warnings +.B retval.WarnMsgs A Python list containing warning messages. These describe minor problems not fatal to the parse process, but that you really ought to clean up in the configuration file. .TP -.B retval.SymTable +.B retval.LiteralLines -A Python dictionary which lists all the defined symbols and their -associated values. A "value" in this case is always an object of type -tconfpy.VarDescriptor (as described above). - -.TP -.B retval.Literals - -As described below, the \*(TC configuration language supports a +As described below, the \fCtconfpy\fP configuration language supports a \fC.literal\fP directive. This directive allows the user to embed literal text anywhere in the configuration file. This effectively -makes \*(TC useful as a preprocessor for any other language or text. -retval.Literals is a Python list containing all literal text +makes \fCtconfpy\fP useful as a preprocessor for any other language or text. +\fCretval.LiteralLines\fP is a Python list containing all literal text discovered during the parse. The lines appear there in the order they were discovered in the configuration file. -.TP -.B retval.Debug - -A Python list containing detailed debug information for each line -parsed as well as some brief summary information about the parse. -retval.Debug defaults to an empty list and is only populated if you -set \fCDebug=True\fP in the API call that initiated the parse (as in the -example above). - .SH CONFIGURATION LANGUAGE REFERENCE -\*(TC recognizes a full-featured configuration language that includes +\fCtconfpy\fP recognizes a full-featured configuration language that includes variable creation and value assignment, a full preprocessor with conditionals, type and value enforcement, and lexical namespaces. This section of the document describes that language and provides examples of how each feature can be used. -.SS \*(TC Configuration Language Syntax +.SS \fCtconfpy\fP Configuration Language Syntax -\*(TC supports a fairly simple and direct configuration +\fCtconfpy\fP supports a fairly simple and direct configuration language syntax: @@ -1188,8 +1314,8 @@ .fi .ft \" revert -If \fCMyVariable\fP is a new variable, \*(TC will create it on the spot. -If it already exists, \*(TC will first check and make sure that \fCSome +If \fCMyVariable\fP is a new variable, \fCtconfpy\fP will create it on the spot. +If it already exists, \fCtconfpy\fP will first check and make sure that \fCSome string of text\fP is a legal value for this variable. If not, it will produce an error and refuse to change the current value of \fCMyVariable\fP. @@ -1206,12 +1332,12 @@ variables with other types and place limitations on what values the variable can take and/or how short or long a string variable may be. (See the previous section, -.B PROGRAMMING USING THE \*(TC API +.B PROGRAMMING USING THE \fCtconfpy\fP API for all the gory details.) The programmer can also arrange for the configuration file to only have access to variables predefined by the program ahead of time. In -that case, if you try to create a new variable, \*(TC will produce an +that case, if you try to create a new variable, \fCtconfpy\fP will produce an appropriate error and the new variable will not be created. @@ -1240,10 +1366,10 @@ .IP \(bu 4 Variable names cannot have the \fC#\fP character anywhere in them -because \*(TC sees that character as the beginning a comment. +because \fCtconfpy\fP sees that character as the beginning a comment. .IP \(bu 4 -Variable names cannot begin with \fC.\fP character. \*(TC understands +Variable names cannot begin with \fC.\fP character. \fCtconfpy\fP understands a leading period in a variable name to be a "namespace escape". This is discussed in a later section on lexical namespaces. @@ -1264,7 +1390,7 @@ .IP \(bu 4 The variable named \fCNAMESPACE\fP is not available for your own -use. \*(TC understands this variable to hold the current lexical +use. \fCtconfpy\fP understands this variable to hold the current lexical namespace as described later in this document. If you set it to a new value, it will change the namespace, so be sure this is what you wanted to do. @@ -1342,7 +1468,7 @@ .B defined before they can be .B referenced. -\*(TC does not support so-called "forward" references. +\fCtconfpy\fP does not support so-called "forward" references. .IP \(bu 4 @@ -1380,7 +1506,7 @@ .ft \" revert To understand what this does you need to realize that before -\*(TC does anything with a statement in a configuration file, it +\fCtconfpy\fP does anything with a statement in a configuration file, it replaces every variable reference with its associated value (or produces an error for references to non-existent variables). So the second statement above is first converted to: @@ -1416,7 +1542,7 @@ .ft \" revert This is illegal because whitespace is not permitted in variable names. -\*(TC will produce an error if it sees such a construct. As a general +\fCtconfpy\fP will produce an error if it sees such a construct. As a general matter, any variable you construct through this indirection method must still conform to all the rules of variable naming: It cannot contain whitespace, begin with \fC$\fP, contain \fC#\fP, \fC[\fP, or \fC]\fP and @@ -1439,7 +1565,7 @@ The second assignment statement in this example does not do what you -might initially think. Remember, \*(TC always does variable +might initially think. Remember, \fCtconfpy\fP always does variable dereferencing before anything else, so the second statement becomes: .ft C \" Courier @@ -1492,7 +1618,7 @@ .SS Introducing Lexical Namespaces So far,the discussion of variables and references has conveniently -ignored the presence of another related \*(TC feature, "Lexical +ignored the presence of another related \fCtconfpy\fP feature, "Lexical Namespaces." Namespaces are a way to automatically group related variables together. Suppose you wanted to describe the options on your car in a configuration file. You might do @@ -1529,7 +1655,7 @@ variable assignment .B and reference is "relative" to the namespace. What this really means is -that \*(TC sticks the namspace plus a \fC.\fP in front of every +that \fCtconfpy\fP sticks the namspace plus a \fC.\fP in front of every variable assigned or referenced. It does this automatically and invisibly, so \fCBrand\fP is turned into \fCMyCar.Brand\fP and so on. You can actually check this by loading the example above into a test @@ -1538,7 +1664,7 @@ into the symbol table, each beginning with \fCMyCar.\fP and ending with the variable name you specified. -Realize that this is entirely a naming "trick". \*(TC has no clue +Realize that this is entirely a naming "trick". \fCtconfpy\fP has no clue what the namespace .B means, it just combines the current namespace with the variable name to @@ -1546,7 +1672,7 @@ table. You're likely scratching your head wondering why on earth this -feature present in \*(TC. There are several good reasons for it: +feature present in \fCtconfpy\fP. There are several good reasons for it: .IP \(bu 4 It reduces typing repetetive information throughout the configuration @@ -1556,7 +1682,7 @@ .IP \(bu 4 It helps visibly organize the configuration file. A namespace makes it clear which variables are related to each other somehow. This is no -big deal in small configurations, but \*(TC was written with the idea +big deal in small configurations, but \fCtconfpy\fP was written with the idea of supporting configuration files that might contain thousands or even tens of thousands of entries. @@ -1575,7 +1701,7 @@ .IP \(bu 4 It helps enforce correct configuration files. By default, you can introduce new namespaces into the configuration file any time you -like. However, as described in the previous section on the \*(TC API, +like. However, as described in the previous section on the \fCtconfpy\fP API, the application programmer can limit you to a predefined set of legal namespaces (via the \fCLegalVals\fP attribute of the \fCNAMESPACE\fP variable descriptor). By doing this, the programmer is helping you @@ -1590,7 +1716,7 @@ .IP \(bu 4 The default initial namespace is the empty string, "". In this one -case, \*(TC does nothing to variables assigned or referenced. That's +case, \fCtconfpy\fP does nothing to variables assigned or referenced. That's why our early examples in the previous section worked. When we assigned a value to a variable and then referenced that variable value, we did so while in the so-called "root" namespace, "". When @@ -1640,8 +1766,8 @@ .ft \" revert In other words, the second form of a namespace change allows you to -employ the \*(TC string substitution and variable referencing -features. Bear in mind that \*(TC is case-sensitive so this +employ the \fCtconfpy\fP string substitution and variable referencing +features. Bear in mind that \fCtconfpy\fP is case-sensitive so this will not work as you expect: .ft C \" Courier @@ -1704,7 +1830,7 @@ .ft \" revert There is another clever way to do this without using the escape -character. \*(TC has no understanding whatsoever of what a +character. \fCtconfpy\fP has no understanding whatsoever of what a lexical namespace actually is. It does nothing more than "glue" the current namespace to any variable names and references in your configuration file. Internally, all variables are @@ -1726,7 +1852,7 @@ .IP \(bu 4 Lexical namspaces are implemented by having \fCNAMESPACE\fP just be -nothing more than (yet) another variable in the symbol table. \*(TC +nothing more than (yet) another variable in the symbol table. \fCtconfpy\fP just understands that variable to be special - it treats it as the repository of the current lexical namespace. This means you can use the value of NAMESPACE in your own string substitutions: @@ -1770,7 +1896,7 @@ .SS Predefined Variables -\*(TC predefines a number of variables. The \fCNAMESPACE\fP variable we +\fCtconfpy\fP predefines a number of variables. The \fCNAMESPACE\fP variable we discussed in the previous section is one of them, but there are a number of others of which you should be aware. Note that all predefined variables .B are relative to the root namespace. @@ -1827,13 +1953,13 @@ .ft \" revert The other kind of predefined variables are called "Reserved Variables". -\*(TC understands a number of symbols as part of its own language. -For example, the string \fC#\fP tells \*(TC to begin a comment until +\fCtconfpy\fP understands a number of symbols as part of its own language. +For example, the string \fC#\fP tells \fCtconfpy\fP to begin a comment until end-of-line. There may be times, however, when .B you need these strings for your own use. In other words, you would like -to use one of the strings which comprise the \*(TC language for your -own purposes and have \*(TC ignore them. The Reserved Variables +to use one of the strings which comprise the \fCtconfpy\fP language for your +own purposes and have \fCtconfpy\fP ignore them. The Reserved Variables give you a way to do this. The Reserved Variables are: .ft C \" Courier @@ -1864,7 +1990,7 @@ For instance, suppose you wanted to include the \fC#\fP symbol in the value of one of your variables. This will not work, -because \*(TC interprets it as the beginning of a comment, +because \fCtconfpy\fP interprets it as the beginning of a comment, which is not what you want: .ft C \" Courier @@ -1901,18 +2027,18 @@ is understood to just hold a string of characters. There are no limits to what that string may contain, how long it is, and so on. -However, \*(TC gives the programmer considerable power to enforce variable +However, \fCtconfpy\fP gives the programmer considerable power to enforce variable types and values, if they so choose. (See the section above entitled, -.B PROGRAMMING USING THE \*(TC API +.B PROGRAMMING USING THE \fCtconfpy\fP API for the details.) The programmer can set all kinds of limitations about a variable's type, permissible values, and (in the case of strings) how long or short it may be. The programmer does this by defining these limitations for each variable of interest -.B prior to calling \*(TC to parse your configuration file. -In that case, when \*(TC actually processes the configuration file, +.B prior to calling \fCtconfpy\fP to parse your configuration file. +In that case, when \fCtconfpy\fP actually processes the configuration file, it "enforces" these restrictions any time you attempt to change the value of one of these variables. If you try to assign a value that -fails one of these "validation" tests, \*(TC will produce an error +fails one of these "validation" tests, \fCtconfpy\fP will produce an error and leave the variable's value unchanged. For instance, suppose the programmer has defined @@ -1994,7 +2120,7 @@ .SS Notes On Variable Type/Value Enforcement -There are a few other things you should know about how \*(TC +There are a few other things you should know about how \fCtconfpy\fP enforces restrictions on variables: .IP \(bu 4 @@ -2044,7 +2170,7 @@ Similarly, you cannot change any of the enforcement options from within a configuration file. These features are only available under program control, presumably by the application program that -is calling \*(TC. +is calling \fCtconfpy\fP. .IP \(bu 4 There is no way to know what the limitations are on a particular @@ -2060,7 +2186,7 @@ One last note here concerns Boolean variables. Booleans are actually stored in the symbol table as the Python boolean values, \fCTrue\fP or \fCFalse\fP. -However, \*(TC accepts user statements that set the value of the +However, \fCtconfpy\fP accepts user statements that set the value of the boolean in a number of formats: .ft C \" Courier @@ -2077,7 +2203,7 @@ .fi .ft \" revert -This is the one case where \*(TC is insensitive to case - +This is the one case where \fCtconfpy\fP is insensitive to case - \fCtRUE\fP, \fCTRUE\fP, and \fCtrue\fP are all accepted, for example. .B NOTE HOWEVER: @@ -2164,14 +2290,14 @@ .P -One last thing needs to be noted here. \*(TC does not detect +One last thing needs to be noted here. \fCtconfpy\fP does not detect so-called "circular" inclusions. If file \fCa\fP \fC.include\fPs file \fCb\fP and file \fCb\fP \fC.include\fPs file \fCa\fP, you will have an infinite loop of inclusion, which, uh ..., is a Bad Thing... .SS Conditional Directives -One of the most powerful features of \*(TC is its "conditional +One of the most powerful features of \fCtconfpy\fP is its "conditional processing" capabilities. The general idea is to test some condition and .B include or exclude configuration information based on the outcome of the test. @@ -2247,7 +2373,7 @@ There are no explicit limits to how deeply you can nest a configuration. However, you must have an \fC.endif\fP that terminates each conditional test. Bear in mind that -\*(TC pays no attention to your indentation. It associates an \fC.endif\fP +\fCtconfpy\fP pays no attention to your indentation. It associates an \fC.endif\fP .B with the last conditional it encountered. That's why it's a really good idea to use some consistent indentation style so .B you @@ -2262,13 +2388,13 @@ arguments (which may- or may not have whitespace in them). .IP \(bu 4 -As with any other kind of \*(TC statement, you may place comments +As with any other kind of \fCtconfpy\fP statement, you may place comments anywhere at the end of a conditional directive line or within the conditional blocks. .IP \(bu 4 Each conditional directive must have a corresponding \fC.endif\fP. If -you have more conditionals than \fC.endif\fPs or vice-versa, \*(TC will +you have more conditionals than \fC.endif\fPs or vice-versa, \fCtconfpy\fP will produce an error message to that effect. It can get complicated to keep track of this, especially with deeply nested conditionals. It is therefore recommended that you always begin and end conditional blocks @@ -2281,7 +2407,7 @@ some preceding conditional directive. .IP \(bu 4 -As in other parts of the \*(TC language, variable names and references +As in other parts of the \fCtconfpy\fP language, variable names and references in conditional directives are always relative to the currently active namespace unless they are escaped with a leading period. Similarly, in this context, Environment Variables, Predefined Variables, @@ -2358,7 +2484,7 @@ .fi .ft \" revert -When \*(TC finishes processing this, x=1, y=2, and z=0. +When \fCtconfpy\fP finishes processing this, x=1, y=2, and z=0. You can also use references to environment variables in an existential conditional test: @@ -2445,7 +2571,7 @@ .ft \" revert .fi -These are particularly useful when used in combination with the \*(TC +These are particularly useful when used in combination with the \fCtconfpy\fP Predefinded Variable or environment variables. You can build configurations that "sense" what system is currently running and "adapt" accordingly: @@ -2470,10 +2596,10 @@ .SS The \fC.literal\fP Directive -By default, \*(TC only permits statements it "recognizes" in the +By default, \fCtconfpy\fP only permits statements it "recognizes" in the configuration file. Anything else is flagged as an unrecognized statement or "syntax error". However, it is possible to "embed" -arbitrary text in a configuration file and have \*(TC pass it back +arbitrary text in a configuration file and have \fCtconfpy\fP pass it back to the calling program without comment by using the \fC.literal\fP directive. It works like this: @@ -2485,15 +2611,15 @@ .fi .ft \" revert -This tells \*(TC to ignore everything between \fC.literal\fP and \fC.endliteral\fP +This tells \fCtconfpy\fP to ignore everything between \fC.literal\fP and \fC.endliteral\fP and just pass it back to the calling program (in \fCretval.Literals\fP - see -previous section on the \*(TC API). Literal text is returned in the order +previous section on the \fCtconfpy\fP API). Literal text is returned in the order it is found in the configuration file. What good is this? It is a nifty way to embed plain text or even programs written in other languages within a configuration file and pass them back to the calling program. This is especially handy -when used in combination with \*(TC conditional features: +when used in combination with \fCtconfpy\fP conditional features: .ft C \" Courier .nf @@ -2512,13 +2638,13 @@ .ft \" revert -In other words, we can use \*(TC as a "preprocessor" for other text or +In other words, we can use \fCtconfpy\fP as a "preprocessor" for other text or computer languages. Obviously, the program has to be written to understand whatever is returned as literal text. -By default, \*(TC leaves text within the literal block completely untouched. +By default, \fCtconfpy\fP leaves text within the literal block completely untouched. It simply returns it as it finds it in the literal block. However, the -programmer can invoke \*(TC with an option (\fCLiteralVars=True\fP) that +programmer can invoke \fCtconfpy\fP with an option (\fCLiteralVars=True\fP) that allows .B variable substitution within literal blocks. This allows you to combine the results of your configuration into the @@ -2582,7 +2708,7 @@ .SS GOTCHAS -\*(TC is a "little language". It is purpose-built to do one +\fCtconfpy\fP is a "little language". It is purpose-built to do one and only one thing well: process configuration options. Even so, it is complex enough that there are a few things that can "bite" you when writing these configuration files: @@ -2601,7 +2727,7 @@ .fi .ft \" revert -But this will not work. \*(TC is very strict about requiring you to +But this will not work. \fCtconfpy\fP is very strict about requiring you to explicitly distinguish between .B variable names and @@ -2629,7 +2755,7 @@ This was done for a very good reason. Because you have to explicitly note whether you want the name or value of a variable (instead of -having \*(TC infer it from context), you can mix both literal text and +having \fCtconfpy\fP infer it from context), you can mix both literal text and variable values on either side of a comparison or assignment: .ft C \" Courier @@ -2687,7 +2813,7 @@ .IP \(bu 4 Remember that all variable references are .B string replacements -no matter what the type of the variable actually is. \*(TC +no matter what the type of the variable actually is. \fCtconfpy\fP type and value enforcement is used to return the proper value and type to the calling program. But within the actual processing of a configuration file, variable references (i.e., the values of @@ -2703,7 +2829,7 @@ the specified type. But, using only the assignment statements available in this language, you cannot define values in a meaningful way for user-defined types. So, assignment of user-defined variable -types will always fail with a type error. Again, \*(TC is designed as +types will always fail with a type error. Again, \fCtconfpy\fP is designed as a small configuration processing language, not as a general purpose programming language. In short, user-defined types are not supported in the variable descriptor processing and will always cause a type @@ -2712,7 +2838,7 @@ .SH ADVANCED TOPICS FOR PROGRAMMERS -Here are some ideas on how you might combine \*(TC features +Here are some ideas on how you might combine \fCtconfpy\fP features to enhance your own applications. .SS Guaranteeing A Correct Base Configuration @@ -2722,7 +2848,7 @@ misconfigure a program. This is especially a problem when you are doing technical support. You'd really like to get them to a "standard" configuration and then work from there to help solve their -problem. If your write your program with this in mind, \*(TC gives +problem. If your write your program with this in mind, \fCtconfpy\fP gives you several ways to easily do this: .IP \(bu 4 @@ -2751,7 +2877,7 @@ instantiated, it defaults to a string type and sets the default attribute to an empty string. However, you can change both type and default value under program control.) If you predefine a variable in the -initial symbol table passed to the parser, \*(TC will leave this +initial symbol table passed to the parser, \fCtconfpy\fP will leave this attribute alone. However, variables that are created for the first time in the configuration file will have this attribute set to the first value assigned to the variable. Now provide a "reset" feature @@ -2761,12 +2887,12 @@ .SS Enforcing Mandatory Configurations -The \*(TC type and value validation features give you a handy way to +The \fCtconfpy\fP type and value validation features give you a handy way to enforce what the legal values for a particular option may be. However, you may want to go further than this. For instance, you may only want to give certain classes of users the ability to change certain options. This is easily done. First, predefine all the -options of interest in the symbol table prior to calling the \*(TC +options of interest in the symbol table prior to calling the \fCtconfpy\fP parser. Next, have your program decide which options the current user is permitted to change. Finally, mark all the options they may not change as "Read Only", by setting the "Writeable" attribute for those @@ -2819,10 +2945,10 @@ The goal might be that a variable is set to a particular value (like, \fCSYSTEMS=3\fP). -It might even be tempting to keep parsing iteratively until \*(TC no +It might even be tempting to keep parsing iteratively until \fCtconfpy\fP no longer returns any errors. This is not recommended, though. A well-formed configuration file should have no errors on any pass. -Iterating until \*(TC no longer detects errors makes it hard to +Iterating until \fCtconfpy\fP no longer detects errors makes it hard to debug complex configuration files. It is tough to distinguish actual configuration errors from errors would be resolved in a future parsing pass. @@ -2830,7 +2956,7 @@ .SH INSTALLATION -There are three ways to install \*(TC depending on your preferences +There are three ways to install \fCtconfpy\fP depending on your preferences and type of system. In each of these installation methods you must be logged in with root authority on Unix-like systems or as the Administrator on Win32 systems. @@ -2878,7 +3004,7 @@ .fi .ft \" revert -This will install the \*(TC module and compile it. +This will install the \fCtconfpy\fP module and compile it. You will manually have to copy the 'test-tc.py' program to a directory somewhere in your executable path. Similarly, copy the documentation @@ -2909,7 +3035,7 @@ Where X.Y is the Python release number. -You can precompile the \*(TC module by starting Python interactively +You can precompile the \fCtconfpy\fP module by starting Python interactively and then issuing the command: .ft C \" Courier @@ -2956,10 +3082,10 @@ .fi .ft \" revert -.SS Bundling \*(TC With Your Own Programs +.SS Bundling \fCtconfpy\fP With Your Own Programs -If you write a program that depends on \*(TC you'll need to ensure +If you write a program that depends on \fCtconfpy\fP you'll need to ensure that the end-users have it installed on their systems. There are two ways to do this: @@ -2974,10 +3100,10 @@ regardless of what the end-user system has installed. -.SH THE \*(TC MAILING LIST +.SH THE \fCtconfpy\fP MAILING LIST TundraWare Inc. maintains a mailing list to help you with your -\*(TC questions and bug reports. To join the list, send email +\fCtconfpy\fP questions and bug reports. To join the list, send email to .B majordomo@tundraware.com with a single line of text in the body (not the Subject line) @@ -2995,15 +3121,15 @@ .SH OTHER -\*(TC requires Python 2.3 or later. +\fCtconfpy\fP requires Python 2.3 or later. .SH BUGS AND MISFEATURES None known as of this release. .SH COPYRIGHT AND LICENSING -\*(TC is Copyright (c) \*(CP TundraWare Inc. For terms of use, see +\fCtconfpy\fP is Copyright (c) \*(CP TundraWare Inc. For terms of use, see the tconfpy-license.txt file in the program distribution. If you -install \*(TC on a FreeBSD system using the 'ports' mechanism, you +install \fCtconfpy\fP on a FreeBSD system using the 'ports' mechanism, you will also find this file in /usr/local/share/doc/py-tconfpy. .SH AUTHOR