Compare commits
	
		
			14 Commits
		
	
	
		
			v1.0.0-rc2
			...
			b726d5ba75
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b726d5ba75 | |||
| bfb587360d | |||
| f964ef7b60 | |||
| dd05449f36 | |||
| 3ff626134e | |||
| 29fdc841b7 | |||
| dc30188593 | |||
| 2bea5d288c | |||
| 8a0226a5ea | |||
| ed6373473c | |||
| 80b5f5b1b3 | |||
| 4fab6ffd3a | |||
| 0ee19eaea4 | |||
| 26eb480343 | 
							
								
								
									
										2
									
								
								3rdparty/libfort
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								3rdparty/libfort
									
									
									
									
										vendored
									
									
								
							 Submodule 3rdparty/libfort updated: 41237162a9...5a8f9312bd
									
								
							| @@ -1,4 +1,4 @@ | ||||
| cmake_minimum_required(VERSION 3.5) | ||||
| cmake_minimum_required(VERSION 3.5...3.18) | ||||
|  | ||||
| project(patchelfcrc LANGUAGES C) | ||||
|  | ||||
| @@ -28,8 +28,6 @@ pkg_check_modules(ELF REQUIRED libelf) | ||||
| find_package(Doxygen) | ||||
| find_package(LibXml2 REQUIRED) | ||||
|  | ||||
| add_subdirectory(man) | ||||
|  | ||||
| aux_source_directory("src" CFILES) | ||||
|  | ||||
| set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") | ||||
| @@ -37,11 +35,14 @@ set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") | ||||
| add_custom_target( | ||||
| 		version-header | ||||
| 	COMMAND | ||||
| 		mkdir -p ${GEN_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/gen_version_header.sh" "${GEN_HEADER_PATH}/version.h" | ||||
| 		${CMAKE_COMMAND} -D SRC=${CMAKE_SOURCE_DIR}/version.h.template | ||||
| 					 -D DST=${GEN_HEADER_PATH}/version.h | ||||
| 					 -P ${CMAKE_SOURCE_DIR}/GenerateVersion.cmake | ||||
| 	WORKING_DIRECTORY | ||||
| 		${CMAKE_CURRENT_SOURCE_DIR} | ||||
| 	COMMENT "Generating version header" | ||||
| 	) | ||||
| 	add_subdirectory(man) | ||||
|  | ||||
| add_custom_target(schema-header DEPENDS "${GEN_HEADER_PATH}/schema-blob.h") | ||||
| add_custom_command( | ||||
| @@ -66,7 +67,8 @@ target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS} ${LIBXML2_LI | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE ${ELF_INCLUDE_DIRS}) | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE "include") | ||||
| add_dependencies(${PROJECT_NAME} version-header schema-header) | ||||
| add_dependencies(${PROJECT_NAME} schema-header) | ||||
| add_dependencies(${PROJECT_NAME} version-header) | ||||
|  | ||||
| if (DOXYGEN_FOUND) | ||||
| 	set(DOXYFILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in") | ||||
| @@ -83,11 +85,13 @@ if (DOXYGEN_FOUND) | ||||
|  | ||||
| 	add_custom_target(doxygen-version-header | ||||
| 		COMMAND | ||||
| 			bash ${CMAKE_CURRENT_SOURCE_DIR}/doxygen/gen-version-string.sh "${CMAKE_CURRENT_BINARY_DIR}/doxyversion.in" | ||||
| 			${CMAKE_COMMAND} -D SRC="${CMAKE_SOURCE_DIR}/doxyversion.in.template" | ||||
| 					 -D DST="${CMAKE_CURRENT_BINARY_DIR}/doxyversion.in" | ||||
| 					 -P ${CMAKE_SOURCE_DIR}/GenerateVersion.cmake | ||||
| 		WORKING_DIRECTORY | ||||
| 			${CMAKE_CURRENT_SOURCE_DIR} | ||||
| 	) | ||||
| else (DOXYGEN_FOUND) | ||||
| else  (DOXYGEN_FOUND) | ||||
| 	message("${BoldMagenta}Doxygen needs to be installed to generate the doxygen documentation${ColorReset}") | ||||
| 	message("${BoldMagenta}doxygen target will not be available${ColorReset}") | ||||
| endif (DOXYGEN_FOUND) | ||||
| endif  (DOXYGEN_FOUND) | ||||
|   | ||||
							
								
								
									
										26
									
								
								GenerateVersion.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								GenerateVersion.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| find_package(Git) | ||||
|  | ||||
| if(GIT_EXECUTABLE) | ||||
|   get_filename_component(WORKING_DIR ${SRC} DIRECTORY) | ||||
|   execute_process( | ||||
|     COMMAND ${GIT_EXECUTABLE} describe --always --dirty | ||||
|     WORKING_DIRECTORY ${WORKING_DIR} | ||||
|     OUTPUT_VARIABLE PROGRAM_GIT_VERSION | ||||
|     RESULT_VARIABLE ERROR_CODE | ||||
|     OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|     ) | ||||
|  | ||||
|   if(NOT ERROR_CODE EQUAL "0") | ||||
|     set(PROGRAM_GIT_VERSION "") | ||||
|   endif() | ||||
|  | ||||
| endif() | ||||
|  | ||||
| if(PROGRAM_GIT_VERSION STREQUAL "") | ||||
|   set(PROGRAM_GIT_VERSION 0.0.0-unknown) | ||||
|   message(WARNING "Failed to determine version from Git tags. Using default version \"${PROGRAM_GIT_VERSION}\".") | ||||
| else() | ||||
| message("Git Version: \"${PROGRAM_GIT_VERSION}\".") | ||||
| endif() | ||||
|  | ||||
| configure_file(${SRC} ${DST} @ONLY) | ||||
							
								
								
									
										1
									
								
								doxyversion.in.template
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doxyversion.in.template
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| @PROGRAM_GIT_VERSION@ | ||||
| @@ -1 +0,0 @@ | ||||
| echo `git describe --tags --always --dirty` | ||||
| @@ -1,11 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| if [[ -z $1 ]]; then | ||||
| 	exit -1; | ||||
| fi | ||||
|  | ||||
| ver=`git describe --tags --always --dirty` | ||||
| echo "#ifndef _VERSION_GENERATED_H_" > $1 | ||||
| echo "#define _VERSION_GENERATED_H_" >> $1 | ||||
| echo "#define GIT_VERSION_STRING \"$ver\"" >> $1 | ||||
| echo "#endif /* _VERSION_GENERATED_H_ */" >> $1 | ||||
| @@ -21,14 +21,25 @@ | ||||
|  | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__) | ||||
| /** | ||||
|  * @brief Setting for reporting to console. | ||||
|  */ | ||||
| enum reporting_color_mode { | ||||
|     COLOR_MODE_DETECT, /**< @brief Automatically detect if tty. If tty, color is used */ | ||||
|     COLOR_MODE_COLOR, /**< @brief Force color mode on stderr */ | ||||
|     COLOR_MODE_COLOR_OFF, /**< @brief Force no color on stderr */ | ||||
| }; | ||||
|  | ||||
| #define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VA_ARGS__) | ||||
| void print_err(const char *fmt, ...); | ||||
|  | ||||
| void print_warn(const char *fmt, ...); | ||||
|  | ||||
| void print_debug(const char *fmt, ...); | ||||
|  | ||||
| void reporting_enable_verbose(void); | ||||
| void reporting_enable_verbose(bool state); | ||||
|  | ||||
| bool reporting_get_verbosity(void); | ||||
|  | ||||
| void reporting_init(enum reporting_color_mode mode); | ||||
|  | ||||
| #endif /* _REPORTING_H_ */ | ||||
|   | ||||
 Submodule linklist-lib updated: c20b5c2528...fdd99bad48
									
								
							| @@ -61,7 +61,7 @@ | ||||
