1 /*
2 * HT Editor
3 * main.cc
4 *
5 * Copyright (C) 1999-2002 Stefan Weyergraf
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "analy_register.h"
26 #include "asm.h"
27 #include "htapp.h"
28 #include "atom.h"
29 #include "htcfg.h"
30 #include "htclipboard.h"
31 #include "display.h"
32 #include "except.h"
33 #include "htformat.h"
34 #include "hthist.h"
35 #include "htiobox.h"
36 #include "keyb.h"
37 #include "htidle.h"
38 #include "htmenu.h"
39 #include "htpal.h"
40 #include "htinfo.h"
41 #include "htreg.h"
42 #include "sys.h"
43 #include "snprintf.h"
44 #include "info/infoview.h"
45 #include "log.h"
46 #include "stddata.h"
47
48 const char *htcopyrights[]=
49 {
50 ht_name " " ht_version " (%s) " __TIME__ " on " __DATE__,
51 ht_copyright1,
52 ht_copyright2,
53 NULL
54 };
55
add_file_history_entry(char * n)56 static void add_file_history_entry(char *n)
57 {
58 List *hist=(List*)getAtomValue(HISTATOM_FILE);
59 if (hist) insert_history_entry(hist, n, 0);
60 }
61
62 typedef bool (*initfunc)();
63 typedef void (*donefunc)();
64
65 struct initdonefunc {
66 initfunc i;
67 donefunc d;
68 const char *name;
69 };
70
71 #define INITDONE(name) { init_##name, done_##name, #name }
72
73 initdonefunc initdone[] = {
74 INITDONE(system),
75 INITDONE(atom),
76 INITDONE(data),
77 INITDONE(pal),
78 INITDONE(registry),
79 INITDONE(keyb),
80 INITDONE(idle),
81 INITDONE(menu),
82 INITDONE(hist),
83 INITDONE(clipboard),
84 INITDONE(obj),
85 INITDONE(analyser),
86 INITDONE(asm),
87 INITDONE(stddata),
88 INITDONE(cfg),
89 INITDONE(format),
90 INITDONE(app)
91 };
92
93 int htstate;
94
init()95 static bool init()
96 {
97 for (htstate=0; htstate<(int)(sizeof initdone / sizeof initdone[0]); htstate++) {
98 if (!initdone[htstate].i()) return false;
99 }
100 return true;
101 }
102
done()103 static void done()
104 {
105 for (htstate--; htstate>=0; htstate--) {
106 initdone[htstate].d();
107 }
108 }
109
load_file(char * fn,uint mode)110 static void load_file(char *fn, uint mode)
111 {
112 char cfn[HT_NAME_MAX];
113 char cwd[HT_NAME_MAX];
114
115 cwd[0] = 0;
116 getcwd(cwd, sizeof cwd);
117
118 if (sys_common_canonicalize(cfn, sizeof cfn, fn, cwd, sys_is_path_delim)==0) {
119 add_file_history_entry(cfn);
120 try {
121 ((ht_app*)app)->create_window_file(cfn, mode, true);
122 } catch (const IOException &e) {
123 LOG_EX(LOG_ERROR, "error loading file %s: %y", cfn, &e);
124 }
125 }
126 }
127
show_help()128 static void show_help()
129 {
130 ((ht_app*)app)->create_window_help(MAGIC_HT_HELP, "Top");
131 }
132
show_version()133 static void show_version()
134 {
135 const char **copyrights = htcopyrights;
136 while (*copyrights) {
137 printf(*copyrights, sys_get_name());
138 puts("");
139 copyrights++;
140 }
141 exit(0);
142 }
143
params(int argc,char * argv[],bool started)144 static void params(int argc, char *argv[], bool started)
145 {
146 int escaped_params_start = 0;
147 // FIXME: FOM_AUTO should be the default
148 int load_mode = FOM_BIN;
149 bool showhelp = false;
150
151 #define PARAM_ERROR(a...) {if (started) LOG_EX(LOG_ERROR, a);}
152 #define EXPECT_PARAMEND(b) if ((j+1)!=len) { PARAM_ERROR("syntax error in options"); b;}
153 #define EXPECT_PARAMS(p, b) if (i+p+1 > argc) { PARAM_ERROR("syntax error in options"); b;}
154 #define NOTHING ((void)(0))
155 for (int i = 1; i < argc; i++) {
156 if (argv[i][0] == '-') {
157 int len = strlen(argv[i]);
158 if (len==1) PARAM_ERROR("unknown option: %s", argv[i]);
159 if (argv[i][1] == '-') {
160 if (len == 2) {
161 // --
162 escaped_params_start = i+1;
163 break;
164 }
165 if (strcmp(argv[i], "--auto") == 0) {
166 EXPECT_PARAMS(1, NOTHING) else {
167 if (started) load_file(argv[i+1], FOM_AUTO);
168 i++;
169 }
170 } else
171 if (strcmp(argv[i], "--bin") == 0) {
172 EXPECT_PARAMS(1, NOTHING) else {
173 if (started) load_file(argv[i+1], FOM_BIN);
174 i++;
175 }
176 } else
177 if (strcmp(argv[i], "--help") == 0) {
178 showhelp = true;
179 } else
180 if (strcmp(argv[i], "--project") == 0) {
181 EXPECT_PARAMS(1, NOTHING) else {
182 if (started) ((ht_app*)app)->project_opencreate(argv[i+1]);
183 i++;
184 }
185 } else
186 if (strcmp(argv[i], "--text") == 0) {
187 EXPECT_PARAMS(1, NOTHING) else {
188 if (started) load_file(argv[i+1], FOM_TEXT);
189 i++;
190 }
191 } else
192 if (strcmp(argv[i], "--version") == 0) {
193 show_version();
194 } else
195 if (strcmp(argv[i], "--cfg-shared") == 0) {
196 ht_cfg_use_homedir = false;
197 } else
198 {
199 PARAM_ERROR("unknown option: %s", argv[i]);
200 }
201 } else {
202 for (int j=1; j<len; j++) {
203 switch (argv[i][j]) {
204 case 'A':
205 load_mode = FOM_AUTO;
206 break;
207 case 'B':
208 load_mode = FOM_BIN;
209 break;
210 case 'T':
211 load_mode = FOM_TEXT;
212 break;
213 case 'a':
214 EXPECT_PARAMEND(break);
215 EXPECT_PARAMS(1, break);
216 if (started) load_file(argv[i+1], FOM_AUTO);
217 i++;
218 break;
219 case 'b':
220 EXPECT_PARAMEND(break);
221 EXPECT_PARAMS(1, break);
222 if (started) load_file(argv[i+1], FOM_BIN);
223 i++;
224 break;
225 case 'h':
226 showhelp = true;
227 break;
228 case 'p':
229 EXPECT_PARAMEND(break);
230 EXPECT_PARAMS(1, break);
231 if (started) ((ht_app*)app)->project_opencreate(argv[i+1]);
232 i++;
233 break;
234 case 't':
235 EXPECT_PARAMEND(break);
236 EXPECT_PARAMS(1, break);
237 if (started) load_file(argv[i+1], FOM_TEXT);
238 i++;
239 break;
240 case 'v':
241 show_version();
242 break;
243 default:
244 PARAM_ERROR("unknown option: -%c", argv[i][j]);
245 break;
246 }
247 }
248 }
249 } else {
250 if (started) {
251 load_file(argv[i], load_mode);
252 }
253 }
254 }
255 if (escaped_params_start && started) {
256 char **s = &argv[escaped_params_start];
257 while (*s) {
258 load_file(*s, load_mode);
259 s++;
260 }
261 }
262 if (showhelp && started) show_help();
263 }
264
265 #if defined(WIN32) || defined(__WIN32__)
266 #define LEAN_AND_MEAN
267 #include <windows.h>
268 #endif
269
270
main(int argc,char * argv[])271 int main(int argc, char *argv[])
272 {
273 #if defined(WIN32) || defined(__WIN32__)
274 HMODULE h = GetModuleHandle(NULL);
275 GetModuleFileName(h, appname, sizeof appname-1);
276 #else
277 ht_strlcpy(appname, argv[0], sizeof appname);
278 #endif
279
280 params(argc, argv, false);
281
282 if (!init()) {
283 int init_failed = htstate;
284 done();
285 printf("init(): fatal error in init_%s\n", initdone[init_failed].name);
286 return 1;
287 }
288
289 ((ht_app*)app)->sendmsg(msg_draw);
290
291 const char **copyrights = htcopyrights;
292 while (*copyrights) {
293 LOG(*copyrights, sys_get_name());
294 copyrights++;
295 }
296 LOG("appname = %s", appname);
297 LOG("config = %s", systemconfig_file);
298
299 int systemconfig_version = 0; // -1 for older and 1 for newer file found
300 int systemconfig_magic = 0; // !=0 meens wrong magic found
301
302 loadstore_result load;
303 int error_info;
304 if (!load_systemconfig(&load, &error_info)) {
305 switch (load) {
306 case LS_OK:
307 break;
308 case LS_ERROR_NOT_FOUND:
309 LOG_EX(LOG_WARN, "no configuration file found, using defaults");
310 LOG_EX(LOG_WARN, "note that %s has no mouse support. Use the keyboard!", ht_name);
311 break;
312 case LS_ERROR_READ:
313 LOG_EX(LOG_ERROR, "couldn't read configuration file...");
314 infobox("couldn't read configuration file...");
315 break;
316 case LS_ERROR_MAGIC:
317 case LS_ERROR_FORMAT:
318 LOG_EX(LOG_ERROR, "%s %s %s...", "current configuration file (" SYSTEM_CONFIG_FILE_NAME ") has", "invalid", "magic");
319 systemconfig_magic = true;
320 break;
321 case LS_ERROR_VERSION:
322 LOG_EX(LOG_ERROR, "%s %s %s...", "current configuration file (" SYSTEM_CONFIG_FILE_NAME ") has", "wrong", "version");
323 if (error_info < ht_systemconfig_fileversion) {
324 systemconfig_version = -1;
325 } else {
326 systemconfig_version = 1;
327 }
328 break;
329 case LS_ERROR_CORRUPTED:
330 // done();
331 delete screen;
332 printf("\n\n\nfatal error loading configuration file (%s)", systemconfig_file);
333 if (error_info) {
334 printf(":\nerror near line %d\n", error_info);
335 } else {
336 printf(".\n");
337 }
338 printf("please try to delete it.\n");
339 return 1;
340 default: {assert(0);}
341 }
342 }
343
344 try {
345 params(argc, argv, true);
346 ht_app *a = ((ht_app*)app);
347 a->run(false);
348 } catch (const Exception &x) {
349 done();
350 ht_fprintf(stderr, "\n\nFATAL: %s: %y\n", "unhandled exception", &x);
351 return 1;
352 } catch (...) {
353 done();
354 fprintf(stderr, "\n\nFATAL: unknown %s!?\n", "unhandled exception");
355 return 1;
356 }
357
358 loadstore_result save = LS_OK;
359 bool save_config = true;
360
361 if (systemconfig_magic) {
362 if (confirmbox_modal("%s %s %s...\noverwrite it?", "current configuration file (" SYSTEM_CONFIG_FILE_NAME ") has", "wrong", "magic")!=button_ok) {
363 save_config = false;
364 }
365 }
366
367 if (systemconfig_version < 0) {
368 if (confirmbox_modal("%s %s %s...\noverwrite it?", "current configuration file (" SYSTEM_CONFIG_FILE_NAME ") has", "older", "version")!=button_ok) {
369 save_config = false;
370 }
371 } else if (systemconfig_version > 0) {
372 if (confirmbox_modal("%s %s %s...\noverwrite it?", "current configuration file (" SYSTEM_CONFIG_FILE_NAME ") has", "NEWER", "version")!=button_ok) {
373 save_config = false;
374 }
375 }
376
377 String err;
378 if (save_config) {
379 LOG("saving config...");
380 save = save_systemconfig(err);
381 }
382 LOG("exit.");
383 done();
384 if (save != LS_OK) {
385 ht_printf("save_systemconfig(): error: %y\n", &err);
386 return 1;
387 }
388 return 0;
389 }
390
391