ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1300 lines
44 KiB

  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  5. #
  6. # See accompanying file COPYING.TXT file for licensing details.
  7. #
  8. ############################################################################
  9. import os
  10. import re
  11. import sys
  12. import StringIO
  13. str_match=r'"([^"\\]|\\[^"]|\\")*"'
  14. single_var_param_match=r'(?:-?\d+|"(?:[^"\\]|\\[^"]|\\")*")'
  15. call_param_match=r'(?:\(\)|\((?:' + single_var_param_match + r')(?:,' + single_var_param_match + r')*\))'
  16. variable_match=r"\*?([a-zA-Z][a-zA-Z0-9_]*"+ call_param_match +r"?)(((\.|->)([a-zA-Z][a-zA-Z0-9_]*" + call_param_match + r"?))*)"
  17. def interleave(*args):
  18. for idx in range(0, max(map(len,args))):
  19. for arg in args:
  20. try:
  21. yield arg[idx]
  22. except IndexError:
  23. continue
  24. def output_declaration(s):
  25. global stack
  26. global file_name
  27. global line_number
  28. global declarations
  29. declarations.write('\t'*len(stack) + '#line %d "%s"' % (line_number,file_name)+'\n')
  30. declarations.write('\t'*len(stack) + s + '\n');
  31. def output_definition(s):
  32. global stack
  33. global file_name
  34. global line_number
  35. global definitions
  36. definitions.write('\t'*(len(stack)-1) + '#line %d "%s"' % (line_number,file_name)+'\n')
  37. definitions.write('\t'*(len(stack)-1) + s + '\n');
  38. def output_all(s):
  39. output_definition(s)
  40. output_declaration(s)
  41. class tmpl_descr:
  42. def __init__(self,start,size):
  43. self.start_id=start
  44. self.param_num=size
  45. class skin_block:
  46. basic_pattern='skin'
  47. basic_name='skin'
  48. pattern=r'^<%\s*skin\s+(\w+)?\s*%>$'
  49. type='skin'
  50. def use(self,m):
  51. global inline_cpp_to
  52. global namespace_name
  53. inline_cpp_to = output_declaration
  54. name = m.group(1)
  55. if namespace_name == '':
  56. if name == '':
  57. error_ext("Skin name is not defined implicitly or explicitly")
  58. else:
  59. namespace_name = name
  60. elif namespace_name != name and name:
  61. error_exit("Can't use more then one skin name for same skin: %s, %s" % ( namespace_name,name))
  62. output_all( "namespace %s {" % namespace_name)
  63. global stack
  64. stack.append(self)
  65. def on_end(self):
  66. global namespace_name
  67. output_all( "} // end of namespace %s" % namespace_name)
  68. def write_class_loader(unsafe = False):
  69. global class_list
  70. global namespace_name
  71. output_definition("namespace {")
  72. output_definition(" cppcms::views::generator my_generator; ")
  73. output_definition(" struct loader { ")
  74. output_definition(" loader() { ")
  75. output_definition(' my_generator.name("%s");' % namespace_name)
  76. if unsafe:
  77. safe = 'false'
  78. else:
  79. safe = 'true'
  80. for class_def in class_list:
  81. output_definition( ' my_generator.add_view<%s::%s,%s>("%s",%s);' \
  82. % (class_def.namespace,class_def.name,class_def.content_name,class_def.name,safe))
  83. output_definition(' cppcms::views::pool::instance().add(my_generator);')
  84. output_definition(' }')
  85. output_definition(' ~loader() { cppcms::views::pool::instance().remove(my_generator); }')
  86. output_definition('} a_loader;')
  87. output_definition('} // anon ')
  88. class html_type:
  89. basic_pattern='x?html'
  90. basic_name='xhtml'
  91. pattern=r'^<%\s*(x)?html\s*%>$'
  92. def use(self,m):
  93. global html_type_code
  94. if m.group(1):
  95. html_type_code='as_xhtml'
  96. else:
  97. html_type_code='as_html'
  98. class view_block:
  99. pattern=r'^<%\s*view\s+(\w+)\s+uses\s+(:?:?\w+(::\w+)*)(\s+extends\s+(:?:?\w+(::\w+)?))?(?P<abs>\s+abstract)?(?P<inline>\s+inline)?\s*%>$'
  100. basic_pattern='view'
  101. basic_name='view'
  102. type='view'
  103. topmost = 0
  104. def declare(self):
  105. if self.extends=='' :
  106. constructor='cppcms::base_view(_s)'
  107. self.extends='cppcms::base_view'
  108. self.topmost = 1
  109. else:
  110. constructor='%s(_s,_content)' % self.extends;
  111. global dll_api
  112. if self.inline:
  113. api_ref = ''
  114. else:
  115. api_ref = dll_api
  116. output_declaration( "struct %s %s :public %s" % (api_ref, self.class_name , self.extends ))
  117. output_declaration( "{")
  118. if self.uses!='' :
  119. output_declaration( "\t%s &content;" % self.uses)
  120. output_declaration( "\t%s(std::ostream &_s,%s &_content): %s,content(_content),_domain_id(0)" % ( self.class_name,self.uses,constructor ))
  121. else:
  122. output_declaration( "\t%s(std::ostream &_s): %s,_domain_id(0)" % ( self.class_name,constructor ))
  123. output_declaration("\t{")
  124. global spec_gettext
  125. if spec_gettext:
  126. self.gettext_domain = spec_gettext;
  127. output_declaration( '\t\t_domain_id=cppcms::translation_domain_scope::domain_id(_s,"%s");' % self.gettext_domain)
  128. else:
  129. output_declaration( '\t\t_domain_id=booster::locale::ios_info::get(_s).domain_id();')
  130. self.gettext_domain = None;
  131. output_declaration("\t}")
  132. def use(self,m):
  133. global view_created
  134. view_created = True
  135. self.abstract = m.group('abs')!=None
  136. self.inline = m.group('inline')!=None
  137. global view_name
  138. global output_template
  139. self.class_name=m.group(1)
  140. view_name = self.class_name
  141. self.uses=m.group(2)
  142. if m.group(4):
  143. self.extends=m.group(5)
  144. else:
  145. self.extends=''
  146. self.declare();
  147. global stack
  148. if len(stack)!=1 or stack[-1].type!='skin':
  149. error_exit("You must define view inside skin block only")
  150. stack.append(self)
  151. global namespace_name
  152. class information:
  153. content_name=self.uses
  154. name=self.class_name
  155. namespace=namespace_name
  156. global class_list
  157. if not self.abstract:
  158. class_list.append(information())
  159. def on_end(self):
  160. output_declaration( "private:")
  161. output_declaration( "\tint _domain_id;")
  162. output_declaration( "}; // end of class %s" % self.class_name)
  163. class template_block:
  164. pattern=r'^<%\s*template\s+([a-zA-Z]\w*)\s*\(([\w\s,:\&]*)\)\s*(?P<abs>=\s*0\s*)?%>$'
  165. basic_pattern = 'template'
  166. basic_name='template'
  167. type='template'
  168. plist=[]
  169. def create_parameters(self,lst):
  170. pattern=r'^\s*((:?:?\w+(::\w+)*)\s*(const)?\s*(\&)?\s*(\w+))\s*(,(.*))?$'
  171. m=re.match(pattern,lst)
  172. res=[]
  173. while m:
  174. global tmpl_seq
  175. id=m.group(6)
  176. if id in tmpl_seq:
  177. error_exit("Duplicate definition of patameter %s" % id)
  178. for v in self.plist:
  179. del tmpl_seq[v]
  180. return ""
  181. tmpl_seq[id]=''
  182. res.append(m.group(1))
  183. self.plist.append(id)
  184. if m.group(8):
  185. lst=m.group(8)
  186. m=re.match(pattern,lst)
  187. else:
  188. return ','.join(res)
  189. for v in self.plist:
  190. del tmpl_seq[v]
  191. error_exit("Wrong expression %s" % lst)
  192. def use(self,m):
  193. global view_name
  194. global inline_templates
  195. self.name=m.group(1)
  196. params=""
  197. abstract = m.group('abs') != None
  198. if m.group(2) and not re.match('^\s*$',m.group(2)):
  199. params=self.create_parameters(m.group(2))
  200. if abstract:
  201. output_declaration( "virtual void %s(%s) = 0;" % (self.name,params) )
  202. else:
  203. if inline_templates:
  204. output_declaration( "virtual void %s(%s) {" % (self.name,params) )
  205. output_declaration( "\tcppcms::translation_domain_scope _trs(out(),_domain_id);\n")
  206. else:
  207. output_declaration( "virtual void %s(%s);" % (self.name,params) )
  208. output_definition( "void %s::%s(%s) {" % (view_name,self.name,params) )
  209. output_definition( "\tcppcms::translation_domain_scope _trs(out(),_domain_id);\n")
  210. global stack
  211. if len(stack)==0 or stack[-1].type!='view':
  212. error_exit("You must define template inside view block only")
  213. if abstract:
  214. return
  215. stack.append(self)
  216. global current_template
  217. current_template=self.name
  218. global ignore_inline
  219. global inline_cpp_to
  220. ignore_inline=0
  221. inline_cpp_to = output_template
  222. def on_end(self):
  223. global output_template
  224. output_template( "} // end of template %s" % self.name)
  225. global ignore_inline
  226. ignore_inline=1
  227. global tmpl_seq
  228. tmpl_seq={}
  229. global inline_cpp_to
  230. inline_cpp_to = output_declaration
  231. def inline_content(s):
  232. global ignore_inline
  233. global output_template
  234. if not ignore_inline:
  235. output_template( 'out()<<"%s";' % to_string(s))
  236. def warning(x):
  237. global file_name
  238. global line_number
  239. sys.stderr.write("Warning: %s in file %s, line %d\n" % (x,file_name,line_number))
  240. def error_exit(x):
  241. global exit_flag
  242. global file_name
  243. global line_number
  244. sys.stderr.write("Error: %s in file %s, line %d\n" % (x,file_name,line_number))
  245. exit_flag=1
  246. def to_string(s):
  247. res=''
  248. for c in s:
  249. global stack
  250. if c=='\n':
  251. res+="\\n\""+"\n"+"\t"*len(stack)+"\t\""
  252. elif c=="\t":
  253. res+="\\t"
  254. elif c=="\v":
  255. res+="\\v"
  256. elif c=="\b":
  257. res+="\\b"
  258. elif c=="\r":
  259. res+="\\r"
  260. elif c=="\f":
  261. res+="\\f"
  262. elif c=="\a":
  263. res+="\\a"
  264. elif c=="\\":
  265. res+="\\\\"
  266. elif c=="\"":
  267. res+="\\\""
  268. elif ord(c)>0 and ord(c)<32:
  269. res+="%03o" % ord(c)
  270. else:
  271. res+=c
  272. return res
  273. def make_ident(val):
  274. m=re.match('^'+variable_match+'$',val)
  275. global tmpl_seq
  276. if m.group(1) in tmpl_seq:
  277. return val
  278. m2=re.match('^\*(.*)$',val)
  279. if m2:
  280. return "*content." + m2.group(1)
  281. else:
  282. return "content." + val
  283. def print_using_block_start(class_name,variable_name,content_name,temp_and_view=None):
  284. global output_template
  285. if content_name:
  286. content=make_ident(content_name)
  287. guard=True
  288. else:
  289. content ='content'
  290. guard=False
  291. output_template(r'{')
  292. if guard:
  293. output_template(r' cppcms::base_content::app_guard _g(%s,content);' % content);
  294. if temp_and_view:
  295. output_template(r' cppcms::views::view_lock _vl(%s,out(),%s); %s &%s = _vl.use_view<%s>();' % ( temp_and_view, content, class_name, variable_name, class_name));
  296. else:
  297. output_template(r' %s %s(out(),%s);' % ( class_name, variable_name, content));
  298. def print_using_block_end():
  299. global output_template
  300. output_template('}')
  301. class using_block:
  302. pattern=r'^<%\s*using\s+(?P<class>(?:\w+::)*\w+)(?:\s+with\s+(?P<content>' + variable_match + r'))?\s+as\s+(?P<name>[a-zA-Z_]\w*)' \
  303. + r'(?P<from>\s+from' \
  304. + r'(\s*(?P<fst_str>'+ str_match +r')|(?:\s+(?P<fst_var>' + variable_match + r')))' \
  305. + r'(\s*,\s*((?P<snd_str>'+ str_match +r')|(?P<snd_var>' + variable_match + r')))?' \
  306. + r')?' \
  307. + '\s*%>$'
  308. basic_pattern = 'using'
  309. basic_name = 'using'
  310. type='using'
  311. def use(self,m):
  312. if m.group('from'):
  313. temp_and_view = get_render_names(m);
  314. else:
  315. temp_and_view = None
  316. print_using_block_start(m.group('class'),m.group('name'),m.group('content'),temp_and_view)
  317. global stack
  318. stack.append(self)
  319. def on_end(self):
  320. print_using_block_end();
  321. class foreach_block:
  322. pattern=r'^<%\s*foreach\s+([a-zA-Z]\w*)(\s+as\s+((:?:?\w+)(::\w+)*))?' \
  323. + r'(?:\s+rowid\s+([a-zA-Z]\w*)(?:\s+from\s+(\d+))?)?' \
  324. + r'(?:\s+(reverse))?' \
  325. + '\s+in\s+(' + variable_match +')\s*%>$'
  326. basic_pattern = 'foreach'
  327. basic_name = 'foreach'
  328. type='foreach'
  329. has_item=0
  330. has_separator=0
  331. separator_label=''
  332. on_first_label=''
  333. type_name=0
  334. def use(self,m):
  335. global output_template
  336. self.ident=m.group(1)
  337. self.seq_name=make_ident(m.group(9))
  338. self.rowid = m.group(6)
  339. if m.group(7):
  340. self.rowid_begin = int(m.group(7))
  341. else:
  342. self.rowid_begin = 0
  343. if m.group(8):
  344. self.reverse = 'r'
  345. else:
  346. self.reverse = ''
  347. self.type_name = m.group(3)
  348. global tmpl_seq
  349. if self.ident in tmpl_seq:
  350. error_exit("Nested sequences with same name %s" % self.ident)
  351. if self.rowid == self.ident:
  352. error_exit("Nested sequence and rowid has same name %s" % self.ident)
  353. if self.rowid and (self.rowid in tmpl_seq):
  354. error_exit("Nested sequences with same rowid name %s" % self.rowid )
  355. tmpl_seq[self.ident]='';
  356. output_template( "if((%s).%sbegin()!=(%s).%send()) {" % (self.seq_name,self.reverse,self.seq_name,self.reverse) )
  357. if self.rowid:
  358. tmpl_seq[self.rowid]='';
  359. output_template(" int %s = %s;" % (self.rowid,self.rowid_begin))
  360. global stack
  361. stack.append(self)
  362. def on_end(self):
  363. global output_template
  364. if not self.has_item:
  365. error_exit("foreach without item")
  366. global tmpl_seq
  367. del tmpl_seq[self.ident]
  368. if self.rowid:
  369. del tmpl_seq[self.rowid]
  370. output_template( "}" )
  371. def prepare_foreach(self):
  372. global output_template
  373. if not self.type_name:
  374. ptr_type = 'CPPCMS_TYPEOF((%(s)s).%(r)sbegin())'
  375. else:
  376. ptr_type = self.type_name
  377. incr = ''
  378. if self.rowid:
  379. incr = ',++%s' % self.rowid;
  380. fmt = "for("+ptr_type+" %(i)s_ptr=(%(s)s).%(r)sbegin(),%(i)s_ptr_end=(%(s)s).%(r)send();%(i)s_ptr!=%(i)s_ptr_end;++%(i)s_ptr%(u)s) {";
  381. fmt = fmt % { 's' : self.seq_name, 'i' : self.ident , 'r' : self.reverse, 'u' : incr };
  382. output_template(fmt)
  383. if not self.type_name:
  384. output_template( "CPPCMS_TYPEOF(*%s_ptr) &%s=*%s_ptr;" % (self.ident,self.ident,self.ident))
  385. else:
  386. output_template( "std::iterator_traits< %s >::value_type &%s=*%s_ptr;" % (self.type_name,self.ident,self.ident))
  387. if self.has_separator:
  388. output_template( "if(%s_ptr!=(%s).%sbegin()) {" % (self.ident,self.seq_name,self.reverse))
  389. class separator_block:
  390. pattern=r'^<%\s*separator\s*%>'
  391. basic_pattern = 'separator'
  392. basic_name = 'separator'
  393. type='separator'
  394. def use(self,m):
  395. global stack
  396. if len(stack)==0 or stack[len(stack)-1].type!='foreach':
  397. error_exit("separator without foreach")
  398. return
  399. foreachb=stack[len(stack)-1]
  400. if foreachb.has_separator:
  401. error_exit("two separators for one foreach")
  402. foreachb.has_separator=1
  403. foreachb.prepare_foreach()
  404. class item_block:
  405. pattern=r'^<%\s*item\s*%>'
  406. basic_pattern = 'item'
  407. basic_name = 'item'
  408. type='item'
  409. def use(self,m):
  410. global stack
  411. global output_template
  412. if not stack or stack[-1].type!='foreach':
  413. error_exit("item without foreach")
  414. return
  415. foreachb=stack[-1]
  416. if foreachb.has_item:
  417. error_exit("Two items for one foreach");
  418. if foreachb.has_separator:
  419. output_template( "} // end of separator")
  420. else:
  421. foreachb.prepare_foreach()
  422. foreachb.has_item=1
  423. stack.append(self)
  424. def on_end(self):
  425. global output_template
  426. output_template( "} // end of item" )
  427. class empty_block:
  428. pattern=r'^<%\s*empty\s*%>'
  429. basic_pattern = 'empty'
  430. basic_name = 'empty'
  431. type='empty'
  432. def use(self,m):
  433. global stack
  434. global output_template
  435. if not stack or stack[-1].type!='foreach':
  436. error_exit("empty without foreach")
  437. return
  438. forb=stack.pop()
  439. if not forb.has_item:
  440. error_exit("Unexpected empty - item missed?")
  441. output_template( " } else {")
  442. self.ident=forb.ident
  443. self.rowid=forb.rowid
  444. stack.append(self)
  445. def on_end(self):
  446. global output_template
  447. output_template( "} // end of empty")
  448. global tmpl_seq
  449. del tmpl_seq[self.ident]
  450. if self.rowid:
  451. del tmpl_seq[self.rowid]
  452. class else_block:
  453. pattern=r'^<%\s*else\s*%>$'
  454. basic_pattern = 'else'
  455. basic_name = 'else'
  456. type='else'
  457. def on_end(self):
  458. global output_template
  459. output_template("}")
  460. def use(self,m):
  461. global output_template
  462. prev=stack.pop()
  463. if prev.type!='if' and prev.type!='elif':
  464. error_exit("elif without if");
  465. output_template( "}else{")
  466. stack.append(self)
  467. class if_block:
  468. pattern=r'^<%\s*(if|elif)\s+((not\s+|not\s+empty\s+|empty\s+)?('+variable_match+')|\((.+)\)|)\s*%>$'
  469. basic_pattern = '(if|elif)'
  470. basic_name = 'if/elif'
  471. type='if'
  472. def prepare(self):
  473. global output_template
  474. output_template( "if(%s) {" % self.ident)
  475. def on_end(self):
  476. global output_template
  477. output_template( "} // endif")
  478. def use(self,m):
  479. global stack
  480. global output_template
  481. self.type=m.group(1)
  482. if m.group(4):
  483. if m.group(4)=='rtl':
  484. self.ident='(cppcms::locale::translate("LTR").str(out().getloc())=="RTL")'
  485. else:
  486. self.ident=make_ident(m.group(4))
  487. if m.group(3):
  488. if re.match('.*empty',m.group(3)):
  489. self.ident=self.ident + '.empty()'
  490. if re.match('not.*',m.group(3)):
  491. self.ident="!("+self.ident+")"
  492. else:
  493. self.ident=m.group(10)
  494. if self.type == 'if' :
  495. self.prepare()
  496. stack.append(self)
  497. else: # type == elif
  498. if stack :
  499. prev=stack.pop()
  500. if prev.type!='if' and prev.type!='elif':
  501. error_exit("elif without if");
  502. output_template( "}")
  503. output_template( "else")
  504. self.prepare()
  505. stack.append(self)
  506. else:
  507. error_exit("Unexpeced elif");
  508. # END ifop
  509. class end_block:
  510. pattern=r'^<%\s*end(\s+(\w+))?\s*%>$';
  511. basic_pattern = 'end'
  512. basic_name = 'end'
  513. def use(self,m):
  514. global stack
  515. if not stack:
  516. error_exit("Unexpeced 'end'");
  517. else:
  518. obj=stack.pop();
  519. if m.group(1):
  520. if obj.type!=m.group(2):
  521. error_exit("End of %s does not match block %s" % (m.group(2) , obj.type));
  522. obj.on_end()
  523. class error_com:
  524. pattern=r'^<%(.*)%>$'
  525. basic_pattern = ''
  526. basic_name = ''
  527. def use(self,m):
  528. error_exit("Invalid statement `%s'" % m.group(1))
  529. class domain_block:
  530. pattern=r'^<%\s*domain\s+(\w+)\s*%>$'
  531. basic_pattern = 'domain'
  532. basic_name = 'domain'
  533. type = 'domain'
  534. def use(self,m):
  535. gt = m.group(1)
  536. global spec_gettext
  537. global view_created
  538. if not spec_gettext:
  539. if view_created:
  540. error_exit("Can't use domain command after a view was created")
  541. else:
  542. spec_gettext = gt
  543. return
  544. if spec_gettext != gt:
  545. error_exit("Gettext domain is already defined as `%s' and differs from given `%s'" % (spec_gettext , gt ))
  546. class cpp_include_block:
  547. pattern=r'^<%\s*c\+\+(src)?\s+(.*)%>$'
  548. basic_pattern = 'c\+\+(src)?'
  549. basic_name = 'c++'
  550. def use(self,m):
  551. global inline_cpp_to
  552. if m.group(1):
  553. output_definition(m.group(2));
  554. else:
  555. inline_cpp_to( m.group(2));
  556. def get_filter(cur):
  557. if not cur:
  558. global scope_filter
  559. return scope_filter
  560. return cur
  561. class base_show:
  562. mark='('+variable_match+r')\s*(\|(.*))?'
  563. base_pattern='^\s*'+mark + '$'
  564. def __init__(self,default_filter=None):
  565. self.default_filter=default_filter
  566. def get_params(self,s):
  567. pattern='^\s*(('+variable_match+')|('+str_match+')|(\-?\d+(\.\d*)?))\s*(,(.*))?$'
  568. res=[]
  569. m=re.match(pattern,s)
  570. while m:
  571. if m.group(2):
  572. res.append(make_ident(m.group(2)))
  573. elif m.group(8):
  574. res.append(m.group(8))
  575. elif m.group(10):
  576. res.append(m.group(10))
  577. if m.group(13):
  578. s=m.group(13)
  579. m=re.match(pattern,s)
  580. else:
  581. return res
  582. error_exit("Invalid parameters: `%s'" % s )
  583. return []
  584. def prepare(self,s):
  585. m=re.match(self.base_pattern,s)
  586. if not m:
  587. error_exit("No variable")
  588. return [];
  589. var=make_ident(m.group(1))
  590. if not m.group(8):
  591. return "%s(%s)" % (get_filter(self.default_filter), var)
  592. filters=m.group(8)
  593. expr='^\s*(ext\s+)?(\w+)\s*(\((([^"\)]|'+str_match + ')*)\))?\s*(\|(.*))?$'
  594. m=re.match(expr,filters)
  595. while m:
  596. if m.group(1):
  597. func="content."+m.group(2)
  598. else:
  599. func="cppcms::filters::" + m.group(2)
  600. if m.group(3):
  601. params=','.join([var]+self.get_params(m.group(4)))
  602. else:
  603. params=var
  604. var=func+"("+params+")"
  605. if m.group(8):
  606. filters=m.group(8)
  607. m=re.match(expr,filters)
  608. else:
  609. return var
  610. error_exit("Seems to be a problem in expression %s" % filters)
  611. return "";
  612. class form_block:
  613. pattern=r'^<%\s*form\s+(as_p|as_table|as_ul|as_dl|as_space|input|block|begin|end)\s+('\
  614. + variable_match +')\s*%>$'
  615. basic_pattern = 'form'
  616. basic_name = 'form'
  617. type = 'form'
  618. def format_input(self,command_type,ident):
  619. global html_type_code
  620. global output_template
  621. flags = 'cppcms::form_flags::' + html_type_code;
  622. output_template('{ cppcms::form_context _form_context(out(),%s);' % flags)
  623. render_command = ' (%s).render_input(_form_context);' % ident;
  624. if command_type=='begin':
  625. output_template(' _form_context.widget_part(cppcms::form_context::first_part);')
  626. output_template(render_command)
  627. elif command_type=='end':
  628. output_template(' _form_context.widget_part(cppcms::form_context::second_part);')
  629. output_template(render_command)
  630. else:
  631. output_template(' _form_context.widget_part(cppcms::form_context::first_part);')
  632. output_template(render_command)
  633. output_template(' out() << (%s).attributes_string();' % ident)
  634. output_template(' _form_context.widget_part(cppcms::form_context::second_part);')
  635. output_template(render_command)
  636. output_template('}')
  637. def use(self,m):
  638. global output_template
  639. ident=make_ident(m.group(2))
  640. command_type = m.group(1)
  641. global html_type_code
  642. if command_type=='input' or command_type=='begin' or command_type=='end' or command_type=='block':
  643. if command_type != 'block':
  644. self.format_input(command_type,ident)
  645. else:
  646. self.format_input('begin',ident)
  647. self.ident = ident
  648. self.command_type = 'end'
  649. global stack
  650. stack.append(self)
  651. else:
  652. flags = 'cppcms::form_flags::%s,cppcms::form_flags::%s' % ( html_type_code, m.group(1));
  653. output_template('{ cppcms::form_context _form_context(out(),%s); (%s).render(_form_context); }' % (flags , ident))
  654. def on_end(self):
  655. self.format_input(self.command_type,self.ident)
  656. def get_render_names(m):
  657. first_str = m.group('fst_str')
  658. first_var = m.group('fst_var')
  659. if first_var:
  660. first = make_ident(first_var)
  661. else:
  662. first = first_str
  663. second_str = m.group('snd_str')
  664. second_var = m.group('snd_var')
  665. if second_var:
  666. second = make_ident(second_var)
  667. else:
  668. second = second_str
  669. if first and second:
  670. template_name = first
  671. view_name = second
  672. else:
  673. global namespace_name
  674. template_name = '"' + namespace_name + '"'
  675. view_name = first;
  676. return template_name + ', ' + view_name
  677. class render_block:
  678. pattern=r'^<%\s*render\s+' \
  679. + r'((?P<fst_str>'+ str_match +r')|(?P<fst_var>' + variable_match + r'))' \
  680. + r'(\s*,\s*((?P<snd_str>'+ str_match +r')|(?P<snd_var>' + variable_match + r')))?' \
  681. + r'(\s+with\s+(?P<content>' + variable_match + r'))?\s*%>$'
  682. basic_pattern = 'render'
  683. basic_name = 'render'
  684. def use(self,m):
  685. global output_template
  686. if m.group('content'):
  687. content = make_ident(m.group('content'))
  688. guard=True
  689. else:
  690. content = 'content';
  691. guard=False
  692. temp_and_view = get_render_names(m);
  693. output_template('{')
  694. if guard:
  695. output_template(r'cppcms::base_content::app_guard _g(%s,content);' % content)
  696. output_template(r'cppcms::views::pool::instance().render(%s,out(),%s);' % (temp_and_view,content))
  697. output_template('}')
  698. class filters_show_block(base_show):
  699. pattern=r'^<%(=)?\s*('+ variable_match + r'\s*(\|.*)?)%>$'
  700. basic_pattern = '=?'
  701. basic_name = 'Inline Variable'
  702. def use(self,m):
  703. global output_template
  704. if not m.group(1):
  705. warning("Variables syntax like <% foo %> is deprecated, use <%= foo %> syntax");
  706. expr=self.prepare(m.group(2));
  707. if expr!="":
  708. output_template('out()<<%s;' % expr)
  709. def make_format_params(s,default_filter = None):
  710. pattern=r'^(([^,\("]|'+str_match+'|\(([^"\)]|'+str_match+')*\))+)(,(.*))?$'
  711. params=[]
  712. m=re.match(pattern,s)
  713. s_orig=s
  714. while m.group(1):
  715. res=base_show(default_filter).prepare(m.group(1))
  716. if res:
  717. params.append(res)
  718. if not m.group(6):
  719. return params
  720. s=m.group(7)
  721. m=re.match(pattern,s)
  722. error_exit("Seems to be wrong parameters list [%s]" % s_orig)
  723. return []
  724. class filter_block:
  725. pattern=r'^<%\s*filter\s+(ext\s+)?(\w+)\s*%>'
  726. basic_pattern = 'filter'
  727. basic_name = 'filter'
  728. type = 'filter'
  729. def use(self,m):
  730. global scope_filter
  731. self.save_filter = scope_filter
  732. if m.group(1):
  733. scope_filter='content.' + m.group(2)
  734. else:
  735. scope_filter='cppcms::filters::' + m.group(2)
  736. global stack
  737. stack.append(self)
  738. def on_end(self):
  739. global scope_filter
  740. scope_filter=self.save_filter
  741. class cache_block:
  742. pattern=r'^<%\s*cache\s+((?P<str>'+ \
  743. str_match +')|(?P<var>'+ variable_match +r'))' + \
  744. r'(\s+for\s+(?P<time>\d+))?(\s+on\s+miss\s+(?P<callback>[a-zA-Z]\w*)\(\))?' \
  745. + r'(?P<notriggers>\s+no\s+triggers)?' \
  746. + r'(?P<norecording>\s+no\s+recording)?' \
  747. + '\s*%>$'
  748. basic_pattern = 'cache'
  749. basic_name = 'cache'
  750. type = 'cache'
  751. def use(self,m):
  752. global output_template
  753. if(m.group('str')):
  754. self.parameter = m.group('str')
  755. else:
  756. self.parameter = make_ident(m.group('var'));
  757. self.notriggers = m.group('notriggers')
  758. self.norecording = m.group('norecording')
  759. output_template('{ std::string _cppcms_temp_val;')
  760. output_template(' if(content.app().cache().fetch_frame(%s,_cppcms_temp_val))' % self.parameter);
  761. output_template(' out() << _cppcms_temp_val;');
  762. output_template(' else {')
  763. output_template(' cppcms::copy_filter _cppcms_cache_flt(out());')
  764. if not self.norecording:
  765. output_template(' cppcms::triggers_recorder _cppcms_trig_rec(content.app().cache());')
  766. # the code below should be the last one
  767. if(m.group('callback')):
  768. output_template(' '+make_ident(m.group('callback')+'()') + ';')
  769. self.timeout = m.group('time');
  770. global stack
  771. stack.append(self)
  772. def on_end(self):
  773. global output_template
  774. if self.timeout:
  775. timeout_time = self.timeout
  776. else:
  777. timeout_time = '-1'
  778. if self.norecording:
  779. recorded = 'std::set<std::string>()'
  780. else:
  781. recorded = '_cppcms_trig_rec.detach()'
  782. if self.notriggers:
  783. notriggers='true'
  784. else:
  785. notriggers='false'
  786. output_template(' content.app().cache().store_frame(%s,_cppcms_cache_flt.detach(),%s,%s,%s);' \
  787. % (self.parameter,recorded,timeout_time,notriggers))
  788. output_template('}} // cache')
  789. class trigger_block:
  790. pattern=r'^<%\s*trigger\s+((?P<str>'+ str_match +')|(?P<var>'+ variable_match +r'))' + r'\s*%>$'
  791. basic_pattern = 'trigger'
  792. basic_name = 'trigger'
  793. def use(self,m):
  794. global output_template
  795. if(m.group('str')):
  796. parameter = m.group('str')
  797. else:
  798. parameter = make_ident(m.group('var'));
  799. output_template('content.app().cache().add_trigger(%s);' % parameter)
  800. class ngettext_block:
  801. pattern=r'^<%\s*ngt\s*((?:' + str_match + '\s*,\s*)?'+str_match+')\s*,\s*('+str_match+')\s*,\s*('+variable_match+')\s*(using(.*))?\s*%>$'
  802. basic_pattern = 'ngt'
  803. basic_name = 'ngt'
  804. def use(self,m):
  805. global output_template
  806. s1=m.group(1)
  807. s2=m.group(4)
  808. idt=make_ident(m.group(6))
  809. params=[]
  810. if m.group(12):
  811. params=make_format_params(m.group(13))
  812. if not params:
  813. output_template( "out()<<cppcms::locale::translate(%s,%s,%s);" % (s1,s2,idt))
  814. else:
  815. output_template( "out()<<cppcms::locale::format(cppcms::locale::translate(%s,%s,%s)) %% (%s);" % (s1,s2,idt, ') % ('.join(params)))
  816. class gettext_block:
  817. pattern=r'^<%\s*gt\s*((?:' + str_match + '\s*,\s*)?' +str_match+')\s*(using(.*))?\s*%>$'
  818. basic_pattern = 'gt'
  819. basic_name = 'gt'
  820. def use(self,m):
  821. global output_template
  822. s=m.group(1)
  823. params=[]
  824. if m.group(4):
  825. params=make_format_params(m.group(5))
  826. if not params:
  827. output_template( "out()<<cppcms::locale::translate(%s);" % s)
  828. else:
  829. output_template( "out()<<cppcms::locale::format(cppcms::locale::translate(%s)) %% (%s);" % (s , ') % ('.join(params)))
  830. class url_block:
  831. pattern=r'^<%\s*url\s*('+str_match+')\s*(using(.*))?\s*%>$'
  832. basic_pattern = 'url'
  833. basic_name = 'url'
  834. def use(self,m):
  835. global output_template
  836. s=m.group(1)
  837. params=[]
  838. if m.group(3):
  839. params=make_format_params(m.group(4),'cppcms::filters::urlencode')
  840. if not params:
  841. output_template( "content.app().mapper().map(out(),%s);" % s)
  842. else:
  843. output_template( "content.app().mapper().map(out(),%s, %s);" % (s , ', '.join(params)))
  844. class csrf_block:
  845. pattern=r'^<%\s*csrf(\s+(token|cookie|script))?\s*%>$'
  846. basic_pattern = 'csrf'
  847. basic_name = 'csrf'
  848. def use(self,m):
  849. global output_template
  850. s=m.group(2)
  851. global html_type_code
  852. if html_type_code == 'as_xhtml':
  853. suffix = '/'
  854. else:
  855. suffix =''
  856. if not s:
  857. output_template(r'out() << "<input type=\"hidden\" name=\"_csrf\" value=\"" << content.app().session().get_csrf_token() <<"\" %s>\n";' % suffix)
  858. elif s == 'token':
  859. output_template(r'out() << content.app().session().get_csrf_token();')
  860. elif s == 'cookie':
  861. output_template(r'out() << content.app().session().get_csrf_token_cookie_name();')
  862. else: # script
  863. script="""
  864. <script type='text/javascript'>
  865. <!--
  866. {
  867. var cppcms_cs = document.cookie.indexOf("$=");
  868. if(cppcms_cs != -1) {
  869. cppcms_cs += '$='.length;
  870. var cppcms_ce = document.cookie.indexOf(";",cppcms_cs);
  871. if(cppcms_ce == -1) {
  872. cppcms_ce = document.cookie.length;
  873. }
  874. var cppcms_token = document.cookie.substring(cppcms_cs,cppcms_ce);
  875. document.write('<input type="hidden" name="_csrf" value="' + cppcms_token + '" %s>');
  876. }
  877. }
  878. -->
  879. </script>
  880. """ % suffix;
  881. script = to_string(script).replace('$','"<< content.app().session().get_csrf_token_cookie_name() <<"')
  882. output_template('out() << "' + script +'";')
  883. class include_block:
  884. basic_pattern = 'include'
  885. basic_name = 'include'
  886. pattern=r'^<%\s*include\s+([a-zA-Z]\w*(::\w+)?)\s*\(\s*(.*)\)' \
  887. + r'(?:\s+' \
  888. + r'(from\s+(?P<from>\w+)' \
  889. + '|' \
  890. + r'using\s+(?P<class>(\w+::)*(\w+))(?:\s+with\s+(?P<content>' + variable_match +r'))?' \
  891. + r'))?' \
  892. + r'\s*%>$'
  893. def print_include(self,call,params):
  894. global output_template
  895. output_template( "%s(%s);" % (call , ','.join(params)))
  896. def use(self,m):
  897. if m.group(3):
  898. params=base_show().get_params(m.group(3))
  899. else:
  900. params=[]
  901. call=m.group(1)
  902. if m.group('from'):
  903. call = m.group('from') + '.' + call
  904. self.print_include(call,params)
  905. elif m.group('class'):
  906. print_using_block_start(m.group('class'),'_using',m.group('content'))
  907. self.print_include('_using.' + call,params)
  908. print_using_block_end()
  909. else:
  910. self.print_include(call,params)
  911. def fetch_content(content):
  912. tmp=''
  913. for row in re.split('\n',content):
  914. global line_number
  915. global file_name
  916. line_number+=1
  917. l1=re.split(r'<%([^"%]|"([^"\\]|\\[^"]|\\")*"|%[^>])*%>',row)
  918. n=0
  919. for l2 in re.finditer(r'<%([^"%]|"([^"\\]|\\[^"]|\\")*"|%[^>])*%>',row):
  920. yield tmp+l1[n]
  921. tmp=''
  922. yield l2.group(0)
  923. n+=3
  924. tmp+=l1[n]+'\n'
  925. yield tmp
  926. def help():
  927. print( "Usage cppcms_tmpl_cc [-o filename.cpp] [-s skin] [-d domain] file1.tmpl ... \n" \
  928. " -o/--code filename.cpp file name that implements this template\n" \
  929. " -s/-n/--skin skin define skin name\n" \
  930. " -d domain setup gettext domain for this template\n" \
  931. " -u/--unsafe-cast use unsafe static casting instead of dynamic casing for dlls\n" \
  932. " -l/--no-loader do not generate loader for the views.\n" \
  933. " This requires a separate loader to be implemented in some other cpp.\n" \
  934. " -H/--header filename.hpp generate header file. \n" \
  935. " -I/--include directory prepend directory to file name include path. \n" \
  936. " -i/--inline-templates value Whether to inline the template definitions inside the view declaration.\n" \
  937. " value can be one of the following:\n" \
  938. " true Inline the template functions inside the view class declaration.\n" \
  939. " false Place the template function definitions outside the class declaration.\n" \
  940. " default (Default value is parameter is omitted.) If header file is\n" \
  941. " generated, same as false, otherwise same as true.\n" \
  942. " -h/--help show this help message\n")
  943. def main():
  944. global stack
  945. all=[]
  946. indx=1
  947. global namespace_name
  948. global output_file
  949. global header_file
  950. global exit_flag
  951. global include_directory
  952. global inline_templates
  953. unsafe_build = False
  954. write_loader = True
  955. while indx < len(os.sys.argv):
  956. if os.sys.argv[indx]=='-s' or os.sys.argv[indx]=='-n' or os.sys.argv[indx]=='--skin':
  957. if indx+1>=len(os.sys.argv):
  958. sys.stderr.write("%s should be followed by skin name\n" % (os.sys.argv[indx]))
  959. help()
  960. exit_flag=1
  961. return
  962. else:
  963. namespace_name=os.sys.argv[indx+1];
  964. indx+=1
  965. elif os.sys.argv[indx]=='-o' or os.sys.argv[indx]=='--code':
  966. if indx+1>=len(os.sys.argv):
  967. sys.stderr.write("%s should be followed by output file name\n" % (os.sys.argv[indx]))
  968. help()
  969. exit_flag=1
  970. return
  971. else:
  972. output_file=os.sys.argv[indx+1]
  973. indx+=1
  974. elif os.sys.argv[indx]=='-I' or os.sys.argv[indx]=='-include':
  975. if indx+1>=len(os.sys.argv):
  976. sys.stderr.write("%s should be followed by directory name\n" % (os.sys.argv[indx]))
  977. help()
  978. exit_flag=1
  979. return
  980. else:
  981. include_directory=os.sys.argv[indx+1]
  982. if not include_directory.endswith('/') and not include_directory.endswith('\\'):
  983. include_directory=include_directory + '/';
  984. indx+=1
  985. elif os.sys.argv[indx]=='-H' or os.sys.argv[indx]=='--header':
  986. if indx+1>=len(os.sys.argv):
  987. sys.stderr.write("%s should be followed by output header file name\n" % (os.sys.argv[indx]))
  988. help()
  989. exit_flag=1
  990. return
  991. else:
  992. header_file=os.sys.argv[indx+1]
  993. indx+=1
  994. elif os.sys.argv[indx]=='-i' or os.sys.argv[indx]=='--inline-templates':
  995. if indx+1>=len(os.sys.argv):
  996. sys.stderr.write("%s should be followed by inline value.\n" % (os.sys.argv[indx]))
  997. help()
  998. exit_flag=1
  999. return
  1000. else:
  1001. inline_templates=os.sys.argv[indx+1]
  1002. indx+=1
  1003. elif os.sys.argv[indx]=='-d':
  1004. if indx+1>=len(os.sys.argv):
  1005. sys.stderr.write("-d should followed by gettext domain name\n")
  1006. help()
  1007. exit_flag=1
  1008. return
  1009. else:
  1010. global spec_gettext
  1011. spec_gettext=os.sys.argv[indx+1]
  1012. indx+=1
  1013. elif os.sys.argv[indx]=='-u' or os.sys.argv[indx]=='--unsafe-cast':
  1014. unsafe_build = True
  1015. elif os.sys.argv[indx]=='-l' or os.sys.argv[indx]=='--no-loader':
  1016. write_loader = False
  1017. elif os.sys.argv[indx]=='--help' or os.sys.argv[indx]=='-h':
  1018. help()
  1019. exit_flag=1
  1020. return
  1021. else:
  1022. all.append(os.sys.argv[indx])
  1023. indx+=1
  1024. if not all:
  1025. sys.stderr.write("No input file names given\n")
  1026. help()
  1027. exit_flag=1
  1028. return
  1029. if inline_templates == "default":
  1030. if header_file!='':
  1031. inline_templates=False
  1032. else:
  1033. inline_templates=True
  1034. elif inline_templates == "true":
  1035. inline_templates = True
  1036. else:
  1037. inline_templates = False
  1038. global output_template
  1039. if inline_templates:
  1040. output_template = output_declaration
  1041. else:
  1042. output_template = output_definition
  1043. if header_file!='':
  1044. global header_define
  1045. global dll_api
  1046. header_define = "CPPCMS_GENERATED_HEADER_%s_TMPL_HEADER_INCLUDED" % ( re.sub("[^a-zA-Z0-9]+", "_", header_file ).upper())
  1047. if sys.version_info >= (2,5):
  1048. from hashlib import md5
  1049. else:
  1050. from md5 import md5
  1051. dll_api = 'VIEW_%s_API' % md5(header_define).hexdigest().upper()
  1052. global output_fd
  1053. if output_file!='':
  1054. output_fd=open(output_file,"w")
  1055. for file in all:
  1056. global file_name
  1057. global line_number
  1058. global inline_cpp_to
  1059. inline_cpp_to = output_declaration
  1060. line_number=0
  1061. file_name=file
  1062. f=open(file,'r')
  1063. content=f.read()
  1064. f.close()
  1065. for x in fetch_content(content):
  1066. if x=='' : continue
  1067. if len(stack)==0:
  1068. if re.match(r"^\s*$",x):
  1069. continue
  1070. elif not re.match(r"<\%.*\%>",x):
  1071. error_exit("Content is not allowed outside template blocks")
  1072. continue
  1073. matched=0
  1074. for c in [\
  1075. skin_block(), \
  1076. view_block(), \
  1077. template_block(), \
  1078. end_block(), \
  1079. if_block(), \
  1080. else_block(), \
  1081. cpp_include_block(), \
  1082. gettext_block(),ngettext_block(), \
  1083. url_block(), \
  1084. foreach_block(), item_block(), empty_block(),separator_block(), \
  1085. include_block(), \
  1086. cache_block(), \
  1087. trigger_block(), \
  1088. filter_block(), \
  1089. using_block(), \
  1090. render_block(), \
  1091. html_type(), form_block(), csrf_block(), \
  1092. domain_block(), \
  1093. filters_show_block(), error_com() ]:
  1094. basic_pattern = r'^<%\s*' + c.basic_pattern + r'.*%>$'
  1095. if re.match(basic_pattern,x):
  1096. m = re.match(c.pattern,x)
  1097. if m:
  1098. c.use(m)
  1099. else:
  1100. error_exit('Syntax error in command %s : %s' % ( c.basic_name , x))
  1101. matched=1
  1102. break;
  1103. if not matched:
  1104. inline_content(x)
  1105. if stack:
  1106. error_exit("Unexpected end of file %s" % file)
  1107. global class_list
  1108. if class_list and exit_flag==0 and write_loader:
  1109. write_class_loader(unsafe_build)
  1110. #######################
  1111. # MAIN
  1112. #######################
  1113. html_type_code='as_html'
  1114. output_file=''
  1115. header_file=''
  1116. include_directory=''
  1117. output_fd=sys.stdout
  1118. namespace_name=''
  1119. file_name=''
  1120. labels_counter=0
  1121. tmpl_seq={}
  1122. template_parameters={}
  1123. templates_map={}
  1124. parameters_counter=2
  1125. stack=[]
  1126. class_list=[]
  1127. exit_flag=0
  1128. current_template=''
  1129. spec_gettext=''
  1130. ignore_inline=1
  1131. view_created=False
  1132. scope_filter='cppcms::filters::escape'
  1133. view_name = ''
  1134. declarations = StringIO.StringIO();
  1135. definitions = StringIO.StringIO();
  1136. inline_cpp_to = output_declaration
  1137. inline_templates = "default"
  1138. output_template = output_definition
  1139. header_define = ''
  1140. dll_api = ''
  1141. ################
  1142. main()
  1143. ################
  1144. if header_file!='':
  1145. output_hfd=open(header_file,"w")
  1146. output_hfd.write("#ifndef %s\n" % ( header_define ))
  1147. output_hfd.write("#define %s\n\n" % ( header_define ))
  1148. output_hfd.write("#if defined(__WIN32) || defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__)\n")
  1149. output_hfd.write("# ifdef DLL_EXPORT\n")
  1150. output_hfd.write("# ifdef %s_SOURCE\n" % dll_api)
  1151. output_hfd.write("# define %s __declspec(dllexport)\n" % dll_api)
  1152. output_hfd.write("# else\n")
  1153. output_hfd.write("# define %s __declspec(dllimport)\n" % dll_api)
  1154. output_hfd.write("# endif\n")
  1155. output_hfd.write("# else\n")
  1156. output_hfd.write("# define %s\n" % dll_api)
  1157. output_hfd.write("# endif\n")
  1158. output_hfd.write("#else\n")
  1159. output_hfd.write("# define %s\n" % dll_api)
  1160. output_hfd.write("#endif\n")
  1161. output_hfd.write(declarations.getvalue());
  1162. output_hfd.write("#endif // %s\n" % ( header_define ))
  1163. output_hfd.close()
  1164. output_fd.write('#define %s_SOURCE\n' % dll_api);
  1165. output_fd.write('#include "%s"\n\n' % os.path.basename(header_file));
  1166. else:
  1167. output_fd.write(declarations.getvalue());
  1168. output_fd.write(definitions.getvalue());
  1169. if output_fd!=sys.stderr:
  1170. output_fd.close()
  1171. if exit_flag!=0 and output_file!='':
  1172. try:
  1173. os.unlink(output_file)
  1174. except:
  1175. pass
  1176. sys.exit(exit_flag)
  1177. # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4