1 |
#!python |
#!/bin/env python |
2 |
# |
# |
3 |
# This file is part of GNU Enterprise. |
# This file is part of GNU Enterprise. |
4 |
# |
# |
5 |
# GNU Enterprise is free software; you can redistribute it |
# GNU Enterprise is free software; you can redistribute it |
6 |
# and/or modify it under the terms of the GNU General Public |
# and/or modify it under the terms of the GNU General Public |
7 |
# License as published by the Free Software Foundation; either |
# License as published by the Free Software Foundation; either |
8 |
# version 2, or (at your option) any later version. |
# version 2, or (at your option) any later version. |
9 |
# |
# |
10 |
# GNU Enterprise is distributed in the hope that it will be |
# GNU Enterprise is distributed in the hope that it will be |
11 |
# useful, but WITHOUT ANY WARRANTY; without even the implied |
# useful, but WITHOUT ANY WARRANTY; without even the implied |
12 |
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
13 |
# PURPOSE. See the GNU General Public License for more details. |
# PURPOSE. See the GNU General Public License for more details. |
14 |
# |
# |
15 |
# You should have received a copy of the GNU General Public |
# You should have received a copy of the GNU General Public |
16 |
# License along with program; see the file COPYING. If not, |
# License along with program; see the file COPYING. If not, |
17 |
# write to the Free Software Foundation, Inc., 59 Temple Place |
# write to the Free Software Foundation, Inc., 59 Temple Place |
18 |
# - Suite 330, Boston, MA 02111-1307, USA. |
# - Suite 330, Boston, MA 02111-1307, USA. |
19 |
# |
# |
20 |
# Copyright 2001 Free Software Foundation |
# Copyright 2001-2002 Free Software Foundation |
21 |
# |
# |
22 |
# |
# |
23 |
# FILE: |
# FILE: |
24 |
# gnuedtd |
# gnuedtd |
25 |
# |
# |
26 |
# DESCRIPTION: |
# DESCRIPTION: |
27 |
# This script generates a DTD for the client apps based on |
# This script generates a DTD for the client apps based on |
28 |
# their GParser markup |
# their GParser markup |
29 |
# |
# |
30 |
# NOTES: |
# NOTES: |
33 |
import sys, string, time |
import sys, string, time |
34 |
from gnue.common import GParser, GTypecast |
from gnue.common import GParser, GTypecast |
35 |
|
|
36 |
|
# This is simply to initialize gettext support :( |
37 |
|
from gnue.common import GBaseApp |
38 |
|
|
39 |
class GenerateDTD: |
class GenerateDTD: |
40 |
def __init__ (self, tool, dest=sys.__stdout__): |
def __init__ (self, tool, dest=sys.__stdout__): |
41 |
|
|
42 |
if tool == 'reports': |
if tool == 'reports': |
43 |
from gnue.reports import GRParser, VERSION, PACKAGE |
from gnue.reports import GRParser, VERSION, PACKAGE |
44 |
xmlElements = GRParser.getXMLelements() |
xmlElements = GRParser.getXMLelements() |
45 |
topLevelElement = 'report' |
topLevelElement = 'report' |
46 |
name = PACKAGE |
name = PACKAGE |
47 |
version = VERSION |
version = VERSION |
48 |
|
|
49 |
elif tool == 'forms': |
elif tool == 'forms': |
50 |
from gnue.forms import GFParser, VERSION, PACKAGE |
from gnue.forms import GFParser, VERSION, PACKAGE |
51 |
xmlElements = GFParser.getXMLelements() |
xmlElements = GFParser.getXMLelements() |
52 |
topLevelElement = 'form' |
topLevelElement = 'form' |
53 |
name = PACKAGE |
name = PACKAGE |
54 |
version = VERSION |
version = VERSION |
55 |
|
|
56 |
elif tool == 'gnurpc': |
elif tool == 'navigator': |
57 |
|
from gnue.navigator import GNParser, VERSION, PACKAGE |
58 |
|
xmlElements = GNParser.getXMLelements() |
59 |
|
topLevelElement = 'processes' |
60 |
|
name = PACKAGE |
61 |
|
version = VERSION |
62 |
|
|
63 |
|
elif tool == 'schema': |
64 |
|
from gnue.common.schema import GSParser |
65 |
|
from gnue.common import VERSION, PACKAGE |
66 |
|
xmlElements = GSParser.getXMLelements() |
67 |
|
topLevelElement = 'schema' |
68 |
|
name = 'GNUe Schema' |
69 |
|
version = VERSION |
70 |
|
|
71 |
|
elif tool == 'gnurpc': |
72 |
from gnue.common.commdrivers._parser import Parser |
from gnue.common.commdrivers._parser import Parser |
73 |
xmlElements = Parser.getXMLelements() |
xmlElements = Parser.getXMLelements() |
74 |
topLevelElement = 'gnurpc' |
topLevelElement = 'gnurpc' |
75 |
name = 'GNURPC' |
name = 'GNURPC' |
76 |
version = '0.0001' |
from gnue.common import VERSION as version |
77 |
|
|
78 |
else: |
else: |
79 |
print "\nSyntax: gnuedtd <forms|reports|gnurpc>\n" |
print "\nSyntax: gnuedtd <forms|reports|schema|navigator|gnurpc> [outfile.dtd]\n" |
80 |
sys.exit() |
sys.exit() |
81 |
|
|
82 |
self.parentMappings = {} |
self.parentMappings = {} |
88 |
for element in xmlElements.keys(): |
for element in xmlElements.keys(): |
89 |
# Get a mapping of all parent tags |
# Get a mapping of all parent tags |
90 |
if xmlElements[element].has_key('ParentTags') and \ |
if xmlElements[element].has_key('ParentTags') and \ |
91 |
xmlElements[element]['ParentTags'] != None: |
xmlElements[element]['ParentTags'] != None: |
92 |
for parent in xmlElements[element]['ParentTags']: |
for parent in xmlElements[element]['ParentTags']: |
93 |
if not self.parentMappings.has_key(parent): |
if not self.parentMappings.has_key(parent): |
94 |
self.parentMappings[parent] = {} |
self.parentMappings[parent] = {} |
97 |
xmlElements[element]['UsableBySiblings'] |
xmlElements[element]['UsableBySiblings'] |
98 |
|
|
99 |
# Find out what Typecasts are being used |
# Find out what Typecasts are being used |
100 |
if xmlElements[element].has_key('Attributes'): |
if xmlElements[element].has_key('Attributes'): |
101 |
for att in xmlElements[element]['Attributes'].keys(): |
for att in xmlElements[element]['Attributes'].keys(): |
102 |
self.typecasts[xmlElements[element]['Attributes'][att]['Typecast']] \ |
self.typecasts[xmlElements[element]['Attributes'][att]['Typecast']] \ |
103 |
= 'CDATA' |
= 'CDATA' |
106 |
|
|
107 |
dest.write (""" |
dest.write (""" |
108 |
<!-- |
<!-- |
109 |
Copyright 2001 Free Software Foundation |
Copyright 2001-2002 Free Software Foundation |
110 |
|
|
111 |
This file is part of GNU Enterprise. |
This file is part of GNU Enterprise. |
112 |
|
|
113 |
GNU Enterprise is free software; you can redistribute it |
GNU Enterprise is free software; you can redistribute it |
114 |
and/or modify it under the terms of the GNU General Public |
and/or modify it under the terms of the GNU General Public |
115 |
License as published by the Free Software Foundation; either |
License as published by the Free Software Foundation; either |
116 |
version 2, or (at your option) any later version. |
version 2, or (at your option) any later version. |
117 |
|
|
118 |
GNU Enterprise is distributed in the hope that it will be |
GNU Enterprise is distributed in the hope that it will be |
119 |
useful, but WITHOUT ANY WARRANTY; without even the implied |
useful, but WITHOUT ANY WARRANTY; without even the implied |
120 |
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
121 |
PURPOSE. See the GNU General Public License for more details. |
PURPOSE. See the GNU General Public License for more details. |
122 |
|
|
123 |
You should have received a copy of the GNU General Public |
You should have received a copy of the GNU General Public |
124 |
License along with program; see the file COPYING. If not, |
License along with program; see the file COPYING. If not, |
125 |
write to the Free Software Foundation, Inc., 59 Temple Place |
write to the Free Software Foundation, Inc., 59 Temple Place |
126 |
- Suite 330, Boston, MA 02111-1307, USA. |
- Suite 330, Boston, MA 02111-1307, USA. |
127 |
--> |
--> |
128 |
|
|
129 |
<!-- Entities for characters/symbols --> |
<!-- Entities for characters/symbols --> |
130 |
<!ENTITY lt "&#60;"> |
<!ENTITY % lt "&#60;"> |
131 |
<!ENTITY gt ">"> |
<!ENTITY % gt ">"> |
132 |
<!ENTITY amp "&#38;"> |
<!ENTITY % amp "&#38;"> |
133 |
|
|
134 |
<!-- +---------------------------------------------------+ --> |
<!-- ================================================= --> |
135 |
<!-- | Datatype entities to make DTD more human readable | --> |
<!-- Datatype entities to make DTD more human readable --> |
136 |
<!-- +---------------------------------------------------+ --> |
<!-- ================================================= --> |
137 |
|
|
138 |
""") |
""") |
139 |
if self.typecasts.has_key (GTypecast.text): |
if self.typecasts.has_key (GTypecast.text): |
140 |
self.typecasts[GTypecast.text] = '%text;' |
self.typecasts[GTypecast.text] = '%text;' |
141 |
dest.write('<!ENTITY % text "CDATA">\n\n') |
dest.write('<!ENTITY % text "CDATA">\n\n') |
142 |
|
|
143 |
if self.typecasts.has_key (GTypecast.boolean): |
if self.typecasts.has_key (GTypecast.boolean): |
144 |
self.typecasts[GTypecast.boolean] = '%boolean;' |
self.typecasts[GTypecast.boolean] = '%boolean;' |
145 |
dest.write('<!ENTITY % boolean "(%true;) #IMPLIED">\n' |
dest.write('<!ENTITY % true "Y">\n' |
146 |
'<!ENTITY % true "">\n\n') |
'<!ENTITY % false "N">\n' |
147 |
|
'<!ENTITY % boolean "(%true;|%false;) #IMPLIED">\n\n') |
148 |
|
|
149 |
if self.typecasts.has_key (GTypecast.number): |
if self.typecasts.has_key (GTypecast.number): |
150 |
self.typecasts[GTypecast.number] = '%number;' |
self.typecasts[GTypecast.number] = '%number;' |
151 |
dest.write('<!ENTITY % number "NMTOKEN">\n' |
dest.write('<!ENTITY % number "NMTOKEN">\n' |
152 |
'<!-- [-]?[0-9]+([.][0-9]+)? -->\n\n') |
'<!-- [-]?[0-9]+([.][0-9]+)? -->\n\n') |
153 |
|
|
154 |
if self.typecasts.has_key (GTypecast.whole): |
if self.typecasts.has_key (GTypecast.whole): |
168 |
|
|
169 |
if self.typecasts.has_key (GTypecast.names): |
if self.typecasts.has_key (GTypecast.names): |
170 |
self.typecasts[GTypecast.names] = '%names;' |
self.typecasts[GTypecast.names] = '%names;' |
171 |
dest.write('<!ENTITY & names "CDATA">\n' |
dest.write('<!ENTITY % names "CDATA">\n' |
172 |
'<!-- (%name;)(,[ ]*(%name;))* -->\n\n') |
'<!-- (%name;)(,[ ]*(%name;))* -->\n\n') |
173 |
|
|
174 |
dest.write('\n') |
dest.write('\n') |
175 |
|
|
176 |
self.elementStack = [['Top level element',topLevelElement]] |
self.elementStack = [['Top level element',topLevelElement]] |
177 |
|
|
178 |
while len(self.elementStack) and \ |
while len(self.elementStack) and \ |
179 |
(self.elementStack!=[['Child elements of service']]): |
(self.elementStack!=[['Child elements of service']]): |
180 |
i = 1 |
i = 1 |
181 |
#print "first loop: %s, %s " % \ |
##print "first loop: %s, %s " % \ |
182 |
# (len(self.elementStack),self.elementStack) |
## (len(self.elementStack),self.elementStack) |
183 |
|
|
184 |
## remove allready processed tags |
## remove allready processed tags |
185 |
while i < len(self.elementStack[0]): |
while i < len(self.elementStack[0]): |
186 |
if self.processedTags.has_key(self.elementStack[0][i]): |
if self.processedTags.has_key(self.elementStack[0][i]): |
187 |
|
## print "Popping already used tag %s" % self.elementStack[0][i] |
188 |
self.elementStack[0].pop(i) |
self.elementStack[0].pop(i) |
189 |
else: |
else: |
190 |
i = i + 1 |
i += 1 |
191 |
|
|
192 |
if len (self.elementStack[0]) > 1: |
if len (self.elementStack[0]) > 1: |
193 |
elements = self.elementStack[0][1:] |
elements = self.elementStack[0][1:] |
194 |
elements.sort() |
elements.sort() |
195 |
dest.write('\n<!-- +-' + '-' * (len(self.elementStack[0][0])) + '-+ -->\n') |
dest.write('\n<!-- ' + '=' * (len(self.elementStack[0][0])) + ' -->\n') |
196 |
dest.write('<!-- | %s | -->\n' % self.elementStack[0][0]) |
dest.write('<!-- %s -->\n' % self.elementStack[0][0]) |
197 |
dest.write('<!-- +-' + '-' * (len(self.elementStack[0][0])) + '-+ -->\n') |
dest.write('<!-- ' + '=' * (len(self.elementStack[0][0])) + ' -->\n') |
198 |
for element in elements: |
for element in elements: |
199 |
self.handleElement(element) |
self.handleElement(element) |
200 |
self.elementStack.pop(0) |
self.elementStack.pop(0) |
201 |
# else: |
else: |
202 |
# self.elementStack.pop(0) |
self.elementStack.pop(0) |
203 |
|
|
204 |
|
|
205 |
dest.write ("\n<!-- This DTD was created by gnuedtd\n" |
dest.write ("\n<!-- This DTD was created by gnuedtd\n" |
211 |
# If a dictionary has a key, return value |
# If a dictionary has a key, return value |
212 |
# associated w/that key. Otherwise return dflt. |
# associated w/that key. Otherwise return dflt. |
213 |
# |
# |
214 |
def default(self, dict, key, dflt): |
def default(self, dict, key, dflt): |
215 |
if dict.has_key(key): |
if dict.has_key(key): |
216 |
return dict[key] |
return dict[key] |
217 |
else: |
else: |
222 |
# Line wrap a string. Note, this eliminates redundant spacing |
# Line wrap a string. Note, this eliminates redundant spacing |
223 |
# |
# |
224 |
def wrap(self, indent, text, firstindent=None): |
def wrap(self, indent, text, firstindent=None): |
225 |
if firstindent == None: |
if firstindent == None: |
226 |
firstindent = indent |
firstindent = indent |
227 |
|
|
228 |
pos = 0 |
pos = 0 |
256 |
# for i in self.xmlElements.keys(): |
# for i in self.xmlElements.keys(): |
257 |
# print "element: %s" % i |
# print "element: %s" % i |
258 |
|
|
259 |
if self.default(self.xmlElements[element],'Deprecated',0): |
deprecated = self.default(self.xmlElements[element],'Deprecated',0) |
260 |
self.dest.write(self.wrap(17, |
if deprecated: |
261 |
'<!-- DEPRECATED: Use of the %s element has been deprecated -->' % \ |
if type(deprecated) != type(""): |
262 |
(element),0)) |
deprecated = "" |
263 |
|
else: |
264 |
|
deprecated = "[%s] " % deprecated |
265 |
|
|
266 |
|
self.dest.write(self.wrap(17, |
267 |
|
'<!-- DEPRECATED: Use of the <%s> element has been deprecated %s -->' % \ |
268 |
|
(element, deprecated),0)) |
269 |
|
|
270 |
if self.parentMappings.has_key(element): |
if self.parentMappings.has_key(element): |
271 |
es = self.parentMappings[element].keys() |
es = self.parentMappings[element].keys() |
272 |
else: |
else: |
273 |
es = [] |
es = [] |
274 |
if len(es): |
if len(es): |
275 |
es.insert(0,'Child elements of %s' % element) |
es.insert(0,'Child elements of %s' % element) |
276 |
self.elementStack.append(es) |
self.elementStack.append(es) |
277 |
|
|
278 |
|
|
279 |
descr = self.default(self.xmlElements[element],'Description','') |
descr = self.default(self.xmlElements[element],'Description','') |
280 |
if len(descr): |
if len(descr): |
281 |
self.dest.write(self.wrap(5, |
self.dest.write(self.wrap(5, |
282 |
'<!-- %s -->' % (description), 0)) |
'<!-- %s -->' % (descr), 0)) |
283 |
|
|
284 |
elemdef = "<!ELEMENT %s" % element |
elemdef = "<!ELEMENT %s" % element |
285 |
indent = len(elemdef) + 2 |
indent = len(elemdef) + 2 |
291 |
for child in m: |
for child in m: |
292 |
required = self.default(self.xmlElements[child], 'Required', 0) |
required = self.default(self.xmlElements[child], 'Required', 0) |
293 |
single = self.default(self.xmlElements[child],'SingleInstance',0) |
single = self.default(self.xmlElements[child],'SingleInstance',0) |
294 |
if single and required: |
if single and required: |
295 |
children.append("%s" % child) |
children.append("%s" % child) |
296 |
elif single: |
elif single: |
297 |
children.append("%s?" % child) |
children.append("%s?" % child) |
298 |
elif required: |
elif required: |
299 |
children.append("%s+" % child) |
children.append("%s+" % child) |
300 |
else: |
else: |
301 |
children.append("%s*" % child) |
children.append("%s*" % child) |
304 |
children.append ('#PCDATA') |
children.append ('#PCDATA') |
305 |
|
|
306 |
elemdef = elemdef + (" (%s)" % string.join(children,', ')) |
elemdef = elemdef + (" (%s)" % string.join(children,', ')) |
307 |
|
|
308 |
else: |
else: |
309 |
elemdef = elemdef + " EMPTY" |
elemdef = elemdef + " EMPTY" |
310 |
|
|
311 |
elemdef = elemdef + ">\n" |
elemdef = elemdef + ">\n" |
319 |
otherAtts = [] |
otherAtts = [] |
320 |
atts = self.default(self.xmlElements[element], 'Attributes',{}).keys() |
atts = self.default(self.xmlElements[element], 'Attributes',{}).keys() |
321 |
atts.sort() |
atts.sort() |
322 |
for att in atts: |
for att in atts: |
323 |
|
|
324 |
req = self.default(self.xmlElements[element]['Attributes'][att], |
req = self.default(self.xmlElements[element]['Attributes'][att], |
325 |
'Required',0) |
'Required',0) |
347 |
|
|
348 |
attdef = "<!ATTLIST %s %s " % (element, att) |
attdef = "<!ATTLIST %s %s " % (element, att) |
349 |
|
|
350 |
if self.default(self.xmlElements[element]['Attributes'][att], |
deprecated = self.default(self.xmlElements[element]['Attributes'][att], |
351 |
'Deprecated',0): |
'Deprecated',0) |
352 |
self.dest.write(self.wrap(17, |
if deprecated: |
353 |
' <!-- DEPRECATED: The %s attribute of %s ' |
if type(deprecated) != type(""): |
354 |
'has been deprecated -->' % (att, element),0)) |
deprecated = "" |
355 |
|
else: |
356 |
|
deprecated = "\n[%s] " % deprecated |
357 |
|
|
358 |
|
self.dest.write(self.wrap(17, |
359 |
|
' <!-- DEPRECATED: The "%s" attribute of "%s" ' |
360 |
|
'has been deprecated %s -->' % (att, element, deprecated),0)) |
361 |
|
|
362 |
|
|
363 |
descr = self.default(self.xmlElements[element]['Attributes'][att], |
descr = self.default(self.xmlElements[element]['Attributes'][att], |
364 |
'Description','') |
'Description','') |
365 |
if len(descr): |
if len(descr): |
366 |
self.dest.write(self.wrap(7, |
self.dest.write(self.wrap(7, |
367 |
' <!-- %s -->' % (description), 0)) |
' <!-- %s: %s -->' % (att, descr), 0)) |
368 |
|
|
369 |
datatype = self.default( |
datatype = self.default( |
370 |
self.xmlElements[element]['Attributes'][att], |
self.xmlElements[element]['Attributes'][att], |
371 |
'Typecast',GParser.char) |
'Typecast',GTypecast.text) |
372 |
|
|
373 |
if datatype == int: |
if datatype == int: |
374 |
tokentype = "%number;" |
tokentype = "%number;" |
375 |
else: |
else: |
376 |
tokentype = "NMTOKEN" |
tokentype = "NMTOKEN" |
377 |
|
|
378 |
# handle bool attributes specially |
# handle bool attributes specially |
379 |
if datatype == GParser.bool: |
if datatype == GTypecast.boolean: |
380 |
self.dest.write(self.wrap(len(attdef),attdef +'%boolean;>',0)) |
self.dest.write(self.wrap(len(attdef),attdef +'%boolean;>',0)) |
381 |
|
|
382 |
elif set != None: |
elif set != None: |
383 |
set = set.keys() |
set = set.keys() |
384 |
set.sort() |
set.sort() |
385 |
if len(set) == 1: |
if len(set) == 1: |
386 |
indent = len(attdef) |
indent = len(attdef) |
387 |
attdef = attdef + '%s #FIXED "%s">' \ |
attdef = attdef + '%s #FIXED "%s">' \ |
388 |
% (self.typecasts[datatype], set[0]) |
% (self.typecasts[datatype], set[0]) |
389 |
else: |
else: |
390 |
attdef = attdef + "(" |
attdef = attdef + "(" |
391 |
indent = len(attdef) |
indent = len(attdef) |
392 |
attdef = attdef + "%s)" % string.join(set, ' | ') |
attdef = attdef + "%s)" % string.join(set, ' | ') |
393 |
if dflt != None and len(dflt): |
if dflt != None and len(dflt): |
394 |
attdef = attdef + ' "%s">' % dflt |
attdef = attdef + ' "%s">' % dflt |
395 |
else: |
else: |
396 |
attdef = attdef + ' #IMPLIED>' |
attdef = attdef + ' #IMPLIED>' |
397 |
self.dest.write(self.wrap(indent, attdef, 0)) |
self.dest.write(self.wrap(indent, attdef, 0)) |
398 |
|
|
399 |
elif refs != None: |
elif refs != None: |
400 |
indent = len(attdef) |
indent = len(attdef) |
401 |
if req: |
if req: |
402 |
attdef = attdef + ' IDREF #REQUIRED>' |
attdef = attdef + ' IDREF #REQUIRED>' |
403 |
else: |
else: |
404 |
attdef = attdef + ' IDREF #IMPLIED>' |
attdef = attdef + ' IDREF #IMPLIED>' |
405 |
self.dest.write(self.wrap(indent, attdef, 0)) |
self.dest.write(self.wrap(indent, attdef, 0)) |
406 |
|
|
407 |
elif unq: |
elif unq: |
408 |
indent = len(attdef) |
indent = len(attdef) |
409 |
if req: |
if req: |
410 |
attdef = attdef + ' ID #REQUIRED>' |
attdef = attdef + ' ID #REQUIRED>' |
411 |
else: |
else: |
412 |
attdef = attdef + ' ID #IMPLIED>' |
attdef = attdef + ' ID #IMPLIED>' |
413 |
self.dest.write(self.wrap(indent, attdef, 0)) |
self.dest.write(self.wrap(indent, attdef, 0)) |
414 |
|
|
415 |
elif dflt != None: |
elif dflt != None: |
416 |
indent = len(attdef) |
indent = len(attdef) |
417 |
attdef = attdef + ' %s #DEFAULT "%s">' \ |
attdef = attdef + ' %s "%s">' \ |
418 |
% (self.typecasts[datatype], dflt) |
% (self.typecasts[datatype], dflt) |
419 |
self.dest.write(self.wrap(indent, attdef, 0)) |
self.dest.write(self.wrap(indent, attdef, 0)) |
420 |
|
|
421 |
else: |
else: |
431 |
|
|
432 |
self.dest.write ("\n") |
self.dest.write ("\n") |
433 |
|
|
434 |
if len(sys.argv) > 1: |
if len(sys.argv) > 1: |
435 |
GenerateDTD(sys.argv[1]) |
try: |
436 |
else: |
dest = open(sys.argv[2],'w') |
437 |
|
except IndexError: |
438 |
|
dest = sys.stdout |
439 |
|
GenerateDTD(sys.argv[1], dest) |
440 |
|
dest.close() |
441 |
|
else: |
442 |
GenerateDTD(None) |
GenerateDTD(None) |