Files
FreeRDP/tools/update-settings-tests
akallabeth d03b4b91d5 [cmake,freerdp] add WITH_FREERDP_3x_DEPRECATED
This new CMake option (ON by default) allows building the library with
all symbols deprecated during 3.x release cycle disabled.
This allows compatibility testing external applications for future
FreeRDP 4.x support
2025-03-04 13:26:45 +01:00

413 lines
16 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import sys
def get_values(entry_dict, entry_type):
values = []
if '*' == entry_type:
for key in list(entry_dict.keys()):
if entry_type in key:
values += entry_dict[key]
entry_dict.pop(key, None)
elif entry_type in dict(entry_dict):
values = entry_dict[entry_type]
entry_dict.pop(entry_type, None)
if values:
return sorted(values)
return values
def get_keys(entry_dict, entry_type, values):
l = list()
if '*' == entry_type:
dval = dict()
for key in list(entry_dict.keys()):
if entry_type in key:
xval = entry_dict[key]
for val in xval:
dval[val] = key
for val in list(values):
key = dval[val]
l.append(key)
return l
def write_entry(f, entry_dict, entry_type, entry_name):
values = get_values(entry_dict, entry_type)
if not values:
return
f.write('#define have_' + entry_name.lower() + '_list_indices\n')
f.write('static const size_t ' + entry_name.lower() + '_list_indices[] =\n')
f.write('{\n')
for val in values:
f.write('\tFreeRDP_' + val + ',\n')
f.write('};\n\n')
def write_str_case(f, entry_idx, val):
entry_types = ['BOOL', 'UINT16', 'INT16', 'UINT32', 'INT32', 'UINT64', 'INT64', 'STRING', 'POINTER']
f.write('\t\t{FreeRDP_' + val + ', FREERDP_SETTINGS_TYPE_' + str(entry_types[entry_idx]) + ', "FreeRDP_' + val + '"},\n')
def write_str(f, entry_dict):
f.write('typedef enum {\n')
f.write('\tFREERDP_SETTINGS_TYPE_BOOL,\n')
f.write('\tFREERDP_SETTINGS_TYPE_UINT16,\n')
f.write('\tFREERDP_SETTINGS_TYPE_INT16,\n')
f.write('\tFREERDP_SETTINGS_TYPE_UINT32,\n')
f.write('\tFREERDP_SETTINGS_TYPE_INT32,\n')
f.write('\tFREERDP_SETTINGS_TYPE_UINT64,\n')
f.write('\tFREERDP_SETTINGS_TYPE_INT64,\n')
f.write('\tFREERDP_SETTINGS_TYPE_STRING,\n')
f.write('\tFREERDP_SETTINGS_TYPE_POINTER\n')
f.write('} FREERDP_SETTINGS_TYPE;\n')
f.write('\n')
f.write('struct settings_str_entry {\n')
f.write('\tSSIZE_T id;\n')
f.write('\tSSIZE_T type;\n')
f.write('\tconst char* str;\n')
f.write('};\n')
f.write('static const struct settings_str_entry settings_map[] =\n')
f.write('{\n')
entry_types = ['BOOL', 'UINT16', 'INT16', 'UINT32', 'INT32', 'UINT64', 'INT64', 'char*', '*']
for entry_type in entry_types:
values = get_values(entry_dict, entry_type)
if values:
for val in values:
write_str_case(f, entry_types.index(entry_type), val)
f.write('};\n\n')
f.write('\n')
def write_getter_case(f, val, cast, typestr):
f.write('\t\tcase ')
if typestr:
f.write('(' + typestr + ')')
f.write('FreeRDP_' + val + ':\n')
f.write('\t\t\treturn ' + cast + 'settings->' + val + ';\n\n')
def write_getter_body(f, values, ret, keys, isPointer, compat_values, typestr, entry_type):
f.write('{\n')
f.write('\tWINPR_ASSERT(settings);\n\n')
f.write('\tswitch (id)\n')
f.write('\t{\n')
if values:
for i in range(len(values)):
val = values[i]
cast = ''
if isPointer and keys:
key = keys[i]
if key != 'void*':
cast = '(void*)'
write_getter_case(f, val, cast, None)
if compat_values:
f.write('#if defined(WITH_FREERDP_3x_DEPRECATED)\n')
for i in range(len(compat_values)):
val = compat_values[i]
cast = '(' + entry_type + ')'
f.write('\t\t// API Compatibility section, remove with FreeRDP 4.x\n')
write_getter_case(f, val, cast, typestr)
f.write('#endif\n')
f.write('\t\tdefault:\n')
f.write('\t\t\tWLog_ERR(TAG, "Invalid key index %" PRIuz " [%s|%s]", id, freerdp_settings_get_name_for_key(id), freerdp_settings_get_type_name_for_key(id));\n')
f.write('\t\t\tWINPR_ASSERT(FALSE);\n')
f.write('\t\t\treturn ' + ret + ';\n')
f.write('\t}\n')
f.write('}\n\n')
def write_getter(f, entry_dict, entry_type, entry_name, postfix, compat_dict):
isString = 'string' in entry_name
isPointer = 'pointer' in entry_name
copy = dict(entry_dict)
values = get_values(entry_dict, entry_type)
compat_values = get_values(compat_dict, entry_type)
keys = get_keys(copy, entry_type, values)
typestr = 'FreeRDP_Settings_Keys_' + entry_name.capitalize()
typestr = typestr.replace('_Uint', '_UInt')
if isPointer:
f.write('void*')
elif isString:
f.write('const ' + entry_type)
else:
f.write(entry_type)
if isPointer:
f.write(' freerdp_settings_get_pointer_writable(rdpSettings* settings, ' + typestr + ' id)\n')
else:
f.write(' freerdp_settings_get_' + entry_name.lower() + '(WINPR_ATTR_UNUSED const rdpSettings* settings, WINPR_ATTR_UNUSED ' + typestr + ' id)\n')
if isString or isPointer:
ret = 'NULL';
elif 'bool' in entry_name:
ret = 'FALSE';
else:
ret = '0';
write_getter_body(f, values, ret, keys, isPointer, compat_values, typestr, entry_type)
if isString:
f.write('char* freerdp_settings_get_' + entry_name.lower() + '_writable(rdpSettings* settings, ' + typestr + ' id)\n')
write_getter_body(f, values, ret, keys, isPointer, compat_values, typestr, entry_type)
def write_setter_case(f, val, postfix, isPointer, cast):
f.write('\t\tcase FreeRDP_' + val + ':\n')
if isPointer:
f.write('\t\t\tsettings->' + val + ' = ' + cast + ' cnv.v;\n')
f.write('\t\t\tbreak;\n\n')
elif not postfix:
f.write('\t\t\tsettings->' + val + ' = ' + cast + ' cnv.c;\n')
f.write('\t\t\tbreak;\n\n')
elif len(postfix) <= 1:
f.write('\t\t\treturn update_string' + postfix + '(&settings->' + val + ', cnv.c, len);\n\n')
else:
f.write('\t\t\treturn update_string' + postfix + '(&settings->' + val + ', cnv.cc, len, cleanup);\n\n')
def write_setter(f, entry_dict, entry_type, entry_name, postfix, compat_dict):
isString = 'string' in entry_name
isPointer = 'pointer' in entry_name
copy = dict(entry_dict)
values = get_values(entry_dict, entry_type)
compat_values = get_values(compat_dict, entry_type)
keys = get_keys(copy, entry_type, values)
typestr = 'FreeRDP_Settings_Keys_' + entry_name.capitalize()
typestr = typestr.replace('_Uint', '_UInt')
f.write('BOOL freerdp_settings_set_' + entry_name.lower())
f.write(postfix)
f.write('(WINPR_ATTR_UNUSED rdpSettings* settings, WINPR_ATTR_UNUSED ' + typestr + ' id, ')
if isString or isPointer:
f.write('const ')
if not isPointer:
f.write(entry_type + ' val')
else:
f.write('void* val')
if isString and len(postfix) <= 1:
f.write(', size_t len)\n')
elif isString:
f.write(', size_t len, BOOL cleanup)\n')
else:
f.write(')\n')
f.write('{\n')
f.write('\tunion\n')
f.write('\t{\n')
f.write('\t\tvoid* v;\n')
f.write('\t\tconst void* cv;\n')
if not isPointer:
f.write(' ' + entry_type + ' c;\n')
f.write(' const ' + entry_type + ' cc;\n')
f.write('} cnv;\n')
f.write('\tWINPR_ASSERT(settings);\n\n')
if isPointer:
f.write('\tcnv.cv = val;\n\n')
elif isString:
f.write('\tcnv.cc = val;\n\n')
else:
f.write('\tcnv.c = val;\n\n')
f.write('\tswitch (id)\n')
f.write('\t{\n')
if values:
count = 0
for val in values:
index = count
count += 1
cast = ''
if isPointer:
k = keys[index];
if k != 'void*' and len(k) > 0:
cast = '(' + k + ')'
write_setter_case(f, val, postfix, isPointer, cast)
if compat_values:
f.write('#if defined(WITH_FREERDP_3x_DEPRECATED)\n')
for val in compat_values:
cast = '(int32_t)'
f.write('\t\t// API Compatibility section, remove with FreeRDP 4.x\n')
write_setter_case(f, val, postfix, isPointer, cast)
f.write('#endif\n')
f.write('\t\tdefault:\n')
f.write('\t\t\tWLog_ERR(TAG, "Invalid key index %" PRIuz " [%s|%s]", id, freerdp_settings_get_name_for_key(id), freerdp_settings_get_type_name_for_key(id));\n')
f.write('\t\t\treturn FALSE;\n')
f.write('\t}\n')
f.write('\treturn TRUE;\n')
f.write('}\n\n')
f.write('\n')
if isString and len(postfix) <= 1:
f.write('BOOL freerdp_settings_set_string_len(rdpSettings* settings, FreeRDP_Settings_Keys_String id, const char* val, size_t len)\n')
f.write('{\n')
f.write('\treturn freerdp_settings_set_string_copy_(settings, id, val, len, TRUE);\n')
f.write('}\n')
f.write('\n')
f.write('BOOL freerdp_settings_set_string(rdpSettings* settings, FreeRDP_Settings_Keys_String id, const char* val)\n')
f.write('{\n')
f.write('\tsize_t len = 0;\n')
f.write('\tif (val) len = strlen(val);\n')
f.write('\treturn freerdp_settings_set_string_copy_(settings, id, val, len, TRUE);\n')
f.write('}\n')
f.write('\n')
name = os.path.dirname(os.path.realpath(__file__))
begin = "WARNING: this data structure is carefully padded for ABI stability!"
end = "WARNING: End of ABI stable zone!"
print('begin parsing settings header')
try:
type_list = dict()
with open(name + "/../include/freerdp/settings_types_private.h", "r") as f:
lines = f.readlines()
started = False
for line in lines:
if not started:
if begin in line:
started = True
continue
if end in line:
break
sline = line.strip()
if not sline:
continue
if sline.startswith('/'):
continue
if sline.startswith('*'):
continue
if 'padding' in sline:
continue
if 'version' in sline:
continue
if sline.startswith('SETTINGS_DEPRECATED(ALIGN64'):
sline = sline[27:].strip()
sline = sline[:sline.find(');')]
pair = sline.split()
if pair[0] in type_list:
type_list[pair[0]].append(pair[1])
else:
type_list[pair[0]] = [pair[1]]
with open(name + '/../libfreerdp/common/settings_getters.c', 'w+') as f:
f.write('/* Generated by ' + '' + ' */\n\n')
f.write('#include "../core/settings.h"\n\n')
f.write('#include <winpr/assert.h>\n')
f.write('#include <freerdp/settings.h>\n')
f.write('#include <freerdp/log.h>\n\n')
f.write('#define TAG FREERDP_TAG("common.settings")\n\n')
f.write('static void free_string(char** current, BOOL cleanup)\n')
f.write('{\n')
f.write('\tif (cleanup)\n')
f.write('\t{\n')
f.write('\t\tif (*current)\n')
f.write('\t\t\tmemset(*current, 0, strlen(*current));\n')
f.write('\t\tfree(*current);\n')
f.write('\t\t(*current) = NULL;\n')
f.write('\t}\n')
f.write('}\n\n')
f.write('static BOOL alloc_empty_string(char** current, const char* next, size_t next_len)\n')
f.write('{\n')
f.write('\tif (!next && (next_len > 0))\n')
f.write('\t{\n')
f.write('\t\t*current = calloc(next_len, 1);\n')
f.write('\t\treturn (*current != NULL);\n')
f.write('\t}\n')
f.write('\treturn FALSE;\n')
f.write('}\n\n')
f.write('static BOOL update_string_copy_(char** current, const char* next, size_t next_len, BOOL cleanup)\n')
f.write('{\n')
f.write('\tfree_string(current, cleanup);\n')
f.write('\n')
f.write('\tif (alloc_empty_string(current, next, next_len))\n')
f.write('\t\treturn TRUE;\n')
f.write('\n')
f.write('\t*current = (next ? strndup(next, next_len) : NULL);\n')
f.write('\treturn !next || (*current != NULL);\n')
f.write('}\n\n')
f.write('static BOOL update_string_(char** current, char* next, size_t next_len)\n')
f.write('{\n')
f.write('\tfree_string(current, TRUE);\n')
f.write('\n')
f.write('\tif (alloc_empty_string(current, next, next_len))\n')
f.write('\t\treturn TRUE;\n')
f.write('\n')
f.write('\t*current = next;\n')
f.write('\treturn !next || (*current != NULL);\n')
f.write('}\n\n')
getter_list = dict(type_list)
setter_list = dict(type_list)
setter_list2 = dict(type_list)
# Compatibility with older 3.x releases where the value was wrongly an unsigned type
compat_getter_list = dict()
compat_getter_list['UINT32'] = list()
compat_getter_list['UINT32'].append('MonitorLocalShiftX')
compat_getter_list['UINT32'].append('MonitorLocalShiftY')
compat_setter_list = dict(compat_getter_list)
write_getter(f, getter_list, 'BOOL', 'bool', '', compat_getter_list)
write_setter(f, setter_list, 'BOOL', 'bool', '', compat_setter_list)
write_getter(f, getter_list, 'UINT16', 'uint16', '', compat_getter_list)
write_setter(f, setter_list, 'UINT16', 'uint16', '', compat_setter_list)
write_getter(f, getter_list, 'INT16', 'int16', '', compat_getter_list)
write_setter(f, setter_list, 'INT16', 'int16', '', compat_setter_list)
write_getter(f, getter_list, 'UINT32', 'uint32', '', compat_getter_list)
write_setter(f, setter_list, 'UINT32', 'uint32', '', compat_setter_list)
write_getter(f, getter_list, 'INT32', 'int32', '', compat_getter_list)
write_setter(f, setter_list, 'INT32', 'int32', '', compat_setter_list)
write_getter(f, getter_list, 'UINT64', 'uint64', '', compat_getter_list)
write_setter(f, setter_list, 'UINT64', 'uint64', '', compat_setter_list)
write_getter(f, getter_list, 'INT64', 'int64', '', compat_getter_list)
write_setter(f, setter_list, 'INT64', 'int64', '', compat_setter_list)
write_getter(f, getter_list, 'char*', 'string', '_', compat_getter_list)
write_setter(f, setter_list, 'char*', 'string', '_', compat_setter_list)
write_setter(f, setter_list2, 'char*', 'string', '_copy_', compat_setter_list)
write_getter(f, getter_list, '*', 'pointer', '', compat_getter_list)
write_setter(f, setter_list, '*', 'pointer', '', compat_setter_list)
f.write('\n')
with open(name + '/../libfreerdp/common/settings_str.h', 'w+') as f:
f.write('/* Generated by ' + '' + ' */\n\n')
f.write('#ifndef FREERDP_CORE_SETTINGS_STR_H\n')
f.write('#define FREERDP_CORE_SETTINGS_STR_H\n\n')
f.write('#include "../core/settings.h"\n\n')
f.write('#include <freerdp/settings.h>\n')
f.write('#include <freerdp/log.h>\n\n')
f.write('#define TAG FREERDP_TAG("common.settings")\n\n')
getter_list = dict(type_list)
write_str(f, getter_list)
f.write('#endif\n')
f.write('\n')
with open(name + '/../libfreerdp/core/test/settings_property_lists.h', 'w+') as f:
f.write('#ifndef TEST_SETTINGS_PROPERTY_LISTS\n')
f.write('#define TEST_SETTINGS_PROPERTY_LISTS\n\n')
write_entry(f, type_list, 'BOOL', 'bool')
write_entry(f, type_list, 'UINT16', 'uint16')
write_entry(f, type_list, 'INT16', 'int16')
write_entry(f, type_list, 'UINT32', 'uint32')
write_entry(f, type_list, 'INT32', 'int32')
write_entry(f, type_list, 'UINT64', 'uint64')
write_entry(f, type_list, 'INT64', 'int64')
write_entry(f, type_list, 'char*', 'string')
write_entry(f, type_list, '*', 'pointer')
f.write('#endif /* TEST_SETTINGS_PROPERTY_LISTS */\n\n')
print('remaining:\n' + str(type_list))
except IOError as e:
print('failed to parse settings header ' + str(e))
sys.exit(-1)
print('ended parsing settings header')