This file is indexed.

/usr/bin/kramdown-rfc2629 is in ruby-kramdown-rfc2629 1.0.30-1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
require 'kramdown-rfc2629'
require 'yaml'
require 'erb'
require 'date'

Encoding.default_external = "UTF-8" # wake up, smell the coffee

RE_NL = /(?:\n|\r|\r\n)/
RE_SECTION = /---(?:\s+(\w+)(-?))?\s*#{RE_NL}(.*?#{RE_NL})(?=---(?:\s+\w+-?)?\s*#{RE_NL}|\Z)/m

NMDTAGS = ["{:/nomarkdown}\n\n", "\n\n{::nomarkdown}\n"]

NORMINFORM = { "!" => :normative, "?" => :informative }

def xml_from_sections(input)
  sections = input.scan(RE_SECTION)
  # resulting in an array; each section is [section-label, nomarkdown-flag, section-text]

  # the first section is a YAML with front matter parameters (don't put a label here)
  # We put back the "---" plus gratuitous blank lines to hack the line number in errors
  yaml_in = input[/---\s*/] << sections.shift[2]
  ps = ParameterSet.new(YAML.load(yaml_in))
  coding_override = (ps.has(:coding) =~ /ascii/i) ? :symbolic : :as_char

  # all the other sections are put in a Hash, possibly concatenated from parts there
  sechash = Hash.new{ |h,k| h[k] = ""}
  snames = []                   # a stack of section names
  sections.each do |sname, nmdflag, text|
    nmdin, nmdout = {
      "-" => ["", ""],          # stay in nomarkdown
      "" => NMDTAGS, # pop out temporarily
    }[nmdflag || ""]
    if sname
      snames << sname           # "--- label" -> push label (now current)
    else
      snames.pop                # just "---" -> pop label (previous now current)
    end
    sechash[snames.last] << "#{nmdin}#{text}#{nmdout}"
  end

  ref_replacements = { }

  [:ref, :normative, :informative].each do |sn|
    if refs = ps.has(sn)
      warn "*** bad section #{sn}: #{refs.inspect}" unless refs.respond_to? :each
      refs.each do |k, v|
        if v.respond_to? :to_str
          ref_replacements[v.to_str] = k
        end
        if v.respond_to? :[]
          if aliasname = v.delete("-")
            ref_replacements[aliasname] = k
          end
        end
      end
    end
  end
  open_refs = ps[:ref] || { }       # consumed

  norm_ref = { }

  # convenience replacement of {{-coap}} with {{I-D.ietf-core-coap}}
  # collect normative/informative tagging {{!RFC2119}} {{?RFC4711}}
  sechash.each do |k, v|
    next if k == "fluff"
    v.gsub!(/{{(?:([?!])(-)?|(-))([\w.\-]+)}}/) do |match|
      norminform = $1
      replacing = $2 || $3
      word = $4
      if replacing
        if new = ref_replacements[word]
          word = new
        else
          warn "*** no alias replacement for {{-#{word}}}" 
          word = "-#{word}"
        end
      end
      # things can be normative in one place and informative in another -> normative
      # collect norm/inform above and assign it by priority here
      if norminform
        norm_ref[word] ||= norminform == '!' # one normative ref is enough
      end
      "{{#{word}}}"
    end
  end

  [:normative, :informative].each do |k|
    ps.rest[k.to_s] ||= { }
  end

  norm_ref.each do |k, v|
    # could check bibtagsys here: needed if open_refs is nil or string
    target = ps.has(v ? :normative : :informative)
    warn "*** overwriting #{k}" if target.has_key?(k)
    target[k] = open_refs[k] # add reference to normative/informative
  end
  # note that unused items from ref are considered OK, therefore no check for that here

  # also should allow norm/inform check of other references
  # {{?coap}} vs. {{!coap}} vs. {{-coap}} (undecided)
  # or {{?-coap}} vs. {{!-coap}} vs. {{-coap}} (undecided)
  # could require all references to be decided by a global flag
  overlap = [:normative, :informative].map { |s| (ps.has(s) || { }).keys }.reduce(:&)
  unless overlap.empty?
    warn "*** #{overlap.join(', ')}: both normative and informative"
  end

  stand_alone = ps[:stand_alone]
  link_defs = {}

  [:normative, :informative].each do |sn|
    if refs = ps[sn]
      refs.each do |k, v|
        href = k.gsub(/\A[0-9]/) { "_#{$&}" } # can't start an IDREF with a number
        link_defs[k] = ["##{href}", nil]            # allow [RFC2119] in addition to {{RFC2119}}
        if bts = bibtagsys(k)
          if v
            warn "*** redundant in #{k}: #{v.inspect}" unless v.respond_to? :to_str
          end
          if stand_alone
            sechash[sn.to_s] << %{\n#{NMDTAGS[0]}\n![:include:](#{bts[0]})\n#{NMDTAGS[1]}\n}
          else
            (ps.rest["bibxml"] ||= []) << k
            sechash[sn.to_s] << %{&#{bts[0]};\n}
          end
        else
          unless v && Hash === v
            warn "*** don't know how to expand ref #{k}" 
            next
          end
          vps = ParameterSet.new(v)
          erb = ERB.new <<-REFERB, nil, '-'
<reference anchor="<%= k %>" <%= vps.attr("target") %>>
  <front>
    <%= vps.ele("title") -%>

<% vps.arr("author", true, true) do |au|
   aups = authorps_from_hash(au)
 -%>
    <author <%=aups.attrs("initials", "surname", "fullname=name", "role")%>>
      <%= aups.ele("organization=org", aups.attr("abbrev=orgabbrev"), "") %>
    </author>
<%   aups.warn_if_leftovers  -%>
<% end -%>
    <date <%= dateattrs(vps[:date]) %>/>
  </front>
<% vps.arr("seriesinfo", false) do |k, v| -%>
  <seriesInfo name="<%=k%>" value="<%=v%>"/>
<% end -%>
<% vps.arr("format", false) do |k, v| -%>
  <format type="<%=k%>" target="<%=v%>"/>
<% end -%>
<%= vps.ele("annotation=ann") -%>
</reference>
          REFERB
          sechash[sn.to_s] << erb.result(binding)
          vps.warn_if_leftovers
        end
      end
    end
  end

  erbfilename = '/usr/share/ruby-kramdown-rfc2629/kramdown-rfc2629.erb'
  erbfile = File.read(erbfilename, coding: "UTF-8")
  erb = ERB.new(erbfile, nil, '-')
  # remove redundant nomarkdown pop outs/pop ins as they confuse kramdown
  input = erb.result(binding).gsub(%r"{::nomarkdown}\s*{:/nomarkdown}"m, "")
  ps.warn_if_leftovers
  sechash.delete("fluff")       # fluff is a "commented out" section
  if !sechash.empty?            # any sections unused by the ERb file?
    warn "*** sections left #{sechash.keys.inspect}!"
  end

  [input, coding_override, link_defs]
end

class ParameterSet
  include Kramdown::Utils::Html

  attr_reader :f
  def initialize(y)
    raise "*** invalid parameter set #{y.inspect}" unless Hash === y
    @f = y
  end
  def [](pn)
    @f.delete(pn.to_s)
  end
  def has(pn)
    @f[pn.to_s]
  end
  def van(pn)                   # pn is a parameter name, possibly with an =alias
    an, pn = pn.to_s.split("=")
    pn ||= an
    [self[pn] || self[an], an]
  end
  def attr(pn)
    val, an = van(pn)
    %{#{an}="#{val}"}    if val
  end
  def attrs(*pns)
    pns.map{ |pn| attr(pn) }.compact.join(" ")
  end
  def ele(pn, attr=nil, defcontent=nil)
    val, an = van(pn)
    val ||= defcontent
    Array(val).map do |val1|
      %{<#{[an, *Array(attr).map(&:to_s)].join(" ").strip}>#{escape_html(val1.to_s.strip)}</#{an}>}
    end.join(" ")
  end
  def arr(an, converthash=true, must_have_one=false, &block)
    arr = self[an] || []
    arr = [arr] if Hash === arr && converthash
    arr << { } if must_have_one && arr.empty?
    Array(arr).each(&block)
  end
  def rest
    @f
  end
  def warn_if_leftovers
    if !@f.empty?
      warn "*** attributes left #{@f.inspect}!"
    end
  end
end

XML_RESOURCE_ORG_PREFIX = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_PREFIX

def bibtagsys(bib)
  if bib =~ /\Arfc(\d+)/i
    rfc4d = "%04d" % $1.to_i
    [bib.upcase,
     "#{XML_RESOURCE_ORG_PREFIX}/bibxml/reference.RFC.#{rfc4d}.xml"]
  elsif bib =~ /\A([-A-Z0-9]+)\./ &&
        dir = Kramdown::Converter::Rfc2629::XML_RESOURCE_ORG_MAP[$1]
    bib1 = bib.gsub(/\A[0-9]/) { "_#{$&}" } # can't start an ID with a number
    [bib1,
     "#{XML_RESOURCE_ORG_PREFIX}/#{dir}/reference.#{bib}.xml"]
  end
end

def authorps_from_hash(au)
  aups = ParameterSet.new(au)
  if ins = aups[:ins]
    parts = ins.split('.').map(&:strip)
    aups.rest["initials"] = parts[0..-2].join('.') << '.'
    aups.rest["surname"] = parts[-1]
  end
  # hack ("heuristic for") initials and surname from name
  # -- only works for people with exactly one last name and uncomplicated first names
  if n = aups.rest["name"]
    n = n.split
    aups.rest["initials"] ||= n[0..-2].map(&:chr).join('.') << '.'
    aups.rest["surname"] ||= n[-1]
  end
  aups
end

def dateattrs(date)
  begin
    case date
    when Integer
      %{year="#{"%04d" % date}"}
    when String
      Date.parse("#{date}-01").strftime(%{year="%Y" month="%B"})
    when Date
      date.strftime(%{year="%Y" month="%B" day="%d"})
    when Array                  # this allows to explicitly give a string
      %{year="#{date.join(" ")}"}
    when nil
      %{year="n.d."}
    end

  rescue ArgumentError
    warn "*** Invalid date: #{date} -- use 2012, 2012-07, or 2012-07-28"
  end
end

coding_override = :as_char
input = ARGF.read
if input[0] == "\uFEFF"
   warn "*** There is a leading byte order mark. Ignored."
   input[0..0] = ''
end
input.gsub!(/^\{::include\s+(.*?)\}/) {
  File.read($1).chomp
} unless ENV["KRAMDOWN_SAFE"]
link_defs = {}
if input =~ /\A---/        # this is a sectionized file
  input, coding_override, link_defs = xml_from_sections(input)
end
if input =~ /\A<\?xml/          # if this is a whole XML file, protect it
  input = "{::nomarkdown}\n#{input}\n{:/nomarkdown}\n"
end
options = {input: 'RFC2629Kramdown', entity_output: coding_override, link_defs: link_defs}
case coding_override
when :symbolic
  options[:smart_quotes] = ["'".ord, "'".ord, '"'.ord, '"'.ord]
end
# warn "options: #{options.inspect}"
doc = Kramdown::Document.new(input, options)
$stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
puts doc.to_rfc2629