aboutsummaryrefslogtreecommitdiff
blob: b0cd7aa66643b3dc2cd7acadd68d70d5a0216192 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import os
import glob
from filetypes.ctypefiles import scanincludes
from filetypes.makefiles import scanmakefile
from filetypes.makefilecom import expand
from filetypes.autoconf import scanac
from filetypes.automake import initscan

def scandirfor(dir, filetypes):
    """Scans recursivly the supplied dir for provided filetypes.

    And return a list of files found
    """

    files = []
    dirs = [f for f in os.listdir(dir)
        if os.path.isdir(os.path.join(dir, f))]
    for filetype in filetypes:
        files += glob.glob(dir + "/*" + filetype)
    for dir_path in dirs:
        files += scandirfor(dir + "/" + dir_path, filetypes)
    return files

def scanmakefiledeps(makefile):
    """Scans makefile for what files it would compile.

    returns a list of files to scan for deps,
    binaries build with the first makefile option,
    additional includeflags and what the 'targets : deps'
    are in the makefile
    """

    curdir = os.path.split(makefile)[0] + "/"
    olddir = os.getcwd()
    makefile = openfile(makefile)
    binaries = set() #the binaries that the .o file create
    filestoscan = set()
    impfiles = [] #look for these files
    moptions = [] #make options scan these for -I... flags
    os.chdir(curdir) #so makefiles commands can execute in the correct dir
    targets,variables = scanmakefile(makefile)
    deps = targets[0][1] #Use first make target
    while deps != []:
        newdeps = []
        for dep in deps:
            for target in targets:
                if target[0] == dep:
                    newdeps += target[1]
                    if ".o" in dep or dep in impfiles:
                        impfiles += target[1]
                        moptions += target[2]
                    elif ".o" in target[1][0]:
                        binaries.add(target[0])
                        moptions += target[2]
        deps = newdeps

    #print(impfiles)
    for impfile in impfiles:
        filestoscan.add(curdir + impfile)

    incflags = set()
    for item in expand(moptions,variables):
        if item[0:2] == "-I":
            incflags.add(item[2:])

    #print(filestoscan)
    os.chdir(olddir)
    return filestoscan,binaries,incflags,targets

def scanautotoolsdeps(acfile,amfile):
    """Scans autoconf file for useflags and the automake file in the same dir.

    Scans the provided autoconf file and then looks for a automakefile in the
    same dir. Autoconf scan returns a dict with useflags and a list with variables
    that gets defined by those useflags.

    Call the automake scan with the am file (that is in the same dir as the ac file)
    and the list of variables from the autoconf scan and it will return a list of
    default source files and a dict of files that gets pulled in by the useflag it
    returns.
    """
    #these are not really useflags yet. So perhaps change name?
    topdir = os.path.split(amfile)[0] + "/"
    useflags, iflst = scanac(openfile(acfile),topdir)
    srcfiles, src_useflag, src_incflag = initscan(amfile, iflst)

    #print(iflst)
    #print(srcfiles)
    #standard includes
    includes = scanfilelist(srcfiles,src_incflag)

    def inter_useflag(uselst):
        if uselst[1] == "yes" or uselst[1] == "!no":
            usearg = uselst[0]
        elif uselst[1] == "no" or uselst[1] == "!yes":
            usearg = "!" + uselst[1]
        else:
            usearg = uselst[0] + "=" + uselst[1]

        return usearg

    #useflag includes
    useargs = {}
    for src in src_useflag:
        usearg = inter_useflag(src_useflag[src])
        if usearg in useargs:
            useargs[usearg] += [src]
        else:
            useargs[usearg] = [src]

    for usearg in useargs:
        useargs[usearg] = scanfilelist(useargs[usearg],src_incflag)

    #print(useargs)
    #print(includes)
    return useflags,includes,useargs

def scanfilelist(filelist,src_incflag):
    """ Scan files in filelist for #includes

    returns a includes list with this structure:
    [set(),set(),dict()]
    There the first two sets contains global and local includes
    and the dict contains variables that can pull in additional includes
    with the same structure as above
    """
    global_hfiles = set()
    local_hfiles = set()
    inclst = [global_hfiles,local_hfiles,{}]

    for file in filelist:
        #print(file)
        incpaths = src_incflag[file]
        filestring = openfile(file)
        if not filestring == None:
            inclst = scanincludes(filestring,inclst,os.path.split(file)[0],incpaths)

    return(inclst)

def scanproject(dir,projecttype):
    """Scan a project (source) dir for files that may build it

    This tries to guess which kind of project it is. IE
    autotools? makefile?
    """
    if projecttype == "guess":
        filestolookfor = ["Makefile","makefile",
	"configure.ac","configure.in"] #add more later
    elif projecttype == "makefile":
        filestolookfor = ["Makefile","makefile"]
    elif projecttype == "autotools":
        filestolookfor = ["configure.ac","configure.in"]

    mfile = scandirfor(dir, filestolookfor)[0] #use first file found
    print(mfile)
    if mfile == "Makefile" or mfile == "makefile":
        (scanlist,binaries,incflags,targets) = scanmakefiledeps(mfile)
	#this is broken now... rewrite
        return scanfilelist(scanlist),binaries,incflags,targets

    else:
        amfile = os.path.split(mfile)[0] + "/" + "Makefile.am"
        return scanautotoolsdeps(mfile,amfile)

def openfile(file):
    """Open a file and return the content as a string.

    Returns nothing and print an error if the file cannot be read
    """
    try:
        with open(file, encoding="utf-8", errors="replace") as inputfile:
            return inputfile.read()
    except IOError:
        print('cannot open', file)