6 from ListStack
import ListStack
;
12 def __init__(self
, templateLines
):
13 """Create a new TemplateFiller, that fills the template given in
14 templateLines, which is a list of strings, as produced by readlines.
16 self
.m_log
= logging
.getLogger("TemplateFiller");
17 self
.m_inLines
= templateLines
;
20 self
.m_varRE
= re
.compile(r
"@!([^!@]*)!@");
21 self
.m_ifRE
= re
.compile(r
"@@if[ \t]+(!|)([A-Za-z\.]*)");
22 self
.m_elseRE
= re
.compile(r
"@@else");
23 self
.m_endifRE
= re
.compile(r
"@@endif");
24 self
.m_BeginFieldLoopRE
= re
.compile(r
"@@BeginFieldLoop");
25 self
.m_EndFieldLoopRE
= re
.compile(r
"@@EndFieldLoop");
26 self
.m_BeginSFFieldLoopRE
= re
.compile(r
"@@BeginSFFieldLoop");
27 self
.m_EndSFFieldLoopRE
= re
.compile(r
"@@EndSFFieldLoop");
28 self
.m_BeginMFFieldLoopRE
= re
.compile(r
"@@BeginMFFieldLoop");
29 self
.m_EndMFFieldLoopRE
= re
.compile(r
"@@EndMFFieldLoop");
30 self
.m_AdditionIncludesRE
= re
.compile(r
"@@AdditionalIncludes");
31 self
.m_AdditionPrioIncludesRE
= re
.compile(r
"@@AdditionalPriorityIncludes");
33 def fill(self
, dictList
):
34 """Fill in a template using the contents of the dictionaries in
39 skipStack
= ListStack();
44 # Go through template and find loops, collect their lines in loopLines.
45 # call _processLoop for the loopLines.
47 context
= [d
for d
in dictList
];
49 for lineNum
, line
in enumerate(self
.m_inLines
):
50 # handle @@BeginFieldLoop
51 matchBeginFieldLoop
= self
.m_BeginFieldLoopRE
.search(line
);
52 if (not skipCurrent
) and (matchBeginFieldLoop
!= None):
53 #self.m_log.debug("fill: line %d -> BeginFieldLoop", lineNum);
57 # handle @@BeginSFFieldLoop
58 matchBeginSFFieldLoop
= self
.m_BeginSFFieldLoopRE
.search(line
);
59 if (not skipCurrent
) and (matchBeginSFFieldLoop
!= None):
60 #self.m_log.debug("fill: line %d -> BeginSFFieldLoop", lineNum);
64 # handle @@BeginMFFieldLoop
65 matchBeginMFFieldLoop
= self
.m_BeginMFFieldLoopRE
.search(line
);
66 if (not skipCurrent
) and (matchBeginMFFieldLoop
!= None):
67 #self.m_log.debug("fill: line %d -> BeginMFFieldLoop", lineNum);
71 # handle loops - do not bother with conditionals they are handled in
73 if (not skipCurrent
) and (inLoop
== True):
74 # handle @@EndFieldLoop
75 matchEndFieldLoop
= self
.m_EndFieldLoopRE
.search(line
);
76 if matchEndFieldLoop
!= None:
77 #self.m_log.debug("fill: line %d -> EndFieldLoop", lineNum);
78 self
._processLoop
("Fields", loopLines
, context
);
83 # handle @@EndSFFieldLoop
84 matchEndSFFieldLoop
= self
.m_EndSFFieldLoopRE
.search(line
);
85 if matchEndSFFieldLoop
!= None:
86 #self.m_log.debug("fill: line %d -> EndSFFieldLoop", lineNum);
87 self
._processLoop
("SFields", loopLines
, context
);
92 # handle @@EndMFFieldLoop
93 matchEndMFFieldLoop
= self
.m_EndMFFieldLoopRE
.search(line
);
94 if matchEndMFFieldLoop
!= None:
95 #self.m_log.debug("fill: line %d -> EndMFFieldLoop", lineNum);
96 self
._processLoop
("MFields", loopLines
, context
);
101 loopLines
.append(line
);
104 # handle @@AdditionalIncludes
105 matchAdditionalIncludes
= self
.m_AdditionIncludesRE
.search(line
);
106 if matchAdditionalIncludes
!= None:
107 self
._processAdditionalIncludes
(dictList
);
110 # handle @@AdditionalIncludes
111 matchAdditionalPrioIncludes
= self
.m_AdditionPrioIncludesRE
.search(line
);
112 if matchAdditionalPrioIncludes
!= None:
113 self
._processAdditionalPrioIncludes
(dictList
);
116 # conditionals outside of loops must be treated here
119 matchIf
= self
.m_ifRE
.search(line
);
121 #self.m_log.debug("fill: line %d -> if", lineNum);
122 skipStack
.push(copy
.copy(skipCurrent
));
124 if skipStack
.top() == False:
125 if self
._lookup
(matchIf
.group(2), dictList
) == True:
130 if matchIf
.group(1) == "!":
131 skipCurrent
= not skipCurrent
;
135 matchElse
= self
.m_elseRE
.search(line
);
136 if matchElse
!= None:
137 #self.m_log.debug("fill: line %d -> else", lineNum);
138 if skipStack
.top() == False:
139 skipCurrent
= not skipCurrent
;
143 matchEndif
= self
.m_endifRE
.search(line
);
144 if matchEndif
!= None:
145 #self.m_log.debug("fill: line %d -> endif", lineNum);
146 skipCurrent
= skipStack
.top();
150 if skipCurrent
== True:
153 # a line with regular text - substitute variables and add to output
154 self
.m_outLines
.append(self
._substituteVariables
(line
, context
));
156 return self
.m_outLines
;
158 def _processAdditionalIncludes(self
, context
):
159 includeList
= self
._lookup
("AdditionalIncludes", context
);
161 for include
in includeList
:
162 self
.m_outLines
.append("#include <" + include
+ ">\n");
164 def _processAdditionalPrioIncludes(self
, context
):
165 includeList
= self
._lookup
("AdditionalPriorityIncludes", context
);
167 for include
in includeList
:
168 self
.m_outLines
.append("#include <" + include
+ ">\n");
170 def _processLoop(self
, loopType
, loopLines
, context
):
171 """For loopType == "Fields" repeat lines in loopLines for all fields
172 for loopType == "SFields" repeat lines in loopLines for all sfields
173 for loopType == "MFields" repeat lines in loopLines for all mfields
175 if loopType
== "Fields" or loopType
== "SFields" or loopType
== "MFields":
176 fields
= self
._lookup
(loopType
, context
);
178 self
.m_log
.error("_processLoop: unknown loopType \"%s\"." % loopType
);
181 localDict
= dict([("field", None)]);
182 loopContext
= [localDict
];
184 loopContext
.append(c
);
187 localDict
["field"] = field
;
189 skipStack
= ListStack();
192 for line
in loopLines
:
194 matchIf
= self
.m_ifRE
.search(line
);
196 skipStack
.push(copy
.copy(skipCurrent
));
198 if skipStack
.top() == False:
199 if self
._lookup
(matchIf
.group(2), loopContext
) == True:
204 if matchIf
.group(1) == "!":
205 skipCurrent
= not skipCurrent
;
209 matchElse
= self
.m_elseRE
.search(line
);
210 if matchElse
!= None:
211 if skipStack
.top() == False:
212 skipCurrent
= not skipCurrent
;
216 matchEndif
= self
.m_endifRE
.search(line
);
217 if matchEndif
!= None:
218 skipCurrent
= skipStack
.top();
222 if skipCurrent
== True:
225 # a line with regular text - substitute variables and add to output
226 self
.m_outLines
.append(self
._substituteVariables
(line
, loopContext
));
228 def _substituteVariables(self
, inLine
, context
):
229 """Replace all variables in inLine and return the resulting line.
233 for matchVar
in self
.m_varRE
.finditer(inLine
):
234 varString
= matchVar
.group(1);
235 varLen
= len(varString
) + 4;
237 if varString
.find(":") != -1:
238 varName
= varString
.split(":")[0];
239 varFieldLen
= int(varString
.split(":")[1]);
244 varValue
= self
._lookup
(varName
, context
);
245 varValue
= varValue
.ljust(varFieldLen
);
246 repLen
= len(varValue
);
248 outLine
= outLine
[:matchVar
.start()+indexOffset
] + varValue
+ \
249 outLine
[matchVar
.end()+indexOffset
:];
250 indexOffset
= indexOffset
+ (repLen
- varLen
);
254 def _lookup(self
, var
, context
):
255 """Determine the value of var in the given context, which is a dict or
257 var may consist of multiple parts separated by dots, i.e.
259 In that case the first part is looked up in the given context, the
260 next part in the context returned by the first lookup and so forth.
262 #self.m_log.debug("_lookup: var: %s" % var);
264 varParts
= var
.split(".");
267 for part
in varParts
:
268 if isinstance(context
, list):
270 if elem
.has_key(part
):
273 elif context
.has_key(part
):
274 value
= context
[part
];
279 self
.m_log
.warning("_lookup: value is None for var: %s part: %s",