c++写的一个小型数据库,支持增删改查,功能是将一些长句子简化为缩写,然后通过缩写来检索并复制到剪切板
有时候我们需要将一个长的句子用一个简短的缩写记住他,比如一些常用的命令。下面的代码实现了一个map表去查询缩写对应的原文,并将原文复制到剪切板方便使用。
使用方法:
1、将以下代码在VS上编译,取出exe文件
2、将该exe文件所在目录加到环境变量里,假如该exe名为ctc.exe
3、打开cmd,设置数据文件保存路径,注意这里要全名
ctc -s "E:\ProgramEnvironment\UsefulExe\CTC\config\CtcDatabase.txt"
4、添加一条缩写记录(当然我们也可以指直接修改数据文件,添加一行就行,行格式为 缩写名 + 空格 + 原文)
ctc -a lty "when I was young I listen to the radio"
5、查询缩写原文,运行完该语句后原文"when I was young I listen to the radio"就被写入到了剪切板,我们就可以直接使用ctl-v来使用原文了
ctc --lty
6、支持value是多行的形式,格式如下,其中两个***之间的多行为value
key ***
...
...
...
***
编译方法:找到自己vs配置编译环境的脚本vcvarsall.bat(鄙人的是在C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build目录下),双击运行即可打开一个用于cl编译的命令行环境。在该环境下进入到代码所在目录,然后执行如下命令编译:
cl.exe ctc.cpp /link User32.lib advapi32.lib /Fe: ctc.exe
#include <iostream>
#include <vector>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LINE 1024
#pragma warning(disable:4996)
std::string STORE_FILE;
void SetClipLTY(const std::string& str)
{
char* clipBoardData = (char*)malloc(str.length() + 1);
if (clipBoardData == NULL) {
printf("malloc failed!\n");
return;
}
strcpy(clipBoardData, str.c_str());
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_TEXT, (HANDLE)clipBoardData);
CloseClipboard();
free(clipBoardData);
}
void Usage() {
printf("Usage:\n");
printf("prog -o/-a/-m/-d/--key\n");
printf("-s: set the database file path\n");
printf("-o: copy string to the clipboard\n");
printf("-a: add a key-value map\n");
printf("-m: modify the value of key\n");
printf("-d: delete the key-value map\n");
printf("-h: show all the keys in database\n");
printf("--key: copy the value of this key to the clipboard\n");
}
// 获取第一个空白子串的起始和末尾位置,以及最后一个字符(即\n)前的空白子串的起始位置(如果不存在,则指向最后一个字符)
// 约束:str以\n结尾
void GetFirstAndLastSpaceSubStr(char *str, char* &headBegin, char* &headEnd, char* &tailBegin)
{
for (char *p = str; *p != '\n'; p++) {
if (isspace(*p)) {
headBegin = headEnd = p;
while (*(headEnd + 1) != '\n' && isspace(*(headEnd + 1))) {
headEnd++;
}
break;
}
}
tailBegin = str + strlen(str) - 1;
while (tailBegin - 1 >= str && isspace(*(tailBegin - 1))) {
tailBegin--;
}
}
std::string QueryMap(char* key)
{
if (*key == '\0') {
return "";
}
FILE* fp = fopen(STORE_FILE.c_str(), "r");
if (fp == NULL) {
printf("open file %s failed!!!\n", STORE_FILE.c_str());
return "";
}
char Line[MAX_LINE] = { 0 };
while (fgets(Line, MAX_LINE, fp) != NULL) {
if (isspace(*Line)) { // 跳过开头是空白符的行
continue;
}
char *headFirstSpace = NULL;
char *headLastSpace = NULL;
char *tailFirstSpace = NULL;
GetFirstAndLastSpaceSubStr(Line, headFirstSpace, headLastSpace, tailFirstSpace);
if (headFirstSpace != NULL && headFirstSpace != tailFirstSpace) { // 只处理形如"key xxx"的行
*headFirstSpace = 0;
bool isMatchKey = strcmp(Line, key) == 0;
std::string result;
/*考虑key ***的表示value是多行*/
char *multiLineBeginSign = strstr(headLastSpace + 1, "***");
if (multiLineBeginSign == headLastSpace + 1 && multiLineBeginSign + 3 == tailFirstSpace) {
/* 读取***之后的行,直到下一个***出现 */
while(fgets(Line, MAX_LINE, fp) != NULL && strcmp(Line, "***\n") != 0) {
if (isMatchKey) result += std::string(Line);
}
} else {
if (isMatchKey) {
char *valueStart = headLastSpace + 1;
valueStart[strlen(valueStart) - 1] = 0;// 将末尾的\n去掉
result = std::string(valueStart);
}
}
if (isMatchKey) {
fclose(fp);
return result;
}
}
}
fclose(fp);
return "";
}
void AddMap(char* key, char* value)
{
if (!QueryMap(key).empty()) {
printf("the key already exists, please use -m to modify\n");
return;
}
FILE* fp = fopen(STORE_FILE.c_str(), "a");
if (fp == NULL) {
printf("open file %s failed!!!\n", STORE_FILE.c_str());
return;
}
fprintf(fp, "%s %s\n", key, value);
fclose(fp);
}
void ModifyMap(char* key, char* value)
{
if (QueryMap(key).empty()) {
AddMap(key, value);
return;
}
FILE* src = fopen(STORE_FILE.c_str(), "r");
if (src == NULL) {
printf("open file %s failed!!!\n", STORE_FILE.c_str());
return;
}
FILE* dst = fopen((STORE_FILE + ".tmp").c_str(), "w");
if (dst == NULL) {
printf("open file %s failed!!!\n", (STORE_FILE + ".tmp").c_str());
fclose(src);
return;
}
char Line[MAX_LINE];
while (fgets(Line, MAX_LINE, src)) {
char* firstPos = strstr(Line, " ");
if (firstPos != NULL) {
*firstPos = '\0';
if (strcmp(Line, key) == 0) {
fprintf(dst, "%s %s\n", key, value);
}
else {
*firstPos = ' ';
fprintf(dst, "%s", Line);
}
}
}
fclose(src);
fclose(dst);
remove(STORE_FILE.c_str());
rename((STORE_FILE + ".tmp").c_str(), STORE_FILE.c_str());
}
void DelMap(char* key)
{
if (QueryMap(key).empty()) {
return;
}
FILE* src = fopen(STORE_FILE.c_str(), "r");
if (src == NULL) {
printf("open file %s failed!!!\n", STORE_FILE.c_str());
return;
}
FILE* dst = fopen((STORE_FILE + ".tmp").c_str(), "w");
if (dst == NULL) {
printf("open file %s failed!!!\n", (STORE_FILE + ".tmp").c_str());
return;
}
char Line[MAX_LINE];
while (fgets(Line, MAX_LINE, src)) {
char* firstPos = strstr(Line, " ");
if (firstPos != NULL) {
*firstPos = '\0';
if (strcmp(Line, key) != 0) {
*firstPos = ' ';
fprintf(dst, "%s", Line);
}
}
}
fclose(src);
fclose(dst);
remove(STORE_FILE.c_str());
rename((STORE_FILE + ".tmp").c_str(), STORE_FILE.c_str());
}
void ShowMapKeys()
{
FILE* fp = fopen(STORE_FILE.c_str(), "r");
if (fp == NULL) {
printf("open file %s failed!!!\n", STORE_FILE.c_str());
return;
}
char Line[MAX_LINE] = { 0 };
while (fgets(Line, MAX_LINE, fp) != NULL) {
if (isspace(*Line)) { // 跳过开头是空白符的行
continue;
}
char *headFirstSpace = NULL;
char *headLastSpace = NULL;
char *tailFirstSpace = NULL;
GetFirstAndLastSpaceSubStr(Line, headFirstSpace, headLastSpace, tailFirstSpace);
if (headFirstSpace != NULL && headFirstSpace != tailFirstSpace) { // 只处理形如"key xxx"的行
*headFirstSpace = 0;
printf("%s\n", Line);
/*考虑key ***的表示value是多行*/
char *multiLineBeginSign = strstr(headLastSpace + 1, "***");
if (multiLineBeginSign == headLastSpace + 1 && multiLineBeginSign + 3 == tailFirstSpace) {
/* 读取***之后的行,直到下一个***出现 */
while(fgets(Line, MAX_LINE, fp) != NULL && strcmp(Line, "***\n") != 0) {}
}
}
}
fclose(fp);
}
#define SUB_KEY "Software\\Wow6432Node\\CTC"
#define VALUE_NAME "CtcDataBaseFilePath"
bool WriteRegistryString(HKEY hKeyRoot, const std::string& subKey, const std::string& valueName, const std::string& value) {
HKEY hKey;
// 打开或创建注册表键
if (ERROR_SUCCESS != RegCreateKeyExA(hKeyRoot, subKey.c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))
{
return false;
}
// 写入 REG_SZ 值
int result = RegSetValueExA(hKey, valueName.c_str(), 0, REG_SZ, (BYTE*)value.c_str(), value.length() + 1); // +1 包含 null 终止符
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
bool ReadRegistryString(HKEY hKeyRoot, const std::string& subKey, const std::string& valueName, std::string& outValue) {
HKEY hKey;
// 打开注册表键
if (ERROR_SUCCESS != RegOpenKeyExA(hKeyRoot, subKey.c_str(), 0, KEY_READ, &hKey)) {
return false;
}
// 获取值大小
DWORD dataSize = 0;
long result = RegQueryValueExA(hKey, valueName.c_str(), nullptr, nullptr, nullptr, &dataSize);
if (result != ERROR_SUCCESS || dataSize == 0) {
RegCloseKey(hKey);
return false;
}
// 读取值数据
std::vector<char> buffer(dataSize);
result = RegQueryValueExA(hKey, valueName.c_str(), nullptr, nullptr, (LPBYTE)(buffer.data()), &dataSize);
RegCloseKey(hKey);
if (result == ERROR_SUCCESS) {
outValue = buffer.data();
return true;
}
return false;
}
bool SetDataBaseFilePath(std::string dataBasePath) {
return WriteRegistryString(HKEY_CURRENT_USER, SUB_KEY, VALUE_NAME, dataBasePath);
}
std::string GetDataBaseFilePath() {
std::string dataBaseFilePath;
ReadRegistryString(HKEY_CURRENT_USER, SUB_KEY, VALUE_NAME, dataBaseFilePath);
return dataBaseFilePath;
}
std::string FindDir(std::string path) {
int findPos = 0;
if ((findPos = path.find_last_not_of('\\')) != std::string::npos) {
return path.substr(0, findPos);
}
return "";
}
bool DirectoryExists(std::string dirPath) {
DWORD attribs = GetFileAttributesA(dirPath.c_str());
if (attribs == INVALID_FILE_ATTRIBUTES) {
return false; // 路径无效或不存在
}
return (attribs & FILE_ATTRIBUTE_DIRECTORY); // 检查是否是目录属性
}
bool CreateAllDir(std::string dir)
{
if (dir == "") {
printf("dir is empty!\n");
return false;
}
for (int i = 0; i < dir.length(); i++) {
if (dir[i] == '\\') {
std::string curDir = dir.substr(0, i);
// 尝试创建目录
if (!DirectoryExists(curDir)) {
if (!CreateDirectoryA(curDir.c_str(), NULL) && (GetLastError() != ERROR_ALREADY_EXISTS)) {
return false; // 创建成功
}
}
}
}
return true;
}
int main(int argc, char** argv)
{
if (argc < 2 || argv[1][0] != '-') {
Usage();
return 1;
}
if (argv[1][1] == 's' && argv[1][2] == '\0' && argc == 3) {
SetDataBaseFilePath(argv[2]);
STORE_FILE = argv[2];
} else {
STORE_FILE = GetDataBaseFilePath();
}
if (STORE_FILE.empty()) {
printf("can not get store file path\n");
return 2;
}
if (!CreateAllDir(STORE_FILE)) {
printf("can not create dir for data base file\n");
return 3;
}
if (argv[1][1] == 'o' && argv[1][2] == '\0' && argc == 3) {
SetClipLTY(argv[2]);
}
if (argv[1][1] == 'a' && argv[1][2] == '\0' && argc > 3) {
AddMap(argv[2], argv[3]);
}
if (argv[1][1] == 'm' && argv[1][2] == '\0' && argc > 3) {
ModifyMap(argv[2], argv[3]);
}
if (argv[1][1] == 'd' && argv[1][2] == '\0' && argc > 2) {
DelMap(argv[2]);
}
if (argv[1][1] == 'h' && argv[1][2] == '\0') {
ShowMapKeys();
}
if (argv[1][1] == '-') {
std::string tmp = QueryMap(&argv[1][2]);
if (!tmp.empty()) {
printf("%s\nsuccess copy to clipboard\n", tmp.c_str());
SetClipLTY(tmp);
}
}
return 0;
}

浙公网安备 33010602011771号