Fossil SCM

Bringing back in the old parser for rcs archives.

aku 2007-10-06 18:28 trunk
Commit 860f533e98efba37a38bffd56706299a0299430c
--- tools/cvs2fossil/lib/pkgIndex.tcl
+++ tools/cvs2fossil/lib/pkgIndex.tcl
@@ -6,12 +6,13 @@
66
package ifneeded vc::fossil::import::cvs 1.0 [list source [file join $dir cvs2fossil.tcl]]
77
package ifneeded vc::fossil::import::cvs::option 1.0 [list source [file join $dir c2f_option.tcl]]
88
package ifneeded vc::fossil::import::cvs::pass 1.0 [list source [file join $dir c2f_pass.tcl]]
99
package ifneeded vc::fossil::import::cvs::pass::collar 1.0 [list source [file join $dir c2f_pcollar.tcl]]
1010
package ifneeded vc::fossil::import::cvs::pass::collrev 1.0 [list source [file join $dir c2f_pcollrev.tcl]]
11
-package ifneeded vc::fossil::import::cvs::repository 1.0 [list source [file join $dir c2f_repository.tcl]]
1211
package ifneeded vc::fossil::import::cvs::project 1.0 [list source [file join $dir c2f_project.tcl]]
12
+package ifneeded vc::fossil::import::cvs::repository 1.0 [list source [file join $dir c2f_repository.tcl]]
1313
package ifneeded vc::fossil::import::cvs::state 1.0 [list source [file join $dir c2f_state.tcl]]
14
-package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]]
14
+package ifneeded vc::rcs::parser 1.0 [list source [file join $dir rcsparser.tcl]]
1515
package ifneeded vc::tools::log 1.0 [list source [file join $dir log.tcl]]
1616
package ifneeded vc::tools::misc 1.0 [list source [file join $dir misc.tcl]]
17
+package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]]
1718
1819
1920
ADDED tools/cvs2fossil/lib/rcsparser.tcl
--- tools/cvs2fossil/lib/pkgIndex.tcl
+++ tools/cvs2fossil/lib/pkgIndex.tcl
@@ -6,12 +6,13 @@
6 package ifneeded vc::fossil::import::cvs 1.0 [list source [file join $dir cvs2fossil.tcl]]
7 package ifneeded vc::fossil::import::cvs::option 1.0 [list source [file join $dir c2f_option.tcl]]
8 package ifneeded vc::fossil::import::cvs::pass 1.0 [list source [file join $dir c2f_pass.tcl]]
9 package ifneeded vc::fossil::import::cvs::pass::collar 1.0 [list source [file join $dir c2f_pcollar.tcl]]
10 package ifneeded vc::fossil::import::cvs::pass::collrev 1.0 [list source [file join $dir c2f_pcollrev.tcl]]
11 package ifneeded vc::fossil::import::cvs::repository 1.0 [list source [file join $dir c2f_repository.tcl]]
12 package ifneeded vc::fossil::import::cvs::project 1.0 [list source [file join $dir c2f_project.tcl]]
 
13 package ifneeded vc::fossil::import::cvs::state 1.0 [list source [file join $dir c2f_state.tcl]]
14 package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]]
15 package ifneeded vc::tools::log 1.0 [list source [file join $dir log.tcl]]
16 package ifneeded vc::tools::misc 1.0 [list source [file join $dir misc.tcl]]
 
17
18
19 DDED tools/cvs2fossil/lib/rcsparser.tcl
--- tools/cvs2fossil/lib/pkgIndex.tcl
+++ tools/cvs2fossil/lib/pkgIndex.tcl
@@ -6,12 +6,13 @@
6 package ifneeded vc::fossil::import::cvs 1.0 [list source [file join $dir cvs2fossil.tcl]]
7 package ifneeded vc::fossil::import::cvs::option 1.0 [list source [file join $dir c2f_option.tcl]]
8 package ifneeded vc::fossil::import::cvs::pass 1.0 [list source [file join $dir c2f_pass.tcl]]
9 package ifneeded vc::fossil::import::cvs::pass::collar 1.0 [list source [file join $dir c2f_pcollar.tcl]]
10 package ifneeded vc::fossil::import::cvs::pass::collrev 1.0 [list source [file join $dir c2f_pcollrev.tcl]]
 
