Automatically fix filename cases in C++ codebase? - c++

I am porting a C++ codebase which was developed on a Windows platform to Linux/GCC. It seems that the author didn't care for the case of filenames, so he used
#include "somefile.h"
instead of
#include "SomeFile.h"
to include the file which is actually called "SomeFile.h". I was wondering if there is any tool out there to automatically fix these includes? The files are all in one directory, so it would be easy for the tool to find the correct names.

EDIT: Before doing anything note that I'm assuming you either have copies of the files off ot the side or preferably that you have a baseline version in source control should you need to roll back for any reason.
You should be able to do this with sed: Something like sed -i 's/somefile\.h/SomeFile.H/I' *.[Ch]
This means take a case-insensitive somefile (trailing /I) and do an in-place (same file) replacement (-i) with the other text, SomeFile.H.
You can even do it in a loop (totally untested):
for file in *.[Ch]
do
sed -i "s/$file/$file/I" *.[Ch]
done
I should note that although I don't believe this applies to you, Solaris sed doesn't support -i and you'd have to install GNU sed or redirect to a file and rename.

Forgive my, I'm away from my linux environment right now so I can't test this myself, but I can tell you what utilities you would need to use to do it.
Open a terminal and use cd to navigate to the correct directory.
cd ~/project
Get a list of all of the .h files you need. You should be able to accomplish this with the shell's wildcard expansion without any effort.
ls include/*.h libs/include/*.h
Get a list of all of the files in the entire project (.c, .cpp, .h, .whatever), anything that can #include "header.h". Again, wildcard expansion.
ls include/*.h libs/include/*.h *.cpp libs/*.cpp
Iterate over each file in the project with a for loop
for f in ... # wildcard file list
do
echo "Looking in $f"
done
Iterate over each header file with a for loop
for h in ... # wildcard header list
do
echo "Looking for $h"
done
For each header in each project file, use sed to search for #include "headerfilename.h", and replace with #include "HeaderFileName.h" or whatever the correct case is.
Warning: Untested and probably dangerous: This stuff is a place to start and should be thoroughly tested before use.
h_escaped=$(echo $h | sed -e 's/\([[\/.*]\|\]\)/\\&/g') # escapes characters in file name
argument="(^\s*\#include\s*\")$h_escaped(\"\s*\$)" # I think this is right
sed -i -e "s/$argument/\$1$h\$2/gip"`
Yes, I know it looks awful.
Things to consider:
Rather than going straight to running this on your production codebase, test it thoroughly first.
sed can eat files like a VCR can eat tapes.
Make a backup.
Make another backup.
This is an O(N^2) operation involving hard disk access, and if your project is large it will run slowly. If your project is not gigantic, don't bother, but if it is, consider doing something to pipe sed's output to other seds.
Your search should be case insensitive: it should match #include, #INCLUDE, #iNcLuDe, and any combination of case present in the existing header filename, as well as any amount of whitespace between the include and the header. Bonus points if you preserve whitespace.

Use Notepad++ to do a 'Find in Files' and replace.
From toolbar:
Search - Find in Files.
Then complete the 'Find what' and 'Replace with'.

Related

Find and replace pattern in large number of files

I want to replace text in about 80.000 log files using a regex. I love the batch search and replace of VSCode. I was unable to do this with VSCode, because it did not seem to handle this amount of data well. Any suggestion how I could do this with VSCode? Are there suggestions for alternatives?
Instead of depending on a GUI based tool, it might be easier to for a CLI tool for this.
If you're using Linux, or willing to install any of the tools like sed and find if you're on Windows then it should be relatively simple.
You can use sed which is a command line tool on all (or at least most) distributions of Linux, and can be installed on Windows.
Usage (for this use case):
sed -i s/{pattern}/{replacement}/g {file}
Use sed to replace the matched pattern with a replacement, using the global modifier to match all results, and the file to do the replacement and overwrite.
To target all files in a directory you can do:
find -type f -name "*.log" exec sed -i s/{pattern}/{replacement}/g {};
Find items recursively starting from the current directory where it's type is file, and it has a name ending with .log. Then use sed to replace the pattern with the contents you want for each matched file.
You can find how to get tools like sed and find for Windows on the following question:
https://stackoverflow.com/a/127567/6277798

How switch a specific expression to lower case in a file (linux command)

I'm trying to find a command or to create a script on linux allowing to switch a specific expression to lower-case in many files in subdirectories.
I need this to change the case in all the includes statements in a C++ project (Porting Visual studio project to linux)
So in many files I have
#include <Path1/pAth2/naMeofTheHeader.h>
and i would like to change it to
#include <Path1/pAth2/nameoftheheader.h>
(Of course I don't want the path to be moved in lower case)
Does anyone have an idea to perform this? I tried somme sed command (with \L) but anything have worked.
Thanks
You could try the below sed command,
sed 's~\(#include .*\/\)\([^\/.]*\)~\1\L\2~g' file
Example:
$ echo '#include <Path1/pAth2/naMeofTheHeader.h>' | sed 's~\(#include .*\/\)\([^\/.]*\)~\1\L\2~g'
#include <Path1/pAth2/nameoftheheader.h>

emacs drill down shortcut

I am new to emacs. In Netbeans, you can right click on any object and it will send you directly to the header or implementation file. Is there a shortcut key to do this in emacs?
You have to create a TAGS file first.
If you're on linux:
$ ctags -e -R *.h *.cpp
// this will create tags for all .h and .cpp files,
// starting from the current directory, and recursing into subdirectories.
// -e : emacs tags (as oposed to vi tags, the default)
// -R : recursive
You can also add to an existing tags file by using the --append flag. For example:
$ ctags --append -e -R *.h *.cpp /home/user/jdoe/thirdparty
// This will add to the TAGS file in the current directory
When you want to jump to a symbol definition, in emacs use M-x find-tag, or M-.. It'll ask you where the TAGS file is, and you're set. To pop out, use M-x pop-tag-mark, by default mapped to M-*.
Note: ctags is alright, but since it's not a compiler, sometimes it'll take you to the wrong place.
You can use etags to provide a similar functionality. Once your TAGS file is created, you can use the M-. shortcut that invokes (find-tag).
As with everything: Emacs gives you several ways to do something, in this case a bunch of them don't work out of the box. You can either use etags or if you need a really big hammer semantic, which is part of the cedet project. This will give you much more then simply jumping into a header file, but maybe that is what you need.

Loading files that meet certain criteria into hidden buffers in vim

I'd like to do some code refactoring in vim. I have found the following gem to apply transformations to all buffers.
:dobuf %s/match/replace/gc
My code is layed out with the root directory having a directory for the dependencies and a build directory. I want to load all .cc , .h and .proto files from ./src ./include and ./tests. But not from the dependencies and build directories, into background/hidden buffers. I want to do this to do the refactor using the command above.
If someone knows of a cleaner way to perform the use case, please show it.
Note: I know you can string together find and sed to do this from the shell, however I prefer doing it in vim , if at all possible. The /gc prefix in the pattern I presented above serves the role of confirming replacements on each match, I need this functionality as often I don't want to replace certain matches, the find and sedsolution is too restrictive and finicky when attempting my use-case, it is also easy to destroy files when doing in-place replacements.
For reference using sed and find:
List candidate replacements:
find src include tests -name *.h -or -name *.cc -or -name *.proto|
xargs sed -n 's/ListServices/list_services/p'
Perform replacements:
`find src include tests -name *.h -or -name *.cc -or -name *.proto|
xargs sed -i 's/ListServices/list_services`'
You can use :argadd to add the files you need to vim's argument list. This will load them as inactive buffers (you can see them afterwards with an :ls. In your case, it might look like this:
argadd src/**/*.cc
argadd src/**/*.h
argadd src/**/*.proto
And so on, for the include and tests directories. You might want to make a command for that or experiment with glob patterns to make it a bit simpler. Afterwards, your command should work, although I'd recommend running it with :argdo instead:
argdo %s/match/replace/gc
This will only execute it for the buffers you explicitly specified, not for any of the other ones you might have opened at the time. Check :help argadd and :help argdo for more information.

