1#!/usr/bin/env python
2# Copyright (c) 2007, Secure64 Software Corporation
3#
4# Permission is hereby granted, free of charge, to any person obtaining a copy
5# of this software and associated documentation files (the "Software"), to deal
6# in the Software without restriction, including without limitation the rights
7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8# copies of the Software, and to permit persons to whom the Software is
9# furnished to do so, subject to the following conditions:
10#
11# The above copyright notice and this permission notice shall be included in
12# all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20# THE SOFTWARE.
21#
22#
23#
24#	class to tokenize a named.conf file
25#
26#
27
28T_KEYWORD = 0
29T_STRING  = 1
30T_LBRACE  = 2
31T_RBRACE  = 3
32T_SEMI    = 4
33T_COMMA   = 5
34T_QUAD    = 6
35T_COMMENT = 7
36T_NAME    = 8
37T_EOF     = 9
38T_LPAREN  = 10
39T_RPAREN  = 11
40
41NAMED_KEYWORDS = [ 'algorithm', 'allow-notify', 'allow-recursion',
42                   'allow-transfer', 'also-notify',
43                   'category', 'channel', 'check-names', 'controls',
44		   'coresize',
45                   'directory', 'dump-file',
46		   'file',
47		   'IN', 'in', 'include',
48		   'key', 'keys',
49		   'logging',
50		   'masters',
51                   'options',
52		   'pid-file', 'print-time',
53		   'recursive-clients',
54		   'secret', 'severity', 'statistics-file', 'syslog',
55		   'transfer-format', 'type',
56		   'version', 'versions',
57		   'zone',
58		 ]
59
60class Tokenizer:
61
62   def __init__(self, fname):
63      infile = file(fname)
64      self.data = ''.join(infile.readlines())
65      self.curpos = 0
66      self.lastpos = len(self.data)
67      self.line = 1
68      return
69
70   def get(self):
71      tok = ''
72      done = False
73      while not done:
74         if self.curpos >= self.lastpos:
75	    return (T_EOF, None, self.line)
76         c = self.data[self.curpos]
77	 if c == '\n':
78	    self.line += 1
79	 if c.isspace():
80	    self.curpos += 1
81	    continue
82	 elif c == '{':
83	    self.curpos += 1
84	    return (T_LBRACE, c, self.line)
85	 elif c == '}':
86	    self.curpos += 1
87	    return (T_RBRACE, c, self.line)
88	 elif c == '(':
89	    self.curpos += 1
90	    return (T_LPAREN, c, self.line)
91	 elif c == ')':
92	    self.curpos += 1
93	    return (T_RPAREN, c, self.line)
94	 elif c == ';':
95	    self.curpos += 1
96	    return (T_SEMI, c, self.line)
97	 elif c == '#':
98	    while c != '\n':
99	       tok += c
100	       self.curpos += 1
101	       c = self.data[self.curpos]
102            self.curpos += 1
103	    if c == '\n':
104	       self.line += 1
105	    return (T_COMMENT, tok, self.line)
106	 elif c == '"':
107	    tok += c
108	    self.curpos += 1
109	    c = self.data[self.curpos]
110	    while c != '"':
111	       tok += c
112	       self.curpos += 1
113	       c = self.data[self.curpos]
114	    tok += c
115            self.curpos += 1
116	    return (T_STRING, tok, self.line)
117	 elif c == '/' and self.data[self.curpos+1] == '/':
118	    while c != '\n':
119	       tok += c
120	       self.curpos += 1
121	       c = self.data[self.curpos]
122	    if c == '\n':
123	       self.line += 1
124            self.curpos += 1
125	    return (T_COMMENT, tok, self.line)
126	 elif c == '/' and self.data[self.curpos+1] == '*':
127	    cmtDone = False
128	    tok += c
129	    tok += self.data[self.curpos+1]
130	    self.curpos += 2
131	    c = self.data[self.curpos]
132	    while not cmtDone:
133	       if c == '*' and self.data[self.curpos+1] == '/':
134		  tok += c
135	          tok += self.data[self.curpos+1]
136	          self.curpos += 2
137	          return (T_COMMENT, tok, self.line)
138	       else:
139	          tok += c
140		  if c == '\n':
141		     self.line += 1
142		  self.curpos +=1
143	          c = self.data[self.curpos]
144	    return (T_COMMENT, tok, self.line)
145	 elif c.isdigit():
146	    tok += c
147	    self.curpos += 1
148	    c = self.data[self.curpos]
149	    while c.isdigit() or c == '.' or c == '/':
150	       tok += c
151	       self.curpos += 1
152	       c = self.data[self.curpos]
153	    return (T_QUAD, tok, self.line)
154	 else:
155	    while c.isalnum() or c == '_' or c == '-' or c == '.':
156	       tok += c
157	       self.curpos += 1
158	       c = self.data[self.curpos]
159	    if tok in NAMED_KEYWORDS:
160	       return (T_KEYWORD, tok, self.line)
161	    else:
162	       return (T_NAME, tok, self.line)
163
164      return
165
166   def dump(self):
167      print 'Tokenizer raw data:'
168      print 'cur, last: %d, %d' % (self.curpos, self.lastpos)
169      print self.data
170      return
171
172