taskjuggler 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (544) hide show
  1. data/CHANGELOG +2086 -0
  2. data/benchmarks/666tasks.tjp +3183 -0
  3. data/benchmarks/booking.tjp +14 -10
  4. data/doc/AppConfig.html +95 -73
  5. data/doc/Arguments.html +22 -2
  6. data/doc/CHANGELOG.html +2587 -0
  7. data/doc/COPYING.html +21 -1
  8. data/doc/Object.html +161 -122
  9. data/doc/README.html +21 -1
  10. data/doc/RuntimeConfig.html +26 -6
  11. data/doc/String.html +38 -18
  12. data/doc/StringIO.html +579 -0
  13. data/doc/TaskJuggler.html +251 -143
  14. data/doc/TaskJuggler/Account.html +26 -6
  15. data/doc/TaskJuggler/AccountAttribute.html +28 -8
  16. data/doc/TaskJuggler/AccountScenario.html +24 -4
  17. data/doc/TaskJuggler/Allocation.html +30 -10
  18. data/doc/TaskJuggler/AllocationAttribute.html +28 -8
  19. data/doc/TaskJuggler/AttributeBase.html +46 -26
  20. data/doc/TaskJuggler/AttributeDefinition.html +22 -2
  21. data/doc/TaskJuggler/BatchProcessor.html +40 -20
  22. data/doc/TaskJuggler/Booking.html +26 -6
  23. data/doc/TaskJuggler/BookingListAttribute.html +28 -8
  24. data/doc/TaskJuggler/BooleanAttribute.html +28 -8
  25. data/doc/TaskJuggler/CSVFile.html +308 -146
  26. data/doc/TaskJuggler/CellSettingPattern.html +22 -2
  27. data/doc/TaskJuggler/CellSettingPatternList.html +26 -6
  28. data/doc/TaskJuggler/Charge.html +26 -6
  29. data/doc/TaskJuggler/ChargeListAttribute.html +26 -6
  30. data/doc/TaskJuggler/ChargeSet.html +33 -13
  31. data/doc/TaskJuggler/ChargeSetListAttribute.html +28 -8
  32. data/doc/TaskJuggler/ColumnListAttribute.html +26 -6
  33. data/doc/TaskJuggler/ColumnTable.html +24 -4
  34. data/doc/TaskJuggler/Daemon.html +26 -6
  35. data/doc/TaskJuggler/DateAttribute.html +26 -6
  36. data/doc/TaskJuggler/DefinitionListAttribute.html +22 -2
  37. data/doc/TaskJuggler/DependencyListAttribute.html +28 -8
  38. data/doc/TaskJuggler/DurationAttribute.html +28 -8
  39. data/doc/TaskJuggler/FixnumAttribute.html +24 -4
  40. data/doc/TaskJuggler/FlagListAttribute.html +28 -8
  41. data/doc/TaskJuggler/FloatAttribute.html +26 -6
  42. data/doc/TaskJuggler/FormatListAttribute.html +24 -4
  43. data/doc/TaskJuggler/GanttChart.html +147 -126
  44. data/doc/TaskJuggler/GanttContainer.html +34 -14
  45. data/doc/TaskJuggler/GanttHeader.html +28 -8
  46. data/doc/TaskJuggler/GanttHeaderScaleItem.html +24 -4
  47. data/doc/TaskJuggler/GanttLine.html +38 -18
  48. data/doc/TaskJuggler/GanttLoadStack.html +26 -6
  49. data/doc/TaskJuggler/GanttMilestone.html +34 -14
  50. data/doc/TaskJuggler/GanttRouter.html +50 -30
  51. data/doc/TaskJuggler/GanttTaskBar.html +34 -14
  52. data/doc/TaskJuggler/HTMLDocument.html +26 -6
  53. data/doc/TaskJuggler/HTMLGraphics.html +30 -10
  54. data/doc/TaskJuggler/Interval.html +40 -22
  55. data/doc/TaskJuggler/IntervalListAttribute.html +28 -8
  56. data/doc/TaskJuggler/JobInfo.html +24 -4
  57. data/doc/TaskJuggler/Journal.html +226 -147
  58. data/doc/TaskJuggler/JournalEntry.html +22 -2
  59. data/doc/TaskJuggler/JournalEntryList.html +129 -112
  60. data/doc/TaskJuggler/KeywordArray.html +26 -6
  61. data/doc/TaskJuggler/KeywordDocumentation.html +46 -26
  62. data/doc/TaskJuggler/Limits.html +152 -123
  63. data/doc/TaskJuggler/Limits/Limit.html +149 -70
  64. data/doc/TaskJuggler/LimitsAttribute.html +36 -51
  65. data/doc/TaskJuggler/ListAttributeBase.html +24 -4
  66. data/doc/TaskJuggler/Log.html +50 -32
  67. data/doc/TaskJuggler/LogFile.html +37 -17
  68. data/doc/TaskJuggler/LogicalAttribute.html +53 -33
  69. data/doc/TaskJuggler/LogicalExpression.html +26 -6
  70. data/doc/TaskJuggler/LogicalExpressionAttribute.html +32 -12
  71. data/doc/TaskJuggler/LogicalFlag.html +42 -22
  72. data/doc/TaskJuggler/LogicalFunction.html +204 -140
  73. data/doc/TaskJuggler/LogicalOperation.html +135 -111
  74. data/doc/TaskJuggler/Macro.html +22 -2
  75. data/doc/TaskJuggler/MacroParser.html +32 -12
  76. data/doc/TaskJuggler/MacroTable.html +32 -12
  77. data/doc/TaskJuggler/ManagerResponsibilities.html +24 -4
  78. data/doc/TaskJuggler/ManagerStatusRecord.html +24 -4
  79. data/doc/TaskJuggler/Message.html +24 -4
  80. data/doc/TaskJuggler/MessageHandler.html +24 -4
  81. data/doc/TaskJuggler/Navigator.html +104 -71
  82. data/doc/TaskJuggler/NavigatorElement.html +32 -12
  83. data/doc/TaskJuggler/NikuProject.html +22 -2
  84. data/doc/TaskJuggler/NikuReport.html +310 -228
  85. data/doc/TaskJuggler/NikuResource.html +22 -2
  86. data/doc/TaskJuggler/NodeListAttribute.html +615 -0
  87. data/doc/TaskJuggler/OnShiftCache.html +32 -12
  88. data/doc/TaskJuggler/ProcessIntercom.html +205 -78
  89. data/doc/TaskJuggler/ProcessIntercomIface.html +26 -6
  90. data/doc/TaskJuggler/Project.html +708 -660
  91. data/doc/TaskJuggler/ProjectBroker.html +506 -304
  92. data/doc/TaskJuggler/ProjectBrokerIface.html +61 -41
  93. data/doc/TaskJuggler/ProjectFileParser.html +429 -373
  94. data/doc/TaskJuggler/ProjectFileScanner.html +1790 -0
  95. data/doc/TaskJuggler/ProjectRecord.html +80 -60
  96. data/doc/TaskJuggler/ProjectServer.html +312 -237
  97. data/doc/TaskJuggler/ProjectServerIface.html +101 -43
  98. data/doc/TaskJuggler/PropertyAttribute.html +32 -12
  99. data/doc/TaskJuggler/PropertyList.html +166 -145
  100. data/doc/TaskJuggler/PropertySet.html +254 -224
  101. data/doc/TaskJuggler/PropertyTreeNode.html +670 -536
  102. data/doc/TaskJuggler/Query.html +169 -148
  103. data/doc/TaskJuggler/RTFHandlers.html +622 -0
  104. data/doc/TaskJuggler/RTFNavigator.html +28 -8
  105. data/doc/TaskJuggler/RTFQuery.html +40 -20
  106. data/doc/TaskJuggler/RTFReport.html +62 -25
  107. data/doc/TaskJuggler/RTFReportLink.html +765 -0
  108. data/doc/TaskJuggler/RealFormat.html +26 -6
  109. data/doc/TaskJuggler/RealFormatAttribute.html +26 -6
  110. data/doc/TaskJuggler/ReferenceAttribute.html +59 -39
  111. data/doc/TaskJuggler/Report.html +402 -251
  112. data/doc/TaskJuggler/ReportBase.html +162 -137
  113. data/doc/TaskJuggler/ReportContext.html +112 -29
  114. data/doc/TaskJuggler/ReportServer.html +89 -64
  115. data/doc/TaskJuggler/ReportServerIface.html +75 -55
  116. data/doc/TaskJuggler/ReportServerRecord.html +54 -31
  117. data/doc/TaskJuggler/ReportServlet.html +980 -0
  118. data/doc/TaskJuggler/ReportTable.html +41 -21
  119. data/doc/TaskJuggler/ReportTableCell.html +214 -170
  120. data/doc/TaskJuggler/ReportTableColumn.html +30 -10
  121. data/doc/TaskJuggler/ReportTableLegend.html +36 -16
  122. data/doc/TaskJuggler/ReportTableLine.html +32 -12
  123. data/doc/TaskJuggler/Resource.html +99 -87
  124. data/doc/TaskJuggler/ResourceListAttribute.html +59 -39
  125. data/doc/TaskJuggler/ResourceListRE.html +47 -26
  126. data/doc/TaskJuggler/ResourceScenario.html +403 -437
  127. data/doc/TaskJuggler/RichText.html +26 -6
  128. data/doc/TaskJuggler/RichTextAttribute.html +50 -30
  129. data/doc/TaskJuggler/RichTextDocument.html +37 -17
  130. data/doc/TaskJuggler/RichTextElement.html +475 -413
  131. data/doc/TaskJuggler/RichTextException.html +22 -2
  132. data/doc/TaskJuggler/RichTextFunctionExample.html +28 -8
  133. data/doc/TaskJuggler/RichTextFunctionHandler.html +24 -4
  134. data/doc/TaskJuggler/RichTextImage.html +22 -2
  135. data/doc/TaskJuggler/RichTextIntermediate.html +38 -18
  136. data/doc/TaskJuggler/RichTextParser.html +56 -34
  137. data/doc/TaskJuggler/RichTextScanner.html +82 -61
  138. data/doc/TaskJuggler/RichTextSnip.html +34 -14
  139. data/doc/TaskJuggler/RichTextSyntaxRules.html +507 -353
  140. data/doc/TaskJuggler/Scenario.html +22 -2
  141. data/doc/TaskJuggler/ScenarioData.html +30 -46
  142. data/doc/TaskJuggler/ScenarioListAttribute.html +38 -18
  143. data/doc/TaskJuggler/Scoreboard.html +42 -22
  144. data/doc/TaskJuggler/SheetHandlerBase.html +40 -20
  145. data/doc/TaskJuggler/SheetReceiver.html +333 -295
  146. data/doc/TaskJuggler/SheetSender.html +253 -230
  147. data/doc/TaskJuggler/Shift.html +26 -6
  148. data/doc/TaskJuggler/ShiftAssignment.html +89 -73
  149. data/doc/TaskJuggler/ShiftAssignments.html +226 -234
  150. data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +39 -54
  151. data/doc/TaskJuggler/ShiftScenario.html +28 -8
  152. data/doc/TaskJuggler/SortListAttribute.html +34 -14
  153. data/doc/TaskJuggler/SourceFileInfo.html +24 -4
  154. data/doc/TaskJuggler/StatusSheetReceiver.html +24 -3
  155. data/doc/TaskJuggler/StatusSheetReport.html +168 -153
  156. data/doc/TaskJuggler/StatusSheetSender.html +24 -3
  157. data/doc/TaskJuggler/StringAttribute.html +38 -18
  158. data/doc/TaskJuggler/SymbolAttribute.html +32 -12
  159. data/doc/TaskJuggler/SyntaxReference.html +40 -20
  160. data/doc/TaskJuggler/TOCEntry.html +26 -6
  161. data/doc/TaskJuggler/TSResourceRecord.html +22 -2
  162. data/doc/TaskJuggler/TSTaskRecord.html +22 -2
  163. data/doc/TaskJuggler/TableColumnDefinition.html +59 -22
  164. data/doc/TaskJuggler/TableOfContents.html +26 -6
  165. data/doc/TaskJuggler/TableReport.html +937 -904
  166. data/doc/TaskJuggler/Task.html +55 -36
  167. data/doc/TaskJuggler/TaskDependency.html +24 -4
  168. data/doc/TaskJuggler/TaskListAttribute.html +50 -30
  169. data/doc/TaskJuggler/TaskListRE.html +27 -7
  170. data/doc/TaskJuggler/TaskScenario.html +1273 -1153
  171. data/doc/TaskJuggler/TextFormatter.html +28 -8
  172. data/doc/TaskJuggler/TextParser.html +585 -338
  173. data/doc/TaskJuggler/TextParser/Pattern.html +54 -34
  174. data/doc/TaskJuggler/TextParser/Rule.html +95 -73
  175. data/doc/TaskJuggler/TextParser/StackElement.html +39 -17
  176. data/doc/TaskJuggler/TextParser/TextParserResultArray.html +24 -4
  177. data/doc/TaskJuggler/TextParser/TokenDoc.html +22 -2
  178. data/doc/TaskJuggler/TextReport.html +28 -8
  179. data/doc/TaskJuggler/TextScanner.html +400 -1404
  180. data/doc/TaskJuggler/TextScanner/BufferStreamHandle.html +28 -240
  181. data/doc/TaskJuggler/TextScanner/FileStreamHandle.html +37 -184
  182. data/doc/TaskJuggler/TextScanner/MacroStackEntry.html +682 -0
  183. data/doc/TaskJuggler/TextScanner/StreamHandle.html +342 -67
  184. data/doc/TaskJuggler/TimeSheet.html +48 -28
  185. data/doc/TaskJuggler/TimeSheetReceiver.html +24 -3
  186. data/doc/TaskJuggler/TimeSheetRecord.html +47 -27
  187. data/doc/TaskJuggler/TimeSheetReport.html +154 -133
  188. data/doc/TaskJuggler/TimeSheetSender.html +24 -3
  189. data/doc/TaskJuggler/TimeSheetSummary.html +137 -91
  190. data/doc/TaskJuggler/TimeSheets.html +26 -6
  191. data/doc/TaskJuggler/Tj3AppBase.html +85 -58
  192. data/doc/TaskJuggler/Tj3Client.html +292 -238
  193. data/doc/TaskJuggler/Tj3Daemon.html +159 -74
  194. data/doc/TaskJuggler/Tj3SheetAppBase.html +26 -6
  195. data/doc/TaskJuggler/Tj3SsReceiver.html +26 -6
  196. data/doc/TaskJuggler/Tj3SsSender.html +53 -26
  197. data/doc/TaskJuggler/Tj3TsReceiver.html +28 -7
  198. data/doc/TaskJuggler/Tj3TsSender.html +26 -6
  199. data/doc/TaskJuggler/Tj3TsSummary.html +26 -6
  200. data/doc/TaskJuggler/TjException.html +22 -2
  201. data/doc/TaskJuggler/TjTime.html +216 -160
  202. data/doc/TaskJuggler/TjpExample.html +34 -14
  203. data/doc/TaskJuggler/TjpExportRE.html +403 -407
  204. data/doc/TaskJuggler/TjpSyntaxRules.html +4805 -4408
  205. data/doc/TaskJuggler/URLParameter.html +649 -0
  206. data/doc/TaskJuggler/UserManual.html +42 -22
  207. data/doc/TaskJuggler/WebServer.html +702 -0
  208. data/doc/TaskJuggler/WorkingHours.html +38 -18
  209. data/doc/TaskJuggler/WorkingHoursAttribute.html +61 -41
  210. data/doc/TaskJuggler/XMLBlob.html +24 -4
  211. data/doc/TaskJuggler/XMLComment.html +24 -4
  212. data/doc/TaskJuggler/XMLDocument.html +30 -10
  213. data/doc/TaskJuggler/XMLElement.html +34 -14
  214. data/doc/TaskJuggler/XMLNamedText.html +22 -2
  215. data/doc/TaskJuggler/XMLText.html +24 -4
  216. data/doc/index.html +1841 -1666
  217. data/doc/lib/AccountScenario_rb.html +1 -1
  218. data/doc/lib/Account_rb.html +1 -1
  219. data/doc/lib/Allocation_rb.html +1 -1
  220. data/doc/lib/AppConfig_rb.html +2 -2
  221. data/doc/lib/AttributeBase_rb.html +1 -1
  222. data/doc/lib/AttributeDefinition_rb.html +1 -1
  223. data/doc/lib/Attributes_rb.html +2 -2
  224. data/doc/lib/BatchProcessor_rb.html +1 -1
  225. data/doc/lib/Booking_rb.html +1 -1
  226. data/doc/lib/ChargeSet_rb.html +1 -1
  227. data/doc/lib/Charge_rb.html +1 -1
  228. data/doc/lib/HTMLDocument_rb.html +1 -1
  229. data/doc/lib/Interval_rb.html +1 -1
  230. data/doc/lib/Journal_rb.html +2 -2
  231. data/doc/lib/KeywordArray_rb.html +1 -1
  232. data/doc/lib/KeywordDocumentation_rb.html +1 -1
  233. data/doc/lib/Limits_rb.html +2 -2
  234. data/doc/lib/LogFile_rb.html +2 -2
  235. data/doc/lib/Log_rb.html +1 -1
  236. data/doc/lib/LogicalExpression_rb.html +1 -1
  237. data/doc/lib/LogicalFunction_rb.html +2 -2
  238. data/doc/lib/LogicalOperation_rb.html +2 -2
  239. data/doc/lib/MacroParser_rb.html +1 -1
  240. data/doc/lib/MacroTable_rb.html +1 -1
  241. data/doc/lib/MessageHandler_rb.html +1 -1
  242. data/doc/lib/Message_rb.html +1 -1
  243. data/doc/lib/ProjectFileParser_rb.html +4 -8
  244. data/doc/lib/ProjectFileScanner_rb.html +67 -0
  245. data/doc/lib/Project_rb.html +2 -2
  246. data/doc/lib/PropertyList_rb.html +2 -2
  247. data/doc/lib/PropertySet_rb.html +2 -2
  248. data/doc/lib/PropertyTreeNode_rb.html +2 -2
  249. data/doc/lib/Query_rb.html +2 -2
  250. data/doc/lib/RTFHandlers_rb.html +73 -0
  251. data/doc/lib/RTFNavigator_rb.html +1 -1
  252. data/doc/lib/RTFQuery_rb.html +1 -1
  253. data/doc/lib/RTFReportLink_rb.html +71 -0
  254. data/doc/lib/RTFReport_rb.html +2 -2
  255. data/doc/lib/RealFormat_rb.html +1 -1
  256. data/doc/lib/ResourceScenario_rb.html +2 -2
  257. data/doc/lib/Resource_rb.html +2 -2
  258. data/doc/lib/RichTextDocument_rb.html +1 -1
  259. data/doc/lib/RichTextElement_rb.html +2 -2
  260. data/doc/lib/RichTextFunctionExample_rb.html +1 -1
  261. data/doc/lib/RichTextFunctionHandler_rb.html +1 -1
  262. data/doc/lib/RichTextParser_rb.html +2 -2
  263. data/doc/lib/RichTextScanner_rb.html +2 -2
  264. data/doc/lib/RichTextSnip_rb.html +1 -1
  265. data/doc/lib/RichTextSyntaxRules_rb.html +2 -2
  266. data/doc/lib/RichText_rb.html +1 -1
  267. data/doc/lib/RuntimeConfig_rb.html +1 -1
  268. data/doc/lib/ScenarioData_rb.html +2 -2
  269. data/doc/lib/Scenario_rb.html +1 -1
  270. data/doc/lib/Scoreboard_rb.html +1 -1
  271. data/doc/lib/SheetHandlerBase_rb.html +1 -1
  272. data/doc/lib/SheetReceiver_rb.html +2 -2
  273. data/doc/lib/SheetSender_rb.html +4 -2
  274. data/doc/lib/ShiftAssignments_rb.html +4 -2
  275. data/doc/lib/ShiftScenario_rb.html +1 -1
  276. data/doc/lib/Shift_rb.html +1 -1
  277. data/doc/lib/SourceFileInfo_rb.html +1 -1
  278. data/doc/lib/StatusSheetReceiver_rb.html +2 -2
  279. data/doc/lib/StatusSheetSender_rb.html +2 -2
  280. data/doc/lib/SyntaxReference_rb.html +1 -1
  281. data/doc/lib/TOCEntry_rb.html +1 -1
  282. data/doc/lib/TableColumnDefinition_rb.html +2 -2
  283. data/doc/lib/TableOfContents_rb.html +1 -1
  284. data/doc/lib/TaskDependency_rb.html +1 -1
  285. data/doc/lib/TaskJuggler_rb.html +2 -2
  286. data/doc/lib/TaskScenario_rb.html +2 -2
  287. data/doc/lib/Task_rb.html +2 -2
  288. data/doc/lib/TextFormatter_rb.html +1 -1
  289. data/doc/lib/TextParser/Pattern_rb.html +1 -1
  290. data/doc/lib/TextParser/Rule_rb.html +2 -2
  291. data/doc/lib/TextParser/StackElement_rb.html +2 -2
  292. data/doc/lib/TextParser/TokenDoc_rb.html +1 -1
  293. data/doc/lib/TextParser_rb.html +2 -2
  294. data/doc/lib/TextScanner_rb.html +6 -2
  295. data/doc/lib/TimeSheetReceiver_rb.html +2 -2
  296. data/doc/lib/TimeSheetSender_rb.html +2 -2
  297. data/doc/lib/TimeSheetSummary_rb.html +2 -2
  298. data/doc/lib/TimeSheets_rb.html +2 -2
  299. data/doc/lib/Tj3AppBase_rb.html +2 -2
  300. data/doc/lib/Tj3Config_rb.html +2 -2
  301. data/doc/lib/Tj3SheetAppBase_rb.html +2 -2
  302. data/doc/lib/TjException_rb.html +1 -1
  303. data/doc/lib/TjTime_rb.html +2 -2
  304. data/doc/lib/TjpExample_rb.html +1 -1
  305. data/doc/lib/TjpSyntaxRules_rb.html +2 -2
  306. data/doc/lib/URLParameter_rb.html +67 -0
  307. data/doc/lib/UTF8String_rb.html +1 -1
  308. data/doc/lib/UserManual_rb.html +1 -1
  309. data/doc/lib/WorkingHours_rb.html +1 -1
  310. data/doc/lib/XMLDocument_rb.html +2 -2
  311. data/doc/lib/XMLElement_rb.html +1 -1
  312. data/doc/lib/daemon/Daemon_rb.html +1 -1
  313. data/doc/lib/daemon/ProcessIntercom_rb.html +2 -2
  314. data/doc/lib/daemon/ProjectBroker_rb.html +4 -2
  315. data/doc/lib/daemon/ProjectServer_rb.html +2 -2
  316. data/doc/lib/daemon/ReportServer_rb.html +2 -2
  317. data/doc/lib/daemon/WebServer_rb.html +75 -0
  318. data/doc/lib/deep_copy_rb.html +2 -2
  319. data/doc/lib/reports/CSVFile_rb.html +2 -2
  320. data/doc/lib/reports/ColumnTable_rb.html +1 -1
  321. data/doc/lib/reports/GanttChart_rb.html +2 -2
  322. data/doc/lib/reports/GanttContainer_rb.html +1 -1
  323. data/doc/lib/reports/GanttHeaderScaleItem_rb.html +1 -1
  324. data/doc/lib/reports/GanttHeader_rb.html +1 -1
  325. data/doc/lib/reports/GanttLine_rb.html +1 -1
  326. data/doc/lib/reports/GanttLoadStack_rb.html +1 -1
  327. data/doc/lib/reports/GanttMilestone_rb.html +1 -1
  328. data/doc/lib/reports/GanttRouter_rb.html +1 -1
  329. data/doc/lib/reports/GanttTaskBar_rb.html +1 -1
  330. data/doc/lib/reports/HTMLGraphics_rb.html +1 -1
  331. data/doc/lib/reports/Navigator_rb.html +2 -2
  332. data/doc/lib/reports/NikuReport_rb.html +2 -2
  333. data/doc/lib/reports/ReportBase_rb.html +2 -2
  334. data/doc/lib/reports/ReportContext_rb.html +2 -2
  335. data/doc/lib/reports/ReportTableCell_rb.html +2 -2
  336. data/doc/lib/reports/ReportTableColumn_rb.html +1 -1
  337. data/doc/lib/reports/ReportTableLegend_rb.html +1 -1
  338. data/doc/lib/reports/ReportTableLine_rb.html +1 -1
  339. data/doc/lib/reports/ReportTable_rb.html +2 -2
  340. data/doc/lib/reports/Report_rb.html +2 -2
  341. data/doc/lib/reports/ResourceListRE_rb.html +2 -2
  342. data/doc/lib/reports/StatusSheetReport_rb.html +2 -2
  343. data/doc/lib/reports/TableReport_rb.html +2 -2
  344. data/doc/lib/reports/TaskListRE_rb.html +2 -2
  345. data/doc/lib/reports/TextReport_rb.html +1 -1
  346. data/doc/lib/reports/TimeSheetReport_rb.html +2 -2
  347. data/doc/lib/reports/TjpExportRE_rb.html +2 -2
  348. data/doc/lib/ruby-signal-bug_rb.html +1 -1
  349. data/doc/lib/taskjuggler3_rb.html +2 -2
  350. data/doc/lib/tj3client_rb.html +2 -2
  351. data/doc/lib/tj3d_rb.html +2 -2
  352. data/doc/lib/tj3man_rb.html +1 -1
  353. data/doc/lib/tj3ss_receiver_rb.html +1 -1
  354. data/doc/lib/tj3ss_sender_rb.html +2 -2
  355. data/doc/lib/tj3ts_receiver_rb.html +2 -2
  356. data/doc/lib/tj3ts_sender_rb.html +1 -1
  357. data/doc/lib/tj3ts_summary_rb.html +1 -1
  358. data/doc/rdoc.css +9 -4
  359. data/examples/tutorial.tjp +17 -15
  360. data/gem_spec.rb +3 -0
  361. data/lib/AppConfig.rb +3 -1
  362. data/lib/Attributes.rb +10 -8
  363. data/lib/Journal.rb +55 -20
  364. data/lib/Limits.rb +72 -46
  365. data/lib/LogFile.rb +3 -3
  366. data/lib/LogicalFunction.rb +19 -6
  367. data/lib/LogicalOperation.rb +5 -1
  368. data/lib/Project.rb +37 -9
  369. data/lib/ProjectFileParser.rb +25 -22
  370. data/lib/ProjectFileScanner.rb +365 -0
  371. data/lib/PropertyList.rb +2 -1
  372. data/lib/PropertySet.rb +14 -4
  373. data/lib/PropertyTreeNode.rb +42 -29
  374. data/lib/Query.rb +3 -1
  375. data/lib/RTFHandlers.rb +35 -0
  376. data/lib/RTFReport.rb +23 -6
  377. data/lib/RTFReportLink.rb +72 -0
  378. data/lib/Resource.rb +8 -16
  379. data/lib/ResourceScenario.rb +1 -22
  380. data/lib/RichTextElement.rb +42 -0
  381. data/lib/RichTextParser.rb +6 -4
  382. data/lib/RichTextScanner.rb +5 -5
  383. data/lib/RichTextSyntaxRules.rb +48 -10
  384. data/lib/ScenarioData.rb +5 -3
  385. data/lib/SheetReceiver.rb +24 -6
  386. data/lib/SheetSender.rb +17 -13
  387. data/lib/ShiftAssignments.rb +56 -52
  388. data/lib/StatusSheetReceiver.rb +1 -0
  389. data/lib/StatusSheetSender.rb +1 -0
  390. data/lib/TableColumnDefinition.rb +4 -2
  391. data/lib/Task.rb +8 -9
  392. data/lib/TaskJuggler.rb +21 -11
  393. data/lib/TaskScenario.rb +61 -26
  394. data/lib/TextParser.rb +268 -106
  395. data/lib/TextParser/Rule.rb +4 -2
  396. data/lib/TextParser/StackElement.rb +6 -4
  397. data/lib/TextScanner.rb +283 -700
  398. data/lib/TimeSheetReceiver.rb +1 -0
  399. data/lib/TimeSheetSender.rb +1 -0
  400. data/lib/TimeSheetSummary.rb +51 -26
  401. data/lib/TimeSheets.rb +1 -1
  402. data/lib/Tj3AppBase.rb +8 -1
  403. data/lib/Tj3Config.rb +1 -1
  404. data/lib/TjTime.rb +5 -0
  405. data/lib/TjpSyntaxRules.rb +360 -144
  406. data/lib/URLParameter.rb +30 -0
  407. data/lib/XMLDocument.rb +2 -2
  408. data/lib/daemon/ProcessIntercom.rb +50 -9
  409. data/lib/daemon/ProjectBroker.rb +63 -10
  410. data/lib/daemon/ProjectServer.rb +47 -16
  411. data/lib/daemon/ReportServer.rb +9 -4
  412. data/lib/daemon/WebServer.rb +204 -0
  413. data/lib/deep_copy.rb +4 -1
  414. data/lib/reports/CSVFile.rb +150 -66
  415. data/lib/reports/GanttChart.rb +2 -1
  416. data/lib/reports/Navigator.rb +18 -5
  417. data/lib/reports/NikuReport.rb +32 -2
  418. data/lib/reports/Report.rb +65 -37
  419. data/lib/reports/ReportBase.rb +14 -9
  420. data/lib/reports/ReportContext.rb +19 -4
  421. data/lib/reports/ReportTable.rb +2 -2
  422. data/lib/reports/ReportTableCell.rb +54 -30
  423. data/lib/reports/ResourceListRE.rb +4 -3
  424. data/lib/reports/StatusSheetReport.rb +8 -13
  425. data/lib/reports/TableReport.rb +47 -32
  426. data/lib/reports/TaskListRE.rb +3 -3
  427. data/lib/reports/TimeSheetReport.rb +14 -5
  428. data/lib/reports/TjpExportRE.rb +14 -19
  429. data/lib/taskjuggler3.rb +15 -0
  430. data/lib/tj3client.rb +9 -7
  431. data/lib/tj3d.rb +38 -10
  432. data/lib/tj3ss_sender.rb +7 -0
  433. data/lib/tj3ts_receiver.rb +1 -0
  434. data/manual/Day_To_Day_Juggling +1 -1
  435. data/manual/Rich_Text_Attributes +8 -0
  436. data/manual/TaskJuggler_2x_Migration +7 -0
  437. data/manual/The_TaskJuggler_Syntax +20 -6
  438. data/prj_cfg.rb +3 -2
  439. data/tasks/changelog.rake +36 -0
  440. data/tasks/csts.rake +2 -3
  441. data/tasks/gem.rake +10 -0
  442. data/tasks/missing.rake +0 -17
  443. data/test/TestSuite/ReportGenerator/Correct/Journal.html +63 -0
  444. data/test/TestSuite/ReportGenerator/Correct/Journal.tjp +14 -0
  445. data/test/TestSuite/{HTML-Reports/LogicalFunctions.tjp → ReportGenerator/Correct/LogicalFunctions1.tjp} +2 -2
  446. data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.csv +3 -0
  447. data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.tjp +19 -0
  448. data/test/TestSuite/ReportGenerator/Correct/css/tjmanual.css +66 -0
  449. data/test/TestSuite/ReportGenerator/Correct/css/tjreport.css +407 -0
  450. data/test/TestSuite/ReportGenerator/Correct/icons/details.png +0 -0
  451. data/test/TestSuite/ReportGenerator/Correct/icons/flag-green.png +0 -0
  452. data/test/TestSuite/ReportGenerator/Correct/icons/flag-red.png +0 -0
  453. data/test/TestSuite/ReportGenerator/Correct/icons/flag-yellow.png +0 -0
  454. data/test/TestSuite/ReportGenerator/Correct/icons/resource.png +0 -0
  455. data/test/TestSuite/ReportGenerator/Correct/icons/resourcegroup.png +0 -0
  456. data/test/TestSuite/ReportGenerator/Correct/icons/task.png +0 -0
  457. data/test/TestSuite/ReportGenerator/Correct/icons/taskgroup.png +0 -0
  458. data/test/TestSuite/ReportGenerator/Correct/icons/trend-down.png +0 -0
  459. data/test/TestSuite/ReportGenerator/Correct/icons/trend-flat.png +0 -0
  460. data/test/TestSuite/ReportGenerator/Correct/icons/trend-up.png +0 -0
  461. data/test/TestSuite/ReportGenerator/Correct/opennodes.csv +2 -0
  462. data/test/TestSuite/ReportGenerator/Correct/opennodes.tjp +26 -0
  463. data/test/TestSuite/ReportGenerator/Correct/refs/Journal-1.csv +6 -0
  464. data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions1-1.csv +7 -0
  465. data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions2-1.csv +2 -0
  466. data/test/TestSuite/ReportGenerator/Correct/refs/opennodes-1.csv +2 -0
  467. data/test/TestSuite/ReportGenerator/Correct/scripts/wz_tooltip.js +1301 -0
  468. data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.tjp +20 -0
  469. data/test/TestSuite/Scheduler/Correct/Container.html +349 -0
  470. data/test/TestSuite/Scheduler/Correct/Limits.tjp +11 -4
  471. data/test/TestSuite/Scheduler/Correct/Shift2.html +464 -150
  472. data/test/TestSuite/Scheduler/Correct/TimeSheet2.html +108 -0
  473. data/test/TestSuite/Scheduler/Correct/TimeSheet2.tjp +7 -0
  474. data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +14 -0
  475. data/test/TestSuite/Scheduler/Correct/css/tjreport.css +233 -21
  476. data/test/TestSuite/Scheduler/Correct/scripts/wz_tooltip.js +20 -20
  477. data/test/TestSuite/StatusSheetTemplates/project.tji +35 -0
  478. data/test/TestSuite/StatusSheetTemplates/project.tjp +56 -0
  479. data/test/TestSuite/StatusSheets/run +3 -2
  480. data/test/TestSuite/Syntax/Correct/Include.tjp +1 -1
  481. data/test/TestSuite/Syntax/Correct/Macro-1.tjp +1 -1
  482. data/test/TestSuite/Syntax/Correct/Macro-2.tjp +6 -0
  483. data/test/TestSuite/Syntax/Correct/Macro-3.tjp +14 -0
  484. data/test/TestSuite/Syntax/Correct/ResourcePrefix.html +32 -0
  485. data/test/TestSuite/Syntax/Correct/css/tjmanual.css +66 -0
  486. data/test/TestSuite/Syntax/Correct/css/tjreport.css +407 -0
  487. data/test/TestSuite/Syntax/Correct/icons/details.png +0 -0
  488. data/test/TestSuite/Syntax/Correct/icons/flag-green.png +0 -0
  489. data/test/TestSuite/Syntax/Correct/icons/flag-red.png +0 -0
  490. data/test/TestSuite/Syntax/Correct/icons/flag-yellow.png +0 -0
  491. data/test/TestSuite/Syntax/Correct/icons/resource.png +0 -0
  492. data/test/TestSuite/Syntax/Correct/icons/resourcegroup.png +0 -0
  493. data/test/TestSuite/Syntax/Correct/icons/task.png +0 -0
  494. data/test/TestSuite/Syntax/Correct/icons/taskgroup.png +0 -0
  495. data/test/TestSuite/Syntax/Correct/icons/trend-down.png +0 -0
  496. data/test/TestSuite/Syntax/Correct/icons/trend-flat.png +0 -0
  497. data/test/TestSuite/Syntax/Correct/icons/trend-up.png +0 -0
  498. data/test/TestSuite/Syntax/Correct/include/dir1/file2.tji +3 -0
  499. data/test/TestSuite/Syntax/Correct/include/dir1/file5.tji +2 -0
  500. data/test/TestSuite/Syntax/Correct/include/dir3/all.tji +3 -0
  501. data/test/TestSuite/Syntax/Correct/include/dir3/file1.tji +2 -0
  502. data/test/TestSuite/Syntax/Correct/include/dir3/file2.tji +1 -0
  503. data/test/TestSuite/Syntax/Correct/scripts/wz_tooltip.js +1301 -0
  504. data/test/TestSuite/Syntax/Correct/tutorial.tjp +13 -13
  505. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
  506. data/test/TestSuite/Syntax/Errors/include_recursion.tjp +1 -0
  507. data/test/TestSuite/Syntax/Errors/macro_stack_overflow.tjp +2 -1
  508. data/test/TestSuite/Syntax/Errors/{eof_in_istring1.tjp → no_token_match1.tjp} +2 -2
  509. data/test/TestSuite/Syntax/Errors/{eof_in_istring2.tjp → no_token_match2.tjp} +2 -2
  510. data/test/TestSuite/Syntax/Errors/{eof_in_istring3.tjp → no_token_match3.tjp} +1 -1
  511. data/test/TestSuite/Syntax/Errors/{eof_in_istring4.tjp → no_token_match4.tjp} +1 -1
  512. data/test/TestSuite/Syntax/Errors/{eof_in_istring5.tjp → no_token_match5.tjp} +1 -1
  513. data/test/TestSuite/Syntax/Errors/not_scheduled.tjp +13 -0
  514. data/test/TestSuite/Syntax/Errors/unsupported_token.tjp +1 -1
  515. data/test/TestSuite/TimeSheets/run +5 -5
  516. data/test/test_CSVFile.rb +75 -0
  517. data/test/test_Limits.rb +63 -5
  518. data/test/test_ProjectFileScanner.rb +163 -0
  519. data/test/test_ReportGenerator.rb +81 -0
  520. data/test/test_RichText.rb +21 -3
  521. data/test/test_Scheduler.rb +1 -1
  522. data/test/test_ShiftAssignments.rb +4 -4
  523. data/test/test_Syntax.rb +1 -1
  524. data/test/test_URLParameter.rb +30 -0
  525. metadata +126 -32
  526. data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +0 -8
  527. data/test/TestSuite/Syntax/Errors/bad_comment.tjp +0 -7
  528. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/boss_2002-03-01.tji +0 -36
  529. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev1_2002-03-01.tji +0 -48
  530. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev2_2002-03-01.tji +0 -67
  531. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev3_2002-03-01.tji +0 -67
  532. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/doc_2002-03-01.tji +0 -48
  533. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/resources.yml +0 -31
  534. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/test_2002-03-01.tji +0 -36
  535. data/test/TestSuite/TimeSheets/TimeSheetTemplates/acceptable_intervals +0 -1
  536. data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/all.tji +0 -1
  537. data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/dev2_2002-03-01.tji +0 -54
  538. data/test/TestSuite/TimeSheets/TimeSheets/all.tji +0 -2
  539. data/test/TestSuite/TimeSheets/receiver.log +0 -102
  540. data/test/TestSuite/TimeSheets/sender.log +0 -794
  541. data/test/TestSuite/TimeSheets/summary.log +0 -884
  542. data/test/TestSuite/TimeSheets/timesheets.log +0 -45
  543. data/test/TestSuite/TimeSheets/tj3d.log +0 -292
  544. data/test/test_TextScanner.rb +0 -95
@@ -120,8 +120,10 @@ class TaskJuggler::TextParser
120
120
  # Return the pattern of this rule that matches the given +token+. If no
121
121
  # pattern matches, return nil.
122
122
  def matchingPatternIndex(token)
123
- @transitions.length.times do |i|
124
- return i if @transitions[i].has_key?(token)
123
+ i = 0
124
+ @transitions.each do |t|
125
+ return i if t.has_key?(token)
126
+ i += 1
125
127
  end
126
128
 
127
129
  nil
@@ -25,20 +25,22 @@ class TaskJuggler::TextParser
25
25
  # called at the end to store the collected data. _sourceFileInfo_ is a
26
26
  # SourceFileInfo reference that describes the TextScanner position when the
27
27
  # rule was entered.
28
- def initialize(rule, function, sourceFileInfo)
28
+ def initialize(function)
29
29
  # This Array stores the collected values.
30
30
  @val = []
31
+ # Array to store the source file references for the collected values.
32
+ @sourceFileInfo = []
33
+ # Counter used for StackElement::store()
31
34
  @position = 0
32
- @rule = rule
35
+ # The method that will process the collected values.
33
36
  @function = function
34
- @sourceFileInfo = sourceFileInfo
35
37
  end
36
38
 
37
39
  # Store a collected value and move the position to the next pattern.
38
40
  def store(val, sourceFileInfo = nil)
39
41
  @val[@position] = val
42
+ @sourceFileInfo[@position] = sourceFileInfo
40
43
  @position += 1
41
- @sourceFileInfo = sourceFileInfo if sourceFileInfo
42
44
  end
43
45
 
44
46
  end
data/lib/TextScanner.rb CHANGED
@@ -10,6 +10,9 @@
10
10
  # published by the Free Software Foundation.
11
11
  #
12
12
 
13
+ require 'stringio'
14
+ require 'strscan'
15
+
13
16
  require 'UTF8String'
14
17
  require 'TjTime'
15
18
  require 'TjException'
@@ -20,10 +23,27 @@ require 'Log'
20
23
 
21
24
  class TaskJuggler
22
25
 
23
- # The TextScanner class can scan text files and chop then into tokens to be
24
- # used by a parser. Files can be nested. A file can include an other file.
26
+ # The TextScanner class is an abstract text scanner with support for nested
27
+ # include files and text macros. The tokenizer will operate on rules that
28
+ # must be provided by a derived class. The scanner is modal. Each mode
29
+ # operates only with the subset of token patterns that are assigned to the
30
+ # current mode. The current line is tracked accurately and can be used for
31
+ # error reporting. The scanner can operate on Strings or Files.
25
32
  class TextScanner
26
33
 
34
+ class MacroStackEntry
35
+
36
+ attr_reader :macro, :args, :text, :endPos
37
+
38
+ def initialize(macro, args, text, endPos)
39
+ @macro = macro
40
+ @args = args
41
+ @text = text
42
+ @endPos = endPos
43
+ end
44
+
45
+ end
46
+
27
47
  # This class is used to handle the low-level input operations. It knows
28
48
  # whether it deals with a text buffer or a file and abstracts this to the
29
49
  # TextScanner. For each nested file the scanner puts an StreamHandle on the
@@ -32,21 +52,102 @@ class TaskJuggler
32
52
  # completely processed.
33
53
  class StreamHandle
34
54
 
35
- attr_accessor :lineNo, :columnNo, :line, :charBuffer
36
- attr_reader :fileName
55
+ attr_reader :fileName, :macroStack
37
56
 
38
57
  def initialize
39
- @lineNo = 1
40
- @columnNo = 1
41
- @line = ""
42
- @charBuffer = []
43
58
  @fileName = nil
59
+ @stream = nil
60
+ @line = nil
61
+ @pos = 0
62
+ @endPos = 1
63
+ @scanner = nil
64
+ @wrapped = false
65
+ @macroStack = []
66
+ @nextMacroEnd = nil
67
+ end
68
+
69
+ def close
70
+ @stream = nil
71
+ end
72
+
73
+ def injectMacro(macro, args, text)
74
+ @nextMacroEnd = @pos + text.length
75
+ @line = @line[0, @pos] + text + @line[@pos..-1]
76
+ @scanner = StringScanner.new(@line)
77
+ @scanner.pos = @pos
78
+
79
+ # Simple detection for recursive macro calls.
80
+ return false if @macroStack.length > 20
81
+
82
+ @macroStack << MacroStackEntry.new(macro, args, text, @nextMacroEnd)
83
+ true
84
+ end
85
+
86
+ def scan(re)
87
+ # We read the file line by line with gets(). If we don't have a line
88
+ # yet or we've reached the end of a line, we get the next one.
89
+ if @scanner.nil? || @scanner.eos?
90
+ if (@line = @stream.gets)
91
+ # Update activity meter about every 1024 lines.
92
+ Log.activity if (@stream.lineno & 0x3FF) == 0
93
+ # Check for DOS or Mac end of line signatures.
94
+ if @line[-1] == ?\r
95
+ # Mac: Convert CR into LF
96
+ @line[-1] = ?\n
97
+ elsif @line[-2] == ?\r
98
+ # DOS: Convert CR+LF into LF
99
+ @line = @line.chomp + "\n"
100
+ end
101
+ else
102
+ # We've reached the end of the current file.
103
+ @scanner = nil
104
+ # Return special EOF symbol.
105
+ return :scannerEOF
106
+ end
107
+ @scanner = StringScanner.new(@line)
108
+ @wrapped = @line[-1] == ?\n
109
+ end
110
+ return nil if (token = @scanner.scan(re)).nil?
111
+ #puts "#{re.to_s[0..20]}: [#{token}]"
112
+
113
+ @pos = @scanner.pos
114
+ while @nextMacroEnd && @nextMacroEnd < @pos
115
+ @macroStack.pop
116
+ @nextMacroEnd = @macroStack.empty? ? nil : @macroStack.last.endPos
117
+ end
118
+
119
+ token
120
+ end
121
+
122
+ def peek(n)
123
+ @scanner ? @scanner.peek(n) : nil
124
+ end
125
+
126
+ def eof?
127
+ @stream.eof? && @scanner.eos?
44
128
  end
