kramdown-rfc2629 1.5.26 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47ff7c7c6f4593d4d4c036c5986e7ff84ddec57ecb7a55959942d86ee6f0c9c8
4
- data.tar.gz: 363ddf3a404d78bc9c4daa71ae33850ec8a0f214fc9488e0c5d9230784f40056
3
+ metadata.gz: e14f146c7079e4611aa6ddf79f706ef0fddb168e1bb510c278ead6c93595b99a
4
+ data.tar.gz: efa3c83941f0eaa68e82d9d2bbe554826f70bee1469498e870506f006806bcf8
5
5
  SHA512:
6
- metadata.gz: b06841b1a0188f1f343eff51e2846b981d42592bbadbec8cbcdf38010ef66b23f560aab3effa183042d3207b9c0356346ab01dfa89ac551d3146e843cd6e35b1
7
- data.tar.gz: e80bb4fe75e33268c804907f332138fe68440355ef026a853d749e0d82c56d807acf19864b49cbf49f670d4c6c6fd6d1ef58719d534495866fa656ecb11cb562
6
+ metadata.gz: 54b21302c63267ecf9eaf845d67927c8f7f7dc78b4608c545fb6487274a507980695512d21397fa54c7700c3659600229c6dc0cab4964e2c8e9a471da9b51e00
7
+ data.tar.gz: '093aaa4efee63f5a103fba961072413884170bbcf13bb402b3ea40f36d1af1843d0b170be57d257dbf94f7b05bb6dc1e38df6a76abee06a5c475517fdd843d62'
data/README.md CHANGED
@@ -48,6 +48,19 @@ is provided by `kdrfc`:
48
48
 
49
49
  kdrfc -r mydraft.mkd
50
50
 
