Search code examples
regexsed

sed need something like a backreference for append


I have a whole bunch of C++ source files within which I wish to insert a trivial function definition (around 6 lines). The definition should appear immediately after another function definition.

Using the accepted answer to this question: sed match multiple lines and then append, I can insert the trivial function definition, but I am unable to scope it as a member of the appropriate class.

Test code:

void object::func1()
{
    std::cout << "func1" << std::endl;
}

Insertion of non-member function:

james@scrapyard:~/Projects$ sed  '/func1()$/,/^}/!b;/^}/a \\nint func2()\n{\n\ \ \ \ return 0;\n}' func1.cc 
void object::func1()
{
    std::cout << "func1" << std::endl;
}

int 1::func2()
{
    return 0;
}

Attempting to group the class name and use a back reference as below results in 1::func2 rather than object::func2.

sed '/\([[:alnum:]]\+\)::func1()$/,/^}/!b;/^}/a \\nint \1::func2()\n{\n\ \ \ \ return 0;\n}' testcode.cc

If I were using the substitute command instead of the append command it would work, but the substitute command is broken by the /,/ resulting in:

sed: -e expression #1, char 33: unknown option tos'`

Is it possible in sed?


Solution

  • A backreference may only refer to a capture within the same expression. The semicolon after !b ends the first expression. The hold space can carry a string from one expression to another.

    sed '/\w\+::func1()$/,/^}/!b;/\w\+::func1()$/{h;s/^\w*\s\+\(\w\+\)::func1()$/\1/;x};/^}/ {g;s/.*/}\n\nint &::func2()\n{\n\ \ \ \ return 0;\n}/}' testcode.cc

    Sed reads a line at a time into the pattern space, where commands like s/// operate. Lines can be set aside in the hold space and retrieved back into the pattern space later.

    sed '
      /\w\+::func1()$/,/^}/!b   # Ignore lines outside the target function.
      /\w\+::func1()$/ {        # On the line declaring the function,
        h                       # save that line to the hold space;
        s/^\w*\s\+\(\w\+\)::func1()$/\1/  # replace the function with its class name;
        x                       # save the class name and restore the function declaration.
      }
      /^}/ {                    # at the end of the target function
        g                       # retrieve the class name
        # substitue the class name into the new function
        s/.*/}\n\nint &::func2()\n{\n\ \ \ \ return 0;\n}/
      }
    ' testcode.cc