mirror of https://github.com/PCSX2/pcsx2.git
parent
8696812d23
commit
b8596c6f2a
|
@ -25,13 +25,6 @@ optional_system_library(libzip)
|
|||
optional_system_library(SDL2)
|
||||
option(LTO_PCSX2_CORE "Enable LTO/IPO/LTCG on the subset of pcsx2 that benefits most from it but not anything else")
|
||||
|
||||
if(WIN32)
|
||||
set(DEFAULT_NATIVE_TOOLS ON)
|
||||
else()
|
||||
set(DEFAULT_NATIVE_TOOLS OFF)
|
||||
endif()
|
||||
option(USE_NATIVE_TOOLS "Uses c++ tools instead of ones written in scripting languages. OFF requires perl, ON may fail if cross compiling" ${DEFAULT_NATIVE_TOOLS})
|
||||
|
||||
if(DISABLE_BUILD_DATE OR openSUSE)
|
||||
message(STATUS "Disabling the inclusion of the binary compile date.")
|
||||
list(APPEND PCSX2_DEFS DISABLE_BUILD_DATE)
|
||||
|
|
|
@ -171,15 +171,6 @@ endif()
|
|||
add_subdirectory(3rdparty/lzma EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libchdr EXCLUDE_FROM_ALL)
|
||||
|
||||
if(USE_NATIVE_TOOLS)
|
||||
add_subdirectory(tools/bin2cpp EXCLUDE_FROM_ALL)
|
||||
set(BIN2CPP bin2cpp)
|
||||
set(BIN2CPPDEP bin2cpp)
|
||||
else()
|
||||
set(BIN2CPP perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl)
|
||||
set(BIN2CPPDEP ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl)
|
||||
endif()
|
||||
|
||||
# rapidyaml includes fast_float as a submodule, saves us pulling it in directly.
|
||||
# Normally, we'd just pull in the cmake project, and link to it, but... it seems to enable
|
||||
# permissive mode, which breaks other parts of PCSX2. So, we'll just create a target here
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# PCSX2 - PS2 Emulator for PCs
|
||||
# Copyright (C) 2002-2014 PCSX2 Dev Team
|
||||
#
|
||||
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
# ation, either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
|
||||
# find in perl is a PITA so let's do it easy for the moment
|
||||
#
|
||||
# find ./locales -name "pcsx2_Main.po" -exec ./linux_various/check_po_quality.pl {} \;
|
||||
|
||||
my $main = $ARGV[0];
|
||||
my $ico = $main;
|
||||
$ico =~ s/Main/Iconized/;
|
||||
|
||||
open(my $MAIN, "<$main") or die "failed to open $main";
|
||||
print "\nCheck $main\n";
|
||||
check_c_format($MAIN);
|
||||
|
||||
print "Check $ico\n";
|
||||
open(my $ICO1, "<$ico") or die "failed to open $ico";
|
||||
check_double_key($ICO1);
|
||||
open(my $ICO2, "<$ico") or die "failed to open $ico";
|
||||
check_c_format($ICO2);
|
||||
|
||||
sub check_double_key {
|
||||
my $file = shift;
|
||||
my $line;
|
||||
my $index;
|
||||
while ($line = <$file>) {
|
||||
if ($line =~ /^#~/) {
|
||||
next;
|
||||
}
|
||||
if ($line =~ /^#:\s*(.*)/) {
|
||||
$index = $1; # help for debug
|
||||
}
|
||||
if ($line =~ /"!/) {
|
||||
print "$index\n";
|
||||
print "Warning translation beginning with '!'\nEnsure it is not the old double key translation\n\n";
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub check_c_format {
|
||||
my $file = shift;
|
||||
|
||||
my $line;
|
||||
my $index;
|
||||
|
||||
my $in_c_format;
|
||||
my $in_msgid;
|
||||
my $in_msgstr;
|
||||
my $is_empty;
|
||||
|
||||
my @c_symbol;
|
||||
|
||||
while ($line = <$file>) {
|
||||
if ($line =~ /^#~/) {
|
||||
next;
|
||||
}
|
||||
if ($line =~ /^#:\s*(.*)/) {
|
||||
my $old_index = $index;
|
||||
$index = $1; # help for debug
|
||||
|
||||
if (scalar(@c_symbol) > 0 and not $is_empty) {
|
||||
print "$old_index\n";
|
||||
print "Error: translation miss some c format\n";
|
||||
print Dumper @c_symbol;
|
||||
print "\n";
|
||||
die;
|
||||
}
|
||||
my @empty;
|
||||
@c_symbol = @empty;
|
||||
|
||||
$in_c_format = 0;
|
||||
$in_msgid = 0;
|
||||
$in_msgstr = 0;
|
||||
$is_empty = 1;
|
||||
}
|
||||
if ($line =~ /^#.*c-format/) {
|
||||
$in_c_format = 1;
|
||||
}
|
||||
if ($line =~ /^\s*msgid\s/ and $in_c_format) {
|
||||
$in_msgid = 1;
|
||||
$in_msgstr = 0;
|
||||
}
|
||||
if ($line =~ /^\s*msgstr\s/ and $in_c_format) {
|
||||
$in_msgid = 0;
|
||||
$in_msgstr = 1;
|
||||
}
|
||||
if ($in_msgid and $line =~ /%\w/) {
|
||||
my @symbols = $line =~ /%\w/g;
|
||||
#print "add symbol @symbols\n";
|
||||
push(@c_symbol, @symbols);
|
||||
}
|
||||
if ($in_msgstr and $line =~ /".+"/) {
|
||||
$is_empty = 0;
|
||||
}
|
||||
if ($in_msgstr and $line =~ /%\w/) {
|
||||
my @symbols = $line =~ /%\w/g;
|
||||
#print "get symbol @symbols\n";
|
||||
foreach my $symbol (@symbols) {
|
||||
if ($c_symbol[0] ne $symbol) {
|
||||
print "$index\n";
|
||||
print "Error: C format mismatch\n\n";
|
||||
die;
|
||||
}
|
||||
shift @c_symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# PCSX2 - PS2 Emulator for PCs
|
||||
# Copyright (C) 2019 PCSX2 Dev Team
|
||||
#
|
||||
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
# ation, either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Generate glfunction pointer for GS
|
||||
|
||||
use File::Basename;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
my $g_allowed_ext = "(GL_VERSION\|GL_ARB\|GL_KHR)";
|
||||
my $g_fh_cpp;
|
||||
my $g_fh_hpp;
|
||||
my $g_fh_wnd;
|
||||
|
||||
sub to_PFN {
|
||||
my $f = shift;
|
||||
return "PFN" . uc($f) . "PROC";
|
||||
}
|
||||
|
||||
sub header {
|
||||
my $y = `date +%Y`;
|
||||
chomp $y;
|
||||
if ($y ne "2019") {
|
||||
$y = "2019-$y";
|
||||
}
|
||||
my $str = <<EOS;
|
||||
/*
|
||||
* Copyright (C) $y PCSX2 Dev Team
|
||||
*
|
||||
* This Program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This Program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* This file was generated by gen_gl_func_ptr.pl
|
||||
*
|
||||
*/
|
||||
|
||||
EOS
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub open_file {
|
||||
my $filename = shift;
|
||||
open(my $fh, ">$filename") or die $!;
|
||||
print $fh header();
|
||||
return $fh;
|
||||
}
|
||||
|
||||
sub print_all {
|
||||
my $str = shift;
|
||||
print $g_fh_cpp $str;
|
||||
print $g_fh_hpp $str;
|
||||
print $g_fh_wnd $str;
|
||||
}
|
||||
|
||||
sub read_glext {
|
||||
my $gl_h = scalar(@ARGV) == 0 ? "/usr/include/GL/glcorearb.h" : $ARGV[0];
|
||||
open(my $gl, $gl_h) or die $!;
|
||||
|
||||
my $db;
|
||||
my $ext;
|
||||
my $line;
|
||||
while ($line = <$gl>) {
|
||||
|
||||
if ($line =~ /#ifndef\s+(.*)/) {
|
||||
$ext = $1;
|
||||
my @data;
|
||||
$db->{$ext} = \@data;
|
||||
}
|
||||
|
||||
next unless ($ext =~ /$g_allowed_ext/);
|
||||
|
||||
if ($line =~ /^GLAPI.*API\w*\s(gl[\w\d]*)[\s\(]/) {
|
||||
push(@{$db->{$ext}}, $1);
|
||||
}
|
||||
}
|
||||
|
||||
# Trim empty extension
|
||||
foreach my $ext (sort(keys(%{$db}))) {
|
||||
my @funcs = @{$db->{$ext}};
|
||||
if (scalar (@funcs) == 0) {
|
||||
delete $db->{$ext};
|
||||
}
|
||||
}
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
my $glext = read_glext();
|
||||
|
||||
# Helper to enable only a part of GL
|
||||
foreach my $ext (sort(keys(%{$glext}))) {
|
||||
print "// #define ENABLE_$ext 1\n";
|
||||
}
|
||||
print "\n";
|
||||
|
||||
$g_fh_cpp = open_file("PFN_GLLOADER_CPP.h");
|
||||
$g_fh_hpp = open_file("PFN_GLLOADER_HPP.h");
|
||||
$g_fh_wnd = open_file("PFN_WND.h");
|
||||
|
||||
foreach my $ext (sort(keys(%{$glext}))) {
|
||||
print_all "#if defined(ENABLE_$ext) && defined($ext)\n";
|
||||
foreach my $f (@{$glext->{$ext}}) {
|
||||
my $p = to_PFN($f);
|
||||
print $g_fh_cpp "$p $f = NULL;\n";
|
||||
print $g_fh_hpp "extern $p $f;\n";
|
||||
print $g_fh_wnd "GL_EXT_LOAD_OPT($f);\n";
|
||||
}
|
||||
print_all "#endif\n";
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# PCSX2 - PS2 Emulator for PCs
|
||||
# Copyright (C) 2002-2014 PCSX2 Dev Team
|
||||
#
|
||||
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
# ation, either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script call xgettext utility to generate some nice pot (translation template) files
|
||||
|
||||
set -e
|
||||
|
||||
######################################################################
|
||||
# Script configuration
|
||||
######################################################################
|
||||
VERSION=1.3.0
|
||||
COPYRIGHT="PCSX2 Dev Team"
|
||||
BUG_MAIL="https://github.com/PCSX2/pcsx2/issues"
|
||||
|
||||
GENERAL_OPTION="--sort-by-file --no-wrap --package-name=PCSX2 \
|
||||
--package-version=$VERSION --msgid-bugs-address=$BUG_MAIL"
|
||||
|
||||
|
||||
######################################################################
|
||||
# Build Input file list
|
||||
######################################################################
|
||||
[ ! -e pcsx2 ] && echo "pcsx2 directory not present" && exit 1;
|
||||
[ ! -e common ] && echo "common directory not present" && exit 1;
|
||||
[ ! -e locales ] && echo "locales directory not present" && exit 1;
|
||||
|
||||
# Build a list of all input files
|
||||
input_files=""
|
||||
for directory in pcsx2 common
|
||||
do
|
||||
for type in cpp h
|
||||
do
|
||||
new_input_files=`find $directory -iname "*.${type}" -print0 | xargs -0`
|
||||
input_files="$input_files $new_input_files"
|
||||
done
|
||||
done
|
||||
|
||||
######################################################################
|
||||
# Generate the pot
|
||||
######################################################################
|
||||
MAIN_POT=locales/templates/pcsx2_Main.pot
|
||||
MAIN_KEY1=_
|
||||
MAIN_KEY2=pxL
|
||||
|
||||
DEV_KEY1=_d
|
||||
DEV_KEY2=pxDt
|
||||
|
||||
TER_KEY1=_t
|
||||
TER_KEY2=pxLt
|
||||
TER_KEY3=pxEt
|
||||
|
||||
echo "Generate $MAIN_POT"
|
||||
xgettext --keyword=$MAIN_KEY1 --keyword=$MAIN_KEY2 --keyword=$DEV_KEY1 --keyword=$DEV_KEY2 \
|
||||
--keyword=$TER_KEY1 --keyword=$TER_KEY2 $GENERAL_OPTION --copyright-holder="$COPYRIGHT" \
|
||||
$input_files --output=$MAIN_POT
|
||||
sed --in-place $MAIN_POT --expression=s/charset=CHARSET/charset=UTF-8/
|
||||
|
||||
ICO_POT=locales/templates/pcsx2_Iconized.pot
|
||||
ICO_KEY1=pxE
|
||||
|
||||
echo "Generate $ICO_POT"
|
||||
xgettext --keyword=$ICO_KEY1 --keyword=$TER_KEY3 $GENERAL_OPTION --copyright-holder="$COPYRIGHT" \
|
||||
$input_files --output=$ICO_POT
|
||||
sed --in-place $ICO_POT --expression=s/charset=CHARSET/charset=UTF-8/
|
||||
|
||||
######################################################################
|
||||
# Add poedit metadata
|
||||
# It eases poedit for translators
|
||||
######################################################################
|
||||
# Metadata example
|
||||
# "X-Poedit-KeywordsList: pxE_dev;pxDt\n"
|
||||
# "X-Poedit-SourceCharset: utf-8\n"
|
||||
# "X-Poedit-Basepath: trunk\\\n"
|
||||
# "X-Poedit-SearchPath-0: pcsx2\n"
|
||||
# "X-Poedit-SearchPath-1: common\n"
|
||||
# Normally "...Content-Transfer-Encoding..." is the end of the header. Use it as anchor to place poedit metadata after
|
||||
COMMON_META="\"X-Poedit-SourceCharset: utf-8\\\n\"\n\"X-Poedit-Basepath: trunk\\\\\\\\\\\n\"\n\"X-Poedit-SearchPath-0: pcsx2\\\n\"\n\"X-Poedit-SearchPath-1: common\\\n\""
|
||||
sed --in-place $MAIN_POT --expression=s/'\"Content-Transfer-Encoding: 8bit\\n\"'/"\"Content-Transfer-Encoding: 8bit\\\n\"\n\"X-Poedit-KeywordsList: ${MAIN_KEY1};${MAIN_KEY2};${DEV_KEY1};${DEV_KEY2};${TER_KEY1};${TER_KEY2}\\\n\"\n${COMMON_META}"/
|
||||
sed --in-place $ICO_POT --expression=s/'\"Content-Transfer-Encoding: 8bit\\n\"'/"\"Content-Transfer-Encoding: 8bit\\\n\"\n\"X-Poedit-KeywordsList: ${ICO_KEY1};${TER_KEY3}\\\n\"\n${COMMON_META}"/
|
||||
|
||||
######################################################################
|
||||
# Automatically align the .po to the new pot file
|
||||
######################################################################
|
||||
echo "Update pcsx2_Main.po files"
|
||||
for po_file in `find ./locales -iname pcsx2_Main.po`
|
||||
do
|
||||
# Note: --previous corrupt po file
|
||||
msgmerge --update $po_file $MAIN_POT
|
||||
done
|
||||
|
||||
echo "Update pcsx2_Iconized.po files"
|
||||
for po_file in `find ./locales -iname pcsx2_Iconized.po`
|
||||
do
|
||||
# Note: --previous corrupt po file
|
||||
msgmerge --update $po_file $ICO_POT
|
||||
done
|
||||
|
||||
######################################################################
|
||||
# Automatically compile po into mo file
|
||||
######################################################################
|
||||
echo "Compile po files, result are directly installed on bin/Langs directory"
|
||||
for po_file in `find ./locales -iname "pcsx2_*.po"`
|
||||
do
|
||||
mo_file=`echo $po_file | sed -e 's/locales/bin\/Langs/' | sed -e 's/\.po/.mo/'`
|
||||
mkdir -p `dirname $mo_file`
|
||||
msgfmt -o $mo_file $po_file
|
||||
done
|
||||
|
||||
######################################################################
|
||||
# Clean garbage
|
||||
######################################################################
|
||||
find ./locales -iname "pcsx2_*.po~" -exec rm {} \;
|
|
@ -1,97 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# PCSX2 - PS2 Emulator for PCs
|
||||
# Copyright (C) 2002-2011 PCSX2 Dev Team
|
||||
#
|
||||
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
# ation, either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This basic script convert an jpeg/png image to a .h include file
|
||||
# compatible with PCSX2 gui
|
||||
|
||||
use File::Basename;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub ascii_to_hex ($)
|
||||
{
|
||||
(my $str = shift) =~ s/(.|\n)/sprintf("%02lx", ord $1)/eg;
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub get_wx_ext ($)
|
||||
{
|
||||
my $ext = shift;
|
||||
|
||||
my $result = "BAD_FORMAT";
|
||||
if ($ext =~ /png/i) {
|
||||
$result = "wxBITMAP_TYPE_PNG";
|
||||
} elsif ($ext =~ /jpe?g/i) {
|
||||
$result = "wxBITMAP_TYPE_JPEG";
|
||||
} else {
|
||||
print "ERROR: bad format $ext\n";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
my $input=$ARGV[0];
|
||||
my $output=$ARGV[1] . ".h" ;
|
||||
|
||||
my($filename, $directories, $suffix) = fileparse($input);
|
||||
my ($name, $ext) = split(/\./,$filename);
|
||||
|
||||
my $wx_img_class = "res_$name";
|
||||
my $wx_img_extension = get_wx_ext($ext);
|
||||
my $filesize = -s $input;
|
||||
|
||||
### Collect binary data
|
||||
my $lenght = 1;
|
||||
my $binary = "\t\t";
|
||||
my $data;
|
||||
my $byte;
|
||||
|
||||
open(IN,"$input");
|
||||
binmode IN;
|
||||
while (($byte = read IN, $data, 1) != 0) {
|
||||
my $hex = ascii_to_hex($data);
|
||||
$binary .= "0x$hex";
|
||||
if ($lenght % 17 == 0 && $lenght > 1) {
|
||||
# End of line
|
||||
$binary .= ",\n\t\t";
|
||||
} elsif ($filesize == $lenght) {
|
||||
# End of file
|
||||
$binary .= "\n";
|
||||
} else {
|
||||
$binary .= ",";
|
||||
}
|
||||
$lenght++;
|
||||
}
|
||||
close(IN);
|
||||
|
||||
open(OUT,">$output");
|
||||
### Print the header
|
||||
print OUT "#pragma once\n\n";
|
||||
print OUT "#include \"common/Pcsx2Types.h\"\n";
|
||||
print OUT "#include <wx/gdicmn.h>\n\n";
|
||||
print OUT "class $wx_img_class\n{\n";
|
||||
print OUT "public:\n";
|
||||
print OUT "\tstatic const uint Length = $filesize;\n";
|
||||
print OUT "\tstatic const u8 Data[Length];\n";
|
||||
print OUT "\tstatic wxBitmapType GetFormat() { return $wx_img_extension; }\n};\n\n";
|
||||
print OUT "const u8 ${wx_img_class}::Data[Length] =\n{\n";
|
||||
|
||||
### Print the array
|
||||
print OUT $binary;
|
||||
print OUT "};\n";
|
||||
|
||||
close(OUT);
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
open(my $in, $ARGV[0]) or die "failed to get first param: $!";
|
||||
|
||||
my @pp_name = (
|
||||
# GPR
|
||||
"0", "0", "0", "0",
|
||||
"at", "at", "at", "at",
|
||||
"v0", "v0", "v0", "v0",
|
||||
"v1", "v1", "v1", "v1",
|
||||
"a0", "a0", "a0", "a0",
|
||||
"a1", "a1", "a1", "a1",
|
||||
"a2", "a2", "a2", "a2",
|
||||
"a3", "a3", "a3", "a3",
|
||||
"t0", "t0", "t0", "t0",
|
||||
"t1", "t1", "t1", "t1",
|
||||
"t2", "t2", "t2", "t2",
|
||||
"t3", "t3", "t3", "t3",
|
||||
"t4", "t4", "t4", "t4",
|
||||
"t5", "t5", "t5", "t5",
|
||||
"t6", "t6", "t6", "t6",
|
||||
"t7", "t7", "t7", "t7",
|
||||
"s0", "s0", "s0", "s0",
|
||||
"s1", "s1", "s1", "s1",
|
||||
"s2", "s2", "s2", "s2",
|
||||
"s3", "s3", "s3", "s3",
|
||||
"s4", "s4", "s4", "s4",
|
||||
"s5", "s5", "s5", "s5",
|
||||
"s6", "s6", "s6", "s6",
|
||||
"s7", "s7", "s7", "s7",
|
||||
"t8", "t8", "t8", "t8",
|
||||
"t9", "t9", "t9", "t9",
|
||||
"k0", "k0", "k0", "k0",
|
||||
"k1", "k1", "k1", "k1",
|
||||
"gp", "gp", "gp", "gp",
|
||||
"sp", "sp", "sp", "sp",
|
||||
"s8", "s8", "s8", "s8",
|
||||
"ra", "ra", "ra", "ra",
|
||||
"hi", "hi", "hi", "hi",
|
||||
"lo", "lo", "lo", "lo",
|
||||
|
||||
# CP0
|
||||
"Index" , "Random" , "EntryLo0" , "EntryLo1" ,
|
||||
"Context" , "PageMask" , "Wired" , "Reserved0" ,
|
||||
"BadVAddr" , "Count" , "EntryHi" , "Compare" ,
|
||||
"Status" , "Cause" , "EPC" , "PRid" ,
|
||||
"Config" , "LLAddr" , "WatchLO" , "WatchHI" ,
|
||||
"XContext" , "Reserved1" , "Reserved2" , "Debug" ,
|
||||
"DEPC" , "PerfCnt" , "ErrCtl" , "CacheErr" ,
|
||||
"TagLo" , "TagHi" , "ErrorEPC" , "DESAVE" ,
|
||||
|
||||
"sa",
|
||||
"IsDelaySlot",
|
||||
"pc",
|
||||
"code",
|
||||
"PERF", "PERF", "PERF", "PERF",
|
||||
|
||||
"eCycle0" , "eCycle1" , "eCycle2" , "eCycle3" , "eCycle4" , "eCycle5" , "eCycle6" , "eCycle7" ,
|
||||
"eCycle8" , "eCycle9" , "eCycle10" , "eCycle11" , "eCycle12" , "eCycle13" , "eCycle14" , "eCycle15" ,
|
||||
"eCycle16" , "eCycle17" , "eCycle18" , "eCycle19" , "eCycle20" , "eCycle21" , "eCycle22" , "eCycle23" ,
|
||||
"eCycle24" , "eCycle25" , "eCycle26" , "eCycle27" , "eCycle28" , "eCycle29" , "eCycle30" , "eCycle31" ,
|
||||
|
||||
"sCycle0" , "sCycle1" , "sCycle2" , "sCycle3" , "sCycle4" , "sCycle5" , "sCycle6" , "sCycle7" ,
|
||||
"sCycle8" , "sCycle9" , "sCycle10" , "sCycle11" , "sCycle12" , "sCycle13" , "sCycle14" , "sCycle15" ,
|
||||
"sCycle16" , "sCycle17" , "sCycle18" , "sCycle19" , "sCycle20" , "sCycle21" , "sCycle22" , "sCycle23" ,
|
||||
"sCycle24" , "sCycle25" , "sCycle26" , "sCycle27" , "sCycle28" , "sCycle29" , "sCycle30" , "sCycle31" ,
|
||||
|
||||
"cycle", "interrupt", "branch", "opmode", "tempcycles"
|
||||
);
|
||||
|
||||
my @pp_iop_name = (
|
||||
# GPR
|
||||
"0" , "at" , "v0" , "v1" ,
|
||||
"a0" , "a1" , "a2" , "a3" ,
|
||||
"t0" , "t1" , "t2" , "t3" ,
|
||||
"t4" , "t5" , "t6" , "t7" ,
|
||||
"s0" , "s1" , "s2" , "s3" ,
|
||||
"s4" , "s5" , "s6" , "s7" ,
|
||||
"t8" , "t9" , "k0" , "k1" ,
|
||||
"gp" , "sp" , "s8" , "ra" ,
|
||||
"hi" , "lo" ,
|
||||
|
||||
# CP0
|
||||
"Index" , "Random" , "EntryLo0" , "EntryLo1" ,
|
||||
"Context" , "PageMask" , "Wired" , "Reserved0" ,
|
||||
"BadVAddr" , "Count" , "EntryHi" , "Compare" ,
|
||||
"Status" , "Cause" , "EPC" , "PRid" ,
|
||||
"Config" , "LLAddr" , "WatchLO" , "WatchHI" ,
|
||||
"XContext" , "Reserved1" , "Reserved2" , "Debug" ,
|
||||
"DEPC" , "PerfCnt" , "ErrCtl" , "CacheErr" ,
|
||||
"TagLo" , "TagHi" , "ErrorEPC" , "DESAVE" ,
|
||||
|
||||
# CP2D
|
||||
"CP2D1" , "CP2D2" , "CP2D3" , "CP2D4" , "CP2D5" , "CP2D6" , "CP2D7" , "CP2D8" ,
|
||||
"CP2D9" , "CP2D10" , "CP2D11" , "CP2D12" , "CP2D13" , "CP2D14" , "CP2D15" , "CP2D16" ,
|
||||
"CP2D17" , "CP2D18" , "CP2D19" , "CP2D20" , "CP2D21" , "CP2D22" , "CP2D23" , "CP2D24" ,
|
||||
"CP2D25" , "CP2D26" , "CP2D27" , "CP2D28" , "CP2D29" , "CP2D30" , "CP2D31" , "CP2D32" ,
|
||||
|
||||
# CP2H
|
||||
"CP2H1" , "CP2H2" , "CP2H3" , "CP2H4" , "CP2H5" , "CP2H6" , "CP2H7" , "CP2H8" ,
|
||||
"CP2H9" , "CP2H10" , "CP2H11" , "CP2H12" , "CP2H13" , "CP2H14" , "CP2H15" , "CP2H16" ,
|
||||
"CP2H17" , "CP2H18" , "CP2H19" , "CP2H20" , "CP2H21" , "CP2H22" , "CP2H23" , "CP2H24" ,
|
||||
"CP2H25" , "CP2H26" , "CP2H27" , "CP2H28" , "CP2H29" , "CP2H30" , "CP2H31" , "CP2H32" ,
|
||||
|
||||
"pc",
|
||||
"code",
|
||||
"cycle",
|
||||
"int",
|
||||
|
||||
"eCycle0" , "eCycle1" , "eCycle2" , "eCycle3" , "eCycle4" , "eCycle5" , "eCycle6" , "eCycle7" ,
|
||||
"eCycle8" , "eCycle9" , "eCycle10" , "eCycle11" , "eCycle12" , "eCycle13" , "eCycle14" , "eCycle15" ,
|
||||
"eCycle16" , "eCycle17" , "eCycle18" , "eCycle19" , "eCycle20" , "eCycle21" , "eCycle22" , "eCycle23" ,
|
||||
"eCycle24" , "eCycle25" , "eCycle26" , "eCycle27" , "eCycle28" , "eCycle29" , "eCycle30" , "eCycle31" ,
|
||||
|
||||
"sCycle0" , "sCycle1" , "sCycle2" , "sCycle3" , "sCycle4" , "sCycle5" , "sCycle6" , "sCycle7" ,
|
||||
"sCycle8" , "sCycle9" , "sCycle10" , "sCycle11" , "sCycle12" , "sCycle13" , "sCycle14" , "sCycle15" ,
|
||||
"sCycle16" , "sCycle17" , "sCycle18" , "sCycle19" , "sCycle20" , "sCycle21" , "sCycle22" , "sCycle23" ,
|
||||
"sCycle24" , "sCycle25" , "sCycle26" , "sCycle27" , "sCycle28" , "sCycle29" , "sCycle30" , "sCycle31" ,
|
||||
);
|
||||
|
||||
my $line;
|
||||
my $cpu;
|
||||
my $iop = 0;
|
||||
while($line = <$in>) {
|
||||
if ($line =~ /Dump register data: (0x[0-9a-f]+)/) {
|
||||
$cpu = hex($1);
|
||||
}
|
||||
if ($line =~ /Dump PSX register data: (0x[0-9a-f]+)/) {
|
||||
$cpu = hex($1);
|
||||
$iop = 1;
|
||||
}
|
||||
if ($line =~ /ds:(0x[0-9a-f]+)/) {
|
||||
my $mem = hex($1);
|
||||
my $offset = $mem - $cpu;
|
||||
my $pretty;
|
||||
# keep only the cpuRegisters structure
|
||||
next unless ($offset >= 0 && $offset < 980);
|
||||
|
||||
if ($iop) {
|
||||
my $byte = $offset % 4;
|
||||
my $dw = $offset / 4;
|
||||
|
||||
$pretty = "&$pp_iop_name[$dw]_B$byte";
|
||||
} else {
|
||||
my $byte = ($offset >= 544) ? $offset % 4 : $offset % 16;
|
||||
my $dw = $offset / 4;
|
||||
|
||||
# FIXME B doesn't work for duplicated register
|
||||
$pretty = "&$pp_name[$dw]_B$byte";
|
||||
}
|
||||
|
||||
#print "AH $pretty\n";
|
||||
$line =~ s/ds:0x[0-9a-f]+/$pretty/;
|
||||
}
|
||||
print $line;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
# make bin2cpp
|
||||
add_subdirectory(bin2cpp)
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# PCSX2 - PS2 Emulator for PCs
|
||||
# Copyright (C) 2002-2011 PCSX2 Dev Team
|
||||
#
|
||||
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
# ation, either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
# If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Probably self-explanatory: This batch file compiles a single souce image into a
|
||||
# CPP header file for use by pcsx2.
|
||||
#
|
||||
# bin2cpp.sh SrcImage
|
||||
#
|
||||
# Parameters
|
||||
# SrcImage - Complete filename with extension.
|
||||
#
|
||||
|
||||
$1/tools/bin/bin2cpp $2
|
|
@ -1,6 +0,0 @@
|
|||
# bin2cpp tool
|
||||
|
||||
add_executable(bin2cpp bin2cpp.cpp)
|
||||
|
||||
# set output directory
|
||||
# set_target_properties(${bin2cppName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/tools/bin)
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>bin2cpp</ProjectName>
|
||||
<ProjectGuid>{677B7D11-D5E1-40B3-88B1-9A4DF83D2213}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>$(ProjectDir)..\bin\</OutDir>
|
||||
<IntDir>$(Configuration)\</IntDir>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine Condition="'$(Platform)'=='Win32'">MachineX86</TargetMachine>
|
||||
<TargetMachine Condition="'$(Platform)'=='x64'">MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bin2cpp.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bin2cpp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,222 +0,0 @@
|
|||
//
|
||||
// BIN2CPP - Some hack-up Job of some mess I found online.
|
||||
//
|
||||
// Original was uncredited public domain. This is uncredited public domain.
|
||||
// Who am I? You'll have to guess. Walrus, Eggman, or the taxman? Maybe.
|
||||
//
|
||||
// (Officially: Provided to the PCSX2 Dev Team by a combined effort on the part of
|
||||
// the PCSX2 Dev Team and the glorious expanse of the information superhighway).
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Changes from uncredited online version:
|
||||
// * Lots of code cleanups.
|
||||
// * Upgraded from K&R syntax (!) to CPP syntax.
|
||||
// * added wxWidgets class-based interface for instantiating images in neat fashion.
|
||||
// The class and interface used to read images from the host app can be found in
|
||||
// wxEmbeddedImage.cpp.
|
||||
//
|
||||
// Actually I changed every line of code pretty much, except one that I felt really
|
||||
// embodied the personality and spirit of this utility. It's the line that makes it
|
||||
// print the following message upon command line misuse:
|
||||
//
|
||||
// Bad arguments !!! You must give me all the parameters !!!!
|
||||
//
|
||||
// ... I love it. I really do.
|
||||
//
|
||||
// Warning: This program is full of stack overflow holes and other mess. Maybe we'll
|
||||
// rewrite it in C# someday and fix all that stuff, but for now it serves its purpose
|
||||
// and accomplishes its menial tasks with sufficent effectiveness.
|
||||
//
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#if _MSC_VER
|
||||
# pragma warning(disable:4996) // The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name.
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef char s8;
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const unsigned int BUF_LEN = 1;
|
||||
static const unsigned int LINE = 16;
|
||||
|
||||
/* Tell u the file size in bytes */
|
||||
|
||||
long getfilesize( const char* filename )
|
||||
{
|
||||
struct stat result;
|
||||
|
||||
stat( filename, &result );
|
||||
return result.st_size;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_SRCFILE = 1,
|
||||
ARG_DESTFILE,
|
||||
ARG_CLASSNAME,
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
FILE *source,*dest;
|
||||
u8 buffer[BUF_LEN];
|
||||
s8 Dummy[260];
|
||||
s8 srcfile[260];
|
||||
s8 classname[260];
|
||||
|
||||
if ( (argc <= ARG_SRCFILE) )
|
||||
{
|
||||
|
||||
if ( ( argc == 2 ) && ( strcmp(argv[1],"/?")==0 ) )
|
||||
{
|
||||
puts(
|
||||
" - <<< BIN2CPP V1.1 For Win32 >>> by the PCSX2 Team - \n\n"
|
||||
"USAGE: Bin2CPP <SOURCE image> [TARGET file] [CLASS]\n"
|
||||
" <SOURCE> = without extension!\n"
|
||||
" [TARGET] = without extension '.h' it will be added by program.\n"
|
||||
" (defaults to <SOURCE> if unspecified)\n"
|
||||
" [CLASS] = name of the C++ class in the destination file name.\n"
|
||||
" (defaults to res_<TARGET> if unspecified)\n"
|
||||
);
|
||||
return 0L;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts( "Bad arguments !!! You must give me all the parameters !!!!\n"
|
||||
"Type 'BIN2CPP /?' to read the help.\n"
|
||||
);
|
||||
return 0L;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Determine Source Name, and Open Source for Reading
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
strcpy(srcfile,argv[ARG_SRCFILE]);
|
||||
|
||||
const size_t srcfn_len = strlen( srcfile );
|
||||
if( srcfn_len < 4 || srcfile[srcfn_len-4] != '.' )
|
||||
{
|
||||
printf( "ERROR : Malformed source filename. I'm a crap utility and I demand 3-letter extensions only!\n" );
|
||||
return 18;
|
||||
}
|
||||
|
||||
if( (source=fopen( srcfile, "rb" )) == NULL )
|
||||
{
|
||||
printf( "ERROR : I can't find source file %s\n", srcfile );
|
||||
return 20;
|
||||
}
|
||||
|
||||
const int filesize( getfilesize( srcfile ) );
|
||||
|
||||
char wxImgTypeUpper[24];
|
||||
strcpy( wxImgTypeUpper, &srcfile[srcfn_len-3] );
|
||||
|
||||
int i = -1;
|
||||
while(++i, wxImgTypeUpper[i] != 0)
|
||||
wxImgTypeUpper[i] = toupper(wxImgTypeUpper[i]);
|
||||
|
||||
//strcpy( wxImgTypeLower, argv[ARG_IMGEXT] );
|
||||
//char wxImgTypeLower[24];
|
||||
|
||||
if( strcmp( wxImgTypeUpper, "JPG" ) == 0 )
|
||||
strcpy( wxImgTypeUpper, "JPEG" ); // because wxWidgets defines it as JPEG >_<
|
||||
|
||||
argv[ARG_SRCFILE][srcfn_len-4] = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Determine Target Name, and Open Target File for Writing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
strcpy( Dummy, argv[(argc <= ARG_DESTFILE) ? ARG_SRCFILE : ARG_DESTFILE] );
|
||||
|
||||
strcat( Dummy,".h" );
|
||||
|
||||
if( (dest=fopen( Dummy, "wb+" )) == NULL )
|
||||
{
|
||||
printf( "ERROR : I can't open destination file %s\n", Dummy );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
printf( "Bin2CPP Output > %s\n", Dummy );
|
||||
|
||||
const char* fnameonly = NULL;
|
||||
if( argc <= ARG_CLASSNAME )
|
||||
{
|
||||
fnameonly = argv[(argc <= ARG_DESTFILE) ? ARG_SRCFILE : ARG_DESTFILE];
|
||||
strcpy( classname, "res_" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fnameonly = argv[ARG_CLASSNAME];
|
||||
classname[0] = 0;
|
||||
}
|
||||
|
||||
{
|
||||
int len = static_cast<int>(strlen(fnameonly));
|
||||
const char* fnlast = &fnameonly[len];
|
||||
while( --fnlast, --len, (len >= 0 && (*fnlast != '/')) );
|
||||
|
||||
fnameonly = fnlast+1;
|
||||
}
|
||||
|
||||
strcpy( classname, "res_" );
|
||||
strcat( classname, fnameonly );
|
||||
|
||||
/* It writes the header information */
|
||||
|
||||
fprintf( dest,
|
||||
"#pragma once\n\n"
|
||||
"#include \"common/Pcsx2Types.h\"\n"
|
||||
"#include <wx/gdicmn.h>\n\n"
|
||||
"class %s\n{\n"
|
||||
"public:\n"
|
||||
"\tstatic const uint Length = %d;\n"
|
||||
"\tstatic const u8 Data[Length];\n"
|
||||
"\tstatic wxBitmapType GetFormat() { return wxBITMAP_TYPE_%s; }\n};\n\n"
|
||||
"const u8 %s::Data[Length] =\n{\n",
|
||||
classname, filesize, wxImgTypeUpper, classname
|
||||
);
|
||||
|
||||
if( ferror( dest ) )
|
||||
{
|
||||
printf( "ERROR writing on target file: %s\n", Dummy );
|
||||
return 20L;
|
||||
}
|
||||
|
||||
/* It writes the binary data information! */
|
||||
do
|
||||
{
|
||||
fprintf(dest,"\t");
|
||||
for ( unsigned int c=0; c <= LINE; ++c )
|
||||
{
|
||||
if( fread( buffer, 1, 1, source ) == 0 ) break;
|
||||
|
||||
if( c != 0 )
|
||||
fprintf( dest, "," );
|
||||
fprintf( dest,"0x%02x", *buffer );
|
||||
}
|
||||
if( !feof( source ) )
|
||||
fprintf( dest, "," );
|
||||
fprintf(dest,"\n");
|
||||
}
|
||||
while( ! feof( source ) );
|
||||
|
||||
fprintf(dest,"};\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue