mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-05-10 02:09:46 +08:00
feat(导入导出): 支持同时导出和导入系统与用户PATH变量
- 重构导出功能,将系统变量和用户变量合并到单个JSON文件中 - 重构导入功能,支持解析包含系统变量和用户变量的JSON文件 - 在导入时提供选项让用户选择导入目标(系统变量、用户变量或全部) - 更新UI交互逻辑,适配新的导入导出数据结构 - 改进JSON文件格式,包含版本信息和导出时间戳
This commit is contained in:
@@ -5,10 +5,15 @@
|
|||||||
|
|
||||||
#define EXPORT_VERSION "1.0"
|
#define EXPORT_VERSION "1.0"
|
||||||
|
|
||||||
// 导出 PATH 到文件
|
typedef struct {
|
||||||
int export_paths_to_file(const StringList *list, const char *filepath, int is_system);
|
StringList system;
|
||||||
|
StringList user;
|
||||||
|
} ExportData;
|
||||||
|
|
||||||
// 从文件导入 PATH
|
// 导出 PATH 到文件
|
||||||
int import_paths_from_file(const char *filepath, StringList *list);
|
int export_paths_to_file(const ExportData *data, const char *filepath);
|
||||||
|
|
||||||
|
// 从文件导入 PATH (返回是否包含全部格式)
|
||||||
|
int import_paths_from_file(const char *filepath, ExportData *data);
|
||||||
|
|
||||||
#endif // IMPORT_EXPORT_H
|
#endif // IMPORT_EXPORT_H
|
||||||
+73
-18
@@ -386,18 +386,61 @@ int btn_import_cb(Ihandle *self)
|
|||||||
char *filepath = IupGetAttribute(filedlg, "VALUE");
|
char *filepath = IupGetAttribute(filedlg, "VALUE");
|
||||||
if (filepath)
|
if (filepath)
|
||||||
{
|
{
|
||||||
Ihandle *tabs_main = IupGetDialogChild(dlg, "TABS_MAIN");
|
ExportData imported;
|
||||||
int pos = IupGetInt(tabs_main, "VALUEPOS");
|
if (import_paths_from_file(filepath, &imported) == 0)
|
||||||
|
|
||||||
StringList *target_list = (pos == 0) ? &ctx->sys_paths : &ctx->user_paths;
|
|
||||||
|
|
||||||
if (import_paths_from_file(filepath, target_list) == 0)
|
|
||||||
{
|
{
|
||||||
Ihandle *current_list = get_current_list(dlg);
|
int has_system = imported.system.count > 0;
|
||||||
sync_string_list_to_ui(current_list, target_list);
|
int has_user = imported.user.count > 0;
|
||||||
|
|
||||||
|
if (!has_system && !has_user)
|
||||||
|
{
|
||||||
|
IupMessage("错误", "文件中没有找到有效的路径!");
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int choice = 0;
|
||||||
|
if (has_system && has_user)
|
||||||
|
{
|
||||||
|
choice = IupAlarm("导入选项", "请选择导入目标:",
|
||||||
|
"仅系统变量", "仅用户变量", "全部导入");
|
||||||
|
}
|
||||||
|
else if (has_system)
|
||||||
|
{
|
||||||
|
choice = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
choice = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int total_imported = 0;
|
||||||
|
|
||||||
|
if (choice == 1 || choice == 3)
|
||||||
|
{
|
||||||
|
clear_string_list(&ctx->sys_paths);
|
||||||
|
for (int i = 0; i < imported.system.count; i++)
|
||||||
|
{
|
||||||
|
add_string_list(&ctx->sys_paths, imported.system.items[i]);
|
||||||
|
}
|
||||||
|
Ihandle *list_sys = IupGetDialogChild(dlg, "LIST_SYS");
|
||||||
|
sync_string_list_to_ui(list_sys, &ctx->sys_paths);
|
||||||
|
total_imported += imported.system.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice == 2 || choice == 3)
|
||||||
|
{
|
||||||
|
clear_string_list(&ctx->user_paths);
|
||||||
|
for (int i = 0; i < imported.user.count; i++)
|
||||||
|
{
|
||||||
|
add_string_list(&ctx->user_paths, imported.user.items[i]);
|
||||||
|
}
|
||||||
|
Ihandle *list_user = IupGetDialogChild(dlg, "LIST_USER");
|
||||||
|
sync_string_list_to_ui(list_user, &ctx->user_paths);
|
||||||
|
total_imported += imported.user.count;
|
||||||
|
}
|
||||||
|
|
||||||
char msg[256];
|
char msg[256];
|
||||||
snprintf(msg, sizeof(msg), "成功导入 %d 个路径!", target_list->count);
|
snprintf(msg, sizeof(msg), "成功导入 %d 个路径!", total_imported);
|
||||||
IupMessage("导入成功", msg);
|
IupMessage("导入成功", msg);
|
||||||
|
|
||||||
Ihandle *lbl_status = IupGetDialogChild(dlg, "LBL_STATUS");
|
Ihandle *lbl_status = IupGetDialogChild(dlg, "LBL_STATUS");
|
||||||
@@ -422,11 +465,9 @@ int btn_export_cb(Ihandle *self)
|
|||||||
if (!ctx)
|
if (!ctx)
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
|
|
||||||
Ihandle *tabs_main = IupGetDialogChild(dlg, "TABS_MAIN");
|
ExportData data;
|
||||||
int pos = IupGetInt(tabs_main, "VALUEPOS");
|
data.system = ctx->sys_paths;
|
||||||
|
data.user = ctx->user_paths;
|
||||||
StringList *source_list = (pos == 0) ? &ctx->sys_paths : &ctx->user_paths;
|
|
||||||
int is_system = (pos == 0);
|
|
||||||
|
|
||||||
Ihandle *filedlg = IupFileDlg();
|
Ihandle *filedlg = IupFileDlg();
|
||||||
IupSetAttribute(filedlg, "DIALOGTYPE", "SAVE");
|
IupSetAttribute(filedlg, "DIALOGTYPE", "SAVE");
|
||||||
@@ -436,7 +477,7 @@ int btn_export_cb(Ihandle *self)
|
|||||||
IupSetAttribute(filedlg, "DEFAULTEXT", "json");
|
IupSetAttribute(filedlg, "DEFAULTEXT", "json");
|
||||||
|
|
||||||
char default_name[64];
|
char default_name[64];
|
||||||
snprintf(default_name, sizeof(default_name), "path_%s.json", is_system ? "system" : "user");
|
snprintf(default_name, sizeof(default_name), "path_all.json");
|
||||||
IupSetAttribute(filedlg, "VALUE", default_name);
|
IupSetAttribute(filedlg, "VALUE", default_name);
|
||||||
|
|
||||||
IupPopup(filedlg, IUP_CENTER, IUP_CENTER);
|
IupPopup(filedlg, IUP_CENTER, IUP_CENTER);
|
||||||
@@ -446,10 +487,23 @@ int btn_export_cb(Ihandle *self)
|
|||||||
char *filepath = IupGetAttribute(filedlg, "VALUE");
|
char *filepath = IupGetAttribute(filedlg, "VALUE");
|
||||||
if (filepath)
|
if (filepath)
|
||||||
{
|
{
|
||||||
if (export_paths_to_file(source_list, filepath, is_system) == 0)
|
char final_path[MAX_PATH];
|
||||||
|
if (strchr(filepath, '.') == NULL)
|
||||||
{
|
{
|
||||||
char msg[256];
|
snprintf(final_path, sizeof(final_path), "%s.json", filepath);
|
||||||
snprintf(msg, sizeof(msg), "成功导出 %d 个路径到:\n%s", source_list->count, filepath);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(final_path, filepath, sizeof(final_path) - 1);
|
||||||
|
final_path[sizeof(final_path) - 1] = '\0';
|
||||||
|
}
|
||||||
|
filepath = final_path;
|
||||||
|
|
||||||
|
if (export_paths_to_file(&data, filepath) == 0)
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
snprintf(msg, sizeof(msg), "成功导出!\n系统变量: %d 个\n用户变量: %d 个\n\n保存位置: %s",
|
||||||
|
data.system.count, data.user.count, filepath);
|
||||||
IupMessage("导出成功", msg);
|
IupMessage("导出成功", msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -509,5 +563,6 @@ int btn_help_cb(Ihandle *self)
|
|||||||
"邮箱:3364451258@qq.com\n"
|
"邮箱:3364451258@qq.com\n"
|
||||||
"GitHub:https://github.com/LHY0125/PathEditor\n"
|
"GitHub:https://github.com/LHY0125/PathEditor\n"
|
||||||
"记得给我的项目点个star!");
|
"记得给我的项目点个star!");
|
||||||
|
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
+155
-100
@@ -58,39 +58,56 @@ static char *escape_json_string(const char *str)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出 PATH 到 JSON 文件
|
// 导出路径数据到 JSON 文件
|
||||||
int export_paths_to_file(const StringList *list, const char *filepath, int is_system)
|
int export_paths_to_file(const ExportData *data, const char *filepath)
|
||||||
{
|
{
|
||||||
if (!list || !filepath)
|
if (!data || !filepath)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
FILE *fp = fopen(filepath, "w, ccs=UTF-8");
|
FILE *fp = fopen(filepath, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
fprintf(fp, "\xEF\xBB\xBF");
|
||||||
|
|
||||||
char datetime[64];
|
char datetime[64];
|
||||||
get_current_datetime(datetime, sizeof(datetime));
|
get_current_datetime(datetime, sizeof(datetime));
|
||||||
|
|
||||||
fprintf(fp, "{\n");
|
fprintf(fp, "{\n");
|
||||||
fprintf(fp, " \"version\": \"%s\",\n", EXPORT_VERSION);
|
fprintf(fp, " \"version\": \"%s\",\n", EXPORT_VERSION);
|
||||||
fprintf(fp, " \"type\": \"%s\",\n", is_system ? "SYSTEM" : "USER");
|
fprintf(fp, " \"type\": \"ALL\",\n");
|
||||||
fprintf(fp, " \"exported\": \"%s\",\n", datetime);
|
fprintf(fp, " \"exported\": \"%s\",\n", datetime);
|
||||||
fprintf(fp, " \"paths\": [\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < list->count; i++)
|
fprintf(fp, " \"system\": [\n");
|
||||||
|
for (int i = 0; i < data->system.count; i++)
|
||||||
{
|
{
|
||||||
if (list->items[i])
|
if (data->system.items[i])
|
||||||
{
|
{
|
||||||
char *escaped = escape_json_string(list->items[i]);
|
char *escaped = escape_json_string(data->system.items[i]);
|
||||||
if (escaped)
|
if (escaped)
|
||||||
{
|
{
|
||||||
fprintf(fp, " \"%s\"%s\n", escaped, (i < list->count - 1) ? "," : "");
|
fprintf(fp, " \"%s\"%s\n", escaped, (i < data->system.count - 1) ? "," : "");
|
||||||
free(escaped);
|
free(escaped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fprintf(fp, " ],\n");
|
||||||
|
|
||||||
|
fprintf(fp, " \"user\": [\n");
|
||||||
|
for (int i = 0; i < data->user.count; i++)
|
||||||
|
{
|
||||||
|
if (data->user.items[i])
|
||||||
|
{
|
||||||
|
char *escaped = escape_json_string(data->user.items[i]);
|
||||||
|
if (escaped)
|
||||||
|
{
|
||||||
|
fprintf(fp, " \"%s\"%s\n", escaped, (i < data->user.count - 1) ? "," : "");
|
||||||
|
free(escaped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fprintf(fp, " ]\n");
|
fprintf(fp, " ]\n");
|
||||||
|
|
||||||
fprintf(fp, "}\n");
|
fprintf(fp, "}\n");
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -112,7 +129,7 @@ static void trim_whitespace(char *str)
|
|||||||
memmove(str, start, strlen(start) + 1);
|
memmove(str, start, strlen(start) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为注释行或空行
|
// 检查字符串是否为注释行或空行
|
||||||
static int is_comment_or_empty(const char *line)
|
static int is_comment_or_empty(const char *line)
|
||||||
{
|
{
|
||||||
while (*line == ' ' || *line == '\t')
|
while (*line == ' ' || *line == '\t')
|
||||||
@@ -124,118 +141,156 @@ static int is_comment_or_empty(const char *line)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为 JSON 文件
|
// 检查文件是否为 JSON 格式
|
||||||
static int is_json_file(const char *filepath)
|
static int is_json_file(const char *filepath)
|
||||||
{
|
{
|
||||||
const char *ext = strrchr(filepath, '.');
|
const char *ext = strrchr(filepath, '.');
|
||||||
return ext && strcasecmp(ext, ".json") == 0;
|
return ext && strcasecmp(ext, ".json") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从文件导入 PATH
|
// 从文件导入 PATH (返回是否包含全部格式)
|
||||||
int import_paths_from_file(const char *filepath, StringList *list)
|
int import_paths_from_file(const char *filepath, ExportData *data)
|
||||||
{
|
{
|
||||||
if (!filepath || !list)
|
if (!filepath || !data)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (is_json_file(filepath))
|
init_string_list(&data->system);
|
||||||
|
init_string_list(&data->user);
|
||||||
|
|
||||||
|
if (!is_json_file(filepath))
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(filepath, "r, ccs=UTF-8");
|
FILE *fp = fopen(filepath, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
clear_string_list(list);
|
StringList list;
|
||||||
|
init_string_list(&list);
|
||||||
char buffer[8192];
|
|
||||||
int in_paths = 0;
|
|
||||||
int depth = 0;
|
|
||||||
int in_string = 0;
|
|
||||||
char path_buffer[4096];
|
|
||||||
int path_len = 0;
|
|
||||||
|
|
||||||
while (fgets(buffer, sizeof(buffer), fp))
|
|
||||||
{
|
|
||||||
char *p = buffer;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
if (*p == '"' && (p == buffer || *(p - 1) != '\\'))
|
|
||||||
{
|
|
||||||
in_string = !in_string;
|
|
||||||
}
|
|
||||||
else if (in_string && *p == '\\')
|
|
||||||
{
|
|
||||||
p++;
|
|
||||||
if (*p)
|
|
||||||
{
|
|
||||||
if (*p == 'n')
|
|
||||||
*p = '\n';
|
|
||||||
else if (*p == 'r')
|
|
||||||
*p = '\r';
|
|
||||||
else if (*p == 't')
|
|
||||||
*p = '\t';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!in_string)
|
|
||||||
{
|
|
||||||
if (*p == '{' || *p == '[')
|
|
||||||
depth++;
|
|
||||||
else if (*p == '}' || *p == ']')
|
|
||||||
depth--;
|
|
||||||
else if (*p == ':')
|
|
||||||
in_paths = (depth == 1);
|
|
||||||
else if (in_paths && depth == 2 && *p == '"')
|
|
||||||
{
|
|
||||||
path_len = 0;
|
|
||||||
p++;
|
|
||||||
while (*p && path_len < (int)sizeof(path_buffer) - 1)
|
|
||||||
{
|
|
||||||
if (*p == '"' && *(p - 1) != '\\')
|
|
||||||
break;
|
|
||||||
if (*p == '\\' && *(p + 1))
|
|
||||||
{
|
|
||||||
p++;
|
|
||||||
if (*p == 'n')
|
|
||||||
*p = '\n';
|
|
||||||
else if (*p == 'r')
|
|
||||||
*p = '\r';
|
|
||||||
else if (*p == 't')
|
|
||||||
*p = '\t';
|
|
||||||
}
|
|
||||||
path_buffer[path_len++] = *p++;
|
|
||||||
}
|
|
||||||
if (path_len > 0)
|
|
||||||
{
|
|
||||||
path_buffer[path_len] = '\0';
|
|
||||||
add_string_list(list, path_buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FILE *fp = fopen(filepath, "r, ccs=UTF-8");
|
|
||||||
if (!fp)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
clear_string_list(list);
|
|
||||||
|
|
||||||
char line[4096];
|
char line[4096];
|
||||||
while (fgets(line, sizeof(line), fp))
|
while (fgets(line, sizeof(line), fp))
|
||||||
{
|
{
|
||||||
trim_whitespace(line);
|
trim_whitespace(line);
|
||||||
|
|
||||||
if (is_comment_or_empty(line))
|
if (is_comment_or_empty(line))
|
||||||
continue;
|
continue;
|
||||||
|
add_string_list(&list, line);
|
||||||
add_string_list(list, line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
data->system = list;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *fp = fopen(filepath, "rb");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char buffer[8192];
|
||||||
|
int in_system = 0;
|
||||||
|
int in_user = 0;
|
||||||
|
int depth = 0;
|
||||||
|
int in_string = 0;
|
||||||
|
char path_buffer[4096];
|
||||||
|
int path_len = 0;
|
||||||
|
|
||||||
|
while (fgets(buffer, sizeof(buffer), fp))
|
||||||
|
{
|
||||||
|
char *p = buffer;
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
if (*p == '"' && (p == buffer || *(p - 1) != '\\'))
|
||||||
|
{
|
||||||
|
in_string = !in_string;
|
||||||
|
}
|
||||||
|
else if (in_string && *p == '\\')
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
if (*p == 'n')
|
||||||
|
*p = '\n';
|
||||||
|
else if (*p == 'r')
|
||||||
|
*p = '\r';
|
||||||
|
else if (*p == 't')
|
||||||
|
*p = '\t';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!in_string)
|
||||||
|
{
|
||||||
|
if (*p == '{' || *p == '[')
|
||||||
|
depth++;
|
||||||
|
else if (*p == '}' || *p == ']')
|
||||||
|
depth--;
|
||||||
|
else if (depth == 1 && *p == '"')
|
||||||
|
{
|
||||||
|
if (strncmp(p, "\"system\"", 8) == 0)
|
||||||
|
{
|
||||||
|
in_system = 1;
|
||||||
|
in_user = 0;
|
||||||
|
}
|
||||||
|
else if (strncmp(p, "\"user\"", 6) == 0)
|
||||||
|
{
|
||||||
|
in_user = 1;
|
||||||
|
in_system = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (in_system && depth == 2 && *p == '"')
|
||||||
|
{
|
||||||
|
path_len = 0;
|
||||||
|
p++;
|
||||||
|
while (*p && path_len < (int)sizeof(path_buffer) - 1)
|
||||||
|
{
|
||||||
|
if (*p == '"' && *(p - 1) != '\\')
|
||||||
|
break;
|
||||||
|
if (*p == '\\' && *(p + 1))
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
if (*p == 'n')
|
||||||
|
*p = '\n';
|
||||||
|
else if (*p == 'r')
|
||||||
|
*p = '\r';
|
||||||
|
else if (*p == 't')
|
||||||
|
*p = '\t';
|
||||||
|
}
|
||||||
|
path_buffer[path_len++] = *p++;
|
||||||
|
}
|
||||||
|
if (path_len > 0)
|
||||||
|
{
|
||||||
|
path_buffer[path_len] = '\0';
|
||||||
|
add_string_list(&data->system, path_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (in_user && depth == 2 && *p == '"')
|
||||||
|
{
|
||||||
|
path_len = 0;
|
||||||
|
p++;
|
||||||
|
while (*p && path_len < (int)sizeof(path_buffer) - 1)
|
||||||
|
{
|
||||||
|
if (*p == '"' && *(p - 1) != '\\')
|
||||||
|
break;
|
||||||
|
if (*p == '\\' && *(p + 1))
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
if (*p == 'n')
|
||||||
|
*p = '\n';
|
||||||
|
else if (*p == 'r')
|
||||||
|
*p = '\r';
|
||||||
|
else if (*p == 't')
|
||||||
|
*p = '\t';
|
||||||
|
}
|
||||||
|
path_buffer[path_len++] = *p++;
|
||||||
|
}
|
||||||
|
if (path_len > 0)
|
||||||
|
{
|
||||||
|
path_buffer[path_len] = '\0';
|
||||||
|
add_string_list(&data->user, path_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user