45
129
 
46
130
  def dirname
47
131
  @fileName ? File.dirname(@fileName) : ''
48
132
  end
49
133
 
134
+ # Return the number of the currently processed line.
135
+ def lineNo
136
+ # The IO object counts the lines for us by counting the gets() calls.
137
+ currentLine = @stream && @scanner ? @stream.lineno : 1
138
+ # If we've just read the LF, we have to add 1. The LF can only be the
139
+ # last character of the line.
140
+ currentLine += 1 if @wrapped && @line && @scanner && @scanner.eos?
141
+ currentLine
142
+ end
143
+
144
+ # Return the already processed part of the current line.
145
+ def line
146
+ return '' unless @line
147
+
148
+ @line[0..(@scanner.pos - 1)]
149
+ end
150
+
50
151
  end
51
152
 
52
153
  # Specialized version of StreamHandle for operations on files.
@@ -57,53 +158,14 @@ class TaskJuggler
57
158
  def initialize(fileName)
58
159
  super()
59
160
  @fileName = fileName.dup.untaint
60
- @file = fileName == '.' ? $stdin : File.new(@fileName, 'r')
61
- @bytes = 0
161
+ @stream = fileName == '.' ? $stdin : File.new(@fileName, 'r')
62
162
  Log << "Parsing file #{@fileName} ..."
63
163
  Log.startProgressMeter("Reading file #{fileName}")
64
164
  end
65
165
 
66
166
  def close
67
- @file.close unless @file == $stdin
68
- end
69
-
70
- def getc19
71
- Log.activity if @bytes & 0x3FFF == 0
72
-
73
- begin
74
- # This function converts CR+LF or CR into LF on the fly.
75
- if (c1 = @file.getc) == ?\r
76
- @bytes += 1
77
- # CR or CR/LF linebreaks
78
- if (c2 = @file.getc) == ?\n
79
- @bytes += 1
80
- # Ok, CR, LF
81
- return c2
82
- else
83
- # Just CR
84
- @file.ungetc(c2)
85
- return ?\n
86
- end
87
- else
88
- # This is for LF linebreaks and all other characters
89
- @bytes += 1
90
- return c1
91
- end
92
- rescue
93
- return nil
94
- end
95
- end
96
-
97
- def getc18
98
- c = getc19
99
- return nil if c.nil?
100
- '' << c
101
- end
102
-
103
- if RUBY_VERSION < '1.9.0'
104
- alias getc getc18
105
- else
106
- alias getc getc19
167
+ @stream.close unless @stream == $stdin
168
+ super
107
169
  end
108
170
 
109
171
  end
@@ -113,43 +175,10 @@ class TaskJuggler
113
175
 
114
176
  def initialize(buffer)
115
177
  super()
116
- @buffer = buffer
117
- @length = @buffer.length_utf8
118
- @pos = 0
119
- Log << "Parsing buffer #{@buffer[0, 20]} ..."
120
- end
121
-
122
- def close
123
- @buffer = nil
124
- end
125
-
126
- def getc18
127
- return nil if @pos >= @length
128
- '' << getc19
129
- end
130
-
131
- def getc19
132
- return nil if @pos >= @length
133
-
134
- # This function converts CR+LF or CR into LF on the fly.
135
- if (c = @buffer[@pos]) == "\r"
136
- # CR or CR+LF
137
- @pos += 1 if @buffer[@pos + 1] == "\n"
138
- c = "\n"
139
- end
140
- @pos += 1
141
- c
178
+ @stream = StringIO.new(buffer)
179
+ Log << "Parsing buffer #{buffer[0, 20]} ..."
142
180
  end
143
181
 
144
- if RUBY_VERSION < '1.9.0'
145
- alias getc getc18
146
- else
147
- alias getc getc19
148
- end
149
-
150
- def fileName
151
- ''
152
- end
153
182
  end
154
183
 
155
184
  # Create a new instance of TextScanner. _masterFile_ must be a String that
@@ -161,33 +190,78 @@ class TaskJuggler
161
190
  # This table contains all macros that may be expanded when found in the
162
191
  # text.
163
192
  @macroTable = MacroTable.new(messageHandler)
193
+ # The currently processed IO object.
194
+ @cf = nil
164
195
  # This Array stores the currently processed nested files. It's an Array
165
- # of Arrays. The nested Array consists of 3 elements, the @cf,
166
- # @tokenBuffer and the @pos of the file.
196
+ # of Arrays. The nested Array consists of 2 elements, the IO object and
197
+ # the @tokenBuffer.
167
198
  @fileStack = []
168
- # This Array stores the currently processed nested macros.
169
- @macroStack = []
170
- # In certain situation we want to ignore Macro replacement and this flag
171
- # is set to true.
172
- @ignoreMacros = false
199
+ # This flag is set if we have reached the end of a file. Since we will
200
+ # only know when the next new token is requested that the file is really
201
+ # done now, we have to use this flag.
202
+ @finishLastFile = false
203
+ # True if the scanner operates on a buffer.
173
204
  @fileNameIsBuffer = false
