'''
A script used to extract almost all constants from C header files (*.h).

(c) 2007-2018 Jan ONDREJ (SAL) <ondrejj(at)salstar.sk>

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or 
 (at your option) any later version.

'''

import re, sys, os

reg_define = re.compile(
  r'^#define\s+(CL_)([A-Z0-9a-z_]+)\s+(.*?) *$'
)
reg_enum_start = re.compile(
  r'^(typedef +)?enum +([a-z0-9_]*) *{*'
)
reg_enum_end = re.compile(
  r'^} *[a-z0-9_]*;$'
)

if len(sys.argv)>1 and sys.argv[1] not in ['', '-']:
  sys.stdout = open(sys.argv[1], 'wt')

clamav_version = os.popen('clamav-config --version').read().strip() \
                 or 'UNKNOWN'

def cprint(s):
    print(s.rstrip())

cprint("""\
# This file is automatically generated by getconst.py
# on system with clamav-%s.
""" % clamav_version)

if len(sys.argv)>2:
  clamav_h = open(sys.argv[2], 'rt')
  cprint("# source: %s" % sys.argv[2])
else:
  clamav_h = open('/usr/include/clamav.h', 'rt')

enum_block = 0
for line in clamav_h.readlines():
  # handle comments and trailing new lines
  if '/*' in line:
    line, comment = line.strip().split('/*', 1)
    comment = ' # /*'+comment
  else:
    line = line.strip()
    comment = ''
  # enum block
  if enum_block==0 and reg_enum_start.search(line):
    cprint("")
    cprint("# enum block start: %s %s" % (line, comment))
    enum_block += 1
    enum_counter = -1
    continue
  if enum_block>0 and reg_enum_end.search(line):
    cprint("# enum block end: %s %s" % (line, comment))
    cprint("")
    enum_block = 0
    continue
  if enum_block>0:
    if '=' in line:
      enum_counter = int(line.split('#')[0].split('=')[1].strip(' ,'))
      line = line.strip(' ,')
      enum_block += line.split('#',1)[0].count(',')
      cprint("%s %s" % (line, comment))
    elif line.startswith("CL_"):
      enum_counter += 1
      #line = "%s = %d" % (line.strip(' ,'), enum_counter)
      value = ' = %d' % enum_counter
      line2 = line.replace(',', value, 1)
      if line2==line:
        line3 = line.lstrip().replace(' ', value ,1)
        if line3==line:
          line = line+value
        else:
          line = line3
      else:
        line = line2
      enum_block += line.split('#',1)[0].count(',')
      cprint("%s %s" % (line, comment))
  # search for #define line
  r = reg_define.search(line)
  if r:
    cprint("%s%s = %s" % r.groups())

# add section to remove CL_ prefix for all constants
cprint("""
for key, value in list(globals().items()):
  if key.startswith("CL_") and (key[3:] not in globals()):
      exec("%s = %s" % (key[3:], key))

from ctypes import Structure, c_uint32
class OPTIONS(Structure):
  _fields_ = [
    ("general", c_uint32),
    ("parse", c_uint32),
    ("heuristic", c_uint32),
    ("mail", c_uint32),
    ("dev", c_uint32)
  ]
""")
