kramdown-rfc2629 1.5.26 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,577 @@
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
+ displayref = {}
287
+
288
+ [:ref, :normative, :informative].each do |sn|
289
+ if refs = ps.has(sn)
290
+ warn "*** bad section #{sn}: #{refs.inspect}" unless refs.respond_to? :each
291
+ refs.each do |k, v|
292
+ if v.respond_to? :to_str
293
+ if bibtagsys(v) # enable "foo: RFC4711" as a custom anchor definition
294
+ anchor_to_bibref[k] = v.to_str
295
+ end
296
+ ref_replacements[v.to_str] = k
297
+ end
298
+ if Hash === v
299
+ if aliasname = v.delete("-")
300
+ ref_replacements[aliasname] = k
301
+ end
302
+ if bibref = v.delete("=")
303
+ anchor_to_bibref[k] = bibref
304
+ end
305
+ if dr = v.delete("display")
306
+ displayref[k] = dr
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
312
+ open_refs = ps[:ref] || { } # consumed
313
+
314
+ norm_ref = { }
315
+
316
+ # convenience replacement of {{-coap}} with {{I-D.ietf-core-coap}}
317
+ # collect normative/informative tagging {{!RFC2119}} {{?RFC4711}}
318
+ sechash.each do |k, v|
319
+ next if k == "fluff"
320
+ v.gsub!(/{{(#{
321
+ spacify_re(XSR_PREFIX)
322
+ })?(?:([?!])(-)?|(-))([\w._\-]+)(?:=([\w.\/_\-]+))?(#{
323
+ XREF_TXT_SUFFIX
324
+ })?(#{
325
+ spacify_re(XSR_SUFFIX)
326
+ })?}}/) do |match|
327
+ xsr_prefix = $1
328
+ norminform = $2
329
+ replacing = $3 || $4
330
+ word = $5
331
+ bibref = $6
332
+ xrt_suffix = $7
333
+ xsr_suffix = $8
334
+ if replacing
335
+ if new = ref_replacements[word]
336
+ word = new
337
+ else
338
+ warn "*** no alias replacement for {{-#{word}}}"
339
+ word = "-#{word}"
340
+ end
341
+ end # now, word is the anchor
342
+ if bibref
343
+ if old = anchor_to_bibref[word]
344
+ if bibref != old
345
+ warn "*** conflicting definitions for xref #{word}: #{old} != #{bibref}"
346
+ end
347
+ else
348
+ anchor_to_bibref[word] = bibref
349
+ end
350
+ end
351
+
352
+ # things can be normative in one place and informative in another -> normative
353
+ # collect norm/inform above and assign it by priority here
354
+ if norminform
355
+ norm_ref[word] ||= norminform == '!' # one normative ref is enough
356
+ end
357
+ "{{#{xsr_prefix}#{word}#{xrt_suffix}#{xsr_suffix}}}"
358
+ end
359
+ end
360
+
361
+ [:normative, :informative].each do |k|
362
+ ps.rest[k.to_s] ||= { }
363
+ end
364
+
365
+ norm_ref.each do |k, v|
366
+ # could check bibtagsys here: needed if open_refs is nil or string
367
+ target = ps.has(v ? :normative : :informative)
368
+ warn "*** overwriting #{k}" if target.has_key?(k)
369
+ target[k] = open_refs[k] # add reference to normative/informative
370
+ end
371
+ # note that unused items from ref are considered OK, therefore no check for that here
372
+
373
+ # also should allow norm/inform check of other references
374
+ # {{?coap}} vs. {{!coap}} vs. {{-coap}} (undecided)
375
+ # or {{?-coap}} vs. {{!-coap}} vs. {{-coap}} (undecided)
376
+ # could require all references to be decided by a global flag
377
+ overlap = [:normative, :informative].map { |s| (ps.has(s) || { }).keys }.reduce(:&)
378
+ unless overlap.empty?
379
+ warn "*** #{overlap.join(', ')}: both normative and informative"
380
+ end
381
+
382
+ stand_alone = ps[:stand_alone]
383
+
384
+ [:normative, :informative].each do |sn|
385
+ if refs = ps[sn]
386
+ refs.each do |k, v|
387
+ href = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(k)
388
+ kramdown_options[:link_defs][k] = ["##{href}", nil] # allow [RFC2119] in addition to {{RFC2119}}
389
+
390
+ bibref = anchor_to_bibref[k] || k
391
+ bts, url = bibtagsys(bibref, k, stand_alone)
392
+ if bts && (!v || v == {} || v.respond_to?(:to_str))
393
+ if stand_alone
394
+ a = %{{: anchor="#{k}"}}
395
+ sechash[sn.to_s] << %{\n#{NMDTAGS[0]}\n![:include:](#{bts})#{a}\n#{NMDTAGS[1]}\n}
396
+ else
397
+ bts.gsub!('/', '_')
398
+ (ps.rest["bibxml"] ||= []) << [bts, url]
399
+ sechash[sn.to_s] << %{&#{bts};\n} # ???
400
+ end
401
+ else
402
+ unless v && Hash === v
403
+ warn "*** don't know how to expand ref #{k}"
404
+ next
405
+ end
406
+ if bts && !v.delete("override")
407
+ warn "*** warning: explicit settings completely override canned bibxml in reference #{k}"
408
+ end
409
+ sechash[sn.to_s] << KramdownRFC::ref_to_xml(href, v)
410
+ end
411
+ end
412
+ end
413
+ end
414
+
415
+ erbfilename = File.expand_path '../../../data/kramdown-rfc2629.erb', __FILE__
416
+ erbfile = File.read(erbfilename, coding: "UTF-8")
417
+ erb = ERB.trim_new(erbfile, '-')
418
+ # remove redundant nomarkdown pop outs/pop ins as they confuse kramdown
419
+ input = erb.result(binding).gsub(%r"{::nomarkdown}\s*{:/nomarkdown}"m, "")
420
+ ps.warn_if_leftovers
421
+ sechash.delete("fluff") # fluff is a "commented out" section
422
+ if !sechash.empty? # any sections unused by the ERb file?
423
+ warn "*** sections left #{sechash.keys.inspect}!"
424
+ end
425
+
426
+ [input, kramdown_options, coding_override]
427
+ end
428
+
429
+ XML_RESOURCE_ORG_PREFIX = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_PREFIX
430
+
431
+ # return XML entity name, url, rewrite_anchor flag
432
+ def bibtagsys(bib, anchor=nil, stand_alone=true)
433
+ if bib =~ /\Arfc(\d+)/i
434
+ rfc4d = "%04d" % $1.to_i
435
+ [bib.upcase,
436
+ "#{XML_RESOURCE_ORG_PREFIX}/bibxml/reference.RFC.#{rfc4d}.xml"]
437
+ elsif $options.v3 && bib =~ /\A(bcp|std)(\d+)/i
438
+ n4d = "%04d" % $2.to_i
439
+ [bib.upcase,
440
+ "#{XML_RESOURCE_ORG_PREFIX}/bibxml-rfcsubseries-new/reference.#{$1.upcase}.#{n4d}.xml"]
441
+ elsif bib =~ /\A([-A-Z0-9]+)\./ &&
442
+ (xro = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_MAP[$1])
443
+ dir, _ttl, rewrite_anchor = xro
444
+ bib1 = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(bib)
445
+ if anchor && bib1 != anchor
446
+ if rewrite_anchor
447
+ a = %{?anchor=#{anchor}}
448
+ else
449
+ if !stand_alone
450
+ warn "*** selecting a custom anchor '#{anchor}' for '#{bib1}' requires stand_alone mode"
451
+ warn " the output will need manual editing to correct this"
452
+ end
453
+ end
454
+ end
455
+ [bib1,
456
+ "#{XML_RESOURCE_ORG_PREFIX}/#{dir}/reference.#{bib}.xml#{a}"]
457
+ end
458
+ end
459
+
460
+ def read_encodings
461
+ encfilename = File.expand_path '../../../data/encoding-fallbacks.txt', __FILE__
462
+ encfile = File.read(encfilename, coding: "UTF-8")
463
+ Hash[encfile.lines.map{|l|
464
+ l.chomp!;
465
+ x, s = l.split(" ", 2)
466
+ [x.hex.chr(Encoding::UTF_8), s || " "]}]
467
+ end
468
+
469
+ FALLBACK = read_encodings
470
+
471
+ def expand_tabs(s, tab_stops = 8)
472
+ s.gsub(/([^\t\n]*)\t/) do
473
+ $1 + " " * (tab_stops - ($1.size % tab_stops))
474
+ end
475
+ end
476
+
477
+
478
+ require 'optparse'
479
+ require 'ostruct'
480
+
481
+ $options ||= OpenStruct.new
482
+ op = OptionParser.new do |opts|
483
+ opts.banner = <<BANNER
484
+ Usage: kramdown-rfc2629 [options] file.md|file.mkd > file.xml
485
+ Version: #{KDRFC_VERSION}
486
+ BANNER
487
+ opts.on("-V", "--version", "Show version and exit") do |v|
488
+ puts "kramdown-rfc2629 #{KDRFC_VERSION}"
489
+ exit
490
+ end
491
+ opts.on("-H", "--help", "Show option summary and exit") do |v|
492
+ puts opts
493
+ exit
494
+ end
495
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
496
+ $options.verbose = v
497
+ end
498
+ opts.on("-3", "--[no-]v3", "Use RFCXML v3 processing rules") do |v|
499
+ $options.v3 = v
500
+ end
501
+ opts.on("-2", "--[no-]v2", "Use RFCXML v2 processing rules") do |v|
502
+ $options.v2 = v
503
+ end
504
+ end
505
+ op.parse!
506
+
507
+ if $options.v2 && $options.v3
508
+ warn "*** can't have v2 and eat v3 cake"
509
+ $options.v2 = false
510
+ end
511
+
512
+ if $options.v3.nil? && !$options.v2
513
+ if Time.now.to_i >= 1645567342 # Time.parse("2022-02-22T22:02:22Z").to_i
514
+ $options.v3 = true # new default from the above date
515
+ end
516
+ end
517
+
518
+ warn "*** v2 #{$options.v2.inspect} v3 #{$options.v3.inspect}" if $options.verbose
519
+
520
+ input = ARGF.read
521
+ if input[0] == "\uFEFF"
522
+ warn "*** There is a leading byte order mark. Ignored."
523
+ input[0..0] = ''
524
+ end
525
+ if input[-1] != "\n"
526
+ # warn "*** added missing newline at end"
527
+ input << "\n" # fix #26
528
+ end
529
+ process_includes(input) unless ENV["KRAMDOWN_SAFE"]
530
+ input.gsub!(/^\{::boilerplate\s+(.*?)\}/) {
531
+ boilerplate($1)
532
+ }
533
+ if input =~ /[\t]/
534
+ warn "*** Input contains HT (\"tab\") characters. Undefined behavior will ensue."
535
+ input = expand_tabs(input)
536
+ end
537
+
538
+ if input =~ /\A---/ # this is a sectionized file
539
+ do_the_tls_dance unless ENV["KRAMDOWN_DONT_VERIFY_HTTPS"]
540
+ input, options, coding_override = xml_from_sections(input)
541
+ else
542
+ options = process_kramdown_options # all default
543
+ end
544
+ if input =~ /\A<\?xml/ # if this is a whole XML file, protect it
545
+ input = "{::nomarkdown}\n#{input}\n{:/nomarkdown}\n"
546
+ end
547
+
548
+ if $options.v3_used && !$options.v3
549
+ warn $options.v3_used
550
+ $options.v3_used = nil
551
+ $options.v3 = true
552
+ end
553
+
554
+ if coding_override
555
+ input = input.encode(Encoding.find(coding_override), fallback: FALLBACK)
556
+ end
557
+
558
+ # 1.4.17: because of UTF-8 bibxml files, kramdown always needs to see UTF-8 (!)
559
+ if input.encoding != Encoding::UTF_8
560
+ input = input.encode(Encoding::UTF_8)
561
+ end
562
+
563
+ # warn "options: #{options.inspect}"
564
+ doc = Kramdown::Document.new(input, options)
565
+ $stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
566
+ output = doc.to_rfc2629
567
+
568
+ if $options.v3_used && !$options.v3
569
+ warn $options.v3_used
570
+ $options.v3 = true
571
+ end
572
+
573
+ if coding_override
574
+ output = output.encode(Encoding.find(coding_override), fallback: FALLBACK)
575
+ end
576
+
577
+ 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]
@@ -808,7 +808,7 @@ COLORS
808
808
  out ="#{' '*indent}<dd><t/></dd>\n" # you can't make this one up
809
809
  end
810
810
  opts[:haddt] = true
811
- out << "#{' '*indent}<dt#{el_html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</dt>\n"
811
+ out << "#{' '*indent}<dt#{el_html_attributes(el)}>#{inner(el, indent, opts)}</dt>\n"
812
812
  else
813
813
  close = "#{' '*indent}</t>\n" * @in_dt
814
814
  @in_dt = 1
@@ -914,6 +914,17 @@ COLORS
914
914
  gi = el.attr.delete('gi')
915
915
  res = inner(el, indent, opts)
916
916
  target = el.attr['target']
917
+ if target[0..1] == "{{"
918
+ # XXX ignoring all attributes and content
919
+ s = ::Kramdown::Converter::Rfc2629::process_markdown(target)
920
+ # if res != '' && s[-2..-1] == '/>'
921
+ # if s =~ /\A<([-A-Za-z0-9_.]+) /
922
+ # gi ||= $1
923
+ # end
924
+ # s[-2..-1] = ">#{res}</#{gi}>"
925
+ # end
926
+ return s
927
+ end
917
928
  if target[0] == "#" # handle [](#foo) as xref as in RFC 7328
918
929
  el.attr['target'] = target = target[1..-1]
919
930
  if target.downcase == res.downcase
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.3
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-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kramdown
@@ -67,10 +67,11 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
69
  description: |-
70
- An RFC7749 (XML2RFC) generating backend for Thomas Leitner's
70
+ An RFCXML (RFC 799x) generating backend for Thomas Leitner's
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
@@ -120,8 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
123
  - !ruby/object:Gem::Version
121
124
  version: '0'
122
125
  requirements: []
123
- rubygems_version: 3.3.3
126
+ rubygems_version: 3.3.7
124
127
  signing_key:
125
128
  specification_version: 4
126
- summary: Kramdown extension for generating RFC 7749 XML.
129
+ summary: Kramdown extension for generating RFCXML (RFC 799x).
127
130
  test_files: []