205
+ # A SourceFileInfo of the start of the currently processed token.
206
+ @startOfToken = nil
207
+ # Line number correction for error messages.
208
+ @lineDelta = 0
209
+ # Lists of regexps that describe the detectable tokens. The Arrays are
210
+ # grouped by mode.
211
+ @patternsByMode = { }
212
+ # The currently active scanner mode.
213
+ @scannerMode = nil
214
+ # Points to the currently active pattern set as defined by the mode.
215
+ @activePatterns = nil
216
+ end
217
+
218
+ # Add a new pattern to the scanner. _type_ is either nil for tokens that
219
+ # will be ignored, or some identifier that will be returned with each
220
+ # token of this type. _regExp_ is the RegExp that describes the token.
221
+ # _mode_ identifies the scanner mode where the pattern is active. If it's
222
+ # only a single mode, _mode_ specifies the mode directly. For multiple
223
+ # modes, it's an Array of modes. _postProc_ is a method reference. This
224
+ # method is called after the token has been detected. The method gets the
225
+ # type and the matching String and returns them again in an Array.
226
+ def addPattern(type, regExp, mode, postProc = nil)
227
+ if mode.is_a?(Array)
228
+ mode.each do |m|
229
+ # The pattern is active in multiple modes
230
+ @patternsByMode[m] = [] unless @patternsByMode.include?(m)
231
+ @patternsByMode[m] << [ type, regExp, postProc ]
232
+ end
233
+ else
234
+ # The pattern is only active in one specific mode.
235
+ @patternsByMode[mode] = [] unless @patternsByMode.include?(mode)
236
+ @patternsByMode[mode] << [ type, regExp, postProc ]
237
+ end
174
238
  end
175
239
 
240
+ # Switch the parser to another mode. The scanner will then only detect
241
+ # with pattens of that _newMode_.
242
+ def mode=(newMode)
243
+ #puts "**** New mode: #{newMode}"
244
+ @activePatterns = @patternsByMode[newMode]
245
+ raise "Undefined mode #{newMode}" unless @activePatterns
246
+ @scannerMode = newMode
247
+ end
248
+
249
+
176
250
  # Start the processing. if _fileNameIsBuffer_ is true, we operate on a
177
251
  # String, else on a File.
178
252
  def open(fileNameIsBuffer = false)
179
253
  @fileNameIsBuffer = fileNameIsBuffer
180
254
  if fileNameIsBuffer
181
- @fileStack = [ [ @cf = BufferStreamHandle.new(@masterFile), nil, nil ] ]
255
+ @fileStack = [ [ @cf = BufferStreamHandle.new(@masterFile), nil ] ]
182
256
  else
183
257
  begin
184
- @fileStack = [ [ @cf = FileStreamHandle.new(@masterFile), nil, nil ] ]
258
+ @fileStack = [ [ @cf = FileStreamHandle.new(@masterFile), nil ] ]
185
259
  rescue StandardError
186
260
  raise TjException.new, "Cannot open file #{@masterFile}"
187
261
  end
188
262
  end
189
263
  @masterPath = @cf.dirname + '/'
190
- @tokenBuffer = @pos = @lastPos = nil
264
+ @tokenBuffer = nil
191
265
  end
192
266
 
193
267
  # Finish processing and reset all data structures.
@@ -200,46 +274,46 @@ class TaskJuggler
200
274
  @cf = @tokenBuffer = nil
201
275
  end
202
276
 
203
- # Continue processing with a new file specified by _fileName_. When this
204
- # file is finished, we will continue in the old file after the location
205
- # where we started with the new file.
206
- def include(fileName)
207
- if fileName[0] != '/'
208
- if @fileStack.empty?
209
- path = @masterPath == './' ? '' : @masterPath
210
- else
211
- pathOfCallingFile = @fileStack.last[0].dirname
212
- path = pathOfCallingFile.empty? ? '' : pathOfCallingFile + '/'
213
- @fileStack.last[1, 2] = [ @tokenBuffer, @pos ]
214
- end
277
+ # Continue processing with a new file specified by _includeFileName_. When
278
+ # this file is finished, we will continue in the old file after the
279
+ # location where we started with the new file.
280
+ def include(includeFileName, sfi)
281
+ if includeFileName[0] != '/'
282
+ pathOfCallingFile = @fileStack.last[0].dirname
283
+ path = pathOfCallingFile.empty? ? '' : pathOfCallingFile + '/'
215
284
  # If the included file is not an absolute name, we interpret the file
216
285
  # name relative to the including file.
217
- fileName = path + fileName
286
+ includeFileName = path + includeFileName
218
287
  end
219
288
 
220
- @tokenBuffer = nil
221
-
222
- # Check the current file stack to find recusions.
223
- if @pos && fileName == @pos.fileName
224
- error('include_recursion', "Recursive inclusion of #{fileName} detected")
225
- else
226
- @fileStack.each do |entry|
227
- if fileName == entry[0].fileName
228
- error('include_recursion', "Recursive inclusion of #{fileName} " +
229
- "detected")
230
- end
289
+ # Try to dectect recursive inclusions. This will not work if files are
290
+ # accessed via filesystem links.
291
+ @fileStack.each do |entry|
292
+ if includeFileName == entry[0].fileName
293
+ error('include_recursion',
294
+ "Recursive inclusion of #{includeFileName} detected", nil, sfi)
231
295
  end
232
296
  end
297
+
298
+ # Save @tokenBuffer in the record of the parent file.
299
+ @fileStack.last[1] = @tokenBuffer unless @fileStack.empty?
300
+ @tokenBuffer = nil
301
+ @finishLastFile = false
302
+
303
+ # Open the new file and push the handle on the @fileStack.
233
304
  begin
234
- @fileStack << [ (@cf = FileStreamHandle.new(fileName)), nil, nil ]
305
+ @fileStack << [ (@cf = FileStreamHandle.new(includeFileName)), nil, ]
306
+ Log << "Parsing file #{includeFileName}"
235
307
  rescue StandardError
236
- error('bad_include', "Cannot open include file #{fileName}")
308
+ error('bad_include', "Cannot open include file #{includeFileName}",
309
+ nil, sfi)
237
310
  end
238
311
  end
239
312
 
240
313
  # Return SourceFileInfo for the current processing prosition.
241
314
  def sourceFileInfo
242
- @pos ? @pos.dup : SourceFileInfo.new(fileName, lineNo, columnNo)
315
+ @cf ? SourceFileInfo.new(fileName, @cf.lineNo - @lineDelta, 0) :
316
+ SourceFileInfo.new(@masterFile, 0, 0)
243
317
  end
244
318
 
245
319
  # Return the name of the currently processed file. If we are working on a
@@ -253,94 +327,97 @@ class TaskJuggler
253
327
  end
254
328
 
255
329
  def columnNo # :nodoc:
256
- @cf ? @cf.columnNo : 0
330
+ 0
257
331
  end
258
332
 
259
333
  def line # :nodoc:
260
334
  @cf ? @cf.line : 0
261
335
  end
262
336
 
263
- # Scan for the next token in the input stream and return it. The result will
264
- # be an Array of the form [ TokenType, TokenValue ].
337
+ # Return the next token from the input stream. The result is an Array with
338
+ # 3 entries: the token type, the token String and the SourceFileInfo where
339
+ # the token started.
265
340
  def nextToken
266
341
  # If we have a pushed-back token, return that first.
267
342
  unless @tokenBuffer.nil?
268
343
  res = @tokenBuffer
269
344
  @tokenBuffer = nil
270
- @pos = @tokenBufferPos
271
345
  return res
272
346
  end
273
347
 
348
+ if @finishLastFile
349
+ # The previously processed file has now really been processed to
350
+ # completion. Close it and remove the corresponding entry from the
351
+ # @fileStack.
352
+ @finishLastFile = false
353
+ #Log << "Completed file #{@cf.fileName}"
354
+ @cf.close
355
+ @fileStack.pop
356
+
357
+ if @fileStack.empty?
358
+ # We are done with the top-level file now.
359
+ @cf = @tokenBuffer = nil
360
+ @finishLastFile = true
361
+ return [ '.', '<END>', @startOfToken ]
362
+ else
363
+ # Continue parsing the file that included the current file.
364
+ @cf, tokenBuffer = @fileStack.last
365
+ Log << "Parsing file #{@cf.fileName} ..."
366
+ # If we have a left over token from previously processing this file,
367
+ # return it now.
368
+ return tokenBuffer if tokenBuffer
369
+ end
370
+ end
371
+
274
372
  # Start processing characters from the input.
275
- @startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
276
- token = [ '.', '<END>' ]
277
- while c = nextChar
278
- case c
279
- when ' ', "\n", "\t"
280
- if (tok = readBlanks(c))
281
- token = tok
282
- break
373
+ @startOfToken = sourceFileInfo
374
+ loop do
375
+ match = nil
376
+ begin
377
+ @activePatterns.each do |type, re, postProc|
378
+ if (match = @cf.scan(re))
379
+ if match == :scannerEOF
380
+ # We've found the end of an input file. Return a special token
381
+ # that describes the end of a file.
382
+ @finishLastFile = true
383
+ return [ '.', '<END>', @startOfToken ]
384
+ end
385
+
386
+ raise "#{re} matches empty string" if match.empty?
387
+ # If we have a post processing method, call it now. It may modify
388
+ # the type or the found token String.
389
+ type, match = postProc.call(type, match) if postProc
390
+
391
+ break if type.nil? # Ignore certain tokens with nil type.
392
+
393
+ return [ type, match, @startOfToken ]
394
+ end
283
395
  end
284
- @startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
285
- when '#'
286
- skipComment
287
- @startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
288
- when '/'
289
- skipCPlusPlusComments
290
- @startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
291
- when '0'..'9'
292
- token = readNumber(c)
293
- break
294
- when "'"
295
- token = readString(c)
296
- break
297
- when '"'
298
- token = readString(c)
299
- break
300
- when '-'
301
- token = handleDash
302
- break
303
- when '!'
304
- if (c = nextChar) == '='
305
- token = [ 'LITERAL', '!=' ]
396
+ rescue
397
+ error('scan_encoding_error', $!.to_s)
398
+ end
399
+
400
+ if match.nil?
401
+ if @cf.eof?
402
+ error('unexpected_eof',
403
+ "Unexpected end of file found")
306
404
  else
