#!/usr/bin/env python2

import argparse
import os
import random
import subprocess
import sys

start_marker_value = 15787101993977663533L
end_marker_value   = 5017403343786645061L
random_value       = random.getrandbits(64)

def to_le64(value):
    return ''.join(chr((value >> shift) & 0xff) for shift in xrange(0, 64, 8))

def to_be64(value):
    return ''.join(chr((value >> shift) & 0xff) for shift in xrange(56, -8, -8))

def from_le64(data):
    return sum(ord(byte) << shift for byte, shift in zip(data, xrange(0, 64, 8)))

def from_be64(data):
    return sum(ord(byte) << shift for byte, shift in zip(data, xrange(56, -8, -8)))

def write_ccode(out, includes, exprs):
    for include in includes:
        print >>out, '#include <' + include + '>'

    print >>out, 'unsigned long long int values[] = {'
    print >>out, '  {}ull,'.format(start_marker_value)
    print >>out, '  {}ull,'.format(random_value)

    for expr in exprs:
        print >>out, '  {},'.format(expr)

    print >>out, '  {}ull'.format(end_marker_value)
    print >>out, '};'

def find_values(content, to_bytes, from_bytes, n_exprs):
    start_marker = to_bytes(start_marker_value) + to_bytes(random_value)
    end_marker = to_bytes(end_marker_value)

    prev_start = 0

    while True:
        start = content.find(start_marker, prev_start)
        if start == -1:
            return None

        start += 16
        end = start + 8 * n_exprs
        if end + 8 <= len(content) and content[end:end + 8] == end_marker:
            break

        prev_start = start

    return [from_bytes(content[n:n+8]) for n in xrange(start, end, 8)]

def extract_values(filename, n_exprs):
    contents = open(filename).read()

    result = find_values(contents, to_le64, from_le64, n_exprs)

    if result is None:
        result = find_values(contents, to_be64, from_be64, n_exprs)

    return result

def evaluate_exprs(cc, cflags, includes, exprs):
    cfile = open('tmpfile.c', 'w')
    write_ccode(cfile, includes, exprs)
    cfile.close()

    subprocess.check_call([cc] + cflags.split(' ') + ['-c', '-o', 'tmpfile.o', 'tmpfile.c'])

    result = extract_values('tmpfile.o', len(exprs))

    os.unlink('tmpfile.c')
    os.unlink('tmpfile.o')

    return result

print evaluate_exprs('gcc', '-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include', ['glib.h'], ['sizeof(int)', 'sizeof(void*)', 'G_BYTE_ORDER', 'G_STRUCT_OFFSET(GQueue, length)'])

