# Part of the A-A-P recipe executive: handling of a dictlist # Copyright (C) 2002 Stichting NLnet Labs # Permission to copy and use this file is specified in the file COPYING. # If this file is missing you can find it here: http://www.a-a-p.org/COPYING # A Dictlist is a list of dictonaries, used for a parsed variable. # The dictionary contains the "name" key for the item itself, and other keys # for attributes of that item. Attributes starting with an underscore are for # internal use (e.g., "_node"). import string from Util import * from Process import recipe_error def get_attrval(line, idx): """Get items starting at line[idx] and ending at a '}' character. Items are white separated. Quotes are used to include {} characters in an item. Returns the string for list of items and the index of the next character.""" line_len = len(line) res = '' # result collected so far i = idx inquote = '' # inside quotes nesting = 0 # nested {} while 1: if i >= line_len: # end of line break # End of quoted string? if inquote: if line[i] == inquote: inquote = '' # Start of quoted string? elif line[i] == '"' or line[i] == "'": inquote = line[i] # Stop character found? else: if line[i] == '}': if nesting == 0: break nesting = nesting - 1 elif line[i] == '{': nesting = nesting + 1 res = res + line[i] i = i + 1 return res, i def get_attrdict(rpstack, globals, arg, idx, expand): """Obtain attributes {name = val} from arg[idx:]. Returns a dictionary with the attributes and the index of the character after the last "}" When there is no attribute return {} and idx. When "expand" is non-zero, expand $VAR things. When "expand" is zero "globals" isn't used. """ from Commands import aap_eval arglen = len(arg) res = {} while 1: i = skip_white(arg, idx) if i >= arglen or arg[i] != '{': break i = skip_white(arg, i + 1) e = i while 1: if e >= arglen: recipe_error(rpstack, _("Syntax error after {")) if not varchar(arg[e]): break e = e + 1 if e == i: recipe_error(rpstack, _("Missing name after {")) name = arg[i:e] i = skip_white(arg, e) if i < arglen and arg[i] == '}': # No "= value", use one. val = 1 else: if i >= arglen or arg[i] != '=': recipe_error(rpstack, _("Missing = after {")) i = skip_white(arg, i + 1) val, i = get_attrval(arg, i) if i >= arglen or arg[i] != '}': recipe_error(rpstack, _("Missing } after {")) idx = i + 1 # May need to expand $VAR things. if expand and val != 1: val = aap_eval(rpstack, globals, val, Expand(1, Expand.quote_aap)) res[name] = val return res, idx def string2dictlist(rpstack, var, startquote = ''): """Create a Dictlist from a variable string. The variable has to be evaluated and white-separated items isolated. When "startquote" isn't empty, behave like "var" was preceded by it. """ result = [] # TODO: handle parenthesis: "(foo bar) {attr = val}" varlen = len(var) inquote = startquote i = 0 while i < varlen: # Separate one item, removing quotes. item = '' while 1: # Quoted string: check for its end. if inquote: if i >= varlen: break # Missing quote! error message below. if var[i] == inquote: inquote = '' # End of quoted text. else: item = item + var[i] i = i + 1 continue # An item ends at the end of the line, at white space or at '{'. if i >= varlen or var[i] == '\n' \ or var[i] == ' ' or var[i] == '\t' or var[i] == '{': if item: # Found one item, add it. # Parse {attr = value} zero or more times. adddict, i = get_attrdict(rpstack, None, var, i, 0) adddict["name"] = item result.append(adddict) item = '' else: i = i + 1 if i >= varlen: # end of var break continue # Start of quoted string? if var[i] == '"' or var[i] == "'": inquote = var[i] i = i + 1 continue item = item + var[i] i = i + 1 if inquote != '': recipe_error(rpstack, _("Missing quote: ") + inquote) return result def var2dictlist(globals, varname): """Get the value of $"varname" as a dictlist. Should only be called when $"varname" exists and isn't empty.""" try: dictlist = string2dictlist([], get_var_val(0, globals, varname)) except UserError, e: raise UserError, _("Error in parsing $%s") % varname if not dictlist: raise UserError, _("$%s evaluates to nothing") % varname return dictlist def listitem2str(item): """Turn an item of a list into a string, making sure special characters are escaped such that concatenated items are white-separatable.""" # First check which quote would be most appropriate to start with. It # looks a lot better when it's not halfway the item. quote = '' item_str = str(item) for c in item_str: if c == "'": quote = '"' break if c == '"': quote = "'" break if is_white(c): quote = '"' res = quote for c in item_str: if string.find("'\" \t", c) >= 0: if c == quote: res = res + quote quote = '' if not quote: if c == '"': quote = "'" else: quote = '"' res = res + quote res = res + c return res + quote def dictlistattr2str(dl): """Print the attributes in dictlist "dl".""" str = '' for k in dl.keys(): if k != "name" and k[0] != "_": str = str + ('{%s=%s}' % (k, listitem2str(dl[k]))) return str def dictlist2str(list, expand = None): """Turn a dictlist into a string that can be printed. Don't use backslashes to escape special characters. Do expanding according to "expand".""" if not expand: expand = Expand(1, Expand.quote_aap) str = '' for i in list: if str: str = str + ' ' str = str + expand_item(i, expand, "name") return str # vim: set sw=4 sts=4 tw=79 fo+=l: .