Пример #1
0
// Calls callback() for each file and folder found in folder and its subfolders. context is passed to callback() and can be NULL.
// callback() must return:
//  * 0 to continue the scan
//  * 1 to abort the scan
//  * 2 to continue the scan but not recurse through the current directory
// Returns non-zero if callback() asked to abort.
int file_each(const char *folder, int (*callback)(const char *path, void *context), void *context) {
	char subfolder_or_file[FILENAME_MAX];
	DIR *dp;
	struct dirent *ep;     
	struct stat statbuf;
	#define MAX_FILES_IN_DIR 100
	#define MEAN_FILE_NAME_SIZE 50
	#define FILENAMES_BUF_SIZE (MEAN_FILE_NAME_SIZE * MAX_FILES_IN_DIR)
	char *filenames;
	char *filenames_ptrs[MAX_FILES_IN_DIR];
	if (!(filenames = malloc(FILENAMES_BUF_SIZE)))
		return 0;
	if (!(dp = opendir(folder))) {
		free(filenames);
		return 0;
	}
	// list the directory to sort its content
	unsigned i;
	unsigned filenames_used_bytes = 0;
	char *ptr;
	for (i = 0, ptr = filenames; (ep = readdir(dp)) && i < MAX_FILES_IN_DIR && ptr < filenames + FILENAMES_BUF_SIZE; i++) {
		if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) {
			i--;
			continue;
		}
		size_t dname_len = strlen(ep->d_name);
		if (FILENAMES_BUF_SIZE - filenames_used_bytes < dname_len + 1)
			break;
		strcpy(ptr, ep->d_name);
		filenames_ptrs[i] = ptr;
		ptr += dname_len + 1;
	}
	unsigned filenum = i;
	qsort(filenames_ptrs, filenum, sizeof(char*), scmp);
	
	for (i = 0; i < filenum; i++) {
		strcpy(subfolder_or_file, folder);
		if (subfolder_or_file[strlen(subfolder_or_file) - 1] != '/')
			strcat(subfolder_or_file, "/");
		strcat(subfolder_or_file, filenames_ptrs[i]);
		if (stat(subfolder_or_file, &statbuf) == -1)
			continue;
		int next_action = callback(subfolder_or_file, context);
		if (next_action == 1) {
			closedir(dp);
			free(filenames);
			return 1;
		}
		if (S_ISDIR(statbuf.st_mode) && next_action != 2) {
			if (file_each(subfolder_or_file, callback, context)) {
				closedir(dp);
				free(filenames);
				return 1;
			}
		}
	}
	closedir(dp);
	free(filenames);
	return 0;
}
Пример #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;
}