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