static int WM_LoadConfig()

in doom_py/src/vizdoom/src/wildmidi/wildmidi_lib.cpp [662:1192]


static int WM_LoadConfig(const char *config_file) {
	unsigned long int config_size = 0;
	char *config_buffer = NULL;
	const char *dir_end = NULL;
	char *config_dir = NULL;
	unsigned long int config_ptr = 0;
	unsigned long int line_start_ptr = 0;
	unsigned short int patchid = 0;
	struct _patch * tmp_patch;
	char **line_tokens = NULL;
	int token_count = 0;

	config_buffer = (char *) _WM_BufferFile(config_file, &config_size, true);
	if (!config_buffer) {
		WM_FreePatches();
		return -1;
	}


	// This part was rewritten because the original depended on a header that was GPL'd.
	dir_end = strrchr(config_file, '/');
#ifdef _WIN32
	const char *dir_end2 = strrchr(config_file, '\\');
	if (dir_end2 > dir_end) dir_end = dir_end2;
#endif

	if (dir_end) {
		config_dir = (char*)malloc((dir_end - config_file + 2));
		if (config_dir == NULL) {
			_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config",
					errno);
			_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
			WM_FreePatches();
			free(config_buffer);
			return -1;
		}
		strncpy(config_dir, config_file, (dir_end - config_file + 1));
		config_dir[dir_end - config_file + 1] = '\0';
	}

	config_ptr = 0;
	line_start_ptr = 0;

	/* handle files without a newline at the end: this relies on
	 * _WM_BufferFile() allocating the buffer with one extra byte */
	config_buffer[config_size] = '\n';

	while (config_ptr <= config_size) {
		if (config_buffer[config_ptr] == '\r' ||
		    config_buffer[config_ptr] == '\n')
		{
			config_buffer[config_ptr] = '\0';

			if (config_ptr != line_start_ptr) {
				line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]);
				if (line_tokens) {
					if (stricmp(line_tokens[0], "dir") == 0) {
						free(config_dir);
						if (!line_tokens[1]) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(missing name in dir line)", 0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(line_tokens);
							free(config_buffer);
							return -1;
						} else if (!(config_dir = wm_strdup(line_tokens[1]))) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
									"to parse config", errno);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						if (!IS_DIR_SEPARATOR(config_dir[strlen(config_dir) - 1])) {
							config_dir[strlen(config_dir) + 1] = '\0';
							config_dir[strlen(config_dir)] = '/';
						}
					} else if (stricmp(line_tokens[0], "source") == 0) {
						char *new_config = NULL;
						if (!line_tokens[1]) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(missing name in source line)", 0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(line_tokens);
							free(config_buffer);
							return -1;
						} else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) {
							new_config = (char*)malloc(
									strlen(config_dir) + strlen(line_tokens[1])
											+ 1);
							if (new_config == NULL) {
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
										"to parse config", errno);
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
										config_file, 0);
								WM_FreePatches();
								free(config_dir);
								free(line_tokens);
								free(config_buffer);
								return -1;
							}
							strcpy(new_config, config_dir);
							strcpy(&new_config[strlen(config_dir)], line_tokens[1]);
						} else {
							if (!(new_config = wm_strdup(line_tokens[1]))) {
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
										"to parse config", errno);
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
										config_file, 0);
								WM_FreePatches();
								free(line_tokens);
								free(config_buffer);
								return -1;
							}
						}
						if (WM_LoadConfig(new_config) == -1) {
							free(new_config);
							free(line_tokens);
							free(config_buffer);
							free(config_dir);
							return -1;
						}
						free(new_config);
					} else if (stricmp(line_tokens[0], "bank") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in bank line)", 0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						patchid = (atoi(line_tokens[1]) & 0xFF) << 8;
					} else if (stricmp(line_tokens[0], "drumset") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in drumset line)", 0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80;
					} else if (stricmp(line_tokens[0], "reverb_room_width") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in reverb_room_width line)",
									0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						reverb_room_width = (float) atof(line_tokens[1]);
						if (reverb_room_width < 1.0f) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_room_width < 1 meter, setting to minimum of 1 meter)",
									0);
							reverb_room_width = 1.0f;
						} else if (reverb_room_width > 100.0f) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_room_width > 100 meters, setting to maximum of 100 meters)",
									0);
							reverb_room_width = 100.0f;
						}
					} else if (stricmp(line_tokens[0], "reverb_room_length") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in reverb_room_length line)",
									0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						reverb_room_length = (float) atof(line_tokens[1]);
						if (reverb_room_length < 1.0f) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_room_length < 1 meter, setting to minimum of 1 meter)",
									0);
							reverb_room_length = 1.0f;
						} else if (reverb_room_length > 100.0f) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_room_length > 100 meters, setting to maximum of 100 meters)",
									0);
							reverb_room_length = 100.0f;
						}
					} else if (stricmp(line_tokens[0], "reverb_listener_posx") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in reverb_listen_posx line)",
									0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						reverb_listen_posx = (float) atof(line_tokens[1]);
						if ((reverb_listen_posx > reverb_room_width)
								|| (reverb_listen_posx < 0.0f)) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_listen_posx set outside of room)",
									0);
							reverb_listen_posx = reverb_room_width / 2.0f;
						}
					} else if (stricmp(line_tokens[0],
							"reverb_listener_posy") == 0) {
						if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(syntax error in reverb_listen_posy line)",
									0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						}
						reverb_listen_posy = (float) atof(line_tokens[1]);
						if ((reverb_listen_posy > reverb_room_width)
								|| (reverb_listen_posy < 0.0f)) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(reverb_listen_posy set outside of room)",
									0);
							reverb_listen_posy = reverb_room_length * 0.75f;
						}
					} else if (stricmp(line_tokens[0],
							"guspat_editor_author_cant_read_so_fix_release_time_for_me")
							== 0) {
						fix_release = 1;
					} else if (stricmp(line_tokens[0], "auto_amp") == 0) {
						auto_amp = 1;
					} else if (stricmp(line_tokens[0], "auto_amp_with_amp")
							== 0) {
						auto_amp = 1;
						auto_amp_with_amp = 1;
					} else if (wm_isdigit(line_tokens[0][0])) {
						patchid = (patchid & 0xFF80)
								| (atoi(line_tokens[0]) & 0x7F);
						if (patch[(patchid & 0x7F)] == NULL) {
							patch[(patchid & 0x7F)] = (struct _patch*)malloc(
									sizeof(struct _patch));
							if (patch[(patchid & 0x7F)] == NULL) {
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
										NULL, errno);
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
										config_file, 0);
								WM_FreePatches();
								free(config_dir);
								free(line_tokens);
								free(config_buffer);
								return -1;
							}
							tmp_patch = patch[(patchid & 0x7F)];
							tmp_patch->patchid = patchid;
							tmp_patch->filename = NULL;
							tmp_patch->amp = 1024;
							tmp_patch->note = 0;
							tmp_patch->next = NULL;
							tmp_patch->first_sample = NULL;
							tmp_patch->loaded = 0;
							tmp_patch->inuse_count = 0;
						} else {
							tmp_patch = patch[(patchid & 0x7F)];
							if (tmp_patch->patchid == patchid) {
								free(tmp_patch->filename);
								tmp_patch->filename = NULL;
								tmp_patch->amp = 1024;
								tmp_patch->note = 0;
							} else {
								if (tmp_patch->next) {
									while (tmp_patch->next) {
										if (tmp_patch->next->patchid == patchid)
											break;
										tmp_patch = tmp_patch->next;
									}
									if (tmp_patch->next == NULL) {
										if ((tmp_patch->next = (struct _patch*)malloc(
												sizeof(struct _patch)))
												== NULL) {
											_WM_ERROR(__FUNCTION__, __LINE__,
													WM_ERR_MEM, NULL, 0);
											_WM_ERROR(__FUNCTION__, __LINE__,
													WM_ERR_LOAD, config_file,
													0);
											WM_FreePatches();
											free(config_dir);
											free(line_tokens);
											free(config_buffer);
											return -1;
										}
										tmp_patch = tmp_patch->next;
										tmp_patch->patchid = patchid;
										tmp_patch->filename = NULL;
										tmp_patch->amp = 1024;
										tmp_patch->note = 0;
										tmp_patch->next = NULL;
										tmp_patch->first_sample = NULL;
										tmp_patch->loaded = 0;
										tmp_patch->inuse_count = 0;
									} else {
										tmp_patch = tmp_patch->next;
										free(tmp_patch->filename);
										tmp_patch->filename = NULL;
										tmp_patch->amp = 1024;
										tmp_patch->note = 0;
									}
								} else {
									tmp_patch->next = (struct _patch*)malloc(
											sizeof(struct _patch));
									if (tmp_patch->next == NULL) {
										_WM_ERROR(__FUNCTION__, __LINE__,
												WM_ERR_MEM, NULL, errno);
										_WM_ERROR(__FUNCTION__, __LINE__,
												WM_ERR_LOAD, config_file, 0);
										WM_FreePatches();
										free(config_dir);
										free(line_tokens);
										free(config_buffer);
										return -1;
									}
									tmp_patch = tmp_patch->next;
									tmp_patch->patchid = patchid;
									tmp_patch->filename = NULL;
									tmp_patch->amp = 1024;
									tmp_patch->note = 0;
									tmp_patch->next = NULL;
									tmp_patch->first_sample = NULL;
									tmp_patch->loaded = 0;
									tmp_patch->inuse_count = 0;
								}
							}
						}
						if (!line_tokens[1]) {
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG,
									"(missing name in patch line)", 0);
							_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
									config_file, 0);
							WM_FreePatches();
							free(config_dir);
							free(line_tokens);
							free(config_buffer);
							return -1;
						} else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) {
							tmp_patch->filename = (char*)malloc(
									strlen(config_dir) + strlen(line_tokens[1])
											+ 5);
							if (tmp_patch->filename == NULL) {
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
										NULL, 0);
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
										config_file, 0);
								WM_FreePatches();
								free(config_dir);
								free(line_tokens);
								free(config_buffer);
								return -1;
							}
							strcpy(tmp_patch->filename, config_dir);
							strcat(tmp_patch->filename, line_tokens[1]);
						} else {
							if (!(tmp_patch->filename = wm_strdup(line_tokens[1]))) {
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,
										NULL, 0);
								_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD,
										config_file, 0);
								WM_FreePatches();
								free(config_dir);
								free(line_tokens);
								free(config_buffer);
								return -1;
							}
						}
						if (strnicmp(
								&tmp_patch->filename[strlen(tmp_patch->filename)
										- 4], ".pat", 4) != 0) {
							strcat(tmp_patch->filename, ".pat");
						}
						tmp_patch->env[0].set = 0x00;
						tmp_patch->env[1].set = 0x00;
						tmp_patch->env[2].set = 0x00;
						tmp_patch->env[3].set = 0x00;
						tmp_patch->env[4].set = 0x00;
						tmp_patch->env[5].set = 0x00;
						tmp_patch->keep = 0;
						tmp_patch->remove = 0;

						token_count = 0;
						while (line_tokens[token_count]) {
							if (strnicmp(line_tokens[token_count], "amp=", 4)
									== 0) {
								if (!wm_isdigit(line_tokens[token_count][4])) {
									_WM_ERROR(__FUNCTION__, __LINE__,
											WM_ERR_INVALID_ARG,
											"(syntax error in patch line)", 0);
								} else {
									tmp_patch->amp = (atoi(
											&line_tokens[token_count][4]) << 10)
											/ 100;
								}
							} else if (strnicmp(line_tokens[token_count],
									"note=", 5) == 0) {
								if (!wm_isdigit(line_tokens[token_count][5])) {
									_WM_ERROR(__FUNCTION__, __LINE__,
											WM_ERR_INVALID_ARG,
											"(syntax error in patch line)", 0);
								} else {
									tmp_patch->note = atoi(
											&line_tokens[token_count][5]);
								}
							} else if (strnicmp(line_tokens[token_count],
									"env_time", 8) == 0) {
								if ((!wm_isdigit(line_tokens[token_count][8]))
										|| (!wm_isdigit(
												line_tokens[token_count][10]))
										|| (line_tokens[token_count][9] != '=')) {
									_WM_ERROR(__FUNCTION__, __LINE__,
											WM_ERR_INVALID_ARG,
											"(syntax error in patch line)", 0);
								} else {
									unsigned int env_no = atoi(
											&line_tokens[token_count][8]);
									if (env_no > 5) {
										_WM_ERROR(__FUNCTION__, __LINE__,
												WM_ERR_INVALID_ARG,
												"(syntax error in patch line)",
												0);
									} else {
										tmp_patch->env[env_no].time =
												(float) atof(
														&line_tokens[token_count][10]);
										if ((tmp_patch->env[env_no].time
												> 45000.0f)
												|| (tmp_patch->env[env_no].time
														< 1.47f)) {
											_WM_ERROR(__FUNCTION__, __LINE__,
													WM_ERR_INVALID_ARG,
													"(range error in patch line)",
													0);
											tmp_patch->env[env_no].set &= 0xFE;
										} else {
											tmp_patch->env[env_no].set |= 0x01;
										}
									}
								}
							} else if (strnicmp(line_tokens[token_count],
									"env_level", 9) == 0) {
								if ((!wm_isdigit(line_tokens[token_count][9]))
										|| (!wm_isdigit(
												line_tokens[token_count][11]))
										|| (line_tokens[token_count][10] != '=')) {
									_WM_ERROR(__FUNCTION__, __LINE__,
											WM_ERR_INVALID_ARG,
											"(syntax error in patch line)", 0);
								} else {
									unsigned int env_no = atoi(
											&line_tokens[token_count][9]);
									if (env_no > 5) {
										_WM_ERROR(__FUNCTION__, __LINE__,
												WM_ERR_INVALID_ARG,
												"(syntax error in patch line)",
												0);
									} else {
										tmp_patch->env[env_no].level =
												(float) atof(
														&line_tokens[token_count][11]);
										if ((tmp_patch->env[env_no].level > 1.0f)
												|| (tmp_patch->env[env_no].level
														< 0.0f)) {
											_WM_ERROR(__FUNCTION__, __LINE__,
													WM_ERR_INVALID_ARG,
													"(range error in patch line)",
													0);
											tmp_patch->env[env_no].set &= 0xFD;
										} else {
											tmp_patch->env[env_no].set |= 0x02;
										}
									}
								}
							} else if (stricmp(line_tokens[token_count],
									"keep=loop") == 0) {
								tmp_patch->keep |= SAMPLE_LOOP;
							} else if (stricmp(line_tokens[token_count],
									"keep=env") == 0) {
								tmp_patch->keep |= SAMPLE_ENVELOPE;
							} else if (stricmp(line_tokens[token_count],
									"remove=sustain") == 0) {
								tmp_patch->remove |= SAMPLE_SUSTAIN;
							} else if (stricmp(line_tokens[token_count],
									"remove=clamped") == 0) {
								tmp_patch->remove |= SAMPLE_CLAMPED;
							}
							token_count++;
						}
					}
				}
				/* free up tokens */
				free(line_tokens);
			}
			line_start_ptr = config_ptr + 1;
		}
		config_ptr++;
	}

	free(config_buffer);
	free(config_dir);

	return 0;
}