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.
 
 
 
 
 
 

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