51
+ # Versions of RFCXML
52
+
53
+ Since RFC 8650, RFCs are using an updated grammar as defined in RFC
54
+ 7991 to 7998 and further updated informally since, colloquially called "[v3][]".
55
+ As RFC 2629 is no longer the governing standard, kramdown-rfc2629 is
56
+ now called kramdown-rfc. The latter command defaults to v3 processing
57
+ rules; from 2022-02-22T22:02:22 on, kramdown-rfc2629 does as well (1.6.1).
58
+ (-3/--v3 and -2/--v2 select v3 and v2 explicitly; the latter should
59
+ only be needed if there is a reason to to make a document look
60
+ like it's 2016.)
61
+
62
+ [v3]: https://xml2rfc.tools.ietf.org/xml2rfc-doc.html
63
+
51
64
  # Examples
52
65
 
53
66
  For historical interest
data/bin/kdrfc CHANGED
@@ -51,9 +51,26 @@ BANNER
51
51
  opts.on("-3", "--[no-]v3", "Use RFCXML v3 processing rules") do |v|
52
52
  kdrfc.options.v3 = v
53
53
  end
54
+ opts.on("-2", "--[no-]v2", "Use RFCXML v2 processing rules") do |v|
55
+ kdrfc.options.v2 = v
56
+ end
54
57
  end
55
58
  op.parse!
56
59
 
60
+
61
+ if kdrfc.options.v2 && kdrfc.options.v3
62
+ warn "*** can't have v2 and eat v3 cake"
63
+ kdrfc.options.v2 = false
64
+ end
65
+
66
+ if kdrfc.options.v3.nil? && !kdrfc.options.v2
67
+ if Time.now.to_i >= 1645567342 # Time.parse("2022-02-22T22:02:22Z").to_i
68
+ kdrfc.options.v3 = true # new default from the above date
69
+ end
70
+ end
71
+
72
+ warn "*** v2 #{kdrfc.options.v2.inspect} v3 #{kdrfc.options.v3.inspect}" if kdrfc.options.verbose
73
+
57
74
  case ARGV.size
58
75
  when 1
59
76
  fn = ARGV[0]
data/bin/kramdown-rfc ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'ostruct'
4
+
5
+ $options ||= OpenStruct.new
6
+
7
+ $options.v3 = true
8
+ require 'kramdown-rfc/command'
9
+
data/bin/kramdown-rfc2629 CHANGED
@@ -1,539 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
- require 'kramdown-rfc2629'
4
- require 'kramdown-rfc/parameterset'
5
- require 'kramdown-rfc/refxml'
6
- require 'kramdown-rfc/rfc8792'
7
- require 'yaml'
8
- require 'kramdown-rfc/erb'
9
- require 'date'
3
+ require 'kramdown-rfc/command'
10
4
 
11
- # try to get this from gemspec.
12
- KDRFC_VERSION=Gem.loaded_specs["kramdown-rfc2629"].version rescue "unknown-version"
13
-
14
- Encoding.default_external = "UTF-8" # wake up, smell the coffee
15
-
16
- # Note that this doesn't attempt to handle HT characters
17
- def remove_indentation(s)
18
- l = s.lines
19
- indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min
20
- l.map {|li| li.sub(/^ {0,#{indent}}/, "")}.join
21
- end
22
-
23
- def add_quote(s)
24
- l = s.lines
25
- l.map {|li| "> #{li}"}.join
26
- end
27
-
28
- def process_chunk(s, nested, dedent, fold, quote)
29
- process_includes(s) if nested
30
- s = remove_indentation(s) if dedent
31
- s = fold8792_1(s, *fold) if fold
32
- s = add_quote(s) if quote
33
- s
34
- end
35
-
36
- def process_includes(input)
37
- input.gsub!(/^\{::include((?:-[a-z0-9]+)*)\s+(.*?)\}/) {
38
- include_flags = $1
39
- fn = [$2]
40
- chunks = false
41
- nested = false
42
- dedent = false
43
- fold = false
44
- quote = false
45
- include_flags.split("-") do |flag|
46
- case flag
47
- when ""
48
- when "nested"
49
- nested = true
50
- when "quote"
51
- quote = true
52
- when "dedent"
53
- dedent = true
54
- when /\Afold(\d*)(left(\d*))?(dry)?\z/
55
- fold = [$1.to_i, # col 0 for ''
56
- ($3.to_i if $2), # left 0 for '', nil if no "left"
57
- $4] # dry
58
- when "all", "last"
59
- fn = fn.flat_map{|n| Dir[n]}
60
- fn = [fn.last] if flag == "last"
61
- chunks = fn.map{ |f|
62
- ret = process_chunk(File.read(f), nested, dedent, fold, quote)
63
- nested = false; dedent = false; fold = false; quote = false
64
- ret
65
- }
66
- else
67
- warn "** unknown include flag #{flag}"
68
- end
69
- end
70
- chunks = fn.map{|f| File.read(f)} unless chunks # no all/last
71
- chunks = chunks.map {|ch| process_chunk(ch, nested, dedent, fold, quote)}
72
- chunks.join.chomp
73
- }
74
- end
75
-
76
-
77
- def boilerplate(key)
78
- case key.downcase
79
- when /\Abcp14(info)?(\+)?(-tagged)?\z/i
80
- ret = ''
81
- if $1
82
- ret << <<RFC8174ise
83
- Although this document is not an IETF Standards Track publication, it
84
- adopts the conventions for normative language to provide clarity of
85
- instructions to the implementer.
86
- RFC8174ise
87
- end
88
- ret << <<RFC8174
89
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
90
- NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
91
- "MAY", and "OPTIONAL" in this document are to be interpreted as
92
- described in BCP 14 {{!RFC2119}} {{!RFC8174}} when, and only when, they
93
- appear in all capitals, as shown here.
94
- RFC8174
95
- if $2
96
- ret << <<PLUS
97
- These words may also appear in this document in
98
- lower case as plain English words, absent their normative meanings.
99
- PLUS
100
- end
101
- if $3
102
- if $options.v3
103
- ret << <<TAGGED
104
-
105
- *[MUST]: <bcp14>
106
- *[MUST NOT]: <bcp14>
107
- *[REQUIRED]: <bcp14>
108
- *[SHALL]: <bcp14>
109
- *[SHALL NOT]: <bcp14>
110
- *[SHOULD]: <bcp14>
111
- *[SHOULD NOT]: <bcp14>
112
- *[RECOMMENDED]: <bcp14>
113
- *[NOT RECOMMENDED]: <bcp14>
114
- *[MAY]: <bcp14>
115
- *[OPTIONAL]: <bcp14>
116
- TAGGED
117
- else
118
- warn "** need --v3 to tag bcp14"
119
- end
120
- end
121
- ret
122
- else
123
- warn "** Unknwon boilerplate key: #{key}"
124
- "{::boilerplate #{key}}"
125
- end
126
- end
127
-
128
- def do_the_tls_dance
129
- begin
130
- require 'openssl'
131
- File.open(OpenSSL::X509::DEFAULT_CERT_FILE) do end
132
- # This guards against having an unreadable cert file (yes, that appears to happen a lot).
133
- rescue
134
- if Dir[File.join(OpenSSL::X509::DEFAULT_CERT_DIR, "*.pem")].empty?
135
- # This guards against having no certs at all, not against missing the right one for IETF.
136
- # Oh well.
137
- warn "** Configuration problem with OpenSSL certificate store."
138
- warn "** You may want to examine #{OpenSSL::X509::DEFAULT_CERT_FILE}"
139
- warn "** and #{OpenSSL::X509::DEFAULT_CERT_DIR}."
140
- warn "** Activating suboptimal workaround."
141
- warn "** Occasionally run `certified-update` to maintain that workaround."
142
- require 'certified'
143
- end
144
- end
145
- end
146
-
147
- RE_NL = /(?:\n|\r|\r\n)/
148
- RE_SECTION = /---(?: +(\w+)(-?))?\s*#{RE_NL}(.*?#{RE_NL})(?=---(?:\s+\w+-?)?\s*#{RE_NL}|\Z)/m
149
-
150
- NMDTAGS = ["{:/nomarkdown}\n\n", "\n\n{::nomarkdown}\n"]
151
-
152
- NORMINFORM = { "!" => :normative, "?" => :informative }
153
-
154
- def yaml_load(input, *args)
155
- if YAML.respond_to?(:safe_load)
156
- begin
157
- YAML.safe_load(input, *args)
158
- rescue ArgumentError
159
- YAML.safe_load(input, permitted_classes: args[0], permitted_symbols: args[1], aliases: args[2])
160
- end
161
- else
162
- YAML.load(input)
163
- end
164
- end
165
-
166
- def process_kramdown_options(coding_override = nil,
167
- smart_quotes = nil, typographic_symbols = nil,
168
- header_kramdown_options = nil)
169
-
170
- ascii_target = coding_override && coding_override =~ /ascii/
171
- suppress_typography = ascii_target || $options.v3
172
- entity_output = ascii_target ? :numeric : :as_char;
173
-
174
- options = {input: 'RFC2629Kramdown', entity_output: entity_output, link_defs: {}}
175
-
176
- if smart_quotes.nil? && suppress_typography
177
- smart_quotes = false
178
- end
179
- if smart_quotes == false
180
- smart_quotes = ["'".ord, "'".ord, '"'.ord, '"'.ord]
181
- end
182
- case smart_quotes
183
- when Array
184
- options[:smart_quotes] = smart_quotes
185
- when nil, true
186
- # nothin
187
- else
188
- warn "*** Can't deal with smart_quotes value #{smart_quotes.inspect}"
189
- end
190
-
191
- if typographic_symbols.nil? && suppress_typography
192
- typographic_symbols = false
193
- end
194
- if typographic_symbols == false
195
- typographic_symbols = Hash[::Kramdown::Parser::Kramdown::TYPOGRAPHIC_SYMS.map { |k, v|
196
- if Symbol === v
197
- [v.intern, k]
198
- end
199
- }.compact]
200
- end
201
- # warn [:TYPOGRAPHIC_SYMBOLS, typographic_symbols].to_yaml
202
- case typographic_symbols
203
- when Hash
204
- options[:typographic_symbols] = typographic_symbols
205
- when nil, true
206
- # nothin
207
- else
208
- warn "*** Can't deal with typographic_symbols value #{typographic_symbols.inspect}"
209
- end
210
-
211
- if header_kramdown_options
212
- options.merge! header_kramdown_options
213
- end
214
-
215
- $global_markdown_options = options # For nested calls in bibref annotation processing and xref text
216
-
217
- options
218
- end
219
-
220
- XREF_SECTIONS_RE = ::Kramdown::Parser::RFC2629Kramdown::SECTIONS_RE
221
- XSR_PREFIX = "#{XREF_SECTIONS_RE} of "
222
- XSR_SUFFIX = ", (#{XREF_SECTIONS_RE})| \\((#{XREF_SECTIONS_RE})\\)"
223
- XREF_TXT = ::Kramdown::Parser::RFC2629Kramdown::XREF_TXT
224
- XREF_TXT_SUFFIX = " \\(#{XREF_TXT}\\)"
225
-
226
- def spacify_re(s)
227
- s.gsub(' ', '[\u00A0\s]+')
228
- end
229
-
230
- def xml_from_sections(input)
231
-
232
- unless ENV["KRAMDOWN_NO_SOURCE"]
233
- require 'kramdown-rfc/gzip-clone'
234
- require 'base64'
235
- compressed_input = Gzip.compress(input)
236
- $source = Base64.encode64(compressed_input)
237
- end
238
-
239
- sections = input.scan(RE_SECTION)
240
- # resulting in an array; each section is [section-label, nomarkdown-flag, section-text]
241
-
242
- # the first section is a YAML with front matter parameters (don't put a label here)
243
- # We put back the "---" plus gratuitous blank lines to hack the line number in errors
244
- yaml_in = input[/---\s*/] << sections.shift[2]
245
- ps = KramdownRFC::ParameterSet.new(yaml_load(yaml_in, [Date], [], true))
246
-
247
- coding_override = ps.has(:coding)
248
- smart_quotes = ps[:smart_quotes]
249
- typographic_symbols = ps[:typographic_symbols]
250
- header_kramdown_options = ps[:kramdown_options]
251
-
252
- kramdown_options = process_kramdown_options(coding_override,
253
- smart_quotes, typographic_symbols,
254
- header_kramdown_options)
255
-
256
- # all the other sections are put in a Hash, possibly concatenated from parts there
257
- sechash = Hash.new{ |h,k| h[k] = ""}
258
- snames = [] # a stack of section names
259
- sections.each do |sname, nmdflag, text|
260
- # warn [:SNAME, sname, nmdflag, text[0..10]].inspect
261
- nmdin, nmdout = {
262
- "-" => ["", ""], # stay in nomarkdown
263
- "" => NMDTAGS, # pop out temporarily
264
- }[nmdflag || ""]
265
- if sname
266
- snames << sname # "--- label" -> push label (now current)
267
- else
268
- snames.pop # just "---" -> pop label (previous now current)
269
- end
270
- sechash[snames.last] << "#{nmdin}#{text}#{nmdout}"
271
- end
272
-
273
- ref_replacements = { }
274
- anchor_to_bibref = { }
275
-
276
- [:ref, :normative, :informative].each do |sn|
277
- if refs = ps.has(sn)
278
- warn "*** bad section #{sn}: #{refs.inspect}" unless refs.respond_to? :each
279
- refs.each do |k, v|
280
- if v.respond_to? :to_str
281
- if bibtagsys(v) # enable "foo: RFC4711" as a custom anchor definition
282
- anchor_to_bibref[k] = v.to_str
283
- end
284
- ref_replacements[v.to_str] = k
285
- end
286
- if Hash === v
287
- if aliasname = v.delete("-")
288
- ref_replacements[aliasname] = k
289
- end
290
- if bibref = v.delete("=")
291
- anchor_to_bibref[k] = bibref
292
- end
293
- end
294
- end
295
- end
296
- end
297
- open_refs = ps[:ref] || { } # consumed
298
-
299
- norm_ref = { }
300
-
301
- # convenience replacement of {{-coap}} with {{I-D.ietf-core-coap}}
302
- # collect normative/informative tagging {{!RFC2119}} {{?RFC4711}}
303
- sechash.each do |k, v|
304
- next if k == "fluff"
305
- v.gsub!(/{{(#{
306
- spacify_re(XSR_PREFIX)
307
- })?(?:([?!])(-)?|(-))([\w._\-]+)(?:=([\w.\/_\-]+))?(#{
308
- XREF_TXT_SUFFIX
309
- })?(#{
310
- spacify_re(XSR_SUFFIX)
311
- })?}}/) do |match|
312
- xsr_prefix = $1
313
- norminform = $2
314
- replacing = $3 || $4
315
- word = $5
316
- bibref = $6
317
- xrt_suffix = $7
318
- xsr_suffix = $8
319
- if replacing
320
- if new = ref_replacements[word]
321
- word = new
322
- else
323
- warn "*** no alias replacement for {{-#{word}}}"
324
- word = "-#{word}"
325
- end
326
- end # now, word is the anchor
327
- if bibref
328
- if old = anchor_to_bibref[word]
329
- if bibref != old
330
- warn "*** conflicting definitions for xref #{word}: #{old} != #{bibref}"
331
- end
332
- else
333
- anchor_to_bibref[word] = bibref
334
- end
335
- end
336
-
337
- # things can be normative in one place and informative in another -> normative
338
- # collect norm/inform above and assign it by priority here
339
- if norminform
340
- norm_ref[word] ||= norminform == '!' # one normative ref is enough
341
- end
342
- "{{#{xsr_prefix}#{word}#{xrt_suffix}#{xsr_suffix}}}"
343
- end
344
- end
345
-
346
- [:normative, :informative].each do |k|
347
- ps.rest[k.to_s] ||= { }
348
- end
349
-
350
- norm_ref.each do |k, v|
351
- # could check bibtagsys here: needed if open_refs is nil or string
352
- target = ps.has(v ? :normative : :informative)
353
- warn "*** overwriting #{k}" if target.has_key?(k)
354
- target[k] = open_refs[k] # add reference to normative/informative
355
- end
356
- # note that unused items from ref are considered OK, therefore no check for that here
357
-
358
- # also should allow norm/inform check of other references
359
- # {{?coap}} vs. {{!coap}} vs. {{-coap}} (undecided)
360
- # or {{?-coap}} vs. {{!-coap}} vs. {{-coap}} (undecided)
361
- # could require all references to be decided by a global flag
362
- overlap = [:normative, :informative].map { |s| (ps.has(s) || { }).keys }.reduce(:&)
363
- unless overlap.empty?
364
- warn "*** #{overlap.join(', ')}: both normative and informative"
365
- end
366
-
367
- stand_alone = ps[:stand_alone]
368
-
369
- [:normative, :informative].each do |sn|
370
- if refs = ps[sn]
371
- refs.each do |k, v|
372
- href = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(k)
373
- kramdown_options[:link_defs][k] = ["##{href}", nil] # allow [RFC2119] in addition to {{RFC2119}}
374
-
375
- bibref = anchor_to_bibref[k] || k
376
- bts, url = bibtagsys(bibref, k, stand_alone)
377
- if bts && (!v || v == {} || v.respond_to?(:to_str))
378
- if stand_alone
379
- a = %{{: anchor="#{k}"}}
380
- sechash[sn.to_s] << %{\n#{NMDTAGS[0]}\n![:include:](#{bts})#{a}\n#{NMDTAGS[1]}\n}
381
- else
382
- bts.gsub!('/', '_')
383
- (ps.rest["bibxml"] ||= []) << [bts, url]
384
- sechash[sn.to_s] << %{&#{bts};\n} # ???
385
- end
386
- else
387
- unless v && Hash === v
388
- warn "*** don't know how to expand ref #{k}"
389
- next
390
- end
391
- if bts && !v.delete("override")
392
- warn "*** warning: explicit settings completely override canned bibxml in reference #{k}"
393
- end
394
- sechash[sn.to_s] << KramdownRFC::ref_to_xml(href, v)
395
- end
396
- end
397
- end
398
- end
399
-
400
- erbfilename = File.expand_path '../../data/kramdown-rfc2629.erb', __FILE__
401
- erbfile = File.read(erbfilename, coding: "UTF-8")
402
- erb = ERB.trim_new(erbfile, '-')
403
- # remove redundant nomarkdown pop outs/pop ins as they confuse kramdown
404
- input = erb.result(binding).gsub(%r"{::nomarkdown}\s*{:/nomarkdown}"m, "")
405
- ps.warn_if_leftovers
406
- sechash.delete("fluff") # fluff is a "commented out" section
407
- if !sechash.empty? # any sections unused by the ERb file?
408
- warn "*** sections left #{sechash.keys.inspect}!"
409
- end
410
-
411
- [input, kramdown_options, coding_override]
412
- end
413
-
414
- XML_RESOURCE_ORG_PREFIX = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_PREFIX
415
-
416
- # return XML entity name, url, rewrite_anchor flag
417
- def bibtagsys(bib, anchor=nil, stand_alone=true)
418
- if bib =~ /\Arfc(\d+)/i
419
- rfc4d = "%04d" % $1.to_i
420
- [bib.upcase,
421
- "#{XML_RESOURCE_ORG_PREFIX}/bibxml/reference.RFC.#{rfc4d}.xml"]
422
- elsif $options.v3 && bib =~ /\A(bcp|std)(\d+)/i
423
- n4d = "%04d" % $2.to_i
424
- [bib.upcase,
425
- "#{XML_RESOURCE_ORG_PREFIX}/bibxml-rfcsubseries-new/reference.#{$1.upcase}.#{n4d}.xml"]
426
- elsif bib =~ /\A([-A-Z0-9]+)\./ &&
427
- (xro = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_MAP[$1])
428
- dir, _ttl, rewrite_anchor = xro
429
- bib1 = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(bib)
430
- if anchor && bib1 != anchor
431
- if rewrite_anchor
432
- a = %{?anchor=#{anchor}}
433
- else
434
- if !stand_alone
435
- warn "*** selecting a custom anchor '#{anchor}' for '#{bib1}' requires stand_alone mode"
436
- warn " the output will need manual editing to correct this"
437
- end
438
- end
439
- end
440
- [bib1,
441
- "#{XML_RESOURCE_ORG_PREFIX}/#{dir}/reference.#{bib}.xml#{a}"]
442
- end
443
- end
444
-
445
- def read_encodings
446
- encfilename = File.expand_path '../../data/encoding-fallbacks.txt', __FILE__
447
- encfile = File.read(encfilename, coding: "UTF-8")
448
- Hash[encfile.lines.map{|l|
449
- l.chomp!;
450
- x, s = l.split(" ", 2)
451
- [x.hex.chr(Encoding::UTF_8), s || " "]}]
452
- end
453
-
454
- FALLBACK = read_encodings
455
-
456
- def expand_tabs(s, tab_stops = 8)
457
- s.gsub(/([^\t\n]*)\t/) do
458
- $1 + " " * (tab_stops - ($1.size % tab_stops))
459
- end
460
- end
461
-
462
-
463
- require 'optparse'
464
- require 'ostruct'
465
-
466
- $options = OpenStruct.new
467
- op = OptionParser.new do |opts|
468
- opts.banner = <<BANNER
469
- Usage: kramdown-rfc2629 [options] file.md|file.mkd > file.xml
470
- Version: #{KDRFC_VERSION}
471
- BANNER
472
- opts.on("-V", "--version", "Show version and exit") do |v|
473
- puts "kramdown-rfc2629 #{KDRFC_VERSION}"
474
- exit
475
- end
476
- opts.on("-H", "--help", "Show option summary and exit") do |v|
477
- puts opts
478
- exit
479
- end
480
- opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
481
- $options.verbose = v
482
- end
483
- opts.on("-3", "--[no-]v3", "Use RFCXML v3 processing rules") do |v|
484
- $options.v3 = v
485
- end
486
- end
487
- op.parse!
488
-
489
- if $options.verbose && $options.v3
490
- warn "*** not much RFCXMLv3 stuff implemented yet"
491
- end
492
-
493
- input = ARGF.read
494
- if input[0] == "\uFEFF"
495
- warn "*** There is a leading byte order mark. Ignored."
496
- input[0..0] = ''
497
- end
498
- if input[-1] != "\n"
499
- # warn "*** added missing newline at end"
500
- input << "\n" # fix #26
501
- end
502
- process_includes(input) unless ENV["KRAMDOWN_SAFE"]
503
- input.gsub!(/^\{::boilerplate\s+(.*?)\}/) {
504
- boilerplate($1)
505
- }
506
- if input =~ /[\t]/
507
- warn "*** Input contains HT (\"tab\") characters. Undefined behavior will ensue."
508
- input = expand_tabs(input)
509
- end
510
-
511
- if input =~ /\A---/ # this is a sectionized file
512
- do_the_tls_dance unless ENV["KRAMDOWN_DONT_VERIFY_HTTPS"]
513
- input, options, coding_override = xml_from_sections(input)
514
- else
515
- options = process_kramdown_options # all default
516
- end
517
- if input =~ /\A<\?xml/ # if this is a whole XML file, protect it
518
- input = "{::nomarkdown}\n#{input}\n{:/nomarkdown}\n"
519
- end
520
-
521
- if coding_override
522
- input = input.encode(Encoding.find(coding_override), fallback: FALLBACK)
523
- end
524
-
525
- # 1.4.17: because of UTF-8 bibxml files, kramdown always needs to see UTF-8 (!)
526
- if input.encoding != Encoding::UTF_8
527
- input = input.encode(Encoding::UTF_8)
528
- end
529
-
530
- # warn "options: #{options.inspect}"
531
- doc = Kramdown::Document.new(input, options)
532
- $stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
533
- output = doc.to_rfc2629
534
-
535
- if coding_override
536
- output = output.encode(Encoding.find(coding_override), fallback: FALLBACK)
537
- end
538
-
539
- puts output
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'kramdown-rfc2629'
3
- s.version = '1.5.26'
3
+ s.version = '1.6.1'
4
4
  s.summary = "Kramdown extension for generating RFC 7749 XML."
5
5
  s.description = %{An RFC7749 (XML2RFC) generating backend for Thomas Leitner's
6
6
  "kramdown" markdown parser. Mostly useful for RFC writers.}
@@ -8,9 +8,9 @@ spec = Gem::Specification.new do |s|
8
8
  s.add_dependency('kramdown-parser-gfm', '~> 1.1')
9
9
  s.add_dependency('certified', '~> 1.0')
10
10
  s.add_dependency('json_pure', '~> 2.0')
11
- s.files = Dir['lib/**/*.rb'] + %w(README.md LICENSE kramdown-rfc2629.gemspec bin/kdrfc bin/kramdown-rfc2629 bin/doilit bin/kramdown-rfc-extract-markdown data/kramdown-rfc2629.erb data/encoding-fallbacks.txt data/math.json bin/kramdown-rfc-cache-subseries-bibxml bin/de-gfm)
11
+ s.files = Dir['lib/**/*.rb'] + %w(README.md LICENSE kramdown-rfc2629.gemspec bin/kdrfc bin/kramdown-rfc bin/kramdown-rfc2629 bin/doilit bin/kramdown-rfc-extract-markdown data/kramdown-rfc2629.erb data/encoding-fallbacks.txt data/math.json bin/kramdown-rfc-cache-subseries-bibxml bin/de-gfm)
12
12
  s.require_path = 'lib'
13
- s.executables = ['kramdown-rfc2629', 'doilit', 'kramdown-rfc-extract-markdown',
13
+ s.executables = ['kramdown-rfc', 'kramdown-rfc2629', 'doilit', 'kramdown-rfc-extract-markdown',
14
14
  'kdrfc', 'kramdown-rfc-cache-i-d-bibxml',
15
15
  'kramdown-rfc-cache-subseries-bibxml', 'de-gfm']
16
16
  s.required_ruby_version = '>= 2.3.0'
@@ -0,0 +1,572 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'kramdown-rfc2629'
4
+ require 'kramdown-rfc/parameterset'
5
+ require 'kramdown-rfc/refxml'
6
+ require 'kramdown-rfc/rfc8792'
7
+ require 'yaml'
8
+ require 'kramdown-rfc/erb'
9
+ require 'date'
10
+
11
+ # try to get this from gemspec.
12
+ KDRFC_VERSION=Gem.loaded_specs["kramdown-rfc2629"].version rescue "unknown-version"
13
+
14
+ Encoding.default_external = "UTF-8" # wake up, smell the coffee
15
+
16
+ # Note that this doesn't attempt to handle HT characters
17
+ def remove_indentation(s)
18
+ l = s.lines
19
+ indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min
20
+ l.map {|li| li.sub(/^ {0,#{indent}}/, "")}.join
21
+ end
22
+
23
+ def add_quote(s)
24
+ l = s.lines
25
+ l.map {|li| "> #{li}"}.join
26
+ end
27
+
28
+ def process_chunk(s, nested, dedent, fold, quote)
29
+ process_includes(s) if nested
30
+ s = remove_indentation(s) if dedent
31
+ s = fold8792_1(s, *fold) if fold
32
+ s = add_quote(s) if quote
33
+ s
34
+ end
35
+
36
+ def process_includes(input)
37
+ input.gsub!(/^\{::include((?:-[a-z0-9]+)*)\s+(.*?)\}/) {
38
+ include_flags = $1
39
+ fn = [$2]
40
+ chunks = false
41
+ nested = false
42
+ dedent = false
43
+ fold = false
44
+ quote = false
45
+ include_flags.split("-") do |flag|
46
+ case flag
47
+ when ""
48
+ when "nested"
49
+ nested = true
50
+ when "quote"
51
+ quote = true
52
+ when "dedent"
53
+ dedent = true
54
+ when /\Afold(\d*)(left(\d*))?(dry)?\z/
55
+ fold = [$1.to_i, # col 0 for ''
56
+ ($3.to_i if $2), # left 0 for '', nil if no "left"
57
+ $4] # dry
58
+ when "all", "last"
59
+ fn = fn.flat_map{|n| Dir[n]}
60
+ fn = [fn.last] if flag == "last"
61
+ chunks = fn.map{ |f|
62
+ ret = process_chunk(File.read(f), nested, dedent, fold, quote)
63
+ nested = false; dedent = false; fold = false; quote = false
64
+ ret
65
+ }
66
+ else
67
+ warn "** unknown include flag #{flag}"
68
+ end
69
+ end
70
+ chunks = fn.map{|f| File.read(f)} unless chunks # no all/last
71
+ chunks = chunks.map {|ch| process_chunk(ch, nested, dedent, fold, quote)}
72
+ chunks.join.chomp
73
+ }
74
+ end
75
+
76
+
77
+ def boilerplate(key)
78
+ case key.downcase
79
+ when /\Abcp14(info)?(\+)?(-tagged)?\z/i
80
+ ret = ''
81
+ if $1
82
+ ret << <<RFC8174ise
83
+ Although this document is not an IETF Standards Track publication, it
84
+ adopts the conventions for normative language to provide clarity of
85
+ instructions to the implementer.
86
+ RFC8174ise
87
+ end
88
+ ret << <<RFC8174
89
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
90
+ NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
91
+ "MAY", and "OPTIONAL" in this document are to be interpreted as
92
+ described in BCP 14 {{!RFC2119}} {{!RFC8174}} when, and only when, they
93
+ appear in all capitals, as shown here.
94
+ RFC8174
95
+ if $2
96
+ ret << <<PLUS
97
+ These words may also appear in this document in
98
+ lower case as plain English words, absent their normative meanings.
99
+ PLUS
100
+ end
101
+ if $3
102
+ ($options.v3_used ||= []) << "** need --v3 to tag bcp14"
103
+ ret << <<TAGGED
104
+
105
+ *[MUST]: <bcp14>
106
+ *[MUST NOT]: <bcp14>
107
+ *[REQUIRED]: <bcp14>
108
+ *[SHALL]: <bcp14>
109
+ *[SHALL NOT]: <bcp14>
110
+ *[SHOULD]: <bcp14>
111
+ *[SHOULD NOT]: <bcp14>
112
+ *[RECOMMENDED]: <bcp14>
113
+ *[NOT RECOMMENDED]: <bcp14>
114
+ *[MAY]: <bcp14>
115
+ *[OPTIONAL]: <bcp14>
116
+ TAGGED
117
+ end
118
+ ret
119
+ else
120
+ warn "** Unknwon boilerplate key: #{key}"
121
+ "{::boilerplate #{key}}"
122
+ end
123
+ end
124
+
125
+ def do_the_tls_dance
126
+ begin
127
+ require 'openssl'
128
+ File.open(OpenSSL::X509::DEFAULT_CERT_FILE) do end
129
+ # This guards against having an unreadable cert file (yes, that appears to happen a lot).
130
+ rescue
131
+ if Dir[File.join(OpenSSL::X509::DEFAULT_CERT_DIR, "*.pem")].empty?
132
+ # This guards against having no certs at all, not against missing the right one for IETF.
133
+ # Oh well.
134
+ warn "** Configuration problem with OpenSSL certificate store."
135
+ warn "** You may want to examine #{OpenSSL::X509::DEFAULT_CERT_FILE}"
136
+ warn "** and #{OpenSSL::X509::DEFAULT_CERT_DIR}."
137
+ warn "** Activating suboptimal workaround."
138
+ warn "** Occasionally run `certified-update` to maintain that workaround."
139
+ require 'certified'
140
+ end
141
+ end
142
+ end
143
+
144
+ RE_NL = /(?:\n|\r|\r\n)/
145
+ RE_SECTION = /---(?: +(\w+)(-?))?\s*#{RE_NL}(.*?#{RE_NL})(?=---(?:\s+\w+-?)?\s*#{RE_NL}|\Z)/m
146
+
147
+ NMDTAGS = ["{:/nomarkdown}\n\n", "\n\n{::nomarkdown}\n"]
148
+
149
+ NORMINFORM = { "!" => :normative, "?" => :informative }
150
+
151
+ def yaml_load(input, *args)
152
+ if YAML.respond_to?(:safe_load)
153
+ begin
154
+ YAML.safe_load(input, *args)
155
+ rescue ArgumentError
156
+ YAML.safe_load(input, permitted_classes: args[0], permitted_symbols: args[1], aliases: args[2])
157
+ end
158
+ else
159
+ YAML.load(input)
160
+ end
161
+ end
162
+
163
+ def process_kramdown_options(coding_override = nil,
164
+ smart_quotes = nil, typographic_symbols = nil,
165
+ header_kramdown_options = nil)
166
+
167
+ ascii_target = coding_override && coding_override =~ /ascii/
168
+ suppress_typography = ascii_target || $options.v3
169
+ entity_output = ascii_target ? :numeric : :as_char;
170
+
171
+ options = {input: 'RFC2629Kramdown', entity_output: entity_output, link_defs: {}}
172
+
173
+ if smart_quotes.nil? && suppress_typography
174
+ smart_quotes = false
175
+ end
176
+ if smart_quotes == false
177
+ smart_quotes = ["'".ord, "'".ord, '"'.ord, '"'.ord]
178
+ end
179
+ case smart_quotes
180
+ when Array
181
+ options[:smart_quotes] = smart_quotes
182
+ when nil, true
183
+ # nothin
184
+ else
185
+ warn "*** Can't deal with smart_quotes value #{smart_quotes.inspect}"
186
+ end
187
+
188
+ if typographic_symbols.nil? && suppress_typography
189
+ typographic_symbols = false
190
+ end
191
+ if typographic_symbols == false
192
+ typographic_symbols = Hash[::Kramdown::Parser::Kramdown::TYPOGRAPHIC_SYMS.map { |k, v|
193
+ if Symbol === v
194
+ [v.intern, k]
195
+ end
196
+ }.compact]
197
+ end
198
+ # warn [:TYPOGRAPHIC_SYMBOLS, typographic_symbols].to_yaml
199
+ case typographic_symbols
200
+ when Hash
201
+ options[:typographic_symbols] = typographic_symbols
202
+ when nil, true
203
+ # nothin
204
+ else
205
+ warn "*** Can't deal with typographic_symbols value #{typographic_symbols.inspect}"
206
+ end
207
+
208
+ if header_kramdown_options
209
+ options.merge! header_kramdown_options
210
+ end
211
+
212
+ $global_markdown_options = options # For nested calls in bibref annotation processing and xref text
213
+
214
+ options
215
+ end
216
+
217
+ XREF_SECTIONS_RE = ::Kramdown::Parser::RFC2629Kramdown::SECTIONS_RE
218
+ XSR_PREFIX = "#{XREF_SECTIONS_RE} of "
219
+ XSR_SUFFIX = ", (#{XREF_SECTIONS_RE})| \\((#{XREF_SECTIONS_RE})\\)"
220
+ XREF_TXT = ::Kramdown::Parser::RFC2629Kramdown::XREF_TXT
221
+ XREF_TXT_SUFFIX = " \\(#{XREF_TXT}\\)"
222
+
223
+ def spacify_re(s)
224
+ s.gsub(' ', '[\u00A0\s]+')
225
+ end
226
+
227
+ def xml_from_sections(input)
228
+
229
+ unless ENV["KRAMDOWN_NO_SOURCE"]
230
+ require 'kramdown-rfc/gzip-clone'
231
+ require 'base64'
232
+ compressed_input = Gzip.compress(input)
233
+ $source = Base64.encode64(compressed_input)
234
+ end
235
+
236
+ sections = input.scan(RE_SECTION)
237
+ # resulting in an array; each section is [section-label, nomarkdown-flag, section-text]
238
+
239
+ # the first section is a YAML with front matter parameters (don't put a label here)
240
+ # We put back the "---" plus gratuitous blank lines to hack the line number in errors
241
+ yaml_in = input[/---\s*/] << sections.shift[2]
242
+ ps = KramdownRFC::ParameterSet.new(yaml_load(yaml_in, [Date], [], true))
243
+
244
+ if v = ps[:v]
245
+ warn "*** unsupported RFCXML version #{v}" if v != 3
246
+ if $options.v2
247
+ warn "*** command line --v2 wins over document's 'v: #{v}'"
248
+ else
249
+ $options.v3 = true
250
+ $options.v = 3
251
+ ps.default!(:stand_alone, true)
252
+ ps.default!(:ipr, "trust200902")
253
+ ps.default!(:pi, {"toc" => true, "sortrefs" => true, "symrefs" => true})
254
+ end
255
+ end
256
+
257
+ coding_override = ps.has(:coding)
258
+ smart_quotes = ps[:smart_quotes]
259
+ typographic_symbols = ps[:typographic_symbols]
260
+ header_kramdown_options = ps[:kramdown_options]
261
+
262
+ kramdown_options = process_kramdown_options(coding_override,
263
+ smart_quotes, typographic_symbols,
264
+ header_kramdown_options)
265
+
266
+ # all the other sections are put in a Hash, possibly concatenated from parts there
267
+ sechash = Hash.new{ |h,k| h[k] = ""}
268
+ snames = [] # a stack of section names
269
+ sections.each do |sname, nmdflag, text|
270
+ # warn [:SNAME, sname, nmdflag, text[0..10]].inspect
271
+ nmdin, nmdout = {
272
+ "-" => ["", ""], # stay in nomarkdown
273
+ "" => NMDTAGS, # pop out temporarily
274
+ }[nmdflag || ""]
275
+ if sname
276
+ snames << sname # "--- label" -> push label (now current)
277
+ else
278
+ snames.pop # just "---" -> pop label (previous now current)
279
+ end
280
+ sechash[snames.last] << "#{nmdin}#{text}#{nmdout}"
281
+ end
282
+
283
+ ref_replacements = { }
284
+ anchor_to_bibref = { }
285
+
286
+ [:ref, :normative, :informative].each do |sn|
287
+ if refs = ps.has(sn)
288
+ warn "*** bad section #{sn}: #{refs.inspect}" unless refs.respond_to? :each
289
+ refs.each do |k, v|
290
+ if v.respond_to? :to_str
291
+ if bibtagsys(v) # enable "foo: RFC4711" as a custom anchor definition
292
+ anchor_to_bibref[k] = v.to_str
293
+ end
294
+ ref_replacements[v.to_str] = k
295
+ end
296
+ if Hash === v
297
+ if aliasname = v.delete("-")
298
+ ref_replacements[aliasname] = k
299
+ end
300
+ if bibref = v.delete("=")
301
+ anchor_to_bibref[k] = bibref
302
+ end
303
+ end
304
+ end
305
+ end
306
+ end
307
+ open_refs = ps[:ref] || { } # consumed
308
+
309
+ norm_ref = { }
310
+
311
+ # convenience replacement of {{-coap}} with {{I-D.ietf-core-coap}}
312
+ # collect normative/informative tagging {{!RFC2119}} {{?RFC4711}}
313
+ sechash.each do |k, v|
314
+ next if k == "fluff"
315
+ v.gsub!(/{{(#{
316
+ spacify_re(XSR_PREFIX)
317
+ })?(?:([?!])(-)?|(-))([\w._\-]+)(?:=([\w.\/_\-]+))?(#{
318
+ XREF_TXT_SUFFIX
319
+ })?(#{
320
+ spacify_re(XSR_SUFFIX)
321
+ })?}}/) do |match|
322
+ xsr_prefix = $1
323
+ norminform = $2
324
+ replacing = $3 || $4
325
+ word = $5
326
+ bibref = $6
327
+ xrt_suffix = $7
328
+ xsr_suffix = $8
329
+ if replacing
330
+ if new = ref_replacements[word]
331
+ word = new
332
+ else
333
+ warn "*** no alias replacement for {{-#{word}}}"
334
+ word = "-#{word}"
335
+ end
336
+ end # now, word is the anchor
337
+ if bibref
338
+ if old = anchor_to_bibref[word]
339
+ if bibref != old
340
+ warn "*** conflicting definitions for xref #{word}: #{old} != #{bibref}"
341
+ end
342
+ else
343
+ anchor_to_bibref[word] = bibref
344
+ end
345
+ end
346
+
347
+ # things can be normative in one place and informative in another -> normative
348
+ # collect norm/inform above and assign it by priority here
349
+ if norminform
350
+ norm_ref[word] ||= norminform == '!' # one normative ref is enough
351
+ end
352
+ "{{#{xsr_prefix}#{word}#{xrt_suffix}#{xsr_suffix}}}"
353
+ end
354
+ end
355
+
356
+ [:normative, :informative].each do |k|
357
+ ps.rest[k.to_s] ||= { }
358
+ end
359
+
360
+ norm_ref.each do |k, v|
361
+ # could check bibtagsys here: needed if open_refs is nil or string
362
+ target = ps.has(v ? :normative : :informative)
363
+ warn "*** overwriting #{k}" if target.has_key?(k)
364
+ target[k] = open_refs[k] # add reference to normative/informative
365
+ end
366
+ # note that unused items from ref are considered OK, therefore no check for that here
367
+
368
+ # also should allow norm/inform check of other references
369
+ # {{?coap}} vs. {{!coap}} vs. {{-coap}} (undecided)
370
+ # or {{?-coap}} vs. {{!-coap}} vs. {{-coap}} (undecided)
371
+ # could require all references to be decided by a global flag
372
+ overlap = [:normative, :informative].map { |s| (ps.has(s) || { }).keys }.reduce(:&)
373
+ unless overlap.empty?
374
+ warn "*** #{overlap.join(', ')}: both normative and informative"
375
+ end
376
+
377
+ stand_alone = ps[:stand_alone]
378
+
379
+ [:normative, :informative].each do |sn|
380
+ if refs = ps[sn]
381
+ refs.each do |k, v|
382
+ href = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(k)
383
+ kramdown_options[:link_defs][k] = ["##{href}", nil] # allow [RFC2119] in addition to {{RFC2119}}
384
+
385
+ bibref = anchor_to_bibref[k] || k
386
+ bts, url = bibtagsys(bibref, k, stand_alone)
387
+ if bts && (!v || v == {} || v.respond_to?(:to_str))
388
+ if stand_alone
389
+ a = %{{: anchor="#{k}"}}
390
+ sechash[sn.to_s] << %{\n#{NMDTAGS[0]}\n![:include:](#{bts})#{a}\n#{NMDTAGS[1]}\n}
391
+ else
392
+ bts.gsub!('/', '_')
393
+ (ps.rest["bibxml"] ||= []) << [bts, url]
394
+ sechash[sn.to_s] << %{&#{bts};\n} # ???
395
+ end
396
+ else
397
+ unless v && Hash === v
398
+ warn "*** don't know how to expand ref #{k}"
399
+ next
400
+ end
401
+ if bts && !v.delete("override")
402
+ warn "*** warning: explicit settings completely override canned bibxml in reference #{k}"
403
+ end
404
+ sechash[sn.to_s] << KramdownRFC::ref_to_xml(href, v)
405
+ end
406
+ end
407
+ end
408
+ end
409
+
410
+ erbfilename = File.expand_path '../../../data/kramdown-rfc2629.erb', __FILE__
411
+ erbfile = File.read(erbfilename, coding: "UTF-8")
412
+ erb = ERB.trim_new(erbfile, '-')
413
+ # remove redundant nomarkdown pop outs/pop ins as they confuse kramdown
414
+ input = erb.result(binding).gsub(%r"{::nomarkdown}\s*{:/nomarkdown}"m, "")
415
+ ps.warn_if_leftovers
416
+ sechash.delete("fluff") # fluff is a "commented out" section
417
+ if !sechash.empty? # any sections unused by the ERb file?
418
+ warn "*** sections left #{sechash.keys.inspect}!"
419
+ end
420
+
421
+ [input, kramdown_options, coding_override]
422
+ end
423
+
424
+ XML_RESOURCE_ORG_PREFIX = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_PREFIX
425
+
426
+ # return XML entity name, url, rewrite_anchor flag
427
+ def bibtagsys(bib, anchor=nil, stand_alone=true)
428
+ if bib =~ /\Arfc(\d+)/i
429
+ rfc4d = "%04d" % $1.to_i
430
+ [bib.upcase,
431
+ "#{XML_RESOURCE_ORG_PREFIX}/bibxml/reference.RFC.#{rfc4d}.xml"]
432
+ elsif $options.v3 && bib =~ /\A(bcp|std)(\d+)/i
433
+ n4d = "%04d" % $2.to_i
434
+ [bib.upcase,
435
+ "#{XML_RESOURCE_ORG_PREFIX}/bibxml-rfcsubseries-new/reference.#{$1.upcase}.#{n4d}.xml"]
436
+ elsif bib =~ /\A([-A-Z0-9]+)\./ &&
437
+ (xro = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_MAP[$1])
438
+ dir, _ttl, rewrite_anchor = xro
439
+ bib1 = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(bib)
440
+ if anchor && bib1 != anchor
441
+ if rewrite_anchor
442
+ a = %{?anchor=#{anchor}}
443
+ else
444
+ if !stand_alone
445
+ warn "*** selecting a custom anchor '#{anchor}' for '#{bib1}' requires stand_alone mode"
446
+ warn " the output will need manual editing to correct this"
447
+ end
448
+ end
449
+ end
450
+ [bib1,
451
+ "#{XML_RESOURCE_ORG_PREFIX}/#{dir}/reference.#{bib}.xml#{a}"]
452
+ end
453
+ end
454
+
455
+ def read_encodings
456
+ encfilename = File.expand_path '../../../data/encoding-fallbacks.txt', __FILE__
457
+ encfile = File.read(encfilename, coding: "UTF-8")
458
+ Hash[encfile.lines.map{|l|
459
+ l.chomp!;
460
+ x, s = l.split(" ", 2)
461
+ [x.hex.chr(Encoding::UTF_8), s || " "]}]
462
+ end
463
+
464
+ FALLBACK = read_encodings
465
+
466
+ def expand_tabs(s, tab_stops = 8)
467
+ s.gsub(/([^\t\n]*)\t/) do
468
+ $1 + " " * (tab_stops - ($1.size % tab_stops))
469
+ end
470
+ end
471
+
472
+
473
+ require 'optparse'
474
+ require 'ostruct'
475
+
476
+ $options ||= OpenStruct.new
477
+ op = OptionParser.new do |opts|
478
+ opts.banner = <<BANNER
479
+ Usage: kramdown-rfc2629 [options] file.md|file.mkd > file.xml
480
+ Version: #{KDRFC_VERSION}
481
+ BANNER
482
+ opts.on("-V", "--version", "Show version and exit") do |v|
483
+ puts "kramdown-rfc2629 #{KDRFC_VERSION}"
484
+ exit
485
+ end
486
+ opts.on("-H", "--help", "Show option summary and exit") do |v|
487
+ puts opts
488
+ exit
489
+ end
490
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
491
+ $options.verbose = v
492
+ end
493
+ opts.on("-3", "--[no-]v3", "Use RFCXML v3 processing rules") do |v|
494
+ $options.v3 = v
495
+ end
496
+ opts.on("-2", "--[no-]v2", "Use RFCXML v2 processing rules") do |v|
497
+ $options.v2 = v
498
+ end
499
+ end
500
+ op.parse!
501
+
502
+ if $options.v2 && $options.v3
503
+ warn "*** can't have v2 and eat v3 cake"
504
+ $options.v2 = false
505
+ end
506
+
507
+ if $options.v3.nil? && !$options.v2
508
+ if Time.now.to_i >= 1645567342 # Time.parse("2022-02-22T22:02:22Z").to_i
509
+ $options.v3 = true # new default from the above date
510
+ end
511
+ end
512
+
513
+ warn "*** v2 #{$options.v2.inspect} v3 #{$options.v3.inspect}" if $options.verbose
514
+
515
+ input = ARGF.read
516
+ if input[0] == "\uFEFF"
517
+ warn "*** There is a leading byte order mark. Ignored."
518
+ input[0..0] = ''
519
+ end
520
+ if input[-1] != "\n"
521
+ # warn "*** added missing newline at end"
522
+ input << "\n" # fix #26
523
+ end
524
+ process_includes(input) unless ENV["KRAMDOWN_SAFE"]
525
+ input.gsub!(/^\{::boilerplate\s+(.*?)\}/) {
526
+ boilerplate($1)
527
+ }
528
+ if input =~ /[\t]/
529
+ warn "*** Input contains HT (\"tab\") characters. Undefined behavior will ensue."
530
+ input = expand_tabs(input)
531
+ end
532
+
533
+ if input =~ /\A---/ # this is a sectionized file
534
+ do_the_tls_dance unless ENV["KRAMDOWN_DONT_VERIFY_HTTPS"]
535
+ input, options, coding_override = xml_from_sections(input)
536
+ else
537
+ options = process_kramdown_options # all default
538
+ end
539
+ if input =~ /\A<\?xml/ # if this is a whole XML file, protect it
540
+ input = "{::nomarkdown}\n#{input}\n{:/nomarkdown}\n"
541
+ end
542
+
543
+ if $options.v3_used && !$options.v3
544
+ warn $options.v3_used
545
+ $options.v3_used = nil
546
+ $options.v3 = true
547
+ end
548
+
549
+ if coding_override
550
+ input = input.encode(Encoding.find(coding_override), fallback: FALLBACK)
551
+ end
552
+
553
+ # 1.4.17: because of UTF-8 bibxml files, kramdown always needs to see UTF-8 (!)
554
+ if input.encoding != Encoding::UTF_8
555
+ input = input.encode(Encoding::UTF_8)
556
+ end
557
+
558
+ # warn "options: #{options.inspect}"
559
+ doc = Kramdown::Document.new(input, options)
560
+ $stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
561
+ output = doc.to_rfc2629
562
+
563
+ if $options.v3_used && !$options.v3
564
+ warn $options.v3_used
565
+ $options.v3 = true
566
+ end
567
+
568
+ if coding_override
569
+ output = output.encode(Encoding.find(coding_override), fallback: FALLBACK)
570
+ end
571
+
572
+ puts output
@@ -18,7 +18,8 @@ class KDRFC
18
18
  KDRFC_PREPEND = [ENV["KDRFC_PREPEND"]].compact
19
19
 
20
20
  def v3_flag?
21
- @options.v3 ? ["--v3"] : []
21
+ [*(@options.v3 ? ["--v3"] : []),
22
+ *(@options.v2 ? ["--v2"] : [])]
22
23
  end
23
24
 
24
25
  def process_mkd(input, output)
@@ -79,6 +80,7 @@ MODE_AS_FORMAT = {
79
80
  }
80
81
  }
81
82
 
83
+ # XXX move to author-tools@ietf.org API
82
84
  def process_xml_remotely(input, output, *flags)
83
85
  warn "* converting remotely from xml #{input} to txt #{output}" if @options.verbose
84
86
  format = flags[0] || "--text"
@@ -14,7 +14,15 @@ module KramdownRFC
14
14
  @f.delete(pn.to_s)
15
15
  end
16
16
  def []=(pn, val)
17
- @f[pn] = val
17
+ @f[pn.to_s] = val
18
+ end
19
+ def default(pn, &block)
20
+ @f.fetch(pn.to_s, &block)
21
+ end
22
+ def default!(pn, value)
23
+ default(pn) {
24
+ @f[pn.to_s] = value
25
+ }
18
26
  end
19
27
  def has(pn)
20
28
  @f[pn.to_s]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kramdown-rfc2629
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.26
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carsten Bormann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-09 00:00:00.000000000 Z
11
+ date: 2022-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kramdown
@@ -71,6 +71,7 @@ description: |-
71
71
  "kramdown" markdown parser. Mostly useful for RFC writers.
72
72
  email: cabo@tzi.org
73
73
  executables:
74
+ - kramdown-rfc
74
75
  - kramdown-rfc2629
75
76
  - doilit
76
77
  - kramdown-rfc-extract-markdown
@@ -86,6 +87,7 @@ files:
86
87
  - bin/de-gfm
87
88
  - bin/doilit
88
89
  - bin/kdrfc
90
+ - bin/kramdown-rfc
89
91
  - bin/kramdown-rfc-cache-i-d-bibxml
90
92
  - bin/kramdown-rfc-cache-subseries-bibxml
91
93
  - bin/kramdown-rfc-extract-markdown
@@ -94,6 +96,7 @@ files:
94
96
  - data/kramdown-rfc2629.erb
95
97
  - data/math.json
96
98
  - kramdown-rfc2629.gemspec
99
+ - lib/kramdown-rfc/command.rb
97
100
  - lib/kramdown-rfc/erb.rb
98
101
  - lib/kramdown-rfc/gzip-clone.rb
99
102
  - lib/kramdown-rfc/kdrfc-processor.rb