Trace Words in Shell Script - regex

I am trying to find malloc-free series. Consider that we have 1000s of test cases. People may forget to free ptr. Please help me in optimizing the script.
Sample File Under test
Test(func_class,func1)
{
int i,j;
char* ptr = (char*) malloc(sizeof(char));
free(ptr);
}
Test(func_class,func1)
{
int i,j;
char* ptr = (char*) malloc(sizeof(char));
/ Memory Leak /
}
Script under development :
export MY_ROOT=`pwd`
_COUNT=0
pwd
_COUNT_WORD=0
filename=test.c
cat $filename | while read line
do
echo "Reading Line = $LINE"
for word in $line
do
_COUNT_WORD=$(($_COUNT_WORD+1))
echo $_COUNT_WORD $word
if [ "$word" == "malloc\(sizeof\(char\)\);" ]; then
_MALLOC_FLAG=1 #this part of the code is not reached
echo "Malloc Flag Hi"
echo $word[2]
fi
done
_COUNT_WORD=0
done
I have some issue in matching the malloc regex. I know the script needs a lot of modifications as we have to find the pattern of individual person writing malloc.

There are other ways to check:
Using awk:
awk '/malloc/ || /free/{count++;}END{printf "%d",count}' fileundertest
This will search for "malloc" and "free" words in file and will print out the count. if count is even you can say for every malloc there is free.
Using grep:
grep -c "malloc" fileundertest
This will count the malloc word in file
Similarly,
grep -c "free" fileundertest
To list out the line number
grep -n "malloc" fileundertest

Related

Open curly braces should be opened in the same line of if statement, for loops, methods, etc

