dns.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """
  2. pygments.lexers.dns
  3. ~~~~~~~~~~~~~~~~~~~
  4. Pygments lexers for DNS
  5. :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS.
  6. :license: BSD, see LICENSE for details.
  7. """
  8. import re
  9. from pygments.token import Comment, Operator, Keyword, Name, String, \
  10. Number, Punctuation, Whitespace, Literal
  11. from pygments.lexer import RegexLexer, bygroups, include
  12. __all__ = ['DnsZoneLexer']
  13. CLASSES = [
  14. "IN",
  15. "CS",
  16. "CH",
  17. "HS",
  18. ]
  19. CLASSES_RE = "(" + "|".join(CLASSES) + ')'
  20. class DnsZoneLexer(RegexLexer):
  21. """
  22. Lexer for DNS zone file
  23. """
  24. flags = re.MULTILINE
  25. name = 'Zone'
  26. aliases = ['zone']
  27. filenames = [ "*.zone" ]
  28. url = "https://datatracker.ietf.org/doc/html/rfc1035"
  29. mimetypes = ['text/dns']
  30. version_added = '2.16'
  31. tokens = {
  32. 'root': [
  33. # Empty/comment line:
  34. (r'([ \t]*)(;.*)(\n)', bygroups(Whitespace, Comment.Single, Whitespace)),
  35. # Special directives:
  36. (r'^\$ORIGIN\b', Keyword, 'values'),
  37. (r'^\$TTL\b', Keyword, 'values'),
  38. (r'^\$INCLUDE\b', Comment.Preproc, 'include'),
  39. # TODO, $GENERATE https://bind9.readthedocs.io/en/v9.18.14/chapter3.html#soa-rr
  40. (r'^\$[A-Z]+\b', Keyword, 'values'),
  41. # Records:
  42. # <domain-name> [<TTL>] [<class>] <type> <RDATA> [<comment>]
  43. (r'^(@)([ \t]+)(?:([0-9]+[smhdw]?)([ \t]+))?(?:' + CLASSES_RE + "([ \t]+))?([A-Z]+)([ \t]+)",
  44. bygroups(Operator, Whitespace, Number.Integer, Whitespace, Name.Class, Whitespace, Keyword.Type, Whitespace),
  45. "values"),
  46. (r'^([^ \t\n]*)([ \t]+)(?:([0-9]+[smhdw]?)([ \t]+))?(?:' + CLASSES_RE + "([ \t]+))?([A-Z]+)([ \t]+)",
  47. bygroups(Name, Whitespace, Number.Integer, Whitespace, Name.Class, Whitespace, Keyword.Type, Whitespace),
  48. "values"),
  49. # <domain-name> [<class>] [<TTL>] <type> <RDATA> [<comment>]
  50. (r'^(Operator)([ \t]+)(?:' + CLASSES_RE + "([ \t]+))?(?:([0-9]+[smhdw]?)([ \t]+))?([A-Z]+)([ \t]+)",
  51. bygroups(Name, Whitespace, Number.Integer, Whitespace, Name.Class, Whitespace, Keyword.Type, Whitespace),
  52. "values"),
  53. (r'^([^ \t\n]*)([ \t]+)(?:' + CLASSES_RE + "([ \t]+))?(?:([0-9]+[smhdw]?)([ \t]+))?([A-Z]+)([ \t]+)",
  54. bygroups(Name, Whitespace, Number.Integer, Whitespace, Name.Class, Whitespace, Keyword.Type, Whitespace),
  55. "values"),
  56. ],
  57. # Parsing values:
  58. 'values': [
  59. (r'\n', Whitespace, "#pop"),
  60. (r'\(', Punctuation, 'nested'),
  61. include('simple-value'),
  62. ],
  63. # Parsing nested values (...):
  64. 'nested': [
  65. (r'\)', Punctuation, "#pop"),
  66. include('multiple-simple-values'),
  67. ],
  68. # Parsing values:
  69. 'simple-value': [
  70. (r'(;.*)', bygroups(Comment.Single)),
  71. (r'[ \t]+', Whitespace),
  72. (r"@\b", Operator),
  73. ('"', String, 'string'),
  74. (r'[0-9]+[smhdw]?$', Number.Integer),
  75. (r'([0-9]+[smhdw]?)([ \t]+)', bygroups(Number.Integer, Whitespace)),
  76. (r'\S+', Literal),
  77. ],
  78. 'multiple-simple-values': [
  79. include('simple-value'),
  80. (r'[\n]+', Whitespace),
  81. ],
  82. 'include': [
  83. (r'([ \t]+)([^ \t\n]+)([ \t]+)([-\._a-zA-Z]+)([ \t]+)(;.*)?$',
  84. bygroups(Whitespace, Comment.PreprocFile, Whitespace, Name, Whitespace, Comment.Single), '#pop'),
  85. (r'([ \t]+)([^ \t\n]+)([ \t\n]+)$', bygroups(Whitespace, Comment.PreprocFile, Whitespace), '#pop'),
  86. ],
  87. "string": [
  88. (r'\\"', String),
  89. (r'"', String, "#pop"),
  90. (r'[^"]+', String),
  91. ]
  92. }
  93. def analyse_text(text):
  94. return text.startswith("$ORIGIN")