Class: Bind9mgr::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/parser.rb

Overview

SOA, MX, TXT, SRV - are different

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



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
# File 'lib/parser.rb', line 9

def initialize
  @state = :start
  @result = Zone.new

  @SHARED_RULES = {
    :txt => Proc.new{ |t| t == 'TXT' ? update_last_rr(nil, nil, nil, t, nil) : false },
    :mx  => Proc.new{ |t| t == 'MX'  ? update_last_rr(nil, nil, nil, t, nil) : false },
    :srv => Proc.new{ |t| t == 'SRV' ? update_last_rr(nil, nil, nil, t, nil) : false }
  }

  @STATE_RULES = 
    # [current_state, target_state, proc to perform(token will be passe in)
    [ [:start, :origin, Proc.new{ |t| t == '$ORIGIN' }],
      [:start, :ttl,    Proc.new{ |t| t == '$TTL' }],
      [:origin, :last_token_in_a_row, Proc.new{ |t| set_origin t }],
      [:ttl, :last_token_in_a_row,    Proc.new{ |t| set_ttl t }],
      [:last_token_in_a_row, :start, Proc.new{ |t| t == "\n" ? true : false }],
      [:owner, :rttl,   Proc.new{ |t| t.match(/^\d+$/) ? update_last_rr(nil, t, nil, nil, nil) : false }],
      [:owner, :klass,  Proc.new{ |t| KLASSES.include?(t) ? update_last_rr(nil, nil, t, nil, nil) : false }],
      [:owner, :type,   Proc.new{ |t| TYPES.include?(t) ? update_last_rr(nil, nil, nil, t, nil) : false }],
      [:owner, :mx,     @SHARED_RULES[:mx]],
      [:owner, :srv,    @SHARED_RULES[:srv]],
      [:owner, :txt,    @SHARED_RULES[:txt]],
      [:rttl,  :klass,  Proc.new{ |t| KLASSES.include?(t) ? update_last_rr(nil, nil, t, nil, nil) : false }],
      [:rttl,  :txt,    @SHARED_RULES[:txt]],
      [:rttl,  :srv,    @SHARED_RULES[:srv]],
      [:klass, :mx,     @SHARED_RULES[:mx]],
      [:klass, :txt,    @SHARED_RULES[:txt]],
      [:klass, :srv,    @SHARED_RULES[:srv]],
      [:klass, :type,   Proc.new{ |t| TYPES.include?(t) ? update_last_rr(nil, nil, nil, t, nil) : false }],
      [:klass, :soa,    Proc.new{ |t| t == 'SOA' ? update_last_rr(nil, nil, nil, t, nil) : false }],
      [:type,  :last_token_in_a_row,   Proc.new{ |t| update_last_rr(nil, nil, nil, nil, t)  }],
      [:start, :type,   Proc.new{ |t| TYPES.include?(t) ? add_rr(nil, nil, nil, t, nil) : false }],
      [:start, :klass,  Proc.new{ |t| KLASSES.include?(t) ? add_rr(nil, nil, t, nil, nil) : false }],
      [:start, :rttl,   Proc.new{ |t| (t.match(/^\d+$/) && !@tokens.first.match(/^\d+$/) ) ? add_rr(nil, t, nil, nil, nil) : false }],
      [:start,  :srv,    @SHARED_RULES[:srv]],
      [:start,  :txt,    @SHARED_RULES[:txt]],
      [:start, :owner,  Proc.new{ |t| add_rr(t, nil, nil, nil, nil) }],
      [:soa, :last_token_in_a_row,    Proc.new{ |t|
         rdata = [t] + @tokens.shift(@tokens.index(')'))
         rdata.select!{|tt| tt != "\n" }
         raise ParserError, "Zone parsing error: parentices expected in SOA record.\n#{@content}" if (rdata[2] != '(') || (@tokens.first != ')')
         rdata.delete_at(2)
         @result.options[:support_email] = rdata[1]
         @result.options[:serial] = rdata[2]
         @result.options[:refresh] = rdata[3]
         @result.options[:retry] = rdata[4]
         @result.options[:expiry] = rdata[5]
         @result.options[:default_ttl] = rdata[6]
         update_last_rr(nil, nil, nil, nil, rdata)
         @tokens.shift
       }],
      [:mx, :last_token_in_a_row,     Proc.new{ |t| update_last_rr(nil, nil, nil, nil, [t] + [@tokens.shift]) }], 
      [:srv, :last_token_in_a_row,     Proc.new{ |t| update_last_rr(nil, nil, nil, nil, [t] + [@tokens.shift(3)]) }], 
      [:txt, :last_token_in_a_row,     Proc.new{ |t| update_last_rr(nil, nil, nil, nil, ([t] + [@tokens.shift(@tokens.index("\n"))]).join(" ")) }] # '\t' symbol is lost here! may be a BUG
    ]
end

Instance Attribute Details

#resultObject

we can set appropriate Zone instance here



7
8
9
# File 'lib/parser.rb', line 7

def result
  @result
end

#stateObject (readonly)

Returns the value of attribute state.



6
7
8
# File 'lib/parser.rb', line 6

def state
  @state
end

Instance Method Details

#parse(str) ⇒ Object



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
# File 'lib/parser.rb', line 67

def parse str
  @content = str # for debugging
  @tokens = tokenize( str )
  
#      puts @tokens.inspect

  cntr = 0
  while @tokens.size > 0
    token = @tokens.shift
    # puts "state: #{@state}, token: #{token}"
    possible_edges = @STATE_RULES.select{|arr|arr[0] == @state }
    raise( ParserError, "no possible_edges. cur_state: #{@state}" ) if possible_edges.count < 1

    flag = false
    while ( possible_edges.count > 0 ) && flag == false
      current_edge = possible_edges.shift
      flag = current_edge[2].call(token)
      
      # ( puts " succ: #{@state} -> #{current_edge[1]}"; @state = current_edge[1] ) if flag
      # ( puts " fail: #{@state} -> #{current_edge[1]}" ) unless flag
      @state = current_edge[1] if flag
    end

    raise( ParserError, "no successful rules found. cur_state: #{@state}, token: #{token}, next tokens: #{@tokens.inspect}" ) unless flag
    cntr += 1
  end

  get_options

  cntr # returning performed rules count. just for fun
end