307
- returnChar(c)
308
- token = [ 'LITERAL', '!' ]
405
+ error('no_token_match',
406
+ "Unexpected characters found: '#{@cf.peek(10)}...'")
309
407
  end
310
- break
311
- when 'a'..'z', 'A'..'Z', '_'
312
- token = readId(c)
313
- break
314
- when '<', '>', '='
315
- token = readOperator(c)
316
- break
317
- when '['
318
- token = readMacro
319
- break
320
- when nil
321
- # We've reached an end of file or buffer
322
- break
323
- else
324
- str = ""
325
- str << c
326
- token = [ 'LITERAL', str ]
327
- break
328
408
  end
329
409
  end
330
- @pos = @startOfToken
331
- return token
332
410
  end
333
411
 
334
412
  # Return a token to retrieve it with the next nextToken() call again. Only 1
335
413
  # token can be returned before the next nextToken() call.
336
414
  def returnToken(token)
415
+ #Log << "-> Returning Token: [#{token[0]}][#{token[1]}]"
337
416
  unless @tokenBuffer.nil?
338
417
  $stderr.puts @tokenBuffer
339
418
  raise "Fatal Error: Cannot return more than 1 token in a row"
340
419
  end
341
420
  @tokenBuffer = token
342
- @tokenBufferPos = @pos
343
- @pos = @lastPos
344
421
  end
345
422
 
346
423
  # Add a Macro to the macro translation table.
@@ -353,548 +430,54 @@ class TaskJuggler
353
430
  @macroTable.include?(name)
354
431
  end
355
432
 
356
- def expandMacro(args)
433
+ # Expand a macro and inject it into the input stream. _prefix_ is any
434
+ # string that was found right before the macro call. We have to inject it
435
+ # before the expanded macro. _args_ is an Array of Strings. The first is
436
+ # the macro name, the rest are the parameters.
437
+ def expandMacro(prefix, args)
438
+ # Get the expanded macro from the @macroTable.
357
439
  macro, text = @macroTable.resolve(args, sourceFileInfo)
440
+ # If the expanded macro is empty, we can ignore it.
358
441
  return if text == ''
359
442
 
360
- if @macroStack.length > 20
443
+ unless @cf.injectMacro(macro, args, prefix + text)
361
444
  error('macro_stack_overflow', "Too many nested macro calls.")
362
445
  end
363
- @macroStack << [ macro, args ]
364
- # Mark end of macro with a 0 element
365
- @cf.charBuffer << 0
366
- text.reverse.each_utf8_char do |c|
367
- @cf.charBuffer << c
368
- end
369
- @cf.line = ''
370
446
  end
371
447
 
372
448
  # Call this function to report any errors related to the parsed input.
373
- def error(id, text, property = nil)
374
- message('error', id, text, property)
449
+ def error(id, text, property = nil, sfi = nil)
450
+ message('error', id, text, property, sfi)
375
451
  end
376
452
 
377
- def warning(id, text, property = nil)
378
- message('warning', id, text, property)
453
+ def warning(id, text, property = nil, sfi = nil)
454
+ message('warning', id, text, property, sfi)
379
455
  end
380
456
 
381
- def message(type, id, text, property)
457
+ def message(type, id, text, property, sfi)
382
458
  unless text.empty?
383
459
  message = Message.new(id, type, text + "\n" + line.to_s,
384
- property, nil, sourceFileInfo)
460
+ property, nil, sfi || sourceFileInfo)
385
461
  @messageHandler.send(message)
386
462
 
387
- until @macroStack.empty?
388
- macro, args = @macroStack.pop
389
- args.collect! { |a| '"' + a + '"' }
390
- message = Message.new('macro_stack', 'info',
391
- " #{macro.name} #{args.join(' ')}", nil, nil,
392
- macro.sourceFileInfo)
463
+ if @cf && !@cf.macroStack.empty?
464
+ message = Message.new('macro_stack', 'info', 'Macro call history:')
393
465
  @messageHandler.send(message)
394
- end
395
- end
396
-
397
- # An empty strings signals an already reported error
398
- raise TjException.new, '' if type == 'error'
399
- end
400
466
 
401
- private
402
-
403
- # This function is called by the scanner to get the next character. It
404
- # features a FIFO buffer that can hold any amount of returned characters.
405
- # When it has reached the end of the master file it returns nil.
406
- def nextChar
407
- # We've started to find the next token. @pos no longer marks the
408
- # position of the current token. Since we also store the EOF position in
409
- # @pos, don't reset it if we have processed all files completely.
410
- if @pos && @cf
411
- @lastPos = @pos
412
- @pos = nil
413
- end
414
-
415
- if (c = nextCharI) == '$' && !@ignoreMacros
416
- # Double $ are reduced to a single $.
417
- return c if (c = nextCharI) == '$'
418
-
419
- # Macros start with $( or ${. All other $. are ignored.
420
- if c != '(' && c != '{'
421
- returnChar(c)
422
- return '$'
423
- end
424
-
425
- @ignoreMacros = true
426
- returnChar(c)
427
- macroParser = MacroParser.new(self, @messageHandler)
428
- begin
429
- macroParser.parse('macroCall')
430
- rescue TjException
431
- end
432
- @ignoreMacros = false
433
- return nextCharI
434
- else
435
- return c
436
- end
437
- end
438
-
439
- def nextCharI
440
- # This can only happen when a previous call already returned nil.
441
- return nil if @cf.nil?
442
-
443
- c = nil
444
- # If there are characters in the return buffer process them first.
445
- # Otherwise get next character from input stream.
446
- unless @cf.charBuffer.empty?
447
- c = @cf.charBuffer.pop
448
- @cf.lineNo -= 1 if c == "\n" && !@macroStack.empty?
449
- while !@cf.charBuffer.empty? && @cf.charBuffer[-1] == 0
450
- @cf.charBuffer.pop
451
- @macroStack.pop
452
- end
453
- else
454
- # If EOF has been reached, try the parent file until even the master
455
- # file has been processed completely.
456
- if (c = @cf.getc).nil?
457
- # Safe current position so an EOF related error can be properly
458
- # reported.
459
- @pos = sourceFileInfo
460
-
461
- @cf.close
462
- @fileStack.pop
463
- if @fileStack.empty?
464
- # We are done with the top-level file now.
465
- @cf = @tokenBuffer = nil
466
- else
467
- @cf, @tokenBuffer, @lastPos = @fileStack.last
468
- Log << "Parsing file #{@cf.fileName} ..."
469
- # We have been called by nextToken() already, so we can't just
470
- # restore @tokenBuffer and be done. We need to feed the token text
471
- # back into the charBuffer and return the first character.
472
- if @tokenBuffer
473
- @tokenBuffer[1].reverse.each_utf8_char do |ch|
474
- @cf.charBuffer.push(ch)
475
- end
476
- @tokenBuffer = nil
477
- end
467
+ @cf.macroStack.reverse_each do |entry|
468
+ macro = entry.macro
469
+ args = entry.args[1..-1]
470
+ args.collect! { |a| '"' + a + '"' }
471
+ message = Message.new('macro_stack', 'info',
472
+ " ${#{macro.name} #{args.join(' ')}}",
473
+ nil, nil, macro.sourceFileInfo)
474
+ @messageHandler.send(message)
478
475
  end
479
- return nil
480
476
  end
481
477
  end
482
- unless c.nil?
483
- @cf.lineNo += 1 if c == "\n"
484
- @cf.line = "" if @cf.line[-1] == ?\n
485
- @cf.line << c
486
- end
487
- c
488
- end
489
-
490
- def returnChar(c)
491
- return if @cf.nil?
492
478
 
