#!/usr/bin/env python
#******************************************************************************\
#* Copyright (C) 2003-2004 Martin Blais <blais@furius.ca>
#*
#* 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.
#*
#* This program is distributed in the hope that it will be useful,
#* but WITHOUT ANY WARRANTY; without even the implied warranty of
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#* GNU General Public License for more details.
#*
#* You should have received a copy of the GNU General Public License
#* along with this program; if not, write to the Free Software
#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#*
#*****************************************************************************/

"""flatten-baden [<options>] <header-file> [<root-dir>]

Process a C/C++ file as if to pre-process it, only processing include directives
for a single include directory.  This effectively generates one very large
include file that can be included instead of the given file.

Argument ``file`` is the file to be processed. Optional argument ``root-dir`` is
the directory relative to which the included files will be pasted in.

This also implicitly includes any file once only.

"""

__version__ = "Revision: 1.5 "
__author__ = "Martin Blais <blais@furius.ca>"


import sys, os, re
from os.path import *

incre = re.compile('^\s*#\s*include\s*<(.*)>')

sepfmt = '/* ========== flatten-baden %s : "%s" */\n'

def process(srcfn, rootdir, filemap):

    """Process a file like cpp, and call itself recursively for included
    files."""

    try:
        # read all lines and close so that we don't keep too many files open.
        f = open(srcfn, 'r')
        lines = f.readlines()
        f.close()
    except IOError, e:
        raise SystemExit("Error: process file (%s)" % str(e))

    # mark file as processed
    filemap[ srcfn ] = 1
    
    outlines = []
    for l in lines:
        newlines = [l]
        
        mo = incre.match(l)
        if mo:
            sname = mo.group(1)
            aincfn = join(rootdir, sname)
            if aincfn in filemap:
                # skip already included files.
                newlines = [sepfmt % ('SKIP ', sname)]
            elif exists(aincfn):
                print >> sys.stderr, 'Processing:', mo.group(1)

                proclines = process(aincfn, rootdir, filemap)

                newlines = [sepfmt % ('BEGIN', sname)]
                newlines.extend(proclines)
                newlines.append(sepfmt % ('END  ', sname))

        outlines.extend(newlines)
                
    return outlines

    

def main():
    import optparse
    parser = optparse.OptionParser(__doc__.strip(), version=__version__)
    opts, args = parser.parse_args()

    if len(args) not in [1, 2]:
        raise parser.error(
            "Error: you must specify at least a file to process.")

    srcfn, rootdir = args[0], os.getcwd()
    if len(args) >= 2:
        rootdir = args[1]
    assert rootdir
    
    if not exists(srcfn):
        raise SystemExit("Error: specified source file does not exist")
    if not exists(rootdir):
        raise SystemExit("Error: specified root dir does not exist")

    # create a filemap of all the processed files
    filemap = {}
    outlines = process(srcfn, rootdir, filemap)
    
    for i in outlines:
        print i,

if __name__ == '__main__':
    main()
