user1684072
user1684072

Reputation: 169

Edit a line with sed

I have input that contains structures that are defined with a typedef. I later use these to initialize variables in my main function.

For example:

typedef struct {
   int numer;
   int denom;
} Rational;

int main()
{
Rational half, *newf = malloc(sizeof(Rational));

half = (Rational){ 1, 2 };
*newf = (Rational){ 2, 3 };
}

Here is what I want to do: I want to convert the two initialization lines into function calls.

For example:

half = (Rational){ 1, 2 };

should turn into:

init_Rational( &half,  1, 2  );

and

*newf = (Rational){ 2, 3 };

should turn into

init_Rational( newf,  2, 3  );

The trick is to remember that Rational was defined as a struct earlier and replace the initializations with function calls. It doesn't have to be called Rational, it could be any name.

Once it recognizes that the declaration is a struct typedef, it should do the following as shown above.

Turn:

something = (someStructName){ data1, data2, data3.. };

into

init_someStructName( &something, data1, data2, data3.. );

Or for pointers...Turn:

*something = (someStructName){ data1, data2, data3.. };

into

init_someStructName( something, data1, data2, data3.. );

Can someone help me out here? Thanks!

Upvotes: 1

Views: 82

Answers (2)

Giuseppe Guerrini
Giuseppe Guerrini

Reputation: 4426

Almost unreadable!

sed -e 's/\(\**[a-zA-Z_][a-zA-Z_0-9]*\) *= *( *\([a-zA-Z_][a-zA-Z_0-9]*\) *) *{\([^}]*\)} *;/init_\2(\&\1,\3);/'

Note: it's a single line Note2: I have assumed that there may be only spaces as possible separators (no TAB) Note3: The form "*x" is left unchanged, since it's transformed into &*x, that it's correct. I have assumed that there aren't spaces between "*" and the identifier;

Upvotes: 0

Andrew Clark
Andrew Clark

Reputation: 208475

This is a pretty tricky problem, because needing to dynamically detect struct names means you can't write the entire regular expression in advance.

Here is one potential solution, assuming your file name is foo.c:

sed -n '/^typedef struct/,/^}/{/^}/{s/.* \(.*\);/\1/p}}' foo.c | xargs -I {} sed -i -e 's/^\(\s*\)\*\(\w*\) = ('{}'){\(.*\)};/\1init_'{}'( \2,\3);/' -e 's/^\(\s*\)\(\w*\) = ('{}'){\(.*\)};/\1init_'{}'( \&\2,\3);/' foo.c

This does one pass with sed to print out each struct name on a line by itself, and then uses xargs to construct an additional sed command for each struct to perform the replacements on the file in place.

If your version of sed doesn't support the \s or \w shortcuts, you can use [ \t] instead of \s and [_a-zA-Z0-9] instead of \w.

Upvotes: 1

Related Questions