# Part of the A-A-P GUI IDE: Aap project Activity class

# Copyright (C) 2002-2003 Stichting NLnet Labs
# Permission to copy and use this file is specified in the file COPYING.
# If this file is missing you can find it here: http://www.a-a-p.org/COPYING

from Activity import Activity
from os import stat
from sre import split
import Navigator
import os.path

# TODO: Do this properly with gettext().
def _(x):
    return x

class Makefile(Activity):
    """Makefile Activity."""

    def open(self):
        item = Navigator.ActyItem(self.name, os.getcwd(), self, None)
	nav = Navigator.Navigator("Project", item)
	self.addNav(nav)
	
	makefile_items, makefile_topdir = makefile2items(self.name)
	if makefile_items:
	    item.addTree(makefile_items, makefile_topdir, 0)
        
        self.modified = 0

    def save(self):
        # Nothing to be done since Makefile support is read only.
	pass

def getMenuText():
    return _("Makefile"), _("View a Makefile")

def create(topmodel):
    """Create a new activity: create a Makefile."""
    name = topmodel.view.fileDialog(_("Enter name for new Makefile project"))
    if not name:
        return None
    
    # XXX: This is really ugly.
    if name[name.rfind('/')+1:] not in ["Makefile", "makefile", \
    					"GNUmakefile", "GNUMakefile"] \
       and name[-3:] != ".mk":
        name = name + ".mk"
     
    if os.path.exists(name):
        print "Project's makefile '%s' already exist!" % name
	return None

    try:
        f = open(name, "w")
    except StandardError, e:
        print "Cannot create '%s': %s", (name, str(e))
	return None

    try:
        f.write("# Makefile autogenerated. Please edit it before use.\n"
		+ "CC = gcc\n"
		+ "CFLAGS = -g -O2\n"
		+ "CPPFLAGS = -I.\n"
		+ "OBJS = myprog.o\n\n"
		+ "myprog: $(OBJS)\n"
		+ "\t$(CC) $(CFLAGS) -o myprog myprog.o\n"
		)
    except StandardError, e:
        print "Cannot write to '%s': %s" % (name, str(e))
	return None
   
    f.close()
    act = Makefile(name, topmodel)
    act.open()
    return act

def canOpen(name, type):
    """Returns true if it's a Makefile."""
    return os.path.isfile(name) and (type == "make" or name[-3:] == ".mk")

files = {}

def line2list(line, input, variables, expand_var = 1):
    """Splits all elements of a line including those which follow an escape
       sequence ('\\'). Adds all existing files to global 'files'."""
    global files
    
    depsdict = {}
    while 1:
        # First line passed must not be null.
	if line == "":
	    try:
                line = input.readline()
	        if not line: # End of file.
	            return depsdict
	    except IOError, e:
	        # TODO: Print file name.
	        print "Cannot read file: %s" % str(e)
		return {}
	if line.find("#") > 0: # Skip comments
	    line = line[0:line.find("#")]
	deps = split("([ \t]*)([^ \t\\\\]+)", line)
	deps = [dep.lstrip().rstrip() for dep in deps]
	for dep in deps:
	    is_escaped = 0
	    if dep != "" and dep != "\\":
	        # dep is "something\" (without space.)
		if dep[len(dep)-1] == "\\":
		    deps[deps.find(dep)] = dep[-1:]
		    is_escaped = 1
		
		if dep[0] == "$" and expand_var == 1:
		    dep = dep.replace("$(", "").replace(")", "")
		    # Expand variables.
		    try:
		        depsdict[dep] = variables[dep]
		    except KeyError:
		        pass # Forget unknown variables.
		else:
		    try:
		       if stat(dep)[3] == 1: # Is an exisiting file.
		           files[dep] = {}
		    except OSError:
		       pass
		    depsdict[dep] = {}
	# "\" could be followed by some empty fields.
	if "\\" in deps or is_escaped:
	    line = ""
	    continue # There is an escaped line.
	else:
	    break
    return depsdict

def makefile2items(name):
    """Generates tow threes, VARS and TARGETS from Makefile. Really trivial
       parsing, doesn't work with really complex makefiles."""
    global files

    try:
        input = file(name, "r")
    except IOError, e:
        print "Cannot open '%s': %s" % (name, str(e))
	return {}
    items = {}
    
    variables = {}
    targets = {} 
    
    while 1:
        try:
            line = input.readline()
	    if not line:
	        break
	except IOError, e:
	    print "Cannot read '%s': %s" % (name, str(e))
	    return {}

	if line.find("#") >= 0: # Skip comments
	   line = line[0:line.find("#")]
	
	# If line is empty, continue.
	if line.lstrip() == "":
	   continue
        
	colon = line.find(":")
	equal = line.find("=")

	if not line[0].isspace() and (colon > 1 and (equal < 0 or equal > colon)): # Is a target
	    try:
	        [useless, target, depslist] = split("^([^:]+):[ \t]*", line)
            except ValueError:
	        # Should never happen really, but avoids failures.
		print "Sorry, cannot parse this line:\n%s" % line
		continue
	    if depslist:
	        depsdict = line2list(depslist, input, variables)
            else:
	        depsdict = {}
	    # Also add objects without dependencies.
	    if target[0] == "$":
                target = target.replace('$(', '').replace(')', '')
            targets[target] = depsdict
            continue
	
	if not line[0].isspace() and (equal > 1 and (colon < 0 or colon > equal)): # Is a variable
	    try:
	        [useless, varname, useless, varvalue, useless] = \
	           split("^([A-Za-z_][0-9A-Za-z_]+)([ \t]*\\+?=[ \t]*)(.*)$",\
		   	line)
	    except ValueError:
		# Should never happen really, but avoids failures.
		print "Sorry, cannot parse this line:\n%s" % line
		continue
	    if variables.has_key(varname):
	        newcontent = variables[varname]
		varvalues = line2list(varvalue, input, variables, 0)
		for varvalue in varvalues.keys():
		    newcontent[varvalue] = {}
		variables[varname] = newcontent
	    else:
	        if varvalue:
		    variables[varname] = line2list(varvalue, input, variables)
		else:
		    variables[varname] = {}
	    
    if variables != {}:
	items["VARS"] = variables
    if targets != {}:
        items["TARGETS"] = targets
    # Insert FILES even if it's empty.
    items["FILES"] = files
    return items, os.getcwd()

# vim: set sw=4 et sts=4 tw=79 fo+=l: