mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-05 05:18:40 +00:00
merged path helper code from linker layer into main path layer
This commit is contained in:
+14
-3
@@ -129,17 +129,28 @@ hash_table_push_u64_u64(Arena *arena, HashTable *ht, U64 key, U64 value)
|
|||||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
|
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
hash_table_normalize_path_string(Arena *arena, String8 path)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
String8 result;
|
||||||
|
result = lower_from_str8(scratch.arena, path);
|
||||||
|
result = path_convert_slashes(arena, result, PathStyle_UnixAbsolute);
|
||||||
|
scratch_end(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal BucketNode *
|
internal BucketNode *
|
||||||
hash_table_push_path_string(Arena *arena, HashTable *ht, String8 path, String8 value)
|
hash_table_push_path_string(Arena *arena, HashTable *ht, String8 path, String8 value)
|
||||||
{
|
{
|
||||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
String8 path_canon = hash_table_normalize_path_string(arena, path);
|
||||||
return hash_table_push_string_string(arena, ht, path_canon, value);
|
return hash_table_push_string_string(arena, ht, path_canon, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal BucketNode *
|
internal BucketNode *
|
||||||
hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value)
|
hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value)
|
||||||
{
|
{
|
||||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
String8 path_canon = hash_table_normalize_path_string(arena, path);
|
||||||
U64 hash = hash_table_hasher(path_canon);
|
U64 hash = hash_table_hasher(path_canon);
|
||||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_u64 = value });
|
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_u64 = value });
|
||||||
}
|
}
|
||||||
@@ -147,7 +158,7 @@ hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value)
|
|||||||
internal BucketNode *
|
internal BucketNode *
|
||||||
hash_table_push_path_raw(Arena *arena, HashTable *ht, String8 path, void *value)
|
hash_table_push_path_raw(Arena *arena, HashTable *ht, String8 path, void *value)
|
||||||
{
|
{
|
||||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
String8 path_canon = hash_table_normalize_path_string(arena, path);
|
||||||
U64 hash = hash_table_hasher(path_canon);
|
U64 hash = hash_table_hasher(path_canon);
|
||||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_raw = value });
|
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_raw = value });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
// Code Base Extensions
|
// Code Base Extensions
|
||||||
|
|
||||||
#include "base_ext/base_inc.h"
|
#include "base_ext/base_inc.h"
|
||||||
#include "path_ext/path.h"
|
|
||||||
#include "hash_table.h"
|
#include "hash_table.h"
|
||||||
#include "thread_pool/thread_pool.h"
|
#include "thread_pool/thread_pool.h"
|
||||||
#include "codeview_ext/codeview.h"
|
#include "codeview_ext/codeview.h"
|
||||||
@@ -88,7 +87,6 @@
|
|||||||
#include "pdb_ext/pdb_builder.h"
|
#include "pdb_ext/pdb_builder.h"
|
||||||
|
|
||||||
#include "base_ext/base_inc.c"
|
#include "base_ext/base_inc.c"
|
||||||
#include "path_ext/path.c"
|
|
||||||
#include "hash_table.c"
|
#include "hash_table.c"
|
||||||
#include "thread_pool/thread_pool.c"
|
#include "thread_pool/thread_pool.c"
|
||||||
#include "codeview_ext/codeview.c"
|
#include "codeview_ext/codeview.c"
|
||||||
|
|||||||
@@ -1976,22 +1976,22 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
|||||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) {
|
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) {
|
||||||
String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]);
|
String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]);
|
||||||
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
|
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
|
||||||
config->image_name = make_file_name_with_ext(scratch.arena, name, ext);
|
config->image_name = path_replace_file_extension(scratch.arena, name, ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle empty /PDB
|
// handle empty /PDB
|
||||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) {
|
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) {
|
||||||
config->pdb_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("pdb"));
|
config->pdb_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("pdb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle empty /RAD_DEBUG_NAME
|
// handle empty /RAD_DEBUG_NAME
|
||||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) {
|
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) {
|
||||||
config->rad_debug_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("rdi"));
|
config->rad_debug_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("rdi"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle empty /IMPLIB
|
// handle empty /IMPLIB
|
||||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) {
|
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) {
|
||||||
config->imp_lib_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("lib"));
|
config->imp_lib_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("lib"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle empty /MANIFESTFILE
|
// handle empty /MANIFESTFILE
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext)
|
|
||||||
{
|
|
||||||
String8 file_name_no_ext = str8_chop_last_dot(file_name);
|
|
||||||
String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
path_char_from_style(PathStyle style)
|
|
||||||
{
|
|
||||||
String8 result = str8_zero();
|
|
||||||
switch (style) {
|
|
||||||
case PathStyle_Null: break;
|
|
||||||
case PathStyle_Relative: break;
|
|
||||||
case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break;
|
|
||||||
case PathStyle_UnixAbsolute: result = str8_lit("/"); break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
path_convert_slashes(Arena *arena, String8 path, PathStyle path_style)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List list = str8_split_path(scratch.arena, path);
|
|
||||||
StringJoin join = {0};
|
|
||||||
join.sep = path_char_from_style(path_style);
|
|
||||||
String8 result = str8_list_join(arena, &list, &join);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
path_canon_from_regular_path(Arena *arena, String8 path)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 result;
|
|
||||||
result = lower_from_str8(scratch.arena, path);
|
|
||||||
result = path_convert_slashes(arena, result, PathStyle_UnixAbsolute);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct {
|
|
||||||
String8 string;
|
|
||||||
PathStyle path_style;
|
|
||||||
} g_path_style_map[] = {
|
|
||||||
{ str8_lit_comp("windows"), PathStyle_WindowsAbsolute },
|
|
||||||
{ str8_lit_comp("unix"), PathStyle_UnixAbsolute },
|
|
||||||
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
|
||||||
};
|
|
||||||
|
|
||||||
internal PathStyle
|
|
||||||
path_style_from_string(String8 string)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < ArrayCount(g_path_style_map); ++i) {
|
|
||||||
if (str8_match(g_path_style_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
|
||||||
return g_path_style_map[i].path_style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PathStyle_Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
internal String8 make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext);
|
|
||||||
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
|
|
||||||
internal String8 path_canon_from_regular_path(Arena *arena, String8 path);
|
|
||||||
internal PathStyle path_style_from_string(String8 string);
|
|
||||||
|
|
||||||
+99
-34
@@ -1,29 +1,6 @@
|
|||||||
// Copyright (c) 2024 Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ allen: Path Helper Functions
|
|
||||||
|
|
||||||
internal StringMatchFlags
|
|
||||||
path_match_flags_from_os(OperatingSystem os)
|
|
||||||
{
|
|
||||||
StringMatchFlags flags = StringMatchFlag_SlashInsensitive;
|
|
||||||
switch(os)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case OperatingSystem_Windows:
|
|
||||||
{
|
|
||||||
flags |= StringMatchFlag_CaseInsensitive;
|
|
||||||
}break;
|
|
||||||
case OperatingSystem_Linux:
|
|
||||||
case OperatingSystem_Mac:
|
|
||||||
{
|
|
||||||
// NOTE(rjf): no-op
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src)
|
path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src)
|
||||||
{
|
{
|
||||||
@@ -122,14 +99,16 @@ path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal String8List
|
internal String8List
|
||||||
path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out){
|
path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out)
|
||||||
|
{
|
||||||
// analyze path
|
// analyze path
|
||||||
PathStyle path_style = path_style_from_str8(path_string);
|
PathStyle path_style = path_style_from_str8(path_string);
|
||||||
String8List path = str8_split_path(arena, path_string);
|
String8List path = str8_split_path(arena, path_string);
|
||||||
|
|
||||||
// prepend current path to convert relative -> absolute
|
// prepend current path to convert relative -> absolute
|
||||||
PathStyle path_style_full = path_style;
|
PathStyle path_style_full = path_style;
|
||||||
if (path.node_count != 0 && path_style == PathStyle_Relative){
|
if(path.node_count != 0 && path_style == PathStyle_Relative)
|
||||||
|
{
|
||||||
String8 current_path_string = os_get_current_path(arena);
|
String8 current_path_string = os_get_current_path(arena);
|
||||||
|
|
||||||
PathStyle current_path_style = path_style_from_str8(current_path_string);
|
PathStyle current_path_style = path_style_from_str8(current_path_string);
|
||||||
@@ -145,10 +124,11 @@ path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *s
|
|||||||
str8_path_list_resolve_dots_in_place(&path, path_style_full);
|
str8_path_list_resolve_dots_in_place(&path, path_style_full);
|
||||||
|
|
||||||
// return
|
// return
|
||||||
if (style_out != 0){
|
if(style_out != 0)
|
||||||
|
{
|
||||||
*style_out = path_style_full;
|
*style_out = path_style_full;
|
||||||
}
|
}
|
||||||
return(path);
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
@@ -160,19 +140,104 @@ path_normalized_from_string(Arena *arena, String8 path_string){
|
|||||||
|
|
||||||
String8 result = str8_path_list_join_by_style(arena, &path, style);
|
String8 result = str8_path_list_join_by_style(arena, &path, style);
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
path_match_normalized(String8 left, String8 right)
|
path_match_normalized(String8 left, String8 right)
|
||||||
{
|
{
|
||||||
B32 result = 0;
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
String8 left_normalized = path_normalized_from_string(scratch.arena, left);
|
||||||
|
String8 right_normalized = path_normalized_from_string(scratch.arena, right);
|
||||||
|
B32 result = str8_match(left_normalized, right_normalized, StringMatchFlag_CaseInsensitive);
|
||||||
|
scratch_end(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
path_char_from_style(PathStyle style)
|
||||||
|
{
|
||||||
|
String8 result = str8_zero();
|
||||||
|
switch (style)
|
||||||
{
|
{
|
||||||
Temp scratch = scratch_begin(0, 0);
|
case PathStyle_Null: break;
|
||||||
String8 left_normalized = path_normalized_from_string(scratch.arena, left);
|
case PathStyle_Relative: break;
|
||||||
String8 right_normalized = path_normalized_from_string(scratch.arena, right);
|
case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break;
|
||||||
result = str8_match(left_normalized, right_normalized, StringMatchFlag_CaseInsensitive);
|
case PathStyle_UnixAbsolute: result = str8_lit("/"); break;
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal StringMatchFlags
|
||||||
|
path_match_flags_from_os(OperatingSystem os)
|
||||||
|
{
|
||||||
|
StringMatchFlags flags = StringMatchFlag_SlashInsensitive;
|
||||||
|
switch(os)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
case OperatingSystem_Windows:
|
||||||
|
{
|
||||||
|
flags |= StringMatchFlag_CaseInsensitive;
|
||||||
|
}break;
|
||||||
|
case OperatingSystem_Linux:
|
||||||
|
case OperatingSystem_Mac:
|
||||||
|
{
|
||||||
|
// NOTE(rjf): no-op
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
path_convert_slashes(Arena *arena, String8 path, PathStyle path_style)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
String8List list = str8_split_path(scratch.arena, path);
|
||||||
|
StringJoin join = {0};
|
||||||
|
join.sep = path_char_from_style(path_style);
|
||||||
|
String8 result = str8_list_join(arena, &list, &join);
|
||||||
|
scratch_end(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
path_replace_file_extension(Arena *arena, String8 file_name, String8 ext)
|
||||||
|
{
|
||||||
|
String8 file_name_no_ext = str8_chop_last_dot(file_name);
|
||||||
|
String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
global read_only struct
|
||||||
|
{
|
||||||
|
String8 string;
|
||||||
|
PathStyle path_style;
|
||||||
|
} g_path_style_map[] =
|
||||||
|
{
|
||||||
|
{ str8_lit_comp(""), PathStyle_Null },
|
||||||
|
{ str8_lit_comp("relative"), PathStyle_Relative },
|
||||||
|
{ str8_lit_comp("windows"), PathStyle_WindowsAbsolute },
|
||||||
|
{ str8_lit_comp("unix"), PathStyle_UnixAbsolute },
|
||||||
|
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
||||||
|
};
|
||||||
|
|
||||||
|
internal PathStyle
|
||||||
|
path_style_from_string(String8 string)
|
||||||
|
{
|
||||||
|
for (U64 i = 0; i < ArrayCount(g_path_style_map); ++i)
|
||||||
|
{
|
||||||
|
if(str8_match(g_path_style_map[i].string, string, StringMatchFlag_CaseInsensitive))
|
||||||
|
{
|
||||||
|
return g_path_style_map[i].path_style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PathStyle_Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
path_string_from_style(PathStyle style)
|
||||||
|
{
|
||||||
|
Assert(style < ArrayCount(g_path_style_map));
|
||||||
|
return g_path_style_map[style].string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-4
@@ -5,13 +5,30 @@
|
|||||||
#define PATH_H
|
#define PATH_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ allen: Path Helper Functions
|
// Relative <-> Absolute Path
|
||||||
|
|
||||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
|
||||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
||||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Normal Path Helpers
|
||||||
|
|
||||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
||||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
||||||
internal B32 path_match_normalized(String8 left, String8 right);
|
internal B32 path_match_normalized(String8 left, String8 right);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Misc Helpers
|
||||||
|
|
||||||
|
internal String8 path_char_from_style(PathStyle style);
|
||||||
|
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
||||||
|
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
|
||||||
|
internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Enum <-> String
|
||||||
|
|
||||||
|
internal PathStyle path_style_from_string(String8 string);
|
||||||
|
internal String8 path_string_from_style(PathStyle style);
|
||||||
|
|
||||||
#endif //PATH_H
|
#endif //PATH_H
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "rdi_make/rdi_make_local.h"
|
#include "rdi_make/rdi_make_local.h"
|
||||||
#include "rdi_make/rdi_make_help.h"
|
#include "rdi_make/rdi_make_help.h"
|
||||||
#include "path/path.h"
|
#include "path/path.h"
|
||||||
#include "linker/path_ext/path.h"
|
|
||||||
#include "linker/hash_table.h"
|
#include "linker/hash_table.h"
|
||||||
#include "coff/coff.h"
|
#include "coff/coff.h"
|
||||||
#include "coff/coff_enum.h"
|
#include "coff/coff_enum.h"
|
||||||
@@ -65,7 +64,6 @@
|
|||||||
#include "rdi_make/rdi_make_local.c"
|
#include "rdi_make/rdi_make_local.c"
|
||||||
#include "rdi_make/rdi_make_help.c"
|
#include "rdi_make/rdi_make_help.c"
|
||||||
#include "path/path.c"
|
#include "path/path.c"
|
||||||
#include "linker/path_ext/path.c"
|
|
||||||
#include "linker/hash_table.c"
|
#include "linker/hash_table.c"
|
||||||
#include "coff/coff.c"
|
#include "coff/coff.c"
|
||||||
#include "coff/coff_enum.c"
|
#include "coff/coff_enum.c"
|
||||||
|
|||||||
Reference in New Issue
Block a user