This repository has been archived on 2020-05-03. You can view files and clone it, but cannot push or open issues or pull requests.
rren/dist-archive/rren.cpp

239 lines
5.7 KiB
C++

// rren
#define RREN_VERSION L"1.1"
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <windows.h>
#else
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif
#include <stdio.h>
#include <wchar.h>
#include <string>
#include <vector>
#include <regex>
using namespace std;
struct twostr {
wstring first;
wstring second;
};
enum RREN_MODES {
RREN_MODE_NONE,
RREN_MODE_REGEX,
RREN_MODE_REPLACE,
RREN_MODE_PCASE
};
#define BUFF 255
typedef vector<twostr> V2STR;
V2STR vFiles;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define PRINT_ARGS wprintf( \
L"rren v" RREN_VERSION L"\n" \
L"Usage: rren mode filemask <args>\n" \
L" -e ECMA Regex rren -e filemask \"find\" \"replace\"\n" \
L" -r Find/Replace rren -r filemask \"find\" \"replace\"\n" \
L" -p Proper case rren -p filemask\n")
#define PRINT_INVALID_ARGS \
wprintf(L"Invalid number of arguments.\n\n"); \
PRINT_ARGS;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Applies a find/replace ECMAScript regex over all twostr::first in vFiles
bool do_regex(wchar_t* wcFind, wchar_t* wcReplace) {
// Initialise variables
tr1::wregex rFind;
wstring sReplace = wcReplace;
try {rFind.assign(wcFind);} catch (...) {
wprintf(L"Invalid search regex.\n");
return false;
}
// Loop over vFiles
for (V2STR::iterator vi = vFiles.begin(); vi != vFiles.end(); vi++) {
vi->second = tr1::regex_replace(vi->first, rFind, sReplace);
}
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Applies a find/replace string search over all twostr::first in vFiles
bool do_replace(wchar_t* wcFind, wchar_t* wcReplace) {
// Initialise variables
if (std::wstring(wcReplace).find(wcFind) != wstring::npos) {
wprintf(L"Recursive find/replace.\n");
return false;
}
size_t pos = wstring::npos;
size_t flen = wcslen(wcFind);
// Loop over vFiles
for (V2STR::iterator vi = vFiles.begin(); vi != vFiles.end(); vi++) {
vi->second.assign(vi->first);
for(;;) {
pos = vi->second.find(wcFind);
if (pos == wstring::npos) break;
vi->second.replace(pos, flen, wcReplace);
}
}
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Returns the proper-case version of a wstring
wstring proper_case(wstring wsInputString) {
wstring wBuff(wsInputString);
size_t pos = wstring::npos;
// All lowercase
for (;;) {
if (++pos > wBuff.size()) break;
wBuff[pos] = towlower(wBuff[pos]);
}
// First character becomes uppercase
if (wBuff.size() > 0) wBuff[0] = towupper(wBuff[0]);
// Everything following a space becomes uppercase
pos = 0;
for (;;) {
pos = wBuff.find(L" ", pos+1);
if (pos == wstring::npos) break;
if (wBuff.size() >= (pos+1)) {
wBuff[pos+1] = towupper(wBuff[pos+1]);
} else break;
}
return wBuff;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Modifies the case of all twostr::first in vFiles
bool do_pcase() {
for (V2STR::iterator vi = vFiles.begin(); vi != vFiles.end(); vi++) {
vi->second = proper_case(vi->first);
}
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Program entry point
int wmain(int argc, wchar_t* argv[]) {
// Variables
WIN32_FIND_DATA wfd;
HANDLE hFind = 0;
wchar_t wCwd[BUFF] = {0};
wstring sSearch;
twostr tsNext;
int iMode = RREN_MODE_NONE;
// Validate command-line arguments
if (argc < 3) {
PRINT_ARGS; return EXIT_FAILURE;
} else if (_wcsnicmp(argv[1], L"-e", 2)==0) {
if (argc != 5) {
PRINT_INVALID_ARGS; return EXIT_FAILURE;
} else iMode = RREN_MODE_REGEX;
} else if (_wcsnicmp(argv[1], L"-r", 2)==0) {
if (argc != 5) {
PRINT_INVALID_ARGS; return EXIT_FAILURE;
} else iMode = RREN_MODE_REPLACE;
} else if (_wcsnicmp(argv[1], L"-p", 2)==0) {
if (argc != 3) {
PRINT_INVALID_ARGS; return EXIT_FAILURE;
} else iMode = RREN_MODE_PCASE;
} else {
wprintf(L"Invalid mode.\n");
PRINT_ARGS;
return EXIT_FAILURE;
}
// Create search mask from working directory
GetCurrentDirectory(BUFF-1, wCwd);
if (!wcslen(wCwd)) return EXIT_FAILURE;
sSearch.assign(wCwd);
sSearch.append(L"\\");
sSearch.append(argv[2]);
// Get all file matches
hFind = FindFirstFileW(sSearch.c_str(), &wfd);
if (!hFind) {
wprintf(L"No files.\n");
return EXIT_FAILURE;
}
vFiles.clear();
tsNext.first.clear();
tsNext.second.clear();
do {
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
tsNext.first.assign(wfd.cFileName);
vFiles.push_back(tsNext);
}
} while (FindNextFile(hFind, &wfd));
if (vFiles.empty()) {
wprintf(L"No files.\n");
return EXIT_FAILURE;
}
// Apply transform based on argument
switch (iMode) {
case RREN_MODE_REGEX:
if (!do_regex(argv[3], argv[4])) return EXIT_FAILURE;
break;
case RREN_MODE_REPLACE:
if (!do_replace(argv[3], argv[4])) return EXIT_FAILURE;
break;
case RREN_MODE_PCASE:
if (!do_pcase()) return EXIT_FAILURE;
break;
default:
wprintf(L"Invalid mode.\n");
PRINT_ARGS; return EXIT_FAILURE;
}
// Display all results
for (V2STR::iterator vi = vFiles.begin(); vi != vFiles.end(); vi++) {
wprintf(L"%s\n--> %s\n", vi->first.c_str(), vi->second.c_str());
}
// Prompt for apply
wprintf(L"\nApply changes? (y/n) ");
wint_t gwc = getwchar();
if (gwc == 'Y' || gwc == 'y') {
wprintf(L"Applying changes... ");
int count = vFiles.size(), done = 0;
for (V2STR::iterator vi = vFiles.begin(); vi != vFiles.end(); vi++) {
if (MoveFile(vi->first.c_str(), vi->second.c_str()) == TRUE) done++;
}
wprintf(L"done (%d / %d).\n", done, count);
} else {
wprintf(L"No changes were made.\n");
}
// Clean up
return EXIT_SUCCESS;
}