Help with automated renaming in C++

Here is my issue:
I have a large library of code where all of the class names begin with Agui. For example:
class AguiWidget
{
};
class AguiBitmap
{
};
also, all the hpp and cpp files are named like this also:
AguiWidget.hpp
etc.
The library also does not use a namespace.
all of the enums begin and use Agui:
ex:
enum AguiKeyEnum
{
AGUI_KEY_SPACE,
AGUI_KEY_ENTER
};
The include guards also use ex:
AGUI_WIDGET_HPP
So,
My task is to remove all the Agui, AGUI references from the entire project (all the classes and enums), then to encapsulate all the classes into namespace agui.
What would be the easiest way to do this. I also need the hpp and cpp files to no longer have Agui in the filename.
I use MSVC 2008 as an IDE if that helps.
Thanks!
You need to use a global find and replace tool. If you have Visual Studio 2008, then it is already built-in. Once you rename all the classes and namespaces, then use another tool to rename the files or build a script to do it for you.
As a Linux user (which you aren't, but you could use Cygwin or a separate machine), I'd use the program sed to strip the prefixes. I'd start with this, then review the diffs vs. source control:
sed -i 's/Agui//g; s/AGUI_//g' *.hpp *.cpp # and maybe *.sln *.proj
Then, renaming the files:
for f in *.hpp *.cpp; do mv $f ${f#Agui}; done # or source control's mv
Then all that's left is to add namespacing. You could probably get this done using sed as well, but if the number of files is not huge I'd just do it by hand. The namespace closing braces are trivial to add though:
for f in *.hpp *.cpp; do (echo '} // namespace agui' >> $f); done
The opening braces you might want to take a little more care to add, depending on your existing code's structure.
Oh, and look, sed for Windows: http://gnuwin32.sourceforge.net/packages/sed.htm (I haven't used this).
I would suggest either using
cygwin + recursive find + script - use sed for changing names, mv to change files
or figuring how to do the equivalent in powershell.
With the right regular expressions it should work fine.
Make sure to copy the entire directory structure before editing, as it may take a few iterations to debug.