493
- @cf.line.chop! if c
494
- @cf.charBuffer << c
495
- @cf.lineNo -= 1 if c == "\n" && @macroStack.empty?
496
- end
497
-
498
- def skipComment
499
- # Read all characters until line or file end is found
500
- @ignoreMacros = true
501
- while (c = nextChar) && c != "\n"
502
- end
503
- @ignoreMacros = false
504
- returnChar(c)
505
- end
506
-
507
- def skipCPlusPlusComments
508
- if (c = nextChar) == '*'
509
- # /* */ style multi-line comment
510
- @ignoreMacros = true
511
- begin
512
- while (c = nextChar) != '*'
513
- end
514
- end until (c = nextChar) == '/'
515
- @ignoreMacros = false
516
- elsif c == '/'
517
- # // style single line comment
518
- skipComment
519
- else
520
- error('bad_comment', "'/' or '*' expected after start of comment")
521
- end
522
- end
523
-
524
- def handleDash
525
- if (c1 = nextChar) == '8'
526
- if (c2 = nextChar) == '<'
527
- if (c3 = nextChar) == '-'
528
- return readIndentedString
529
- else
530
- returnChar(c3)
531
- returnChar(c2)
532
- returnChar(c1)
533
- end
534
- else
535
- returnChar(c2)
536
- returnChar(c1)
537
- end
538
- else
539
- returnChar(c1)
540
- end
541
- return [ 'LITERAL', ' - ']
542
- end
543
-
544
- def readBlanks(c)
545
- loop do
546
- if c == ' '
547
- if (c2 = nextChar) == '-'
548
- # Special case for the dash between period dates. It must be
549
- # surrounded by blanks.
550
- if (c3 = nextChar) == ' '
551
- return [ 'LITERAL', ' - ']
552
- end
553
- returnChar(c3)
554
- end
555
- returnChar(c2)
556
- elsif c != "\n" && c != "\t"
557
- returnChar(c)
558
- return nil
559
- end
560
- c = nextChar
561
- end
562
- end
563
-
564
- def readNumber(c)
565
- token = ""
566
- token << c
567
- while ('0'..'9') === (c = nextChar)
568
- token << c
569
- end
570
- if c == '-'
571
- return readDate(token)
572
- elsif c == '.'
573
- frac = readDigits
574
-
575
- return [ 'FLOAT', token.to_f + frac.to_f / (10.0 ** frac.length) ]
576
- elsif c == ':'
577
- hours = token.to_i
578
- mins = readDigits.to_i
579
- if hours < 0 || hours > 24
580
- raise TjException.new, "Hour must be between 0 and 23"
581
- end
582
- if mins < 0 || mins > 59
583
- raise TjException.new, "Minutes must be between 0 and 59"
584
- end
585
- if hours == 24 && mins != 0
586
- raise TjException.new, "Time may not be larger than 24:00"
587
- end
588
-
589
- # Return time as seconds of day since midnight.
590
- return [ 'TIME', hours * 60 * 60 + mins * 60 ]
591
- else
592
- returnChar(c)
593
- end
594
-
595
- [ 'INTEGER', token.to_i ]
596
- end
597
-
598
- def readDate(token)
599
- year = token.to_i
600
- if year < 1970 || year > 2030
601
- raise TjException.new, "Year must be between 1970 and 2030"
602
- end
603
-
604
- month = readDigits.to_i
605
- if month < 1 || month > 12
606
- raise TjException.new, "Month must be between 1 and 12"
607
- end
608
- if nextChar != '-'
609
- raise TjException.new, "Corrupted date"
610
- end
611
-
612
- day = readDigits.to_i
613
- if day < 1 || day > 31
614
- raise TjException.new, "Day must be between 1 and 31"
615
- end
616
-
617
- if (c = nextChar) != '-'
618
- returnChar(c)
619
- return [ 'DATE', TjTime.local(year, month, day) ]
620
- end
621
-
622
- hour = readDigits.to_i
623
- if hour < 0 || hour > 23
624
- raise TjException.new, "Hour must be between 0 and 23"
625
- end
626
-
627
- if nextChar != ':'
628
- raise TjException.new, "Corrupted time. ':' expected."
629
- end
630
-
631
- minutes = readDigits.to_i
632
- if minutes < 0 || minutes > 59
633
- raise TjException.new, "Minutes must be between 0 and 59"
634
- end
635
-
636
- if (c = nextChar) == ':'
637
- seconds = readDigits.to_i
638
- if seconds < 0 || seconds > 59
639
- raise TjException.new, "Seconds must be between 0 and 59"
640
- end
641
- else
642
- seconds = 0
643
- returnChar(c)
644
- end
645
-
646
- if (c = nextChar) != '-'
647
- returnChar(c)
648
- return [ 'DATE', TjTime.local(year, month, day, hour, minutes, seconds) ]
649
- end
650
-
651
- if (c = nextChar) == '-'
652
- delta = 1
653
- elsif c == '+'
654
- delta = -1
655
- else
656
- # An actual time zone name
657
- tz = readId(c)[1]
658
- oldTz = ENV['TZ']
659
- ENV['TZ'] = tz
660
- timeVal = TjTime.local(year, month, day, hour, minutes, seconds)
661
- ENV['TZ'] = oldTz
662
- if timeVal.to_a[9] != tz
663
- raise TjException.new, "Unknown time zone #{tz}"
664
- end
665
- return [ 'DATE', timeVal ]
666
- end
667
-
668
- utcDiff = readDigits
669
- utcHour = utcDiff[0, 2].to_i
670
- if utcHour < 0 || utcHour > 23
671
- raise TjException.new, "Hour must be between 0 and 23"
672
- end
673
- utcMin = utcDiff[2, 2].to_i
674
- if utcMin < 0 || utcMin > 59
675
- raise TjException.new, "Minutes must be between 0 and 59"
676
- end
677
-
678
- [ 'DATE', TjTime.gm(year, month, day, hour, minutes, seconds) +
679
- delta * ((utcHour * 3600) + utcMin * 60) ]
680
- end
681
-
682
- def readString(terminator)
683
- token = ""
684
- while (c = nextChar) && c != terminator
685
- if c == "\\"
686
- # Terminators can be used as regular characters when prefixed by a \.
687
- if (c = nextChar) && c != terminator
688
- # \ followed by non-terminator. Just add both.
689
- token << "\\"
690
- end
691
- end
692
- token << c
693
- end
694
-
695
- [ 'STRING', token ]
696
- end
697
-
698
- def readIndentedString
699
- state = 0
700
- indent = ''
701
- token = ''
702
- while true
703
- case state
704
- when 0 # Determining indent
705
- # Skip trailing spaces and tabs.
706
- while (c = nextChar) == ' ' || c == "\t" do
707
- # empty on purpose
708
- end
709
- if c != "\n"
710
- error('junk_after_cut',
711
- 'The cut mark -8<- must be immediately followed by a ' +
712
- 'line break.')
713
- end
714
- while (c = nextChar) == ' ' || c == "\t"
715
- indent << c
716
- end
717
- @startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
718
- returnChar(c)
719
- state = 1
720
- when 1 # reading '-' or first content line character
721
- if (c = nextChar) == '-'
722
- state = 3
723
- elsif c.nil?
724
- errorEOF(1, token)
725
- elsif c == "\n"
726
- token << c
727
- state = 6
728
- else
729
- token << c
730
- state = 2
731
- end
732
- when 2 # reading content line
733
- # The '->8-' is only valid if no other content preceded it on this
734
- # line.
735
- onlyBlanks = true
736
- while (c = nextChar) != "\n" && !(c == '-' && onlyBlanks)
737
- onlyBlanks = false if c != ' ' && c != "\t"
738
- errorEOF(2, token) if c.nil?
739
- token << c
740
- end
741
- if c == '-'
742
- # we may have found the start of '->8-'
743
- state = 3
744
- else
745
- token << c
746
- state = 6
747
- end
748
- when 3 # reading '>' of '->8-'
749
- if (c = nextChar) == '>'
750
- state = 4
751
- else
752
- errorEOF(3, token) if c.nil?
753
- token << '-'
754
- token << c
755
- state = 2
756
- end
757
- when 4 # reading '8' of '->8-'
758
- if (c = nextChar) == '8'
759
- state = 5
760
- else
761
- errorEOF(4, token) if c.nil?
762
- token << c
763
- state = 2
764
- end
765
- when 5 # reading '-' of '->8-'
766
- if (c = nextChar) == '-'
767
- return [ 'STRING', token ]
768
- else
769
- errorEOF(5, token) if c.nil?
770
- token << c
771
- state = 2
772
- end
773
- when 6 # reading indentation
774
- state = 1
775
- indent.each_utf8_char do |ci|
776
- if ci != (c = nextChar)
777
- if c == '-'
778
- state = 3
779
- break
780
- elsif c == "\n"
781
- returnChar(c)
782
- break
783
- else
784
- warning('bad_indent',
785
- "Not all lines of string have same indentation. " +
786
- "The first line of the string determines the " +
787
- "indentation for all subsequent lines of the same " +
788
- "string.")
789
- token << c
790
- state = 2
791
- break
792
- end
793
- end
794
- end
795
- else
796
- raise "State machine error"
797
- end
798
- end
799
- end
800
-
801
- def readId(c)
802
- token = ""
803
- token << c
804
- while (c = nextChar) &&
805
- (('a'..'z') === c || ('A'..'Z') === c || ('0'..'9') === c ||
806
- c == '_')
807
- token << c
808
- end
809
- if c == ':'
810
- return [ 'ID_WITH_COLON', token ]
811
- elsif c == '.'
812
- token << c
813
- loop do
814
- token += readIdentifier
815
- break if (c = nextChar) != '.'
816
- token += '.'
817
- end
818
- returnChar c
819
-
820
- return [ 'ABSOLUTE_ID', token ]
821
- else
822
- returnChar c
823
- return [ 'ID', token ]
824
- end
825
- end
826
-
827
- def readMacro
828
- # We can deal with ']' inside of the macro as long as each ']' is
829
- # preceeded by a corresponding '['.
830
- token = ''
831
- bracketLevel = 1
832
- while bracketLevel > 0
833
- case (c = nextCharI)
834
- when nil
835
- error('unterminated_macro', "Unterminated macro #{token}")
836
- when '['
837
- bracketLevel += 1
838
- when ']'
839
- bracketLevel -= 1
840
- end
841
- token << c unless bracketLevel == 0
842
- end
843
- return [ 'MACRO', token ]
844
- end
845
-
846
- # Read operators of logical expressions.
847
- def readOperator(c)
848
- case c
849
- when '='
850
- return [ 'LITERAL', '=' ]
851
- when '>'
852
- return [ 'LITERAL', '>=' ] if (c = nextChar) == '='
853
- returnChar(c)
854
- return [ 'LITERAL', '>' ]
855
- when '<'
856
- return [ 'LITERAL', '<=' ] if (c = nextChar) == '='
857
- returnChar(c)
858
- return [ 'LITERAL', '<' ]
859
- else
860
- raise "Unsupported operator #{c}"
861
- end
862
- end
863
-
864
- # Read only decimal digits and return the result als Fixnum.
865
- def readDigits
866
- token = ""
867
- while ('0'..'9') === (c = nextChar)
868
- token << c
869
- end
870
- # Make sure that we have read at least one digit.
871
- if token == ""
872
- raise TjException.new, "Digit (0 - 9) expected"
873
- end
874
- # Push back the non-digit that terminated the digits.
875
- returnChar(c)
876
- token
877
- end
878
-
879
- def readIdentifier(noDigit = true)
880
- token = ""
881
- while (c = nextChar) &&
882
- (('a'..'z') === c || ('A'..'Z') === c ||
883
- (!noDigit && (('0'..'9') === c)) || c == '_')
884
- token << c
885
- noDigit = false
886
- end
887
- returnChar(c)
888
- if token == ""
889
- raise TjException.new, "Identifier expected"
890
- end
891
- token
892
- end
893
-
894
- def errorEOF(no, token)
895
- error("eof_in_istring#{no}",
896
- "Unexpected end of file in string '#{token[0,20]}...'" +
897
- "starting in line #{@startOfToken.lineNo}.")
479
+ # An empty strings signals an already reported error
480
+ raise TjException.new, '' if type == 'error'
898
481
  end
899
482
 
900
483
  end