| : Export the calculated files to an XML file *XMLFILE*. | ||||
|  | ||||
| **--import**=*XMLFILE* | ||||
| : Import the CRCs from an XML file *XMLFILE* and do not caclulate anything in the given *ELF* | ||||
| : Import the CRCs from an XML file *XMLFILE* and do not calculate anything in the given *ELF* | ||||
|  | ||||
| **--help**, **-h**, **-?** | ||||
| : Print help. | ||||
| @@ -84,6 +84,9 @@ | ||||
| **--usage** | ||||
| : Print usage hints on command line options. | ||||
|  | ||||
| **--no-color** | ||||
| : Force output on stdout and stderr to be pure text without color codes. | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| **patchelfcrc** --list-crcs | ||||
| @@ -131,8 +134,8 @@ | ||||
|  | ||||
| **patchelfcrc** -l -g word --start-magic=0x12345678 --end-magic=0x8754321 -p crc-32-mpeg -f bare -O .outputsection -S .text executable.elf | ||||
| : Calculate the CRC over *.text* section and place the result in the *.outputsection* section. | ||||
| The output sections start and end are checked for the given magic numbers in order to assure correct memory layout. | ||||
| *CRC-32-MPEG* is used as CRC algorothm. | ||||
| The output sections start and end are checked for the given magic numbers in order to ensure correct memory layout. | ||||
| *CRC-32-MPEG* is used as CRC algorithm. | ||||
| The memory is interpreted as *little endian* and the CRC calculation granularity is a 32 bit *word*. | ||||
|  | ||||
| # BUGS | ||||
|   | ||||
| @@ -470,12 +470,12 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_l | ||||
| 		case 1: | ||||
| 			print_debug("ELF Endianess: little\n"); | ||||
| 			if (!expect_little_endian) | ||||
| 				print_err("Big endian format expected. File is little endian. Double check settings!\n"); | ||||
| 				print_warn("Big endian format expected. File is little endian. Double check settings!\n"); | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			print_debug("ELF Endianess: big\n"); | ||||
| 			if (expect_little_endian) | ||||
| 				print_err("Little endian format expected. File is big endian. Double check settings!\n"); | ||||
| 				print_warn("Little endian format expected. File is big endian. Double check settings!\n"); | ||||
| 			break; | ||||
| 		default: | ||||
| 			print_err("Cannot determine endianess of ELF file. EI_DATA is: %d\n", ident[5]); | ||||
| @@ -561,25 +561,24 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio | ||||
| 	/* Find section */ | ||||
| 	sec = find_section_in_list(ep->sections, section); | ||||
| 	if (!sec) { | ||||
| 		print_err("Cannot find section %s\n", section); | ||||
| 		print_err("Cannot find section '%s'\n", section); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	data = elf_getdata(sec->scn, NULL); | ||||
| 	if (!data) { | ||||
| 		print_err("Error reading section data from %s: %s\n", section, elf_errmsg(-1)); | ||||
| 		print_err("Error reading section data from '%s': %s\n", section, elf_errmsg(-1)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	print_debug("Section data length: %lu\n", data->d_size); | ||||
| 	if (!data->d_size) { | ||||
| 		print_err("Section %s contains no data.\n", section); | ||||
| 		print_err("Section '%s' contains no data.\n", section); | ||||
| 		return -2; | ||||
| 	} | ||||
|  | ||||
| 	/* NOBIT sections have a length but no data in the file. Abort in this case */ | ||||
| 	if (!data->d_buf) { | ||||
| 		print_err("Section %s does not contain loadable data.\n", section); | ||||
| 		print_err("Section '%s' does not contain loadable data.\n", section); | ||||
| 		return -2; | ||||
| 	} | ||||
|  | ||||
| @@ -593,7 +592,7 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio | ||||
| 		/* Check granularity vs size of section */ | ||||
| 		padding_count = (gran_in_bytes - data->d_size % gran_in_bytes) % gran_in_bytes; | ||||
| 		if (padding_count) { | ||||
| 			print_err("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n", | ||||
| 			print_warn("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n", | ||||
| 				  section, padding_count); | ||||
| 		} | ||||
|  | ||||
| @@ -633,7 +632,7 @@ static size_t calculate_needed_space_for_crcs(enum crc_format format, | ||||
| 		break; | ||||
| 	default: | ||||
| 		needed_space = 0; | ||||
| 		print_err("Unsupported CRC output format\n"); | ||||
| 		print_err("Unsupported CRC output format.\n"); | ||||
| 	} | ||||
| 	/* Add existing magic numbers to required space */ | ||||
| 	if (check_start_magic) { | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -40,8 +40,10 @@ const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] co | ||||
| #define ARG_KEY_IMPORT (6) | ||||
| #define ARG_KEY_USE_VMA (7) | ||||
| #define ARG_KEY_XSD (8) | ||||
| #define ARG_KEY_FORCE_NO_COLOR (9) | ||||
|  | ||||
| struct command_line_options { | ||||
| 	bool force_nocolor; | ||||
| 	bool little_endian; | ||||
| 	bool dry_run; | ||||
| 	bool verbose; | ||||
| @@ -104,6 +106,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) | ||||
| 	case ARG_KEY_USE_VMA: | ||||
| 		args->use_vma = true; | ||||
| 		break; | ||||
| 	case ARG_KEY_FORCE_NO_COLOR: | ||||
| 		args->force_nocolor = true; | ||||
| 		break; | ||||
| 	case 'p': | ||||
| 		/* Polyniomial */ | ||||
| 		args->crc.polynomial = strtoull(arg, &endptr, 0); | ||||
| @@ -195,6 +200,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op | ||||
| 		{"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from file", 3}, | ||||
| 		{"xsd", ARG_KEY_XSD, 0, 0, "Print XSD to stdout", 0}, | ||||
| 		{"use-vma", ARG_KEY_USE_VMA, 0, 0, "Use the VMA instead of the LMA for struct output", 2}, | ||||
| 		{"no-color", ARG_KEY_FORCE_NO_COLOR, 0, 0, "Force the output to be text only without colors", 0}, | ||||
| 		/* Sentinel */ | ||||
| 		{NULL, 0, 0, 0, NULL, 0} | ||||
| 	}; | ||||
| @@ -233,12 +239,11 @@ static void prepare_default_opts(struct command_line_options *opts) | ||||
| 	opts->output_section = NULL; | ||||
| 	opts->export_xml = NULL; | ||||
| 	opts->import_xml = NULL; | ||||
|     opts->force_nocolor = false; | ||||
| } | ||||
|  | ||||
| static void print_verbose_start_info(const struct command_line_options *cmd_opts) | ||||
| { | ||||
| 	int i; | ||||
| 	SlList *list_iter; | ||||
| 	const struct named_crc *predef_crc; | ||||
|  | ||||
| 	print_debug("Start CRC patching\n"); | ||||
| @@ -272,11 +277,6 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts | ||||
|  | ||||
| 	if (cmd_opts->import_xml) | ||||
| 		print_debug("Import CRCs from '%s'\n", cmd_opts->import_xml); | ||||
|  | ||||
| 	if (cmd_opts->section_list) { | ||||
| 		for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) | ||||
| 			print_debug("Input section [%d]: \"%s\"\n", i, (const char *)list_iter->data); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void free_cmd_args(struct command_line_options *opts) | ||||
| @@ -425,8 +425,11 @@ int main(int argc, char **argv) | ||||
| 		goto free_cmds; | ||||
| 	} | ||||
|  | ||||
| 	/* Initialize console output */ | ||||
| 	reporting_init(cmd_opts.force_nocolor ? COLOR_MODE_COLOR_OFF : COLOR_MODE_DETECT); | ||||
|  | ||||
| 	if (cmd_opts.verbose || cmd_opts.dry_run) | ||||
| 		reporting_enable_verbose(); | ||||
| 		reporting_enable_verbose(true); | ||||
|  | ||||
| 	print_verbose_start_info(&cmd_opts); | ||||
|  | ||||
| @@ -450,7 +453,7 @@ int main(int argc, char **argv) | ||||
| 		print_warn("--use-vma option only has an effect when exporting as struct output.\n"); | ||||
|  | ||||
| 	if (!cmd_opts.output_section && cmd_opts.export_xml == NULL) | ||||
| 		print_err("No output section / XML export specified. Will continue but not create any output\n"); | ||||
| 		print_warn("No output section or XML export specified. Will continue but not create any output.\n"); | ||||
|  | ||||
| 	/* Prepare libelf for use with the latest ELF version */ | ||||
| 	elf_version(EV_CURRENT); | ||||
| @@ -492,7 +495,7 @@ int main(int argc, char **argv) | ||||
|  | ||||
| 	if (cmd_opts.export_xml) { | ||||
| 		if (xml_write_crcs_to_file(cmd_opts.export_xml, crc_data)) { | ||||
| 			print_err("Error during XML generation\n"); | ||||
| 			print_err("Error during XML generation.\n"); | ||||
| 			ret = -3; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										101
									
								
								src/reporting.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								src/reporting.c
									
									
									
									
									
								
							| @@ -19,9 +19,66 @@ | ||||
| #include <patchelfcrc/reporting.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| static bool global_verbosity_state = false; | ||||
| static bool reporting_use_color = false; | ||||
|  | ||||
| #define COLOR_RESET "\e[0m" | ||||
|  | ||||
| #define COLOR_BOLD_RED "\e[31;1m" | ||||
| #define COLOR_RED "\e[31m" | ||||
|  | ||||
| #define COLOR_BOLD_YELLOW "\e[33;1m" | ||||
| #define COLOR_YELLOW "\e[33m" | ||||
|  | ||||
|  | ||||
| void print_err(const char *fmt, ...) | ||||
| { | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
|  | ||||
| 	/* Set color */ | ||||
| 	if (reporting_use_color) | ||||
| 		fprintf(stderr, COLOR_BOLD_RED "[ERR]" COLOR_RESET " " COLOR_RED); | ||||
| 	else | ||||
| 		fprintf(stderr, "[ERR] "); | ||||
|  | ||||
|  | ||||
| 	vfprintf(stderr, fmt, va); | ||||
|  | ||||
| 	/* Reset color */ | ||||
| 	if (reporting_use_color) { | ||||
| 		fprintf(stderr, COLOR_RESET); | ||||
| 	} | ||||
|  | ||||
| 	va_end(va); | ||||
| } | ||||
|  | ||||
| void print_warn(const char *fmt, ...) | ||||
| { | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
|  | ||||
| 	/* Set color */ | ||||
| 	if (reporting_use_color) | ||||
| 		fprintf(stderr, COLOR_BOLD_YELLOW "[WARN]" COLOR_RESET " " COLOR_YELLOW); | ||||
| 	else | ||||
| 		fprintf(stderr, "[WARN] "); | ||||
|  | ||||
|  | ||||
| 	vfprintf(stderr, fmt, va); | ||||
|  | ||||
| 	/* Reset color */ | ||||
| 	if (reporting_use_color) { | ||||
| 		fprintf(stderr, COLOR_RESET); | ||||
| 	} | ||||
|  | ||||
| 	va_end(va); | ||||
| } | ||||
|  | ||||
| void print_debug(const char *fmt, ...) | ||||
| { | ||||
| @@ -34,12 +91,52 @@ void print_debug(const char *fmt, ...) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void reporting_enable_verbose(void) | ||||
| void reporting_enable_verbose(bool state) | ||||
| { | ||||
| 	global_verbosity_state = true; | ||||
| 	global_verbosity_state = state; | ||||
| } | ||||
|  | ||||
| bool reporting_get_verbosity(void) | ||||
| { | ||||
| 	return global_verbosity_state; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Check whether stderr supports colors. | ||||
|  * @note This function checks for a tty and the TERM environment variable. It has to contain "xterm". | ||||
|  * @return true if colors are supported | ||||
|  * @return false if no colors should be used | ||||
|  */ | ||||
| static bool stderr_supports_colors(void) | ||||
| { | ||||
| 	const char *env_var; | ||||
| 	const char *tmp; | ||||
|  | ||||
| 	if (isatty(2) != 1) | ||||
| 		return false; | ||||
|  | ||||
| 	env_var = getenv("TERM"); | ||||
| 	if (!env_var) | ||||
| 		return false; | ||||
|  | ||||
| 	tmp = strstr(env_var, "xterm"); | ||||
| 	if (!tmp) | ||||
| 		return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void reporting_init(enum reporting_color_mode mode) | ||||
| { | ||||
| 	switch (mode) { | ||||
| 	case COLOR_MODE_COLOR: | ||||
| 		reporting_use_color = true; | ||||
| 		break; | ||||
| 	case COLOR_MODE_COLOR_OFF: | ||||
| 		reporting_use_color = false; | ||||
| 		break; | ||||
| 	default: /* Auto detect case and invalid settings */ | ||||
| 		reporting_use_color = stderr_supports_colors(); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								version.h.template
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								version.h.template
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| #ifndef _GENRATED_VERSION_H_ | ||||
| #define _GENRATED_VERSION_H_ | ||||
| #define GIT_VERSION_STRING "@PROGRAM_GIT_VERSION@" | ||||
| #endif /* _GENRATED_VERSION_H_ */ | ||||
		Reference in New Issue
	
	Block a user