11 package ifneeded vc::fossil::import::cvs::project 1.0 [list source [file join $dir c2f_project.tcl]]
12 package ifneeded vc::fossil::import::cvs::repository 1.0 [list source [file join $dir c2f_repository.tcl]]
13 package ifneeded vc::fossil::import::cvs::state 1.0 [list source [file join $dir c2f_state.tcl]]
14 package ifneeded vc::rcs::parser 1.0 [list source [file join $dir rcsparser.tcl]]
15 package ifneeded vc::tools::log 1.0 [list source [file join $dir log.tcl]]
16 package ifneeded vc::tools::misc 1.0 [list source [file join $dir misc.tcl]]
17 package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]]
18
19
20 DDED tools/cvs2fossil/lib/rcsparser.tcl
--- a/tools/cvs2fossil/lib/rcsparser.tcl
+++ b/tools/cvs2fossil/lib/rcsparser.tcl
@@ -0,0 +1,303 @@
1
+# -----------------------------------------------------------------------------
2
+# Tool packages. Parsing RCS files.
3
+#
4
+# Some of the information in RCS files is skipped over, most
5
+# importantly the actual delta texts. The users of this parser need
6
+# only the meta-data about when revisions were added, the tree
7
+# (branching) structure, commit messages.
8
+#
9
+# The parser is based on Recursive Descent.
10
+
11
+# -----------------------------------------------------------------------------
12
+# Requirements
13
+
14
+package require Tcl 8.4
15
+package require fileutil ; # Tcllib (cat)
16
+package require vc::tools::log ; # User feedback
17
+
18
+namespace eval ::vc::rcs::parser {
19
+ vc::tools::log::system rcs
20
+ namesp::* return
21
+}
22
+
23
+proc ::vc::rcs::parser::Log {} {
24
+ upvar 1 data data res res
25
+ LiteraAPI
26
+
27
+# vc::rcs::parser::process file
28
+#
29
+# Parses the rcs file and returns a dictionary containing the meta
30
+# data. The following keys are used
31
+#
32
+# Key Meaning
33
+# --- -------
34
+# 'head' head revision
35
+# 'branch' ?
36
+# 'symbol' dict (symbol -> revision)
37
+# 'lock' dict (symbol -> revision)
38
+# 'comment' file comment
39
+# 'expand' ?
40
+# 'date' dict (revision -> date)
41
+# 'author' dict (revision -> author)
42
+# 'state' dict (revision -> state)
43
+# 'parent' dict (revision -> parent revision)
44
+# 'commit' dict (revision -> commit message)
45
+#
46
+# The state 'dead' has special meaning, the user should know that.
47
+
48
+# -----------------------------------------------------------------------------
49
+# API Implementation
50
+
51
+proc ::vc::rcs::parser::configure {key value} {
52
+ variable cache
53
+ switch -exact -- $key {
54
+ -cache {
55
+ set cache $value
56
+ }
57
+ default {
58
+ return -code error "Unknown switch $key, expected one of -cache"
59
+ }
60
+ }
61
+ return
62
+}
63
+
64
+proc ::vc::rcs::parser::process {path} {
65
+ variable cache
66
+
67
+ if {!$cache} {
68
+ return [Process $path]
69
+ }
70
+
71
+ set cachefile [Cache $path]
72
+ if {
73
+ [file exists $cachefile] &&
74
+ ([file mtime $cachefile] > [file mtime $path])
75
+ } {
76
+ # Use preparsed data if not invalidated by changes to the
77
+ # archive they are derived from.
78
+ write 4 rcs {Load preparsed data block}
79
+ return [fileutil::cat -encoding binary $cachefile]
80
+ }
81
+
82
+ set res [Process $path]
83
+
84
+ # Save parse result for quick pickup by future runs.
85
+ fileutil::writeFile $cachefile $res
86
+
87
+ return $res
88
+}
89
+
90
+# -----------------------------------------------------------------------------
91
+
92
+proc ::vc::rcs::parser::Process {path} {
93
+ set data [fileutil::cat -encoding binary $path]
94
+ array set res {}
95
+ set res(size) [file size $path]
96
+ set res(done) 0
97
+ set res(nsize) [string length $res(size)]
98
+
99
+ Admin
100
+ Deltas
101
+ Description
102
+ DeltaTexts
103
+
104
+ # Remove parser state
105
+ catch {unset res(id)}
106
+ catch {unset res(lastval)}
107
+ unset res(size)
108
+ unset res(nsize)
109
+ unset res(done)
110
+
111
+ return [array get res]
112
+}
113
+
114
+proc ::vc::rcs::parser::Cache {path} {
115
+ return ${path},,preparsed
116
+}
117
+
118
+# -----------------------------------------------------------------------------
119
+# Internal - Recursive Descent functions implementing the syntax.
120
+
121
+proc ::vc::rcs::parser::Admin {} {
122
+ upvar 1 data data res res
123
+ Head ; Branch ; Access ; Symbols ; Locks ; Strict ; Comment ; Expand
124
+ return
125
+}
126
+
127
+proc ::vc::rcs::parser::Deltas {} {
128
+ upvar 1 data data res res
129
+ while {[Num 0]} { IsIdent ; Date ; Author ; State ; Branches ; NextRev }
130
+ return
131
+}
132
+
133
+proc ::vc::rcs::parser::Description {} {
134
+ upvar 1 data data res res
135
+ Literal desc
136
+ String 1
137
+ Def desc
138
+ return
139
+}
140
+
141
+proc ::vc::rcs::parser::DeltaTexts {} {
142
+ upvar 1 data data res res
143
+ while {[Num 0]} { IsIdent ; Log ; Text }
144
+ return
145
+}
146
+
147
+proc ::vc::rcs::parser::Head {} {
148
+ upvar 1 data data res res
149
+ Literal head ; Num 1 ; Literal \;
150
+ Def head
151
+ return
152
+}
153
+
154
+proc ::vc::rcs::parser::Branch {} {
155
+ upvar 1 data data res res
156
+ if {![Literal branch 0]} return ; Num 1 ; Literal \;
157
+ Def branch
158
+ return
159
+}
160
+
161
+proc ::vc::rcs::parser::Access {} {
162
+ upvar 1 data data res res
163
+ Literal access ; Literal \;
164
+ return
165
+}
166
+
167
+proc ::vc::rcs::parser::Symbols {} {
168
+ upvar 1 data data res res
169
+ Literal symbols
170
+ while {[Ident]} { Num 1 ; Map symbol }
171
+ Literal \;
172
+ return
173
+}
174
+
175
+proc ::vc::rcs::parser::Locks {} {
176
+ upvar 1 data data res res
177
+ Literal locks
178
+ while {[Ident]} { Num 1 ; Map lock }
179
+ Literal \;
180
+ return
181
+}
182
+
183
+proc ::vc::rcs::parser::Strict {} {
184
+ upvar 1 data data res res
185
+ if {![Literal strict 0]} return ; Literal \;
186
+ return
187
+}
188
+
189
+proc ::vc::rcs::parser::Comment {} {
190
+ upvar 1 data data res res
191
+ if {![Literal comment 0]} return ;
192
+ if {![String 0]} return ;
193
+ Literal \;
194
+ Def comment
195
+ return
196
+}
197
+
198
+proc ::vc::rcs::parser::Expand {} {
199
+ upvar 1 data data res res
200
+ if {![Literal expand 0]} return ;
201
+ if {![String 0]} return ;
202
+ Literal \;
203
+ Def expand
204
+ return
205
+}
206
+
207
+proc ::vc::rcs::parser::Date {} {
208
+ upvar 1 data data res res
209
+ Literal date ; Num 1 ; Literal \;
210
+
211
+ foreach {yr mo dy h m s} [split $res(lastval) .] break
212
+ if {$yr < 100} {incr yr 1900}
213
+ set res(lastval) [join [list $yr $mo $dy $h $m $s] .]
214
+ Map date
215
+ return
216
+}
217
+
218
+proc ::vc::rcs::parser::Author {} {
219
+ upvar 1 data data res res
220
+ Literal author ; Skip ; Literal \; ; Map author
221
+ return
222
+}
223
+
224
+proc ::vc::rcs::parser::State {} {
225
+ upvar 1 data data res res
226
+ Literal state ; Skip ; Literal \; ; Map state
227
+ return
228
+}
229
+
230
+proc ::vc::rcs::parser::Branches {} {
231
+ upvar 1 data data res res
232
+ Literal branches ; Skip ; Literal \;
233
+ return
234
+}
235
+
236
+proc ::vc::rcs::parser::NextRev {} {
237
+ upvar 1 data data res res
238
+ Literal next ; Skip ; Literal \; ; Map parent
239
+ return
240
+}
241
+
242
+proc ::vc::rcs::parser::Log {} {
243
+ upvar 1 data data res res
244
+ Literal log ; String 1 ; Map commit
245
+ return
246
+}
247
+
248
+proc ::vc::rcs::parser::Text {} {
249
+ upvar 1 data data res res
250
+ Literal text ; String 1
251
+ return
252
+}
253
+
254
+# -----------------------------------------------------------------------------
255
+# Internal - Lexicographical commands and data aquisition preparation
256
+
257
+proc ::vc::rcs::parser::Ident {} {
258
+ upvar 1 data data res res
259
+
260
+ #puts I@?<[string range $data 0 10]...>
261
+
262
+ if {[regexp -indices -- {^\s*;\s*} $data]} {
263
+ return 0
264
+ } elseif {![regexp -indices -- {^\s*([^:]*)\s*:\s*} $data match val]} {
265
+ return 0
266
+ }
267
+
268
+ Get $val ; IsIdent
269
+ Next
270
+ return 1
271
+}
272
+
273
+proc ::vc::rcs::parser::Literal {name {required 1}} {
274
+ upvar 1 data data res res
275
+ if {![regexp -indices -- "^\\s*$name\\s*" $data match]} {
276
+ if {$required} {
277
+ return -code error "Expected '$name' @ '[string range $data 0 30]...'"
278
+ }
279
+ return 0
280
+ }
281
+
282
+ Next
283
+ return 1
284
+}
285
+
286
+proc ::vc::rcs::parser::String {{required 1}} {
287
+ upvar 1 data data res res
288
+
289
+ if {![regexp -indices -- {^\s*@(([^@]*(@@)*)*)@\s*} $data match val]} {
290
+ if {$required} {
291
+ return -code error "Expected string @ '[string range $data 0 30]...'"
292
+ }
293
+ return 0
294
+ }
295
+
296
+ Get $val
297
+ Next
298
+ return 1
299
+}
300
+
301
+proc ::vc::rcs::parser::Num {required} {
302
+ upvar 1 data data res res
303
+ if {![regexp -indices -- {^\s*((\d|\.)+)\s*} $data match val]} {
--- a/tools/cvs2fossil/lib/rcsparser.tcl
+++ b/tools/cvs2fossil/lib/rcsparser.tcl
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/tools/cvs2fossil/lib/rcsparser.tcl
+++ b/tools/cvs2fossil/lib/rcsparser.tcl
@@ -0,0 +1,303 @@
1 # -----------------------------------------------------------------------------
2 # Tool packages. Parsing RCS files.
3 #
4 # Some of the information in RCS files is skipped over, most
5 # importantly the actual delta texts. The users of this parser need
6 # only the meta-data about when revisions were added, the tree
7 # (branching) structure, commit messages.
8 #
9 # The parser is based on Recursive Descent.
10
11 # -----------------------------------------------------------------------------
12 # Requirements
13
14 package require Tcl 8.4
15 package require fileutil ; # Tcllib (cat)
16 package require vc::tools::log ; # User feedback
17
18 namespace eval ::vc::rcs::parser {
19 vc::tools::log::system rcs
20 namesp::* return
21 }
22
23 proc ::vc::rcs::parser::Log {} {
24 upvar 1 data data res res
25 LiteraAPI
26
27 # vc::rcs::parser::process file
28 #
29 # Parses the rcs file and returns a dictionary containing the meta
30 # data. The following keys are used
31 #
32 # Key Meaning
33 # --- -------
34 # 'head' head revision
35 # 'branch' ?
36 # 'symbol' dict (symbol -> revision)
37 # 'lock' dict (symbol -> revision)
38 # 'comment' file comment
39 # 'expand' ?
40 # 'date' dict (revision -> date)
41 # 'author' dict (revision -> author)
42 # 'state' dict (revision -> state)
43 # 'parent' dict (revision -> parent revision)
44 # 'commit' dict (revision -> commit message)
45 #
46 # The state 'dead' has special meaning, the user should know that.
47
48 # -----------------------------------------------------------------------------
49 # API Implementation
50
51 proc ::vc::rcs::parser::configure {key value} {
52 variable cache
53 switch -exact -- $key {
54 -cache {
55 set cache $value
56 }
57 default {
58 return -code error "Unknown switch $key, expected one of -cache"
59 }
60 }
61 return
62 }
63
64 proc ::vc::rcs::parser::process {path} {
65 variable cache
66
67 if {!$cache} {
68 return [Process $path]
69 }
70
71 set cachefile [Cache $path]
72 if {
73 [file exists $cachefile] &&
74 ([file mtime $cachefile] > [file mtime $path])
75 } {
76 # Use preparsed data if not invalidated by changes to the
77 # archive they are derived from.
78 write 4 rcs {Load preparsed data block}
79 return [fileutil::cat -encoding binary $cachefile]
80 }
81
82 set res [Process $path]
83
84 # Save parse result for quick pickup by future runs.
85 fileutil::writeFile $cachefile $res
86
87 return $res
88 }
89
90 # -----------------------------------------------------------------------------
91
92 proc ::vc::rcs::parser::Process {path} {
93 set data [fileutil::cat -encoding binary $path]
94 array set res {}
95 set res(size) [file size $path]
96 set res(done) 0
97 set res(nsize) [string length $res(size)]
98
99 Admin
100 Deltas
101 Description
102 DeltaTexts
103
104 # Remove parser state
105 catch {unset res(id)}
106 catch {unset res(lastval)}
107 unset res(size)
108 unset res(nsize)
109 unset res(done)
110
111 return [array get res]
112 }
113
114 proc ::vc::rcs::parser::Cache {path} {
115 return ${path},,preparsed
116 }
117
118 # -----------------------------------------------------------------------------
119 # Internal - Recursive Descent functions implementing the syntax.
120
121 proc ::vc::rcs::parser::Admin {} {
122 upvar 1 data data res res
123 Head ; Branch ; Access ; Symbols ; Locks ; Strict ; Comment ; Expand
124 return
125 }
126
127 proc ::vc::rcs::parser::Deltas {} {
128 upvar 1 data data res res
129 while {[Num 0]} { IsIdent ; Date ; Author ; State ; Branches ; NextRev }
130 return
131 }
132
133 proc ::vc::rcs::parser::Description {} {
134 upvar 1 data data res res
135 Literal desc
136 String 1
137 Def desc
138 return
139 }
140
141 proc ::vc::rcs::parser::DeltaTexts {} {
142 upvar 1 data data res res
143 while {[Num 0]} { IsIdent ; Log ; Text }
144 return
145 }
146
147 proc ::vc::rcs::parser::Head {} {
148 upvar 1 data data res res
149 Literal head ; Num 1 ; Literal \;
150 Def head
151 return
152 }
153
154 proc ::vc::rcs::parser::Branch {} {
155 upvar 1 data data res res
156 if {![Literal branch 0]} return ; Num 1 ; Literal \;
157 Def branch
158 return
159 }
160
161 proc ::vc::rcs::parser::Access {} {
162 upvar 1 data data res res
163 Literal access ; Literal \;
164 return
165 }
166
167 proc ::vc::rcs::parser::Symbols {} {
168 upvar 1 data data res res
169 Literal symbols
170 while {[Ident]} { Num 1 ; Map symbol }
171 Literal \;
172 return
173 }
174
175 proc ::vc::rcs::parser::Locks {} {
176 upvar 1 data data res res
177 Literal locks
178 while {[Ident]} { Num 1 ; Map lock }
179 Literal \;
180 return
181 }
182
183 proc ::vc::rcs::parser::Strict {} {
184 upvar 1 data data res res
185 if {![Literal strict 0]} return ; Literal \;
186 return
187 }
188
189 proc ::vc::rcs::parser::Comment {} {
190 upvar 1 data data res res
191 if {![Literal comment 0]} return ;
192 if {![String 0]} return ;
193 Literal \;
194 Def comment
195 return
196 }
197
198 proc ::vc::rcs::parser::Expand {} {
199 upvar 1 data data res res
200 if {![Literal expand 0]} return ;
201 if {![String 0]} return ;
202 Literal \;
203 Def expand
204 return
205 }
206
207 proc ::vc::rcs::parser::Date {} {
208 upvar 1 data data res res
209 Literal date ; Num 1 ; Literal \;
210
211 foreach {yr mo dy h m s} [split $res(lastval) .] break
212 if {$yr < 100} {incr yr 1900}
213 set res(lastval) [join [list $yr $mo $dy $h $m $s] .]
214 Map date
215 return
216 }
217
218 proc ::vc::rcs::parser::Author {} {
219 upvar 1 data data res res
220 Literal author ; Skip ; Literal \; ; Map author
221 return
222 }
223
224 proc ::vc::rcs::parser::State {} {
225 upvar 1 data data res res
226 Literal state ; Skip ; Literal \; ; Map state
227 return
228 }
229
230 proc ::vc::rcs::parser::Branches {} {
231 upvar 1 data data res res
232 Literal branches ; Skip ; Literal \;
233 return
234 }
235
236 proc ::vc::rcs::parser::NextRev {} {
237 upvar 1 data data res res
238 Literal next ; Skip ; Literal \; ; Map parent
239 return
240 }
241
242 proc ::vc::rcs::parser::Log {} {
243 upvar 1 data data res res
244 Literal log ; String 1 ; Map commit
245 return
246 }
247
248 proc ::vc::rcs::parser::Text {} {
249 upvar 1 data data res res
250 Literal text ; String 1
251 return
252 }
253
254 # -----------------------------------------------------------------------------
255 # Internal - Lexicographical commands and data aquisition preparation
256
257 proc ::vc::rcs::parser::Ident {} {
258 upvar 1 data data res res
259
260 #puts I@?<[string range $data 0 10]...>
261
262 if {[regexp -indices -- {^\s*;\s*} $data]} {
263 return 0
264 } elseif {![regexp -indices -- {^\s*([^:]*)\s*:\s*} $data match val]} {
265 return 0
266 }
267
268 Get $val ; IsIdent
269 Next
270 return 1
271 }
272
273 proc ::vc::rcs::parser::Literal {name {required 1}} {
274 upvar 1 data data res res
275 if {![regexp -indices -- "^\\s*$name\\s*" $data match]} {
276 if {$required} {
277 return -code error "Expected '$name' @ '[string range $data 0 30]...'"
278 }
279 return 0
280 }
281
282 Next
283 return 1
284 }
285
286 proc ::vc::rcs::parser::String {{required 1}} {
287 upvar 1 data data res res
288
289 if {![regexp -indices -- {^\s*@(([^@]*(@@)*)*)@\s*} $data match val]} {
290 if {$required} {
291 return -code error "Expected string @ '[string range $data 0 30]...'"
292 }
293 return 0
294 }
295
296 Get $val
297 Next
298 return 1
299 }
300
301 proc ::vc::rcs::parser::Num {required} {
302 upvar 1 data data res res
303 if {![regexp -indices -- {^\s*((\d|\.)+)\s*} $data match val]} {

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button