winprefs v0.3.2
A registry exporter for programmers.
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
2#ifdef ENABLE_VLD
3#include <vld.h>
4#endif
5
6#include "arg.h"
7#include "constants.h"
8#include "git.h"
9#include "io.h"
10#include "reg_code.h"
11#include "reg_command.h"
12#include "registry.h"
13
14static inline void print_leaks() {
15#ifndef ENABLE_VLD
16 if (debug_print_enabled) {
17 _CrtDumpMemoryLeaks();
18 }
19#endif
20}
21
23
27static inline HKEY get_top_key(wchar_t *reg_path) {
28 if (!_wcsnicmp(reg_path, L"HKCU", 4) || !_wcsnicmp(reg_path, L"HKEY_CURRENT_USER", 17)) {
29 return HKEY_CURRENT_USER;
30 }
31 if (!_wcsnicmp(reg_path, L"HKCR", 4) || !_wcsnicmp(reg_path, L"HKEY_CLASSES_ROOT", 17)) {
32 return HKEY_CLASSES_ROOT;
33 }
34 if (!_wcsnicmp(reg_path, L"HKLM", 4) || !_wcsnicmp(reg_path, L"HKEY_LOCAL_MACHINE", 18)) {
35 return HKEY_LOCAL_MACHINE;
36 }
37 if (!_wcsnicmp(reg_path, L"HKCC", 4) || !_wcsnicmp(reg_path, L"HKEY_CURRENT_CONFIG", 19)) {
38 return HKEY_CURRENT_CONFIG;
39 }
40 if (!_wcsnicmp(reg_path, L"HKU", 3) || !_wcsnicmp(reg_path, L"HKEY_USERS", 10)) {
41 return HKEY_USERS;
42 }
43 if (!_wcsnicmp(reg_path, L"HKDD", 4) || !_wcsnicmp(reg_path, L"HKEY_DYN_DATA", 13)) {
44 return HKEY_DYN_DATA;
45 }
46 return nullptr;
47}
48
50int wmain(int argc, wchar_t *argv[]) {
51 (void)argc;
52 int ret = EXIT_SUCCESS;
53 HKEY starting_key = HKEY_CURRENT_USER;
54 bool commit = false;
55 bool debug = false;
56 int max_depth = 20;
57 char *as_char = nullptr;
58 wchar_t *argv0 = argv[0];
59 wchar_t *deploy_key = nullptr;
60 wchar_t *format = nullptr;
61 wchar_t *output_dir = nullptr;
62 wchar_t *output_file = nullptr;
63 bool output_dir_specified = false;
64 ARG_BEGIN {
65 if (ARG_LONG("deploy-key"))
66 case 'K': {
67 deploy_key = ARG_VAL();
68 }
69 else if (ARG_LONG("commit")) case 'c': {
70 commit = true;
71 ARG_FLAG();
72 }
73 else if (ARG_LONG("debug")) case 'd': {
74 debug = true;
75 ARG_FLAG();
76 }
77 else if (ARG_LONG("output-file")) case 'f': {
78 output_file = ARG_VAL();
79 }
80 else if (ARG_LONG("output-dir")) case 'o': {
81 output_dir = ARG_VAL();
82 output_dir_specified = true;
83 }
84 else if (ARG_LONG("format")) case 'F': {
85 format = ARG_VAL();
86 }
87 else if (ARG_LONG("max-depth")) case 'm': {
88 wchar_t *val = ARG_VAL();
89 size_t w_len = wcslen(val);
90 as_char = malloc(w_len + 1);
91 if (!as_char) { // LCOV_EXCL_START
92 fprintf(stderr, "Memory error.\n");
93 goto fail;
94 } // LCOV_EXCL_STOP
95 memset(as_char, 0, w_len + 1);
96 wcstombs(as_char, val, w_len);
97 max_depth = atoi(as_char);
98 }
99 else if (ARG_LONG("help")) case 'h':
100 case '?': {
101 PathStripPath(argv0);
102 wprintf(L"Usage: %ls [OPTION...] [REG_PATH]\n", argv0);
103 wprintf(L"\nIf a path to a value name is specified, the output directory argument is "
104 L"ignored and the line is printed to\nstandard output.\n\n");
105 puts("Options:");
106 puts(" -F, --format=FORMAT Format to output. Options: c, cs, c#, ps, ps1, "
107 "powershell, reg. Default: reg.");
108 puts(" -K, --deploy-key Deploy key for committing.");
109 puts(" -c, --commit Commit changes.");
110 puts(" -d, --debug Enable debug logging.");
111 puts(" -f, --output-file Output filename.");
112 puts(" -m, --max-depth=INT Set maximum depth.");
113 puts(" -o, --output-dir Output directory.");
114 puts(" -h, --help Display this help and exit.");
115 return EXIT_SUCCESS;
116 }
117 else {
118 default:
119 fwprintf(stderr,
120 L"%ls: invalid option '%ls'\n"
121 L"Try '%s --help' for more information.\n",
122 argv0,
123 *argv,
124 argv0);
125 goto fail;
126 }
127 }
128 ARG_END;
129 wchar_t *reg_path = *argv;
130 enum OUTPUT_FORMAT output_format_e =
131 (!format || !_wcsicmp(L"reg", format)) ? OUTPUT_FORMAT_REG :
132 (!_wcsicmp(L"c#", format) || !_wcsicmp(L"cs", format) || !_wcsicmp(L"csharp", format)) ?
133 OUTPUT_FORMAT_C_SHARP :
134 (!_wcsicmp(L"powershell", format) || !_wcsicmp(L"ps", format) ||
135 !_wcsicmp(L"ps1", format)) ?
136 OUTPUT_FORMAT_POWERSHELL :
137 (format[0] == L'c' || format[0] == L'C') ? OUTPUT_FORMAT_C :
138 OUTPUT_FORMAT_UNKNOWN;
139 if (output_format_e == OUTPUT_FORMAT_UNKNOWN) {
140 fwprintf(stderr, L"Unknown format specified: %ls\n", format);
141 goto fail;
142 }
143 if (reg_path) {
144 size_t len = wcslen(reg_path);
145 bool top_key_only =
146 (reg_path[len - 1] == L'\\' && reg_path[len - 2] == L':') || reg_path[len - 1] == L':';
147 if (reg_path[len - 1] == L'\\' && reg_path[len - 2] == L':') {
148 reg_path[len - 2] = L'\0';
149 } else if (reg_path[len - 1] == L':') {
150 reg_path[len - 1] = L'\0';
151 }
152 HKEY top_key = get_top_key(reg_path);
153 if (!top_key) {
154 fwprintf(stderr, L"Invalid top-level key in '%ls'.\n", reg_path);
155 goto fail;
156 }
157 if (!top_key_only) {
158 wchar_t *subkey = wcschr(reg_path, L'\\') + 1;
159 if (RegOpenKeyEx(top_key, subkey, 0, KEY_READ, &starting_key) != ERROR_SUCCESS) {
160 // See if it's a full path to value
161 ret = export_single_value(top_key, reg_path, output_format_e, nullptr) ?
162 EXIT_SUCCESS :
163 EXIT_FAILURE;
164 goto cleanup;
165 }
166 }
167 }
168 if (!output_dir) {
169 output_dir = calloc(MAX_PATH, WL);
170 if (!output_dir) { // LCOV_EXCL_START
171 fprintf(stderr, "Failed to allocate memory.\n");
172 return EXIT_FAILURE;
173 } // LCOV_EXCL_STOP
174 wmemset(output_dir, L'\0', MAX_PATH);
175 if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, output_dir))) {
176 PathAppend(output_dir, L"prefs-export");
177 }
178 output_dir[MAX_PATH - 1] = L'\0';
179 }
180 debug_print_enabled = debug;
181 bool success = save_preferences(
182 commit,
183 deploy_key,
184 output_dir,
185 output_file ? output_file :
186 (output_format_e == OUTPUT_FORMAT_C ? L"exec-reg.c" :
187 output_format_e == OUTPUT_FORMAT_POWERSHELL ? L"exec-reg.ps1" :
188 output_format_e == OUTPUT_FORMAT_C_SHARP ? L"exec-reg.cs" :
189 L"exec-reg.bat"),
190 max_depth,
191 starting_key,
192 reg_path,
193 output_format_e,
194 nullptr);
195 if (!success) {
196 fwprintf(stderr, L"Error occurred. Possibilities:\n");
197 DWORD last_win_error = GetLastError();
198 wchar_t p_message_buf[8192];
199 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
200 nullptr,
201 last_win_error,
202 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
203 (LPTSTR)&p_message_buf,
204 8192,
205 nullptr);
206 fprintf(stderr, "POSIX (%d): %s\n", errno, strerror(errno));
207 fwprintf(stderr, L"Windows (%lu): %ls", last_win_error, p_message_buf);
208 goto fail;
209 }
210 goto cleanup;
211fail:
212 ret = EXIT_FAILURE;
213cleanup:
214 free(as_char);
215 if (!output_dir_specified) {
216 free(output_dir);
217 }
218 print_leaks();
219 return ret;
220}
static HKEY get_top_key(wchar_t *reg_path)
Gets the HKEY pointer for the first part of a registry path.
Definition main.c:27
int wmain(int argc, wchar_t *argv[])
Entry point.
Definition main.c:50