5
\$\begingroup\$

So I came up with a problem In C. Our compiler is pre c99 and wasn't identifying functions that are never called. So I ended up writing this script and decided to post it up to be critiqued and to help people who might be in the same predicament. The script works great for me and finished the job that I needed it to do. I just felt that it could be done better.

from sys import exit
import re
import os ,fnmatch
#"(static BOOL|BOOL|static void|void)\s+([A-Z a-z]+)(\(.*?\)\;)"
pattern = "(static BOOL|BOOL|static void|void|static BYTE|BYTE|static int|int)\s+([A-Z a-z]+)(\(.*?\)\;)"

compiled = re.compile(pattern)
commentend = re.compile("\*/")
commentbegin = re.compile("/\*.*") #|\}/s/\*.* extra pattern
count = 0
directory =" "

def menu():#menu function
    global directory
    print "what would you like to do"
    print "1. Enter directory of .c and .h files you want searched"
    print "2. Display possibly unused functions" #not used
    print "Any other key exit program"

    selection = raw_input("> ")
    if selection == '1':#this menu starts the search process
        print "you selected search"
        print "what is the file name"
        directory = raw_input("> ")
        openfiles()
    elif selection == '2':#this selection is not currently used
        print "displaying matching functions"
        print count
    else:
        exit(0)


def openfiles(): #gets a list of file names and then passes the name to search for function to open
    for root,dirs,files in os.walk(directory):
        for pat in ['*.c','*.h']:
            for current_file in fnmatch.filter(files,pat):
                searchforfunction(current_file)

def searchforfunction(file_name):
    global directory
    print file_name
    with open(os.path.join(directory,file_name) ,"r" ,1) as f:
        for line in f:
            matchfun(line)


def matchfun(line): #This searches for a function looking for specific definition then checks how many times the function occurs
    global count
    name_func = compiled.match(line)
    if name_func:
        name_func = name_func.group(2)
        count = searchfilesecond(name_func)
        if count <= 2:
            print name_func," was called",count,"times"
        if count == 2:
            writefunc_twice(name_func)
        if count == 1:
            writefunc_one(name_func)
    count = 0

def writefunc_one(name_func):
    with open("occur_once_func.txt", "a") as myfile:
        myfile.write(name_func+" was called 1 time\n")

def writefunc_twice(name_func):
    with open("occur_twice_func.txt", "a") as myfile:
        myfile.write(name_func + " was called 2 times\n")

def searchfilesecond(name_func): #walks the directory again and searches for a match by passing it so secondsearch
    global count
    global directory
    for root,dirs,files in os.walk(directory):
        for pat in ['*.c','*.h']:
            for current_file in fnmatch.filter(files,pat):
                count = secondsearch(name_func,current_file)

    return count

def secondsearch(name_func,current_file): #this function searches for any instances of the function
    global count
    global directory
    in_comment = False
    secondpatern = re.compile(name_func)
    with open(os.path.join(directory,current_file) ,"r" ,1) as f:

        for line in f:
            if commentbegin.search(line):#This statement searches for the /* part of a comment
                in_comment = True
            if commentend.search(line):#This statement searches for the */ part of a comment
                in_comment = False
            elif in_comment == False:           
                name_func1 = secondpatern.search(line)
                if name_func1:
                    count += 1  
            else:
                pass
    return count

while(1):
    menu()
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Have you tried, with gcc, to compile with -ffunction-sections and link with --gc-sections? \$\endgroup\$ Commented Sep 12, 2013 at 15:37
  • \$\begingroup\$ Do you use VIM? There is a plugin called Pyflakes that can do this for you (among other things). If a function is defined but never called or a library imported but never used Pyflakes puts break lines underneath the names. \$\endgroup\$ Commented Sep 12, 2013 at 15:53
  • 1
    \$\begingroup\$ What you're looking for is code coverage. I've never done it for C, but this question on SO looks like a good place to start. \$\endgroup\$ Commented Sep 12, 2013 at 20:04
  • \$\begingroup\$ See this question on Stack Overflow. \$\endgroup\$ Commented Sep 14, 2013 at 13:37

1 Answer 1

2
\$\begingroup\$

Two major points:

  • The parsing is very fragile and only works when the code is laid out in a certain way. You should look for a proper parser and leverage that.
  • It is rather inefficient to scan all the files every time you encounter a function declaration. You could use dictionaries to keep track of functions so one pass over the files would suffice.
\$\endgroup\$

You must log in to answer this question.