remind-rb 6.2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (658) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +328 -0
  3. data/README.md +141 -0
  4. data/ext/remind/shim.c +379 -0
  5. data/lib/remind/builder.rb +252 -0
  6. data/lib/remind/library.rb +141 -0
  7. data/lib/remind/native.rb +257 -0
  8. data/lib/remind/reminder.rb +527 -0
  9. data/lib/remind/runtime.rb +130 -0
  10. data/lib/remind/session.rb +246 -0
  11. data/lib/remind/source.rb +160 -0
  12. data/lib/remind/value.rb +170 -0
  13. data/lib/remind/version.rb +13 -0
  14. data/lib/remind.rb +147 -0
  15. data/remind-v06.02.10/COPYRIGHT +300 -0
  16. data/remind-v06.02.10/configure +5684 -0
  17. data/remind-v06.02.10/configure.ac +131 -0
  18. data/remind-v06.02.10/docs/WHATSNEW +3858 -0
  19. data/remind-v06.02.10/include/ansitext.rem +35 -0
  20. data/remind-v06.02.10/include/holidays/ad/02.rem +15 -0
  21. data/remind-v06.02.10/include/holidays/ad/03.rem +14 -0
  22. data/remind-v06.02.10/include/holidays/ad/04.rem +14 -0
  23. data/remind-v06.02.10/include/holidays/ad/05.rem +14 -0
  24. data/remind-v06.02.10/include/holidays/ad/06.rem +16 -0
  25. data/remind-v06.02.10/include/holidays/ad/07.rem +15 -0
  26. data/remind-v06.02.10/include/holidays/ad/08.rem +14 -0
  27. data/remind-v06.02.10/include/holidays/ad.rem +28 -0
  28. data/remind-v06.02.10/include/holidays/ae.rem +10 -0
  29. data/remind-v06.02.10/include/holidays/al.rem +33 -0
  30. data/remind-v06.02.10/include/holidays/am.rem +19 -0
  31. data/remind-v06.02.10/include/holidays/ao.rem +41 -0
  32. data/remind-v06.02.10/include/holidays/ar.rem +38 -0
  33. data/remind-v06.02.10/include/holidays/as.rem +40 -0
  34. data/remind-v06.02.10/include/holidays/at/1.rem +15 -0
  35. data/remind-v06.02.10/include/holidays/at/2.rem +16 -0
  36. data/remind-v06.02.10/include/holidays/at/3.rem +15 -0
  37. data/remind-v06.02.10/include/holidays/at/4.rem +15 -0
  38. data/remind-v06.02.10/include/holidays/at/5.rem +15 -0
  39. data/remind-v06.02.10/include/holidays/at/6.rem +15 -0
  40. data/remind-v06.02.10/include/holidays/at/7.rem +15 -0
  41. data/remind-v06.02.10/include/holidays/at/8.rem +15 -0
  42. data/remind-v06.02.10/include/holidays/at/9.rem +15 -0
  43. data/remind-v06.02.10/include/holidays/at.rem +32 -0
  44. data/remind-v06.02.10/include/holidays/au/act.rem +27 -0
  45. data/remind-v06.02.10/include/holidays/au/nsw.rem +25 -0
  46. data/remind-v06.02.10/include/holidays/au/nt.rem +28 -0
  47. data/remind-v06.02.10/include/holidays/au/qld.rem +23 -0
  48. data/remind-v06.02.10/include/holidays/au/sa.rem +29 -0
  49. data/remind-v06.02.10/include/holidays/au/tas.rem +16 -0
  50. data/remind-v06.02.10/include/holidays/au/vic.rem +24 -0
  51. data/remind-v06.02.10/include/holidays/au/wa.rem +24 -0
  52. data/remind-v06.02.10/include/holidays/au.rem +21 -0
  53. data/remind-v06.02.10/include/holidays/aw.rem +19 -0
  54. data/remind-v06.02.10/include/holidays/az.rem +44 -0
  55. data/remind-v06.02.10/include/holidays/ba/bih.rem +23 -0
  56. data/remind-v06.02.10/include/holidays/ba/brc.rem +20 -0
  57. data/remind-v06.02.10/include/holidays/ba/srp.rem +23 -0
  58. data/remind-v06.02.10/include/holidays/ba.rem +22 -0
  59. data/remind-v06.02.10/include/holidays/bb.rem +28 -0
  60. data/remind-v06.02.10/include/holidays/bd.rem +14 -0
  61. data/remind-v06.02.10/include/holidays/be.rem +24 -0
  62. data/remind-v06.02.10/include/holidays/bf.rem +29 -0
  63. data/remind-v06.02.10/include/holidays/bg.rem +34 -0
  64. data/remind-v06.02.10/include/holidays/bh.rem +11 -0
  65. data/remind-v06.02.10/include/holidays/bi.rem +30 -0
  66. data/remind-v06.02.10/include/holidays/bn.rem +22 -0
  67. data/remind-v06.02.10/include/holidays/bo/b.rem +13 -0
  68. data/remind-v06.02.10/include/holidays/bo/c.rem +13 -0
  69. data/remind-v06.02.10/include/holidays/bo/h.rem +13 -0
  70. data/remind-v06.02.10/include/holidays/bo/l.rem +13 -0
  71. data/remind-v06.02.10/include/holidays/bo/n.rem +13 -0
  72. data/remind-v06.02.10/include/holidays/bo/o.rem +13 -0
  73. data/remind-v06.02.10/include/holidays/bo/p.rem +13 -0
  74. data/remind-v06.02.10/include/holidays/bo/s.rem +13 -0
  75. data/remind-v06.02.10/include/holidays/bo/t.rem +13 -0
  76. data/remind-v06.02.10/include/holidays/bo.rem +32 -0
  77. data/remind-v06.02.10/include/holidays/br/ac.rem +21 -0
  78. data/remind-v06.02.10/include/holidays/br/al.rem +16 -0
  79. data/remind-v06.02.10/include/holidays/br/am.rem +13 -0
  80. data/remind-v06.02.10/include/holidays/br/ap.rem +15 -0
  81. data/remind-v06.02.10/include/holidays/br/ba.rem +13 -0
  82. data/remind-v06.02.10/include/holidays/br/ce.rem +15 -0
  83. data/remind-v06.02.10/include/holidays/br/df.rem +14 -0
  84. data/remind-v06.02.10/include/holidays/br/es.rem +13 -0
  85. data/remind-v06.02.10/include/holidays/br/go.rem +14 -0
  86. data/remind-v06.02.10/include/holidays/br/ma.rem +13 -0
  87. data/remind-v06.02.10/include/holidays/br/mg.rem +13 -0
  88. data/remind-v06.02.10/include/holidays/br/ms.rem +13 -0
  89. data/remind-v06.02.10/include/holidays/br/pa.rem +13 -0
  90. data/remind-v06.02.10/include/holidays/br/pb.rem +13 -0
  91. data/remind-v06.02.10/include/holidays/br/pe.rem +13 -0
  92. data/remind-v06.02.10/include/holidays/br/pi.rem +13 -0
  93. data/remind-v06.02.10/include/holidays/br/pr.rem +13 -0
  94. data/remind-v06.02.10/include/holidays/br/rj.rem +13 -0
  95. data/remind-v06.02.10/include/holidays/br/rn.rem +14 -0
  96. data/remind-v06.02.10/include/holidays/br/ro.rem +14 -0
  97. data/remind-v06.02.10/include/holidays/br/rr.rem +13 -0
  98. data/remind-v06.02.10/include/holidays/br/rs.rem +13 -0
  99. data/remind-v06.02.10/include/holidays/br/sc.rem +14 -0
  100. data/remind-v06.02.10/include/holidays/br/se.rem +13 -0
  101. data/remind-v06.02.10/include/holidays/br/sp.rem +13 -0
  102. data/remind-v06.02.10/include/holidays/br/to.rem +15 -0
  103. data/remind-v06.02.10/include/holidays/br.rem +33 -0
  104. data/remind-v06.02.10/include/holidays/bs.rem +26 -0
  105. data/remind-v06.02.10/include/holidays/bw.rem +31 -0
  106. data/remind-v06.02.10/include/holidays/by.rem +17 -0
  107. data/remind-v06.02.10/include/holidays/bz.rem +43 -0
  108. data/remind-v06.02.10/include/holidays/ca/ab.rem +17 -0
  109. data/remind-v06.02.10/include/holidays/ca/bc.rem +14 -0
  110. data/remind-v06.02.10/include/holidays/ca/mb.rem +16 -0
  111. data/remind-v06.02.10/include/holidays/ca/nb.rem +14 -0
  112. data/remind-v06.02.10/include/holidays/ca/nl.rem +19 -0
  113. data/remind-v06.02.10/include/holidays/ca/ns.rem +16 -0
  114. data/remind-v06.02.10/include/holidays/ca/nt.rem +14 -0
  115. data/remind-v06.02.10/include/holidays/ca/nu.rem +16 -0
  116. data/remind-v06.02.10/include/holidays/ca/on.rem +16 -0
  117. data/remind-v06.02.10/include/holidays/ca/pe.rem +13 -0
  118. data/remind-v06.02.10/include/holidays/ca/qc.rem +18 -0
  119. data/remind-v06.02.10/include/holidays/ca/sk.rem +14 -0
  120. data/remind-v06.02.10/include/holidays/ca/yt.rem +17 -0
  121. data/remind-v06.02.10/include/holidays/ca.rem +37 -0
  122. data/remind-v06.02.10/include/holidays/cg.rem +17 -0
  123. data/remind-v06.02.10/include/holidays/ch/ag.rem +22 -0
  124. data/remind-v06.02.10/include/holidays/ch/ai.rem +20 -0
  125. data/remind-v06.02.10/include/holidays/ch/ar.rem +16 -0
  126. data/remind-v06.02.10/include/holidays/ch/be.rem +17 -0
  127. data/remind-v06.02.10/include/holidays/ch/bl.rem +17 -0
  128. data/remind-v06.02.10/include/holidays/ch/bs.rem +17 -0
  129. data/remind-v06.02.10/include/holidays/ch/fr.rem +19 -0
  130. data/remind-v06.02.10/include/holidays/ch/ge.rem +17 -0
  131. data/remind-v06.02.10/include/holidays/ch/gl.rem +22 -0
  132. data/remind-v06.02.10/include/holidays/ch/gr.rem +18 -0
  133. data/remind-v06.02.10/include/holidays/ch/ju.rem +21 -0
  134. data/remind-v06.02.10/include/holidays/ch/lu.rem +21 -0
  135. data/remind-v06.02.10/include/holidays/ch/ne.rem +18 -0
  136. data/remind-v06.02.10/include/holidays/ch/nw.rem +24 -0
  137. data/remind-v06.02.10/include/holidays/ch/ow.rem +24 -0
  138. data/remind-v06.02.10/include/holidays/ch/sg.rem +20 -0
  139. data/remind-v06.02.10/include/holidays/ch/sh.rem +20 -0
  140. data/remind-v06.02.10/include/holidays/ch/so.rem +17 -0
  141. data/remind-v06.02.10/include/holidays/ch/sz.rem +22 -0
  142. data/remind-v06.02.10/include/holidays/ch/tg.rem +18 -0
  143. data/remind-v06.02.10/include/holidays/ch/ti.rem +23 -0
  144. data/remind-v06.02.10/include/holidays/ch/ur.rem +22 -0
  145. data/remind-v06.02.10/include/holidays/ch/vd.rem +17 -0
  146. data/remind-v06.02.10/include/holidays/ch/vs.rem +23 -0
  147. data/remind-v06.02.10/include/holidays/ch/zg.rem +23 -0
  148. data/remind-v06.02.10/include/holidays/ch/zh.rem +18 -0
  149. data/remind-v06.02.10/include/holidays/ch.rem +18 -0
  150. data/remind-v06.02.10/include/holidays/chinese-new-year.rem +86 -0
  151. data/remind-v06.02.10/include/holidays/cl/ap.rem +13 -0
  152. data/remind-v06.02.10/include/holidays/cl/nb.rem +13 -0
  153. data/remind-v06.02.10/include/holidays/cl.rem +46 -0
  154. data/remind-v06.02.10/include/holidays/cm.rem +21 -0
  155. data/remind-v06.02.10/include/holidays/co.rem +85 -0
  156. data/remind-v06.02.10/include/holidays/cr.rem +39 -0
  157. data/remind-v06.02.10/include/holidays/cu.rem +19 -0
  158. data/remind-v06.02.10/include/holidays/cw.rem +24 -0
  159. data/remind-v06.02.10/include/holidays/cy.rem +27 -0
  160. data/remind-v06.02.10/include/holidays/cz.rem +20 -0
  161. data/remind-v06.02.10/include/holidays/de/bb.rem +15 -0
  162. data/remind-v06.02.10/include/holidays/de/be.rem +13 -0
  163. data/remind-v06.02.10/include/holidays/de/bw.rem +15 -0
  164. data/remind-v06.02.10/include/holidays/de/by.rem +18 -0
  165. data/remind-v06.02.10/include/holidays/de/hb.rem +13 -0
  166. data/remind-v06.02.10/include/holidays/de/he.rem +13 -0
  167. data/remind-v06.02.10/include/holidays/de/hh.rem +13 -0
  168. data/remind-v06.02.10/include/holidays/de/mv.rem +14 -0
  169. data/remind-v06.02.10/include/holidays/de/ni.rem +13 -0
  170. data/remind-v06.02.10/include/holidays/de/nw.rem +14 -0
  171. data/remind-v06.02.10/include/holidays/de/rp.rem +14 -0
  172. data/remind-v06.02.10/include/holidays/de/sh.rem +13 -0
  173. data/remind-v06.02.10/include/holidays/de/sl.rem +15 -0
  174. data/remind-v06.02.10/include/holidays/de/sn.rem +14 -0
  175. data/remind-v06.02.10/include/holidays/de/st.rem +14 -0
  176. data/remind-v06.02.10/include/holidays/de/th.rem +14 -0
  177. data/remind-v06.02.10/include/holidays/de.rem +23 -0
  178. data/remind-v06.02.10/include/holidays/discordian.rem +25 -0
  179. data/remind-v06.02.10/include/holidays/dj.rem +12 -0
  180. data/remind-v06.02.10/include/holidays/dk.rem +23 -0
  181. data/remind-v06.02.10/include/holidays/dm.rem +24 -0
  182. data/remind-v06.02.10/include/holidays/do.rem +36 -0
  183. data/remind-v06.02.10/include/holidays/dz.rem +12 -0
  184. data/remind-v06.02.10/include/holidays/ec.rem +48 -0
  185. data/remind-v06.02.10/include/holidays/ee.rem +19 -0
  186. data/remind-v06.02.10/include/holidays/eg.rem +17 -0
  187. data/remind-v06.02.10/include/holidays/es/an.rem +17 -0
  188. data/remind-v06.02.10/include/holidays/es/ar.rem +17 -0
  189. data/remind-v06.02.10/include/holidays/es/as.rem +17 -0
  190. data/remind-v06.02.10/include/holidays/es/cb.rem +15 -0
  191. data/remind-v06.02.10/include/holidays/es/ce.rem +15 -0
  192. data/remind-v06.02.10/include/holidays/es/cl.rem +17 -0
  193. data/remind-v06.02.10/include/holidays/es/cm.rem +15 -0
  194. data/remind-v06.02.10/include/holidays/es/cn.rem +15 -0
  195. data/remind-v06.02.10/include/holidays/es/ct.rem +16 -0
  196. data/remind-v06.02.10/include/holidays/es/ex.rem +16 -0
  197. data/remind-v06.02.10/include/holidays/es/ga.rem +15 -0
  198. data/remind-v06.02.10/include/holidays/es/ib.rem +15 -0
  199. data/remind-v06.02.10/include/holidays/es/mc.rem +17 -0
  200. data/remind-v06.02.10/include/holidays/es/md.rem +16 -0
  201. data/remind-v06.02.10/include/holidays/es/ml.rem +15 -0
  202. data/remind-v06.02.10/include/holidays/es/nc.rem +15 -0
  203. data/remind-v06.02.10/include/holidays/es/pv.rem +15 -0
  204. data/remind-v06.02.10/include/holidays/es/ri.rem +16 -0
  205. data/remind-v06.02.10/include/holidays/es/vc.rem +16 -0
  206. data/remind-v06.02.10/include/holidays/es.rem +23 -0
  207. data/remind-v06.02.10/include/holidays/et.rem +20 -0
  208. data/remind-v06.02.10/include/holidays/fi.rem +43 -0
  209. data/remind-v06.02.10/include/holidays/fr/bl.rem +13 -0
  210. data/remind-v06.02.10/include/holidays/fr/ges.rem +14 -0
  211. data/remind-v06.02.10/include/holidays/fr/gp.rem +16 -0
  212. data/remind-v06.02.10/include/holidays/fr/gy.rem +13 -0
  213. data/remind-v06.02.10/include/holidays/fr/mf.rem +13 -0
  214. data/remind-v06.02.10/include/holidays/fr/mq.rem +15 -0
  215. data/remind-v06.02.10/include/holidays/fr/nc.rem +13 -0
  216. data/remind-v06.02.10/include/holidays/fr/pf.rem +15 -0
  217. data/remind-v06.02.10/include/holidays/fr/re.rem +13 -0
  218. data/remind-v06.02.10/include/holidays/fr/wf.rem +14 -0
  219. data/remind-v06.02.10/include/holidays/fr/yt.rem +13 -0
  220. data/remind-v06.02.10/include/holidays/fr.rem +18 -0
  221. data/remind-v06.02.10/include/holidays/ga.rem +18 -0
  222. data/remind-v06.02.10/include/holidays/gb/eng.rem +14 -0
  223. data/remind-v06.02.10/include/holidays/gb/nir.rem +20 -0
  224. data/remind-v06.02.10/include/holidays/gb/sct.rem +20 -0
  225. data/remind-v06.02.10/include/holidays/gb/wls.rem +14 -0
  226. data/remind-v06.02.10/include/holidays/gb.rem +27 -0
  227. data/remind-v06.02.10/include/holidays/ge.rem +24 -0
  228. data/remind-v06.02.10/include/holidays/gh.rem +34 -0
  229. data/remind-v06.02.10/include/holidays/gl.rem +25 -0
  230. data/remind-v06.02.10/include/holidays/gr.rem +37 -0
  231. data/remind-v06.02.10/include/holidays/gt.rem +24 -0
  232. data/remind-v06.02.10/include/holidays/gu.rem +37 -0
  233. data/remind-v06.02.10/include/holidays/hk.rem +25 -0
  234. data/remind-v06.02.10/include/holidays/hn.rem +18 -0
  235. data/remind-v06.02.10/include/holidays/hr.rem +21 -0
  236. data/remind-v06.02.10/include/holidays/ht.rem +34 -0
  237. data/remind-v06.02.10/include/holidays/hu.rem +20 -0
  238. data/remind-v06.02.10/include/holidays/id.rem +15 -0
  239. data/remind-v06.02.10/include/holidays/ie.rem +41 -0
  240. data/remind-v06.02.10/include/holidays/im.rem +26 -0
  241. data/remind-v06.02.10/include/holidays/in/ap.rem +14 -0
  242. data/remind-v06.02.10/include/holidays/in/as.rem +13 -0
  243. data/remind-v06.02.10/include/holidays/in/br.rem +14 -0
  244. data/remind-v06.02.10/include/holidays/in/cg.rem +13 -0
  245. data/remind-v06.02.10/include/holidays/in/gj.rem +15 -0
  246. data/remind-v06.02.10/include/holidays/in/hr.rem +14 -0
  247. data/remind-v06.02.10/include/holidays/in/ka.rem +13 -0
  248. data/remind-v06.02.10/include/holidays/in/kl.rem +14 -0
  249. data/remind-v06.02.10/include/holidays/in/mh.rem +15 -0
  250. data/remind-v06.02.10/include/holidays/in/mp.rem +13 -0
  251. data/remind-v06.02.10/include/holidays/in/od.rem +15 -0
  252. data/remind-v06.02.10/include/holidays/in/rj.rem +14 -0
  253. data/remind-v06.02.10/include/holidays/in/sk.rem +13 -0
  254. data/remind-v06.02.10/include/holidays/in/tn.rem +15 -0
  255. data/remind-v06.02.10/include/holidays/in/ts.rem +14 -0
  256. data/remind-v06.02.10/include/holidays/in/uk.rem +13 -0
  257. data/remind-v06.02.10/include/holidays/in/up.rem +13 -0
  258. data/remind-v06.02.10/include/holidays/in/wb.rem +16 -0
  259. data/remind-v06.02.10/include/holidays/in.rem +24 -0
  260. data/remind-v06.02.10/include/holidays/is.rem +23 -0
  261. data/remind-v06.02.10/include/holidays/it/ag.rem +13 -0
  262. data/remind-v06.02.10/include/holidays/it/al.rem +13 -0
  263. data/remind-v06.02.10/include/holidays/it/an.rem +13 -0
  264. data/remind-v06.02.10/include/holidays/it/andria.rem +13 -0
  265. data/remind-v06.02.10/include/holidays/it/ao.rem +13 -0
  266. data/remind-v06.02.10/include/holidays/it/ap.rem +13 -0
  267. data/remind-v06.02.10/include/holidays/it/aq.rem +13 -0
  268. data/remind-v06.02.10/include/holidays/it/ar.rem +13 -0
  269. data/remind-v06.02.10/include/holidays/it/at.rem +13 -0
  270. data/remind-v06.02.10/include/holidays/it/av.rem +13 -0
  271. data/remind-v06.02.10/include/holidays/it/ba.rem +13 -0
  272. data/remind-v06.02.10/include/holidays/it/barletta.rem +13 -0
  273. data/remind-v06.02.10/include/holidays/it/bg.rem +13 -0
  274. data/remind-v06.02.10/include/holidays/it/bl.rem +13 -0
  275. data/remind-v06.02.10/include/holidays/it/bn.rem +13 -0
  276. data/remind-v06.02.10/include/holidays/it/bo.rem +13 -0
  277. data/remind-v06.02.10/include/holidays/it/br.rem +13 -0
  278. data/remind-v06.02.10/include/holidays/it/bs.rem +13 -0
  279. data/remind-v06.02.10/include/holidays/it/bt.rem +15 -0
  280. data/remind-v06.02.10/include/holidays/it/bz.rem +14 -0
  281. data/remind-v06.02.10/include/holidays/it/ca.rem +13 -0
  282. data/remind-v06.02.10/include/holidays/it/cb.rem +13 -0
  283. data/remind-v06.02.10/include/holidays/it/ce.rem +13 -0
  284. data/remind-v06.02.10/include/holidays/it/cesena.rem +13 -0
  285. data/remind-v06.02.10/include/holidays/it/ch.rem +13 -0
  286. data/remind-v06.02.10/include/holidays/it/cl.rem +13 -0
  287. data/remind-v06.02.10/include/holidays/it/cn.rem +13 -0
  288. data/remind-v06.02.10/include/holidays/it/co.rem +13 -0
  289. data/remind-v06.02.10/include/holidays/it/cr.rem +13 -0
  290. data/remind-v06.02.10/include/holidays/it/cs.rem +13 -0
  291. data/remind-v06.02.10/include/holidays/it/ct.rem +13 -0
  292. data/remind-v06.02.10/include/holidays/it/cz.rem +13 -0
  293. data/remind-v06.02.10/include/holidays/it/en.rem +13 -0
  294. data/remind-v06.02.10/include/holidays/it/fc.rem +14 -0
  295. data/remind-v06.02.10/include/holidays/it/fe.rem +13 -0
  296. data/remind-v06.02.10/include/holidays/it/fg.rem +13 -0
  297. data/remind-v06.02.10/include/holidays/it/fi.rem +13 -0
  298. data/remind-v06.02.10/include/holidays/it/fm.rem +14 -0
  299. data/remind-v06.02.10/include/holidays/it/forli.rem +13 -0
  300. data/remind-v06.02.10/include/holidays/it/fr.rem +13 -0
  301. data/remind-v06.02.10/include/holidays/it/ge.rem +13 -0
  302. data/remind-v06.02.10/include/holidays/it/go.rem +13 -0
  303. data/remind-v06.02.10/include/holidays/it/gr.rem +13 -0
  304. data/remind-v06.02.10/include/holidays/it/im.rem +13 -0
  305. data/remind-v06.02.10/include/holidays/it/is.rem +13 -0
  306. data/remind-v06.02.10/include/holidays/it/kr.rem +13 -0
  307. data/remind-v06.02.10/include/holidays/it/lc.rem +13 -0
  308. data/remind-v06.02.10/include/holidays/it/le.rem +13 -0
  309. data/remind-v06.02.10/include/holidays/it/li.rem +13 -0
  310. data/remind-v06.02.10/include/holidays/it/lo.rem +13 -0
  311. data/remind-v06.02.10/include/holidays/it/lt.rem +14 -0
  312. data/remind-v06.02.10/include/holidays/it/lu.rem +13 -0
  313. data/remind-v06.02.10/include/holidays/it/mb.rem +13 -0
  314. data/remind-v06.02.10/include/holidays/it/mc.rem +13 -0
  315. data/remind-v06.02.10/include/holidays/it/me.rem +13 -0
  316. data/remind-v06.02.10/include/holidays/it/mi.rem +13 -0
  317. data/remind-v06.02.10/include/holidays/it/mn.rem +13 -0
  318. data/remind-v06.02.10/include/holidays/it/mo.rem +13 -0
  319. data/remind-v06.02.10/include/holidays/it/ms.rem +13 -0
  320. data/remind-v06.02.10/include/holidays/it/mt.rem +13 -0
  321. data/remind-v06.02.10/include/holidays/it/na.rem +13 -0
  322. data/remind-v06.02.10/include/holidays/it/no.rem +13 -0
  323. data/remind-v06.02.10/include/holidays/it/nu.rem +13 -0
  324. data/remind-v06.02.10/include/holidays/it/or.rem +13 -0
  325. data/remind-v06.02.10/include/holidays/it/pa.rem +13 -0
  326. data/remind-v06.02.10/include/holidays/it/pc.rem +13 -0
  327. data/remind-v06.02.10/include/holidays/it/pd.rem +13 -0
  328. data/remind-v06.02.10/include/holidays/it/pe.rem +13 -0
  329. data/remind-v06.02.10/include/holidays/it/pesaro.rem +13 -0
  330. data/remind-v06.02.10/include/holidays/it/pg.rem +14 -0
  331. data/remind-v06.02.10/include/holidays/it/pi.rem +13 -0
  332. data/remind-v06.02.10/include/holidays/it/pn.rem +14 -0
  333. data/remind-v06.02.10/include/holidays/it/pr.rem +13 -0
  334. data/remind-v06.02.10/include/holidays/it/pt.rem +13 -0
  335. data/remind-v06.02.10/include/holidays/it/pu.rem +14 -0
  336. data/remind-v06.02.10/include/holidays/it/pv.rem +13 -0
  337. data/remind-v06.02.10/include/holidays/it/pz.rem +13 -0
  338. data/remind-v06.02.10/include/holidays/it/ra.rem +13 -0
  339. data/remind-v06.02.10/include/holidays/it/rc.rem +13 -0
  340. data/remind-v06.02.10/include/holidays/it/re.rem +13 -0
  341. data/remind-v06.02.10/include/holidays/it/rg.rem +14 -0
  342. data/remind-v06.02.10/include/holidays/it/ri.rem +13 -0
  343. data/remind-v06.02.10/include/holidays/it/rm.rem +13 -0
  344. data/remind-v06.02.10/include/holidays/it/rn.rem +13 -0
  345. data/remind-v06.02.10/include/holidays/it/ro.rem +13 -0
  346. data/remind-v06.02.10/include/holidays/it/sa.rem +13 -0
  347. data/remind-v06.02.10/include/holidays/it/si.rem +13 -0
  348. data/remind-v06.02.10/include/holidays/it/so.rem +13 -0
  349. data/remind-v06.02.10/include/holidays/it/sp.rem +13 -0
  350. data/remind-v06.02.10/include/holidays/it/sr.rem +13 -0
  351. data/remind-v06.02.10/include/holidays/it/ss.rem +13 -0
  352. data/remind-v06.02.10/include/holidays/it/su.rem +13 -0
  353. data/remind-v06.02.10/include/holidays/it/sv.rem +13 -0
  354. data/remind-v06.02.10/include/holidays/it/ta.rem +13 -0
  355. data/remind-v06.02.10/include/holidays/it/te.rem +13 -0
  356. data/remind-v06.02.10/include/holidays/it/tn.rem +13 -0
  357. data/remind-v06.02.10/include/holidays/it/to.rem +13 -0
  358. data/remind-v06.02.10/include/holidays/it/tp.rem +13 -0
  359. data/remind-v06.02.10/include/holidays/it/tr.rem +13 -0
  360. data/remind-v06.02.10/include/holidays/it/trani.rem +13 -0
  361. data/remind-v06.02.10/include/holidays/it/ts.rem +13 -0
  362. data/remind-v06.02.10/include/holidays/it/tv.rem +13 -0
  363. data/remind-v06.02.10/include/holidays/it/ud.rem +13 -0
  364. data/remind-v06.02.10/include/holidays/it/urbino.rem +13 -0
  365. data/remind-v06.02.10/include/holidays/it/va.rem +13 -0
  366. data/remind-v06.02.10/include/holidays/it/vb.rem +13 -0
  367. data/remind-v06.02.10/include/holidays/it/vc.rem +13 -0
  368. data/remind-v06.02.10/include/holidays/it/ve.rem +14 -0
  369. data/remind-v06.02.10/include/holidays/it/vi.rem +13 -0
  370. data/remind-v06.02.10/include/holidays/it/vr.rem +13 -0
  371. data/remind-v06.02.10/include/holidays/it/vt.rem +13 -0
  372. data/remind-v06.02.10/include/holidays/it/vv.rem +13 -0
  373. data/remind-v06.02.10/include/holidays/it.rem +26 -0
  374. data/remind-v06.02.10/include/holidays/je.rem +19 -0
  375. data/remind-v06.02.10/include/holidays/jewish.rem +135 -0
  376. data/remind-v06.02.10/include/holidays/jm.rem +24 -0
  377. data/remind-v06.02.10/include/holidays/jo.rem +11 -0
  378. data/remind-v06.02.10/include/holidays/jp.rem +27 -0
  379. data/remind-v06.02.10/include/holidays/ke.rem +25 -0
  380. data/remind-v06.02.10/include/holidays/kg.rem +20 -0
  381. data/remind-v06.02.10/include/holidays/kh.rem +22 -0
  382. data/remind-v06.02.10/include/holidays/kn.rem +28 -0
  383. data/remind-v06.02.10/include/holidays/kr.rem +19 -0
  384. data/remind-v06.02.10/include/holidays/kw.rem +10 -0
  385. data/remind-v06.02.10/include/holidays/kz.rem +34 -0
  386. data/remind-v06.02.10/include/holidays/la.rem +47 -0
  387. data/remind-v06.02.10/include/holidays/lgbtq/au.rem +8 -0
  388. data/remind-v06.02.10/include/holidays/lgbtq/br.rem +10 -0
  389. data/remind-v06.02.10/include/holidays/lgbtq/ca.rem +7 -0
  390. data/remind-v06.02.10/include/holidays/lgbtq/cl.rem +7 -0
  391. data/remind-v06.02.10/include/holidays/lgbtq/ie.rem +7 -0
  392. data/remind-v06.02.10/include/holidays/lgbtq/in.rem +7 -0
  393. data/remind-v06.02.10/include/holidays/lgbtq/nl.rem +7 -0
  394. data/remind-v06.02.10/include/holidays/lgbtq/ua.rem +7 -0
  395. data/remind-v06.02.10/include/holidays/lgbtq/uk.rem +8 -0
  396. data/remind-v06.02.10/include/holidays/lgbtq/us.rem +16 -0
  397. data/remind-v06.02.10/include/holidays/lgbtq.rem +34 -0
  398. data/remind-v06.02.10/include/holidays/li.rem +31 -0
  399. data/remind-v06.02.10/include/holidays/ls.rem +18 -0
  400. data/remind-v06.02.10/include/holidays/lt.rem +23 -0
  401. data/remind-v06.02.10/include/holidays/lu.rem +18 -0
  402. data/remind-v06.02.10/include/holidays/lv.rem +25 -0
  403. data/remind-v06.02.10/include/holidays/ma.rem +17 -0
  404. data/remind-v06.02.10/include/holidays/mc.rem +26 -0
  405. data/remind-v06.02.10/include/holidays/md.rem +21 -0
  406. data/remind-v06.02.10/include/holidays/me.rem +28 -0
  407. data/remind-v06.02.10/include/holidays/mg.rem +24 -0
  408. data/remind-v06.02.10/include/holidays/mh.rem +22 -0
  409. data/remind-v06.02.10/include/holidays/misc.rem +9 -0
  410. data/remind-v06.02.10/include/holidays/mk.rem +17 -0
  411. data/remind-v06.02.10/include/holidays/mp.rem +44 -0
  412. data/remind-v06.02.10/include/holidays/mr.rem +11 -0
  413. data/remind-v06.02.10/include/holidays/mt.rem +21 -0
  414. data/remind-v06.02.10/include/holidays/mv.rem +12 -0
  415. data/remind-v06.02.10/include/holidays/mw.rem +36 -0
  416. data/remind-v06.02.10/include/holidays/mx.rem +15 -0
  417. data/remind-v06.02.10/include/holidays/my/01.rem +13 -0
  418. data/remind-v06.02.10/include/holidays/my/02.rem +13 -0
  419. data/remind-v06.02.10/include/holidays/my/03.rem +14 -0
  420. data/remind-v06.02.10/include/holidays/my/04.rem +18 -0
  421. data/remind-v06.02.10/include/holidays/my/05.rem +16 -0
  422. data/remind-v06.02.10/include/holidays/my/06.rem +17 -0
  423. data/remind-v06.02.10/include/holidays/my/07.rem +17 -0
  424. data/remind-v06.02.10/include/holidays/my/08.rem +15 -0
  425. data/remind-v06.02.10/include/holidays/my/09.rem +14 -0
  426. data/remind-v06.02.10/include/holidays/my/10.rem +16 -0
  427. data/remind-v06.02.10/include/holidays/my/11.rem +16 -0
  428. data/remind-v06.02.10/include/holidays/my/12.rem +19 -0
  429. data/remind-v06.02.10/include/holidays/my/13.rem +22 -0
  430. data/remind-v06.02.10/include/holidays/my/14.rem +16 -0
  431. data/remind-v06.02.10/include/holidays/my/15.rem +18 -0
  432. data/remind-v06.02.10/include/holidays/my/16.rem +16 -0
  433. data/remind-v06.02.10/include/holidays/my.rem +23 -0
  434. data/remind-v06.02.10/include/holidays/mz.rem +25 -0
  435. data/remind-v06.02.10/include/holidays/na.rem +27 -0
  436. data/remind-v06.02.10/include/holidays/ng.rem +21 -0
  437. data/remind-v06.02.10/include/holidays/ni/mn.rem +14 -0
  438. data/remind-v06.02.10/include/holidays/ni.rem +24 -0
  439. data/remind-v06.02.10/include/holidays/nl.rem +26 -0
  440. data/remind-v06.02.10/include/holidays/no.rem +19 -0
  441. data/remind-v06.02.10/include/holidays/nz/auk.rem +13 -0
  442. data/remind-v06.02.10/include/holidays/nz/can.rem +13 -0
  443. data/remind-v06.02.10/include/holidays/nz/cit.rem +13 -0
  444. data/remind-v06.02.10/include/holidays/nz/hkb.rem +13 -0
  445. data/remind-v06.02.10/include/holidays/nz/mbh.rem +13 -0
  446. data/remind-v06.02.10/include/holidays/nz/nsn.rem +13 -0
  447. data/remind-v06.02.10/include/holidays/nz/ntl.rem +13 -0
  448. data/remind-v06.02.10/include/holidays/nz/ota.rem +14 -0
  449. data/remind-v06.02.10/include/holidays/nz/south_canterbury.rem +13 -0
  450. data/remind-v06.02.10/include/holidays/nz/stl.rem +13 -0
  451. data/remind-v06.02.10/include/holidays/nz/tki.rem +13 -0
  452. data/remind-v06.02.10/include/holidays/nz/wgn.rem +13 -0
  453. data/remind-v06.02.10/include/holidays/nz/wtc.rem +13 -0
  454. data/remind-v06.02.10/include/holidays/nz.rem +69 -0
  455. data/remind-v06.02.10/include/holidays/pa.rem +27 -0
  456. data/remind-v06.02.10/include/holidays/pagan.rem +65 -0
  457. data/remind-v06.02.10/include/holidays/pe.rem +22 -0
  458. data/remind-v06.02.10/include/holidays/pg.rem +24 -0
  459. data/remind-v06.02.10/include/holidays/ph.rem +26 -0
  460. data/remind-v06.02.10/include/holidays/pk.rem +13 -0
  461. data/remind-v06.02.10/include/holidays/pl.rem +20 -0
  462. data/remind-v06.02.10/include/holidays/pr.rem +40 -0
  463. data/remind-v06.02.10/include/holidays/pt/01.rem +13 -0
  464. data/remind-v06.02.10/include/holidays/pt/02.rem +13 -0
  465. data/remind-v06.02.10/include/holidays/pt/03.rem +13 -0
  466. data/remind-v06.02.10/include/holidays/pt/04.rem +13 -0
  467. data/remind-v06.02.10/include/holidays/pt/05.rem +13 -0
  468. data/remind-v06.02.10/include/holidays/pt/06.rem +13 -0
  469. data/remind-v06.02.10/include/holidays/pt/07.rem +13 -0
  470. data/remind-v06.02.10/include/holidays/pt/08.rem +13 -0
  471. data/remind-v06.02.10/include/holidays/pt/09.rem +13 -0
  472. data/remind-v06.02.10/include/holidays/pt/10.rem +13 -0
  473. data/remind-v06.02.10/include/holidays/pt/12.rem +13 -0
  474. data/remind-v06.02.10/include/holidays/pt/13.rem +13 -0
  475. data/remind-v06.02.10/include/holidays/pt/14.rem +13 -0
  476. data/remind-v06.02.10/include/holidays/pt/15.rem +13 -0
  477. data/remind-v06.02.10/include/holidays/pt/16.rem +13 -0
  478. data/remind-v06.02.10/include/holidays/pt/18.rem +13 -0
  479. data/remind-v06.02.10/include/holidays/pt/20.rem +13 -0
  480. data/remind-v06.02.10/include/holidays/pt/30.rem +14 -0
  481. data/remind-v06.02.10/include/holidays/pt.rem +17 -0
  482. data/remind-v06.02.10/include/holidays/pw.rem +34 -0
  483. data/remind-v06.02.10/include/holidays/py.rem +20 -0
  484. data/remind-v06.02.10/include/holidays/ro.rem +24 -0
  485. data/remind-v06.02.10/include/holidays/rs.rem +26 -0
  486. data/remind-v06.02.10/include/holidays/ru.rem +21 -0
  487. data/remind-v06.02.10/include/holidays/sa.rem +13 -0
  488. data/remind-v06.02.10/include/holidays/sc.rem +28 -0
  489. data/remind-v06.02.10/include/holidays/se.rem +23 -0
  490. data/remind-v06.02.10/include/holidays/sg.rem +16 -0
  491. data/remind-v06.02.10/include/holidays/si.rem +20 -0
  492. data/remind-v06.02.10/include/holidays/sk.rem +25 -0
  493. data/remind-v06.02.10/include/holidays/sm.rem +25 -0
  494. data/remind-v06.02.10/include/holidays/sv/ss.rem +14 -0
  495. data/remind-v06.02.10/include/holidays/sv.rem +25 -0
  496. data/remind-v06.02.10/include/holidays/sz.rem +26 -0
  497. data/remind-v06.02.10/include/holidays/td.rem +22 -0
  498. data/remind-v06.02.10/include/holidays/th.rem +72 -0
  499. data/remind-v06.02.10/include/holidays/tl.rem +31 -0
  500. data/remind-v06.02.10/include/holidays/tn.rem +15 -0
  501. data/remind-v06.02.10/include/holidays/to.rem +38 -0
  502. data/remind-v06.02.10/include/holidays/tr.rem +17 -0
  503. data/remind-v06.02.10/include/holidays/tw.rem +26 -0
  504. data/remind-v06.02.10/include/holidays/tz.rem +23 -0
  505. data/remind-v06.02.10/include/holidays/ua.rem +20 -0
  506. data/remind-v06.02.10/include/holidays/uk.rem +27 -0
  507. data/remind-v06.02.10/include/holidays/um.rem +32 -0
  508. data/remind-v06.02.10/include/holidays/us/ak.rem +17 -0
  509. data/remind-v06.02.10/include/holidays/us/al.rem +17 -0
  510. data/remind-v06.02.10/include/holidays/us/ar.rem +13 -0
  511. data/remind-v06.02.10/include/holidays/us/as.rem +20 -0
  512. data/remind-v06.02.10/include/holidays/us/az.rem +14 -0
  513. data/remind-v06.02.10/include/holidays/us/ca.rem +16 -0
  514. data/remind-v06.02.10/include/holidays/us/co.rem +14 -0
  515. data/remind-v06.02.10/include/holidays/us/ct.rem +17 -0
  516. data/remind-v06.02.10/include/holidays/us/dc.rem +16 -0
  517. data/remind-v06.02.10/include/holidays/us/de.rem +14 -0
  518. data/remind-v06.02.10/include/holidays/us/fl.rem +14 -0
  519. data/remind-v06.02.10/include/holidays/us/ga.rem +18 -0
  520. data/remind-v06.02.10/include/holidays/us/gu.rem +17 -0
  521. data/remind-v06.02.10/include/holidays/us/hi.rem +19 -0
  522. data/remind-v06.02.10/include/holidays/us/ia.rem +15 -0
  523. data/remind-v06.02.10/include/holidays/us/id.rem +14 -0
  524. data/remind-v06.02.10/include/holidays/us/il.rem +17 -0
  525. data/remind-v06.02.10/include/holidays/us/in.rem +19 -0
  526. data/remind-v06.02.10/include/holidays/us/ks.rem +16 -0
  527. data/remind-v06.02.10/include/holidays/us/ky.rem +16 -0
  528. data/remind-v06.02.10/include/holidays/us/la.rem +14 -0
  529. data/remind-v06.02.10/include/holidays/us/ma.rem +17 -0
  530. data/remind-v06.02.10/include/holidays/us/md-extra.rem +19 -0
  531. data/remind-v06.02.10/include/holidays/us/md.rem +14 -0
  532. data/remind-v06.02.10/include/holidays/us/me.rem +14 -0
  533. data/remind-v06.02.10/include/holidays/us/mi.rem +19 -0
  534. data/remind-v06.02.10/include/holidays/us/mo.rem +16 -0
  535. data/remind-v06.02.10/include/holidays/us/mp.rem +23 -0
  536. data/remind-v06.02.10/include/holidays/us/ms.rem +14 -0
  537. data/remind-v06.02.10/include/holidays/us/mt.rem +13 -0
  538. data/remind-v06.02.10/include/holidays/us/nc.rem +22 -0
  539. data/remind-v06.02.10/include/holidays/us/ne.rem +14 -0
  540. data/remind-v06.02.10/include/holidays/us/nh.rem +14 -0
  541. data/remind-v06.02.10/include/holidays/us/nj.rem +17 -0
  542. data/remind-v06.02.10/include/holidays/us/nm.rem +14 -0
  543. data/remind-v06.02.10/include/holidays/us/nv.rem +16 -0
  544. data/remind-v06.02.10/include/holidays/us/ny.rem +17 -0
  545. data/remind-v06.02.10/include/holidays/us/oh.rem +13 -0
  546. data/remind-v06.02.10/include/holidays/us/ok.rem +13 -0
  547. data/remind-v06.02.10/include/holidays/us/pa.rem +14 -0
  548. data/remind-v06.02.10/include/holidays/us/pr.rem +21 -0
  549. data/remind-v06.02.10/include/holidays/us/ri.rem +14 -0
  550. data/remind-v06.02.10/include/holidays/us/sc.rem +13 -0
  551. data/remind-v06.02.10/include/holidays/us/sd.rem +13 -0
  552. data/remind-v06.02.10/include/holidays/us/tn.rem +13 -0
  553. data/remind-v06.02.10/include/holidays/us/tx.rem +25 -0
  554. data/remind-v06.02.10/include/holidays/us/ut.rem +16 -0
  555. data/remind-v06.02.10/include/holidays/us/va.rem +13 -0
  556. data/remind-v06.02.10/include/holidays/us/vi.rem +22 -0
  557. data/remind-v06.02.10/include/holidays/us/vt.rem +16 -0
  558. data/remind-v06.02.10/include/holidays/us/wi.rem +20 -0
  559. data/remind-v06.02.10/include/holidays/us/wv.rem +17 -0
  560. data/remind-v06.02.10/include/holidays/us.rem +41 -0
  561. data/remind-v06.02.10/include/holidays/uy.rem +39 -0
  562. data/remind-v06.02.10/include/holidays/uz.rem +21 -0
  563. data/remind-v06.02.10/include/holidays/va.rem +23 -0
  564. data/remind-v06.02.10/include/holidays/ve.rem +21 -0
  565. data/remind-v06.02.10/include/holidays/vi.rem +41 -0
  566. data/remind-v06.02.10/include/holidays/vn.rem +17 -0
  567. data/remind-v06.02.10/include/holidays/vu.rem +32 -0
  568. data/remind-v06.02.10/include/holidays/ws.rem +18 -0
  569. data/remind-v06.02.10/include/holidays/za.rem +28 -0
  570. data/remind-v06.02.10/include/holidays/zm.rem +31 -0
  571. data/remind-v06.02.10/include/lang/auto.rem +32 -0
  572. data/remind-v06.02.10/include/lang/ca.rem +60 -0
  573. data/remind-v06.02.10/include/lang/da.rem +77 -0
  574. data/remind-v06.02.10/include/lang/de.rem +80 -0
  575. data/remind-v06.02.10/include/lang/en.rem +4 -0
  576. data/remind-v06.02.10/include/lang/es.rem +55 -0
  577. data/remind-v06.02.10/include/lang/fi.rem +202 -0
  578. data/remind-v06.02.10/include/lang/fr.rem +172 -0
  579. data/remind-v06.02.10/include/lang/gr.rem +74 -0
  580. data/remind-v06.02.10/include/lang/is.rem +58 -0
  581. data/remind-v06.02.10/include/lang/it.rem +76 -0
  582. data/remind-v06.02.10/include/lang/nl.rem +71 -0
  583. data/remind-v06.02.10/include/lang/no.rem +66 -0
  584. data/remind-v06.02.10/include/lang/pl.rem +177 -0
  585. data/remind-v06.02.10/include/lang/pt.rem +176 -0
  586. data/remind-v06.02.10/include/lang/ro.rem +74 -0
  587. data/remind-v06.02.10/include/lunar-eclipses.rem +149 -0
  588. data/remind-v06.02.10/include/moonphases.rem +19 -0
  589. data/remind-v06.02.10/include/seasons.rem +21 -0
  590. data/remind-v06.02.10/include/solar-eclipses.rem +238 -0
  591. data/remind-v06.02.10/include/sun.rem +12 -0
  592. data/remind-v06.02.10/include/translations/de/holidays/chinese-new-year.rem +13 -0
  593. data/remind-v06.02.10/include/translations/de/moonphases.rem +4 -0
  594. data/remind-v06.02.10/include/translations/de/seasons.rem +4 -0
  595. data/remind-v06.02.10/include/translations/de/sun.rem +2 -0
  596. data/remind-v06.02.10/include/translations/nl/holidays/chinese-new-year.rem +13 -0
  597. data/remind-v06.02.10/include/translations/nl/moonphases.rem +4 -0
  598. data/remind-v06.02.10/include/translations/nl/seasons.rem +4 -0
  599. data/remind-v06.02.10/include/translations/nl/sun.rem +2 -0
  600. data/remind-v06.02.10/include/utils/add-html-anchors.rem +5 -0
  601. data/remind-v06.02.10/install-sh +238 -0
  602. data/remind-v06.02.10/man/rem.1.in +21 -0
  603. data/remind-v06.02.10/man/rem2ps.1.in +816 -0
  604. data/remind-v06.02.10/man/remind.1.in +7658 -0
  605. data/remind-v06.02.10/man/tkremind.1.in +612 -0
  606. data/remind-v06.02.10/rem2html/Makefile.in +30 -0
  607. data/remind-v06.02.10/rem2html/rem2html.in +1299 -0
  608. data/remind-v06.02.10/rem2pdf/Makefile.PL.in +25 -0
  609. data/remind-v06.02.10/rem2pdf/Makefile.top.in +50 -0
  610. data/remind-v06.02.10/rem2pdf/bin/rem2pdf.in +761 -0
  611. data/remind-v06.02.10/scripts/tkremind.in +5794 -0
  612. data/remind-v06.02.10/src/Makefile.in +133 -0
  613. data/remind-v06.02.10/src/calendar.c +3069 -0
  614. data/remind-v06.02.10/src/config.h +117 -0
  615. data/remind-v06.02.10/src/config.h.in +116 -0
  616. data/remind-v06.02.10/src/custom.h +167 -0
  617. data/remind-v06.02.10/src/custom.h.in +167 -0
  618. data/remind-v06.02.10/src/dedupe.c +179 -0
  619. data/remind-v06.02.10/src/dorem.c +2389 -0
  620. data/remind-v06.02.10/src/dosubst.c +910 -0
  621. data/remind-v06.02.10/src/dynbuf.c +198 -0
  622. data/remind-v06.02.10/src/dynbuf.h +41 -0
  623. data/remind-v06.02.10/src/err.h +294 -0
  624. data/remind-v06.02.10/src/expr.c +3408 -0
  625. data/remind-v06.02.10/src/files.c +1437 -0
  626. data/remind-v06.02.10/src/funcs.c +5230 -0
  627. data/remind-v06.02.10/src/globals.c +23 -0
  628. data/remind-v06.02.10/src/globals.h +277 -0
  629. data/remind-v06.02.10/src/hashtab.c +428 -0
  630. data/remind-v06.02.10/src/hashtab.h +88 -0
  631. data/remind-v06.02.10/src/hashtab_stats.c +101 -0
  632. data/remind-v06.02.10/src/hbcal.c +579 -0
  633. data/remind-v06.02.10/src/ifelse.c +236 -0
  634. data/remind-v06.02.10/src/init.c +1494 -0
  635. data/remind-v06.02.10/src/json.c +1048 -0
  636. data/remind-v06.02.10/src/json.h +276 -0
  637. data/remind-v06.02.10/src/main.c +2310 -0
  638. data/remind-v06.02.10/src/md5.c +250 -0
  639. data/remind-v06.02.10/src/md5.h +33 -0
  640. data/remind-v06.02.10/src/moon.c +957 -0
  641. data/remind-v06.02.10/src/omit.c +560 -0
  642. data/remind-v06.02.10/src/protos.h +284 -0
  643. data/remind-v06.02.10/src/queue.c +1118 -0
  644. data/remind-v06.02.10/src/rem2ps.c +1383 -0
  645. data/remind-v06.02.10/src/rem2ps.h +229 -0
  646. data/remind-v06.02.10/src/sort.c +257 -0
  647. data/remind-v06.02.10/src/token.c +494 -0
  648. data/remind-v06.02.10/src/trans.c +544 -0
  649. data/remind-v06.02.10/src/trigger.c +871 -0
  650. data/remind-v06.02.10/src/types.h +341 -0
  651. data/remind-v06.02.10/src/userfns.c +810 -0
  652. data/remind-v06.02.10/src/utils.c +374 -0
  653. data/remind-v06.02.10/src/var.c +1762 -0
  654. data/remind-v06.02.10/src/version.h +1 -0
  655. data/remind-v06.02.10/src/version.h.in +1 -0
  656. data/remind-v06.02.10/src/xlat.c +100 -0
  657. data/remind-v06.02.10/www/Makefile.in +91 -0
  658. metadata +764 -0
@@ -0,0 +1,3408 @@
1
+ /***************************************************************/
2
+ /* */
3
+ /* EXPR.C */
4
+ /* */
5
+ /* Remind's expression-evaluation engine */
6
+ /* */
7
+ /* This engine breaks expression evaluation into two phases: */
8
+ /* 1) Compilation: The expression is parsed and a tree */
9
+ /* structure consisting of linked expr_node obbjects */
10
+ /* is created. */
11
+ /* 2) Evaluation: The expr_node tree is traversed and */
12
+ /* evaluated. */
13
+ /* */
14
+ /* This file is part of REMIND. */
15
+ /* Copyright (C) 1992-2026 by Dianne Skoll */
16
+ /* SPDX-License-Identifier: GPL-2.0-only */
17
+ /* */
18
+ /***************************************************************/
19
+ #include "config.h"
20
+ #include "err.h"
21
+ #include "types.h"
22
+ #include "protos.h"
23
+ #include "globals.h"
24
+ #include <stdlib.h>
25
+ #include <string.h>
26
+ #include <stdarg.h>
27
+ #include <unistd.h>
28
+
29
+ /*
30
+ The parser parses expressions into an internal tree
31
+ representation. Each node in the tree is an expr_node
32
+ object, which can be one of the following types:
33
+ 0) N_FREE: An unallocated node
34
+ 1) N_CONSTANT: A constant, such as 3, 13:30, '2024-01-01' or "foo"
35
+ 2) N_LOCAL_VAR: A reference to a function argument.
36
+ 3) N_VARIABLE: A reference to a global variable
37
+ 4) N_SYSVAR: A reference to a system variable
38
+ 5) N_BUILTIN_FUNC: A reference to a built-in function
39
+ 6) N_USER_FUNC: A reference to a user-defined function
40
+ 7) N_OPERATOR: A reference to an operator such as "+" or "&&"
41
+ 8) N_SHORT_STR: A string constant short enough to store in u.name
42
+ 9) N_ERROR: An uninitialized node, or a parse error
43
+
44
+ Additional types are N_SHORT_VAR and N_SHORT_USER_FUNC
45
+ which behave identically to N_VARIABLE and N_USER_FUNC
46
+ respectively, but have short-enough names to be stored more efficiently
47
+ in the expr_node object.
48
+
49
+ expr_nodes contain the following data, depending on their type:
50
+
51
+ 1) N_CONSTANT: The constant value is stored in the node's u.value field
52
+ 2) N_LOCAL_VAR: The offset into the function's argument list is stored in
53
+ u.arg
54
+ 3) N_VARIABLE: The variable's name is stored in u.value.v.str
55
+ 4) N_SYSVAR: A pointer to the SysVar structure is store in u.sysvar
56
+ 5) N_BUILTIN_FUNC: A pointer to the function descriptor is stored in
57
+ u.builtin_func
58
+ 6) N_USER_FUNC: The function's name is stored in u.value.v.str
59
+ 7) N_OPERATOR: A pointer to the operator function is stored in
60
+ u.operator_func
61
+ 8) N_SHORT_VAR: The variable's name is stored in u.name
62
+ 9) N_SHORT_USER_FUNC: The function's name is stored in u.name
63
+
64
+ Nodes may have an arbitrary number of children, represented in the standard
65
+ two-pointer left-child, right-sibling representation.
66
+
67
+ As an example, the expression: 3 + 5 * min(x, 4) is represented like this:
68
+
69
+ +----------+
70
+ | OPERATOR |
71
+ | + |
72
+ +----------+
73
+ / \
74
+ +----------+ +----------+
75
+ | CONSTANT | | OPERATOR |
76
+ | 3 | | * |
77
+ +----------+ +----------+
78
+ / \
79
+ +----------+ +---------+
80
+ | CONSTANT | | BUILTIN |
81
+ | 5 | | min |
82
+ +----------+ +---------+
83
+ / \
84
+ +----------+ +----------+
85
+ | VARIABLE | | CONSTANT |
86
+ | x | | 4 |
87
+ +----------+ +----------+
88
+
89
+ Evaluation is done recursively from the root of the tree. To
90
+ evaluate a node N:
91
+
92
+ 1) Evaluate node N's children from left to right
93
+ 2) Apply the operator or function to all of the resulting values
94
+
95
+ For nodes without children, the result of evaluation is:
96
+ 1) For N_CONSTANT nodes: The constant
97
+ 2) For N_VARIABLE nodes: The value of the variable
98
+ 3) For N_SYSVAR nodes: The value of the system variable
99
+ 4) For N_LOCAL_VAR nodes: The value of the user-defined function's argument
100
+
101
+ User-defined functions contain their own expr_node tree. This is
102
+ evaluated with the "locals" parameter set to the values of all
103
+ of the function's arguments.
104
+
105
+ Some operators don't evaluate all of their children. For example,
106
+ the || and && operators always evaluate their leftmost child. If
107
+ the result is true for ||, or false for &&, then the rightmost child
108
+ is not evaluated because its value is not needed to know the result
109
+ of the operator.
110
+
111
+ The built-in functions choose() and iif() also perform this sort of
112
+ short-circuit evaluation.
113
+ */
114
+
115
+ /*
116
+ * The expression grammar is as follows:
117
+ *
118
+ * EXPR: OR_EXP |
119
+ * OR_EXP '||' EXPR
120
+ *
121
+ * OR_EXP: AND_EXP |
122
+ * AND_EXP '&&' OR_EXP
123
+ *
124
+ * AND_EXP: EQ_EXP |
125
+ * EQ_EXP '==' AND_EXP |
126
+ * EQ_EXP '!=' AND_EXP
127
+ *
128
+ * EQ_EXP: CMP_EXP |
129
+ * CMP_EXP '<' EQ_EXP |
130
+ * CMP_EXP '>' EQ_EXP |
131
+ * CMP_EXP '<=' EQ_EXP |
132
+ * CMP_EXP '<=' EQ_EXP
133
+ *
134
+ * CMP_EXP: TERM_EXP |
135
+ * TERM_EXP '+' CMP_EXP |
136
+ * TERM_EXP '-' CMP_EXP
137
+ *
138
+ * TERM_EXP: FACTOR_EXP |
139
+ * FACTOR_EXP '*' TERM_EXP |
140
+ * FACTOR_EXP '/' TERM_EXP |
141
+ * FACTOR_EXP '%' TERM_EXP
142
+ *
143
+ * FACTOR_EXP: '-' FACTOR_EXP |
144
+ * '!' FACTOR_EXP |
145
+ * ATOM
146
+ *
147
+ * ATOM: '+' ATOM |
148
+ * '(' EXPR ')' |
149
+ * CONSTANT |
150
+ * VAR |
151
+ * FUNCTION_CALL
152
+ */
153
+
154
+
155
+ /* Constants for the "how" arg to compare() */
156
+ enum { EQ, GT, LT, GE, LE, NE };
157
+
158
+ /* Our pool of free expr_node objects, as a linked list, linked by child ptr */
159
+ static expr_node *expr_node_free_list = NULL;
160
+
161
+ #define TOKEN_IS(x) (!strcmp(DBufValue(&ExprBuf), x))
162
+ #define TOKEN_ISNOT(x) strcmp(DBufValue(&ExprBuf), x)
163
+ #define ISID(c) (isalnum(c) || (c) == '_')
164
+
165
+ /* Threshold above which to malloc space for function args rather
166
+ than using the stack */
167
+ #define STACK_ARGS_MAX 5
168
+
169
+ /* Maximum parse level before we bail (to avoid SEGV from filling stack)*/
170
+ #define MAX_PARSE_LEVEL 2000
171
+
172
+ /* Legal punctuation characters in an expression */
173
+ #define LEGAL_CHARS "+-*/%&|=<>!)"
174
+ static int parse_level_high_water = 0;
175
+ #define CHECK_PARSE_LEVEL() do { if (level > parse_level_high_water) { parse_level_high_water = level; if (level > MAX_PARSE_LEVEL) { *r = E_OP_STK_OVER; return NULL; } } } while(0)
176
+
177
+ /* Macro that only does "x" if the "-x" debug flag is on */
178
+ #define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0)
179
+
180
+ #define PEEK_TOKEN() peek_expr_token(&ExprBuf, *e)
181
+ #define GET_TOKEN() parse_expr_token(&ExprBuf, e)
182
+
183
+ /* The built-in function table lives in funcs.c */
184
+ extern BuiltinFunc Func[];
185
+ extern int NumFuncs;
186
+
187
+ /* Keep track of expr_node usage */
188
+ static int ExprNodesAllocated = 0;
189
+ static int ExprNodesHighWater = 0;
190
+ static int ExprNodesUsed = 0;
191
+
192
+ /* Forward references */
193
+ static expr_node * parse_expression_aux(char const **e, int *r, Var *locals, int level);
194
+ static char const *get_operator_name(expr_node *node);
195
+ static void print_expr_tree(expr_node *node, FILE *fp);
196
+
197
+ /* This is super-skanky... we keep track of the currently-executing
198
+ user-defined function in a global var */
199
+ static UserFunc *CurrentUserFunc = NULL;
200
+
201
+ /* How many expr_node objects to allocate at a time */
202
+ #define ALLOC_CHUNK 256
203
+
204
+ static char const *
205
+ find_end_of_expr(char const *s)
206
+ {
207
+ char const *e = s;
208
+ int in_quoted_string = 0;
209
+ int escaped = 0;
210
+
211
+ while(*e) {
212
+ if (in_quoted_string) {
213
+ if (escaped) {
214
+ escaped = 0;
215
+ e++;
216
+ continue;
217
+ }
218
+ if (*e == '\\') {
219
+ escaped = 1;
220
+ e++;
221
+ continue;
222
+ }
223
+ if (*e == '"') {
224
+ in_quoted_string = 0;
225
+ e++;
226
+ continue;
227
+ }
228
+ e++;
229
+ continue;
230
+ }
231
+ if (*e == '"') {
232
+ in_quoted_string = 1;
233
+ e++;
234
+ continue;
235
+ }
236
+ if (*e == ']') {
237
+ break;
238
+ }
239
+ e++;
240
+ }
241
+ return e;
242
+ }
243
+
244
+ /***************************************************************/
245
+ /* */
246
+ /* node_str - get string associated with a node */
247
+ /* */
248
+ /***************************************************************/
249
+ static char const *
250
+ node_str(expr_node const *node)
251
+ {
252
+ switch(node->type) {
253
+ case N_VARIABLE:
254
+ case N_USER_FUNC:
255
+ return node->u.value.v.str;
256
+
257
+ case N_SHORT_VAR:
258
+ case N_SHORT_USER_FUNC:
259
+ case N_SHORT_STR:
260
+ return node->u.name;
261
+
262
+ case N_SYSVAR:
263
+ return node->u.sysvar->name;
264
+
265
+ default:
266
+ return NULL;
267
+ }
268
+ }
269
+
270
+ /***************************************************************/
271
+ /* */
272
+ /* alloc_expr_node - allocate an expr_node object */
273
+ /* */
274
+ /* Allocates and returns an expr_node object. If all goes */
275
+ /* well, a pointer to the object is returned and *r is set */
276
+ /* to OK. On failure, *r is set to an error code and NULL */
277
+ /* is returned. */
278
+ /* */
279
+ /***************************************************************/
280
+ static expr_node *
281
+ alloc_expr_node(int *r)
282
+ {
283
+ expr_node *node;
284
+ if (!expr_node_free_list) {
285
+ expr_node_free_list = calloc(ALLOC_CHUNK, sizeof(expr_node));
286
+ if (!expr_node_free_list) {
287
+ *r = E_NO_MEM;
288
+ return NULL;
289
+ }
290
+ ExprNodesAllocated += ALLOC_CHUNK;
291
+ for (size_t i=0; i<ALLOC_CHUNK-1; i++) {
292
+ expr_node_free_list[i].child = &(expr_node_free_list[i+1]);
293
+ expr_node_free_list[i].sibling = NULL;
294
+ expr_node_free_list[i].type = N_FREE;
295
+ }
296
+ expr_node_free_list[ALLOC_CHUNK-1].child = NULL;
297
+ }
298
+ ExprNodesUsed++;
299
+ if (ExprNodesUsed > ExprNodesHighWater) ExprNodesHighWater = ExprNodesUsed;
300
+ node = expr_node_free_list;
301
+ expr_node_free_list = node->child;
302
+ node->type = N_ERROR;
303
+ node->child = NULL;
304
+ node->sibling = NULL;
305
+ node->num_kids = 0;
306
+ return node;
307
+ }
308
+
309
+ /***************************************************************/
310
+ /* */
311
+ /* add_child - add a new child to an existing node */
312
+ /* */
313
+ /* adds "child" as the rightmost child of "parent". Always */
314
+ /* succeeds, so returns no value. */
315
+ /* */
316
+ /***************************************************************/
317
+ static void
318
+ add_child(expr_node *parent, expr_node *child)
319
+ {
320
+ parent->num_kids++;
321
+ child->sibling = NULL;
322
+ if (!parent->child) {
323
+ parent->child = child;
324
+ return;
325
+ }
326
+
327
+ expr_node *cur = parent->child;
328
+ while (cur->sibling) {
329
+ cur = cur->sibling;
330
+ }
331
+ cur->sibling = child;
332
+ }
333
+
334
+ /***************************************************************/
335
+ /* */
336
+ /* debug_evaluation - print debugging information */
337
+ /* */
338
+ /* This is a helper function for the DB_PRTEXPR (-dx flag) */
339
+ /* */
340
+ /* It prints fmt and following printf-style args, followed */
341
+ /* by " => " and then either an error message for r != OK */
342
+ /* or a value that's the result of evaluation. */
343
+ /* */
344
+ /***************************************************************/
345
+ static void
346
+ debug_evaluation(Value const *ans, int r, char const *fmt, ...)
347
+ {
348
+ va_list argptr;
349
+ va_start(argptr, fmt);
350
+ vfprintf(ErrFp, fmt, argptr);
351
+ fprintf(ErrFp, " => ");
352
+ if (r != OK) {
353
+ fprintf(ErrFp, "%s\n", GetErr(r));
354
+ } else {
355
+ PrintValue(ans, ErrFp);
356
+ fprintf(ErrFp, "\n");
357
+ }
358
+ va_end(argptr);
359
+ }
360
+
361
+ /***************************************************************/
362
+ /* */
363
+ /* debug_evaluation_binop - print debugging information */
364
+ /* */
365
+ /* This is a helper function for the DB_PRTEXPR (-dx flag) */
366
+ /* */
367
+ /* It's called specifically for binary operators. v1 and v2 */
368
+ /* are the operands (a NULL operand indicates one that was */
369
+ /* not evaluated), ans is the result, and r is the error code. */
370
+ /* */
371
+ /***************************************************************/
372
+ static void
373
+ debug_evaluation_binop(Value const *ans, int r, Value const *v1, Value const *v2, char const *fmt, ...)
374
+ {
375
+ va_list argptr;
376
+ va_start(argptr, fmt);
377
+ if (v1) {
378
+ PrintValue(v1, ErrFp);
379
+ } else {
380
+ fprintf(ErrFp, "?");
381
+ }
382
+ fprintf(ErrFp, " ");
383
+ vfprintf(ErrFp, fmt, argptr);
384
+ fprintf(ErrFp, " ");
385
+ if (v2) {
386
+ PrintValue(v2, ErrFp);
387
+ } else {
388
+ fprintf(ErrFp, "?");
389
+ }
390
+ fprintf(ErrFp, " => ");
391
+ if (r != OK) {
392
+ fprintf(ErrFp, "%s\n", GetErr(r));
393
+ } else {
394
+ PrintValue(ans, ErrFp);
395
+ fprintf(ErrFp, "\n");
396
+ }
397
+ va_end(argptr);
398
+ }
399
+
400
+ /***************************************************************/
401
+ /* */
402
+ /* debug_evaluation_unop - print debugging information */
403
+ /* */
404
+ /* This is a helper function for the DB_PRTEXPR (-dx flag) */
405
+ /* */
406
+ /* It's called specifically for unary operators. v1 */
407
+ /* is the operand, ans is the result, and r is the error code */
408
+ /* */
409
+ /***************************************************************/
410
+ static void
411
+ debug_evaluation_unop(Value const *ans, int r, Value const *v1, char const *fmt, ...)
412
+ {
413
+ va_list argptr;
414
+ va_start(argptr, fmt);
415
+ vfprintf(ErrFp, fmt, argptr);
416
+ fprintf(ErrFp, " ");
417
+ if (v1) {
418
+ PrintValue(v1, ErrFp);
419
+ } else {
420
+ fprintf(ErrFp, "?");
421
+ }
422
+ fprintf(ErrFp, " => ");
423
+ if (r != OK) {
424
+ fprintf(ErrFp, "%s\n", GetErr(r));
425
+ } else {
426
+ PrintValue(ans, ErrFp);
427
+ fprintf(ErrFp, "\n");
428
+ }
429
+ va_end(argptr);
430
+ }
431
+
432
+ /***************************************************************/
433
+ /* */
434
+ /* get_var - get the value of a variable */
435
+ /* */
436
+ /* Gets the value of a global variable, with the name taken */
437
+ /* from the appropriate field of `node' */
438
+ /* */
439
+ /***************************************************************/
440
+ static int
441
+ get_var(expr_node *node, Value *ans, int *nonconst)
442
+ {
443
+ Var *v;
444
+ char const *str;
445
+
446
+ str = node_str(node);
447
+ v = FindVar(str, 0);
448
+ if (!v) {
449
+ Eprint("%s: `%s'", GetErr(E_NOSUCH_VAR), str);
450
+ return E_NOSUCH_VAR;
451
+ }
452
+ v->used_since_set = 1;
453
+ if (!v->is_constant) {
454
+ nonconst_debug(*nonconst, tr("Global variable `%s' makes expression non-constant"), str);
455
+ *nonconst = 1;
456
+ }
457
+ return CopyValue(ans, &(v->v));
458
+ }
459
+
460
+ /***************************************************************/
461
+ /* */
462
+ /* eval_builtin - evaluate a builtin function */
463
+ /* */
464
+ /* node is an expr_node of type N_BUILTIN_FUNC */
465
+ /* locals is an array of local variables (if any) or NULL */
466
+ /* The result of evaluation is stored in ans */
467
+ /* If a non-constant function is evaluated, *nonconst is set */
468
+ /* to 1. The return code is OK if all went well, or an error */
469
+ /* code otherwise. In case of an error, *ans is not updated */
470
+ /* */
471
+ /* The iif() and choose() functions know how to evaluate */
472
+ /* themselves when passed the expr_node. All other functions */
473
+ /* use an older API with a func_info object containing the */
474
+ /* evaluated arguments and a spot for the return value. */
475
+ /* */
476
+ /***************************************************************/
477
+ static int
478
+ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
479
+ {
480
+ func_info info;
481
+ BuiltinFunc *f = node->u.builtin_func;
482
+ expr_node *kid;
483
+ int i, j, r;
484
+ Value stack_args[STACK_ARGS_MAX];
485
+
486
+ /* Check that we have the right number of argumens */
487
+ if (node->num_kids < f->minargs) {
488
+ Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
489
+ return E_2FEW_ARGS;
490
+ }
491
+ if (node->num_kids > f->maxargs && f->maxargs != NO_MAX_ARGS) {
492
+ Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
493
+ return E_2MANY_ARGS;
494
+ }
495
+
496
+ if (FuncRecursionLevel >= MAX_RECURSION_LEVEL) {
497
+ return E_RECURSIVE;
498
+ }
499
+
500
+ /* If this is a new-style function that knows about expr_nodes,
501
+ let it evaluate itself */
502
+ if (f->newfunc) {
503
+ FuncRecursionLevel++;
504
+ r = node->u.builtin_func->newfunc(node, locals, ans, nonconst);
505
+ FuncRecursionLevel--;
506
+ return r;
507
+ }
508
+
509
+ /* It's an old-style function, so we need to simulate the
510
+ old function call API by building up a bundle of evaluated
511
+ arguments */
512
+ info.nargs = node->num_kids;
513
+ info.nonconst = 0;
514
+
515
+ if (info.nargs) {
516
+ if (info.nargs <= STACK_ARGS_MAX) {
517
+ info.args = stack_args;
518
+ } else {
519
+ info.args = malloc(info.nargs * sizeof(Value));
520
+ if (!info.args) {
521
+ return E_NO_MEM;
522
+ }
523
+ }
524
+ } else {
525
+ info.args = NULL;
526
+ }
527
+
528
+ kid = node->child;
529
+ i = 0;
530
+
531
+ /* Evaluate each child node and store it as the i'th argument */
532
+ while (kid) {
533
+ r = evaluate_expr_node(kid, locals, &(info.args[i]), nonconst);
534
+ if (r != OK) {
535
+ for (j=0; j<i; j++) {
536
+ DestroyValue(info.args[j]);
537
+ }
538
+ if (info.args != NULL && info.args != stack_args) {
539
+ free(info.args);
540
+ }
541
+ return r;
542
+ }
543
+ i++;
544
+ kid = kid->sibling;
545
+ }
546
+
547
+ /* Mark retval as uninitialized */
548
+ info.retval.type = ERR_TYPE;
549
+
550
+ /* Actually call the function */
551
+ if (DebugFlag & DB_PRTEXPR) {
552
+ fprintf(ErrFp, "%s(", f->name);
553
+ for (i=0; i<info.nargs; i++) {
554
+ if (i > 0) {
555
+ fprintf(ErrFp, " ");
556
+ }
557
+ PrintValue(&(info.args[i]), ErrFp);
558
+ if (i < info.nargs-1) {
559
+ fprintf(ErrFp, ",");
560
+ }
561
+ }
562
+ fprintf(ErrFp, ") => ");
563
+ }
564
+ FuncRecursionLevel++;
565
+ r = f->func(&info);
566
+ FuncRecursionLevel--;
567
+
568
+ /* Propagate non-constness */
569
+ if (info.nonconst) {
570
+ nonconst_debug(*nonconst, tr("Non-constant built-in function `%s' makes expression non-constant"), f->name);
571
+ *nonconst = 1;
572
+ }
573
+ if (r == OK) {
574
+ /* All went well; copy the result destructively */
575
+ (*ans) = info.retval;
576
+
577
+ /* Special case of const function */
578
+ if (!strcmp(f->name, "const")) {
579
+ if (*nonconst) {
580
+ nonconst_debug(0, tr("Non-constant expression converted to constant by `const' built-in function"));
581
+ }
582
+ *nonconst = 0;
583
+ }
584
+ /* Don't allow retval to be destroyed! */
585
+ info.retval.type = ERR_TYPE;
586
+ }
587
+
588
+ /* Debug */
589
+ if (DebugFlag & DB_PRTEXPR) {
590
+ if (r) {
591
+ fprintf(ErrFp, "%s", GetErr(r));
592
+ } else {
593
+ PrintValue(ans, ErrFp);
594
+ }
595
+ fprintf(ErrFp, "\n");
596
+ }
597
+ if (r != OK) {
598
+ Eprint("%s(): %s", f->name, GetErr(r));
599
+ }
600
+ /* Clean up */
601
+ if (info.args) {
602
+ for (i=0; i<info.nargs; i++) {
603
+ DestroyValue(info.args[i]);
604
+ }
605
+ if (info.args != NULL && info.args != stack_args) {
606
+ free(info.args);
607
+ }
608
+ }
609
+ DestroyValue(info.retval);
610
+ return r;
611
+ }
612
+
613
+ /***************************************************************/
614
+ /* */
615
+ /* debug_enter_userfunc - debugging helper function */
616
+ /* */
617
+ /* This function prints debugging info when a user-defined */
618
+ /* function is invoked. */
619
+ /* */
620
+ /***************************************************************/
621
+ static void
622
+ debug_enter_userfunc(expr_node *node, Value *locals, int nargs)
623
+ {
624
+ int i;
625
+ char const *fname = node_str(node);
626
+
627
+ fprintf(ErrFp, "%s %s(", GetErr(E_ENTER_FUN), fname);
628
+ for (i=0; i<nargs; i++) {
629
+ if (i) fprintf(ErrFp, ", ");
630
+ PrintValue(&(locals[i]), ErrFp);
631
+ }
632
+ fprintf(ErrFp, ")\n");
633
+ }
634
+
635
+ /***************************************************************/
636
+ /* */
637
+ /* debug_exit_userfunc - debugging helper function */
638
+ /* */
639
+ /* This function prints debugging info when a user-defined */
640
+ /* function has been evaluated. */
641
+ /* */
642
+ /***************************************************************/
643
+ static void
644
+ debug_exit_userfunc(expr_node *node, Value const *ans, int r, Value *locals, int nargs)
645
+ {
646
+ char const *fname = node_str(node);
647
+ int i;
648
+
649
+ fprintf(ErrFp, "%s %s(", GetErr(E_LEAVE_FUN), fname);
650
+ for (i=0; i<nargs; i++) {
651
+ if (i) fprintf(ErrFp, ", ");
652
+ PrintValue(&(locals[i]), ErrFp);
653
+ }
654
+ fprintf(ErrFp, ") => ");
655
+ if (r == OK) {
656
+ PrintValue(ans, ErrFp);
657
+ } else {
658
+ fprintf(ErrFp, "%s", GetErr(r));
659
+ }
660
+ fprintf(ErrFp, "\n");
661
+ }
662
+
663
+ static void
664
+ print_placeholders(int n)
665
+ {
666
+ int i;
667
+ for (i=0; i<n; i++) {
668
+ if (i > 0) {
669
+ fprintf(ErrFp, ", ");
670
+ }
671
+ fprintf(ErrFp, "?");
672
+ }
673
+ }
674
+
675
+ /***************************************************************/
676
+ /* */
677
+ /* eval_userfunc - evaluate a user-defined function */
678
+ /* */
679
+ /* This function sets up a local value array by evaluating */
680
+ /* all of its children, and then evaluates the expr_node */
681
+ /* tree associated with the user-defined function. */
682
+ /* */
683
+ /***************************************************************/
684
+ static int
685
+ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
686
+ {
687
+ UserFunc *f;
688
+ UserFunc *previously_executing;
689
+
690
+ Value *new_locals = NULL;
691
+ expr_node *kid;
692
+ int i, r, j, pushed;
693
+ int old_rundisabled;
694
+
695
+ /* If we have <= STACK_ARGS_MAX, store them on the stack here */
696
+ Value stack_locals[STACK_ARGS_MAX];
697
+
698
+ /* Get the function name */
699
+ char const *fname = node_str(node);
700
+
701
+ /* Find the function */
702
+ f = FindUserFunc(fname);
703
+
704
+ /* Bail if function does not exist */
705
+ if (!f) {
706
+ Eprint("%s: `%s'", GetErr(E_UNDEF_FUNC), fname);
707
+ return E_UNDEF_FUNC;
708
+ }
709
+
710
+ /* Make sure we have the right number of arguments */
711
+ if (node->num_kids < f->nargs) {
712
+ DBG(fprintf(ErrFp, "%s(", fname); print_placeholders(node->num_kids); fprintf(ErrFp, ") => %s\n", GetErr(E_2FEW_ARGS)));
713
+ Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
714
+ return E_2FEW_ARGS;
715
+ }
716
+ if (node->num_kids > f->nargs) {
717
+ DBG(fprintf(ErrFp, "%s(", fname); print_placeholders(node->num_kids); fprintf(ErrFp, ") => %s\n", GetErr(E_2MANY_ARGS)));
718
+ Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
719
+ return E_2MANY_ARGS;
720
+ }
721
+
722
+ /* Build up the array of locals */
723
+ if (node->num_kids) {
724
+ if (node->num_kids > STACK_ARGS_MAX) {
725
+ /* Too many args to fit on stack; put on heap */
726
+ new_locals = malloc(node->num_kids * sizeof(Value));
727
+ if (!new_locals) {
728
+ DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_NO_MEM)));
729
+ return E_NO_MEM;
730
+ }
731
+ } else {
732
+ new_locals = stack_locals;
733
+ }
734
+
735
+ /* Evaluate each child node and store in new_locals */
736
+ kid = node->child;
737
+ i = 0;
738
+ while(kid) {
739
+ r = evaluate_expr_node(kid, locals, &(new_locals[i]), nonconst);
740
+ if (r != OK) {
741
+ for (j=0; j<i; j++) {
742
+ DestroyValue(new_locals[j]);
743
+ }
744
+ if (new_locals != stack_locals) free(new_locals);
745
+ return r;
746
+ }
747
+ i++;
748
+ kid = kid->sibling;
749
+ }
750
+ }
751
+
752
+ /* Check for deep recursion */
753
+ if (FuncRecursionLevel >= MAX_RECURSION_LEVEL) {
754
+ for (j=0; j<node->num_kids; j++) {
755
+ DestroyValue(new_locals[j]);
756
+ }
757
+ if (new_locals != NULL && new_locals != stack_locals) free(new_locals);
758
+ return E_RECURSIVE;
759
+ }
760
+
761
+ /* Set currently-executing function (for debugging) */
762
+ previously_executing = CurrentUserFunc;
763
+ CurrentUserFunc = f;
764
+
765
+ FuncRecursionLevel++;
766
+
767
+ if (!f->is_constant) {
768
+ nonconst_debug(*nonconst, tr("User function `%s' defined in non-constant context makes expression non-constant"), f->name);
769
+ *nonconst = 1;
770
+ }
771
+ /* Add a call to the call stack for better error messages */
772
+ pushed = push_call(f->filename, f->name, f->lineno, f->lineno_start);
773
+
774
+ DBG(debug_enter_userfunc(node, new_locals, f->nargs));
775
+
776
+ old_rundisabled = RunDisabled;
777
+ if (f->run_disabled) {
778
+ RunDisabled |= RUN_UF;
779
+ }
780
+ /* Evaluate the function's expr_node tree */
781
+ r = evaluate_expr_node(f->node, new_locals, ans, nonconst);
782
+
783
+ RunDisabled = old_rundisabled;
784
+
785
+ DBG(debug_exit_userfunc(node, ans, r, new_locals, f->nargs));
786
+
787
+ if (r != OK) {
788
+ /* We print the error here in order to get the call stack trace */
789
+ Eprint("%s", GetErr(r));
790
+ }
791
+
792
+ if (pushed == OK) pop_call();
793
+ FuncRecursionLevel--;
794
+ CurrentUserFunc = previously_executing;
795
+
796
+ /* Clean up */
797
+ for (j=0; j<node->num_kids; j++) {
798
+ DestroyValue(new_locals[j]);
799
+ }
800
+ if (new_locals != stack_locals &&
801
+ new_locals != NULL) {
802
+ free(new_locals);
803
+ }
804
+
805
+ return r;
806
+ }
807
+
808
+ /***************************************************************/
809
+ /* */
810
+ /* evaluate_expression - evaluate an expression, possibly */
811
+ /* with timeout */
812
+ /* */
813
+ /* See evaluate_expr_node for a description of arguments and */
814
+ /* return value. */
815
+ /* */
816
+ /***************************************************************/
817
+ int
818
+ evaluate_expression(expr_node *node, Value *locals, Value *ans, int *nonconst)
819
+ {
820
+ int r;
821
+
822
+ /* Set up time limits */
823
+ if (ExpressionEvaluationTimeLimit > 0) {
824
+ ExpressionTimeLimitExceeded = 0;
825
+ alarm(ExpressionEvaluationTimeLimit);
826
+ }
827
+ r = evaluate_expr_node(node, locals, ans, nonconst);
828
+ if (ExpressionEvaluationTimeLimit > 0) {
829
+ alarm(0);
830
+ ExpressionTimeLimitExceeded = 0;
831
+ }
832
+ return r;
833
+ }
834
+
835
+ static int CopyShortStr(Value *ans, expr_node const *node)
836
+ {
837
+ size_t len = strlen(node->u.name);
838
+ ans->v.str = malloc(len+1);
839
+ if (!ans->v.str) {
840
+ ans->type = ERR_TYPE;
841
+ return E_NO_MEM;
842
+ }
843
+ strcpy(ans->v.str, node->u.name);
844
+ ans->type = STR_TYPE;
845
+ return OK;
846
+ }
847
+
848
+ /***************************************************************/
849
+ /* */
850
+ /* evaluate_expr_node - evaluate an expression */
851
+ /* */
852
+ /* Arguments: */
853
+ /* node - the expr_node to evaluate */
854
+ /* locals - an array of arguments to a user-defined */
855
+ /* function. NULL if we're not in a function */
856
+ /* ans - pointer to a Value object that will hold */
857
+ /* the result of an evaluation */
858
+ /* nonconst - pointer to an integer that will be set to 1 */
859
+ /* if a non-constant object or function is */
860
+ /* evaluated */
861
+ /* Returns: */
862
+ /* OK if all goes well; a non-zero error code on failure. */
863
+ /* On failure, *ans is not updated. */
864
+ /* */
865
+ /***************************************************************/
866
+ int
867
+ evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst)
868
+ {
869
+ int r;
870
+
871
+ if (ExpressionEvaluationDisabled) {
872
+ return E_EXPR_DISABLED;
873
+ }
874
+
875
+ if (ExpressionTimeLimitExceeded) {
876
+ ExpressionTimeLimitExceeded = 0;
877
+ return E_TIME_EXCEEDED;
878
+ }
879
+ if (!node) {
880
+ return E_SWERR;
881
+ }
882
+ if (ExpressionNodeLimitPerLine > 0 &&
883
+ ExpressionNodesEvaluatedThisLine >= ExpressionNodeLimitPerLine) {
884
+ return E_EXPR_NODES_EXCEEDED;
885
+ }
886
+ ExpressionNodesEvaluated++;
887
+ ExpressionNodesEvaluatedThisLine++;
888
+ if (ExpressionNodesEvaluatedThisLine > MaxExprNodesPerLine) {
889
+ MaxExprNodesPerLine = ExpressionNodesEvaluatedThisLine;
890
+ MaxExprNodeLineNo = LineNo;
891
+ MaxExprNodeFilename = GetCurrentFilename();
892
+ }
893
+ switch(node->type) {
894
+ case N_FREE:
895
+ case N_ERROR:
896
+ ans->type = ERR_TYPE;
897
+ return E_SWERR;
898
+
899
+ case N_SHORT_STR:
900
+ return CopyShortStr(ans, node);
901
+
902
+ case N_CONSTANT:
903
+ /* Constant node? Just return a copy of the constant */
904
+ return CopyValue(ans, &(node->u.value));
905
+
906
+ case N_SHORT_VAR:
907
+ case N_VARIABLE:
908
+ r = get_var(node, ans, nonconst);
909
+ DBG(debug_evaluation(ans, r, "%s", node_str(node)));
910
+ return r;
911
+
912
+ case N_LOCAL_VAR:
913
+ /* User-defined function argument? Copy the value */
914
+ r = CopyValue(ans, &(locals[node->u.arg]));
915
+ DBG(debug_evaluation(ans, r, "%s", CurrentUserFunc->args[node->u.arg]));
916
+ return r;
917
+
918
+ case N_SYSVAR:
919
+ /* System var? Return it and note non-constant expression */
920
+ if (node->u.sysvar->type != CONST_INT_TYPE) {
921
+ nonconst_debug(*nonconst, tr("System variable `$%s' makes expression non-constant"), node_str(node));
922
+ *nonconst = 1;
923
+ }
924
+ r = GetSysVar(node->u.sysvar, ans);
925
+ DBG(debug_evaluation(ans, r, "$%s", node_str(node)));
926
+ return r;
927
+
928
+ case N_BUILTIN_FUNC:
929
+ /* Built-in function? Evaluate and note non-constant where applicable */
930
+ if (!node->u.builtin_func->is_constant) {
931
+ nonconst_debug(*nonconst, tr("Non-constant built-in function `%s' makes expression non-constant"), node->u.builtin_func->name);
932
+ *nonconst = 1;
933
+ }
934
+ return eval_builtin(node, locals, ans, nonconst);
935
+
936
+ case N_SHORT_USER_FUNC:
937
+ case N_USER_FUNC:
938
+ /* User-defined function? Evaluate it */
939
+ return eval_userfunc(node, locals, ans, nonconst);
940
+
941
+ case N_OPERATOR:
942
+ /* Operator? Evaluate it */
943
+ r = node->u.operator_func(node, locals, ans, nonconst);
944
+ if (r != OK) {
945
+ Eprint("`%s': %s", get_operator_name(node), GetErr(r));
946
+ }
947
+ return r;
948
+ }
949
+
950
+ /* Can't happen */
951
+ return E_SWERR;
952
+ }
953
+
954
+ /***************************************************************/
955
+ /* */
956
+ /* how_to_op - convert a symbolic comparison constant to name */
957
+ /* */
958
+ /* Converts EQ, NE, etc to "==", "!=", etc for debugging */
959
+ /* */
960
+ /***************************************************************/
961
+ static char const *how_to_op(int how)
962
+ {
963
+ switch(how) {
964
+ case EQ: return "==";
965
+ case NE: return "!=";
966
+ case GE: return ">=";
967
+ case LE: return "<=";
968
+ case GT: return ">";
969
+ case LT: return "<";
970
+ default: return "???";
971
+ }
972
+ }
973
+
974
+ /***************************************************************/
975
+ /* */
976
+ /* compare - evaluate a comparison operator. */
977
+ /* */
978
+ /* In addition to the usual arguments, "how" specifies */
979
+ /* specifically which comparison operator we're evaluating. */
980
+ /* */
981
+ /***************************************************************/
982
+ static int
983
+ compare(expr_node *node, Value *locals, Value *ans, int *nonconst, int how)
984
+ {
985
+ int r;
986
+ Value v1, v2;
987
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
988
+ if (r != OK) return r;
989
+ r = evaluate_expr_node(node->child->sibling, locals, &v2, nonconst);
990
+ if (r != OK) {
991
+ DestroyValue(v1);
992
+ return r;
993
+ }
994
+
995
+ ans->type = INT_TYPE;
996
+
997
+ /* Different types? Only allowed for != and == */
998
+ if (v1.type != v2.type) {
999
+ if (how == EQ) {
1000
+ ans->v.val = 0;
1001
+ } else if (how == NE) {
1002
+ ans->v.val = 1;
1003
+ } else {
1004
+ DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v1, &v2, "%s", how_to_op(how)));
1005
+ DestroyValue(v1);
1006
+ DestroyValue(v2);
1007
+ return E_BAD_TYPE;
1008
+ }
1009
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "%s", how_to_op(how)));
1010
+ DestroyValue(v1);
1011
+ DestroyValue(v2);
1012
+ return OK;
1013
+ }
1014
+
1015
+ /* Same types */
1016
+ if (v1.type == STR_TYPE) {
1017
+ switch(how) {
1018
+ case EQ: ans->v.val = (strcmp(v1.v.str, v2.v.str) == 0); break;
1019
+ case NE: ans->v.val = (strcmp(v1.v.str, v2.v.str) != 0); break;
1020
+ case LT: ans->v.val = (strcmp(v1.v.str, v2.v.str) < 0); break;
1021
+ case GT: ans->v.val = (strcmp(v1.v.str, v2.v.str) > 0); break;
1022
+ case LE: ans->v.val = (strcmp(v1.v.str, v2.v.str) <= 0); break;
1023
+ case GE: ans->v.val = (strcmp(v1.v.str, v2.v.str) >= 0); break;
1024
+ }
1025
+ } else {
1026
+ switch(how) {
1027
+ case EQ: ans->v.val = (v1.v.val == v2.v.val); break;
1028
+ case NE: ans->v.val = (v1.v.val != v2.v.val); break;
1029
+ case LT: ans->v.val = (v1.v.val < v2.v.val); break;
1030
+ case GT: ans->v.val = (v1.v.val > v2.v.val); break;
1031
+ case LE: ans->v.val = (v1.v.val <= v2.v.val); break;
1032
+ case GE: ans->v.val = (v1.v.val >= v2.v.val); break;
1033
+ }
1034
+ }
1035
+ DBG(debug_evaluation_binop(ans, r, &v1, &v2, "%s", how_to_op(how)));
1036
+ DestroyValue(v1);
1037
+ DestroyValue(v2);
1038
+ return OK;
1039
+ }
1040
+
1041
+ /***************************************************************/
1042
+ /* */
1043
+ /* compare_eq - evaluate the "==" operator */
1044
+ /* */
1045
+ /***************************************************************/
1046
+ static int compare_eq(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1047
+ return compare(node, locals, ans, nonconst, EQ);
1048
+ }
1049
+
1050
+ /***************************************************************/
1051
+ /* */
1052
+ /* compare_ne evaluate the "!=" operator */
1053
+ /* */
1054
+ /***************************************************************/
1055
+ static int compare_ne(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1056
+ return compare(node, locals, ans, nonconst, NE);
1057
+ }
1058
+
1059
+ /***************************************************************/
1060
+ /* */
1061
+ /* compare_le - evaluate the "<=" operator */
1062
+ /* */
1063
+ /***************************************************************/
1064
+ static int compare_le(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1065
+ return compare(node, locals, ans, nonconst, LE);
1066
+ }
1067
+
1068
+ /***************************************************************/
1069
+ /* */
1070
+ /* compare_ge - evaluate the ">=" operator */
1071
+ /* */
1072
+ /***************************************************************/
1073
+ static int compare_ge(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1074
+ return compare(node, locals, ans, nonconst, GE);
1075
+ }
1076
+
1077
+ /***************************************************************/
1078
+ /* */
1079
+ /* compare_lt - evaluate the "<" operator */
1080
+ /* */
1081
+ /***************************************************************/
1082
+ static int compare_lt(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1083
+ return compare(node, locals, ans, nonconst, LT);
1084
+ }
1085
+
1086
+ /***************************************************************/
1087
+ /* */
1088
+ /* compare_gt - evaluate the ">" operator */
1089
+ /* */
1090
+ /***************************************************************/
1091
+ static int compare_gt(expr_node *node, Value *locals, Value *ans, int *nonconst) {
1092
+ return compare(node, locals, ans, nonconst, GT);
1093
+ }
1094
+
1095
+
1096
+ /***************************************************************/
1097
+ /* */
1098
+ /* add - evaluate the "+" operator */
1099
+ /* */
1100
+ /***************************************************************/
1101
+ static int add(expr_node *node, Value *locals, Value *ans, int *nonconst)
1102
+ {
1103
+ int r;
1104
+ Value v1, v2;
1105
+ size_t l1, l2;
1106
+
1107
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1108
+ if (r != OK) return r;
1109
+ r = evaluate_expr_node(node->child->sibling, locals, &v2, nonconst);
1110
+ if (r != OK) {
1111
+ DestroyValue(v1);
1112
+ return r;
1113
+ }
1114
+
1115
+ /* If both are ints, just add 'em */
1116
+ if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
1117
+ /* Check for overflow */
1118
+ if (_private_add_overflow(v1.v.val, v2.v.val)) {
1119
+ DBG(debug_evaluation_binop(ans, E_2HIGH, &v1, &v2, "+"));
1120
+ return E_2HIGH;
1121
+ }
1122
+ *ans = v1;
1123
+ ans->v.val += v2.v.val;
1124
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "+"));
1125
+ return OK;
1126
+ }
1127
+
1128
+ /* If it's a date plus an int, add 'em */
1129
+ if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) ||
1130
+ (v1.type == INT_TYPE && v2.type == DATE_TYPE)) {
1131
+ if (_private_add_overflow(v1.v.val, v2.v.val)) {
1132
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "+"));
1133
+ return E_DATE_OVER;
1134
+ }
1135
+
1136
+ *ans = v1;
1137
+ ans->v.val += v2.v.val;
1138
+ if (ans->v.val < 0) {
1139
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "+"));
1140
+ return E_DATE_OVER;
1141
+ }
1142
+ ans->type = DATE_TYPE;
1143
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "+"));
1144
+ return OK;
1145
+ }
1146
+
1147
+ /* If it's a datetime plus an int or a time, add 'em */
1148
+ if ((v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) ||
1149
+ ((v1.type == INT_TYPE || v1.type == TIME_TYPE) && v2.type == DATETIME_TYPE)) {
1150
+ if (_private_add_overflow(v1.v.val, v2.v.val)) {
1151
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "+"));
1152
+ return E_DATE_OVER;
1153
+ }
1154
+ *ans = v1;
1155
+ ans->v.val += v2.v.val;
1156
+ if (ans->v.val < 0) {
1157
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "+"));
1158
+ return E_DATE_OVER;
1159
+ }
1160
+ ans->type = DATETIME_TYPE;
1161
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "+"));
1162
+ return OK;
1163
+ }
1164
+
1165
+ /* If it's a time plus an int or a time plus a time,
1166
+ add 'em mod MINUTES_PER_DAY */
1167
+ if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) ||
1168
+ (v1.type == INT_TYPE && v2.type == TIME_TYPE) ||
1169
+ (v1.type == TIME_TYPE && v2.type == TIME_TYPE)) {
1170
+ if (_private_add_overflow(v1.v.val, v2.v.val)) {
1171
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "+"));
1172
+ return E_DATE_OVER;
1173
+ }
1174
+ *ans = v1;
1175
+ ans->v.val += v2.v.val;
1176
+ ans->v.val = ans->v.val % MINUTES_PER_DAY;
1177
+ if (ans->v.val < 0) ans->v.val += MINUTES_PER_DAY;
1178
+ ans->type = TIME_TYPE;
1179
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "+"));
1180
+ return OK;
1181
+ }
1182
+
1183
+ /* If either is a string, coerce them both to strings and concatenate */
1184
+ if (v1.type == STR_TYPE || v2.type == STR_TYPE) {
1185
+ /* Skanky... copy the values shallowly for debug */
1186
+ Value o1 = v1;
1187
+ Value o2 = v2;
1188
+ if ( (r = DoCoerce(STR_TYPE, &v1)) ) {
1189
+ DBG(debug_evaluation_binop(ans, r, &o1, &o2, "+"));
1190
+ DestroyValue(v1);
1191
+ DestroyValue(v2);
1192
+ return r;
1193
+ }
1194
+ if ( (r = DoCoerce(STR_TYPE, &v2)) ) {
1195
+ DBG(debug_evaluation_binop(ans, r, &o1, &o2, "+"));
1196
+ DestroyValue(v1);
1197
+ DestroyValue(v2);
1198
+ return r;
1199
+ }
1200
+ l1 = strlen(v1.v.str);
1201
+ l2 = strlen(v2.v.str);
1202
+ if (MaxStringLen > 0 && (l1 + l2 > (size_t) MaxStringLen)) {
1203
+ DBG(debug_evaluation_binop(ans, E_STRING_TOO_LONG, &o1, &o2, "+"));
1204
+ DestroyValue(v1);
1205
+ DestroyValue(v2);
1206
+ return E_STRING_TOO_LONG;
1207
+ }
1208
+ ans->v.str = malloc(l1 + l2 + 1);
1209
+ if (!ans->v.str) {
1210
+ DBG(debug_evaluation_binop(ans, E_NO_MEM, &o1, &o2, "+"));
1211
+ DestroyValue(v1);
1212
+ DestroyValue(v2);
1213
+ return E_NO_MEM;
1214
+ }
1215
+ ans->type = STR_TYPE;
1216
+ strcpy(ans->v.str, v1.v.str);
1217
+ strcpy(ans->v.str+l1, v2.v.str);
1218
+ DBG(debug_evaluation_binop(ans, OK, &o1, &o2, "+"));
1219
+ DestroyValue(v1);
1220
+ DestroyValue(v2);
1221
+ return OK;
1222
+ }
1223
+
1224
+ /* Don't handle other types yet */
1225
+ DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v1, &v2, "+"));
1226
+ DestroyValue(v1);
1227
+ DestroyValue(v2);
1228
+ return E_BAD_TYPE;
1229
+ }
1230
+
1231
+ /***************************************************************/
1232
+ /* */
1233
+ /* subtract - evaluate the binary "-" operator */
1234
+ /* */
1235
+ /***************************************************************/
1236
+ static int subtract(expr_node *node, Value *locals, Value *ans, int *nonconst)
1237
+ {
1238
+ int r;
1239
+ Value v1, v2;
1240
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1241
+ if (r != OK) return r;
1242
+ r = evaluate_expr_node(node->child->sibling, locals, &v2, nonconst);
1243
+ if (r != OK) {
1244
+ DestroyValue(v1);
1245
+ return r;
1246
+ }
1247
+ /* If they're both INTs, do subtraction */
1248
+ if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
1249
+ if (_private_sub_overflow(v1.v.val, v2.v.val)) {
1250
+ DBG(debug_evaluation_binop(ans, E_2HIGH, &v1, &v2, "-"));
1251
+ return E_2HIGH;
1252
+ }
1253
+ *ans = v1;
1254
+ ans->v.val -= v2.v.val;
1255
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "-"));
1256
+ return OK;
1257
+ }
1258
+
1259
+ /* If it's a date minus an int, do subtraction, checking for underflow */
1260
+ if (v1.type == DATE_TYPE && v2.type == INT_TYPE) {
1261
+ if (_private_sub_overflow(v1.v.val, v2.v.val)) {
1262
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "-"));
1263
+ return E_DATE_OVER;
1264
+ }
1265
+ *ans = v1;
1266
+ ans->v.val -= v2.v.val;
1267
+ if (ans->v.val < 0) return E_DATE_OVER;
1268
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "-"));
1269
+ return OK;
1270
+ }
1271
+
1272
+ /* If it's a datetime minus an int or a time, do subtraction,
1273
+ * checking for underflow */
1274
+ if (v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) {
1275
+ if (_private_sub_overflow(v1.v.val, v2.v.val)) {
1276
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "-"));
1277
+ return E_DATE_OVER;
1278
+ }
1279
+ *ans = v1;
1280
+ ans->v.val -= v2.v.val;
1281
+ if (ans->v.val < 0) {
1282
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "-"));
1283
+ return E_DATE_OVER;
1284
+ }
1285
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "-"));
1286
+ return OK;
1287
+ }
1288
+
1289
+ /* If it's a time minus an int, do subtraction mod MINUTES_PER_DAY */
1290
+ if (v1.type == TIME_TYPE && v2.type == INT_TYPE) {
1291
+ *ans = v1;
1292
+ ans->v.val = (ans->v.val - v2.v.val) % MINUTES_PER_DAY;
1293
+ if (ans->v.val < 0) ans->v.val += MINUTES_PER_DAY;
1294
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "-"));
1295
+ return OK;
1296
+ }
1297
+
1298
+ /* If it's a time minus a time or a date minus a date, do it */
1299
+ if ((v1.type == TIME_TYPE && v2.type == TIME_TYPE) ||
1300
+ (v1.type == DATETIME_TYPE && v2.type == DATETIME_TYPE) ||
1301
+ (v1.type == DATE_TYPE && v2.type == DATE_TYPE)) {
1302
+ if (_private_sub_overflow(v1.v.val, v2.v.val)) {
1303
+ DBG(debug_evaluation_binop(ans, E_DATE_OVER, &v1, &v2, "-"));
1304
+ return E_DATE_OVER;
1305
+ }
1306
+ *ans = v1;
1307
+ ans->v.val -= v2.v.val;
1308
+ ans->type = INT_TYPE;
1309
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "-"));
1310
+ return OK;
1311
+ }
1312
+
1313
+ DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v1, &v2, "-"));
1314
+ /* Must be types illegal for subtraction */
1315
+ DestroyValue(v1); DestroyValue(v2);
1316
+ return E_BAD_TYPE;
1317
+ }
1318
+
1319
+ /***************************************************************/
1320
+ /* */
1321
+ /* multiply - evaluate the "*" operator */
1322
+ /* */
1323
+ /***************************************************************/
1324
+ static int multiply(expr_node *node, Value *locals, Value *ans, int *nonconst)
1325
+ {
1326
+ int r;
1327
+ Value v1, v2;
1328
+ char *ptr;
1329
+
1330
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1331
+ if (r != OK) return r;
1332
+ r = evaluate_expr_node(node->child->sibling, locals, &v2, nonconst);
1333
+ if (r != OK) {
1334
+ DestroyValue(v1);
1335
+ return r;
1336
+ }
1337
+
1338
+ if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
1339
+ /* Prevent floating-point exception */
1340
+ if ((v2.v.val == -1 && v1.v.val == INT_MIN) ||
1341
+ (v1.v.val == -1 && v2.v.val == INT_MIN)) {
1342
+ DBG(debug_evaluation_binop(ans, E_2HIGH, &v1, &v2, "*"));
1343
+ return E_2HIGH;
1344
+ }
1345
+ if (_private_mul_overflow(v1.v.val, v2.v.val)) {
1346
+ DBG(debug_evaluation_binop(ans, E_2HIGH, &v1, &v2, "*"));
1347
+ return E_2HIGH;
1348
+ }
1349
+ *ans = v1;;
1350
+ ans->v.val *= v2.v.val;
1351
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "*"));
1352
+ return OK;
1353
+ }
1354
+
1355
+ /* String times int means repeat the string that many times */
1356
+ if ((v1.type == INT_TYPE && v2.type == STR_TYPE) ||
1357
+ (v1.type == STR_TYPE && v2.type == INT_TYPE)) {
1358
+ int rep = (v1.type == INT_TYPE ? v1.v.val : v2.v.val);
1359
+ char const *str = (v1.type == INT_TYPE ? v2.v.str : v1.v.str);
1360
+ int l;
1361
+
1362
+ /* Can't multiply by a negative number */
1363
+ if (rep < 0) {
1364
+ DBG(debug_evaluation_binop(ans, E_2LOW, &v1, &v2, "*"));
1365
+ DestroyValue(v1);
1366
+ DestroyValue(v2);
1367
+ return E_2LOW;
1368
+ }
1369
+ if (rep == 0 || !str || !*str) {
1370
+ /* Empty string */
1371
+ ans->type = STR_TYPE;
1372
+ ans->v.str = malloc(1);
1373
+ if (!ans->v.str) {
1374
+ DBG(debug_evaluation_binop(ans, E_NO_MEM, &v1, &v2, "*"));
1375
+ DestroyValue(v1);
1376
+ DestroyValue(v2);
1377
+ return E_NO_MEM;
1378
+ }
1379
+ *ans->v.str = 0;
1380
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "*"));
1381
+ DestroyValue(v1); DestroyValue(v2);
1382
+ return OK;
1383
+ }
1384
+
1385
+ /* Create the new value */
1386
+ l = (int) strlen(str);
1387
+ if (l * rep < 0) {
1388
+ DBG(debug_evaluation_binop(ans, E_STRING_TOO_LONG, &v1, &v2, "*"));
1389
+ DestroyValue(v1); DestroyValue(v2);
1390
+ return E_STRING_TOO_LONG;
1391
+ }
1392
+ if ((unsigned long) l * (unsigned long) rep >= (unsigned long) INT_MAX) {
1393
+ DBG(debug_evaluation_binop(ans, E_STRING_TOO_LONG, &v1, &v2, "*"));
1394
+ DestroyValue(v1); DestroyValue(v2);
1395
+ return E_STRING_TOO_LONG;
1396
+ }
1397
+ if (MaxStringLen > 0 && ((unsigned long) l * (unsigned long) rep) > (unsigned long)MaxStringLen) {
1398
+ DBG(debug_evaluation_binop(ans, E_STRING_TOO_LONG, &v1, &v2, "*"));
1399
+ DestroyValue(v1); DestroyValue(v2);
1400
+ return E_STRING_TOO_LONG;
1401
+ }
1402
+ ans->type = STR_TYPE;
1403
+ ans->v.str = malloc(l * rep + 1);
1404
+ if (!ans->v.str) {
1405
+ DBG(debug_evaluation_binop(ans, E_NO_MEM, &v1, &v2, "*"));
1406
+ DestroyValue(v1); DestroyValue(v2);
1407
+ return E_NO_MEM;
1408
+ }
1409
+ *ans->v.str = 0;
1410
+ ptr = ans->v.str;
1411
+ for (int i=0; i<rep; i++) {
1412
+ strcat(ptr, str);
1413
+ ptr += l;
1414
+ }
1415
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "*"));
1416
+ DestroyValue(v1); DestroyValue(v2);
1417
+ return OK;
1418
+ }
1419
+ DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v1, &v2, "*"));
1420
+ DestroyValue(v1); DestroyValue(v2);
1421
+ return E_BAD_TYPE;
1422
+ }
1423
+
1424
+ /***************************************************************/
1425
+ /* */
1426
+ /* divide_or_mod - evaluate the "/" or "%" operator */
1427
+ /* */
1428
+ /***************************************************************/
1429
+ static int divide_or_mod(expr_node *node, Value *locals, Value *ans, int *nonconst, char op)
1430
+ {
1431
+ int r;
1432
+ Value v1, v2;
1433
+
1434
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1435
+ if (r != OK) return r;
1436
+ r = evaluate_expr_node(node->child->sibling, locals, &v2, nonconst);
1437
+ if (r != OK) {
1438
+ DestroyValue(v1);
1439
+ return r;
1440
+ }
1441
+ if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
1442
+ if (v2.v.val == 0) {
1443
+ DBG(debug_evaluation_binop(ans, E_DIV_ZERO, &v1, &v2, "%c", op));
1444
+ return E_DIV_ZERO;
1445
+ }
1446
+ /* This is the only way it can overflow */
1447
+ if (v2.v.val == -1 && v1.v.val == INT_MIN) {
1448
+ DBG(debug_evaluation_binop(ans, E_2HIGH, &v1, &v2, "%c", op));
1449
+ return E_2HIGH;
1450
+ }
1451
+ *ans = v1;
1452
+ if (op == '/') {
1453
+ ans->v.val /= v2.v.val;
1454
+ } else {
1455
+ ans->v.val %= v2.v.val;
1456
+ }
1457
+ DBG(debug_evaluation_binop(ans, OK, &v1, &v2, "%c", op));
1458
+ return OK;
1459
+ }
1460
+ DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v1, &v2, "%c", op));
1461
+ DestroyValue(v1);
1462
+ DestroyValue(v2);
1463
+ return E_BAD_TYPE;
1464
+ }
1465
+
1466
+ /***************************************************************/
1467
+ /* */
1468
+ /* do_mod - evaluate the "%" operator */
1469
+ /* */
1470
+ /***************************************************************/
1471
+ static int do_mod(expr_node *node, Value *locals, Value *ans, int *nonconst)
1472
+ {
1473
+ return divide_or_mod(node, locals, ans, nonconst, '%');
1474
+ }
1475
+
1476
+ /***************************************************************/
1477
+ /* */
1478
+ /* divide - evaluate the "/" operator */
1479
+ /* */
1480
+ /***************************************************************/
1481
+ static int divide(expr_node *node, Value *locals, Value *ans, int *nonconst)
1482
+ {
1483
+ return divide_or_mod(node, locals, ans, nonconst, '/');
1484
+ }
1485
+
1486
+ /***************************************************************/
1487
+ /* */
1488
+ /* logical_not - evaluate the unary "!" operator */
1489
+ /* */
1490
+ /***************************************************************/
1491
+ static int logical_not(expr_node *node, Value *locals, Value *ans, int *nonconst)
1492
+ {
1493
+ int r;
1494
+ Value v1;
1495
+
1496
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1497
+ if (r != OK) return r;
1498
+ ans->type = INT_TYPE;
1499
+ ans->v.val = !truthy(&v1);
1500
+ DBG(debug_evaluation_unop(ans, OK, &v1, "!"));
1501
+ DestroyValue(v1);
1502
+ return OK;
1503
+ }
1504
+
1505
+ /***************************************************************/
1506
+ /* */
1507
+ /* unary_minus - evaluate the unary "-" operator */
1508
+ /* */
1509
+ /***************************************************************/
1510
+ static int unary_minus(expr_node *node, Value *locals, Value *ans, int *nonconst)
1511
+ {
1512
+ int r;
1513
+ Value v1;
1514
+
1515
+ r = evaluate_expr_node(node->child, locals, &v1, nonconst);
1516
+ if (r != OK) return r;
1517
+ if (v1.type != INT_TYPE) {
1518
+ DBG(debug_evaluation_unop(ans, E_BAD_TYPE, &v1, "-"));
1519
+ DestroyValue(v1);
1520
+ return E_BAD_TYPE;
1521
+ }
1522
+ if (v1.v.val == INT_MIN) {
1523
+ DBG(debug_evaluation_unop(ans, E_2LOW, &v1, "-"));
1524
+ DestroyValue(v1);
1525
+ return E_2LOW;
1526
+ }
1527
+ ans->type = INT_TYPE;
1528
+ ans->v.val = -(v1.v.val);
1529
+ DBG(debug_evaluation_unop(ans, OK, &v1, "-"));
1530
+ return OK;
1531
+ }
1532
+
1533
+ /***************************************************************/
1534
+ /* */
1535
+ /* logical_binop - evaluate the short-circuit || or && ops */
1536
+ /* */
1537
+ /***************************************************************/
1538
+ static int logical_binop(expr_node *node, Value *locals, Value *ans, int *nonconst, int is_and)
1539
+ {
1540
+ Value v;
1541
+ char const *opname = (is_and) ? "&&" : "||";
1542
+
1543
+ /* Evaluate first arg */
1544
+ int r = evaluate_expr_node(node->child, locals, &v, nonconst);
1545
+
1546
+ /* Bail on error */
1547
+ if (r != OK) return r;
1548
+
1549
+ if (is_and) {
1550
+ /* If first arg is false, return it */
1551
+ if (!truthy(&v)) {
1552
+ *ans = v;
1553
+ DBG(debug_evaluation_binop(ans, OK, &v, NULL, opname));
1554
+ return OK;
1555
+ }
1556
+ } else {
1557
+ /* If first arg is true, return it */
1558
+ if (truthy(&v)) {
1559
+ *ans = v;
1560
+ DBG(debug_evaluation_binop(ans, OK, &v, NULL, opname));
1561
+ return OK;
1562
+ }
1563
+ }
1564
+
1565
+ /* Otherwise, evaluate and return second arg */
1566
+ r = evaluate_expr_node(node->child->sibling, locals, ans, nonconst);
1567
+ DBG(debug_evaluation_binop(ans, r, &v, ans, opname));
1568
+ DestroyValue(v);
1569
+ return r;
1570
+ }
1571
+
1572
+ /***************************************************************/
1573
+ /* */
1574
+ /* logical_or - evaluate the short-circuit || operator */
1575
+ /* */
1576
+ /***************************************************************/
1577
+ static int logical_or(expr_node *node, Value *locals, Value *ans, int *nonconst)
1578
+ {
1579
+ return logical_binop(node, locals, ans, nonconst, 0);
1580
+ }
1581
+
1582
+ /***************************************************************/
1583
+ /* */
1584
+ /* logical_and - evaluate the short-circuit && operator */
1585
+ /* */
1586
+ /***************************************************************/
1587
+ static int logical_and(expr_node *node, Value *locals, Value *ans, int *nonconst)
1588
+ {
1589
+ return logical_binop(node, locals, ans, nonconst, 1);
1590
+ }
1591
+
1592
+ /***************************************************************/
1593
+ /* */
1594
+ /* parse_expr_token */
1595
+ /* */
1596
+ /* Read a token. */
1597
+ /* */
1598
+ /***************************************************************/
1599
+ static int parse_expr_token(DynamicBuffer *buf, char const **in)
1600
+ {
1601
+
1602
+ char c;
1603
+ char c2;
1604
+ char hexbuf[3];
1605
+
1606
+ DBufFree(buf);
1607
+
1608
+ /* Skip white space */
1609
+ while (**in && isempty(**in)) (*in)++;
1610
+
1611
+ if (!**in) return OK;
1612
+
1613
+ c = *(*in)++;
1614
+ if (DBufPutc(buf, c) != OK) {
1615
+ DBufFree(buf);
1616
+ return E_NO_MEM;
1617
+ }
1618
+
1619
+ switch(c) {
1620
+ case COMMA:
1621
+ case END_OF_EXPR:
1622
+ case '+':
1623
+ case '-':
1624
+ case '*':
1625
+ case '/':
1626
+ case '(':
1627
+ case ')':
1628
+ case '%': return OK;
1629
+
1630
+ case '&':
1631
+ case '|':
1632
+ case '=':
1633
+ if (**in == c) {
1634
+ if (DBufPutc(buf, c) != OK) {
1635
+ DBufFree(buf);
1636
+ return E_NO_MEM;
1637
+ }
1638
+ (*in)++;
1639
+ } else {
1640
+ Eprint("%s `%c' (%s `%c%c'?)", GetErr(E_PARSE_ERR), c, tr("did you mean"), c, c);
1641
+ return E_PARSE_ERR;
1642
+ }
1643
+ return OK;
1644
+ case '!':
1645
+ case '>':
1646
+ case '<':
1647
+ if (**in == '=') {
1648
+ if (DBufPutc(buf, '=') != OK) {
1649
+ DBufFree(buf);
1650
+ return E_NO_MEM;
1651
+ }
1652
+ (*in)++;
1653
+ }
1654
+ return OK;
1655
+ }
1656
+
1657
+
1658
+ /* Handle the parsing of quoted strings */
1659
+ if (c == '\"') {
1660
+ if (!**in) return E_MISS_QUOTE;
1661
+ while (**in) {
1662
+ /* Allow backslash-escapes */
1663
+ if (**in == '\\') {
1664
+ int r;
1665
+ (*in)++;
1666
+ if (!**in) {
1667
+ DBufFree(buf);
1668
+ return E_MISS_QUOTE;
1669
+ }
1670
+ switch(**in) {
1671
+ case 'a':
1672
+ r = DBufPutc(buf, '\a');
1673
+ break;
1674
+ case 'b':
1675
+ r = DBufPutc(buf, '\b');
1676
+ break;
1677
+ case 'f':
1678
+ r = DBufPutc(buf, '\f');
1679
+ break;
1680
+ case 'n':
1681
+ r = DBufPutc(buf, '\n');
1682
+ break;
1683
+ case 'r':
1684
+ r = DBufPutc(buf, '\r');
1685
+ break;
1686
+ case 't':
1687
+ r = DBufPutc(buf, '\t');
1688
+ break;
1689
+ case 'v':
1690
+ r = DBufPutc(buf, '\v');
1691
+ break;
1692
+ case 'x':
1693
+ c2 = *(*in + 1);
1694
+ if (!isxdigit(c2)) {
1695
+ r = DBufPutc(buf, **in);
1696
+ break;
1697
+ }
1698
+ hexbuf[0] = c2;
1699
+ hexbuf[1] = 0;
1700
+ (*in)++;
1701
+ c2 = *(*in + 1);
1702
+ if (isxdigit(c2)) {
1703
+ hexbuf[1] = c2;
1704
+ hexbuf[2] = 0;
1705
+ (*in)++;
1706
+ }
1707
+ c2 = (int) strtol(hexbuf, NULL, 16);
1708
+ if (!c2) {
1709
+ Eprint(tr("\\x00 is not a valid escape sequence"));
1710
+ r = E_PARSE_ERR;
1711
+ } else {
1712
+ r = DBufPutc(buf, c2);
1713
+ }
1714
+ break;
1715
+ default:
1716
+ r = DBufPutc(buf, **in);
1717
+ break;
1718
+ }
1719
+ (*in)++;
1720
+ if (r != OK) {
1721
+ DBufFree(buf);
1722
+ return E_NO_MEM;
1723
+ }
1724
+ continue;
1725
+ }
1726
+ c = *(*in)++;
1727
+ if (DBufPutc(buf, c) != OK) {
1728
+ DBufFree(buf);
1729
+ return E_NO_MEM;
1730
+ }
1731
+ if (c == '\"') break;
1732
+ }
1733
+ if (c == '\"') return OK;
1734
+ DBufFree(buf);
1735
+ return E_MISS_QUOTE;
1736
+ }
1737
+
1738
+ /* Dates can be specified with single-quotes */
1739
+ if (c == '\'') {
1740
+ if (!**in) return E_MISS_QUOTE;
1741
+ while (**in) {
1742
+ c = *(*in)++;
1743
+ if (DBufPutc(buf, c) != OK) {
1744
+ DBufFree(buf);
1745
+ return E_NO_MEM;
1746
+ }
1747
+ if (c == '\'') break;
1748
+ }
1749
+ if (c == '\'') return OK;
1750
+ DBufFree(buf);
1751
+ return E_MISS_QUOTE;
1752
+ }
1753
+
1754
+ if (!ISID(c) && c != '$') {
1755
+ if (!c) {
1756
+ Eprint("%s", GetErr(E_EOLN));
1757
+ return E_EOLN;
1758
+ }
1759
+ Eprint("%s `%c'", GetErr(E_ILLEGAL_CHAR), c);
1760
+ return E_ILLEGAL_CHAR;
1761
+ }
1762
+
1763
+ if (c == '$' && **in && isalpha(**in)) {
1764
+ while(ISID(**in)) {
1765
+ if (DBufPutc(buf, **in) != OK) {
1766
+ DBufFree(buf);
1767
+ return E_NO_MEM;
1768
+ }
1769
+ (*in)++;
1770
+ }
1771
+ return OK;
1772
+ }
1773
+
1774
+ /* Parse a constant, variable name or function */
1775
+ while (ISID(**in) || **in == ':' || **in == '.' || **in == TimeSep) {
1776
+ if (DBufPutc(buf, **in) != OK) {
1777
+ DBufFree(buf);
1778
+ return E_NO_MEM;
1779
+ }
1780
+ (*in)++;
1781
+ }
1782
+ /* Chew up any remaining white space */
1783
+ while (**in && isempty(**in)) (*in)++;
1784
+
1785
+ /* Peek ahead - is it an id followed by '('? Then we have a function call */
1786
+ if (isalpha(*(DBufValue(buf))) ||
1787
+ *DBufValue(buf) == '_') {
1788
+ if (**in == '(') {
1789
+ if (DBufPutc(buf, '(') != OK) {
1790
+ DBufFree(buf);
1791
+ return E_NO_MEM;
1792
+ }
1793
+ (*in)++;
1794
+ }
1795
+ }
1796
+ return OK;
1797
+ }
1798
+
1799
+ /***************************************************************/
1800
+ /* */
1801
+ /* peek_expr_token */
1802
+ /* */
1803
+ /* Read a token without advancing the input pointer */
1804
+ /* */
1805
+ /***************************************************************/
1806
+ static int peek_expr_token(DynamicBuffer *buf, char const *in)
1807
+ {
1808
+ return parse_expr_token(buf, &in);
1809
+ }
1810
+
1811
+ /***************************************************************/
1812
+ /* */
1813
+ /* free_expr_tree */
1814
+ /* */
1815
+ /* Recursively free the expr_node tree rooted at node */
1816
+ /* Always returns NULL */
1817
+ /* */
1818
+ /***************************************************************/
1819
+ expr_node * free_expr_tree(expr_node *node)
1820
+ {
1821
+ if (node && (node->type != N_FREE)) {
1822
+ ExprNodesUsed--;
1823
+ if (node->type == N_CONSTANT ||
1824
+ node->type == N_VARIABLE ||
1825
+ node->type == N_USER_FUNC) {
1826
+ DestroyValue(node->u.value);
1827
+ }
1828
+ free_expr_tree(node->child);
1829
+ free_expr_tree(node->sibling);
1830
+ node->child = (expr_node *) expr_node_free_list;
1831
+ expr_node_free_list = (void *) node;
1832
+ node->type = N_FREE;
1833
+ }
1834
+ return NULL;
1835
+ }
1836
+
1837
+ /***************************************************************/
1838
+ /* */
1839
+ /* clone_expr_tree */
1840
+ /* */
1841
+ /* Clone an entire expr_tree. The clone shares no memory */
1842
+ /* with the original. Returns NULL and sets *r on failure. */
1843
+ /* */
1844
+ /***************************************************************/
1845
+ expr_node * clone_expr_tree(expr_node const *src, int *r)
1846
+ {
1847
+ int rc;
1848
+ expr_node *dest = alloc_expr_node(r);
1849
+ if (!dest) return NULL;
1850
+
1851
+ dest->type = src->type;
1852
+ dest->num_kids = src->num_kids;
1853
+ switch(dest->type) {
1854
+ case N_FREE:
1855
+ case N_ERROR:
1856
+ *r = E_SWERR;
1857
+ free_expr_tree(dest);
1858
+ return NULL;
1859
+
1860
+ case N_SYSVAR:
1861
+ dest->u.sysvar = src->u.sysvar;
1862
+ break;
1863
+
1864
+ case N_CONSTANT:
1865
+ case N_VARIABLE:
1866
+ case N_USER_FUNC:
1867
+ rc = CopyValue(&(dest->u.value), &(src->u.value));
1868
+ if (rc != OK) {
1869
+ *r = rc;
1870
+ free_expr_tree(dest);
1871
+ return NULL;
1872
+ }
1873
+ break;
1874
+
1875
+ case N_SHORT_STR:
1876
+ case N_SHORT_VAR:
1877
+ case N_SHORT_USER_FUNC:
1878
+ strcpy(dest->u.name, src->u.name);
1879
+ break;
1880
+
1881
+ case N_LOCAL_VAR:
1882
+ dest->u.arg = src->u.arg;
1883
+ break;
1884
+
1885
+ case N_BUILTIN_FUNC:
1886
+ dest->u.builtin_func = src->u.builtin_func;
1887
+ break;
1888
+
1889
+ case N_OPERATOR:
1890
+ dest->u.operator_func = src->u.operator_func;
1891
+ break;
1892
+ }
1893
+
1894
+ if (src->child) {
1895
+ dest->child = clone_expr_tree(src->child, r);
1896
+ if (!dest->child) {
1897
+ free_expr_tree(dest);
1898
+ return NULL;
1899
+ }
1900
+ }
1901
+ if (src->sibling) {
1902
+ dest->sibling = clone_expr_tree(src->sibling, r);
1903
+ if (!dest->sibling) {
1904
+ free_expr_tree(dest);
1905
+ return NULL;
1906
+ }
1907
+ }
1908
+ return dest;
1909
+ }
1910
+
1911
+ /***************************************************************/
1912
+ /* */
1913
+ /* set_long_name - set a long name in an expr_node */
1914
+ /* */
1915
+ /* Set the name field in an expr_node that's too long to fit */
1916
+ /* in u.name -- instead, set in u.value.v.str */
1917
+ /* */
1918
+ /***************************************************************/
1919
+ static int set_long_name(expr_node *node, char const *s)
1920
+ {
1921
+ char *buf;
1922
+ size_t len = strlen(s);
1923
+ if (len > VAR_NAME_LEN) len = VAR_NAME_LEN;
1924
+ buf = malloc(len+1);
1925
+ if (!buf) {
1926
+ return E_NO_MEM;
1927
+ }
1928
+ StrnCpy(buf, s, VAR_NAME_LEN);
1929
+ node->u.value.type = STR_TYPE;
1930
+ node->u.value.v.str = buf;
1931
+ return OK;
1932
+ }
1933
+
1934
+ /***************************************************************/
1935
+ /* */
1936
+ /* parse_function_call - parse a function call */
1937
+ /* */
1938
+ /* Starting from *e, parse a function call and return the */
1939
+ /* parsed expr_node tree */
1940
+ /* */
1941
+ /* All parsing functions have the following arguments and */
1942
+ /* return value: */
1943
+ /* */
1944
+ /* e - the current parse pointer. *e points to the */
1945
+ /* character we're readin, and *e is updated as we parse */
1946
+ /* */
1947
+ /* r - holds the return code. Set to OK if all is well */
1948
+ /* or a non-zero error code on error */
1949
+ /* */
1950
+ /* locals - an array of Vars representing named arguments */
1951
+ /* for a user-defined function */
1952
+ /* */
1953
+ /* Returns an expr_node on success, NULL on failure. */
1954
+ /* */
1955
+ /***************************************************************/
1956
+ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int level)
1957
+ {
1958
+ expr_node *node;
1959
+ expr_node *arg;
1960
+ char *s;
1961
+ char const *ptr;
1962
+ CHECK_PARSE_LEVEL();
1963
+
1964
+ node = alloc_expr_node(r);
1965
+ if (!node) {
1966
+ return NULL;
1967
+ }
1968
+ s = DBufValue(&ExprBuf);
1969
+ *(s + DBufLen(&ExprBuf) - 1) = 0;
1970
+ BuiltinFunc *f = FindBuiltinFunc(s);
1971
+ if (f) {
1972
+ node->u.builtin_func = f;
1973
+ node->type = N_BUILTIN_FUNC;
1974
+ } else {
1975
+ if (strlen(s) < SHORT_NAME_BUF) {
1976
+ node->type = N_SHORT_USER_FUNC;
1977
+ strcpy(node->u.name, s);
1978
+ strtolower(node->u.name);
1979
+ } else {
1980
+ if (set_long_name(node, s) != OK) {
1981
+ *r = E_NO_MEM;
1982
+ return free_expr_tree(node);
1983
+ }
1984
+ strtolower(node->u.value.v.str);
1985
+ node->type = N_USER_FUNC;
1986
+ }
1987
+ }
1988
+ /* Now parse the arguments */
1989
+ *r = GET_TOKEN();
1990
+ if (*r != OK) {
1991
+ free_expr_tree(node);
1992
+ return NULL;
1993
+ }
1994
+ while(TOKEN_ISNOT(")")) {
1995
+ *r = PEEK_TOKEN();
1996
+ if (*r != OK) {
1997
+ return free_expr_tree(node);
1998
+ }
1999
+ if (TOKEN_IS(")")) {
2000
+ continue;
2001
+ }
2002
+ ptr = *e;
2003
+ arg = parse_expression_aux(e, r, locals, level+1);
2004
+ if (*r != OK) {
2005
+ free_expr_tree(node);
2006
+ return NULL;
2007
+ }
2008
+ add_child(node, arg);
2009
+ if (node->type == N_BUILTIN_FUNC) {
2010
+ f = node->u.builtin_func;
2011
+ if (node->num_kids > f->maxargs && f->maxargs != NO_MAX_ARGS) {
2012
+ *r = E_2MANY_ARGS;
2013
+ *e = ptr;
2014
+ free_expr_tree(node);
2015
+ return NULL;
2016
+ }
2017
+ }
2018
+ *r = PEEK_TOKEN();
2019
+ if (*r != OK) {
2020
+ return free_expr_tree(node);
2021
+ }
2022
+ if (TOKEN_ISNOT(")") &&
2023
+ TOKEN_ISNOT(",")) {
2024
+ *r = E_EXPECT_COMMA;
2025
+ return free_expr_tree(node);
2026
+ }
2027
+ if (TOKEN_IS(",")) {
2028
+ *r = GET_TOKEN();
2029
+ if (*r != OK) {
2030
+ return free_expr_tree(node);
2031
+ }
2032
+ *r = PEEK_TOKEN();
2033
+ if (*r != OK) {
2034
+ return free_expr_tree(node);
2035
+ }
2036
+ if (TOKEN_IS(")")) {
2037
+ Eprint("%s `)'", GetErr(E_PARSE_ERR));
2038
+ *r = E_PARSE_ERR;
2039
+ return free_expr_tree(node);
2040
+ }
2041
+ }
2042
+ }
2043
+ ptr = *e;
2044
+ if (TOKEN_IS(")")) {
2045
+ *r = GET_TOKEN();
2046
+ if (*r != OK) {
2047
+ return free_expr_tree(node);
2048
+ }
2049
+ }
2050
+ /* Check args for builtin funcs */
2051
+ if (node->type == N_BUILTIN_FUNC) {
2052
+ f = node->u.builtin_func;
2053
+ if (node->num_kids < f->minargs) {
2054
+ *e = ptr;
2055
+ *r = E_2FEW_ARGS;
2056
+ }
2057
+ /* Already checked for too many args earlier... */
2058
+ }
2059
+ if (*r != OK) {
2060
+ if (node->type == N_BUILTIN_FUNC) {
2061
+ f = node->u.builtin_func;
2062
+ Eprint("%s: %s", f->name, GetErr(*r));
2063
+ }
2064
+ return free_expr_tree(node);
2065
+ }
2066
+ return node;
2067
+ }
2068
+
2069
+ /***************************************************************/
2070
+ /* */
2071
+ /* set_constant_value - Given a constant value token in */
2072
+ /* ExprBuf, parse ExprBuf and set atom->u.value appropriately */
2073
+ /* */
2074
+ /***************************************************************/
2075
+ static int set_constant_value(expr_node *atom)
2076
+ {
2077
+ int dse, tim, val, prev_val, h, m, ampm, r;
2078
+ size_t len;
2079
+ char const *s = DBufValue(&ExprBuf);
2080
+ atom->u.value.type = ERR_TYPE;
2081
+ atom->type = N_CONSTANT;
2082
+
2083
+ if (!*s) {
2084
+ Eprint("%s", GetErr(E_EOLN));
2085
+ return E_EOLN;
2086
+ }
2087
+ ampm = 0;
2088
+ if (*s == '\"') { /* It's a literal string "*/
2089
+ len = strlen(s)-1;
2090
+ if (len <= SHORT_NAME_BUF) {
2091
+ atom->type = N_SHORT_STR;
2092
+ strncpy(atom->u.name, s+1, len-1);
2093
+ atom->u.name[len-1] = 0;
2094
+ return OK;
2095
+ }
2096
+ atom->u.value.type = STR_TYPE;
2097
+ atom->u.value.v.str = malloc(len);
2098
+ if (! atom->u.value.v.str) {
2099
+ atom->u.value.type = ERR_TYPE;
2100
+ return E_NO_MEM;
2101
+ }
2102
+ strncpy(atom->u.value.v.str, s+1, len-1);
2103
+ *(atom->u.value.v.str+len-1) = 0;
2104
+ return OK;
2105
+ } else if (*s == '\'') { /* It's a literal date */
2106
+ s++;
2107
+ if ((r=ParseLiteralDateOrTime(&s, &dse, &tim)) != 0) {
2108
+ Eprint("%s: %s", GetErr(r), DBufValue(&ExprBuf));
2109
+ return r;
2110
+ }
2111
+ if (*s != '\'') {
2112
+ if (dse != NO_DATE) {
2113
+ Eprint("%s: %s", GetErr(E_BAD_DATE), DBufValue(&ExprBuf));
2114
+ return E_BAD_DATE;
2115
+ } else {
2116
+ Eprint("%s: %s", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
2117
+ return E_BAD_TIME;
2118
+ }
2119
+ }
2120
+ if (tim == NO_TIME) {
2121
+ atom->u.value.type = DATE_TYPE;
2122
+ atom->u.value.v.val = dse;
2123
+ } else if (dse == NO_DATE) {
2124
+ atom->u.value.type = TIME_TYPE;
2125
+ atom->u.value.v.val = tim;
2126
+ } else {
2127
+ atom->u.value.type = DATETIME_TYPE;
2128
+ atom->u.value.v.val = (dse * MINUTES_PER_DAY) + tim;
2129
+ }
2130
+ return OK;
2131
+ } else if (isdigit(*s)) { /* It's a number or time */
2132
+ atom->u.value.type = INT_TYPE;
2133
+ val = 0;
2134
+ prev_val = 0;
2135
+ if (*s == '0' && (*(s+1) == 'x' || *(s+1) == 'X')) {
2136
+ /* Hex constant */
2137
+ s += 2;
2138
+ if (!*s || !isxdigit(*s)) {
2139
+ return E_BAD_NUMBER;
2140
+ }
2141
+ while (*s && isxdigit(*s)) {
2142
+ val *= 16;
2143
+ if (*s >= '0' && *s <= '9') {
2144
+ val += (*s - '0');
2145
+ } else {
2146
+ val += (toupper(*s) - 'A') + 10;
2147
+ }
2148
+ s++;
2149
+ if (val < prev_val) {
2150
+ return E_2HIGH;
2151
+ }
2152
+ prev_val = val;
2153
+ }
2154
+ if (*s) {
2155
+ return E_BAD_NUMBER;
2156
+ }
2157
+ atom->u.value.v.val = val;
2158
+ return OK;
2159
+ }
2160
+ while (*s && isdigit(*s)) {
2161
+ val *= 10;
2162
+ val += (*s++ - '0');
2163
+ if (val < prev_val) {
2164
+ /* We overflowed */
2165
+ return E_2HIGH;
2166
+ }
2167
+ prev_val = val;
2168
+ }
2169
+ if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
2170
+ s++;
2171
+ if (!isdigit(*s)) {
2172
+ Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
2173
+ return E_BAD_TIME;
2174
+ }
2175
+ h = val;
2176
+ m = 0;
2177
+ while (isdigit(*s)) {
2178
+ m *= 10;
2179
+ m += *s - '0';
2180
+ s++;
2181
+ }
2182
+ /* Check for p[m] or a[m] */
2183
+ if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
2184
+ ampm = tolower(*s);
2185
+ s++;
2186
+ if (*s == 'm' || *s == 'M') {
2187
+ s++;
2188
+ }
2189
+ }
2190
+ if (*s || h>23 || m>59) {
2191
+ Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
2192
+ return E_BAD_TIME;
2193
+ }
2194
+ if (ampm) {
2195
+ if (h < 1 || h > 12) {
2196
+ Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
2197
+ return E_BAD_TIME;
2198
+ }
2199
+ if (ampm == 'a') {
2200
+ if (h == 12) {
2201
+ h = 0;
2202
+ }
2203
+ } else if (ampm == 'p') {
2204
+ if (h < 12) {
2205
+ h += 12;
2206
+ }
2207
+ }
2208
+ }
2209
+ atom->u.value.type = TIME_TYPE;
2210
+ atom->u.value.v.val = h*60 + m;
2211
+ return OK;
2212
+ }
2213
+ /* Not a time - must be a number */
2214
+ if (*s) {
2215
+ Eprint("%s: `%s'", GetErr(E_BAD_NUMBER), DBufValue(&ExprBuf));
2216
+ return E_BAD_NUMBER;
2217
+ }
2218
+ atom->u.value.type = INT_TYPE;
2219
+ atom->u.value.v.val = val;
2220
+ return OK;
2221
+ }
2222
+
2223
+ atom->u.value.type = ERR_TYPE;
2224
+ if (strchr(LEGAL_CHARS, *s) != NULL) {
2225
+ r = E_EXPECTING_ATOM;
2226
+ } else {
2227
+ r = E_ILLEGAL_CHAR;
2228
+ }
2229
+ Eprint("`%s': %s", DBufValue(&ExprBuf), GetErr(r));
2230
+ return r;
2231
+ }
2232
+
2233
+ /***************************************************************/
2234
+ /* */
2235
+ /* make_atom - create a constant, variable, system variable */
2236
+ /* or local variable node. */
2237
+ /* */
2238
+ /***************************************************************/
2239
+ static int make_atom(expr_node *atom, Var *locals)
2240
+ {
2241
+ int r;
2242
+ int i = 0;
2243
+ Var *v = locals;
2244
+ char const *s = DBufValue(&ExprBuf);
2245
+ /* Variable */
2246
+ if (isalpha(*s) || *s == '_') {
2247
+ while(v) {
2248
+ if (! strncasecmp(s, v->name, VAR_NAME_LEN)) {
2249
+ atom->type = N_LOCAL_VAR;
2250
+ atom->u.arg = i;
2251
+ return OK;
2252
+ }
2253
+ v = v->link.next;
2254
+ i++;
2255
+ }
2256
+ if (strlen(s) < SHORT_NAME_BUF) {
2257
+ atom->type = N_SHORT_VAR;
2258
+ strcpy(atom->u.name, s);
2259
+ } else {
2260
+ if (set_long_name(atom, s) != OK) {
2261
+ return E_NO_MEM;
2262
+ }
2263
+ atom->type = N_VARIABLE;
2264
+ }
2265
+ return OK;
2266
+ }
2267
+
2268
+ /* System Variable */
2269
+ if (*(s) == '$' && isalpha(*(s+1))) {
2270
+ SysVar const *v = FindSysVar(s+1);
2271
+ if (!v) {
2272
+ Eprint("%s: `%s'", GetErr(E_NOSUCH_VAR), s);
2273
+ return E_NOSUCH_VAR;
2274
+ }
2275
+ atom->type = N_SYSVAR;
2276
+ atom->u.sysvar = v;
2277
+ return OK;
2278
+ }
2279
+
2280
+ /* Constant */
2281
+ r = set_constant_value(atom);
2282
+ if (r != OK) {
2283
+ atom->type = N_ERROR;
2284
+ }
2285
+ return r;
2286
+ }
2287
+
2288
+ /***************************************************************/
2289
+ /* */
2290
+ /* Parse an atom. */
2291
+ /* */
2292
+ /* ATOM: '(' EXPR ')' | */
2293
+ /* CONSTANT | */
2294
+ /* VAR | */
2295
+ /* FUNCTION_CALL */
2296
+ /* */
2297
+ /***************************************************************/
2298
+ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
2299
+ {
2300
+ expr_node *node;
2301
+ char const *s;
2302
+ CHECK_PARSE_LEVEL();
2303
+ *r = PEEK_TOKEN();
2304
+ if (*r != OK) return NULL;
2305
+
2306
+ if (TOKEN_IS("(")) {
2307
+ /* Parenthesiszed expession: '(' EXPR ')' */
2308
+
2309
+ /* Pull off the peeked token */
2310
+ *r = GET_TOKEN();
2311
+ if (*r != OK) {
2312
+ return NULL;
2313
+ }
2314
+ node = parse_expression_aux(e, r, locals, level+1);
2315
+ if (*r != OK) {
2316
+ return NULL;
2317
+ }
2318
+ if (TOKEN_ISNOT(")")) {
2319
+ *r = E_MISS_RIGHT_PAREN;
2320
+ return free_expr_tree(node);
2321
+ }
2322
+ *r = GET_TOKEN();
2323
+ if (*r != OK) {
2324
+ return free_expr_tree(node);
2325
+ }
2326
+ return node;
2327
+ }
2328
+
2329
+ /* Check that it's a valid ID or constant */
2330
+ s = DBufValue(&ExprBuf);
2331
+ if (!*s) {
2332
+ Eprint("%s", GetErr(E_EOLN));
2333
+ *r = E_EOLN;
2334
+ return NULL;
2335
+ }
2336
+ if (!ISID(*s) &&
2337
+ *s != '$' &&
2338
+ *s != '"' &&
2339
+ *s != '\'') {
2340
+ if (strchr(LEGAL_CHARS, *s) != NULL) {
2341
+ *r = E_EXPECTING_ATOM;
2342
+ Eprint("%s", GetErr(*r));
2343
+ } else {
2344
+ *r = E_ILLEGAL_CHAR;
2345
+ Eprint("%s `%c'", GetErr(*r), *s);
2346
+ }
2347
+ return NULL;
2348
+ }
2349
+
2350
+ /* Is it a function call? */
2351
+ if (*(s + DBufLen(&ExprBuf) - 1) == '(') {
2352
+ return parse_function_call(e, r, locals, level+1);
2353
+ }
2354
+
2355
+ /* It's a constant or a variable reference */
2356
+ char const *olds = *e;
2357
+ *r = GET_TOKEN();
2358
+ if (*r != OK) return NULL;
2359
+ node = alloc_expr_node(r);
2360
+ if (!node) {
2361
+ return NULL;
2362
+ }
2363
+ *r = make_atom(node, locals);
2364
+ if (*r != OK) {
2365
+ /* Preserve location for error position when we print ^-- here */
2366
+ *e = olds;
2367
+ return free_expr_tree(node);
2368
+ }
2369
+ return node;
2370
+ }
2371
+
2372
+ /***************************************************************/
2373
+ /* */
2374
+ /* parse_factor - parse a factor */
2375
+ /* */
2376
+ /* FACTOR_EXP: '-' FACTOR_EXP | */
2377
+ /* '!' FACTOR_EXP | */
2378
+ /* '+' FACTOR_EXP */
2379
+ /* ATOM */
2380
+ /* */
2381
+ /***************************************************************/
2382
+ static expr_node *parse_factor(char const **e, int *r, Var *locals, int level)
2383
+ {
2384
+ expr_node *node;
2385
+ expr_node *factor_node;
2386
+ char op;
2387
+ CHECK_PARSE_LEVEL();
2388
+ *r = PEEK_TOKEN();
2389
+ if (*r != OK) {
2390
+ return NULL;
2391
+ }
2392
+ if (TOKEN_IS("!") || TOKEN_IS("-") || TOKEN_IS("+")) {
2393
+ if (TOKEN_IS("!")) {
2394
+ op = '!';
2395
+ } else if (TOKEN_IS("-")) {
2396
+ op = '-';
2397
+ } else {
2398
+ op = '+';
2399
+ }
2400
+ /* Pull off the peeked token */
2401
+ GET_TOKEN();
2402
+ node = parse_factor(e, r, locals, level+1);
2403
+ if (*r != OK) {
2404
+ return NULL;
2405
+ }
2406
+
2407
+ /* Ignore unary plus operator */
2408
+ if (op == '+') {
2409
+ return node;
2410
+ }
2411
+
2412
+ /* Optimize '-' or '!' followed by integer constant */
2413
+ if (node->type == N_CONSTANT &&node->u.value.type == INT_TYPE) {
2414
+ if (op == '-') {
2415
+ node->u.value.v.val = - node->u.value.v.val;
2416
+ } else {
2417
+ node->u.value.v.val = ! node->u.value.v.val;
2418
+ }
2419
+ return node;
2420
+ }
2421
+ factor_node = alloc_expr_node(r);
2422
+ if (!factor_node) {
2423
+ free_expr_tree(node);
2424
+ return NULL;
2425
+ }
2426
+ factor_node->type = N_OPERATOR;
2427
+ if (op == '!') {
2428
+ factor_node->u.operator_func = logical_not;
2429
+ } else {
2430
+ factor_node->u.operator_func = unary_minus;
2431
+ }
2432
+ add_child(factor_node, node);
2433
+ return factor_node;
2434
+ }
2435
+ return parse_atom(e, r, locals, level+1);
2436
+ }
2437
+
2438
+ /***************************************************************/
2439
+ /* */
2440
+ /* parse_term - parse a term */
2441
+ /* */
2442
+ /* TERM_EXP: FACTOR_EXP | */
2443
+ /* FACTOR_EXP '*' TERM_EXP | */
2444
+ /* FACTOR_EXP '/' TERM_EXP | */
2445
+ /* FACTOR_EXP '%' TERM_EXP */
2446
+ /* */
2447
+ /***************************************************************/
2448
+ static expr_node *parse_term_expr(char const **e, int *r, Var *locals, int level)
2449
+ {
2450
+ expr_node *node;
2451
+ expr_node *term_node;
2452
+ CHECK_PARSE_LEVEL();
2453
+
2454
+ node = parse_factor(e, r, locals, level+1);
2455
+ if (*r != OK) {
2456
+ return free_expr_tree(node);
2457
+ }
2458
+ *r = PEEK_TOKEN();
2459
+ if (*r != OK) {
2460
+ return free_expr_tree(node);
2461
+ }
2462
+
2463
+ while(TOKEN_IS("*") || TOKEN_IS("/") || TOKEN_IS("%")) {
2464
+ term_node = alloc_expr_node(r);
2465
+ if (!term_node) {
2466
+ return free_expr_tree(node);
2467
+ }
2468
+ term_node->type = N_OPERATOR;
2469
+ if (TOKEN_IS("*")) {
2470
+ term_node->u.operator_func = multiply;
2471
+ } else if (TOKEN_IS("/")) {
2472
+ term_node->u.operator_func = divide;
2473
+ } else {
2474
+ term_node->u.operator_func = do_mod;
2475
+ }
2476
+ add_child(term_node, node);
2477
+ *r = GET_TOKEN();
2478
+ if (*r != OK) {
2479
+ return free_expr_tree(term_node);
2480
+ }
2481
+ node = parse_factor(e, r, locals, level+1);
2482
+ if (*r != OK) {
2483
+ return free_expr_tree(term_node);
2484
+ }
2485
+ add_child(term_node, node);
2486
+ node = term_node;
2487
+ *r = PEEK_TOKEN();
2488
+ if (*r != OK) {
2489
+ return free_expr_tree(term_node);
2490
+ }
2491
+ }
2492
+ return node;
2493
+ }
2494
+
2495
+ /***************************************************************/
2496
+ /* */
2497
+ /* parse_cmp_expr - parse a cmp_expr */
2498
+ /* */
2499
+ /* CMP_EXP: TERM_EXP | */
2500
+ /* TERM_EXP '+' CMP_EXP | */
2501
+ /* TERM_EXP '-' CMP_EXP */
2502
+ /* */
2503
+ /***************************************************************/
2504
+ static expr_node *parse_cmp_expr(char const **e, int *r, Var *locals, int level)
2505
+ {
2506
+ expr_node *node;
2507
+ expr_node *cmp_node;
2508
+ CHECK_PARSE_LEVEL();
2509
+
2510
+ node = parse_term_expr(e, r, locals, level+1);
2511
+ if (*r != OK) {
2512
+ return free_expr_tree(node);
2513
+ }
2514
+ while(TOKEN_IS("+") || TOKEN_IS("-")) {
2515
+ cmp_node = alloc_expr_node(r);
2516
+ if (!cmp_node) {
2517
+ return free_expr_tree(node);
2518
+ }
2519
+ cmp_node->type = N_OPERATOR;
2520
+ if (TOKEN_IS("+")) {
2521
+ cmp_node->u.operator_func = add;
2522
+ } else {
2523
+ cmp_node->u.operator_func = subtract;
2524
+ }
2525
+ add_child(cmp_node, node);
2526
+ *r = GET_TOKEN();
2527
+ if (*r != OK) {
2528
+ return free_expr_tree(cmp_node);
2529
+ }
2530
+ node = parse_term_expr(e, r, locals, level+1);
2531
+ if (*r != OK) {
2532
+ return free_expr_tree(cmp_node);
2533
+ }
2534
+ add_child(cmp_node, node);
2535
+ node = cmp_node;
2536
+ }
2537
+ return node;
2538
+ }
2539
+
2540
+ /***************************************************************/
2541
+ /* */
2542
+ /* parse_eq_expr - parse an eq_expr */
2543
+ /* */
2544
+ /* EQ_EXP: CMP_EXP | */
2545
+ /* CMP_EXP '<' EQ_EXP | */
2546
+ /* CMP_EXP '>' EQ_EXP | */
2547
+ /* CMP_EXP '<=' EQ_EXP | */
2548
+ /* CMP_EXP '<=' EQ_EXP */
2549
+ /* */
2550
+ /***************************************************************/
2551
+ static expr_node *parse_eq_expr(char const **e, int *r, Var *locals, int level)
2552
+ {
2553
+ expr_node *node;
2554
+ expr_node *eq_node;
2555
+ CHECK_PARSE_LEVEL();
2556
+
2557
+ node = parse_cmp_expr(e, r, locals, level+1);
2558
+ if (*r != OK) {
2559
+ return free_expr_tree(node);
2560
+ }
2561
+ while(TOKEN_IS("<=") || TOKEN_IS(">=") || TOKEN_IS("<") || TOKEN_IS(">")) {
2562
+ eq_node = alloc_expr_node(r);
2563
+ if (!eq_node) {
2564
+ return free_expr_tree(node);
2565
+ }
2566
+ eq_node->type = N_OPERATOR;
2567
+ if (TOKEN_IS("<=")) {
2568
+ eq_node->u.operator_func = compare_le;
2569
+ } else if (TOKEN_IS(">=")) {
2570
+ eq_node->u.operator_func = compare_ge;
2571
+ } else if (TOKEN_IS("<")) {
2572
+ eq_node->u.operator_func = compare_lt;
2573
+ } else {
2574
+ eq_node->u.operator_func = compare_gt;
2575
+ }
2576
+ add_child(eq_node, node);
2577
+ *r = GET_TOKEN();
2578
+ if (*r != OK) {
2579
+ return free_expr_tree(eq_node);
2580
+ }
2581
+ node = parse_cmp_expr(e, r, locals, level+1);
2582
+ if (*r != OK) {
2583
+ free_expr_tree(eq_node);
2584
+ return free_expr_tree(node);
2585
+ }
2586
+ add_child(eq_node, node);
2587
+ node = eq_node;
2588
+ }
2589
+ return node;
2590
+ }
2591
+
2592
+ /***************************************************************/
2593
+ /* */
2594
+ /* parse_and_expr - parse an and_expr */
2595
+ /* */
2596
+ /* AND_EXP: EQ_EXP | */
2597
+ /* EQ_EXP '==' AND_EXP | */
2598
+ /* EQ_EXP '!=' AND_EXP */
2599
+ /* */
2600
+ /***************************************************************/
2601
+ static expr_node *parse_and_expr(char const **e, int *r, Var *locals, int level)
2602
+ {
2603
+ expr_node *node;
2604
+ expr_node *and_node;
2605
+ CHECK_PARSE_LEVEL();
2606
+
2607
+ node = parse_eq_expr(e, r, locals, level+1);
2608
+ if (*r != OK) {
2609
+ return free_expr_tree(node);
2610
+ }
2611
+ while(TOKEN_IS("==") || TOKEN_IS("!=")) {
2612
+ and_node = alloc_expr_node(r);
2613
+ if (!and_node) {
2614
+ return free_expr_tree(node);
2615
+ }
2616
+ and_node->type = N_OPERATOR;
2617
+ if (TOKEN_IS("==")) {
2618
+ and_node->u.operator_func = compare_eq;
2619
+ } else {
2620
+ and_node->u.operator_func = compare_ne;
2621
+ }
2622
+ add_child(and_node, node);
2623
+ *r = GET_TOKEN();
2624
+ if (*r != OK) {
2625
+ return free_expr_tree(and_node);
2626
+ }
2627
+ node = parse_eq_expr(e, r, locals, level+1);
2628
+ if (*r != OK) {
2629
+ return free_expr_tree(and_node);
2630
+ }
2631
+ add_child(and_node, node);
2632
+ node = and_node;
2633
+ }
2634
+ return node;
2635
+ }
2636
+
2637
+ /***************************************************************/
2638
+ /* */
2639
+ /* parse_or_expr - parse an or_expr */
2640
+ /* */
2641
+ /* OR_EXP: AND_EXP | */
2642
+ /* AND_EXP '&&' OR_EXP */
2643
+ /* */
2644
+ /***************************************************************/
2645
+ static expr_node *parse_or_expr(char const **e, int *r, Var *locals, int level)
2646
+ {
2647
+ expr_node *node;
2648
+ expr_node *logand_node;
2649
+ CHECK_PARSE_LEVEL();
2650
+
2651
+ node = parse_and_expr(e, r, locals, level+1);
2652
+
2653
+ if (*r != OK) {
2654
+ return free_expr_tree(node);
2655
+ }
2656
+
2657
+ while (TOKEN_IS("&&")) {
2658
+ *r = GET_TOKEN();
2659
+ if (*r != OK) {
2660
+ return free_expr_tree(node);
2661
+ }
2662
+ logand_node = alloc_expr_node(r);
2663
+ if (!logand_node) {
2664
+ return free_expr_tree(node);
2665
+ }
2666
+ logand_node->type = N_OPERATOR;
2667
+ logand_node->u.operator_func = logical_and;
2668
+ add_child(logand_node, node);
2669
+ node = parse_and_expr(e, r, locals, level+1);
2670
+ if (*r != OK) {
2671
+ free_expr_tree(logand_node);
2672
+ return free_expr_tree(node);
2673
+ }
2674
+ add_child(logand_node, node);
2675
+ node = logand_node;
2676
+ }
2677
+ return node;
2678
+ }
2679
+
2680
+ /***************************************************************/
2681
+ /* */
2682
+ /* parse_expression_aux - parse an EXPR */
2683
+ /* */
2684
+ /* EXPR: OR_EXP | */
2685
+ /* OR_EXP '||' EXPR */
2686
+ /* */
2687
+ /***************************************************************/
2688
+ static expr_node *parse_expression_aux(char const **e, int *r, Var *locals, int level)
2689
+ {
2690
+ expr_node *node;
2691
+ expr_node *logor_node;
2692
+ CHECK_PARSE_LEVEL();
2693
+
2694
+ node = parse_or_expr(e, r, locals, level+1);
2695
+
2696
+ if (*r != OK) {
2697
+ return free_expr_tree(node);
2698
+ }
2699
+ while (TOKEN_IS("||")) {
2700
+ *r = GET_TOKEN();
2701
+ if (*r != OK) {
2702
+ return free_expr_tree(node);
2703
+ }
2704
+ logor_node = alloc_expr_node(r);
2705
+ if (!logor_node) {
2706
+ return free_expr_tree(node);
2707
+ }
2708
+ logor_node->type = N_OPERATOR;
2709
+ logor_node->u.operator_func = logical_or;
2710
+ add_child(logor_node, node);
2711
+ node = parse_or_expr(e, r, locals, level+1);
2712
+ if (*r != OK) {
2713
+ free_expr_tree(logor_node);
2714
+ return free_expr_tree(node);
2715
+ }
2716
+ add_child(logor_node, node);
2717
+ node = logor_node;
2718
+ }
2719
+ return node;
2720
+ }
2721
+
2722
+ /***************************************************************/
2723
+ /* */
2724
+ /* parse_expression - top-level expression-parsing function */
2725
+ /* */
2726
+ /* *e points to string being parsed; *e will be updated */
2727
+ /* r points to a location for the return code (OK or an error) */
2728
+ /* locals is an array of local function arguments, if any */
2729
+ /* */
2730
+ /* Returns a parsed expr_node or NULL on error */
2731
+ /* */
2732
+ /***************************************************************/
2733
+ expr_node *parse_expression(char const **e, int *r, Var *locals)
2734
+ {
2735
+ char const *orig = *e;
2736
+ char const *o2 = *e;
2737
+ char const *end_of_expr;
2738
+ if (ExpressionEvaluationDisabled) {
2739
+ *r = E_EXPR_DISABLED;
2740
+ return NULL;
2741
+ }
2742
+
2743
+ expr_node *node = parse_expression_aux(e, r, locals, 0);
2744
+ if (DebugFlag & DB_PARSE_EXPR) {
2745
+ fprintf(ErrFp, "Parsed expression: ");
2746
+ while (*orig && orig != *e) {
2747
+ putc(*orig, ErrFp);
2748
+ orig++;
2749
+ }
2750
+ putc('\n', ErrFp);
2751
+ if (*r != OK) {
2752
+ fprintf(ErrFp, " => Error: %s\n", GetErr(*r));
2753
+ } else {
2754
+ fprintf(ErrFp, " => ");
2755
+ print_expr_tree(node, ErrFp);
2756
+ fprintf(ErrFp, "\n");
2757
+ }
2758
+ orig = o2;
2759
+ }
2760
+ while (**e && isempty(**e)) {
2761
+ (*e)++;
2762
+ }
2763
+ if (**e && (**e != ']')) {
2764
+ if (DebugFlag & DB_PARSE_EXPR) {
2765
+ fprintf(ErrFp, " Unparsed: %s\n", *e);
2766
+ }
2767
+ if (*r == OK) {
2768
+ *r = E_EXPECTING_EOXPR;
2769
+ }
2770
+ }
2771
+ if (*r != OK) {
2772
+ if (node) {
2773
+ free_expr_tree(node);
2774
+ node = NULL;
2775
+ }
2776
+ }
2777
+ if (!SuppressErrorOutputInCatch) {
2778
+ if (*r == E_EXPECT_COMMA ||
2779
+ *r == E_MISS_RIGHT_PAREN ||
2780
+ *r == E_EXPECTING_EOL ||
2781
+ *r == E_2MANY_ARGS ||
2782
+ *r == E_2FEW_ARGS ||
2783
+ *r == E_PARSE_ERR ||
2784
+ *r == E_EOLN ||
2785
+ *r == E_EXPECTING_EOXPR ||
2786
+ *r == E_BAD_NUMBER ||
2787
+ *r == E_BAD_DATE ||
2788
+ *r == E_BAD_TIME ||
2789
+ *r == E_EXPECTING_ATOM ||
2790
+ *r == E_ILLEGAL_CHAR) {
2791
+ end_of_expr = find_end_of_expr(orig);
2792
+ while (**e && isempty(**e)) {
2793
+ (*e)++;
2794
+ }
2795
+ while (*orig && ((orig < end_of_expr) || (orig <= *e))) {
2796
+ if (*orig == '\n') {
2797
+ fprintf(ErrFp, " ");
2798
+ } else {
2799
+ fprintf(ErrFp, "%c", *orig);
2800
+ }
2801
+ orig++;
2802
+ }
2803
+ fprintf(ErrFp, "\n");
2804
+ orig = o2;
2805
+ while (*orig && (orig < *e || isspace(*orig))) {
2806
+ orig++;
2807
+ fprintf(ErrFp, " ");
2808
+ }
2809
+ fprintf(ErrFp, "^-- %s\n", tr("here"));
2810
+ }
2811
+ }
2812
+ return node;
2813
+ }
2814
+
2815
+
2816
+ /***************************************************************/
2817
+ /* */
2818
+ /* print_kids - print all of this node's children to a file, */
2819
+ /* recursively. Used for debugging. */
2820
+ /* */
2821
+ /***************************************************************/
2822
+ static void print_kids(expr_node *node, FILE *fp)
2823
+ {
2824
+ int done = 0;
2825
+ expr_node *kid = node->child;
2826
+ while(kid) {
2827
+ if (done) {
2828
+ fprintf(fp, " ");
2829
+ }
2830
+ done=1;
2831
+ print_expr_tree(kid, fp);
2832
+ kid = kid->sibling;
2833
+ }
2834
+ }
2835
+
2836
+ /***************************************************************/
2837
+ /* */
2838
+ /* print_expr_tree - print the entire expression tree to a */
2839
+ /* file. Used for debugging (the "-ds" flag.) */
2840
+ /* */
2841
+ /***************************************************************/
2842
+ static void print_expr_tree(expr_node *node, FILE *fp)
2843
+ {
2844
+ if (!node) {
2845
+ return;
2846
+ }
2847
+ switch(node->type) {
2848
+ case N_CONSTANT:
2849
+ PrintValue(&(node->u.value), fp);
2850
+ return;
2851
+ case N_SHORT_STR:
2852
+ fprintf(fp, "\"%s\"", node->u.name);
2853
+ return;
2854
+ case N_SHORT_VAR:
2855
+ case N_VARIABLE:
2856
+ fprintf(fp, "%s", node_str(node));
2857
+ return;
2858
+ case N_SYSVAR:
2859
+ fprintf(fp, "$%s", node_str(node));
2860
+ return;
2861
+ case N_LOCAL_VAR:
2862
+ fprintf(fp, "arg[%d]", node->u.arg);
2863
+ return;
2864
+ case N_BUILTIN_FUNC:
2865
+ fprintf(fp, "(%c%s",
2866
+ toupper(*(node->u.builtin_func->name)),
2867
+ node->u.builtin_func->name+1);
2868
+ if (node->child) fprintf(fp, " ");
2869
+ print_kids(node, fp);
2870
+ fprintf(fp, ")");
2871
+ return;
2872
+ case N_SHORT_USER_FUNC:
2873
+ case N_USER_FUNC:
2874
+ fprintf(fp, "(%s", node_str(node));
2875
+ if (node->child) fprintf(fp, " ");
2876
+ print_kids(node, fp);
2877
+ fprintf(fp, ")");
2878
+ return;
2879
+ case N_OPERATOR:
2880
+ fprintf(fp, "(%s ", get_operator_name(node));
2881
+ print_kids(node, fp);
2882
+ fprintf(fp, ")");
2883
+ return;
2884
+ default:
2885
+ return;
2886
+ }
2887
+ }
2888
+
2889
+ /***************************************************************/
2890
+ /* */
2891
+ /* get_operator_name - given an expr_node of type N_OPERATOR, */
2892
+ /* return a string representation of the operator. */
2893
+ /* */
2894
+ /***************************************************************/
2895
+ static char const *get_operator_name(expr_node *node)
2896
+ {
2897
+ int (*f)(expr_node *node, Value *locals, Value *ans, int *nonconst) = node->u.operator_func;
2898
+ if (f == logical_not) return "!";
2899
+ else if (f == unary_minus) return "-";
2900
+ else if (f == multiply) return "*";
2901
+ else if (f == divide) return "/";
2902
+ else if (f == do_mod) return "%";
2903
+ else if (f == add) return "+";
2904
+ else if (f == subtract) return "-";
2905
+ else if (f == compare_le) return "<=";
2906
+ else if (f == compare_ge) return ">=";
2907
+ else if (f == compare_lt) return "<";
2908
+ else if (f == compare_gt) return ">";
2909
+ else if (f == compare_eq) return "==";
2910
+ else if (f == compare_ne) return "!=";
2911
+ else if (f == logical_and) return "&&";
2912
+ else if (f == logical_or) return "||";
2913
+ else return "UNKNOWN_OPERATOR";
2914
+ }
2915
+
2916
+ /***************************************************************/
2917
+ /* */
2918
+ /* EvalExprRunDisabled - parse and evaluate an expression */
2919
+ /* */
2920
+ /* Evaluate an expression. Return 0 if OK, non-zero if error */
2921
+ /* Put the result into value pointed to by v. During */
2922
+ /* evaluation, RUN will be disabled */
2923
+ /* */
2924
+ /***************************************************************/
2925
+ int EvalExprRunDisabled(char const **e, Value *v, ParsePtr p)
2926
+ {
2927
+ int old_run_disabled = RunDisabled;
2928
+ int r;
2929
+ RunDisabled |= RUN_CB;
2930
+ r = EvalExpr(e, v, p);
2931
+ RunDisabled = old_run_disabled;
2932
+ return r;
2933
+ }
2934
+
2935
+ /***************************************************************/
2936
+ /* */
2937
+ /* EvalExpr - parse and evaluate an expression. */
2938
+ /* */
2939
+ /* Evaluate an expression. Return 0 if OK, non-zero if error */
2940
+ /* Put the result into value pointed to by v. */
2941
+ /* */
2942
+ /***************************************************************/
2943
+ int EvalExpr(char const **e, Value *v, ParsePtr p)
2944
+ {
2945
+ int r;
2946
+ int nonconst = 0;
2947
+
2948
+ /* Parse */
2949
+ expr_node *n = parse_expression(e, &r, NULL);
2950
+ if (r != OK) {
2951
+ return r;
2952
+ }
2953
+
2954
+ /* Evaluate */
2955
+ r = evaluate_expression(n, NULL, v, &nonconst);
2956
+
2957
+ /* Throw away the parsed tree */
2958
+ free_expr_tree(n);
2959
+ if (r != OK) {
2960
+ return r;
2961
+ }
2962
+ if (nonconst) {
2963
+ if (p) {
2964
+ p->nonconst_expr = 1;
2965
+ }
2966
+ }
2967
+ return r;
2968
+ }
2969
+
2970
+ /* Truncate a wide-char string to MAX_PRT_LEN characters */
2971
+ static char const *truncate_string(char const *src)
2972
+ {
2973
+ static wchar_t wbuf[MAX_PRT_LEN+1];
2974
+ static char cbuf[(MAX_PRT_LEN * 8) + 1];
2975
+ size_t l;
2976
+
2977
+ l = mbstowcs(wbuf, src, MAX_PRT_LEN);
2978
+ if (l == (size_t) -1) {
2979
+ return src;
2980
+ }
2981
+ wbuf[MAX_PRT_LEN] = 0;
2982
+ l = wcstombs(cbuf, wbuf, MAX_PRT_LEN*8);
2983
+ if (l == (size_t) -1) {
2984
+ return src;
2985
+ }
2986
+ cbuf[MAX_PRT_LEN*8] = 0;
2987
+ return cbuf;
2988
+ }
2989
+
2990
+ /***************************************************************/
2991
+ /* */
2992
+ /* PrintValue */
2993
+ /* */
2994
+ /* Print or stringify a value for debugging purposes. */
2995
+ /* */
2996
+ /***************************************************************/
2997
+ static DynamicBuffer printbuf = {NULL, 0, 0, ""};
2998
+
2999
+ #define PV_PUTC(fp, c) do { if (fp) { putc((c), fp); } else { DBufPutc(&printbuf, (c)); } } while(0);
3000
+
3001
+ char const *PrintValue (Value const *v, FILE *fp)
3002
+ {
3003
+ int y, m, d;
3004
+ unsigned char const *s;
3005
+ int max_str_put = MAX_PRT_LEN;
3006
+ int truncated = 0;
3007
+ char pvbuf[512];
3008
+ if (!fp) {
3009
+ /* It's OK to DBufFree an uninitialized *BUT STATIC* dynamic buffer */
3010
+ DBufFree(&printbuf);
3011
+ }
3012
+
3013
+ if (v->type == STR_TYPE) {
3014
+ s = (unsigned char const *) truncate_string(v->v.str);
3015
+ if (s != (unsigned char const *) v->v.str) {
3016
+ max_str_put = INT_MAX;
3017
+ if (strlen((char const *) s) != strlen(v->v.str)) {
3018
+ truncated = 1;
3019
+ }
3020
+ }
3021
+ PV_PUTC(fp, '"');
3022
+ for (y=0; y<max_str_put && *s; y++) {
3023
+ switch(*s) {
3024
+ case '\a': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'a'); break;
3025
+ case '\b': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'b'); break;
3026
+ case '\f': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'f'); break;
3027
+ case '\n': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'n'); break;
3028
+ case '\r': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'r'); break;
3029
+ case '\t': PV_PUTC(fp, '\\'); PV_PUTC(fp, 't'); break;
3030
+ case '\v': PV_PUTC(fp, '\\'); PV_PUTC(fp, 'v'); break;
3031
+ case '"': PV_PUTC(fp, '\\'); PV_PUTC(fp, '"'); break;
3032
+ case '\\': PV_PUTC(fp, '\\'); PV_PUTC(fp, '\\'); break;
3033
+ default:
3034
+ if (*s < 32) {
3035
+ if (fp) {
3036
+ fprintf(fp, "\\x%02x", (unsigned int) *s);
3037
+ } else {
3038
+ snprintf(pvbuf, sizeof(pvbuf), "\\x%02x", (unsigned int) *s);
3039
+ DBufPuts(&printbuf, pvbuf);
3040
+ }
3041
+ } else {
3042
+ PV_PUTC(fp, *s); break;
3043
+ }
3044
+ }
3045
+ s++;
3046
+ }
3047
+ PV_PUTC(fp, '"');
3048
+ if (*s || truncated) {
3049
+ if (fp) {
3050
+ fprintf(fp, "...");
3051
+ } else {
3052
+ DBufPuts(&printbuf, "...");
3053
+ }
3054
+ }
3055
+ }
3056
+ else if (v->type == INT_TYPE) {
3057
+ if (fp) {
3058
+ fprintf(fp, "%d", v->v.val);
3059
+ } else {
3060
+ snprintf(pvbuf, sizeof(pvbuf), "%d", v->v.val);
3061
+ DBufPuts(&printbuf, pvbuf);
3062
+ }
3063
+ } else if (v->type == TIME_TYPE) {
3064
+ if (fp) {
3065
+ fprintf(fp, "%02d%c%02d", v->v.val / 60,
3066
+ TimeSep, v->v.val % 60);
3067
+ } else {
3068
+ snprintf(pvbuf, sizeof(pvbuf), "%02d%c%02d", v->v.val / 60,
3069
+ TimeSep, v->v.val % 60);
3070
+ DBufPuts(&printbuf, pvbuf);
3071
+ }
3072
+ } else if (v->type == DATE_TYPE) {
3073
+ FromDSE(v->v.val, &y, &m, &d);
3074
+ if (fp) {
3075
+ fprintf(fp, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
3076
+ } else {
3077
+ snprintf(pvbuf, sizeof(pvbuf), "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
3078
+ DBufPuts(&printbuf, pvbuf);
3079
+ }
3080
+ } else if (v->type == DATETIME_TYPE) {
3081
+ FromDSE(v->v.val / MINUTES_PER_DAY, &y, &m, &d);
3082
+ if (fp) {
3083
+ fprintf(fp, "%04d%c%02d%c%02d%c%02d%c%02d", y, DateSep, m+1, DateSep, d, DateTimeSep,
3084
+ (v->v.val % MINUTES_PER_DAY) / 60, TimeSep, (v->v.val % MINUTES_PER_DAY) % 60);
3085
+ } else {
3086
+ snprintf(pvbuf, sizeof(pvbuf), "%04d%c%02d%c%02d%c%02d%c%02d", y, DateSep, m+1, DateSep, d, DateTimeSep,
3087
+ (v->v.val % MINUTES_PER_DAY) / 60, TimeSep, (v->v.val % MINUTES_PER_DAY) % 60);
3088
+ DBufPuts(&printbuf, pvbuf);
3089
+ }
3090
+ } else {
3091
+ if (fp) {
3092
+ fprintf(fp, "ERR");
3093
+ } else {
3094
+ DBufPuts(&printbuf, "ERR");
3095
+ }
3096
+ }
3097
+ if (fp) {
3098
+ return NULL;
3099
+ } else {
3100
+ return DBufValue(&printbuf);
3101
+ }
3102
+ }
3103
+
3104
+ /***************************************************************/
3105
+ /* */
3106
+ /* CopyValue */
3107
+ /* */
3108
+ /* Copy a value. If value is a string, strdups the string. */
3109
+ /* */
3110
+ /***************************************************************/
3111
+ int CopyValue(Value *dest, const Value *src)
3112
+ {
3113
+ dest->type = ERR_TYPE;
3114
+ if (src->type == STR_TYPE) {
3115
+ dest->v.str = strdup(src->v.str);
3116
+ if (!dest->v.str) return E_NO_MEM;
3117
+ } else {
3118
+ dest->v.val = src->v.val;
3119
+ }
3120
+ dest->type = src->type;
3121
+ return OK;
3122
+ }
3123
+
3124
+ /***************************************************************/
3125
+ /* */
3126
+ /* ParseLiteralTime - parse a literal time like 11:15 or */
3127
+ /* 4:00PM */
3128
+ /* */
3129
+ /***************************************************************/
3130
+ static int ParseLiteralTime(char const **s, int *tim)
3131
+ {
3132
+ int h=0;
3133
+ int m=0;
3134
+ int ampm=0;
3135
+ if (!isdigit(**s)) return E_BAD_TIME;
3136
+ while(isdigit(**s)) {
3137
+ h *= 10;
3138
+ h += *(*s)++ - '0';
3139
+ }
3140
+ if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
3141
+ (*s)++;
3142
+ if (!isdigit(**s)) return E_BAD_TIME;
3143
+ while(isdigit(**s)) {
3144
+ m *= 10;
3145
+ m += *(*s)++ - '0';
3146
+ }
3147
+ /* Check for p[m] or a[m] */
3148
+ if (**s == 'A' || **s == 'a' || **s == 'P' || **s == 'p') {
3149
+ ampm = tolower(**s);
3150
+ (*s)++;
3151
+ if (**s == 'm' || **s == 'M') {
3152
+ (*s)++;
3153
+ }
3154
+ }
3155
+ if (h>23 || m>59) return E_BAD_TIME;
3156
+ if (ampm) {
3157
+ if (h < 1 || h > 12) return E_BAD_TIME;
3158
+ if (ampm == 'a') {
3159
+ if (h == 12) {
3160
+ h = 0;
3161
+ }
3162
+ } else if (ampm == 'p') {
3163
+ if (h < 12) {
3164
+ h += 12;
3165
+ }
3166
+ }
3167
+ }
3168
+ *tim = h * 60 + m;
3169
+ return OK;
3170
+ }
3171
+
3172
+ /***************************************************************/
3173
+ /* */
3174
+ /* ParseLiteralDateOrTime */
3175
+ /* */
3176
+ /* Parse a literal date or datetime. Return result in dse */
3177
+ /* and tim; update s. */
3178
+ /* */
3179
+ /***************************************************************/
3180
+ int ParseLiteralDateOrTime(char const **s, int *dse, int *tim)
3181
+ {
3182
+ int y, m, d;
3183
+ int r;
3184
+
3185
+ char const *orig_s = *s;
3186
+
3187
+ y=0; m=0; d=0;
3188
+
3189
+ *tim = NO_TIME;
3190
+ *dse = NO_DATE;
3191
+ if (!isdigit(**s)) return E_BAD_DATE;
3192
+ while (isdigit(**s)) {
3193
+ y *= 10;
3194
+ y += *(*s)++ - '0';
3195
+ }
3196
+ if (**s == ':' || **s == '.' || **s == TimeSep) {
3197
+ *s = orig_s;
3198
+ return ParseLiteralTime(s, tim);
3199
+ }
3200
+ if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE;
3201
+ (*s)++;
3202
+ if (!isdigit(**s)) return E_BAD_DATE;
3203
+ while (isdigit(**s)) {
3204
+ m *= 10;
3205
+ m += *(*s)++ - '0';
3206
+ }
3207
+ m--;
3208
+ if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE;
3209
+ (*s)++;
3210
+ if (!isdigit(**s)) return E_BAD_DATE;
3211
+ while (isdigit(**s)) {
3212
+ d *= 10;
3213
+ d += *(*s)++ - '0';
3214
+ }
3215
+ if (!DateOK(y, m, d)) return E_BAD_DATE;
3216
+
3217
+ *dse = DSE(y, m, d);
3218
+
3219
+ /* Do we have a time part as well? */
3220
+ if (**s == ' ' || **s == '@' || **s == 'T' || **s == 't') {
3221
+ (*s)++;
3222
+ r = ParseLiteralTime(s, tim);
3223
+ if (r != OK) return r;
3224
+ }
3225
+ return OK;
3226
+ }
3227
+
3228
+ /***************************************************************/
3229
+ /* */
3230
+ /* DoCoerce - actually coerce a value to the specified type. */
3231
+ /* */
3232
+ /***************************************************************/
3233
+ int DoCoerce(char type, Value *v)
3234
+ {
3235
+ int h, d, m, y, i, k;
3236
+ char const *s;
3237
+
3238
+ char coerce_buf[128];
3239
+
3240
+ /* Do nothing if value is already the right type */
3241
+ if (type == v->type) return OK;
3242
+
3243
+ switch(type) {
3244
+ case DATETIME_TYPE:
3245
+ switch(v->type) {
3246
+ case INT_TYPE:
3247
+ v->type = DATETIME_TYPE;
3248
+ return OK;
3249
+ case DATE_TYPE:
3250
+ v->type = DATETIME_TYPE;
3251
+ v->v.val *= MINUTES_PER_DAY;
3252
+ return OK;
3253
+ case STR_TYPE:
3254
+ s = v->v.str;
3255
+ if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
3256
+ if (i == NO_DATE) return E_CANT_COERCE;
3257
+ if (*s) return E_CANT_COERCE;
3258
+ v->type = DATETIME_TYPE;
3259
+ free(v->v.str);
3260
+ if (m == NO_TIME) m = 0;
3261
+ v->v.val = i * MINUTES_PER_DAY + m;
3262
+ return OK;
3263
+ default:
3264
+ return E_CANT_COERCE;
3265
+ }
3266
+ case STR_TYPE:
3267
+ switch(v->type) {
3268
+ case INT_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%d", v->v.val); break;
3269
+ case TIME_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%02d%c%02d", v->v.val / 60,
3270
+ TimeSep, v->v.val % 60);
3271
+ break;
3272
+ case DATE_TYPE: FromDSE(v->v.val, &y, &m, &d);
3273
+ snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d",
3274
+ y, DateSep, m+1, DateSep, d);
3275
+ break;
3276
+ case DATETIME_TYPE:
3277
+ i = v->v.val / MINUTES_PER_DAY;
3278
+ FromDSE(i, &y, &m, &d);
3279
+ k = v->v.val % MINUTES_PER_DAY;
3280
+ h = k / 60;
3281
+ i = k % 60;
3282
+ snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d%c%02d%c%02d",
3283
+ y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
3284
+ break;
3285
+ default: return E_CANT_COERCE;
3286
+ }
3287
+ v->type = STR_TYPE;
3288
+ v->v.str = strdup(coerce_buf);
3289
+ if (!v->v.str) {
3290
+ v->type = ERR_TYPE;
3291
+ return E_NO_MEM;
3292
+ }
3293
+ return OK;
3294
+
3295
+ case INT_TYPE:
3296
+ i = 0;
3297
+ m = 1;
3298
+ switch(v->type) {
3299
+ case STR_TYPE:
3300
+ s = v->v.str;
3301
+ if (*s == '-') {
3302
+ m = -1;
3303
+ s++;
3304
+ }
3305
+ while(*s && isdigit(*s)) {
3306
+ i *= 10;
3307
+ i += (*s++) - '0';
3308
+ }
3309
+ if (*s) {
3310
+ free (v->v.str);
3311
+ v->type = ERR_TYPE;
3312
+ return E_CANT_COERCE;
3313
+ }
3314
+ free(v->v.str);
3315
+ v->type = INT_TYPE;
3316
+ v->v.val = i * m;
3317
+ return OK;
3318
+
3319
+ case DATE_TYPE:
3320
+ case TIME_TYPE:
3321
+ case DATETIME_TYPE:
3322
+ v->type = INT_TYPE;
3323
+ return OK;
3324
+
3325
+ default: return E_CANT_COERCE;
3326
+ }
3327
+
3328
+ case DATE_TYPE:
3329
+ switch(v->type) {
3330
+ case INT_TYPE:
3331
+ if(v->v.val >= 0) {
3332
+ v->type = DATE_TYPE;
3333
+ return OK;
3334
+ } else return E_2LOW;
3335
+
3336
+ case STR_TYPE:
3337
+ s = v->v.str;
3338
+ if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
3339
+ if (i == NO_DATE) return E_CANT_COERCE;
3340
+ if (*s) return E_CANT_COERCE;
3341
+ v->type = DATE_TYPE;
3342
+ free(v->v.str);
3343
+ v->v.val = i;
3344
+ return OK;
3345
+
3346
+ case DATETIME_TYPE:
3347
+ v->type = DATE_TYPE;
3348
+ v->v.val /= MINUTES_PER_DAY;
3349
+ return OK;
3350
+
3351
+ default: return E_CANT_COERCE;
3352
+ }
3353
+
3354
+ case TIME_TYPE:
3355
+ switch(v->type) {
3356
+ case INT_TYPE:
3357
+ case DATETIME_TYPE:
3358
+ v->type = TIME_TYPE;
3359
+ v->v.val %= MINUTES_PER_DAY;
3360
+ if (v->v.val < 0) v->v.val += MINUTES_PER_DAY;
3361
+ return OK;
3362
+
3363
+ case STR_TYPE:
3364
+ s = v->v.str;
3365
+ i=0; /* Avoid compiler warning */
3366
+ if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
3367
+ if (*s) return E_CANT_COERCE;
3368
+ v->type = TIME_TYPE;
3369
+ free(v->v.str);
3370
+ v->v.val = i;
3371
+ return OK;
3372
+
3373
+ default: return E_CANT_COERCE;
3374
+ }
3375
+ default: return E_CANT_COERCE;
3376
+ }
3377
+ }
3378
+
3379
+ /***************************************************************/
3380
+ /* */
3381
+ /* print_expr_nodes_stats - print statistics about expr_node */
3382
+ /* allocation. */
3383
+ /* */
3384
+ /* This is a debugging routine that prints data about */
3385
+ /* expr_node allocation on program exit */
3386
+ /* */
3387
+ /***************************************************************/
3388
+ void print_expr_nodes_stats(void)
3389
+ {
3390
+ fprintf(ErrFp, " Expression nodes allocated: %d\n", ExprNodesAllocated);
3391
+ fprintf(ErrFp, "Expression nodes high-water: %d\n", ExprNodesHighWater);
3392
+ fprintf(ErrFp, " Expression nodes leaked: %d\n", ExprNodesUsed);
3393
+ fprintf(ErrFp, " Parse level high-water: %d\n", parse_level_high_water);
3394
+ }
3395
+
3396
+ /* Return 1 if a value is "true" for its type, 0 if "false" */
3397
+ int truthy(Value const *v)
3398
+ {
3399
+ if (v->type == STR_TYPE) {
3400
+ if (v->v.str && *(v->v.str)) {
3401
+ return 1;
3402
+ } else {
3403
+ return 0;
3404
+ }
3405
+ }
3406
+
3407
+ return (v->v.val != 0);
3408
+ }