Beispiel #1
0
unsigned _show_msgbox(const char *title, const char *msg, unsigned button_num, ...) {
	va_list ap;
	char title16[(strlen(title) + 1) * 2];
	char msg16[(strlen(msg) + 1) * 2];
	char undef_buf[8];
	unsigned button_pressed = 0;
	memset(undef_buf, 0, sizeof(undef_buf));
	va_start(ap, button_num);
	
	ascii2utf16(title16, title, sizeof(title16));
	ascii2utf16(msg16, msg, sizeof(msg16));
	*(char**)undef_buf = "DLG";
	BOOL incolor = lcd_isincolor();
	void *saved_screen = NULL;
	if (has_colors && !incolor) {
		if ((saved_screen = malloc(SCREEN_WIDTH * SCREEN_HEIGHT * 2))) {
			// The screen buffer size of the color mode is used, but before switching to it
			memcpy(saved_screen, SCREEN_BASE_ADDRESS, SCREEN_WIDTH * SCREEN_HEIGHT * 2);
			memset(SCREEN_BASE_ADDRESS, 0xFF, SCREEN_WIDTH * SCREEN_HEIGHT * 2); // clrscr. avoid displaying a grayscaled buffer in colors
		}
		lcd_incolor();
	}
	/* required since OS 2.1 for OS key scan */
	int orig_mask = TCT_Local_Control_Interrupts(0);
	if (button_num == 2 || button_num == 3) {
		char *button1 = va_arg(ap, char*);
		char *button2 = va_arg(ap, char*);
		char button1_16[(strlen(button1) + 1) * 2];
		char button2_16[(strlen(button2) + 1) * 2];
		ascii2utf16(button1_16, button1, sizeof(button1_16));
		ascii2utf16(button2_16, button2, sizeof(button2_16));
		if (button_num == 2) {
			button_pressed = _show_msgbox_2b(0, title16, msg16, button1_16, 1, button2_16, 2, undef_buf);
		} else {
			char *button3 = va_arg(ap, char*);
			char button3_16[(strlen(button3) + 1) * 2];
			ascii2utf16(button3_16, button3, sizeof(button3_16));
			button_pressed = _show_msgbox_3b(0, title16, msg16, button1_16, 1, button2_16, 2, button3_16, 3, undef_buf);
		}
	} else {
Beispiel #2
0
// Run a program. Returns 0xDEAD if can't run it or 0xBEEF if the error dialog should be skipped. Else returns the program return code.
// If resident_ptr isn't NULL, the program's memory block isn't freed and is stored in resident_ptr. It may be freed later with ld_free(). 
// Resident program shouldn't use argv after returning.
// argsn/args don't include the program path. args doesn't need to be NULL terminated. Can be 0/NULL.
int ld_exec_with_args(const char *path, int argsn, char *args[], void **resident_ptr) {
	char prgm_path[FILENAME_MAX];
	char doc_path[FILENAME_MAX]; // non const
	unsigned i;
	char **argv = NULL;
	char **argvptr;
	int argc;
	int ret;
	BOOL isassoc = FALSE;
	strcpy(doc_path, path);
	strcpy(prgm_path, path); // may deffer if using file association

	// File association
	char extbuf[FILENAME_MAX];
	strcpy(extbuf, prgm_path);
	char *ext = strrchr(extbuf, '.');
	if (!ext || ext == extbuf) {
		puts("ld_exec: can't find file extension");
		return 0xDEAD; // shouldn't happen, all files have a .tns extension
	}
	*ext = '\0'; // keep the extension before .tns
	ext = strrchr(extbuf, '.');
	unsigned pathlen = strlen(extbuf);
	// without '.'
	#define MAX_EXT_LEN 8
	if (ext && extbuf + pathlen - ext <= (MAX_EXT_LEN+1) && extbuf + pathlen - ext > 1) { // looks like an extension
		cfg_open();
		char ext_key[4 + MAX_EXT_LEN + 1]; // ext.extension
		strcpy(ext_key, "ext");
		strcat(ext_key, ext);
		char *prgm_name_noext = cfg_get(ext_key);
		if (prgm_name_noext) {
			char prgm_name[FILENAME_MAX + 4];
			strcpy(prgm_name, prgm_name_noext);
			strcat(prgm_name, ".tns");
			struct assoc_file_each_cb_ctx context = {prgm_name, prgm_path, &isassoc};
			file_each("/", assoc_file_each_cb, &context);
		}
		cfg_close();
	}

	ld_bin_format = LD_ERROR_BIN;

	uint32_t signature;

	NUC_FILE *prgm = nuc_fopen(prgm_path, "rb");
	if(nuc_fread(&signature, sizeof(signature), 1, prgm) != 1)
	{
		// empty file?
		nuc_fclose(prgm);
		return 0xDEAD;
	}

	nuc_fseek(prgm, 0, SEEK_SET);

	void *base = 0;
	int (*entry)(int argc, char *argv[]);

	switch(signature)
	{
	case 0x00475250: //"PRG\0"
		if((ret = ndless_load(prgm_path, prgm, &base, &entry)) == 0)
		{
			nuc_fclose(prgm);
			ld_bin_format = LD_PRG_BIN;
			break;
		}

		nuc_fclose(prgm);
		return ret == 1 ? 0xDEAD : 0xBEEF;
	case 0x544c4662: //"bFLT"
		if(bflt_load(prgm, &base, &entry) == 0)
		{
			nuc_fclose(prgm);
			ld_bin_format = LD_BFLT_BIN;
			break;
		}

		nuc_fclose(prgm);
		return 0xDEAD;
	case 0x6e68655a: //"Zehn"
		if((ret = zehn_load(prgm, &base, &entry)) == 0)
		{
			nuc_fclose(prgm);
			ld_bin_format = LD_ZEHN_BIN;
			break;
		}
		if(base && base != emu_debug_alloc_ptr)
			free(base);

		nuc_fclose(prgm);
		return ret == 1 ? 0xDEAD : 0xBEEF;
	default:
		nuc_fclose(prgm);
		return 0xDEAD;
	}	
	
	int intmask = TCT_Local_Control_Interrupts(-1); /* TODO workaround: disable the interrupts to avoid the clock on the screen */
	wait_no_key_pressed(); // let the user release the Enter key, to avoid being read by the program
	void *savedscr = malloc(SCREEN_BYTES_SIZE);
	if (!savedscr) {
		puts("ld_exec: can't malloc savedscr");
		ret = 0xDEAD;
		goto ld_exec_with_args_quit;
	}
	memcpy(savedscr, (void*) SCREEN_BASE_ADDRESS, SCREEN_BYTES_SIZE);
	
	argc = 1 + argsn;
	if (isassoc)
		argc++;

	argv = malloc((argc + 1) * sizeof(char*));
	if (!argv) {
		puts("ld_exec: can't malloc argv");
		ret = 0xDEAD;
		goto ld_exec_with_args_quit;
	}
	argv[0] = prgm_path;
	argvptr = &argv[1];
	if (isassoc) {
		argv[1] = doc_path;
		argvptr++;
	}
	if (args)
		memcpy(argvptr, args, argsn * sizeof(char*));

	argv[argc] = NULL;
	
	if (has_colors) {
		volatile unsigned *palette = (volatile unsigned*)0xC0000200;
		for (i = 0; i < 16/2; i++)
			*palette++ = ((i * 2 + 1) << (1 + 16)) | ((i * 2 + 1) << (6 + 16)) | ((i * 2 + 1) << (11 + 16)) | ((i * 2) << 1) | ((i * 2) << 6) | ((i * 2) << 11); // set the grayscale palette
		ut_disable_watchdog(); // seems to be sometimes renabled by the OS
	}
	
	is_current_prgm_resident = FALSE;
	clear_cache();
	ret = entry(argc, argv); /* run the program */
	if (has_colors)
		lcd_incolor(); // in case not restored by the program

	if (!plh_noscrredraw)
		memcpy((void*) SCREEN_BASE_ADDRESS, savedscr, SCREEN_BYTES_SIZE);
	
ld_exec_with_args_quit:
	free(savedscr);
	wait_no_key_pressed(); // let the user release the key used to exit the program, to avoid being read by the OS
	TCT_Local_Control_Interrupts(intmask);
	if (ret != 0xDEAD && resident_ptr) {
		*resident_ptr = base;
		return ret;
	}
	if (is_current_prgm_resident) // required by the program itself
		return ret;
	if (!emu_debug_alloc_ptr)
	    free(base);

	free(argv);
	return ret;
}