Steve Steve - 7 months ago 12
Bash Question

Adding Log Statements To Beginning and Ending of All Functions By Shell

I have a project which has more than 1000 source c++ files storing in different folders under the same directory. I want to add log code to the beginning and ending of all functions defined in these .cpp files. See the example below:

//SomeSrcFile.cpp
//Sample
ReturnType SomeClass::SomeFunc1(InputParameters)
{
......
}

ReturnType SomeClass::SomeFunc2(InputParameters) {
......
}


output



ReturnType SomeClass::SomeFunc1(InputParameters)
{
char FuncName[] = "SomeClass::SomeFunc1()"; //line added
printf("%s begins\n", FuncName); //line added

......

printf("%s ends\n", FuncName); //line added
}

ReturnType SomeClass::SomeFunc2(InputParameters) {
char FuncName[] = "SomeClass::SomeFunc2()"; //line added
printf("%s begins\n", FuncName); //line added

......

printf("%s ends\n", FuncName); //line added
}


How to write the shell script for this kind of work? Can awk be used here?

UPDATE


  1. I think it is possible to do it by AWK like This Post does. But I haven't figured out how to do it in my way.

  2. I only want to use either Bash or Python for doing this, because they are only tools I am familiar with now.



UPDATE 2

Perhaps this work is really hard that beyond my expectation. But what if I don't care about the accuracy? What if I don't care the cases that Functions are included in comments and the like? Isn't there a simple way to do this?

Answer

If you don't mind it not being robust, this will do what you want for simple consistent cases using GNU awk for the 3rd arg to match() and abbreviations for character classes (e.g. \w):

$ cat tst.awk
BEGIN {
    beg = "\tchar FuncName[] = \"%s()\";\n\tprintf(\"%%s begins\\n\", FuncName);\n"
    end = "\n\tprintf(\"%%s ends\\n\", FuncName);"
}
match($0,/^\s*\w+\s+(\w+::\w+)[(][^)]*[)]/,arr) { funcName  = arr[1] }
/{/ && (++braceCnt == 1) { $0 = $0 ORS sprintf(beg,funcName) }
/}/ && (--braceCnt == 0) { $0 = sprintf(end,funcName) ORS $0 }
{ print }

.

$ awk -f tst.awk file
    //SomeSrcFile.cpp
    //Sample
    ReturnType SomeClass::SomeFunc1(InputParameters)
    {
        char FuncName[] = "SomeClass::SomeFunc1()";
        printf("%s begins\n", FuncName);

         ......

        printf("%s ends\n", FuncName);
    }

    ReturnType SomeClass::SomeFunc2(InputParameters) {
        char FuncName[] = "SomeClass::SomeFunc2()";
        printf("%s begins\n", FuncName);

         ......

        printf("%s ends\n", FuncName);
    }

With other awks just use [[:space:]] instead of \s and [[:alnum:]_] instead of \w in the regexp and use a combination of match() with substr() and/or sub()s to extract the function name from the string that matches the regexp, e.g.:

$ cat tst2.awk
BEGIN {
    beg = "\tchar FuncName[] = \"%s()\";\n\tprintf(\"%%s begins\\n\", FuncName);\n"
    end = "\n\tprintf(\"%%s ends\\n\", FuncName);"
}
/^[[:space:]]*[[:alnum:]_]+[[:space:]]+([[:alnum:]_]+::[[:alnum:]_]+)[(][^)]*[)]/ {
    funcName = $0
    gsub(/^[[:space:]]*[[:alnum:]_]+[[:space:]]+|[(][^)]*[)].*/,"",funcName)
}
/{/ && (++braceCnt == 1) { $0 = $0 ORS sprintf(beg,funcName) }
/}/ && (--braceCnt == 0) { $0 = sprintf(end,funcName) ORS $0 }
{ print }
Comments