1 /* main.c
2  * main()
3  * (c) 2002 Mikulas Patocka
4  * This file is a part of the Links program, released under GPL.
5  */
6 
7 #include "links.h"
8 
9 int retval = RET_OK;
10 
11 static void unhandle_basic_signals(struct terminal *);
12 static void poll_fg(void *);
13 
14 #ifdef WIN
sig_terminate(void * t_)15 static void sig_terminate(void *t_)
16 {
17 	struct terminal *t = (struct terminal *)t_;
18 	unhandle_basic_signals(t);
19 	terminate_loop = 1;
20 	retval = RET_SIGNAL;
21 }
22 #endif
23 
sig_intr(void * t_)24 static void sig_intr(void *t_)
25 {
26 	struct terminal *t = (struct terminal *)t_;
27 	if (!t) {
28 		unhandle_basic_signals(t);
29 		terminate_loop = 1;
30 	} else {
31 		unhandle_basic_signals(t);
32 		exit_prog(t, NULL, NULL);
33 	}
34 }
35 
sig_ctrl_c(void * t_)36 static void sig_ctrl_c(void *t_)
37 {
38 	if (!is_blocked()) kbd_ctrl_c();
39 }
40 
41 #ifdef SIGTTOU
sig_ign(void * x)42 static void sig_ign(void *x)
43 {
44 }
45 #endif
46 
47 static struct timer *fg_poll_timer = NULL;
48 
sig_tstp(void * t_)49 void sig_tstp(void *t_)
50 {
51 	struct terminal *t = (struct terminal *)t_;
52 #if defined(SIGSTOP) && !defined(NO_CTRL_Z)
53 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
54 	pid_t pid, newpid;
55 	EINTRLOOP(pid, getpid());
56 #endif
57 	if (!F) block_itrm(1);
58 #ifdef G
59 	else if (drv->block) drv->block(NULL);
60 #endif
61 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
62 	EINTRLOOP(newpid, fork());
63 	if (!newpid) {
64 		while (1) {
65 			int rr;
66 			portable_sleep(1000);
67 			EINTRLOOP(rr, kill(pid, SIGCONT));
68 		}
69 	}
70 #endif
71 	{
72 		int rr;
73 		EINTRLOOP(rr, raise(SIGSTOP));
74 	}
75 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
76 	if (newpid != -1) {
77 		int rr;
78 		EINTRLOOP(rr, kill(newpid, SIGKILL));
79 	}
80 #endif
81 #endif
82 	if (fg_poll_timer != NULL) kill_timer(fg_poll_timer);
83 	fg_poll_timer = install_timer(FG_POLL_TIME, poll_fg, t);
84 }
85 
poll_fg(void * t_)86 static void poll_fg(void *t_)
87 {
88 	struct terminal *t = (struct terminal *)t_;
89 	int r = 0;
90 	fg_poll_timer = NULL;
91 	if (!F) r = unblock_itrm(1);
92 #ifdef G
93 	else if (drv->unblock) r = drv->unblock(NULL);
94 #endif
95 	if (r == -1) {
96 		fg_poll_timer = install_timer(FG_POLL_TIME, poll_fg, t);
97 	}
98 	if (r == -2) {
99 		/* This will unblock externally spawned viewer, if it exists */
100 #ifdef SIGCONT
101 		EINTRLOOP(r, kill(0, SIGCONT));
102 #endif
103 	}
104 }
105 
sig_cont(void * t_)106 void sig_cont(void *t_)
107 {
108 	if (!F) unblock_itrm(1);
109 #ifdef G
110 	else if (drv->unblock) drv->unblock(NULL);
111 #endif
112 }
113 
handle_basic_signals(struct terminal * term)114 static void handle_basic_signals(struct terminal *term)
115 {
116 	install_signal_handler(SIGHUP, sig_intr, term, 0);
117 	if (!F) install_signal_handler(SIGINT, sig_ctrl_c, term, 0);
118 	/*install_signal_handler(SIGTERM, sig_terminate, term, 0);*/
119 #ifdef WIN
120 	install_signal_handler(SIGQUIT, sig_terminate, term, 0);
121 #endif
122 #ifdef SIGTSTP
123 	if (!F) install_signal_handler(SIGTSTP, sig_tstp, term, 0);
124 #endif
125 #ifdef SIGTTIN
126 	if (!F) install_signal_handler(SIGTTIN, sig_tstp, term, 0);
127 #endif
128 #ifdef SIGTTOU
129 	install_signal_handler(SIGTTOU, sig_ign, term, 0);
130 #endif
131 #ifdef SIGCONT
132 	if (!F) install_signal_handler(SIGCONT, sig_cont, term, 0);
133 #endif
134 }
135 
unhandle_terminal_signals(struct terminal * term)136 void unhandle_terminal_signals(struct terminal *term)
137 {
138 	install_signal_handler(SIGHUP, NULL, NULL, 0);
139 	if (!F) install_signal_handler(SIGINT, NULL, NULL, 0);
140 #ifdef SIGTSTP
141 	install_signal_handler(SIGTSTP, NULL, NULL, 0);
142 #endif
143 #ifdef SIGTTIN
144 	install_signal_handler(SIGTTIN, NULL, NULL, 0);
145 #endif
146 #ifdef SIGTTOU
147 	install_signal_handler(SIGTTOU, NULL, NULL, 0);
148 #endif
149 #ifdef SIGCONT
150 	install_signal_handler(SIGCONT, NULL, NULL, 0);
151 #endif
152 	if (fg_poll_timer != NULL) kill_timer(fg_poll_timer), fg_poll_timer = NULL;
153 }
154 
unhandle_basic_signals(struct terminal * term)155 static void unhandle_basic_signals(struct terminal *term)
156 {
157 	install_signal_handler(SIGHUP, NULL, NULL, 0);
158 	if (!F) install_signal_handler(SIGINT, NULL, NULL, 0);
159 	/*install_signal_handler(SIGTERM, NULL, NULL, 0);*/
160 #ifdef SIGTSTP
161 	install_signal_handler(SIGTSTP, NULL, NULL, 0);
162 #endif
163 #ifdef SIGTTIN
164 	install_signal_handler(SIGTTIN, NULL, NULL, 0);
165 #endif
166 #ifdef SIGTTOU
167 	install_signal_handler(SIGTTOU, NULL, NULL, 0);
168 #endif
169 #ifdef SIGCONT
170 	install_signal_handler(SIGCONT, NULL, NULL, 0);
171 #endif
172 	if (fg_poll_timer != NULL) kill_timer(fg_poll_timer), fg_poll_timer = NULL;
173 }
174 
175 int terminal_pipe[2] = { -1, -1 };
176 
attach_terminal(int in,int out,int ctl,void * info,int len)177 int attach_terminal(int in, int out, int ctl, void *info, int len)
178 {
179 	struct terminal *term;
180 	set_nonblock(terminal_pipe[0]);
181 	set_nonblock(terminal_pipe[1]);
182 	handle_trm(in, out, out, terminal_pipe[1], ctl, info, len);
183 	mem_free(info);
184 	if ((term = init_term(terminal_pipe[0], out, win_func))) {
185 		handle_basic_signals(term);	/* OK, this is race condition, but it must be so; GPM installs it's own buggy TSTP handler */
186 		return terminal_pipe[1];
187 	}
188 	close_socket(&terminal_pipe[0]);
189 	close_socket(&terminal_pipe[1]);
190 	return -1;
191 }
192 
193 #ifdef G
194 
attach_g_terminal(unsigned char * cwd,void * info,int len)195 int attach_g_terminal(unsigned char *cwd, void *info, int len)
196 {
197 	struct terminal *term;
198 	term = init_gfx_term(win_func, cwd, info, len);
199 	mem_free(info);
200 	return term ? 0 : -1;
201 }
202 
gfx_connection(int h)203 void gfx_connection(int h)
204 {
205 	int r;
206 	unsigned char cwd[MAX_CWD_LEN];
207 	unsigned char hold_conn;
208 	void *info;
209 	int info_len;
210 	struct terminal *term;
211 
212 	if (os_send_fg_cookie(h))
213 		goto err_close;
214 	if (hard_read(h, cwd, MAX_CWD_LEN) != MAX_CWD_LEN)
215 		goto err_close;
216 	cwd[MAX_CWD_LEN - 1] = 0;
217 	if (hard_read(h, &hold_conn, 1) != 1)
218 		goto err_close;
219 	if (hard_read(h, (unsigned char *)&info_len, sizeof(int)) != sizeof(int) || info_len < 0)
220 		goto err_close;
221 	info = mem_alloc(info_len);
222 	if (hard_read(h, info, info_len) != info_len)
223 		goto err_close_free;
224 	term = init_gfx_term(win_func, cwd, info, info_len);
225 	if (term) {
226 		if (hold_conn) {
227 			term->handle_to_close = h;
228 		} else {
229 			hard_write(h, cast_uchar "x", 1);
230 			EINTRLOOP(r, close(h));
231 		}
232 		mem_free(info);
233 		return;
234 	}
235 err_close_free:
236 	mem_free(info);
237 err_close:
238 	EINTRLOOP(r, close(h));
239 }
240 
gfx_connection_terminate(void * p)241 static void gfx_connection_terminate(void *p)
242 {
243 	int h = (int)(my_intptr_t)p;
244 	set_handlers(h, NULL, NULL, NULL);
245 	terminate_loop = 1;
246 }
247 
248 #endif
249 
250 static struct object_request *dump_obj;
251 static off_t dump_pos;
252 
end_dump(struct object_request * r,void * p)253 static void end_dump(struct object_request *r, void *p)
254 {
255 	struct cache_entry *ce;
256 	int oh;
257 	if (!r->state || (r->state == 1 && dmp != D_SOURCE)) return;
258 	if ((oh = get_output_handle()) == -1) return;
259 	ce = r->ce;
260 	if (dmp == D_SOURCE) {
261 		if (ce) {
262 			struct fragment *frag;
263 			struct list_head *lfrag;
264 			nextfrag:
265 			foreach(struct fragment, frag, lfrag, ce->frag) if (frag->offset <= dump_pos && frag->offset + frag->length > dump_pos) {
266 				off_t l;
267 				int w;
268 				l = frag->length - (dump_pos - frag->offset);
269 				if (l >= MAXINT) l = MAXINT;
270 				w = hard_write(oh, frag->data + dump_pos - frag->offset, (int)l);
271 				if (w != l) {
272 					unsigned char *msg = strerror_alloc(errno, NULL);
273 					detach_object_connection(r, dump_pos);
274 					if (w < 0) fprintf(stderr, "Error writing to stdout: %s.\n", msg);
275 					else fprintf(stderr, "Can't write to stdout.\n");
276 					mem_free(msg);
277 					retval = RET_ERROR;
278 					goto terminate;
279 				}
280 				dump_pos += w;
281 				detach_object_connection(r, dump_pos);
282 				goto nextfrag;
283 			}
284 		}
285 		if (r->state >= 0) return;
286 	} else if (ce) {
287 		struct document_options o;
288 		struct f_data_c *fd;
289 		int err;
290 		fd = create_f_data_c(NULL, NULL);
291 		memset(&o, 0, sizeof(struct document_options));
292 		o.xp = 0;
293 		o.yp = 1;
294 		o.xw = screen_width;
295 		o.yw = 25;
296 		o.col = 0;
297 		o.cp = get_commandline_charset();
298 		ds2do(&dds, &o, 0);
299 		o.plain = 0;
300 		o.frames = 0;
301 		o.js_enable = 0;
302 		o.framename = cast_uchar "";
303 		if (!casecmp(r->url, cast_uchar "file://", 7) && !o.hard_assume) {
304 			o.assume_cp = get_commandline_charset();
305 		}
306 		if (!(fd->f_data = cached_format_html(fd, r, r->url, &o, NULL, 0))) goto term_1;
307 		if ((err = dump_to_file(fd->f_data, oh))) {
308 			fprintf(stderr, "Error writing to stdout: %s.\n", get_err_msg(err, NULL));
309 			retval = RET_ERROR;
310 		}
311 		term_1:
312 		reinit_f_data_c(fd);
313 		mem_free(fd);
314 	}
315 	if (r->state != O_OK) {
316 		unsigned char *m = get_err_msg(r->stat.state, NULL);
317 		fprintf(stderr, "%s\n", get_english_translation(m));
318 		retval = RET_ERROR;
319 		goto terminate;
320 	}
321 	terminate:
322 	terminate_loop = 1;
323 }
324 
325 int g_argc;
326 char **g_argv;
327 
328 unsigned char *path_to_exe;
329 
330 static unsigned char init_b = 0;
331 
332 static void initialize_all_subsystems(void);
333 static void initialize_all_subsystems_2(void);
334 
fixup_g(void)335 static void fixup_g(void)
336 {
337 	if (ggr_drv[0] || ggr_mode[0] || force_g) ggr = 1;
338 	if (dmp) ggr = 0;
339 }
340 
init(void)341 static void init(void)
342 {
343 	int uh;
344 	void *info;
345 	int len;
346 	unsigned char *u;
347 
348 	initialize_all_subsystems();
349 
350 /* OS/2 has some stupid bug and the pipe must be created before socket :-/ */
351 	if (c_pipe(terminal_pipe)) {
352 		fatal_exit("ERROR: can't create pipe for internal communication");
353 	}
354 	if (!(u = parse_options(g_argc - 1, g_argv + 1))) {
355 		retval = RET_SYNTAX;
356 		goto ttt;
357 	}
358 	fixup_g();
359 	if (!dmp && !ggr) {
360 		init_os_terminal();
361 	}
362 	if (!ggr && !no_connect && (uh = bind_to_af_unix(NULL)) != -1) {
363 		close_socket(&terminal_pipe[0]);
364 		close_socket(&terminal_pipe[1]);
365 		info = create_session_info(base_session, u, default_target, &len);
366 		initialize_all_subsystems_2();
367 		handle_trm(get_input_handle(), get_output_handle(), uh, uh, get_ctl_handle(), info, len);
368 		handle_basic_signals(NULL);	/* OK, this is race condition, but it must be so; GPM installs it's own buggy TSTP handler */
369 		mem_free(info);
370 #if defined(HAVE_MALLOC_TRIM)
371 		malloc_trim(8192);
372 #endif
373 		return;
374 	}
375 	if ((dds.assume_cp = get_cp_index(cast_uchar "ISO-8859-1")) == -1) dds.assume_cp = 0;
376 	load_config();
377 	if (proxies.only_proxies)
378 		reset_settings_for_tor();
379 	u = parse_options(g_argc - 1, g_argv + 1);
380 	fixup_g();
381 	if (!u) {
382 		ttt:
383 		initialize_all_subsystems_2();
384 		tttt:
385 		terminate_loop = 1;
386 		return;
387 	}
388 	init_cookies();
389 	if (!dmp) {
390 		if (ggr) {
391 			close_socket(&terminal_pipe[0]);
392 			close_socket(&terminal_pipe[1]);
393 #ifdef G
394 			{
395 				unsigned char *r;
396 				if ((r = init_graphics(ggr_drv, ggr_mode, ggr_display))) {
397 					fprintf(stderr, "%s", r);
398 					mem_free(r);
399 					retval = RET_SYNTAX;
400 					goto ttt;
401 				}
402 				handle_basic_signals(NULL);
403 				if (drv->get_af_unix_name && !no_connect) {
404 					unsigned char *n = stracpy(drv->name);
405 					unsigned char *nn = drv->get_af_unix_name();
406 					if (*nn) {
407 						add_to_strn(&n, cast_uchar "-");
408 						add_to_strn(&n, nn);
409 					}
410 					uh = bind_to_af_unix(n);
411 					mem_free(n);
412 					if (uh != -1) {
413 						unsigned char hold_conn;
414 						unsigned char *w;
415 						int lw;
416 						shutdown_graphics();
417 						if (os_receive_fg_cookie(uh)) {
418 							retval = RET_ERROR;
419 							goto ttt;
420 						}
421 						w = get_cwd();
422 						if (!w) w = stracpy(cast_uchar "");
423 						if (strlen(cast_const_char w) >= MAX_CWD_LEN)
424 							w[MAX_CWD_LEN - 1] = 0;
425 						lw = (int)strlen(cast_const_char w) + 1;
426 						if (hard_write(uh, w, lw) != lw) {
427 							mem_free(w);
428 							retval = RET_ERROR;
429 							goto ttt;
430 						}
431 						mem_free(w);
432 						w = mem_calloc(MAX_CWD_LEN - lw);
433 						if (hard_write(uh, w, MAX_CWD_LEN - lw) != MAX_CWD_LEN - lw) {
434 							mem_free(w);
435 							retval = RET_ERROR;
436 							goto ttt;
437 						}
438 						mem_free(w);
439 						hold_conn = *u != 0;
440 						if (hard_write(uh, &hold_conn, 1) != 1) {
441 							retval = RET_ERROR;
442 							goto ttt;
443 						}
444 						info = create_session_info(base_session, u, default_target, &len);
445 						if (hard_write(uh, (unsigned char *)&len, sizeof len) != sizeof len) {
446 							mem_free(info);
447 							retval = RET_ERROR;
448 							goto ttt;
449 						}
450 						if (hard_write(uh, info, len) != len) {
451 							mem_free(info);
452 							retval = RET_ERROR;
453 							goto ttt;
454 						}
455 						mem_free(info);
456 						set_handlers(uh, gfx_connection_terminate, NULL, (void *)(my_intptr_t)uh);
457 						initialize_all_subsystems_2();
458 						heap_trim();
459 						return;
460 					}
461 				}
462 				init_dither(drv->depth);
463 				fontconfig_init();
464 				freetype_init();
465 			}
466 #else
467 			fprintf(stderr, "Graphics not enabled when compiling\n");
468 			retval = RET_SYNTAX;
469 			goto ttt;
470 #endif
471 		}
472 		init_b = 1;
473 		init_bookmarks();
474 		create_initial_extensions();
475 		load_url_history();
476 		initialize_all_subsystems_2();
477 		info = create_session_info(base_session, u, default_target, &len);
478 		if (!F) {
479 			if (attach_terminal(get_input_handle(), get_output_handle(), get_ctl_handle(), info, len) < 0)
480 				fatal_exit("Could not open initial session");
481 		}
482 #ifdef G
483 		else {
484 			unsigned char *cwd = get_cwd();
485 			if (!cwd)
486 				cwd = stracpy(cast_uchar "");
487 			if (attach_g_terminal(cwd, info, len) < 0)
488 				fatal_exit("Could not open initial session");
489 			mem_free(cwd);
490 		}
491 #endif
492 	} else {
493 		unsigned char *uu, *uuu, *wd;
494 		initialize_all_subsystems_2();
495 		close_socket(&terminal_pipe[0]);
496 		close_socket(&terminal_pipe[1]);
497 		if (!*u) {
498 			fprintf(stderr, "URL expected after %s\n", dmp == D_DUMP ? "-dump" : "-source");
499 			retval = RET_SYNTAX;
500 			goto tttt;
501 		}
502 		uu = convert(get_commandline_charset(), utf8_table, u, NULL);
503 		if (!(uuu = translate_url(uu, wd = get_cwd()))) uuu = stracpy(uu);
504 		mem_free(uu);
505 		request_object(NULL, uuu, NULL, PRI_MAIN, NC_RELOAD, ALLOW_ALL, end_dump, NULL, &dump_obj);
506 		mem_free(uuu);
507 		if (wd) mem_free(wd);
508 	}
509 }
510 
511 /* Is called before gaphics driver init */
initialize_all_subsystems(void)512 static void initialize_all_subsystems(void)
513 {
514 	init_charset();
515 	init_trans();
516 	set_sigcld();
517 	init_home();
518 	init_dns();
519 	init_session_cache();
520 	init_cache();
521 	init_blocks();
522 	memset(&dd_opt, 0, sizeof dd_opt);
523 }
524 
525 /* Is called sometimes after and sometimes before graphics driver init */
initialize_all_subsystems_2(void)526 static void initialize_all_subsystems_2(void)
527 {
528 	GF(init_dip());
529 	init_bfu();
530 	GF(init_imgcache());
531 	init_fcache();
532 	GF(init_grview());
533 }
534 
terminate_all_subsystems(void)535 static void terminate_all_subsystems(void)
536 {
537 	check_bottom_halves();
538 	abort_all_downloads();
539 	check_bottom_halves();
540 	destroy_all_terminals();
541 	check_bottom_halves();
542 	shutdown_bfu();
543 	if (!F) free_all_itrms();
544 	release_object(&dump_obj);
545 	abort_all_connections();
546 
547 	free_all_caches();
548 #ifdef HAVE_SSL
549 	ssl_finish();
550 #endif
551 	if (init_b) save_url_history();
552 	free_history_lists();
553 	free_term_specs();
554 	free_types();
555 	free_blocks();
556 	finalize_bookmarks();
557 	free_conv_table();
558 	free_blacklist();
559 	do_save_cookies();
560 	free_cookies();
561 	free_auth();
562 	check_bottom_halves();
563 	end_config();
564 	free_strerror_buf();
565 	shutdown_trans();
566 	GF(freetype_done());
567 	GF(free_dither());
568 	GF(shutdown_graphics());
569 	af_unix_close();
570 	os_free_clipboard();
571 	if (fg_poll_timer != NULL) kill_timer(fg_poll_timer), fg_poll_timer = NULL;
572 	terminate_select();
573 	terminate_osdep();
574 }
575 
main(int argc,char * argv[])576 int main(int argc, char *argv[])
577 {
578 	g_argc = argc;
579 	g_argv = (char **)argv;		/* we fix this up in init_os in vms.c */
580 
581 #if 0
582 	if (argc != 3)
583 		fprintf(stderr, "two args expected\n"), exit(1);
584 	printf("cookie %saccepted\n", allow_cookie_domain(cast_uchar argv[1], cast_uchar argv[2]) ? "" : "not ");
585 	return 0;
586 #endif
587 #if 0
588 	{
589 		unsigned char a[216];
590 		double dist[216];
591 		int i;
592 		memset(&a, 0, sizeof a);
593 		for (i = 0; i < 216; i++) dist[i] = 1e30;
594 		for (i = 0; i < 216; i++) {
595 			int j, b = -1;
596 			double maxdist = 0;
597 			for (j = 0; j < 216; j++) {
598 				if ((j / 36 == 0 || j / 36 == 5) &&
599 				    (j / 6 % 6 == 0 || j / 6 % 6 == 5) &&
600 				    (j % 6 == 0 || j % 6 == 5))
601 					if (dist[j] && dist[j] > maxdist) {
602 						maxdist = dist[j];
603 						b = j;
604 					}
605 			}
606 			if (b == -1) for (j = 0; j < 216; j++) {
607 				if (dist[j] > maxdist) {
608 					maxdist = dist[j];
609 					b = j;
610 				}
611 			}
612 			for (j = 0; j < 216; j++) {
613 				double d;
614 				unsigned rgb1[3];
615 				unsigned rgb2[3];
616 				q_palette(216, b, 65535, rgb1);
617 				q_palette(216, j, 65535, rgb2);
618 				d = rgb_distance(rgb1[0], rgb1[1], rgb1[2], rgb2[0], rgb2[1], rgb2[2]);
619 				if (d < dist[j])
620 					dist[j] = d;
621 			}
622 			fprintf(stderr, "%d: (%d, %d, %d)\n", b, b / 36, b / 6 % 6, b % 6);
623 		}
624 		return 0;
625 	}
626 #endif
627 
628 	init_page_size();
629 	init_heap();
630 	init_os();
631 	get_path_to_exe();
632 
633 #if 0
634 	{
635 		int i;
636 		int ix, iy, ox, oy, rep;
637 		ulonglong tm = 0;
638 		parse_options(g_argc - 1, g_argv + 1);
639 		ix = getenv("SRC_X") ? atoi(getenv("SRC_X")) : 100;
640 		iy = getenv("SRC_Y") ? atoi(getenv("SRC_Y")) : ix;
641 		ox = getenv("DST_X") ? atoi(getenv("DST_X")) : 100;
642 		oy = getenv("DST_Y") ? atoi(getenv("DST_Y")) : ox;
643 		rep = getenv("REP") ? atoi(getenv("REP")) : 1;
644 		for (i = 0; i <= rep; i++) {
645 			unsigned short *dst;
646 			unsigned short *src;
647 			struct timeval tv1, tv2;
648 			src = mem_alloc(sizeof(unsigned short) * ix * iy * 3);
649 			memset(src, 0x12, sizeof(unsigned short) * ix * iy * 3);
650 			gettimeofday(&tv1, NULL);
651 			scale_color(src, ix, iy, &dst, ox, oy);
652 			gettimeofday(&tv2, NULL);
653 			if (dst) mem_free(dst);
654 			if (i)
655 				tm += ((ulonglong)tv2.tv_sec * 1000000 + tv2.tv_usec) - ((ulonglong)tv1.tv_sec * 1000000 + tv1.tv_usec);
656 		}
657 		fprintf(stderr, "time: %f\n", (double)tm / 1000 / rep);
658 		check_memory_leaks();
659 		return 0;
660 	}
661 #endif
662 #if 0
663 	{
664 		int i;
665 		for (i = 0; i < 100; i++) {
666 			unsigned char *a = mem_calloc(i);
667 			unsigned char *b = base64_encode(a, i, cast_uchar "", cast_uchar "", 5);
668 			fprintf(stderr, "X:\n%.*s\n", (int)strlen(cast_const_char b), b);
669 			mem_free(a);
670 			mem_free(b);
671 		}
672 		check_memory_leaks();
673 		return 0;
674 	}
675 #endif
676 #if 0
677 	{
678 		unsigned char *puny_encode(unsigned char *s);
679 		unsigned char *puny_decode(unsigned char *s);
680 		int i;
681 		for (i = 1; i < g_argc; i++) {
682 			unsigned char *str = puny_encode(cast_uchar g_argv[i]);
683 			if (str) {
684 				fprintf(stderr, "'%s'\n", str);
685 				unsigned char *d = puny_decode(str);
686 				if (!d || strcmp(cast_const_char d, cast_const_char g_argv[i])) {
687 					internal_error("mismatch - %s", d);
688 				}
689 				mem_free(str);
690 				mem_free(d);
691 			}
692 		}
693 		check_memory_leaks();
694 		return 0;
695 	}
696 #endif
697 #if 0
698 	while (1) {
699 #define maxn	12
700 		static unsigned long long count = 0;
701 		unsigned char *puny_encode(unsigned char *s, int len);
702 		unsigned char *puny_decode(unsigned char *s, int len);
703 		int punycode_encode(size_t input_length, const uint32_t input[], const unsigned char case_flags[], size_t *output_length, char output[]);
704 		int punycode_decode(size_t input_length, const char input[], size_t * output_length, uint32_t output[], unsigned char case_flags[]);
705 		uint32_t unistr[maxn];
706 		unsigned i, n;
707 		unsigned char *utfstr, *puny, *dec;
708 		int utfstr_l;
709 		char pce_o[60];
710 		size_t pce_ol;
711 		int pce_s;
712 		n = random() % (maxn + 1);
713 		for (i = 0; i < n; i++) {
714 			uint32_t uni;
715 			uni = random() % (0x10FFFF + 1);
716 			if (uni >= 0xd800 && uni <= 0xdfff)
717 				uni = random() % 128;
718 			while (uni < 128 && !(
719 				uni == '-' ||
720 				(uni >= '0' && uni <= '9') ||
721 				(uni >= 'A' && uni <= 'Z') ||
722 				(uni >= 'a' && uni <= 'z'))) {
723 				uni = random() % 128;
724 			}
725 			unistr[i] = uni;
726 		}
727 		utfstr = init_str();
728 		utfstr_l = 0;
729 		for (i = 0; i < n; i++) {
730 			unsigned char *us = encode_utf_8(unistr[i]);
731 			add_to_str(&utfstr, &utfstr_l, us);
732 		}
733 		puny = puny_encode(utfstr, utfstr_l);
734 		if (!puny) {
735 			fprintf(stderr, "failed:");
736 			goto err;
737 		}
738 		dec = puny_decode(puny, (int)strlen(cast_const_char puny));
739 		if (!dec)
740 			dec = stracpy(puny);
741 		if (strcmp(cast_const_char utfstr, cast_const_char dec)) {
742 			fprintf(stderr, "mismatch(%s,%s):", utfstr, dec);
743 			goto err;
744 		}
745 		pce_ol = 59;
746 		pce_s = punycode_encode(n, unistr, NULL, &pce_ol, pce_o);
747 		if (pce_s) {
748 			fprintf(stderr, "punycode_encode(%d):", pce_s);
749 			goto err;
750 		}
751 		pce_o[pce_ol] = 0;
752 		if (!strncmp(cast_const_char puny, "xn--", 4) && strcmp(cast_const_char puny + 4, pce_o)) {
753 			fprintf(stderr, "punycode_encode differs(%s,%s):", puny, pce_o);
754 			goto err;
755 		}
756 		mem_free(dec);
757 		mem_free(puny);
758 		mem_free(utfstr);
759 		if (0) {
760 err:
761 			for (i = 0; i < n; i++) {
762 				fprintf(stderr, " %u", unistr[i]);
763 			}
764 			internal_error("failed");
765 		}
766 		count++;
767 		if (!(count % 10000)) {
768 			printf("%llu\r", count);
769 			fflush(stdout);
770 		}
771 	}
772 #endif
773 
774 	select_loop(init);
775 	terminate_all_subsystems();
776 
777 #if 0
778 	{
779 		char msg[65536] = "";
780 		char *p = msg;
781 		int i = 1;
782 		while (p - msg < 60000) {
783 			sprintf(p, "some text %d (%ld) ", i++, p - msg);
784 			p = strchr(p, 0);
785 		}
786 		error(msg);
787 	}
788 #endif
789 	check_memory_leaks();
790 	return retval;
791 }
792 
793