summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2013-06-22 22:30:13 -0700
committerBen Longbons <b.r.longbons@gmail.com>2013-06-23 22:07:50 -0700
commitdbbfda0e96037da4f208ff8f00d181a5294484ae (patch)
tree7a7b9982c6d98ddc2271aade72040ea9233a4a11
parent83db3bbee4e19e7426a32ee89ad6c2d8e48260f2 (diff)
downloadtmwa-dbbfda0e96037da4f208ff8f00d181a5294484ae.tar.gz
tmwa-dbbfda0e96037da4f208ff8f00d181a5294484ae.tar.bz2
tmwa-dbbfda0e96037da4f208ff8f00d181a5294484ae.tar.xz
tmwa-dbbfda0e96037da4f208ff8f00d181a5294484ae.zip
add new stuff stuff (with tests!), poison memcmp and strncpy
-rw-r--r--.travis.yml4
-rw-r--r--Makefile11
-rw-r--r--make.defs6
-rw-r--r--src/char/char.cpp244
-rw-r--r--src/char/int_party.cpp124
-rw-r--r--src/char/int_storage.cpp2
-rw-r--r--src/char/inter.cpp4
-rw-r--r--src/common/dumb_ptr.hpp3
-rw-r--r--src/common/md5calc.cpp3
-rw-r--r--src/common/mmo.hpp9
-rw-r--r--src/common/socket.cpp2
-rw-r--r--src/common/socket.hpp16
-rw-r--r--src/common/strings.hpp537
-rw-r--r--src/common/strings_test.cpp99
-rw-r--r--src/common/utils.hpp14
-rw-r--r--src/common/utils2.hpp21
-rw-r--r--src/ladmin/ladmin.cpp236
-rw-r--r--src/login/login.cpp164
-rw-r--r--src/map/atcommand.cpp43
-rw-r--r--src/map/chrif.cpp41
-rw-r--r--src/map/clif.cpp93
-rw-r--r--src/map/clif.hpp5
-rw-r--r--src/map/intif.cpp52
-rw-r--r--src/map/magic-interpreter-base.cpp2
-rw-r--r--src/map/magic-interpreter-lexer.lpp14
-rw-r--r--src/map/map.hpp2
-rw-r--r--src/map/mob.cpp3
-rw-r--r--src/map/npc.cpp9
-rw-r--r--src/map/party.cpp3
-rw-r--r--src/map/pc.cpp25
-rw-r--r--src/map/script.cpp4
-rw-r--r--src/map/tmw.cpp2
-rw-r--r--src/poison.hpp2
-rw-r--r--src/tests/main.cpp7
34 files changed, 1329 insertions, 477 deletions
diff --git a/.travis.yml b/.travis.yml
index 2722936..ead11f8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,6 +30,7 @@ install:
sudo apt-get update -qq;
fi
- sudo apt-get install -qq ${REAL_CXX}
+ - sudo apt-get install -qq libgtest-dev
## Do something before the main test script
# before_script: ...
@@ -39,7 +40,8 @@ script:
- make -k -j2 CXX=${REAL_CXX} CPPFLAGS=-DQUIET
## Do something after the main test script
-# after_script: ...
+after_script:
+ - make test
### The rest of the file creates a build matrix
### containing gcc-4.6 through gcc-4.7 and clang-3.1
diff --git a/Makefile b/Makefile
index 1e78b51..5436881 100644
--- a/Makefile
+++ b/Makefile
@@ -34,8 +34,13 @@ ${BUILD_DIR}/login/%.o: src/login/%.cpp | ${BUILD_DIR}/login/.
$(COMPILE.cpp) -o $@ $<
${BUILD_DIR}/map/%.o: src/map/%.cpp | ${BUILD_DIR}/map/.
$(COMPILE.cpp) -o $@ $<
+${BUILD_DIR}/tests/%.o: src/tests/%.cpp | ${BUILD_DIR}/tests/.
+ $(COMPILE.cpp) -o $@ $<
${BUILD_DIR}/tool/%.o: src/tool/%.cpp | ${BUILD_DIR}/tool/.
$(COMPILE.cpp) -o $@ $<
+${BUILD_DIR}/gtest-all.o: ${GTEST_DIR}/src/gtest-all.cc | ${BUILD_DIR}/.
+ $(COMPILE.cpp) -I${GTEST_DIR} -DGTEST_HAS_PTHREAD=0 -o $@ $<
+
MOSTPROGS = login-server char-server ladmin eathena-monitor
PROGS = ${MOSTPROGS} map-server
@@ -59,6 +64,10 @@ ladmin: ${BUILD_DIR}/ladmin/ladmin
eathena-monitor: ${BUILD_DIR}/tool/eathena-monitor
cp -f $< $@
+${BUILD_DIR}/tests/main: ${BUILD_DIR}/tests/main.o $(patsubst src/%.cpp,obj/%.o,$(wildcard src/*/*_test.cpp)) ${BUILD_DIR}/gtest-all.o
+test: ${BUILD_DIR}/tests/main
+ $<
+
# Executable dependencies - generated by hand
${BUILD_DIR}/char/char: ${BUILD_DIR}/char/char.o ${BUILD_DIR}/char/inter.o ${BUILD_DIR}/char/int_party.o ${BUILD_DIR}/char/int_storage.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/cxxstdio.o ${BUILD_DIR}/common/extract.o
${BUILD_DIR}/ladmin/ladmin: ${BUILD_DIR}/ladmin/ladmin.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/cxxstdio.o
@@ -67,7 +76,7 @@ ${BUILD_DIR}/map/map: ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/tmw.o ${BUILD_DIR}
${BUILD_DIR}/tool/eathena-monitor: ${BUILD_DIR}/tool/eathena-monitor.o ${BUILD_DIR}/common/utils.o
# silence build warnings for code beyond my control
-${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o : override WARNINGS=
+${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o ${BUILD_DIR}/gtest-all.o: override WARNINGS=
# deps.make is *NOT* automatically rebuilt normally
# but the generated source files do need to be done first
diff --git a/make.defs b/make.defs
index 7e788c5..b5b47fa 100644
--- a/make.defs
+++ b/make.defs
@@ -8,6 +8,12 @@ BISON = bison
CXXFLAGS = -pipe -g -O2 ${WARNINGS}
WARNINGS = -include src/warnings.hpp
+# Location of gtest source tree. It must contain the file src/gtest-all.cc
+# Note: linking against a precompiled library is NOT supported;
+# it may have used different CXXFLAGS. See
+# http://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog
+GTEST_DIR = /usr/src/gtest
+
# works on both x86 and x86_64
override CXX += -std=c++0x
# for linking
diff --git a/src/char/char.cpp b/src/char/char.cpp
index 02d89af..bb0550b 100644
--- a/src/char/char.cpp
+++ b/src/char/char.cpp
@@ -595,15 +595,13 @@ void remove_prefix_blanks(char *name)
// Function to create a new character
//-----------------------------------
static
-mmo_charstatus *make_new_char(int fd, const uint8_t *dat)
+mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uint8_t slot, uint16_t hair_color, uint16_t hair_style)
{
// ugh
- char *cdat = reinterpret_cast<char *>(const_cast<uint8_t *>(dat));
char_session_data *sd = static_cast<char_session_data *>(session[fd]->session_data.get());
// remove control characters from the name
- cdat[23] = '\0';
- if (remove_control_chars(cdat))
+ if (remove_control_chars(name))
{
CHAR_LOG("Make new char error (control char received in the name): (connection #%d, account: %d).\n",
fd, sd->account_id);
@@ -611,14 +609,14 @@ mmo_charstatus *make_new_char(int fd, const uint8_t *dat)
}
// Eliminate whitespace
- remove_trailing_blanks(cdat);
- remove_prefix_blanks(cdat);
+ remove_trailing_blanks(name);
+ remove_prefix_blanks(name);
// check lenght of character name
- if (strlen(cdat) < 4)
+ if (strlen(name) < 4)
{
CHAR_LOG("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n",
- fd, sd->account_id, cdat);
+ fd, sd->account_id, name);
return nullptr;
}
@@ -626,86 +624,86 @@ mmo_charstatus *make_new_char(int fd, const uint8_t *dat)
if (char_name_option == 1)
{
// only letters/symbols in char_name_letters are authorised
- for (int i = 0; cdat[i]; i++)
- if (strchr(char_name_letters, cdat[i]) == NULL)
+ for (int i = 0; name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL)
{
CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n",
- fd, sd->account_id, cdat, cdat[i]);
+ fd, sd->account_id, name, name[i]);
return nullptr;
}
}
else if (char_name_option == 2)
{
// letters/symbols in char_name_letters are forbidden
- for (int i = 0; cdat[i]; i++)
- if (strchr(char_name_letters, cdat[i]) != NULL)
+ for (int i = 0; name[i]; i++)
+ if (strchr(char_name_letters, name[i]) != NULL)
{
CHAR_LOG("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n",
- fd, sd->account_id, cdat, cdat[i]);
+ fd, sd->account_id, name, name[i]);
return nullptr;
}
} // else, all letters/symbols are authorised (except control char removed before)
// this is why it needs to be unsigned
- if (dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29] != 5 * 6 || // stats
- dat[30] >= 9 || // slots (dat[30] can not be negativ)
- dat[33] >= 20 || // hair style
- dat[31] >= 12)
- { // hair color (dat[31] can not be negativ)
+ if (stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5] != 5 * 6 || // stats
+ slot >= 9 ||
+ hair_style >= 20 ||
+ hair_color >= 12)
+ {
CHAR_LOG("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n",
- fd, sd->account_id, dat[30], dat, dat[24], dat[25],
- dat[26], dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29],
- dat[33], dat[31]);
+ fd, sd->account_id, slot, name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color);
return nullptr;
}
// check individual stat value
- for (int i = 24; i <= 29; i++)
+ for (int i = 0; i < 6; i++)
{
- if (dat[i] < 1 || dat[i] > 9)
+ if (stats[i] < 1 || stats[i] > 9)
{
CHAR_LOG("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n",
- fd, sd->account_id, dat[30], dat, dat[24], dat[25],
- dat[26], dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29],
- dat[33], dat[31]);
+ fd, sd->account_id, slot, name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color);
return nullptr;
}
}
for (const mmo_charstatus& cd : char_data)
{
- if ((name_ignoring_case != 0 && strcmp(cd.name, cdat) == 0)
+ if ((name_ignoring_case != 0 && strcmp(cd.name, name) == 0)
|| (name_ignoring_case == 0
- && strcasecmp(cd.name, cdat) == 0))
+ && strcasecmp(cd.name, name) == 0))
{
CHAR_LOG("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n",
- fd, sd->account_id, dat[30], cdat, cd.name,
- dat[24], dat[25], dat[26], dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29],
- dat[33], dat[31]);
+ fd, sd->account_id, slot, name, cd.name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color);
return nullptr;
}
if (cd.account_id == sd->account_id
- && cd.char_num == dat[30])
+ && cd.char_num == slot)
{
CHAR_LOG("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n",
- fd, sd->account_id, dat[30], cdat, cd.name,
- dat[24], dat[25], dat[26], dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29],
- dat[33], dat[31]);
+ fd, sd->account_id, slot, name, cd.name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color);
return nullptr;
}
}
- if (strcmp(wisp_server_name, cdat) == 0)
+ if (strcmp(wisp_server_name, name) == 0)
{
CHAR_LOG("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name whisper server: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n",
- fd, sd->account_id, dat[30], cdat, wisp_server_name,
- dat[24], dat[25], dat[26], dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29],
- dat[33], dat[31]);
+ fd, sd->account_id, slot, name, wisp_server_name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color);
return nullptr;
}
@@ -715,29 +713,29 @@ mmo_charstatus *make_new_char(int fd, const uint8_t *dat)
sin_addr[3]);
CHAR_LOG("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d. [%s]\n",
- fd, sd->account_id, dat[30], cdat, dat[24], dat[25], dat[26],
- dat[27], dat[28], dat[29],
- dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33],
- dat[31], ip);
+ fd, sd->account_id, slot, name,
+ stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5],
+ hair_style, hair_color, ip);
mmo_charstatus cd {};
cd.char_id = char_id_count++;
cd.account_id = sd->account_id;
- cd.char_num = dat[30];
- strcpy(cd.name, cdat);
+ cd.char_num = slot;
+ strcpy(cd.name, name);
cd.species = 0;
cd.base_level = 1;
cd.job_level = 1;
cd.base_exp = 0;
cd.job_exp = 0;
cd.zeny = start_zeny;
- cd.attrs[ATTR::STR] = dat[24];
- cd.attrs[ATTR::AGI] = dat[25];
- cd.attrs[ATTR::VIT] = dat[26];
- cd.attrs[ATTR::INT] = dat[27];
- cd.attrs[ATTR::DEX] = dat[28];
- cd.attrs[ATTR::LUK] = dat[29];
+ cd.attrs[ATTR::STR] = stats[0];
+ cd.attrs[ATTR::AGI] = stats[1];
+ cd.attrs[ATTR::VIT] = stats[2];
+ cd.attrs[ATTR::INT] = stats[3];
+ cd.attrs[ATTR::DEX] = stats[4];
+ cd.attrs[ATTR::LUK] = stats[5];
cd.max_hp = 40 * (100 + cd.attrs[ATTR::VIT]) / 100;
cd.max_sp = 11 * (100 + cd.attrs[ATTR::INT]) / 100;
cd.hp = cd.max_hp;
@@ -749,21 +747,11 @@ mmo_charstatus *make_new_char(int fd, const uint8_t *dat)
cd.manner = 0;
cd.party_id = 0;
//cd.guild_id = 0;
- cd.hair = dat[33];
- cd.hair_color = dat[31];
+ cd.hair = hair_style;
+ cd.hair_color = hair_color;
cd.clothes_color = 0;
- // TODO: remove this - it's not used
- cd.inventory[0].nameid = start_weapon; // Knife
- cd.inventory[0].amount = 1;
- cd.inventory[0].equip = EPOS::WEAPON;
- cd.inventory[0].identify = 1;
- cd.inventory[0].broken = 0;
- cd.inventory[1].nameid = start_armor; // Cotton Shirt
- cd.inventory[1].amount = 1;
- cd.inventory[1].equip = EPOS::MISC1;
- cd.inventory[1].identify = 1;
- cd.inventory[1].broken = 0;
- cd.weapon = ItemLook::BLADE;
+ // removed initial armor/weapon - unused and problematic
+ cd.weapon = ItemLook::NONE;
cd.shield = 0;
cd.head_top = 0;
cd.head_mid = 0;
@@ -1018,11 +1006,11 @@ int set_account_reg2(int acc, int num, struct global_reg *reg)
{
if (cd.account_id == acc)
{
- for (int i = 0; i < num; ++i)
- cd.account_reg2[i] = reg[i];
+ for (int i = 0; i < num; ++i)
+ cd.account_reg2[i] = reg[i];
cd.account_reg2_num = num;
- for (int i = num; i < ACCOUNT_REG2_NUM; ++i)
- cd.account_reg2[i] = global_reg{};
+ for (int i = num; i < ACCOUNT_REG2_NUM; ++i)
+ cd.account_reg2[i] = global_reg{};
c++;
}
}
@@ -1237,7 +1225,7 @@ void parse_tologin(int fd)
{
if (sd->account_id == RFIFOL(fd, 2))
{
- RFIFO_STRING(fd, 6, sd->email, 40);
+ RFIFO_STRING(fd, 6, sd->email, 40);
if (e_mail_check(sd->email) == 0)
strzcpy(sd->email, "a@a.com", 40); // default e-mail
sd->connect_until_time = static_cast<time_t>(RFIFOL(fd, 46));
@@ -1319,9 +1307,9 @@ void parse_tologin(int fd)
CHAR_LOG("'ladmin': Receiving a message for broadcast, but no map-server is online.\n");
else
{
- size_t len = RFIFOL(fd, 4);
+ size_t len = RFIFOL(fd, 4);
char message[len];
- RFIFO_STRING(fd, 8, message, len);
+ RFIFO_STRING(fd, 8, message, len);
remove_control_chars(message);
// remove all first spaces
char *p = message;
@@ -1339,10 +1327,10 @@ void parse_tologin(int fd)
message_ptr);
}
// send broadcast to all map-servers
- uint8_t buf[4 + len];
+ uint8_t buf[4 + len];
WBUFW(buf, 0) = 0x3800;
WBUFW(buf, 2) = 4 + sizeof(message);
- WBUF_STRING(buf, 4, message, sizeof(message));
+ WBUF_STRING(buf, 4, message, sizeof(message));
mapif_sendall(buf, WBUFW(buf, 2));
}
}
@@ -1367,14 +1355,14 @@ void parse_tologin(int fd)
}
set_account_reg2(acc, j, reg);
- size_t len = RFIFOW(fd, 2);
+ size_t len = RFIFOW(fd, 2);
uint8_t buf[len];
RFIFO_BUF_CLONE(fd, buf, len);
WBUFW(buf, 0) = 0x2b11;
mapif_sendall(buf, len);
// PRINTF("char: save_account_reg_reply\n");
}
- RFIFOSKIP(fd, RFIFOW(fd, 2));
+ RFIFOSKIP(fd, RFIFOW(fd, 2));
break;
case 0x7924:
@@ -1487,7 +1475,7 @@ void parse_tologin(int fd)
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd, 2))
return;
{
- size_t len = RFIFOW(fd, 2);
+ size_t len = RFIFOW(fd, 2);
uint8_t buf[len];
gm_accounts.clear();
gm_accounts.reserve((len - 4) / 5);
@@ -1501,7 +1489,7 @@ void parse_tologin(int fd)
gm_accounts.size());
create_online_files(); // update online players files (perhaps some online players change of GM level)
// send new gm acccounts level to map-servers
- RFIFO_BUF_CLONE(fd, buf, len);
+ RFIFO_BUF_CLONE(fd, buf, len);
WBUFW(buf, 0) = 0x2b15;
mapif_sendall(buf, len);
}
@@ -1615,8 +1603,8 @@ void parse_frommap(int fd)
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd, 2))
return;
{
- for (char (&foo)[16] : server[id].maps)
- strzcpy(foo, "", 16);
+ for (char (&foo)[16] : server[id].maps)
+ strzcpy(foo, "", 16);
int j = 0;
for (int i = 4; i < RFIFOW(fd, 2); i += 16)
{
@@ -1652,9 +1640,9 @@ void parse_frommap(int fd)
WBUFW(buf, 2) = j * 16 + 10;
WBUFL(buf, 4) = server[id].ip;
WBUFW(buf, 8) = server[id].port;
- // server[id].maps[i] = RFIFO_STRING(fd, 4 + i * 16)
- for (int i = 0; i < j; ++i)
- WBUF_STRING(buf, 10, server[id].maps[i], 16);
+ // server[id].maps[i] = RFIFO_STRING(fd, 4 + i * 16)
+ for (int i = 0; i < j; ++i)
+ WBUF_STRING(buf, 10, server[id].maps[i], 16);
mapif_sendallwos(fd, buf, WBUFW(buf, 2));
}
// Transmitting the maps of the other map-servers to the new map-server
@@ -1717,7 +1705,7 @@ void parse_frommap(int fd)
FPRINTF(stderr,
"From queue index %zd: recalling packet version %d\n",
(&afi - &auth_fifo.front()), afi.packet_tmw_version);
- WFIFO_STRUCT(fd, 18, *cd);
+ WFIFO_STRUCT(fd, 18, *cd);
WFIFOSET(fd, WFIFOW(fd, 2));
//PRINTF("auth_fifo search success (auth #%d, account %d, character: %d).\n", i, RFIFOL(fd,2), RFIFOL(fd,6));
goto x2afc_out;
@@ -1776,7 +1764,7 @@ void parse_frommap(int fd)
if (cd.account_id == RFIFOL(fd, 4) &&
cd.char_id == RFIFOL(fd, 8))
{
- RFIFO_STRUCT(fd, 12, cd);
+ RFIFO_STRUCT(fd, 12, cd);
break;
}
}
@@ -1811,8 +1799,8 @@ void parse_frommap(int fd)
if (auth_fifo_iter == auth_fifo.end())
auth_fifo_iter = auth_fifo.begin();
- RFIFO_WFIFO_CLONE(fd, fd, 44);
- // overwrite
+ RFIFO_WFIFO_CLONE(fd, fd, 44);
+ // overwrite
WFIFOW(fd, 0) = 0x2b06;
auth_fifo_iter->account_id = RFIFOL(fd, 2);
auth_fifo_iter->char_id = RFIFOL(fd, 14);
@@ -1842,18 +1830,18 @@ void parse_frommap(int fd)
if (RFIFOREST(fd) < 6)
return;
{
- const char (*name)[24] = &unknown_char_name;
+ const char *name = unknown_char_name;
for (const mmo_charstatus& cd : char_data)
{
if (cd.char_id == RFIFOL(fd, 2))
{
- name = &cd.name;
+ name = cd.name;
break;
}
}
WFIFOW(fd, 0) = 0x2b09;
WFIFOL(fd, 2) = RFIFOL(fd, 2);
- WFIFO_STRING(fd, 6, *name, 24);
+ WFIFO_STRING(fd, 6, name, 24);
WFIFOSET(fd, 30);
}
RFIFOSKIP(fd, 6);
@@ -1863,10 +1851,9 @@ void parse_frommap(int fd)
case 0x2b0a:
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd, 2))
return;
-// PRINTF("parse_frommap: change gm -> login, account: %d, pass: '%s'.\n", RFIFOL(fd,4), RFIFOP(fd,8));
if (login_fd > 0)
{ // don't send request if no login-server
- size_t len = RFIFOW(fd, 2);
+ size_t len = RFIFOW(fd, 2);
RFIFO_WFIFO_CLONE(fd, login_fd, len);
WFIFOW(login_fd, 0) = 0x2720;
WFIFOSET(login_fd, len);
@@ -1901,7 +1888,7 @@ void parse_frommap(int fd)
{
char character_name[24];
int acc = RFIFOL(fd, 2); // account_id of who ask (-1 if nobody)
- strzcpy(character_name, static_cast<const char *>(RFIFOP(fd, 6)), 24);
+ RFIFO_STRING(fd, 6, character_name, 24);
// prepare answer
WFIFOW(fd, 0) = 0x2b0f; // answer
WFIFOL(fd, 2) = acc; // who want do operation
@@ -2045,17 +2032,13 @@ void parse_frommap(int fd)
set_account_reg2(acc, j, reg);
// loginサーバーへ送る
if (login_fd > 0)
- { // don't send request if no login-server
- RFIFO_WFIFO_CLONE(fd, login_fd, RFIFOW(fd, 2));
+ {
+ // don't send request if no login-server
+ RFIFO_WFIFO_CLONE(fd, login_fd, RFIFOW(fd, 2));
WFIFOW(login_fd, 0) = 0x2728;
WFIFOSET(login_fd, WFIFOW(login_fd, 2));
}
- // ワールドへの同垢ログインがなければmapサーバーに送る必要はない
- //memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
- //WBUFW(buf,0) = 0x2b11;
- //mapif_sendall(buf, WBUFW(buf,2));
RFIFOSKIP(fd, RFIFOW(fd, 2));
-// PRINTF("char: save_account_reg (from map)\n");
break;
}
@@ -2259,12 +2242,12 @@ void parse_char(int fd)
{
WFIFOW(login_fd, 0) = 0x2740;
WFIFOL(login_fd, 2) = sd->account_id;
- char old_pass[24];
- RFIFO_STRING(fd, 2, old_pass, 24);
- WFIFO_STRING(login_fd, 6, old_pass, 24);
- char new_pass[24];
- RFIFO_STRING(fd, 26, new_pass, 24);
- WFIFO_STRING(login_fd, 30, new_pass, 24);
+ char old_pass[24];
+ RFIFO_STRING(fd, 2, old_pass, 24);
+ WFIFO_STRING(login_fd, 6, old_pass, 24);
+ char new_pass[24];
+ RFIFO_STRING(fd, 26, new_pass, 24);
+ WFIFO_STRING(login_fd, 30, new_pass, 24);
WFIFOSET(login_fd, 54);
}
RFIFOSKIP(fd, 50);
@@ -2370,7 +2353,15 @@ void parse_char(int fd)
if (!sd || RFIFOREST(fd) < 37)
return;
{
- const struct mmo_charstatus *cd = make_new_char(fd, static_cast<const uint8_t *>(RFIFOP(fd, 2)));
+ char name[24];
+ RFIFO_STRING(fd, 2, name, 24);
+ uint8_t stats[6];
+ for (int i = 0; i < 6; ++i)
+ stats[i] = RFIFOB(fd, 26 + i);
+ uint8_t slot = RFIFOB(fd, 32);
+ uint16_t hair_color = RFIFOW(fd, 33);
+ uint16_t hair_style = RFIFOW(fd, 35);
+ const struct mmo_charstatus *cd = make_new_char(fd, name, stats, slot, hair_color, hair_style);
if (!cd)
{
WFIFOW(fd, 0) = 0x6e;
@@ -2381,7 +2372,7 @@ void parse_char(int fd)
}
WFIFOW(fd, 0) = 0x6d;
- WFIFO_ZERO(fd, 2, 106);
+ WFIFO_ZERO(fd, 2, 106);
WFIFOL(fd, 2) = cd->char_id;
WFIFOL(fd, 2 + 4) = cd->base_exp;
@@ -2409,7 +2400,7 @@ void parse_char(int fd)
WFIFOW(fd, 2 + 68) = cd->head_mid;
WFIFOW(fd, 2 + 70) = cd->hair_color;
- WFIFO_STRING(fd, 2 + 74, cd->name, 24);
+ WFIFO_STRING(fd, 2 + 74, cd->name, 24);
WFIFOB(fd, 2 + 98) = min(cd->attrs[ATTR::STR], 255);
WFIFOB(fd, 2 + 99) = min(cd->attrs[ATTR::AGI], 255);
@@ -2427,7 +2418,7 @@ void parse_char(int fd)
case 0x68: // delete char //Yor's Fix
if (!sd || RFIFOREST(fd) < 46)
return;
- RFIFO_STRING(fd, 6, email, 40);
+ RFIFO_STRING(fd, 6, email, 40);
if (e_mail_check(email) == 0)
strzcpy(email, "a@a.com", 40); // default e-mail
@@ -2480,8 +2471,12 @@ void parse_char(int fd)
if (server_fd[i] < 0)
break;
}
- if (i == MAX_MAP_SERVERS || strcmp(static_cast<const char *>(RFIFOP(fd, 2)), userid)
- || strcmp(static_cast<const char *>(RFIFOP(fd, 26)), passwd))
+ char userid_[24];
+ RFIFO_STRING(fd, 2, userid_, 24);
+ char passwd_[24];
+ RFIFO_STRING(fd, 26, passwd_, 24);
+ if (i == MAX_MAP_SERVERS || strcmp(userid_, userid)
+ || strcmp(passwd_, passwd))
{
WFIFOB(fd, 2) = 3;
WFIFOSET(fd, 3);
@@ -2495,11 +2490,12 @@ void parse_char(int fd)
server_fd[i] = fd;
if (anti_freeze_enable)
server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed
+ // ignore RFIFOL(fd, 50)
server[i].ip = RFIFOL(fd, 54);
server[i].port = RFIFOW(fd, 58);
server[i].users = 0;
- for (char (&mapi)[16] : server[i].maps)
- strzcpy(mapi, "", 16);
+ for (char (&mapi)[16] : server[i].maps)
+ strzcpy(mapi, "", 16);
WFIFOSET(fd, 3);
RFIFOSKIP(fd, 60);
realloc_fifo(fd, FIFOSIZE_SERVERLINK,
@@ -2561,7 +2557,7 @@ int mapif_sendall(const uint8_t *buf, unsigned int len)
int fd;
if ((fd = server_fd[i]) >= 0)
{
- WFIFO_BUF_CLONE(fd, buf, len);
+ WFIFO_BUF_CLONE(fd, buf, len);
WFIFOSET(fd, len);
c++;
}
@@ -2580,7 +2576,7 @@ int mapif_sendallwos(int sfd, const uint8_t *buf, unsigned int len)
int fd;
if ((fd = server_fd[i]) >= 0 && fd != sfd)
{
- WFIFO_BUF_CLONE(fd, buf, len);
+ WFIFO_BUF_CLONE(fd, buf, len);
WFIFOSET(fd, len);
c++;
}
@@ -2599,7 +2595,7 @@ int mapif_send(int fd, const uint8_t *buf, unsigned int len)
{
if (fd == server_fd[i])
{
- WFIFO_BUF_CLONE(fd, buf, len);
+ WFIFO_BUF_CLONE(fd, buf, len);
WFIFOSET(fd, len);
return 1;
}
@@ -2638,7 +2634,7 @@ void check_connect_login_server(TimerData *, tick_t)
session[login_fd]->func_parse = parse_tologin;
realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
WFIFOW(login_fd, 0) = 0x2710;
- WFIFO_ZERO(login_fd, 2, 24);
+ WFIFO_ZERO(login_fd, 2, 24);
WFIFO_STRING(login_fd, 2, userid, 24);
WFIFO_STRING(login_fd, 26, passwd, 24);
WFIFOL(login_fd, 50) = 0;
diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp
index 688c05a..38edb9b 100644
--- a/src/char/int_party.cpp
+++ b/src/char/int_party.cpp
@@ -382,8 +382,9 @@ void mapif_party_broken(int party_id, int flag)
// パーティ内発言
static
-void mapif_party_message(int party_id, int account_id, const char *mes, int len)
+void mapif_party_message(int party_id, int account_id, const char *mes)
{
+ size_t len = strlen(mes);
unsigned char buf[len + 12];
WBUFW(buf, 0) = 0x3827;
@@ -575,10 +576,9 @@ void mapif_parse_BreakParty(int fd, int party_id)
// パーティメッセージ送信
static
-void mapif_parse_PartyMessage(int, int party_id, int account_id, const char *mes,
- int len)
+void mapif_parse_PartyMessage(int, int party_id, int account_id, const char *mes)
{
- mapif_party_message(party_id, account_id, mes, len);
+ mapif_party_message(party_id, account_id, mes);
}
// パーティチェック要求
@@ -598,60 +598,114 @@ int inter_party_parse_frommap(int fd)
switch (RFIFOW(fd, 0))
{
case 0x3020:
+ {
+ int account = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ char nick[24];
+ RFIFO_STRING(fd, 30, nick, 24);
+ char map[16];
+ RFIFO_STRING(fd, 54, map, 16);
+ uint16_t lv = RFIFOW(fd, 70);
mapif_parse_CreateParty(fd,
- RFIFOL(fd, 2),
- static_cast<const char *>(RFIFOP(fd, 6)),
- static_cast<const char *>(RFIFOP(fd, 30)),
- static_cast<const char *>(RFIFOP(fd, 54)),
- RFIFOW(fd, 70));
+ account,
+ name,
+ nick,
+ map,
+ lv);
+ }
break;
case 0x3021:
- mapif_parse_PartyInfo(fd, RFIFOL(fd, 2));
+ {
+ int party_id = RFIFOL(fd, 2);
+ mapif_parse_PartyInfo(fd, party_id);
+ }
break;
case 0x3022:
+ {
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ char nick[24];
+ RFIFO_STRING(fd, 10, nick, 24);
+ char map[16];
+ RFIFO_STRING(fd, 34, map, 16);
+ uint16_t lv = RFIFOW(fd, 50);
mapif_parse_PartyAddMember(fd,
- RFIFOL(fd, 2),
- RFIFOL(fd, 6),
- static_cast<const char *>(RFIFOP(fd, 10)),
- static_cast<const char *>(RFIFOP(fd, 34)),
- RFIFOW(fd, 50));
+ party_id,
+ account_id,
+ nick,
+ map,
+ lv);
+ }
break;
case 0x3023:
+ {
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ uint16_t exp = RFIFOW(fd, 10);
+ uint16_t item = RFIFOW(fd, 12);
mapif_parse_PartyChangeOption(fd,
- RFIFOL(fd, 2),
- RFIFOL(fd, 6),
- RFIFOW(fd, 10),
- RFIFOW(fd, 12));
+ party_id,
+ account_id,
+ exp,
+ item);
+ }
break;
case 0x3024:
+ {
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
mapif_parse_PartyLeave(fd,
- RFIFOL(fd, 2),
- RFIFOL(fd, 6));
+ party_id,
+ account_id);
+ }
break;
case 0x3025:
+ {
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ char map[16];
+ RFIFO_STRING(fd, 10, map, 16);
+ uint8_t online = RFIFOB(fd, 26);
+ uint16_t lv = RFIFOW(fd, 27);
mapif_parse_PartyChangeMap(fd,
- RFIFOL(fd, 2),
- RFIFOL(fd, 6),
- static_cast<const char *>(RFIFOP(fd, 10)),
- RFIFOB(fd, 26),
- RFIFOW(fd, 27));
+ party_id,
+ account_id,
+ map,
+ online,
+ lv);
+ }
break;
case 0x3026:
- mapif_parse_BreakParty(fd,
- RFIFOL(fd, 2));
+ {
+ int party_id = RFIFOL(fd, 2);
+ mapif_parse_BreakParty(fd, party_id);
+ }
break;
case 0x3027:
+ {
+ size_t len = RFIFOW(fd, 2) - 12;
+ int party_id = RFIFOL(fd, 4);
+ int account_id = RFIFOL(fd, 8);
+ char mes[len];
+ RFIFO_STRING(fd, 12, mes, len);
mapif_parse_PartyMessage(fd,
- RFIFOL(fd, 4),
- RFIFOL(fd, 8),
- static_cast<const char *>(RFIFOP(fd, 12)),
- RFIFOW(fd, 2) - 12);
+ party_id,
+ account_id,
+ mes);
+ }
break;
case 0x3028:
+ {
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ char nick[24];
+ RFIFO_STRING(fd, 10, nick, 24);
mapif_parse_PartyCheck(fd,
- RFIFOL(fd, 2),
- RFIFOL(fd, 6),
- static_cast<const char *>(RFIFOP(fd, 10)));
+ party_id,
+ account_id,
+ nick);
+ }
break;
default:
return 0;
diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp
index 4067490..09ce9d4 100644
--- a/src/char/int_storage.cpp
+++ b/src/char/int_storage.cpp
@@ -208,7 +208,7 @@ void mapif_parse_SaveStorage(int fd)
else
{
s = account2storage(account_id);
- RFIFO_STRUCT(fd, 8, *s);
+ RFIFO_STRUCT(fd, 8, *s);
mapif_save_storage_ack(fd, account_id);
}
}
diff --git a/src/char/inter.cpp b/src/char/inter.cpp
index fab50d2..68d81e8 100644
--- a/src/char/inter.cpp
+++ b/src/char/inter.cpp
@@ -421,8 +421,8 @@ void mapif_parse_WisRequest(int fd)
size_t len = RFIFOW(fd, 2) - 52;
RFIFO_STRING(fd, 4, wd.src, 24);
RFIFO_STRING(fd, 28, wd.dst, 24);
- char tmpbuf[len];
- RFIFO_STRING(fd, 52, tmpbuf, len);
+ char tmpbuf[len];
+ RFIFO_STRING(fd, 52, tmpbuf, len);
wd.msg = std::string(tmpbuf);
wd.tick = gettick();
wis_db.insert(wd.id, wd);
diff --git a/src/common/dumb_ptr.hpp b/src/common/dumb_ptr.hpp
index e10ca3a..ab98b57 100644
--- a/src/common/dumb_ptr.hpp
+++ b/src/common/dumb_ptr.hpp
@@ -26,6 +26,7 @@
#include <algorithm>
#include "const_array.hpp"
+#include "strings.hpp"
// unmanaged new/delete-able pointer
// should be replaced by std::unique_ptr<T>
@@ -261,6 +262,8 @@ struct dumb_string
return !impl;
}
+ operator ZString() { return ZString(ZString::really_construct_from_a_pointer, c_str()); }
+
#if 0
friend bool operator == (dumb_string l, dumb_string r)
{
diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp
index f773c9f..582c152 100644
--- a/src/common/md5calc.cpp
+++ b/src/common/md5calc.cpp
@@ -317,7 +317,8 @@ const char *make_salt(void)
bool pass_ok(const char *password, const char *crypted)
{
char buf[40];
- strncpy(buf, crypted, 40);
+ strzcpy(buf, crypted, 40);
+ // crypted is like !salt$hash
char *salt = buf + 1;
*strchr(salt, '$') = '\0';
diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp
index 14b8bac..450aa61 100644
--- a/src/common/mmo.hpp
+++ b/src/common/mmo.hpp
@@ -92,6 +92,15 @@ struct skill_value
{
unsigned short lv;
SkillFlags flags;
+
+ friend bool operator == (const skill_value& l, const skill_value& r)
+ {
+ return l.lv == r.lv && l.flags == r.flags;
+ }
+ friend bool operator != (const skill_value& l, const skill_value& r)
+ {
+ return !(l == r);
+ }
};
struct global_reg
diff --git a/src/common/socket.cpp b/src/common/socket.cpp
index c509825..214fb5a 100644
--- a/src/common/socket.cpp
+++ b/src/common/socket.cpp
@@ -38,7 +38,7 @@ std::array<std::unique_ptr<struct socket_data>, FD_SETSIZE> session;
inline
void RFIFOFLUSH(int fd)
{
- really_memmove(&session[fd]->rdata[0], static_cast<const uint8_t *>(RFIFOP(fd, 0)), RFIFOREST(fd));
+ really_memmove(&session[fd]->rdata[0], &session[fd]->rdata[session[fd]->rdata_pos], RFIFOREST(fd));
session[fd]->rdata_size = RFIFOREST(fd);
session[fd]->rdata_pos = 0;
}
diff --git a/src/common/socket.hpp b/src/common/socket.hpp
index ef7b193..2366373 100644
--- a/src/common/socket.hpp
+++ b/src/common/socket.hpp
@@ -103,12 +103,18 @@ FILE *fopen_(const char *path, const char *mode);
bool free_fds(void);
template<class T>
-uint8_t *pod_addressof(T& structure)
+uint8_t *pod_addressof_m(T& structure)
{
static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs");
return &reinterpret_cast<uint8_t&>(structure);
}
+template<class T>
+const uint8_t *pod_addressof_c(const T& structure)
+{
+ static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs");
+ return &reinterpret_cast<const uint8_t&>(structure);
+}
/// Check how much can be read
@@ -141,7 +147,7 @@ uint32_t RFIFOL(int fd, size_t pos)
template<class T>
void RFIFO_STRUCT(int fd, size_t pos, T& structure)
{
- really_memcpy(pod_addressof(structure), static_cast<const uint8_t *>(RFIFOP(fd, pos)), sizeof(T));
+ really_memcpy(pod_addressof_m(structure), static_cast<const uint8_t *>(RFIFOP(fd, pos)), sizeof(T));
}
inline
void RFIFO_STRING(int fd, size_t pos, char *out, size_t len)
@@ -181,7 +187,7 @@ uint32_t RBUFL(const uint8_t *p, size_t pos)
template<class T>
void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure)
{
- really_memcpy(pod_addressof(structure), p + pos, sizeof(T));
+ really_memcpy(pod_addressof_m(structure), p + pos, sizeof(T));
}
inline
void RBUF_STRING(const uint8_t *p, size_t pos, char *out, size_t len)
@@ -220,7 +226,7 @@ uint32_t& WFIFOL(int fd, size_t pos)
template<class T>
void WFIFO_STRUCT(int fd, size_t pos, T& structure)
{
- really_memcpy(static_cast<uint8_t *>(WFIFOP(fd, pos)), pod_addressof(structure), sizeof(T));
+ really_memcpy(static_cast<uint8_t *>(WFIFOP(fd, pos)), pod_addressof_c(structure), sizeof(T));
}
inline
void WFIFO_STRING(int fd, size_t pos, const char *s, size_t len)
@@ -267,7 +273,7 @@ uint32_t& WBUFL(uint8_t *p, size_t pos)
template<class T>
void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure)
{
- really_memcpy(p + pos, pod_addressof(structure), sizeof(T));
+ really_memcpy(p + pos, pod_addressof_c(structure), sizeof(T));
}
inline
void WBUF_STRING(uint8_t *p, size_t pos, const char *s, size_t len)
diff --git a/src/common/strings.hpp b/src/common/strings.hpp
new file mode 100644
index 0000000..2d34d57
--- /dev/null
+++ b/src/common/strings.hpp
@@ -0,0 +1,537 @@
+#ifndef TMWA_COMMON_STRINGS_HPP
+#define TMWA_COMMON_STRINGS_HPP
+// strings.hpp - All the string classes you'll ever need.
+//
+// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "sanity.hpp"
+
+#include <cassert>
+#include <cstring>
+
+#include <iterator>
+#include <string>
+
+// It is a common mistake to assume that one string class for everything.
+// Because C++ and TMWA have a C legacy, there are a few more here
+// than would probably be necessary in an ideal language.
+namespace strings
+{
+ // owning
+ class MString;
+ class FString;
+ class TString; // C legacy version of SString
+ class SString; // is this one really worth it?
+
+ // non-owning
+ class ZString; // C legacy version of XString
+ class XString;
+
+ // semi-owning
+ template<uint8_t len>
+ class VString;
+
+ // simple pointer-wrapping iterator that can be used to get distinct
+ // types for different containers.
+ template<class Tag>
+ class _iterator
+ {
+ typedef _iterator X;
+
+ const char *_ptr;
+ public:
+ typedef ptrdiff_t difference_type;
+ typedef char value_type;
+ typedef const char *pointer;
+ typedef const char& reference;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ _iterator(const char *p=nullptr) : _ptr(p) {}
+
+ // iterator
+ reference operator *() { return *_ptr; }
+ X& operator ++() { ++_ptr; return *this; }
+ // equality comparable
+ friend bool operator == (X l, X r) { return l._ptr == r._ptr; }
+ // input iterator
+ friend bool operator != (X l, X r) { return !(l == r); }
+ pointer operator->() { return _ptr; }
+ X operator++ (int) { X out = *this; ++*this; return out; }
+ // forward iterator is mostly semantical, and the ctor is above
+ // bidirectional iterator
+ X& operator --() { --_ptr; return *this; }
+ X operator-- (int) { X out = *this; --*this; return out; }
+ // random access iterator
+ X& operator += (difference_type n) { _ptr += n; return *this; }
+ friend X operator + (X a, difference_type n) { return a += n; }
+ friend X operator + (difference_type n, X a) { return a += n; }
+ X& operator -= (difference_type n) { _ptr -= n; return *this; }
+ friend X operator - (X a, difference_type n) { return a -= n; }
+ friend difference_type operator - (X b, X a) { return b._ptr - a._ptr; }
+ reference operator[](difference_type n) { return _ptr[n]; }
+ friend bool operator < (X a, X b) { return a._ptr - b._ptr; }
+ friend bool operator > (X a, X b) { return b < a; }
+ friend bool operator >= (X a, X b) { return !(a < b); }
+ friend bool operator <= (X a, X b) { return !(a > b); }
+ };
+
+ /// A helper class that implements all the interesting stuff that can
+ /// be done on any constant string, in terms of .begin() and .end().
+ template<class T>
+ class _crtp_string
+ {
+ public:
+ // this will have to be changed if MString decides to join in.
+ typedef _iterator<T> iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ private:
+ const T& _ref() const { return static_cast<const T&>(*this); }
+ iterator begin() const { return _ref().begin(); }
+ iterator end() const { return _ref().end(); }
+ public:
+ size_t size() const { return end() - begin(); }
+ reverse_iterator rbegin() const { return reverse_iterator(end()); }
+ reverse_iterator rend() const { return reverse_iterator(begin()); }
+ operator bool() { return size(); }
+ bool operator !() { return !size(); }
+
+
+ char operator[](size_t i) const { return begin()[i]; }
+ char front() const { return *begin(); }
+ char back() const { return end()[-1]; }
+ const char *data() { return &*begin(); }
+
+ XString xslice_t(size_t o) const;
+ XString xslice_h(size_t o) const;
+ XString xrslice_t(size_t no) const;
+ XString xrslice_h(size_t no) const;
+ XString xlslice(size_t o, size_t l) const;
+ XString xpslice(size_t b, size_t e) const;
+ bool startswith(XString x) const;
+ bool endswith(XString x) const;
+ };
+
+
+ /// An owning string that is still expected to change.
+ /// The storage might not be contiguous, but it still offers
+ /// random-access iterators.
+ /// TODO implement a special one, to avoid quirks of std::string.
+ class MString
+ {
+ public:
+ typedef char *iterator;
+ typedef _iterator<MString> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ private:
+ std::string _hack;
+ public:
+ template<size_t n>
+ MString(char (&s)[n]) = delete;
+ template<size_t n>
+ MString(const char (&s)[n]) : _hack(s) {}
+ template<class It>
+ MString(It b, It e) : _hack(b, e) {}
+
+ iterator begin() { return &*_hack.begin(); }
+ iterator end() { return &*_hack.end(); }
+ const_iterator begin() const { return &*_hack.begin(); }
+ const_iterator end() const { return &*_hack.end(); }
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+ };
+
+ /// An owning string that has reached its final contents.
+ /// The storage is NUL-terminated
+ /// TODO implement a special one, that guarantees refcounting.
+ class FString : public _crtp_string<FString>
+ {
+ const std::string _hack;
+ public:
+ FString() : _hack() {}
+ FString(const MString& s) : _hack(s.begin(), s.end()) {}
+ template<size_t n>
+ FString(char (&s)[n]) = delete;
+ template<size_t n>
+ FString(const char (&s)[n]) : _hack(s) {}
+ template<class It>
+ FString(It b, It e) : _hack(b, e) {}
+
+ iterator begin() const { return &*_hack.begin(); }
+ iterator end() const { return &*_hack.end(); }
+ const char *c_str() const { return &*begin(); }
+
+ TString oslice_t(size_t o) const;
+ SString oslice_h(size_t o) const;
+ TString orslice_t(size_t no) const;
+ SString orslice_h(size_t no) const;
+ SString olslice(size_t o, size_t l) const;
+ SString opslice(size_t b, size_t e) const;
+ };
+
+ /// An owning string that represents a tail slice of an FString.
+ /// Guaranteed to be NUL-terminated.
+ class TString : public _crtp_string<TString>
+ {
+ friend class SString;
+ FString _s;
+ size_t _o;
+ public:
+ TString() : _s(), _o() {}
+ TString(FString b, size_t i=0) : _s(std::move(b)), _o(i) {}
+
+ iterator begin() const { return &_s.begin()[_o]; }
+ iterator end() const { return &*_s.end(); }
+ const char *c_str() const { return &*begin(); }
+
+ TString oslice_t(size_t o) const;
+ SString oslice_h(size_t o) const;
+ TString orslice_t(size_t no) const;
+ SString orslice_h(size_t no) const;
+ SString olslice(size_t o, size_t l) const;
+ SString opslice(size_t b, size_t e) const;
+
+ operator FString()
+ { if (_o) return FString(begin(), end()); else return _s; }
+ };
+
+ /// An owning string that represents a arbitrary slice of an FString.
+ /// Not guaranteed to be NUL-terminated.
+ class SString : public _crtp_string<SString>
+ {
+ FString _s;
+ size_t _b, _e;
+ public:
+ SString() : _s(), _b(), _e() {}
+ SString(FString f) : _s(std::move(f)), _b(), _e(_s.size()) {}
+ SString(TString t) : _s(t._s), _e(_s.size()) {}
+ SString(FString f, size_t b, size_t e) : _s(std::move(f)), _b(b), _e(e) {}
+
+ iterator begin() const { return &_s.begin()[_b]; }
+ iterator end() const { return &_s.begin()[_e]; }
+
+ SString oslice_t(size_t o) const;
+ SString oslice_h(size_t o) const;
+ SString orslice_t(size_t no) const;
+ SString orslice_h(size_t no) const;
+ SString olslice(size_t o, size_t l) const;
+ SString opslice(size_t b, size_t e) const;
+
+ operator FString()
+ { if (_b == 0 && _e == _s.size()) return _s; else return FString(begin(), end()); }
+ operator TString()
+ { if (_e == _s.size()) return TString(_s, _b); else return FString(begin(), end()); }
+ };
+
+ /// A non-owning string that is guaranteed to be NUL-terminated.
+ /// This should be only used as a parameter.
+ class ZString : public _crtp_string<ZString>
+ {
+ iterator _b, _e;
+ public:
+#ifndef __clang__
+ __attribute__((warning("This should be removed in the next diff")))
+#endif
+ ZString(const std::string& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ enum { really_construct_from_a_pointer };
+ ZString() { *this = ZString(""); }
+ // no MString
+ ZString(const FString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ ZString(const TString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ // no SString
+ ZString(decltype(really_construct_from_a_pointer), const char *s) : _b(s), _e(s + strlen(s)) {}
+ template<size_t n>
+ ZString(char (&s)[n]) = delete;
+ template<size_t n>
+ ZString(const char (&s)[n]) : _b(s), _e(s + strlen(s)) {}
+
+ iterator begin() const { return _b; }
+ iterator end() const { return _e; }
+ const char *c_str() const { return &*begin(); }
+
+ ZString oslice_t(size_t o) const;
+ XString oslice_h(size_t o) const;
+ ZString orslice_t(size_t no) const;
+ XString orslice_h(size_t no) const;
+ XString olslice(size_t o, size_t l) const;
+ XString opslice(size_t b, size_t e) const;
+ };
+
+ /// A non-owning string that is not guaranteed to be NUL-terminated.
+ /// This should be only used as a parameter.
+ class XString : public _crtp_string<XString>
+ {
+ iterator _b, _e;
+ public:
+ // do I really want this?
+ XString() : _b(nullptr), _e(nullptr) {}
+ XString(std::nullptr_t) = delete;
+ // no MString
+ XString(const FString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ XString(const TString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ XString(const SString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ XString(const ZString& s) : _b(&*s.begin()), _e(&*s.end()) {}
+ template<size_t n>
+ XString(char (&s)[n]) = delete;
+ template<size_t n>
+ XString(const char (&s)[n]) : _b(s), _e(s + strlen(s)) {}
+ // mostly internal
+ XString(const char *b, const char *e) : _b(b), _e(e) {}
+
+ iterator begin() const { return _b; }
+ iterator end() const { return _e; }
+
+ XString oslice_t(size_t o) const { return xslice_t(o); }
+ XString oslice_h(size_t o) const { return xslice_h(o); }
+ XString orslice_t(size_t no) const { return xrslice_t(no); }
+ XString orslice_h(size_t no) const { return xrslice_h(no); }
+ XString olslice(size_t o, size_t l) const { return xlslice(o, l); }
+ XString opslice(size_t b, size_t e) const { return xpslice(b, e); }
+ };
+
+ template<uint8_t n>
+ class VString : public _crtp_string<VString<n>>
+ {
+ char _data[n];
+ unsigned char _special;
+ typedef typename _crtp_string<VString<n>>::iterator iterator;
+ public:
+ static_assert(n & 1, "Size should probably be odd.");
+ VString(XString x) : _data(), _special()
+ {
+ if (x.size() > n)
+ // we're hoping this doesn't happen
+ // hopefully there will be few enough users of this class
+ x = x.xslice_h(n);
+ char *e = std::copy(x.begin(), x.end(), std::begin(_data));
+ _special = std::end(_data) - e;
+ assert (_special == n - x.size()); // 0 when it needs to be
+ }
+ // poor man's delegated constructors
+ // needed for gcc 4.6 compatibility
+ template<size_t m>
+ VString(char (&s)[m]) = delete;
+ template<size_t m>
+ VString(const char (&s)[m])
+ {
+ static_assert(m <= n + 1, "string would truncate");
+ *this = XString(s);
+ }
+ VString(decltype(ZString::really_construct_from_a_pointer) e, const char *s)
+ {
+ *this = XString(ZString(e, s));
+ }
+ VString()
+ {
+ *this = XString();
+ }
+ // hopefully this is obvious
+ iterator begin() const { return std::begin(_data); }
+ iterator end() const { return std::end(_data) - _special; }
+ const char *c_str() const { return &*begin(); }
+
+ VString oslice_t(size_t o) const { return this->xslice_t(o); }
+ VString oslice_h(size_t o) const { return this->xslice_h(o); }
+ VString orslice_t(size_t no) const { return this->xrslice_t(no); }
+ VString orslice_h(size_t no) const { return this->xrslice_h(no); }
+ VString olslice(size_t o, size_t l) const { return this->xlslice(o, l); }
+ VString opslice(size_t b, size_t e) const { return this->xpslice(b, e); }
+ operator XString() const { return XString(&*begin(), &*end()); }
+ };
+
+
+ // not really intended for public use
+ inline
+ int xstr_compare(XString l, XString r)
+ {
+ return std::lexicographical_compare(
+ l.begin(), l.end(),
+ r.begin(), r.end());
+ }
+
+ template<class L, class R>
+ bool operator == (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) == 0;
+ }
+ template<class L, class R>
+ bool operator != (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) != 0;
+ }
+ template<class L, class R>
+ bool operator < (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) < 0;
+ }
+ template<class L, class R>
+ bool operator <= (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) <= 0;
+ }
+ template<class L, class R>
+ bool operator > (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) > 0;
+ }
+ template<class L, class R>
+ bool operator >= (const L& l, const R& r)
+ {
+ return xstr_compare(l, r) >= 0;
+ }
+
+
+ // sadness
+ typedef MString MS;
+ typedef FString FS;
+ typedef SString SS;
+ typedef TString TS;
+ typedef ZString ZS;
+ typedef XString XS;
+
+ // _crtp_string
+ template<class T>
+ XS _crtp_string<T>::xslice_t(size_t o) const
+ { return XS(&begin()[o], &*end()); }
+ template<class T>
+ XS _crtp_string<T>::xslice_h(size_t o) const
+ { return XS(&*begin(), &begin()[o]); }
+ template<class T>
+ XS _crtp_string<T>::xrslice_t(size_t no) const
+ { return XS(&end()[-no], &*end()); }
+ template<class T>
+ XS _crtp_string<T>::xrslice_h(size_t no) const
+ { return XS(&*begin(), &end()[-no]); }
+ template<class T>
+ XS _crtp_string<T>::xlslice(size_t o, size_t l) const
+ { return XS(&begin()[o], &begin()[o + l]); }
+ template<class T>
+ XS _crtp_string<T>::xpslice(size_t b, size_t e) const
+ { return XS(&begin()[b], &begin()[e]); }
+ template<class T>
+ bool _crtp_string<T>::startswith(XS x) const
+ { return size() > x.size() && xslice_h(x.size()) == x; }
+ template<class T>
+ bool _crtp_string<T>::endswith(XS x) const
+ { return size() > x.size() && xrslice_t(x.size()) == x; }
+
+ // FString
+ inline
+ TS FS::oslice_t(size_t o) const
+ { return TS(*this, o); }
+ inline
+ SS FS::oslice_h(size_t o) const
+ { return SS(*this, 0, o); }
+ inline
+ TS FS::orslice_t(size_t no) const
+ { return TS(*this, size() - no); }
+ inline
+ SS FS::orslice_h(size_t no) const
+ { return SS(*this, 0, size() - no); }
+ inline
+ SS FS::olslice(size_t o, size_t l) const
+ { return SS(*this, o, o + l); }
+ inline
+ SS FS::opslice(size_t b, size_t e) const
+ { return SS(*this, b, e); }
+
+ // TString
+ inline
+ TS TS::oslice_t(size_t o) const
+ { return TS(_s, _o + o); }
+ inline
+ SS TS::oslice_h(size_t o) const
+ { return SS(_s, _o, _o + o); }
+ inline
+ TS TS::orslice_t(size_t no) const
+ { return TS(_s, _s.size() - no); }
+ inline
+ SS TS::orslice_h(size_t no) const
+ { return SS(_s, _o, _s.size() - no); }
+ inline
+ SS TS::olslice(size_t o, size_t l) const
+ { return SS(_s, _o + o, _o + o + l); }
+ inline
+ SS TS::opslice(size_t b, size_t e) const
+ { return SS(_s, _o + b, _o + e); }
+
+ // SString
+ inline
+ SS SS::oslice_t(size_t o) const
+ { return SS(_s, _b + o, _e); }
+ inline
+ SS SS::oslice_h(size_t o) const
+ { return SS(_s, _b, _b + o); }
+ inline
+ SS SS::orslice_t(size_t no) const
+ { return SS(_s, _e - no, _e); }
+ inline
+ SS SS::orslice_h(size_t no) const
+ { return SS(_s, _b, _e - no); }
+ inline
+ SS SS::olslice(size_t o, size_t l) const
+ { return SS(_s, _b + o, _b + o + l); }
+ inline
+ SS SS::opslice(size_t b, size_t e) const
+ { return SS(_s, _b + b, _b + e); }
+
+ // ZString
+ inline
+ ZS ZS::oslice_t(size_t o) const
+ { return ZS(really_construct_from_a_pointer, &begin()[o]); }
+ inline
+ XS ZS::oslice_h(size_t o) const
+ { return XS(&*begin(), &begin()[o]); }
+ inline
+ ZS ZS::orslice_t(size_t no) const
+ { return ZS(really_construct_from_a_pointer, &end()[-no]); }
+ inline
+ XS ZS::orslice_h(size_t no) const
+ { return XS(&*begin(), &end()[-no]); }
+ inline
+ XS ZS::olslice(size_t o, size_t l) const
+ { return XS(&begin()[o], &begin()[o + l]); }
+ inline
+ XS ZS::opslice(size_t b, size_t e) const
+ { return XS(&begin()[b], &begin()[e]); }
+
+
+ // cxxstdio helpers
+ // I think the conversion will happen automatically. TODO test this.
+ //const char *convert_for_printf(const FString& fs) { return fs.c_str(); }
+ //const char *convert_for_printf(const TString& ts) { return ts.c_str(); }
+ inline
+ const char *convert_for_printf(const ZString& zs) { return zs.c_str(); }
+} // namespace strings
+
+// owning
+using strings::MString;
+using strings::FString;
+using strings::SString;
+using strings::TString;
+
+// non-owning
+using strings::ZString;
+using strings::XString;
+
+// semi-owning
+using strings::VString;
+
+#endif // TMWA_COMMON_STRINGS_HPP
diff --git a/src/common/strings_test.cpp b/src/common/strings_test.cpp
new file mode 100644
index 0000000..e83d283
--- /dev/null
+++ b/src/common/strings_test.cpp
@@ -0,0 +1,99 @@
+#include "../../src/common/strings.hpp"
+
+#include <gtest/gtest.h>
+
+template<typename T>
+class StringTest : public ::testing::Test
+{
+};
+TYPED_TEST_CASE_P(StringTest);
+
+TYPED_TEST_P(StringTest, basic)
+{
+ TypeParam hi("Hello");
+ EXPECT_EQ(5, hi.size());
+ EXPECT_EQ(hi, hi);
+ const char hi2[] = "Hello\0random garbage";
+ EXPECT_EQ(hi, hi2);
+ TypeParam hi0;
+ EXPECT_EQ(0, hi0.size());
+}
+
+TYPED_TEST_P(StringTest, iterators)
+{
+ TypeParam hi("Hello");
+ EXPECT_EQ(hi.begin(), hi.begin());
+ EXPECT_NE(hi.begin(), hi.end());
+ EXPECT_EQ(5, std::distance(hi.begin(), hi.end()));
+ const char *hi2 = "Hello";
+ EXPECT_TRUE(std::equal(hi.begin(), hi.end(), hi2));
+}
+
+TYPED_TEST_P(StringTest, xslice)
+{
+ TypeParam hi("Hello, World!");
+ EXPECT_EQ(" World!", hi.xslice_t(6));
+ EXPECT_EQ("Hello,", hi.xslice_h(6));
+ EXPECT_EQ("World!", hi.xrslice_t(6));
+ EXPECT_EQ("Hello, ", hi.xrslice_h(6));
+ EXPECT_EQ("World", hi.xlslice(7, 5));
+ EXPECT_EQ("World", hi.xpslice(7, 12));
+ EXPECT_TRUE(hi.startswith("Hello"));
+ EXPECT_TRUE(hi.endswith("World!"));
+}
+
+TYPED_TEST_P(StringTest, oslice)
+{
+ TypeParam hi("Hello, World!");
+ EXPECT_EQ(" World!", hi.oslice_t(6));
+ EXPECT_EQ("Hello,", hi.oslice_h(6));
+ EXPECT_EQ("World!", hi.orslice_t(6));
+ EXPECT_EQ("Hello, ", hi.orslice_h(6));
+ EXPECT_EQ("World", hi.olslice(7, 5));
+ EXPECT_EQ("World", hi.opslice(7, 12));
+}
+
+REGISTER_TYPED_TEST_CASE_P(StringTest,
+ basic, iterators, xslice, oslice);
+
+typedef ::testing::Types<
+ FString, TString, SString, ZString, XString, VString<255>
+> MostStringTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(StringStuff, StringTest, MostStringTypes);
+
+TEST(VStringTest, basic)
+{
+ VString<5> hi = "Hello";
+ EXPECT_EQ(5, hi.size());
+ EXPECT_EQ(hi, hi);
+ // truncation
+ VString<5> hi2(ZString::really_construct_from_a_pointer, "Hello, world!");
+ EXPECT_EQ(5, hi2.size());
+ EXPECT_EQ(hi, hi2);
+ // short
+ hi = "hi";
+ EXPECT_EQ(2, hi.size());
+ VString<5> hi0;
+ EXPECT_EQ(0, hi0.size());
+}
+
+template<typename T>
+class NulStringTest : public ::testing::Test
+{
+};
+TYPED_TEST_CASE_P(NulStringTest);
+
+TYPED_TEST_P(NulStringTest, basic)
+{
+ TypeParam hi("hello");
+ EXPECT_EQ(hi.size(), strlen(hi.c_str()));
+ EXPECT_STREQ("hello", hi.c_str());
+}
+
+REGISTER_TYPED_TEST_CASE_P(NulStringTest,
+ basic);
+
+typedef ::testing::Types<
+ FString, TString, ZString, VString<255>
+> NulStringTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(NulStringStuff, NulStringTest, NulStringTypes);
diff --git a/src/common/utils.hpp b/src/common/utils.hpp
index cd45aa1..ab32948 100644
--- a/src/common/utils.hpp
+++ b/src/common/utils.hpp
@@ -34,7 +34,8 @@ void strzcpy(char *dest, const char *src, size_t n)
{
if (n)
{
- strncpy(dest, src, n);
+ // hmph
+ strncpy(dest, src, n - 1);
dest[n - 1] = '\0';
}
}
@@ -50,6 +51,11 @@ void really_memmove(uint8_t *dest, const uint8_t *src, size_t n)
{
memmove(dest, src, n);
}
+inline
+bool really_memequal(const uint8_t *a, const uint8_t *b, size_t n)
+{
+ return memcmp(a, b, n) == 0;
+}
inline
void really_memset0(uint8_t *dest, size_t n)
@@ -140,4 +146,10 @@ static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer),
&t \
)
+template<class T>
+const T& const_(T& t)
+{
+ return t;
+}
+
#endif //UTILS_HPP
diff --git a/src/common/utils2.hpp b/src/common/utils2.hpp
index 2218625..d7d6f8a 100644
--- a/src/common/utils2.hpp
+++ b/src/common/utils2.hpp
@@ -3,6 +3,7 @@
#include "sanity.hpp"
+#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
@@ -39,6 +40,26 @@ struct earray
{
return _data + size_t(max);
}
+
+ const T *begin() const
+ {
+ return _data;
+ }
+
+ const T *end() const
+ {
+ return _data + size_t(max);
+ }
+
+ friend bool operator == (const earray& l, const earray& r)
+ {
+ return std::equal(l.begin(), l.end(), r.begin());
+ }
+
+ friend bool operator != (const earray& l, const earray& r)
+ {
+ return !(l == r);
+ }
};
template<class T, class E>
diff --git a/src/ladmin/ladmin.cpp b/src/ladmin/ladmin.cpp
index c5a98fd..5f3ef7b 100644
--- a/src/ladmin/ladmin.cpp
+++ b/src/ladmin/ladmin.cpp
@@ -1392,7 +1392,7 @@ int delaccount(const char *param)
{
PRINTF("\033[1;36m ** Are you really sure to DELETE account [%s]? (y/n) > \033[0m", name);
fflush(stdout);
- strzcpy(confirm, "", sizeof(confirm));
+ strzcpy(confirm, "", sizeof(confirm));
i = 0;
while ((letter = getchar()) != '\n')
confirm[i++] = letter;
@@ -2709,7 +2709,7 @@ void parse_fromlogin(int fd)
char md5str[64] = "";
size_t key_len = RFIFOW(fd, 2) - 4;
uint8_t md5bin[32];
- char md5key[key_len];
+ char md5key[key_len];
RFIFO_STRING(fd, 4, md5key, key_len);
if (passenc == 1)
{
@@ -2878,84 +2878,104 @@ void parse_fromlogin(int fd)
case 0x7931: // Answer of login-server about an account creation
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int accid = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (accid == -1)
{
PRINTF("Account [%s] creation failed. Same account already exists.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] creation failed. Same account already exists.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s] is successfully created [id: %d].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
LADMIN_LOG("Account [%s] is successfully created [id: %d].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7933: // Answer of login-server about an account deletion
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int accid = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (accid == -1)
{
PRINTF("Account [%s] deletion failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] deletion failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] is successfully DELETED.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
LADMIN_LOG("Account [%s][id: %d] is successfully DELETED.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7935: // answer of the change of an account password
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int accid = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (accid == -1)
{
PRINTF("Account [%s] password changing failed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
PRINTF("Account [%s] doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account password changing failed. The compte [%s] doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] password successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
LADMIN_LOG("Account [%s][id: %d] password successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, accid);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7937: // answer of the change of an account state
if (RFIFOREST(fd) < 34)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int accid = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ int state = RFIFOL(fd, 30);
+ if (accid == -1)
{
PRINTF("Account [%s] state changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] state changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
std::string tmpstr = STRPRINTF(
"Account [%s] state successfully changed in [",
- static_cast<const char *>(RFIFOP(fd, 6)));
- switch (RFIFOL(fd, 30))
+ name);
+ switch (state)
{
case 0:
tmpstr += "0: Account OK";
@@ -2996,6 +3016,7 @@ void parse_fromlogin(int fd)
LADMIN_LOG("%s\n", tmpstr);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 34);
break;
@@ -3016,7 +3037,7 @@ void parse_fromlogin(int fd)
// Displaying of result
for (int i = 4; i < RFIFOW(fd, 2); i += 32)
{
- char name[20];
+ char name[20];
RFIFO_STRING(fd, i + 6, name, 20);
PRINTF(" %-20s : %5d\n", name,
RFIFOW(fd, i + 26));
@@ -3030,167 +3051,205 @@ void parse_fromlogin(int fd)
case 0x793b: // answer of the check of a password
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("The account [%s] doesn't exist or the password is incorrect.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("The account [%s] doesn't exist or the password is incorrect.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("The proposed password is correct for the account [%s][id: %d].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("The proposed password is correct for the account [%s][id: %d].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x793d: // answer of the change of an account sex
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] sex changing failed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
PRINTF("Account [%s] doesn't exist or the sex is already the good sex.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account sex changing failed. The compte [%s] doesn't exist or the sex is already the good sex.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] sex successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Account [%s][id: %d] sex successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x793f: // answer of the change of an account GM level
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] GM level changing failed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
PRINTF("Account [%s] doesn't exist, the GM level is already the good GM level\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
PRINTF("or it's impossible to modify the GM accounts file.\n");
LADMIN_LOG("Account GM level changing failed. The compte [%s] doesn't exist, the GM level is already the good sex or it's impossible to modify the GM accounts file.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] GM level successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Account [%s][id: %d] GM level successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7941: // answer of the change of an account email
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] e-mail changing failed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
PRINTF("Account [%s] doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account e-mail changing failed. The compte [%s] doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] e-mail successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Account [%s][id: %d] e-mail successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7943: // answer of the change of an account memo
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] memo changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] memo changing failed. Account doesn't exist.\n",
-
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("Account [%s][id: %d] memo successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Account [%s][id: %d] memo successfully changed.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7945: // answer of an account id search
if (RFIFOREST(fd) < 30)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Unable to find the account [%s] id. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Unable to find the account [%s] id. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
PRINTF("The account [%s] have the id: %d.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("The account [%s] have the id: %d.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7947: // answer of an account name search
if (RFIFOREST(fd) < 30)
return;
- if (strcmp(static_cast<const char *>(RFIFOP(fd, 6)), "") == 0)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (strcmp(name, "") == 0)
{
PRINTF("Unable to find the account [%d] name. Account doesn't exist.\n",
- RFIFOL(fd, 2));
+ account_id);
LADMIN_LOG("Unable to find the account [%d] name. Account doesn't exist.\n",
- RFIFOL(fd, 2));
+ account_id);
}
else
{
PRINTF("The account [id: %d] have the name: %s.\n",
- RFIFOL(fd, 2), static_cast<const char *>(RFIFOP(fd, 6)));
+ account_id, name);
LADMIN_LOG("The account [id: %d] have the name: %s.\n",
- RFIFOL(fd, 2), static_cast<const char *>(RFIFOP(fd, 6)));
+ account_id, name);
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 30);
break;
case 0x7949: // answer of an account validity limit set
if (RFIFOREST(fd) < 34)
return;
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
if (RFIFOL(fd, 2) == -1)
{
PRINTF("Account [%s] validity limit changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] validity limit changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
@@ -3198,34 +3257,39 @@ void parse_fromlogin(int fd)
if (!timestamp)
{
PRINTF("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
else
{
timestamp_seconds_buffer tmpstr;
stamp_time(tmpstr, &timestamp);
PRINTF("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2), tmpstr);
+ name, account_id, tmpstr);
LADMIN_LOG("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2),
+ name, account_id,
tmpstr);
}
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 34);
break;
case 0x794b: // answer of an account ban set
if (RFIFOREST(fd) < 34)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] final date of banishment changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] final date of banishment changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
@@ -3233,34 +3297,39 @@ void parse_fromlogin(int fd)
if (!timestamp)
{
PRINTF("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
else
{
timestamp_seconds_buffer tmpstr;
stamp_time(tmpstr, &timestamp);
PRINTF("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2), tmpstr);
+ name, RFIFOL(fd, 2), tmpstr);
LADMIN_LOG("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2),
+ name, RFIFOL(fd, 2),
tmpstr);
}
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 34);
break;
case 0x794d: // answer of an account ban date/time changing
if (RFIFOREST(fd) < 34)
return;
- if (RFIFOL(fd, 2) == -1)
+ {
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ if (account_id == -1)
{
PRINTF("Account [%s] final date of banishment changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
LADMIN_LOG("Account [%s] final date of banishment changing failed. Account doesn't exist.\n",
- static_cast<const char *>(RFIFOP(fd, 6)));
+ name);
}
else
{
@@ -3268,23 +3337,24 @@ void parse_fromlogin(int fd)
if (!timestamp)
{
PRINTF("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
LADMIN_LOG("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2));
+ name, account_id);
}
else
{
timestamp_seconds_buffer tmpstr;
stamp_time(tmpstr, &timestamp);
PRINTF("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2),
+ name, account_id,
tmpstr);
LADMIN_LOG("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n",
- static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2),
+ name, account_id,
tmpstr);
}
}
bytes_to_read = 0;
+ }
RFIFOSKIP(fd, 34);
break;
diff --git a/src/login/login.cpp b/src/login/login.cpp
index df271ef..d72bf61 100644
--- a/src/login/login.cpp
+++ b/src/login/login.cpp
@@ -391,7 +391,8 @@ bool check_ip(struct in_addr ip)
for (const AccessEntry& ae : access_allow)
{
const char *p = ae.data();
- if (memcmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
+#warning "TODO remove the strncmp part and use an IPAddress4 class"
+ if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
{
flag = ACF::ALLOW;
if (access_order == ACO::ALLOW_DENY)
@@ -404,7 +405,7 @@ bool check_ip(struct in_addr ip)
for (const AccessEntry& ae : access_deny)
{
const char *p = ae.data();
- if (memcmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
+ if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
{
flag = ACF::DENY;
return 0;
@@ -443,7 +444,7 @@ bool check_ladminip(struct in_addr ip)
for (const AccessEntry& ae : access_ladmin)
{
const char *p = ae.data();
- if (memcmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
+ if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p))
return true;
}
@@ -1151,7 +1152,6 @@ void parse_fromchar(int fd)
acc = RFIFOL(fd, 2); // speed up
RFIFO_STRING(fd, 6, email, 40);
remove_control_chars(email);
- //PRINTF("parse_fromchar: an e-mail creation of an account with a default e-mail: server '%s', account: %d, e-mail: '%s'.\n", server[id].name, acc, RFIFOP(fd,6));
if (e_mail_check(email) == 0)
LOGIN_LOG("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n",
server[id].name, acc, ip);
@@ -1214,7 +1214,11 @@ void parse_fromchar(int fd)
WBUFW(buf, 0) = 0x2721;
WBUFL(buf, 2) = acc;
WBUFL(buf, 6) = 0;
- if (strcmp(static_cast<const char *>(RFIFOP(fd, 8)), gm_pass) == 0)
+ size_t len = RFIFOW(fd, 2) - 8;
+ char pass[len];
+ RFIFO_STRING(fd, 8, pass, len);
+
+ if (strcmp(pass, gm_pass) == 0)
{
// only non-GM can become GM
if (isGM(acc) == 0)
@@ -1511,7 +1515,7 @@ void parse_fromchar(int fd)
{
LOGIN_LOG("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n",
server[id].name, acc, ip);
- size_t len = RFIFOW(fd, 2);
+ size_t len = RFIFOW(fd, 2);
int j;
for (p = 8, j = 0;
p < len && j < ACCOUNT_REG2_NUM;
@@ -1524,7 +1528,7 @@ void parse_fromchar(int fd)
ad.account_reg2_num = j;
// Sending information towards the other char-servers.
uint8_t buf[len];
- RFIFO_BUF_CLONE(fd, buf, len);
+ RFIFO_BUF_CLONE(fd, buf, len);
WBUFW(buf, 0) = 0x2729;
charif_sendallwos(fd, buf, WBUFW(buf, 2));
// PRINTF("parse_fromchar: receiving (from the char-server) of account_reg2 (account id: %d).\n", acc);
@@ -1578,7 +1582,7 @@ void parse_fromchar(int fd)
acc = RFIFOL(fd, 2);
RFIFO_STRING(fd, 6, actual_pass, 24);
remove_control_chars(actual_pass);
- RFIFO_STRING(fd, 30, new_pass, 24);
+ RFIFO_STRING(fd, 30, new_pass, 24);
remove_control_chars(new_pass);
int status = 0;
@@ -1637,7 +1641,7 @@ void parse_fromchar(int fd)
FPRINTF(logfp, "Detail (in hex):\n");
FPRINTF(logfp,
"---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n");
- char tmpstr[16 + 1] {};
+ char tmpstr[16 + 1] {};
int i;
for (i = 0; i < RFIFOREST(fd); i++)
{
@@ -1653,7 +1657,7 @@ void parse_fromchar(int fd)
else if ((i + 1) % 16 == 0)
{
FPRINTF(logfp, " %s\n", tmpstr);
- strzcpy(tmpstr, "", 16 + 1);
+ strzcpy(tmpstr, "", 16 + 1);
}
}
if (i % 16 != 0)
@@ -1774,7 +1778,7 @@ void parse_admin(int fd)
if (RFIFOREST(fd) < 10)
return;
uint8_t buf[10];
- RFIFO_BUF_CLONE(fd, buf, 10);
+ RFIFO_BUF_CLONE(fd, buf, 10);
// forward package to char servers
charif_sendallwos(-1, buf, 10);
RFIFOSKIP(fd, 10);
@@ -1826,7 +1830,7 @@ void parse_admin(int fd)
{
int new_id;
char email[40];
- strzcpy(email, static_cast<const char *>(RFIFOP(fd, 51)), 40);
+ RFIFO_STRING(fd, 51, email, 40);
remove_control_chars(email);
new_id = mmo_auth_new(&ma, ma.sex, email);
LOGIN_LOG("'ladmin': Account creation (account: %s (id: %d), sex: %c, email: %s, ip: %s)\n",
@@ -1847,13 +1851,12 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7933;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
AuthData *ad = search_account(account_name);
if (ad)
{
// TODO rename so I don't need anti-shadow braces
- {
// Char-server is notified of deletion (for characters deletion).
uint8_t buf[6];
WBUFW(buf, 0) = 0x2730;
@@ -1866,13 +1869,12 @@ void parse_admin(int fd)
LOGIN_LOG("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n",
ad->userid, ad->account_id,
ip);
- }
{
- std::string buf = mmo_auth_tostr(ad);
- LOGIN_LOG("%s\n", buf);
+ std::string buf2 = mmo_auth_tostr(ad);
+ LOGIN_LOG("%s\n", buf2);
}
// delete account
- strzcpy(ad->userid, "", 24);
+ strzcpy(ad->userid, "", 24);
ad->account_id = -1;
}
else
@@ -1892,13 +1894,15 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7935;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
AuthData *ad = search_account(account_name);
if (ad)
{
WFIFO_STRING(fd, 6, ad->userid, 24);
- strzcpy(ad->pass, MD5_saltcrypt(static_cast<const char *>(RFIFOP(fd, 26)), make_salt()), 40);
+ char plain[24];
+ RFIFO_STRING(fd, 26, plain, 24);
+ strzcpy(ad->pass, MD5_saltcrypt(plain, make_salt()), 40);
WFIFOL(fd, 2) = ad->account_id;
LOGIN_LOG("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n",
ad->userid, ad->pass, ip);
@@ -1922,10 +1926,10 @@ void parse_admin(int fd)
int statut;
WFIFOW(fd, 0) = 0x7937;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
statut = RFIFOL(fd, 26);
- strzcpy(error_message, static_cast<const char *>(RFIFOP(fd, 30)), 20);
+ RFIFO_STRING(fd, 30, error_message, 20);
remove_control_chars(error_message);
if (statut != 7 || error_message[0] == '\0')
{ // 7: // 6 = Your are Prohibited to log in until %s
@@ -2006,14 +2010,14 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x793b;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
const AuthData *ad = search_account(account_name);
if (ad)
{
WFIFO_STRING(fd, 6, ad->userid, 24);
char pass[24];
- strzcpy(pass, static_cast<const char *>(RFIFOP(fd, 26)), 24);
+ RFIFO_STRING(fd, 26, pass, 24);
if (pass_ok(pass, ad->pass))
{
WFIFOL(fd, 2) = ad->account_id;
@@ -2044,7 +2048,7 @@ void parse_admin(int fd)
return;
WFIFOW(fd, 0) = 0x793d;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
WFIFO_STRING(fd, 6, account_name, 24);
{
@@ -2107,7 +2111,7 @@ void parse_admin(int fd)
return;
WFIFOW(fd, 0) = 0x793f;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
WFIFO_STRING(fd, 6, account_name, 24);
{
@@ -2253,12 +2257,12 @@ void parse_admin(int fd)
return;
WFIFOW(fd, 0) = 0x7941;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
WFIFO_STRING(fd, 6, account_name, 24);
{
char email[40];
- strzcpy(email, static_cast<const char *>(RFIFOP(fd, 26)), 40);
+ RFIFO_STRING(fd, 26, email, 40);
if (e_mail_check(email) == 0)
{
LOGIN_LOG("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n",
@@ -2294,23 +2298,23 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7943;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
AuthData *ad = search_account(account_name);
if (ad)
{
size_t size_of_memo = sizeof(ad->memo);
WFIFO_STRING(fd, 6, ad->userid, 24);
- strzcpy(ad->memo, "", size_of_memo);
+ strzcpy(ad->memo, "", size_of_memo);
if (RFIFOW(fd, 26) == 0)
{
strzcpy(ad->memo, "!", size_of_memo);
}
else
{
- size_t len = RFIFOW(fd, 26);
- if (len > size_of_memo)
- len = size_of_memo;
+ size_t len = RFIFOW(fd, 26);
+ if (len > size_of_memo)
+ len = size_of_memo;
RFIFO_STRING(fd, 28, ad->memo, len);
}
ad->memo[size_of_memo - 1] = '\0';
@@ -2336,7 +2340,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7945;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
const AuthData *ad = search_account(account_name);
if (ad)
@@ -2363,12 +2367,12 @@ void parse_admin(int fd)
return;
WFIFOW(fd, 0) = 0x7947;
WFIFOL(fd, 2) = RFIFOL(fd, 2);
- WFIFO_ZERO(fd, 6, 24);
+ WFIFO_ZERO(fd, 6, 24);
for (const AuthData& ad : auth_data)
{
if (ad.account_id == RFIFOL(fd, 2))
{
- strncpy(static_cast<char *>(WFIFOP(fd, 6)), ad.userid, 24);
+ WFIFO_STRING(fd, 6, ad.userid, 24);
LOGIN_LOG("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n",
ad.userid, RFIFOL(fd, 2), ip);
goto x7946_out;
@@ -2376,7 +2380,7 @@ void parse_admin(int fd)
}
LOGIN_LOG("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n",
RFIFOL(fd, 2), ip);
- strncpy(static_cast<char *>(WFIFOP(fd, 6)), "", 24);
+ WFIFO_STRING(fd, 6, "", 24);
x7946_out:
WFIFOSET(fd, 30);
RFIFOSKIP(fd, 6);
@@ -2388,7 +2392,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7949;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
TimeT timestamp = static_cast<time_t>(RFIFOL(fd, 26));
timestamp_seconds_buffer tmpstr = "unlimited";
@@ -2427,7 +2431,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x794b;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
TimeT timestamp = static_cast<time_t>(RFIFOL(fd, 26));
if (timestamp <= TimeT::now())
@@ -2482,7 +2486,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x794d;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
AuthData *ad = search_account(account_name);
if (ad)
@@ -2587,22 +2591,28 @@ void parse_admin(int fd)
goto x794e_have_no_server;
{
x794e_have_server:
- // overwrite the -1
+ // overwrite the -1
WFIFOW(fd, 2) = 0;
- size_t len = RFIFOL(fd, 4);
- char message[len];
- RFIFO_STRING(fd, 8, message, len);
+ size_t len = RFIFOL(fd, 4);
+ char message[len];
+ RFIFO_STRING(fd, 8, message, len);
remove_control_chars(message);
- const char *message_ptr = message;
- LOGIN_LOG("'ladmin': Receiving a message for broadcast (message: %s, ip: %s)\n",
- message_ptr, ip);
+ const char *message_ptr = message;
+ LOGIN_LOG("'ladmin': Receiving a message for broadcast (message: %s, ip: %s)\n",
+ message_ptr, ip);
// send same message to all char-servers (no answer)
uint8_t buf[len + 8];
- RFIFO_BUF_CLONE(fd, buf, 8 + len);
+ RFIFO_BUF_CLONE(fd, buf, 8 + len);
WBUFW(buf, 0) = 0x2726;
charif_sendallwos(-1, buf, 8 + len);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized" // work around a gcc bug
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
}
+#pragma GCC diagnostic pop
}
x794e_have_no_server:
WFIFOSET(fd, 4);
@@ -2615,7 +2625,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7951;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
AuthData *ad = search_account(account_name);
if (ad)
@@ -2704,7 +2714,7 @@ void parse_admin(int fd)
{
WFIFOW(fd, 0) = 0x7953;
WFIFOL(fd, 2) = -1;
- strzcpy(account_name, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account_name, 24);
remove_control_chars(account_name);
const AuthData *ad = search_account(account_name);
if (ad)
@@ -2721,9 +2731,9 @@ void parse_admin(int fd)
WFIFO_STRING(fd, 100, ad->email, 40);
WFIFOL(fd, 140) = static_cast<time_t>(ad->connect_until_time);
WFIFOL(fd, 144) = static_cast<time_t>(ad->ban_until_time);
- size_t len = strlen(ad->memo) + 1;
+ size_t len = strlen(ad->memo) + 1;
WFIFOW(fd, 148) = len;
- WFIFO_STRING(fd, 150, ad->memo, len);
+ WFIFO_STRING(fd, 150, ad->memo, len);
LOGIN_LOG("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n",
ad->userid, ad->account_id,
ip);
@@ -2764,9 +2774,9 @@ void parse_admin(int fd)
WFIFO_STRING(fd, 100, ad.email, 40);
WFIFOL(fd, 140) = static_cast<time_t>(ad.connect_until_time);
WFIFOL(fd, 144) = static_cast<time_t>(ad.ban_until_time);
- size_t len = strlen(ad.memo) + 1;
+ size_t len = strlen(ad.memo) + 1;
WFIFOW(fd, 148) = len;
- WFIFO_STRING(fd, 150, ad.memo, len);
+ WFIFO_STRING(fd, 150, ad.memo, len);
WFIFOSET(fd, 150 + len);
goto x7954_out;
}
@@ -2774,7 +2784,7 @@ void parse_admin(int fd)
{
LOGIN_LOG("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n",
RFIFOL(fd, 2), ip);
- strncpy(static_cast<char *>(WFIFOP(fd, 7)), "", 24);
+ WFIFO_STRING(fd, 7, "", 24);
WFIFOW(fd, 148) = 0;
WFIFOSET(fd, 150);
}
@@ -2798,7 +2808,7 @@ void parse_admin(int fd)
if (logfp)
{
timestamp_milliseconds_buffer timestr;
- stamp_time(timestr);
+ stamp_time(timestr);
FPRINTF(logfp,
"%s: receiving of an unknown packet -> disconnection\n",
timestr);
@@ -2808,7 +2818,7 @@ void parse_admin(int fd)
FPRINTF(logfp, "Detail (in hex):\n");
FPRINTF(logfp,
"---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n");
- char tmpstr[16 + 1] {};
+ char tmpstr[16 + 1] {};
int i;
for (i = 0; i < RFIFOREST(fd); i++)
{
@@ -2905,16 +2915,24 @@ void parse_login(int fd)
if (RFIFOW(fd, 0) == 0x64 || RFIFOW(fd, 0) == 0x01dd)
{
if (RFIFOREST(fd) >= ((RFIFOW(fd, 0) == 0x64) ? 55 : 47))
+ {
+ char account_name[24];
+ RFIFO_STRING(fd, 6, account_name, 24);
PRINTF("parse_login: connection #%d, packet: 0x%x (with being read: %zu), account: %s.\n",
fd, RFIFOW(fd, 0), RFIFOREST(fd),
- static_cast<const char *>(RFIFOP(fd, 6)));
+ account_name);
+ }
}
else if (RFIFOW(fd, 0) == 0x2710)
{
if (RFIFOREST(fd) >= 86)
+ {
+ char server_name[16];
+ RFIFO_STRING(fd, 60, server_name, 16);
PRINTF("parse_login: connection #%d, packet: 0x%x (with being read: %zu), server: %s.\n",
fd, RFIFOW(fd, 0), RFIFOREST(fd),
- static_cast<const char *>(RFIFOP(fd, 60)));
+ server_name);
+ }
}
else
PRINTF("parse_login: connection #%d, packet: 0x%x (with being read: %zu).\n",
@@ -2939,9 +2957,9 @@ void parse_login(int fd)
if (RFIFOREST(fd) < 55)
return;
- strzcpy(account.userid, static_cast<const char *>(RFIFOP(fd, 6)), 24);
+ RFIFO_STRING(fd, 6, account.userid, 24);
remove_control_chars(account.userid);
- strzcpy(account.passwd, static_cast<const char *>(RFIFOP(fd, 30)), 24);
+ RFIFO_STRING(fd, 30, account.passwd, 24);
remove_control_chars(account.passwd);
account.passwdenc = 0;
@@ -3007,7 +3025,7 @@ void parse_login(int fd)
size_t host_len = strlen(update_host);
if (host_len > 0)
{
- host_len++;
+ host_len++;
WFIFOW(fd, 0) = 0x63;
WFIFOW(fd, 2) = 4 + host_len;
WFIFO_STRING(fd, 4, update_host, host_len);
@@ -3073,7 +3091,7 @@ void parse_login(int fd)
}
else
{
- WFIFO_ZERO(fd, 0, 23);
+ WFIFO_ZERO(fd, 0, 23);
WFIFOW(fd, 0) = 0x6a;
WFIFOB(fd, 2) = result;
if (result == 6)
@@ -3143,12 +3161,12 @@ void parse_login(int fd)
{
int len;
char server_name[20];
- strzcpy(account.userid, static_cast<const char *>(RFIFOP(fd, 2)), 24);
+ RFIFO_STRING(fd, 2, account.userid, 24);
remove_control_chars(account.userid);
- strzcpy(account.passwd, static_cast<const char *>(RFIFOP(fd, 26)), 24);
+ RFIFO_STRING(fd, 26, account.passwd, 24);
remove_control_chars(account.passwd);
account.passwdenc = 0;
- strzcpy(server_name, static_cast<const char *>(RFIFOP(fd, 60)), 20);
+ RFIFO_STRING(fd, 60, server_name, 20);
remove_control_chars(server_name);
LOGIN_LOG("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (ip: %s)\n",
server_name, RFIFOB(fd, 54), RFIFOB(fd, 55),
@@ -3265,7 +3283,7 @@ void parse_login(int fd)
{
// non encrypted password
char password[24];
- strzcpy(password, static_cast<const char *>(RFIFOP(fd, 4)), 24);
+ RFIFO_STRING(fd, 4, password, 24);
remove_control_chars(password);
// If remote administration is enabled and password sent by client matches password read from login server configuration file
if ((admin_state == 1)
@@ -3294,18 +3312,18 @@ void parse_login(int fd)
uint8_t md5bin[32];
if (RFIFOW(fd, 2) == 1)
{
- strncpy(md5str, ld->md5key, sizeof(ld->md5key)); // 20
+ strcpy(md5str, ld->md5key); // 20
strcat(md5str, admin_pass); // 24
}
else if (RFIFOW(fd, 2) == 2)
{
- strncpy(md5str, admin_pass, sizeof(admin_pass)); // 24
+ strcpy(md5str, admin_pass); // 24
strcat(md5str, ld->md5key); // 20
}
MD5_to_bin(MD5_from_cstring(md5str), md5bin);
// If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file
if ((admin_state == 1)
- && (memcmp(md5bin, RFIFOP(fd, 4), 16) == 0))
+ && really_memequal(md5bin, static_cast<const uint8_t *>(RFIFOP(fd, 4)), 16))
{
LOGIN_LOG("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n",
ip);
@@ -3346,7 +3364,7 @@ void parse_login(int fd)
FPRINTF(logfp,
"---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n");
- char tmpstr[16 + 1] {};
+ char tmpstr[16 + 1] {};
int i;
for (i = 0; i < RFIFOREST(fd); i++)
@@ -3363,7 +3381,7 @@ void parse_login(int fd)
else if ((i + 1) % 16 == 0)
{
FPRINTF(logfp, " %s\n", tmpstr);
- strzcpy(tmpstr, "", 16 + 1);
+ strzcpy(tmpstr, "", 16 + 1);
}
}
if (i % 16 != 0)
@@ -3397,7 +3415,7 @@ int login_lan_config_read(const char *lancfgName)
struct hostent *h = NULL;
// set default configuration
- strncpy(lan_char_ip, "127.0.0.1", sizeof(lan_char_ip));
+ strcpy(lan_char_ip, "127.0.0.1");
subneti[0] = 127;
subneti[1] = 0;
subneti[2] = 0;
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index 8e29f86..f893c2e 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -4,6 +4,8 @@
#include <cstring>
#include <ctime>
+#include <fstream>
+
#include "../common/core.hpp"
#include "../common/cxxstdio.hpp"
#include "../common/mmo.hpp"
@@ -432,14 +434,15 @@ bool is_atcommand(const int fd, dumb_ptr<map_session_data> sd,
}
{
- char command[100] {};
const char *str = message;
const char *p = message;
+ // split the first word
while (*p && !isspace(*p))
p++;
- if (p - str >= sizeof(command)) // too long
- return true;
- strncpy(command, str, p - str);
+ size_t len = p - str;
+ char command[len + 1];
+ strzcpy(command, str, len + 1);
+ // skip the spaces; pass as argv
while (isspace(*p))
p++;
@@ -447,7 +450,8 @@ bool is_atcommand(const int fd, dumb_ptr<map_session_data> sd,
if (info->proc(fd, sd, command, p) != 0)
{
// Command can not be executed
- std::string output = STRPRINTF("%s failed.", command);
+ const char *command_ = command;
+ std::string output = STRPRINTF("%s failed.", command_);
clif_displaymessage(fd, output);
}
else
@@ -1773,33 +1777,20 @@ int atcommand_joblevelup(const int fd, dumb_ptr<map_session_data> sd,
int atcommand_help(const int fd, dumb_ptr<map_session_data> sd,
const char *, const char *)
{
- char buf[2048] {};
- int i, gm_level;
- FILE *fp;
-
- if ((fp = fopen_(help_txt, "r")) != NULL)
+ std::ifstream in(help_txt);
+ if (in.is_open())
{
clif_displaymessage(fd, "Help commands:");
- gm_level = pc_isGM(sd);
- while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
+ int gm_level = pc_isGM(sd);
+ std::string line;
+ while (std::getline(in, line))
{
- if (buf[0] == '/' && buf[1] == '/')
+ std::string w1, w2;
+ if (!split_key_value(line, &w1, &w2))
continue;
- for (i = 0; buf[i] != '\0'; i++)
- {
- if (buf[i] == '\r' || buf[i] == '\n')
- {
- buf[i] = '\0';
- break;
- }
- }
- char w1[2048], w2[2048];
- if (sscanf(buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2)
- clif_displaymessage(fd, buf);
- else if (gm_level >= atoi(w1))
+ if (gm_level >= atoi(w1.c_str()))
clif_displaymessage(fd, w2);
}
- fclose_(fp);
}
else
{
diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp
index f2d5ec7..a1e0f55 100644
--- a/src/map/chrif.cpp
+++ b/src/map/chrif.cpp
@@ -22,7 +22,8 @@
#include "../poison.hpp"
static
-const int packet_len_table[0x20] = {
+const int packet_len_table[0x20] =
+{
60, 3, 10, 27, 22, -1, 6, -1, // 2af8-2aff
6, -1, 18, 7, -1, 49, 44, 0, // 2b00-2b07
6, 30, -1, 10, 86, 7, 44, 34, // 2b08-2b0f
@@ -179,9 +180,9 @@ int chrif_recvmap(int fd)
port = RFIFOW(fd, 8);
for (i = 10, j = 0; i < RFIFOW(fd, 2); i += 16, j++)
{
- map_setipport(static_cast<const char *>(RFIFOP(fd, i)), ip, port);
-// if (battle_config.etc_log)
-// PRINTF("recv map %d %s\n", j, RFIFOP(fd,i));
+ char map[16];
+ RFIFO_STRING(fd, i, map, 16);
+ map_setipport(map, ip, port);
}
if (battle_config.etc_log)
PRINTF("recv map on %s:%d (%d maps)\n", ip2str(ip), port, j);
@@ -244,8 +245,13 @@ int chrif_changemapserverack(int fd)
pc_authfail(sd->fd);
return 0;
}
- clif_changemapserver(sd, static_cast<const char *>(RFIFOP(fd, 18)), RFIFOW(fd, 34),
- RFIFOW(fd, 36), in_addr{RFIFOL(fd, 38)}, RFIFOW(fd, 42));
+ char mapname[16];
+ RFIFO_STRING(fd, 18, mapname, 16);
+ uint16_t x = RFIFOW(fd, 34);
+ uint16_t y = RFIFOW(fd, 36);
+ auto ip = in_addr{RFIFOL(fd, 38)};
+ uint16_t port = RFIFOW(fd, 42);
+ clif_changemapserver(sd, mapname, x, y, ip, port);
return 0;
}
@@ -887,7 +893,7 @@ int chrif_accountban(int fd)
TimeT timestamp = static_cast<time_t>(RFIFOL(fd, 7)); // status or final date of a banishment
char tmpstr[] = WITH_TIMESTAMP("Your account has been banished until ");
REPLACE_TIMESTAMP(tmpstr, timestamp);
- clif_displaymessage(sd->fd, tmpstr);
+ clif_displaymessage(sd->fd, const_(tmpstr));
}
clif_setwaitclose(sd->fd); // forced to disconnect for the change
}
@@ -1097,9 +1103,17 @@ void chrif_parse(int fd)
chrif_sendmapack(fd);
break;
case 0x2afd:
- pc_authok(RFIFOL(fd, 4), RFIFOL(fd, 8),
- static_cast<time_t>(RFIFOL(fd, 12)), RFIFOW(fd, 16),
- static_cast<const struct mmo_charstatus *>(RFIFOP(fd, 18)));
+ {
+ int id = RFIFOL(fd, 4);
+ int login_id2 = RFIFOL(fd, 8);
+ TimeT connect_until_time = static_cast<time_t>(RFIFOL(fd, 12));
+ short tmw_version = RFIFOW(fd, 16);
+ struct mmo_charstatus st {};
+ RFIFO_STRUCT(fd, 18, st);
+ pc_authok(id, login_id2,
+ connect_until_time, tmw_version,
+ &st);
+ }
break;
case 0x2afe:
pc_authfail(RFIFOL(fd, 2));
@@ -1117,7 +1131,12 @@ void chrif_parse(int fd)
chrif_changemapserverack(fd);
break;
case 0x2b09:
- map_addchariddb(RFIFOL(fd, 2), static_cast<const char *>(RFIFOP(fd, 6)));
+ {
+ int charid = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ map_addchariddb(charid, name);
+ }
break;
case 0x2b0b:
chrif_changedgm(fd);
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index c37916b..fab8932 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -248,15 +248,6 @@ void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len,
if (session[sd->fd] != NULL)
{
- if (WFIFOP(sd->fd, 0) == buf)
- {
- PRINTF("WARNING: Invalid use of clif_send function\n");
- PRINTF(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n",
- RBUFW(buf, 0));
- PRINTF(" Please correct your code.\n");
- // don't send to not move the pointer of the packet for next sessions in the loop
- }
- else
{
if (clif_parse_func_table[RBUFW(buf, 0)].len)
{
@@ -1261,15 +1252,15 @@ int clif_selllist(dumb_ptr<map_session_data> sd)
*/
int clif_scriptmes(dumb_ptr<map_session_data> sd, int npcid, const char *mes)
{
- int fd;
-
nullpo_ret(sd);
- fd = sd->fd;
+ int fd = sd->fd;
+
+ size_t len = strlen(mes) + 1;
WFIFOW(fd, 0) = 0xb4;
- WFIFOW(fd, 2) = strlen(mes) + 9;
+ WFIFOW(fd, 2) = len + 8;
WFIFOL(fd, 4) = npcid;
- strcpy(static_cast<char *>(WFIFOP(fd, 8)), mes);
+ WFIFO_STRING(fd, 8, mes, len);
WFIFOSET(fd, WFIFOW(fd, 2));
return 0;
@@ -1317,15 +1308,14 @@ int clif_scriptclose(dumb_ptr<map_session_data> sd, int npcid)
*/
int clif_scriptmenu(dumb_ptr<map_session_data> sd, int npcid, const char *mes)
{
- int fd;
-
nullpo_ret(sd);
- fd = sd->fd;
+ int fd = sd->fd;
+ size_t len = strlen(mes) + 1;
WFIFOW(fd, 0) = 0xb7;
- WFIFOW(fd, 2) = strlen(mes) + 8;
+ WFIFOW(fd, 2) = len + 8;
WFIFOL(fd, 4) = npcid;
- strcpy(static_cast<char *>(WFIFOP(fd, 8)), mes);
+ WFIFO_STRING(fd, 8, mes, len);
WFIFOSET(fd, WFIFOW(fd, 2));
return 0;
@@ -2275,13 +2265,11 @@ int clif_useitemack(dumb_ptr<map_session_data> sd, int index, int amount,
*/
int clif_traderequest(dumb_ptr<map_session_data> sd, const char *name)
{
- int fd;
-
nullpo_ret(sd);
- fd = sd->fd;
+ int fd = sd->fd;
WFIFOW(fd, 0) = 0xe5;
- strcpy(static_cast<char *>(WFIFOP(fd, 2)), name);
+ WFIFO_STRING(fd, 2, name, 24);
WFIFOSET(fd, clif_parse_func_table[0xe5].len);
return 0;
@@ -2608,16 +2596,17 @@ void clif_getareachar_pc(dumb_ptr<map_session_data> sd,
nullpo_retv(sd);
nullpo_retv(dstsd);
+ uint8_t buf[256];
if (dstsd->walktimer)
{
- len = clif_set007b(dstsd, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
- WFIFOSET(sd->fd, len);
+ len = clif_set007b(dstsd, buf);
}
else
{
- len = clif_set0078(dstsd, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
- WFIFOSET(sd->fd, len);
+ len = clif_set0078(dstsd, buf);
}
+ WFIFO_BUF_CLONE(sd->fd, buf, len);
+ WFIFOSET(sd->fd, len);
if (battle_config.save_clothcolor == 1 && dstsd->status.clothes_color > 0)
clif_changelook(dstsd, LOOK::CLOTHES_COLOR,
@@ -3137,7 +3126,7 @@ int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag)
* Send message (modified by [Yor])
*------------------------------------------
*/
-void clif_displaymessage(int fd, const_string mes)
+void clif_displaymessage(int fd, ZString mes)
{
if (mes)
{
@@ -3145,7 +3134,7 @@ void clif_displaymessage(int fd, const_string mes)
WFIFOW(fd, 0) = 0x8e;
size_t str_len = mes.size() + 1; // NUL (might not be NUL yet)
WFIFOW(fd, 2) = 4 + str_len;
- WFIFO_STRING(fd, 4, mes.data(), str_len);
+ WFIFO_STRING(fd, 4, mes.c_str(), str_len);
WFIFOSET(fd, 4 + str_len);
}
}
@@ -3154,14 +3143,14 @@ void clif_displaymessage(int fd, const_string mes)
* 天の声を送信する
*------------------------------------------
*/
-void clif_GMmessage(dumb_ptr<block_list> bl, const_string mes, int flag)
+void clif_GMmessage(dumb_ptr<block_list> bl, ZString mes, int flag)
{
size_t str_len = mes.size() + 1;
unsigned char buf[str_len + 4];
WBUFW(buf, 0) = 0x9a;
WBUFW(buf, 2) = str_len + 4;
- WBUF_STRING(buf, 4, mes.data(), str_len);
+ WBUF_STRING(buf, 4, mes.c_str(), str_len);
flag &= 0x07;
clif_send(buf, WBUFW(buf, 2), bl,
(flag == 1) ? SendWho::ALL_SAMEMAP :
@@ -4689,16 +4678,9 @@ void clif_parse_NpcStringInput(int fd, dumb_ptr<map_session_data> sd)
*/
if (len < 0)
return;
-
- if (len >= sizeof(sd->npc_str) - 1)
- {
- PRINTF("clif_parse_NpcStringInput(): Input string too long!\n");
- len = sizeof(sd->npc_str) - 1;
- }
-
- if (len > 0)
- strncpy(sd->npc_str, static_cast<const char *>(RFIFOP(fd, 8)), len);
- sd->npc_str[len] = '\0';
+ char buf[len];
+ RFIFO_STRING(fd, 8, buf, len);
+ sd->npc_str = buf;
map_scriptcont(sd, RFIFOL(fd, 4));
}
@@ -4783,7 +4765,9 @@ void clif_parse_CreateParty(int fd, dumb_ptr<map_session_data> sd)
if (battle_config.basic_skill_check == 0
|| pc_checkskill(sd, SkillID::NV_PARTY) >= 2)
{
- party_create(sd, static_cast<const char *>(RFIFOP(fd, 2)));
+ char name[24];
+ RFIFO_STRING(fd, 2, name, 24);
+ party_create(sd, name);
}
else
clif_skill_fail(sd, SkillID::ONE, 0, 4);
@@ -4841,7 +4825,10 @@ void clif_parse_LeaveParty(int, dumb_ptr<map_session_data> sd)
static
void clif_parse_RemovePartyMember(int fd, dumb_ptr<map_session_data> sd)
{
- party_removemember(sd, RFIFOL(fd, 2), static_cast<const char *>(RFIFOP(fd, 6)));
+ int account_id = RFIFOL(fd, 2);
+ char name[24];
+ RFIFO_STRING(fd, 6, name, 24);
+ party_removemember(sd, account_id, name);
}
/*==========================================
@@ -5584,14 +5571,16 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type)
return std::string();
}
- const char *p = static_cast<const char *>(RFIFOP(fd, 4));
+ size_t pstart = 4;
size_t buf_len = msg_len;
if (type == ChatType::Whisper)
{
- p += 24;
+ pstart += 24;
buf_len -= 24;
}
- const char *pend = p + buf_len;
+ char pbuf[buf_len + 1];
+ // I had to change strzcpy for this :(
+ RFIFO_STRING(fd, pstart, pbuf, buf_len + 1);
/*
* The client attempted to exceed the maximum message length.
@@ -5608,8 +5597,8 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type)
if (type == ChatType::Global)
{
- const char *pos = strstr(p, " : ");
- if (!pos || pos != p + name_len || memcmp(p, sd->status.name, name_len))
+ XString p = ZString(ZString::really_construct_from_a_pointer, pbuf);
+ if (!(p.startswith(const_(sd->status.name)) && p.xslice_t(name_len).startswith(" : ")))
{
/* Disallow malformed/spoofed messages. */
clif_setwaitclose(fd);
@@ -5617,12 +5606,10 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type)
return std::string();
}
/* Step beyond the separator. */
- p = pos + 3;
+ XString xs = p.xslice_t(name_len + 3);
+ return std::string(xs.begin(), xs.end());
}
-
- std::string buf(p, pend);
-
- return buf;
+ return pbuf;
}
/*==========================================
diff --git a/src/map/clif.hpp b/src/map/clif.hpp
index 5d48bc5..b9e2233 100644
--- a/src/map/clif.hpp
+++ b/src/map/clif.hpp
@@ -6,6 +6,7 @@
#include <functional>
#include "../common/const_array.hpp"
+#include "../common/strings.hpp"
#include "../common/timer.t.hpp"
#include "battle.t.hpp"
@@ -146,8 +147,8 @@ int clif_party_xy(struct party *p, dumb_ptr<map_session_data> sd);
int clif_party_hp(struct party *p, dumb_ptr<map_session_data> sd);
// atcommand
-void clif_displaymessage(int fd, const_string mes);
-void clif_GMmessage(dumb_ptr<block_list> bl, const_string mes, int flag);
+void clif_displaymessage(int fd, ZString mes);
+void clif_GMmessage(dumb_ptr<block_list> bl, ZString mes, int flag);
void clif_resurrection(dumb_ptr<block_list> bl, int type);
int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag); // special effects [Valaris]
diff --git a/src/map/intif.cpp b/src/map/intif.cpp
index 9e9d2e1..311c661 100644
--- a/src/map/intif.cpp
+++ b/src/map/intif.cpp
@@ -286,13 +286,16 @@ int intif_parse_WisEnd(int fd)
{
dumb_ptr<map_session_data> sd;
+ char name[24];
+ RFIFO_STRING(fd, 2, name, 24);
+ uint8_t flag = RFIFOB(fd, 26);
if (battle_config.etc_log)
// flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
PRINTF("intif_parse_wisend: player: %s, flag: %d\n",
- static_cast<const char *>(RFIFOP(fd, 2)), RFIFOB(fd, 26));
- sd = map_nick2sd(static_cast<const char *>(RFIFOP(fd, 2)));
+ name, flag);
+ sd = map_nick2sd(name);
if (sd != NULL)
- clif_wis_end(sd->fd, RFIFOB(fd, 26));
+ clif_wis_end(sd->fd, flag);
return 0;
}
@@ -414,8 +417,12 @@ void intif_parse_PartyCreated(int fd)
{
if (battle_config.etc_log)
PRINTF("intif: party created\n");
- party_created(RFIFOL(fd, 2), RFIFOB(fd, 6), RFIFOL(fd, 7),
- static_cast<const char *>(RFIFOP(fd, 11)));
+ int account_id = RFIFOL(fd, 2);
+ int fail = RFIFOB(fd, 6);
+ int party_id = RFIFOL(fd, 7);
+ char name[24];
+ RFIFO_STRING(fd, 11, name, 24);
+ party_created(account_id, fail, party_id, name);
}
// パーティ情報
@@ -438,7 +445,9 @@ void intif_parse_PartyInfo(int fd)
RFIFOL(fd, 4), RFIFOW(fd, 2),
sizeof(struct party) + 4);
}
- party_recv_info(static_cast<const struct party *>(RFIFOP(fd, 4)));
+ party p {};
+ RFIFO_STRUCT(fd, 4, p);
+ party_recv_info(&p);
}
// パーティ追加通知
@@ -463,10 +472,14 @@ void intif_parse_PartyOptionChanged(int fd)
static
void intif_parse_PartyMemberLeaved(int fd)
{
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ char name[24];
+ RFIFO_STRING(fd, 10, name, 24);
if (battle_config.etc_log)
- PRINTF("intif: party member leaved %d %d %s\n", RFIFOL(fd, 2),
- RFIFOL(fd, 6), static_cast<const char *>(RFIFOP(fd, 10)));
- party_member_leaved(RFIFOL(fd, 2), RFIFOL(fd, 6), static_cast<const char *>(RFIFOP(fd, 10)));
+ PRINTF("intif: party member leaved %d %d %s\n",
+ party_id, account_id, name);
+ party_member_leaved(party_id, account_id, name);
}
// パーティ解散通知
@@ -480,18 +493,19 @@ void intif_parse_PartyBroken(int fd)
static
void intif_parse_PartyMove(int fd)
{
-// if(battle_config.etc_log)
-// PRINTF("intif: party move %d %d %s %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOP(fd,10),RFIFOB(fd,26),RFIFOW(fd,27));
- party_recv_movemap(RFIFOL(fd, 2), RFIFOL(fd, 6), static_cast<const char *>(RFIFOP(fd, 10)),
- RFIFOB(fd, 26), RFIFOW(fd, 27));
+ int party_id = RFIFOL(fd, 2);
+ int account_id = RFIFOL(fd, 6);
+ char map[16];
+ RFIFO_STRING(fd, 10, map, 16);
+ uint8_t online = RFIFOB(fd, 26);
+ uint16_t lv = RFIFOW(fd, 27);
+ party_recv_movemap(party_id, account_id, map, online, lv);
}
// パーティメッセージ
static
void intif_parse_PartyMessage(int fd)
{
-// if(battle_config.etc_log)
-// PRINTF("intif_parse_PartyMessage: %s\n",RFIFOP(fd,12));
size_t len = RFIFOW(fd, 2) - 12;
char buf[len];
RFIFO_STRING(fd, 12, buf, len);
@@ -532,9 +546,11 @@ int intif_parse(int fd)
switch (cmd)
{
case 0x3800:
- clif_GMmessage(NULL,
- const_string(static_cast<const char *>(RFIFOP(fd, 4)),
- (packet_len - 4) - 1), 0);
+ {
+ char mes[packet_len - 4];
+ RFIFO_STRING(fd, 4, mes, packet_len - 4);
+ clif_GMmessage(NULL, ZString(ZString::really_construct_from_a_pointer, mes), 0);
+ }
break;
case 0x3801:
intif_parse_WisMessage(fd);
diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp
index e6c1f37..3d0c853 100644
--- a/src/map/magic-interpreter-base.cpp
+++ b/src/map/magic-interpreter-base.cpp
@@ -137,7 +137,7 @@ void magic_free_env(dumb_ptr<env_t> env)
}
dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell,
- dumb_ptr<map_session_data> caster, int spellpower, const_string param)
+ dumb_ptr<map_session_data> caster, int spellpower, const_string param)
{
dumb_ptr<env_t> env = alloc_env(conf);
diff --git a/src/map/magic-interpreter-lexer.lpp b/src/map/magic-interpreter-lexer.lpp
index c0a554b..a7c25e5 100644
--- a/src/map/magic-interpreter-lexer.lpp
+++ b/src/map/magic-interpreter-lexer.lpp
@@ -113,13 +113,13 @@
char *dst = &string[0];
while (*src && *src != '"')
{
- if (*src == '\\')
- {
- *dst++ = src[1];
- src += 2;
- }
- else
- *dst++ = *src++;
+ if (*src == '\\')
+ {
+ *dst++ = src[1];
+ src += 2;
+ }
+ else
+ *dst++ = *src++;
}
*dst = '\0'; /* terminate */
magic_frontend_lval.s = string;
diff --git a/src/map/map.hpp b/src/map/map.hpp
index 968bf43..cf52173 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -161,7 +161,7 @@ struct map_session_data : block_list, SessionData
// but one should probably be replaced with a ScriptPointer ???
const ScriptBuffer *npc_script, *npc_scriptroot;
std::vector<struct script_data> npc_stackbuf;
- char npc_str[256];
+ std::string npc_str;
struct
{
unsigned storage:1;
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index ffeb619..345f5a6 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -2313,7 +2313,6 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
int max_hp;
tick_t tick = gettick();
dumb_ptr<map_session_data> mvp_sd = NULL, second_sd = NULL, third_sd = NULL;
- double tdmg;
nullpo_ret(md); //srcはNULLで呼ばれる場合もあるので、他でチェック
@@ -2455,8 +2454,6 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
// map外に消えた人は計算から除くので
// overkill分は無いけどsumはmax_hpとは違う
- tdmg = 0;
-
// snip a prelude loop, now merged
std::sort(md->dmglogv.begin(), md->dmglogv.end(),
diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index 91331cb..ab6892a 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -205,8 +205,7 @@ int npc_event_doall_l(const char *name, int rid, int argc, argrec_t *args)
int c = 0;
char buf[64] = "::";
- strncpy(buf + 2, name, sizeof(buf)-3);
- buf[sizeof(buf)-1] = '\0';
+ strzcpy(buf + 2, name, 62);
for (auto& pair : ev_db)
npc_event_doall_sub(pair.first, &pair.second, &c, buf, rid, argc, args);
return c;
@@ -1624,10 +1623,8 @@ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y,
retval->bl_type = BL::NPC;
retval->npc_subtype = NpcSubtype::MESSAGE;
- strncpy(retval->name, name, 23);
- strncpy(retval->exname, name, 23);
- retval->name[15] = 0;
- retval->exname[15] = 0;
+ strzcpy(retval->name, name, 24);
+ strzcpy(retval->exname, name, 24);
if (message)
retval->message = message;
diff --git a/src/map/party.cpp b/src/map/party.cpp
index de655d7..62493c8 100644
--- a/src/map/party.cpp
+++ b/src/map/party.cpp
@@ -65,8 +65,7 @@ int party_create(dumb_ptr<map_session_data> sd, const char *name)
char pname[24];
nullpo_ret(sd);
- strncpy(pname, name, 24);
- pname[23] = '\0';
+ strzcpy(pname, name, 24);
tmw_TrimStr(pname);
/* The party name is empty/invalid. */
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index be59c0b..6759deb 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -4,6 +4,8 @@
#include <cstdlib>
#include <cstring>
+#include <fstream>
+
#include "../common/cxxstdio.hpp"
#include "../common/random.hpp"
#include "../common/nullpo.hpp"
@@ -732,25 +734,16 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time,
PRINTF("Connection accepted: Character '%s' (account: %d).\n",
sd->status.name, sd->status.account_id);
- // Message of the Dayの送信
+ // TODO fix this to cache and use inotify
{
- char buf[256];
- FILE *fp;
- if ((fp = fopen_(motd_txt, "r")) != NULL)
+ std::ifstream in(motd_txt);
+ if (in.is_open())
{
- while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
+ std::string buf;
+ while (std::getline(in, buf))
{
- for (int i = 0; buf[i]; i++)
- {
- if (buf[i] == '\r' || buf[i] == '\n')
- {
- buf[i] = 0;
- break;
- }
- }
clif_displaymessage(sd->fd, buf);
}
- fclose_(fp);
}
}
@@ -1447,9 +1440,9 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
return 0;
}
- if (memcmp(&b_skill, &sd->status.skill, sizeof(sd->status.skill))
+ if (b_skill != sd->status.skill
|| b_attackrange != sd->attackrange)
- clif_skillinfoblock(sd); // スキル送信
+ clif_skillinfoblock(sd);
if (b_speed != sd->speed)
clif_updatestatus(sd, SP::SPEED);
diff --git a/src/map/script.cpp b/src/map/script.cpp
index 0e95904..8ba2ebc 100644
--- a/src/map/script.cpp
+++ b/src/map/script.cpp
@@ -1563,7 +1563,7 @@ void builtin_input(ScriptState *st)
sd->state.menu_or_input = 0;
if (postfix == '$')
{
- set_reg(sd, type, num, dumb_string::fake(sd->npc_str));
+ set_reg(sd, type, num, dumb_string::fake(sd->npc_str.c_str()));
}
else
{
@@ -2795,7 +2795,7 @@ void builtin_announce(ScriptState *st)
static
void builtin_mapannounce_sub(dumb_ptr<block_list> bl, dumb_string str, int flag)
{
- clif_GMmessage(bl, str.c_str(), flag | 3);
+ clif_GMmessage(bl, str, flag | 3);
}
static
diff --git a/src/map/tmw.cpp b/src/map/tmw.cpp
index 9929e59..7afe3ca 100644
--- a/src/map/tmw.cpp
+++ b/src/map/tmw.cpp
@@ -63,7 +63,7 @@ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, const char *message)
if (tmw_CheckChatLameness(sd, message))
sd->chat_lines_in += battle_config.chat_lame_penalty;
- strncpy(sd->chat_lastmsg, message, battle_config.chat_maxline);
+ strzcpy(sd->chat_lastmsg, message, battle_config.chat_maxline);
if (sd->chat_lines_in >= battle_config.chat_spam_flood
|| sd->chat_total_repeats >= battle_config.chat_spam_flood)
diff --git a/src/poison.hpp b/src/poison.hpp
index 2a82a72..0a7cc57 100644
--- a/src/poison.hpp
+++ b/src/poison.hpp
@@ -74,3 +74,5 @@
#pragma GCC poison memcpy
#pragma GCC poison memmove
#pragma GCC poison memset
+#pragma GCC poison memcmp
+#pragma GCC poison strncpy // in favor of strzcpy
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
new file mode 100644
index 0000000..96d7200
--- /dev/null
+++ b/src/tests/main.cpp
@@ -0,0 +1,7 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}