Suppose i have code snippet like:
if(some condition)
{
some code here;
}
else if (some other condition)
{
some more code;
}
public static some_method(something passed here maybe)
{
some other code;
}
Then it should get formatted to:
if(some condition) {
some code here;
} else if (some other condition) {
some more code;
}
public static some_method(something passed here maybe) {
some other code;
}
This is just example code. I want to run sed script for whole file containing "if statements, for loops, methods, etc." maybe similar or in different formats. So mostly the purpose of the script should be to move these open curly braces one line up. Thanks in advance..
Just repeating the comment you got from Tom Fenech, especially if the requirements get more complicated:
My recommendation would be not to implement this yourself, and to use
an existing prettifier tool for the language you are writing
But still, here’s a possible solution, but I dont know how well it'll do in the real world. RS="\n[[:space:]]*{" splits the input on points where a newline is followed by spaces, tabs etc. before the brace, and then replace that with ' {'. Saving a line and printing it later avoids adding a final { at the end of the output.
awk '
BEGIN { RS="\n[[:space:]]*{"
NR == 1 {
line=$0;
next
}
{
printf "%s", line" {";
line=$0
}
END {
print line
}' _file_with_code_
Alternatively, this can be written up as follows, using more awk features. This does result in a trailing { at the end of the file though, which is removed by the added sed program
awk '
BEGIN {
# break record on `\n{`
RS="\n[[:space:]]*{";
# replace with `{`
ORS=" {"
}
# print for each line
{ print }
' input_file |
sed '
# for last line ($), `substitute` trailing `{` with ``
$ s/{$//
'
#!/bin/bash
# get input filename ...
filename="${1}"
# Do basic checks (etc) ...
if [[ -z "${filename}" ]]
then
echo "[ERR] No file name supplied."
echo "Usage: `basename ${0}` \"the file name\""
exit 1
fi
if [[ ! -f "${filename}" ]]
then
echo "[ERR] No file named \"${filename}\" exists anywhere."
exit 1
fi
# Create "SED crunch script" ...
sedscript="/tmp/sedscript.sed"
cat << EOF > "${sedscript}"
# if "function syntax found, then read in next line
# and print, else just print current line ...
/^.*([^)]*)[ | ]*$/{
N
/^.*([^)]*)[ | ]*\n[ | ]*{.*$/{
# Remove newline from first and appended line ...
s/\n//g
# ... and print what we have to STDOUT ...
p
b skip_default_print
}
# Next line did not start with open curly brace,
# so just print what we currently have and
# skip default print ..
p
b skip_default_print
}
p
:skip_default_print
EOF
# Execute crunch script against code ...
sed -n -f "${sedscript}" "${filename}"
Save above script into a bash script. Then execute it like below:
(example below assumes script is saved as crunch.sh)
./crunch.sh "code.java"
... where "code.java" is the code you wish to "crunch". Result is sent to STDOUT.
Here's input I used:
if(some condition)
{
some code here;
}
else if (some other condition)
{
some more code;
}
public static some_method(something passed here maybe)
{
some other code;
}
And output:
if(some condition){
some code here;
}
else if (some other condition){
some more code;
}
public static some_method(something passed here maybe) {
some other code;
}

passing input value from bash script to a c++ executable

I have a c++ code which requires an input value. I would like to have a bash script to run my c++ executable file automatically. My bash script is below:
#!/bin/bash
g++ freshness.cpp -g -o prob
for((i=0;i<30;i++))
{
./prob<$2 ../../data/new_r.txt ../../data/new_p.txt ../../data /t_$1.txt >> result.txt
}
./cal result.txt
rm result.txt
My main.cpp is below:
int main(int argc,char*argv[])
{
map<int, struct Router> nodes;
cout<<"creating routers..."<<endl;
Create_router(argv[1],nodes);
cout<<"creating topology..."<<endl;
LoadRouting(argv[2],nodes);
cout<<"simulating..."<<endl;
Simulate(argv[3],nodes);
return 0;
}
There is a cin in Create_router(argv[1],nodes), like cin>>r_size;
Many thanks in advance.
./prob < $2
means to redirect the input of the program to a file whose name is in the $2 variable.
If $2 is the actual input data, not a filename, then you should use a here-string:
./prob <<< "$2" ../../data/new_r.txt ../../data/new_p.txt ../../data /t_$1.txt >> result.txt
or a here-doc:
./prob <EOF ../../data/new_r.txt ../../data/new_p.txt ../../data /t_$1.txt >> result.txt
$2
EOF
or pipe the input to the program:
printf "%s\n" "$2" | ./prob ../../data/new_r.txt ../../data/new_p.txt ../../data /t_$1.txt >> result.txt
The here-string method is the simplest, but it's a bash extension. The other methods are portable to all POSIX shells.

How to use a wildcard expression within system()

The following command runs fine on my embedded Linux (Beaglebone Black):
echo bone_pwm_P9_21 > /sys/devices/bone_capemgr.?/slots
But not when using this small C++ program:
#include <stdlib.h>
#include <string>
int main {
system(std::string("echo bone_pwm_P9_21 > /sys/devices/bone_capemgr.?/slots").c_str());
return 0;
}
The problem involves the '?' question mark, that is used as a wildcard.
When the question mark, in the std::string that is passed to system(), is replaced with a normal character, the system() function evaluates the command perfect.
Solutions I've tried without success:
replace ? with \?
replace ? with *
Apart from your code not being compilable, this fails because system(3) runs sh, often a minimal shell provided by dash or busybox.
Meanwhile, your interactive login uses bash, ksh or some other more comfy shell.
dash and busybox sh do not do glob expansion on redirections, while bash and ksh do. Here's a demonstration of the behavior you want courtesy of bash:
$ touch file.txt
$ bash -c 'echo "bash contents" > *.txt'
$ cat file.txt
bash contents
Meanwhile, the problem you're having with e.g. dash:
$ dash -c 'echo "and now dash" > *.txt'
$ ls
*.txt file.txt
$ cat '*.txt' # Instead of expanding, the path was taken literally
and now dash
$ cat file.txt
bash contents
To fix this, you can (in order of preference)
Write your C program in C code instead of shell script
Call a better shell with execve.
Rewrite to not write to a glob, e.g. echo "stuff" | tee *.txt > /dev/null
Call a better shell with system, e.g. bash -c "echo stuff > *.txt"
NOTE: As πάντα ῥεῖ pointed out the system() command calls the shell which will usually do the expansion when presented with the correct wildcard: *. This answer is thereful more appropriate if you want the control to make each system() call separately or if the underlying shell is limited.
Original answer:
Perhaps you could use wordexp for this to construct your strings before you make the system() call:
#include <string>
#include <vector>
#include <iostream>
#include <wordexp.h>
std::vector<std::string> expand_env(const std::string& var, int flags = 0)
{
std::vector<std::string> vars;
wordexp_t p;
if(!wordexp(var.c_str(), &p, flags))
{
if(p.we_wordc)
for(char** exp = p.we_wordv; *exp; ++exp)
vars.push_back(exp[0]);
wordfree(&p);
}
return vars;
}
int main()
{
for(auto&& s: expand_env("$HOME/*")) // <= Note the wildcard '*'
std::cout << s << '\n';
}
In your specific case you could perhaps use something like this:
int main()
{
std::vector<std::string> devices = expand_env("/sys/devices/bone_capemgr.*/slots");
for(std::vector<std::string>::size_type i = 0; i < devices.size(); ++i)
system(("echo bone_pwm_P9_21 > " + devices[i]).c_str());
}

How do I execute a string as a shell script in C++?

I'm writing a program that needs to be able to execute a shell script provided by the user. I've gotten it to execute a single shell command, but the scripts provided will be more complicated than that.
Googling got me as far as the following code snippet:
FILE *pipe;
char str[100];
// The python line here is just an example, this is *not* about executing
// this particular line.
pipe = popen("python -c \"print 5 * 6\" 2>&1", "r");
fgets(str, 100, pipe);
cout << "Output: " << str << endl;
pclose(pipe)
So that this point str has 30 in it. So far so good. But what if the command has carriage returns in it, as a shell script file would, something like the following:
pipe = popen("python -c \"print 5 * 6\"\nbc <<< 5 + 6 2>&1", "r");
With this my goal is that str eventually have 30\n11.
To put another way, assume I have a file with the following contents:
python -c "print 5 * 6"
bc <<< 5 + 6
The argument I'm sending to popen above is the string representation of that file. I want to, from within C++, send that string (or something similar) to bash and have it execute exactly as if I were in the shell and sourced it with . file.sh, but setting the str variable to what I would see in the shell if it were executed there, in this case, 30\n11.
Yes, I could write this to a file and work it that way, but that seems like it should be unnecessary.
I wouldn't think this was a new problem, so either I'm thinking about it in a completely wrong way or there's a library that I simply don't know about that already does this.
use bash -c.
#include <stdio.h>
int main()
{
FILE *pipe = popen("bash -c \"echo asdf\necho 1234\" ", "r");
char ch;
while ((ch = fgetc(pipe)) != EOF)
putchar(ch);
}
Output:
asdf
1234
(I've test on cygwin)

perl script to read content between marks

In the perl , how to read the contents between two marks. Source data like this
START_HEAD
ddd
END_HEAD
START_DATA
eee|234|ebf
qqq| |ff
END_DATA
--Generate at 2011:23:34
then I only want to get data between "START_DATA" and "END_DATA". How to do this ?
sub readFile(){
open(FILE, "<datasource.txt") or die "file is not found";
while(<FILE>){
if(/START_DATA/){
record(\*FILE);#start record;
}
}
}
sub record($){
my $fileHandle = $_[0];
while(<fileHandle>){
print $_."\n";
if(/END_DATA/) return ;
}
}
I write this code, it doesn't work. do you know why ?
Thanks
Thanks
You can use the range operator:
perl -ne 'print if /START_DATA/ .. /END_DATA/'
The output will include the *_DATA lines, too, but it should not be so hard to get rid of them.
Besides a few typos, your code is not too far off. Had you used
use strict;
use warnings;
You might have figured it out yourself. Here's what I found:
Don't use prototypes if you do not need them, or know what they do.
Normal sub declaration is sub my_function (prototype) {, but you can leave out the prototype and just use sub my_function {.
while (<fileHandle>) { is missing the $ sign to denote that it is
a variable (scalar) and not a global. Should be $fileHandle.
print $_."\n"; will add an extra newline. Just print; will do
what you expect.
if(/END_DATA/) return; is a syntax error. Brackets are not optional
in perl in this case. Unless you reverse the statement.
Use either:
return if (/END_DATA/);
or
if (/END_DATA/) { return }
Below is the cleaned up version. I commented out your open() while testing, so this would be a functional code example.
use strict;
use warnings;
readFile();
sub readFile {
#open(FILE, "<datasource.txt") or die "file is not found";
while(<DATA>) {
if(/START_DATA/) {
recordx(\*DATA); #start record;
}
}
}
sub recordx {
my $fileHandle = $_[0];
while(<$fileHandle>) {
print;
if (/END_DATA/) { return }
}
}
__DATA__
START_HEAD
ddd
END_HEAD
START_DATA
eee|234|ebf
qqq| |ff
END_DATA
--Generate at 2011:23:34
This is a pretty simple thing to do with regular expressions, just use the /s or /m (single line or multiple line) flags - /s allows the . operator to match newlines, so you can do /start_data(.+)end_data/is.