2011-10-02 10:05:45 +00:00
|
|
|
#ifdef NALL_STRING_INTERNAL_HPP
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
namespace nall {
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
template<bool Insensitive>
|
|
|
|
bool chrequal(char x, char y) {
|
|
|
|
if(Insensitive) return chrlower(x) == chrlower(y);
|
|
|
|
return x == y;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool Quoted, typename T>
|
2013-05-02 11:25:45 +00:00
|
|
|
bool quoteskip(T*& p) {
|
2011-08-06 14:03:52 +00:00
|
|
|
if(Quoted == false) return false;
|
|
|
|
if(*p != '\'' && *p != '\"') return false;
|
|
|
|
|
|
|
|
while(*p == '\'' || *p == '\"') {
|
|
|
|
char x = *p++;
|
|
|
|
while(*p && *p++ != x);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool Quoted, typename T>
|
2013-05-02 11:25:45 +00:00
|
|
|
bool quotecopy(char*& t, T*& p) {
|
2011-08-06 14:03:52 +00:00
|
|
|
if(Quoted == false) return false;
|
|
|
|
if(*p != '\'' && *p != '\"') return false;
|
|
|
|
|
|
|
|
while(*p == '\'' || *p == '\"') {
|
|
|
|
char x = *p++;
|
|
|
|
*t++ = x;
|
|
|
|
while(*p && *p != x) *t++ = *p++;
|
|
|
|
*t++ = *p++;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
string substr(const char* src, unsigned start, unsigned length) {
|
2010-08-09 13:28:56 +00:00
|
|
|
string dest;
|
2011-07-07 12:59:26 +00:00
|
|
|
if(length == ~0u) {
|
2010-08-09 13:28:56 +00:00
|
|
|
//copy entire string
|
Update to v086r16 release.
byuu says:
Cydrak, I moved the step from the opcode decoder and opcodes themselves
into bus_(read,write)(byte,word), to minimize code.
If that's not feasible for some reason, please let me know and I'll
change it back to your latest WIP.
This has your carry flag fix, the timer skeleton (doesn't really work
yet), the Booth two-bit steps, and the carry flag clear thing inside
multiply ops.
Also added the aforementioned reset delay and reset bit stuff, and fixed
the steps to 21MHz for instructions and 64KHz for reset pulse.
I wasn't sure about the shifter extra cycles. I only saw it inside one
of the four (or was it three?) opcodes that have shifter functions.
Shouldn't it be in all of them?
The game does indeed appear to be fully playable now, but the AI doesn't
exactly match my real cartridge.
This could be for any number of reasons: ARM CPU bug, timer behavior
bug, oscillator differences between my real hardware and the emulator,
etc.
However ... the AI is 100% predictable every time, both under emulation
and on real hardware.
- For the first step, move 九-1 to 八-1.
- The opponent moves 三-3 to 四-3.
- Now move 七-1 to 六-1.
- The opponent moves 二-2 to 八-8.
However, on my real SNES, the opponent moves 一-3 to 二-4.
2012-03-07 13:03:15 +00:00
|
|
|
dest.reserve(strlen(src + start) + 1);
|
2012-01-15 08:29:57 +00:00
|
|
|
strcpy(dest(), src + start);
|
2010-08-09 13:28:56 +00:00
|
|
|
} else {
|
|
|
|
//copy partial string
|
Update to v086r16 release.
byuu says:
Cydrak, I moved the step from the opcode decoder and opcodes themselves
into bus_(read,write)(byte,word), to minimize code.
If that's not feasible for some reason, please let me know and I'll
change it back to your latest WIP.
This has your carry flag fix, the timer skeleton (doesn't really work
yet), the Booth two-bit steps, and the carry flag clear thing inside
multiply ops.
Also added the aforementioned reset delay and reset bit stuff, and fixed
the steps to 21MHz for instructions and 64KHz for reset pulse.
I wasn't sure about the shifter extra cycles. I only saw it inside one
of the four (or was it three?) opcodes that have shifter functions.
Shouldn't it be in all of them?
The game does indeed appear to be fully playable now, but the AI doesn't
exactly match my real cartridge.
This could be for any number of reasons: ARM CPU bug, timer behavior
bug, oscillator differences between my real hardware and the emulator,
etc.
However ... the AI is 100% predictable every time, both under emulation
and on real hardware.
- For the first step, move 九-1 to 八-1.
- The opponent moves 三-3 to 四-3.
- Now move 七-1 to 六-1.
- The opponent moves 二-2 to 八-8.
However, on my real SNES, the opponent moves 一-3 to 二-4.
2012-03-07 13:03:15 +00:00
|
|
|
dest.reserve(length + 1);
|
2012-01-15 08:29:57 +00:00
|
|
|
strmcpy(dest(), src + start, length + 1);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
string sha256(const uint8_t* data, unsigned size) {
|
2011-07-07 12:59:26 +00:00
|
|
|
sha256_ctx sha;
|
|
|
|
uint8_t hash[32];
|
|
|
|
sha256_init(&sha);
|
|
|
|
sha256_chunk(&sha, data, size);
|
|
|
|
sha256_final(&sha);
|
|
|
|
sha256_hash(&sha, hash);
|
|
|
|
string result;
|
2011-09-27 11:55:02 +00:00
|
|
|
for(auto &byte : hash) result.append(hex<2>(byte));
|
2011-07-07 12:59:26 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-10-24 11:35:34 +00:00
|
|
|
/* cast.hpp arithmetic -> string */
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
char* integer(char* result, intmax_t value) {
|
2011-10-24 11:35:34 +00:00
|
|
|
bool negative = value < 0;
|
|
|
|
if(negative) value = -value;
|
|
|
|
|
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
|
|
|
buffer[size++] = '0' + n;
|
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
2013-01-05 09:19:04 +00:00
|
|
|
if(negative) buffer[size++] = '-';
|
|
|
|
//buffer[size++] = negative ? '-' : '+';
|
2011-10-24 11:35:34 +00:00
|
|
|
|
|
|
|
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
|
|
|
|
result[size] = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
char* decimal(char* result, uintmax_t value) {
|
2011-10-24 11:35:34 +00:00
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
|
|
|
buffer[size++] = '0' + n;
|
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
|
|
|
|
|
|
|
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
|
|
|
|
result[size] = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* general-purpose arithmetic -> string */
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
template<unsigned length_, char padding> string integer(intmax_t value) {
|
2011-01-22 08:15:49 +00:00
|
|
|
bool negative = value < 0;
|
2011-10-24 11:35:34 +00:00
|
|
|
if(negative) value = -value;
|
2011-01-22 08:15:49 +00:00
|
|
|
|
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
|
|
|
buffer[size++] = '0' + n;
|
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
2013-01-05 09:19:04 +00:00
|
|
|
if(negative) buffer[size++] = '-';
|
|
|
|
//buffer[size++] = negative ? '-' : '+';
|
2011-01-22 08:15:49 +00:00
|
|
|
buffer[size] = 0;
|
|
|
|
|
2011-01-29 09:48:44 +00:00
|
|
|
unsigned length = (length_ == 0 ? size : length_);
|
2011-01-22 08:15:49 +00:00
|
|
|
char result[length + 1];
|
2011-08-06 14:03:52 +00:00
|
|
|
memset(result, padding, length);
|
2011-01-22 08:15:49 +00:00
|
|
|
result[length] = 0;
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
2011-01-22 08:15:49 +00:00
|
|
|
result[x] = buffer[y];
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
Update to v075r11 release.
byuu says:
Rewrote the way menus are attached, they act like layouts/widgets now.
All three phoenix targets once again work with both radio menu items and
radio widgets. Both GTK+ and Qt have built-in group controls right
inside the widgets, so I don't have to keep my own groups around
anymore. They do act screwy at widget creation though, have to jump
through some hoops to get it to work right. All I can say is, definitely
set all child widgets to the parent before trying to check any of them.
My long-term goal for the main window is to honor the fullscreen video
setting as a generic setting, and let the window scale auto-fit the best
possible size that matches your scale preference into the output window,
centered just like fullscreen. For now, I've just set it to a fixed
window size until I finish working on phoenix. The scale X settings will
just be to snap the window to an exact size in case you don't want any
black borders, they won't be radio items and the bsnes-geometry.cfg file
will save width/height information as well.
Simplified the sizing requirements for creating layouts and updated all
bsnes windows to support the new system. Layouts also expose their
minimum width/height values, which I use to create perfectly sized
windows on all three platforms. This will fix cut-off heights on the
last Windows WIP. Qt is being annoying though and forcing a minimum
window size of 300,100 despite me telling it to use a smaller window
size. Always have to fight with Qt, I swear to god.
2011-02-10 10:08:12 +00:00
|
|
|
return (const char*)result;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
template<unsigned length_, char padding> string linteger(intmax_t value) {
|
2010-08-09 13:28:56 +00:00
|
|
|
bool negative = value < 0;
|
2011-10-24 11:35:34 +00:00
|
|
|
if(negative) value = -value;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2011-01-22 08:15:49 +00:00
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
2010-08-09 13:28:56 +00:00
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
2011-01-22 08:15:49 +00:00
|
|
|
buffer[size++] = '0' + n;
|
2010-08-09 13:28:56 +00:00
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
2013-01-05 09:19:04 +00:00
|
|
|
if(negative) buffer[size++] = '-';
|
|
|
|
//buffer[size++] = negative ? '-' : '+';
|
2011-01-22 08:15:49 +00:00
|
|
|
buffer[size] = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2011-01-29 09:48:44 +00:00
|
|
|
unsigned length = (length_ == 0 ? size : length_);
|
2011-01-22 08:15:49 +00:00
|
|
|
char result[length + 1];
|
2011-08-06 14:03:52 +00:00
|
|
|
memset(result, padding, length);
|
2011-01-22 08:15:49 +00:00
|
|
|
result[length] = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
2011-01-22 08:15:49 +00:00
|
|
|
result[x] = buffer[y];
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
Update to v075r11 release.
byuu says:
Rewrote the way menus are attached, they act like layouts/widgets now.
All three phoenix targets once again work with both radio menu items and
radio widgets. Both GTK+ and Qt have built-in group controls right
inside the widgets, so I don't have to keep my own groups around
anymore. They do act screwy at widget creation though, have to jump
through some hoops to get it to work right. All I can say is, definitely
set all child widgets to the parent before trying to check any of them.
My long-term goal for the main window is to honor the fullscreen video
setting as a generic setting, and let the window scale auto-fit the best
possible size that matches your scale preference into the output window,
centered just like fullscreen. For now, I've just set it to a fixed
window size until I finish working on phoenix. The scale X settings will
just be to snap the window to an exact size in case you don't want any
black borders, they won't be radio items and the bsnes-geometry.cfg file
will save width/height information as well.
Simplified the sizing requirements for creating layouts and updated all
bsnes windows to support the new system. Layouts also expose their
minimum width/height values, which I use to create perfectly sized
windows on all three platforms. This will fix cut-off heights on the
last Windows WIP. Qt is being annoying though and forcing a minimum
window size of 300,100 despite me telling it to use a smaller window
size. Always have to fight with Qt, I swear to god.
2011-02-10 10:08:12 +00:00
|
|
|
return (const char*)result;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
template<unsigned length_, char padding> string decimal(uintmax_t value) {
|
2011-01-22 08:15:49 +00:00
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
|
|
|
buffer[size++] = '0' + n;
|
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
|
|
|
buffer[size] = 0;
|
|
|
|
|
2011-01-29 09:48:44 +00:00
|
|
|
unsigned length = (length_ == 0 ? size : length_);
|
2011-01-22 08:15:49 +00:00
|
|
|
char result[length + 1];
|
2011-08-06 14:03:52 +00:00
|
|
|
memset(result, padding, length);
|
2011-01-22 08:15:49 +00:00
|
|
|
result[length] = 0;
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
2011-01-22 08:15:49 +00:00
|
|
|
result[x] = buffer[y];
|
|
|
|
}
|
|
|
|
|
Update to v075r11 release.
byuu says:
Rewrote the way menus are attached, they act like layouts/widgets now.
All three phoenix targets once again work with both radio menu items and
radio widgets. Both GTK+ and Qt have built-in group controls right
inside the widgets, so I don't have to keep my own groups around
anymore. They do act screwy at widget creation though, have to jump
through some hoops to get it to work right. All I can say is, definitely
set all child widgets to the parent before trying to check any of them.
My long-term goal for the main window is to honor the fullscreen video
setting as a generic setting, and let the window scale auto-fit the best
possible size that matches your scale preference into the output window,
centered just like fullscreen. For now, I've just set it to a fixed
window size until I finish working on phoenix. The scale X settings will
just be to snap the window to an exact size in case you don't want any
black borders, they won't be radio items and the bsnes-geometry.cfg file
will save width/height information as well.
Simplified the sizing requirements for creating layouts and updated all
bsnes windows to support the new system. Layouts also expose their
minimum width/height values, which I use to create perfectly sized
windows on all three platforms. This will fix cut-off heights on the
last Windows WIP. Qt is being annoying though and forcing a minimum
window size of 300,100 despite me telling it to use a smaller window
size. Always have to fight with Qt, I swear to god.
2011-02-10 10:08:12 +00:00
|
|
|
return (const char*)result;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
template<unsigned length_, char padding> string ldecimal(uintmax_t value) {
|
2011-01-22 08:15:49 +00:00
|
|
|
char buffer[64];
|
|
|
|
unsigned size = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned n = value % 10;
|
|
|
|
buffer[size++] = '0' + n;
|
|
|
|
value /= 10;
|
|
|
|
} while(value);
|
|
|
|
buffer[size] = 0;
|
|
|
|
|
2011-01-29 09:48:44 +00:00
|
|
|
unsigned length = (length_ == 0 ? size : length_);
|
2011-01-22 08:15:49 +00:00
|
|
|
char result[length + 1];
|
2011-08-06 14:03:52 +00:00
|
|
|
memset(result, padding, length);
|
2011-01-22 08:15:49 +00:00
|
|
|
result[length] = 0;
|
|
|
|
|
2011-08-06 14:03:52 +00:00
|
|
|
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
2011-01-22 08:15:49 +00:00
|
|
|
result[x] = buffer[y];
|
|
|
|
}
|
|
|
|
|
Update to v075r11 release.
byuu says:
Rewrote the way menus are attached, they act like layouts/widgets now.
All three phoenix targets once again work with both radio menu items and
radio widgets. Both GTK+ and Qt have built-in group controls right
inside the widgets, so I don't have to keep my own groups around
anymore. They do act screwy at widget creation though, have to jump
through some hoops to get it to work right. All I can say is, definitely
set all child widgets to the parent before trying to check any of them.
My long-term goal for the main window is to honor the fullscreen video
setting as a generic setting, and let the window scale auto-fit the best
possible size that matches your scale preference into the output window,
centered just like fullscreen. For now, I've just set it to a fixed
window size until I finish working on phoenix. The scale X settings will
just be to snap the window to an exact size in case you don't want any
black borders, they won't be radio items and the bsnes-geometry.cfg file
will save width/height information as well.
Simplified the sizing requirements for creating layouts and updated all
bsnes windows to support the new system. Layouts also expose their
minimum width/height values, which I use to create perfectly sized
windows on all three platforms. This will fix cut-off heights on the
last Windows WIP. Qt is being annoying though and forcing a minimum
window size of 300,100 despite me telling it to use a smaller window
size. Always have to fight with Qt, I swear to god.
2011-02-10 10:08:12 +00:00
|
|
|
return (const char*)result;
|
2011-01-22 08:15:49 +00:00
|
|
|
}
|
|
|
|
|
2010-08-09 13:28:56 +00:00
|
|
|
//using sprintf is certainly not the most ideal method to convert
|
|
|
|
//a double to a string ... but attempting to parse a double by
|
|
|
|
//hand, digit-by-digit, results in subtle rounding errors.
|
2013-05-02 11:25:45 +00:00
|
|
|
unsigned fp(char* str, long double value) {
|
2010-08-09 13:28:56 +00:00
|
|
|
char buffer[256];
|
Update to v084r03 release.
(r02 was not posted to the WIP thread)
byuu says:
Internally, all color is processed with 30-bit precision. The filters
also operate at 30-bit depth.
There's a new config file setting, video.depth, which defaults to 24.
This causes the final output to downsample to 24-bit, as most will
require.
If you set it to 30-bit, the downsampling will not occur, and bsnes will
ask ruby for a 30-bit surface. If you don't have one available, you're
going to get bad colors. Or maybe even a crash with OpenGL.
I don't yet have detection code to make sure you have an appropriate
visual in place.
30-bit mode will really only work if you are running Linux, running Xorg
at Depth 30, use the OpenGL or XShm driver, have an nVidia Quadro or AMD
FireGL card with the official drivers, and have a 30-bit capable
monitor.
Lots of planning and work for very little gain here, but it's nice that
it's finally finished.
Oh, I had to change the contrast/brightness formulas a tiny bit, but
they still work and look nice.
2011-12-03 03:22:54 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
//Windows C-runtime does not support long double via sprintf()
|
|
|
|
sprintf(buffer, "%f", (double)value);
|
|
|
|
#else
|
|
|
|
sprintf(buffer, "%Lf", value);
|
|
|
|
#endif
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//remove excess 0's in fraction (2.500000 -> 2.5)
|
2013-05-02 11:25:45 +00:00
|
|
|
for(char* p = buffer; *p; p++) {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(*p == '.') {
|
2013-05-02 11:25:45 +00:00
|
|
|
char* p = buffer + strlen(buffer) - 1;
|
2010-08-09 13:28:56 +00:00
|
|
|
while(*p == '0') {
|
|
|
|
if(*(p - 1) != '.') *p = 0; //... but not for eg 1.0 -> 1.
|
|
|
|
p--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned length = strlen(buffer);
|
|
|
|
if(str) strcpy(str, buffer);
|
|
|
|
return length + 1;
|
|
|
|
}
|
|
|
|
|
Update to v084r03 release.
(r02 was not posted to the WIP thread)
byuu says:
Internally, all color is processed with 30-bit precision. The filters
also operate at 30-bit depth.
There's a new config file setting, video.depth, which defaults to 24.
This causes the final output to downsample to 24-bit, as most will
require.
If you set it to 30-bit, the downsampling will not occur, and bsnes will
ask ruby for a 30-bit surface. If you don't have one available, you're
going to get bad colors. Or maybe even a crash with OpenGL.
I don't yet have detection code to make sure you have an appropriate
visual in place.
30-bit mode will really only work if you are running Linux, running Xorg
at Depth 30, use the OpenGL or XShm driver, have an nVidia Quadro or AMD
FireGL card with the official drivers, and have a 30-bit capable
monitor.
Lots of planning and work for very little gain here, but it's nice that
it's finally finished.
Oh, I had to change the contrast/brightness formulas a tiny bit, but
they still work and look nice.
2011-12-03 03:22:54 +00:00
|
|
|
string fp(long double value) {
|
2010-08-09 13:28:56 +00:00
|
|
|
string temp;
|
2013-03-15 13:11:33 +00:00
|
|
|
temp.reserve(fp(nullptr, value));
|
2010-12-22 14:13:14 +00:00
|
|
|
fp(temp(), value);
|
2010-08-09 13:28:56 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|