10
2009
Often the unix commands basename and dirname are useful in shell scripts, but how do you use these in c or c++?.
The C way: libgen.h
If you’re working in c, the posix header libgen.h provides dirname and basename functions, with some limitations: They only work with char *, and dirname will modify the char * you pass into it so you need to make a copy of your original path if you wish to keep it. Example code:
// libgen_example.c // Demonstrate libgen.h usage and pitfalls // Compile: gcc -g -o libgen_example libgen_example.c #include <libgen.h> //basename and dirname #include <string.h> //strlen and strcpy #include <stdio.h> //printf #include <stdlib.h> //malloc int main(int argc, char* argv[]) { // Demonstrate how dirname changes the path you input to it char path[] = "default/path/to/nowhere.txt"; printf("path='%s'\n", path); char * dir = dirname(path); printf("path='%s' dir='%s'\n", path, dir); char * base = basename(path); printf("path='%s' dir='%s' base='%s'\n\n", path, dir, base); // Since dirname changed path, base is now "to" // instead of "nowhere.txt" as we might have expected. // Output: // path='default/path/to/nowhere.txt' // path='default/path/to' dir='default/path/to' // path='default/path/to' dir='default/path/to' base='to' //======== // Demonstrate c string copying const char * another_path = "another/path"; char * modifiable_copy = (char *)malloc(strlen(another_path) + 1); strcpy(modifiable_copy, another_path); char * another_dir = dirname(modifiable_copy); printf("another_path='%s'\n", another_path); printf("modifiable_copy='%s'\n", modifiable_copy); printf("another_dir='%s'\n\n", another_dir); // note that after this free, another_dir is now also // invalid since it pointed to the modifiable_copy's memory free(modifiable_copy); // Output: // another_path='another/path' // modifiable_copy='another' // another_dir='another' //======== // const strings declared as char * can cause segfaults char * char_pointer_path = "char/pointer/path"; printf("char_pointer_path='%s'\n", char_pointer_path); char * char_pointer_dir = dirname(char_pointer_path); printf("char_pointer_path='%s' char_pointer_dir='%s'\n", char_pointer_path, char_pointer_dir); // Output: // char_pointer_path='char/pointer/path' // Segmentation fault }
The C++ way: boost::filesystem
If you’re looking for a better c++ solution, see the c++ boost filesystem library. boost::filesystem::path.parent_path() can be used like dirname and boost::filesystem::path.filename() acts like basename.
The boost::filesystem library also has many other useful functions for dealing with files and paths (e.g. fs::complete(path) for obtaining an absolute path, fs::exists(path) will check if the path exists, fs::create_directories(path), fs::remove(path), fs::copy_file(from,to) name a few). Note that some of these are functions are boost::filesystem::path methods and some are in boost::filesystem. According to the faq, operations done by the operating system are provided in boost::filesystem functions, but functions just performed on the lexical path (just path string manipulations) are provided as boost::filesystem::path methods.
// filesystem_example.cpp // Demonstrate using boost::filesystem // Compile: g++ -I /usr/local/include/boost-1_38/ -L /usr/local/lib -lboost_filesystem-gcc41-mt-1_38 -o filesystem_example filesystem_example.cpp #include <boost/filesystem.hpp> #include <iostream> namespace fs = boost::filesystem; int main(int argc, char* argv[]) { fs::path pathname("default/path/to/nowhere.txt"); std::string dirname = pathname.parent_path().string(); std::string basename = pathname.filename(); std::cout << "pathname = " << pathname << std::endl; std::cout << "dirname = " << dirname << std::endl; std::cout << "basename = " << basename << std::endl; // Output: // pathname = default/path/to/nowhere.txt // dirname = default/path/to // basename = nowhere.txt std::cout << std::endl; std::cout << "extension = " << pathname.extension() << std::endl; std::cout << "complete = " << fs::complete(pathname) << std::endl; std::cout << "exists = " << ((fs::exists(pathname)) ? "true" : "false") << std::endl; // Output: // extension = .txt // complete = /home/moose/default/path/to/nowhere.txt // exists = false }





