diff options
89 files changed, 5860 insertions, 6101 deletions
@@ -12,3 +12,5 @@ /src/map/magic-interpreter-lexer.cpp # generated header dependencies /deps.make +# tags file +/tags diff --git a/.travis.yml b/.travis.yml index ead11f8..f45733d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: ## Do something after the main test script after_script: - - make test + - make test TESTER='valgrind --error-exitcode=1 --track-fds=yes' ### The rest of the file creates a build matrix ### containing gcc-4.6 through gcc-4.7 and clang-3.1 @@ -49,7 +49,7 @@ all: ${PROGS} most: ${MOSTPROGS} clean: rm -rf ${PROGS} ${BUILD_DIR}/ -common: ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/nullpo.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/cxxstdio.o ${BUILD_DIR}/common/extract.o +common: ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/nullpo.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/extract.o magic: ${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o ${BUILD_DIR}/map/magic-expr.o ${BUILD_DIR}/map/magic-interpreter-base.o ${BUILD_DIR}/map/magic-stmt.o ${BUILD_DIR}/map/magic.o # Top level programs @@ -64,15 +64,16 @@ 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 +${BUILD_DIR}/tests/main: ${BUILD_DIR}/tests/main.o $(patsubst src/%.cpp,obj/%.o,$(wildcard src/*/*_test.cpp)) ${BUILD_DIR}/gtest-all.o \ + ${BUILD_DIR}/common/extract.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/random.o test: ${BUILD_DIR}/tests/main - $< + ${TESTER} $< ${TEST_ARGS} # 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 -${BUILD_DIR}/login/login: ${BUILD_DIR}/login/login.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/md5calc.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/cxxstdio.o ${BUILD_DIR}/common/extract.o -${BUILD_DIR}/map/map: ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/tmw.o ${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o ${BUILD_DIR}/map/magic-interpreter-base.o ${BUILD_DIR}/map/magic-expr.o ${BUILD_DIR}/map/magic-stmt.o ${BUILD_DIR}/map/magic.o ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/chrif.o ${BUILD_DIR}/map/clif.o ${BUILD_DIR}/map/pc.o ${BUILD_DIR}/map/npc.o ${BUILD_DIR}/map/path.o ${BUILD_DIR}/map/itemdb.o ${BUILD_DIR}/map/mob.o ${BUILD_DIR}/map/script.o ${BUILD_DIR}/map/storage.o ${BUILD_DIR}/map/skill.o ${BUILD_DIR}/map/skill-pools.o ${BUILD_DIR}/map/atcommand.o ${BUILD_DIR}/map/battle.o ${BUILD_DIR}/map/intif.o ${BUILD_DIR}/map/trade.o ${BUILD_DIR}/map/party.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/map/grfio.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/nullpo.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/cxxstdio.o ${BUILD_DIR}/common/extract.o +${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/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/extract.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/utils.o +${BUILD_DIR}/login/login: ${BUILD_DIR}/login/login.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/md5calc.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/extract.o +${BUILD_DIR}/map/map: ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/tmw.o ${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o ${BUILD_DIR}/map/magic-interpreter-base.o ${BUILD_DIR}/map/magic-expr.o ${BUILD_DIR}/map/magic-stmt.o ${BUILD_DIR}/map/magic.o ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/chrif.o ${BUILD_DIR}/map/clif.o ${BUILD_DIR}/map/pc.o ${BUILD_DIR}/map/npc.o ${BUILD_DIR}/map/path.o ${BUILD_DIR}/map/itemdb.o ${BUILD_DIR}/map/mob.o ${BUILD_DIR}/map/script.o ${BUILD_DIR}/map/storage.o ${BUILD_DIR}/map/skill.o ${BUILD_DIR}/map/skill-pools.o ${BUILD_DIR}/map/atcommand.o ${BUILD_DIR}/map/battle.o ${BUILD_DIR}/map/intif.o ${BUILD_DIR}/map/trade.o ${BUILD_DIR}/map/party.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/map/grfio.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/nullpo.o ${BUILD_DIR}/common/random.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/utils.o ${BUILD_DIR}/common/extract.o ${BUILD_DIR}/tool/eathena-monitor: ${BUILD_DIR}/tool/eathena-monitor.o ${BUILD_DIR}/common/utils.o # silence build warnings for code beyond my control @@ -93,3 +94,9 @@ BACKUPS=numbered install: install -d ${prefix}/bin/ install --backup=${BACKUPS} -t ${prefix}/bin/ $(wildcard ${PROGS}) + +# might need changes later to handle static declarations (solution: +# run ctags twice, specifying forward patterns for the declarations +# and backward patterns for the definition) +tags: $(shell git ls-files src/) + ctags --totals --c-kinds=+px -f $@ $^ @@ -5,7 +5,10 @@ CXX = g++ LEX = flex BISON = bison -CXXFLAGS = -pipe -g -O2 ${WARNINGS} +CXXFLAGS = ${DEBUG} ${OPT} ${WARNINGS} +# these being separate use useful for development +DEBUG = -g +OPT = -pipe -O2 WARNINGS = -include src/warnings.hpp # Location of gtest source tree. It must contain the file src/gtest-all.cc @@ -14,10 +17,11 @@ WARNINGS = -include src/warnings.hpp # 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 +# gdb bug 15801 +CXX += -fabi-version=6 override CXX += -std=c++0x # for linking override CC = ${CXX} override CXXFLAGS += -fstack-protector -fno-strict-aliasing - +override CXXFLAGS += -fvisibility=hidden diff --git a/src/char/char.cpp b/src/char/char.cpp index d7e7a41..6108dca 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -12,12 +12,15 @@ #include <cstring> #include <ctime> +#include <bitset> #include <fstream> #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" +#include "../common/human_time_diff.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -48,21 +51,21 @@ std::chrono::milliseconds DEFAULT_AUTOSAVE_INTERVAL = static int login_fd, char_fd; static -char userid[24]; +AccountName userid; static -char passwd[24]; +AccountPass passwd; static -char server_name[20]; +ServerName server_name; static -char wisp_server_name[24] = "Server"; +CharName wisp_server_name = stringish<CharName>("Server"); static -char login_ip_str[16]; +IP_String login_ip_str; static int login_ip; static int login_port = 6900; static -char char_ip_str[16]; +IP_String char_ip_str; static int char_ip; static @@ -72,31 +75,29 @@ int char_maintenance; static int char_new; static -char char_txt[1024]; +FString char_txt; static -char unknown_char_name[24] = "Unknown"; +CharName unknown_char_name = stringish<CharName>("Unknown"); static -char char_log_filename[1024] = "log/char.log"; +FString char_log_filename = "log/char.log"; //Added for lan support static -char lan_map_ip[128]; +IP_String lan_map_ip; static uint8_t subneti[4]; static uint8_t subnetmaski[4]; static -int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor] -static int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] static -char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] +std::bitset<256> char_name_letters; // list of letters/symbols authorised (or not) in a character name. by [Yor] struct char_session_data : SessionData { int account_id, login_id1, login_id2, sex; unsigned short packet_tmw_version; - char email[40]; // e-mail (default: a@a.com) by [Yor] - TimeT connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + AccountEmail email; + TimeT connect_until_time; }; void SessionDeleter::operator()(SessionData *sd) @@ -140,16 +141,16 @@ int start_armor = 1202; // Initial position (it's possible to set it in conf file) static -struct point start_point = { "new_1-1.gat", 53, 111 }; +struct point start_point = { {"001-1.gat"}, 273, 354 }; static std::vector<GM_Account> gm_accounts; // online players by [Yor] static -char online_txt_filename[1024] = "online.txt"; +FString online_txt_filename = "online.txt"; static -char online_html_filename[1024] = "online.html"; +FString online_html_filename = "online.html"; static int online_sorting_option = 0; // sorting option to display online players in online files static @@ -168,13 +169,13 @@ pid_t pid = 0; // For forked DB writes //------------------------------ // Writing function of logs file //------------------------------ -void char_log(const_string line) +void char_log(XString line) { - FILE *logfp = fopen_(char_log_filename, "a"); + FILE *logfp = fopen(char_log_filename.c_str(), "a"); if (!logfp) return; log_with_timestamp(logfp, line); - fclose_(logfp); + fclose(logfp); } //---------------------------------------------------------------------- @@ -198,26 +199,16 @@ int isGM(int account_id) // and returns index if only 1 character is found // and similar to the searched name. //---------------------------------------------- -const mmo_charstatus *search_character(const char *character_name) +const mmo_charstatus *search_character(CharName character_name) { - int quantity = 0; - const mmo_charstatus *index = nullptr; for (const mmo_charstatus& cd : char_data) { - // Without case sensitive check (increase the number of similar character names found) - if (strcasecmp(cd.name, character_name) == 0) { // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(cd.name, character_name) == 0) + if (cd.name == character_name) return &cd; - quantity++; - index = &cd; } } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return index; // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found return nullptr; @@ -226,18 +217,16 @@ const mmo_charstatus *search_character(const char *character_name) //------------------------------------------------- // Function to create the character line (for save) //------------------------------------------------- -__inline__ static -std::string mmo_char_tostr(struct mmo_charstatus *p) +static +FString mmo_char_tostr(struct mmo_charstatus *p) { // on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart. - if (p->last_point.map_[0] == '\0') + if (!p->last_point.map_) { - strzcpy(p->last_point.map_, "001-1.gat", 16); - p->last_point.x = 273; - p->last_point.y = 354; + p->last_point = start_point; } - std::string str_p; + MString str_p; str_p += STRPRINTF( "%d\t" "%d,%d\t" @@ -329,11 +318,11 @@ std::string mmo_char_tostr(struct mmo_charstatus *p) p->global_reg[i].value); str_p += '\t'; - return str_p; + return FString(str_p); } static -bool extract(const_string str, struct point *p) +bool extract(XString str, struct point *p) { return extract(str, record<','>(&p->map_, &p->x, &p->y)); } @@ -346,7 +335,7 @@ struct skill_loader }; static -bool extract(const_string str, struct skill_loader *s) +bool extract(XString str, struct skill_loader *s) { uint32_t flags_and_level; if (!extract(str, @@ -361,7 +350,7 @@ bool extract(const_string str, struct skill_loader *s) // Function to set the character from the line (at read of characters file) //------------------------------------------------------------------------- static -bool extract(const_string str, struct mmo_charstatus *p) +bool extract(XString str, struct mmo_charstatus *p) { // initilialise character *p = mmo_charstatus{}; @@ -397,14 +386,14 @@ bool extract(const_string str, struct mmo_charstatus *p) vrec<' '>(&vars)))) return false; - if (strcmp(wisp_server_name, p->name) == 0) + if (wisp_server_name == p->name) return false; for (const mmo_charstatus& cd : char_data) { if (cd.char_id == p->char_id) return false; - if (strcmp(cd.name, p->name) == 0) + if (cd.name == p->name) return false; } @@ -448,7 +437,7 @@ int mmo_char_init(void) char_data.clear(); online_chars.clear(); - std::ifstream in(char_txt); + std::ifstream in(char_txt.c_str()); if (!in.is_open()) { PRINTF("Characters file not found: %s.\n", char_txt); @@ -459,17 +448,13 @@ int mmo_char_init(void) } int line_count = 0; - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { line_count++; - if (line[0] == '/' && line[1] == '/') + if (line.startswith("//")) continue; - if (line.back() == '\r') - { - line.back() = 0; - } { int i, j = 0; @@ -511,10 +496,7 @@ static void mmo_char_sync(void) { int lock; - FILE *fp; - - // Data save - fp = lock_fopen(char_txt, &lock); + FILE *fp = lock_fopen(char_txt, &lock); if (fp == NULL) { PRINTF("WARNING: Server can't not save characters.\n"); @@ -525,7 +507,7 @@ void mmo_char_sync(void) // yes, we need a mutable reference to do the saves ... for (mmo_charstatus& cd : char_data) { - std::string line = mmo_char_tostr(&cd); + FString line = mmo_char_tostr(&cd); fwrite(line.data(), 1, line.size(), fp); fputc('\n', fp); } @@ -565,43 +547,17 @@ void mmo_char_sync_timer(TimerData *, tick_t) _exit(0); } -//---------------------------------------------------- -// Remove trailing whitespace from a name -//---------------------------------------------------- -static -void remove_trailing_blanks(char *name) -{ - char *tail = name + strlen(name) - 1; - - while (tail > name && *tail == ' ') - *tail-- = 0; -} - -//---------------------------------------------------- -// Remove prefix whitespace from a name -//---------------------------------------------------- -static -void remove_prefix_blanks(char *name) -{ - char *dst = name; - char *src = name; - - while (*src == ' ') // find first nonblank - ++src; - while ((*dst++ = *src++)); // `strmove' -} - //----------------------------------- // Function to create a new character //----------------------------------- static -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) +mmo_charstatus *make_new_char(int fd, CharName name, const uint8_t (&stats)[6], uint8_t slot, uint16_t hair_color, uint16_t hair_style) { // ugh char_session_data *sd = static_cast<char_session_data *>(session[fd]->session_data.get()); // remove control characters from the name - if (remove_control_chars(name)) + if (!name.to__actual().is_print()) { CHAR_LOG("Make new char error (control char received in the name): (connection #%d, account: %d).\n", fd, sd->account_id); @@ -609,11 +565,15 @@ mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uin } // Eliminate whitespace - remove_trailing_blanks(name); - remove_prefix_blanks(name); + if (name.to__actual() != name.to__actual().strip()) + { + CHAR_LOG("Make new char error (leading/trailing whitespace): (connection #%d, account: %d, name: '%s'.\n", + fd, sd->account_id, name); + return nullptr; + } // check lenght of character name - if (strlen(name) < 4) + if (name.to__actual().size() < 4) { CHAR_LOG("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n", fd, sd->account_id, name); @@ -624,22 +584,22 @@ mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uin if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (int i = 0; name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) + for (uint8_t c : name.to__actual()) + if (!char_name_letters[c]) { 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, name, name[i]); + fd, sd->account_id, name, c); return nullptr; } } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (int i = 0; name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) + for (uint8_t c : name.to__actual()) + if (char_name_letters[c]) { 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, name, name[i]); + fd, sd->account_id, name, c); return nullptr; } } // else, all letters/symbols are authorised (except control char removed before) @@ -674,9 +634,7 @@ mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uin for (const mmo_charstatus& cd : char_data) { - if ((name_ignoring_case != 0 && strcmp(cd.name, name) == 0) - || (name_ignoring_case == 0 - && strcasecmp(cd.name, name) == 0)) + if (cd.name == name) { 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, slot, name, cd.name, @@ -697,7 +655,7 @@ mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uin } } - if (strcmp(wisp_server_name, name) == 0) + if (wisp_server_name == name) { 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, slot, name, wisp_server_name, @@ -723,7 +681,7 @@ mmo_charstatus *make_new_char(int fd, char *name, const uint8_t (&stats)[6], uin cd.char_id = char_id_count++; cd.account_id = sd->account_id; cd.char_num = slot; - strcpy(cd.name, name); + cd.name = name; cd.species = 0; cd.base_level = 1; cd.job_level = 1; @@ -771,10 +729,10 @@ static void create_online_files(void) { // write files - FILE *fp = fopen_(online_txt_filename, "w"); + FILE *fp = fopen(online_txt_filename.c_str(), "w"); if (fp != NULL) { - FILE *fp2 = fopen_(online_html_filename, "w"); + FILE *fp2 = fopen(online_html_filename.c_str(), "w"); if (fp2 != NULL) { // get time @@ -836,9 +794,9 @@ void create_online_files(void) FPRINTF(fp2, " <td>"); if (gml >= online_gm_display_min_level) FPRINTF(fp2, "<b>"); - for (int k = 0; cd.name[k]; k++) + for (char c : cd.name.to__actual()) { - switch (cd.name[k]) + switch (c) { case '&': FPRINTF(fp2, "&"); @@ -850,7 +808,7 @@ void create_online_files(void) FPRINTF(fp2, ">"); break; default: - FPRINTF(fp2, "%c", cd.name[k]); + FPRINTF(fp2, "%c", c); break; }; } @@ -882,9 +840,9 @@ void create_online_files(void) } FPRINTF(fp2, " </BODY>\n"); FPRINTF(fp2, "</HTML>\n"); - fclose_(fp2); + fclose(fp2); } - fclose_(fp); + fclose(fp); } return; @@ -983,7 +941,7 @@ int mmo_char_send006b(int fd, struct char_session_data *sd) WFIFOW(fd, j + 72) = find_equip_view(p, EPOS::MISC2); // WFIFOW(fd,j+72) = p->clothes_color; - WFIFO_STRING(fd, j + 74, p->name, 24); + WFIFO_STRING(fd, j + 74, p->name.to__actual(), 24); WFIFOB(fd, j + 98) = min(p->attrs[ATTR::STR], 255); WFIFOB(fd, j + 99) = min(p->attrs[ATTR::AGI], 255); @@ -1192,9 +1150,9 @@ void parse_tologin(int fd) // PRINTF("max_connect_user (unlimited) -> accepted.\n"); // else // PRINTF("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user); - RFIFO_STRING(fd, 7, sd->email, 40); - if (e_mail_check(sd->email) == 0) - strzcpy(sd->email, "a@a.com", 40); // default e-mail + sd->email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 7)); + if (!e_mail_check(sd->email)) + sd->email = DEFAULT_EMAIL; sd->connect_until_time = static_cast<time_t>(RFIFOL(fd, 47)); // send characters to player mmo_char_send006b(i, sd); @@ -1226,9 +1184,9 @@ void parse_tologin(int fd) { if (sd->account_id == RFIFOL(fd, 2)) { - 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->email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 6)); + if (!e_mail_check(sd->email)) + sd->email = DEFAULT_EMAIL; sd->connect_until_time = static_cast<time_t>(RFIFOL(fd, 46)); break; } @@ -1309,29 +1267,20 @@ void parse_tologin(int fd) else { size_t len = RFIFOL(fd, 4); - char message[len]; - RFIFO_STRING(fd, 8, message, len); - remove_control_chars(message); - // remove all first spaces - char *p = message; - while (p[0] == ' ') - p++; + FString message = RFIFO_STRING(fd, 8, len).to_print().lstrip(); // if message is only composed of spaces - if (p[0] == '\0') + if (!message) CHAR_LOG("Receiving a message for broadcast, but message is only a lot of spaces.\n"); // else send message to all map-servers else { - { - const char *message_ptr = message; - CHAR_LOG("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", - message_ptr); - } + CHAR_LOG("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", + message); // send broadcast to all map-servers uint8_t buf[4 + len]; WBUFW(buf, 0) = 0x3800; - WBUFW(buf, 2) = 4 + sizeof(message); - WBUF_STRING(buf, 4, message, sizeof(message)); + WBUFW(buf, 2) = 4 + len; + WBUF_STRING(buf, 4, message, len); mapif_sendall(buf, WBUFW(buf, 2)); } } @@ -1351,7 +1300,7 @@ void parse_tologin(int fd) p < RFIFOW(fd, 2) && j < ACCOUNT_REG2_NUM; p += 36, j++) { - RFIFO_STRING(fd, p, reg[j].str, 32); + reg[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p)); reg[j].value = RFIFOL(fd, p + 32); } set_account_reg2(acc, j, reg); @@ -1594,7 +1543,6 @@ void parse_frommap(int fd) { // don't send request if no login-server WFIFOW(login_fd, 0) = 0x2709; WFIFOSET(login_fd, 2); -// PRINTF("char : request from map-server to reload GM accounts -> login-server.\n"); } RFIFOSKIP(fd, 2); break; @@ -1604,13 +1552,12 @@ 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 (MapName &foo : server[id].maps) + foo = MapName(); int j = 0; for (int i = 4; i < RFIFOW(fd, 2); i += 16) { - RFIFO_STRING(fd, i, server[id].maps[j], 16); -// PRINTF("set map %d.%d : %s\n", id, j, server[id].map[j]); + server[id].maps[j] = RFIFO_STRING<16>(fd, i); j++; } { @@ -1624,7 +1571,7 @@ void parse_frommap(int fd) } WFIFOW(fd, 0) = 0x2afb; WFIFOB(fd, 2) = 0; - WFIFO_STRING(fd, 3, wisp_server_name, 24); + WFIFO_STRING(fd, 3, wisp_server_name.to__actual(), 24); WFIFOSET(fd, 27); { unsigned char buf[16384]; @@ -1831,7 +1778,7 @@ void parse_frommap(int fd) if (RFIFOREST(fd) < 6) return; { - const char *name = unknown_char_name; + CharName name = unknown_char_name; for (const mmo_charstatus& cd : char_data) { if (cd.char_id == RFIFOL(fd, 2)) @@ -1842,7 +1789,7 @@ void parse_frommap(int fd) } WFIFOW(fd, 0) = 0x2b09; WFIFOL(fd, 2) = RFIFOL(fd, 2); - WFIFO_STRING(fd, 6, name, 24); + WFIFO_STRING(fd, 6, name.to__actual(), 24); WFIFOSET(fd, 30); } RFIFOSKIP(fd, 6); @@ -1887,9 +1834,8 @@ void parse_frommap(int fd) if (RFIFOREST(fd) < 44) return; { - char character_name[24]; int acc = RFIFOL(fd, 2); // account_id of who ask (-1 if nobody) - RFIFO_STRING(fd, 6, character_name, 24); + CharName character_name = stringish<CharName>(RFIFO_STRING<24>(fd, 6)); // prepare answer WFIFOW(fd, 0) = 0x2b0f; // answer WFIFOL(fd, 2) = acc; // who want do operation @@ -1898,7 +1844,7 @@ void parse_frommap(int fd) const mmo_charstatus *cd = search_character(character_name); if (cd) { - WFIFO_STRING(fd, 6, cd->name, 24); // put correct name if found + WFIFO_STRING(fd, 6, cd->name.to__actual(), 24); // put correct name if found WFIFOW(fd, 32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline switch (RFIFOW(fd, 30)) { @@ -1928,12 +1874,9 @@ void parse_frommap(int fd) { // don't send request if no login-server WFIFOW(login_fd, 0) = 0x2725; WFIFOL(login_fd, 2) = cd->account_id; // account value - WFIFOW(login_fd, 6) = RFIFOW(fd, 32); // year - WFIFOW(login_fd, 8) = RFIFOW(fd, 34); // month - WFIFOW(login_fd, 10) = RFIFOW(fd, 36); // day - WFIFOW(login_fd, 12) = RFIFOW(fd, 38); // hour - WFIFOW(login_fd, 14) = RFIFOW(fd, 40); // minute - WFIFOW(login_fd, 16) = RFIFOW(fd, 42); // second + HumanTimeDiff ban_change; + RFIFO_STRUCT(fd, 32, ban_change); + WFIFO_STRUCT(login_fd, 6, ban_change); WFIFOSET(login_fd, 18); // PRINTF("char : status -> login: account %d, ban: %dy %dm %dd %dh %dmn %ds\n", // char_data[i].account_id, (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), (short)RFIFOW(fd,38), (short)RFIFOW(fd,40), (short)RFIFOW(fd,42)); @@ -2001,7 +1944,7 @@ void parse_frommap(int fd) else { // character name not found - WFIFO_STRING(fd, 6, character_name, 24); + WFIFO_STRING(fd, 6, character_name.to__actual(), 24); WFIFOW(fd, 32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline } // send answer if a player ask, not if the server ask @@ -2027,7 +1970,7 @@ void parse_frommap(int fd) p < RFIFOW(fd, 2) && j < ACCOUNT_REG2_NUM; p += 36, j++) { - RFIFO_STRING(fd, p, reg[j].str, 32); + reg[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p)); reg[j].value = RFIFOL(fd, p + 32); } set_account_reg2(acc, j, reg); @@ -2079,29 +2022,14 @@ void parse_frommap(int fd) } static -int search_mapserver(const char *map) +int search_mapserver(XString map) { - int i, j; - char temp_map[16]; - int temp_map_len; - -// PRINTF("Searching the map-server for map '%s'... ", map); - strzcpy(temp_map, map, sizeof(temp_map)); - if (strchr(temp_map, '.') != NULL) - temp_map[strchr(temp_map, '.') - temp_map + 1] = '\0'; // suppress the '.gat', but conserve the '.' to be sure of the name of the map - - temp_map_len = strlen(temp_map); - for (i = 0; i < MAX_MAP_SERVERS; i++) + for (int i = 0; i < MAX_MAP_SERVERS; i++) if (server_fd[i] >= 0) - for (j = 0; server[i].maps[j][0]; j++) - //PRINTF("%s : %s = %d\n", server[i].map[j], map, strncmp(server[i].map[j], temp_map, temp_map_len)); - if (strncmp(server[i].maps[j], temp_map, temp_map_len) == 0) - { -// PRINTF("found -> server #%d.\n", i); + for (int j = 0; server[i].maps[j][0]; j++) + if (server[i].maps[j] == map) return i; - } -// PRINTF("not found.\n"); return -1; } @@ -2134,7 +2062,7 @@ int lan_ip_check(unsigned char *p) static void handle_x0066(int fd, struct char_session_data *sd, uint8_t rfifob_2, uint8_t *p) { - const char *ip = ip2str(session[fd]->client_addr.sin_addr); + IP_String ip = ip2str(session[fd]->client_addr.sin_addr); { mmo_charstatus *cd = nullptr; @@ -2164,7 +2092,7 @@ void handle_x0066(int fd, struct char_session_data *sd, uint8_t rfifob_2, uint8_ && server[j].maps[0][0]) { // change save point to one of map found on the server (the first) i = j; - strzcpy(cd->last_point.map_, server[j].maps[0], 16); + cd->last_point.map_ = server[j].maps[0]; PRINTF("Map-server #%d found with a map: '%s'.\n", j, server[j].maps[0]); // coordonates are unknown @@ -2187,7 +2115,7 @@ void handle_x0066(int fd, struct char_session_data *sd, uint8_t rfifob_2, uint8_ sd->account_id, cd->char_num, ip); PRINTF("--Send IP of map-server. "); if (lan_ip_check(p)) - WFIFOL(fd, 22) = inet_addr(lan_map_ip); + WFIFOL(fd, 22) = inet_addr(lan_map_ip.c_str()); else WFIFOL(fd, 22) = server[i].ip; WFIFOW(fd, 26) = server[i].port; @@ -2211,7 +2139,6 @@ void handle_x0066(int fd, struct char_session_data *sd, uint8_t rfifob_2, uint8_ static void parse_char(int fd) { - char email[40]; uint8_t *p = reinterpret_cast<uint8_t *>(&session[fd]->client_addr.sin_addr); if (login_fd < 0 || session[fd]->eof) @@ -2243,11 +2170,9 @@ 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); + AccountPass old_pass = stringish<AccountPass>(RFIFO_STRING<24>(fd, 2)); WFIFO_STRING(login_fd, 6, old_pass, 24); - char new_pass[24]; - RFIFO_STRING(fd, 26, new_pass, 24); + AccountPass new_pass = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26)); WFIFO_STRING(login_fd, 30, new_pass, 24); WFIFOSET(login_fd, 54); } @@ -2269,7 +2194,7 @@ void parse_char(int fd) { session[fd]->session_data = make_unique<char_session_data, SessionDeleter>(); sd = static_cast<char_session_data *>(session[fd]->session_data.get()); - strzcpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail + sd->email = stringish<AccountEmail>("no mail"); // put here a mail without '@' to refuse deletion if we don't receive the e-mail sd->connect_until_time = TimeT(); // unknow or illimited (not displaying on map-server) } sd->account_id = RFIFOL(fd, 2); @@ -2354,8 +2279,7 @@ void parse_char(int fd) if (!sd || RFIFOREST(fd) < 37) return; { - char name[24]; - RFIFO_STRING(fd, 2, name, 24); + CharName name = stringish<CharName>(RFIFO_STRING<24>(fd, 2)); uint8_t stats[6]; for (int i = 0; i < 6; ++i) stats[i] = RFIFOB(fd, 26 + i); @@ -2401,7 +2325,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.to__actual(), 24); WFIFOB(fd, 2 + 98) = min(cd->attrs[ATTR::STR], 255); WFIFOB(fd, 2 + 99) = min(cd->attrs[ATTR::AGI], 255); @@ -2419,9 +2343,10 @@ void parse_char(int fd) case 0x68: // delete char //Yor's Fix if (!sd || RFIFOREST(fd) < 46) return; - RFIFO_STRING(fd, 6, email, 40); - if (e_mail_check(email) == 0) - strzcpy(email, "a@a.com", 40); // default e-mail + { + AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 6)); + if (!e_mail_check(email)) + email = DEFAULT_EMAIL; { { @@ -2457,6 +2382,7 @@ void parse_char(int fd) WFIFOSET(fd, 3); } } + } x68_out: RFIFOSKIP(fd, 46); break; @@ -2472,12 +2398,10 @@ void parse_char(int fd) if (server_fd[i] < 0) break; } - 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)) + AccountName userid_ = stringish<AccountName>(RFIFO_STRING<24>(fd, 2)); + AccountPass passwd_ = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26)); + if (i == MAX_MAP_SERVERS || userid_ != userid + || passwd_ != passwd) { WFIFOB(fd, 2) = 3; WFIFOSET(fd, 3); @@ -2495,8 +2419,8 @@ void parse_char(int fd) 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 (MapName& mapi : server[i].maps) + mapi = MapName(); WFIFOSET(fd, 3); RFIFOSKIP(fd, 60); realloc_fifo(fd, FIFOSIZE_SERVERLINK, @@ -2653,12 +2577,12 @@ void check_connect_login_server(TimerData *, tick_t) // Reading Lan Support configuration by [Yor] //------------------------------------------- static -int lan_config_read(const char *lancfgName) +int lan_config_read(ZString lancfgName) { struct hostent *h = NULL; // set default configuration - strzcpy(lan_map_ip, "127.0.0.1", sizeof(lan_map_ip)); + lan_map_ip = stringish<IP_String>("127.0.0.1"); subneti[0] = 127; subneti[1] = 0; subneti[2] = 0; @@ -2666,7 +2590,7 @@ int lan_config_read(const char *lancfgName) for (int j = 0; j < 4; j++) subnetmaski[j] = 255; - std::ifstream in(lancfgName); + std::ifstream in(lancfgName.c_str()); if (!in.is_open()) { @@ -2676,10 +2600,11 @@ int lan_config_read(const char *lancfgName) PRINTF("---start reading of Lan Support configuration...\n"); - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; @@ -2689,7 +2614,7 @@ int lan_config_read(const char *lancfgName) h = gethostbyname(w2.c_str()); if (h != NULL) { - sprintf(lan_map_ip, "%d.%d.%d.%d", + SNPRINTF(lan_map_ip, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), @@ -2697,7 +2622,7 @@ int lan_config_read(const char *lancfgName) } else { - strzcpy(lan_map_ip, w2.c_str(), sizeof(lan_map_ip)); + lan_map_ip = stringish<IP_String>(w2); } PRINTF("LAN IP of map-server: %s.\n", lan_map_ip); } @@ -2742,14 +2667,15 @@ int lan_config_read(const char *lancfgName) } else { - PRINTF("WARNING: unknown lan config key: %s\n", w1); + FString w1z = w1; + PRINTF("WARNING: unknown lan config key: %s\n", w1z); } } // sub-network check of the map-server { unsigned char p[4]; - sscanf(lan_map_ip, "%hhu.%hhu.%hhu.%hhu", &p[0], &p[1], &p[2], &p[3]); + SSCANF(lan_map_ip, "%hhu.%hhu.%hhu.%hhu", &p[0], &p[1], &p[2], &p[3]); PRINTF("LAN test of LAN IP of the map-server: "); if (lan_ip_check(p) == 0) { @@ -2763,11 +2689,11 @@ int lan_config_read(const char *lancfgName) } static -int char_config_read(const char *cfgName) +int char_config_read(ZString cfgName) { struct hostent *h = NULL; - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { @@ -2775,45 +2701,43 @@ int char_config_read(const char *cfgName) exit(1); } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; if (w1 == "userid") - strzcpy(userid, w2.c_str(), 24); + userid = stringish<AccountName>(w2); else if (w1 == "passwd") - strzcpy(passwd, w2.c_str(), 24); + passwd = stringish<AccountPass>(w2); else if (w1 == "server_name") { - strzcpy(server_name, w2.c_str(), sizeof(server_name)); + server_name = stringish<ServerName>(w2); PRINTF("%s server has been intialized\n", w2); } else if (w1 == "wisp_server_name") { if (w2.size() >= 4) - strzcpy(wisp_server_name, w2.c_str(), sizeof(wisp_server_name)); + wisp_server_name = stringish<CharName>(w2); } else if (w1 == "login_ip") { h = gethostbyname(w2.c_str()); if (h != NULL) { - PRINTF("Login server IP address : %s -> %d.%d.%d.%d\n", w2, + SNPRINTF(login_ip_str, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3])); - sprintf(login_ip_str, "%d.%d.%d.%d", - static_cast<uint8_t>(h->h_addr[0]), - static_cast<uint8_t>(h->h_addr[1]), - static_cast<uint8_t>(h->h_addr[2]), - static_cast<uint8_t>(h->h_addr[3])); + PRINTF("Login server IP address : %s -> %s\n", + w2, login_ip_str); } else - strzcpy(login_ip_str, w2.c_str(), 16); + login_ip_str = stringish<IP_String>(w2); } else if (w1 == "login_port") { @@ -2824,20 +2748,16 @@ int char_config_read(const char *cfgName) h = gethostbyname(w2.c_str()); if (h != NULL) { - PRINTF("Character server IP address : %s -> %d.%d.%d.%d\n", - w2, + SNPRINTF(char_ip_str, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3])); - sprintf(char_ip_str, "%d.%d.%d.%d", - static_cast<uint8_t>(h->h_addr[0]), - static_cast<uint8_t>(h->h_addr[1]), - static_cast<uint8_t>(h->h_addr[2]), - static_cast<uint8_t>(h->h_addr[3])); + PRINTF("Character server IP address : %s -> %s\n", + w2, char_ip_str); } else - strzcpy(char_ip_str, w2.c_str(), 16); + char_ip_str = stringish<IP_String>(w2); } else if (w1 == "char_port") { @@ -2853,7 +2773,7 @@ int char_config_read(const char *cfgName) } else if (w1 == "char_txt") { - strzcpy(char_txt, w2.c_str(), sizeof(char_txt)); + char_txt = w2; } else if (w1 == "max_connect_user") { @@ -2863,7 +2783,7 @@ int char_config_read(const char *cfgName) } else if (w1 == "check_ip_flag") { - check_ip_flag = config_switch(w2.c_str()); + check_ip_flag = config_switch(w2); } else if (w1 == "autosave_time") { @@ -2873,16 +2793,7 @@ int char_config_read(const char *cfgName) } else if (w1 == "start_point") { - char map[32]; - int x, y; - if (SSCANF(w2, "%[^,],%d,%d", map, &x, &y) < 3) - continue; - if (strstr(map, ".gat") != NULL) - { // Verify at least if '.gat' is in the map name - strzcpy(start_point.map_, map, 16); - start_point.x = x; - start_point.y = y; - } + extract(w2, &start_point); } else if (w1 == "start_zeny") { @@ -2904,15 +2815,11 @@ int char_config_read(const char *cfgName) } else if (w1 == "unknown_char_name") { - strzcpy(unknown_char_name, w2.c_str(), 24); + unknown_char_name = stringish<CharName>(w2); } else if (w1 == "char_log_filename") { - strzcpy(char_log_filename, w2.c_str(), sizeof(char_log_filename)); - } - else if (w1 == "name_ignoring_case") - { - name_ignoring_case = config_switch(w2.c_str()); + char_log_filename = w2; } else if (w1 == "char_name_option") { @@ -2920,15 +2827,16 @@ int char_config_read(const char *cfgName) } else if (w1 == "char_name_letters") { - strzcpy(char_name_letters, w2.c_str(), sizeof(char_name_letters)); + for (uint8_t c : w2) + char_name_letters[c] = true; } else if (w1 == "online_txt_filename") { - strzcpy(online_txt_filename, w2.c_str(), sizeof(online_txt_filename)); + online_txt_filename = w2; } else if (w1 == "online_html_filename") { - strzcpy(online_html_filename, w2.c_str(), sizeof(online_html_filename)); + online_html_filename = w2; } else if (w1 == "online_sorting_option") { @@ -2948,7 +2856,7 @@ int char_config_read(const char *cfgName) } else if (w1 == "anti_freeze_enable") { - anti_freeze_enable = config_switch(w2.c_str()); + anti_freeze_enable = config_switch(w2); } else if (w1 == "anti_freeze_interval") { @@ -2958,11 +2866,12 @@ int char_config_read(const char *cfgName) } else if (w1 == "import") { - char_config_read(w2.c_str()); + char_config_read(w2); } else { - PRINTF("WARNING: unknown char config key: %s\n", w1); + FString w1z = w1; + PRINTF("WARNING: unknown char config key: %s\n", w1z); } } @@ -2988,7 +2897,7 @@ void term_func(void) CHAR_LOG("----End of char-server (normal end with closing of all files).\n"); } -int do_init(int argc, char **argv) +int do_init(int argc, ZString *argv) { int i; @@ -2996,11 +2905,17 @@ int do_init(int argc, char **argv) CHAR_LOG(""); CHAR_LOG("The char-server starting...\n"); - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - lan_config_read((argc > 1) ? argv[1] : LOGIN_LAN_CONF_NAME); + if (argc > 1) + char_config_read(argv[1]); + else + char_config_read(CHAR_CONF_NAME); + if (argc > 1) + lan_config_read(argv[2]); + else + lan_config_read(LOGIN_LAN_CONF_NAME); - login_ip = inet_addr(login_ip_str); - char_ip = inet_addr(char_ip_str); + login_ip = inet_addr(login_ip_str.c_str()); + char_ip = inet_addr(char_ip_str.c_str()); for (i = 0; i < MAX_MAP_SERVERS; i++) { @@ -3013,7 +2928,10 @@ int do_init(int argc, char **argv) update_online = TimeT::now(); create_online_files(); // update online players files at start of the server - inter_init((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 + if (argc > 3) + inter_init(argv[3]); + else + inter_init(inter_cfgName); // set_termfunc (do_final); set_defaultparse(parse_char); diff --git a/src/char/char.hpp b/src/char/char.hpp index 5e16a6a..8e37c64 100644 --- a/src/char/char.hpp +++ b/src/char/char.hpp @@ -15,18 +15,18 @@ struct mmo_map_server long ip; short port; int users; - char maps[MAX_MAP_PER_SERVER][16]; + MapName maps[MAX_MAP_PER_SERVER]; }; -const mmo_charstatus *search_character(const char *character_name); +const mmo_charstatus *search_character(CharName character_name); int mapif_sendall(const uint8_t *buf, unsigned int len); int mapif_sendallwos(int fd, const uint8_t *buf, unsigned int len); int mapif_send(int fd, const uint8_t *buf, unsigned int len); -void char_log(const_string line); +void char_log(XString line); #define CHAR_LOG(fmt, ...) \ - char_log(static_cast<const std::string&>(STRPRINTF(fmt, ## __VA_ARGS__))) + char_log(STRPRINTF(fmt, ## __VA_ARGS__)) #endif // CHAR_HPP diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp index 38edb9b..d2c64e1 100644 --- a/src/char/int_party.cpp +++ b/src/char/int_party.cpp @@ -3,8 +3,12 @@ #include <cstdlib> #include <cstring> +#include <fstream> + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" +#include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/mmo.hpp" #include "../common/socket.hpp" @@ -14,7 +18,7 @@ #include "../poison.hpp" -char party_txt[1024] = "save/party.txt"; +FString party_txt = "save/party.txt"; static Map<int, struct party> party_db; @@ -30,82 +34,84 @@ void mapif_parse_PartyLeave(int fd, int party_id, int account_id); // パーティデータの文字列への変換 static -std::string inter_party_tostr(struct party *p) +FString inter_party_tostr(struct party *p) { - std::string str = STRPRINTF( - "%d\t" - "%s\t" - "%d,%d\t", - p->party_id, - p->name, - p->exp, p->item); + MString str; + str += STRPRINTF( + "%d\t" + "%s\t" + "%d,%d\t", + p->party_id, + p->name, + p->exp, p->item); for (int i = 0; i < MAX_PARTY; i++) { struct party_member *m = &p->member[i]; + if (!m->account_id) + continue; str += STRPRINTF( "%d,%d\t" "%s\t", m->account_id, m->leader, - (m->account_id > 0) ? m->name : "NoMember"); + m->name); } - return str; + return FString(str); } -// パーティデータの文字列からの変換 static -int inter_party_fromstr(char *str, struct party *p) +bool extract(XString str, party *p) { *p = party(); - if (sscanf(str, - "%d\t" - "%[^\t]\t" - "%d,%d\t", - &p->party_id, - p->name, - &p->exp, &p->item) != 4) - return 1; - - for (int j = 0; j < 3 && str != NULL; j++) - str = strchr(str + 1, '\t'); - - for (int i = 0; i < MAX_PARTY; i++) + // not compatible with the normal extract()ors since it has + // a variable-size element that uses the same separator + std::vector<XString> bits; + if (!extract(str, vrec<'\t'>(&bits))) + return false; + auto begin = bits.begin(); + auto end = bits.end(); + if (begin == end || !extract(*begin, &p->party_id)) + return false; + ++begin; + if (begin == end || !extract(*begin, &p->name)) + return false; + ++begin; + if (begin == end || !extract(*begin, record<','>(&p->exp, &p->item))) + return false; + ++begin; + + for (int i = 0; begin != end && i < MAX_PARTY; ++i) { struct party_member *m = &p->member[i]; - if (str == NULL) - return 1; - - if (sscanf(str + 1, - "%d,%d\t" - "%[^\t]\t", - &m->account_id, &m->leader, - m->name) != 3) - return 1; - - for (int j = 0; j < 2 && str != NULL; j++) - str = strchr(str + 1, '\t'); + + if (begin == end || !extract(*begin, record<','>(&m->account_id, &m->leader))) + return false; + ++begin; + if (begin == end || !extract(*begin, &m->name)) + return false; + ++begin; + if (!m->account_id) + --i; } - return 0; + return true; } // パーティデータのロード int inter_party_init(void) { - char line[8192]; - FILE *fp; - int c = 0; - int i, j; - - if ((fp = fopen_(party_txt, "r")) == NULL) + std::ifstream in(party_txt.c_str()); + if (!in.is_open()) return 1; // TODO: convert to use char_id, and change to extract() - while (fgets(line, sizeof(line) - 1, fp)) + FString line; + int c = 0; + while (io::getline(in, line)) { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 + int i, j = 0; + if (SSCANF(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { party_newid = i; @@ -113,7 +119,7 @@ int inter_party_init(void) } struct party p {}; - if (inter_party_fromstr(line, &p) == 0 && p.party_id > 0) + if (extract(line, &p) && p.party_id > 0) { if (p.party_id >= party_newid) party_newid = p.party_id + 1; @@ -127,7 +133,6 @@ int inter_party_init(void) } c++; } - fclose_(fp); // PRINTF("int_party: %s read done (%d parties)\n", party_txt, c); return 0; @@ -137,7 +142,7 @@ int inter_party_init(void) static void inter_party_save_sub(struct party *data, FILE *fp) { - std::string line = inter_party_tostr(data); + FString line = inter_party_tostr(data); FPRINTF(fp, "%s\n", line); } @@ -164,15 +169,15 @@ int inter_party_save(void) // パーティ名検索用 static -void search_partyname_sub(struct party *p, const char *str, struct party **dst) +void search_partyname_sub(struct party *p, PartyName str, struct party **dst) { - if (strcasecmp(p->name, str) == 0) + if (p->name == str) *dst = p; } // パーティ名検索 static -struct party *search_partyname(const char *str) +struct party *search_partyname(PartyName str) { struct party *p = NULL; for (auto& pair : party_db) @@ -227,7 +232,7 @@ int party_check_empty(struct party *p) // キャラの競合がないかチェック用 static void party_check_conflict_sub(struct party *p, - int party_id, int account_id, const char *nick) + int party_id, int account_id, CharName nick) { int i; @@ -237,7 +242,7 @@ void party_check_conflict_sub(struct party *p, for (i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id == account_id - && strcmp(p->member[i].name, nick) == 0) + && p->member[i].name == nick) { // 別のパーティに偽の所属データがあるので脱退 PRINTF("int_party: party conflict! %d %d %d\n", account_id, @@ -249,7 +254,7 @@ void party_check_conflict_sub(struct party *p, // キャラの競合がないかチェック static -void party_check_conflict(int party_id, int account_id, const char *nick) +void party_check_conflict(int party_id, int account_id, CharName nick) { for (auto& pair : party_db) party_check_conflict_sub(&pair.second, @@ -342,14 +347,14 @@ void mapif_party_optionchanged(int fd, struct party *p, int account_id, // パーティ脱退通知 static -void mapif_party_leaved(int party_id, int account_id, char *name) +void mapif_party_leaved(int party_id, int account_id, CharName name) { unsigned char buf[34]; WBUFW(buf, 0) = 0x3824; WBUFL(buf, 2) = party_id; WBUFL(buf, 6) = account_id; - WBUF_STRING(buf, 10, name, 24); + WBUF_STRING(buf, 10, name.to__actual(), 24); mapif_sendall(buf, 34); PRINTF("int_party: party leaved %d %d %s\n", party_id, account_id, name); } @@ -382,9 +387,9 @@ void mapif_party_broken(int party_id, int flag) // パーティ内発言 static -void mapif_party_message(int party_id, int account_id, const char *mes) +void mapif_party_message(int party_id, int account_id, XString mes) { - size_t len = strlen(mes); + size_t len = mes.size() + 1; unsigned char buf[len + 12]; WBUFW(buf, 0) = 0x3827; @@ -400,14 +405,11 @@ void mapif_party_message(int party_id, int account_id, const char *mes) // パーティ static -void mapif_parse_CreateParty(int fd, int account_id, const char *name, const char *nick, - const char *map, int lv) +void mapif_parse_CreateParty(int fd, int account_id, PartyName name, CharName nick, + MapName map, int lv) { - int i; - - for (i = 0; i < 24 && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) + if (!name.is_print()) { PRINTF("int_party: illegal party name [%s]\n", name); mapif_party_created(fd, account_id, NULL); @@ -423,12 +425,12 @@ void mapif_parse_CreateParty(int fd, int account_id, const char *name, const cha } struct party p {}; p.party_id = party_newid++; - strzcpy(p.name, name, 24); + p.name = name; p.exp = 0; p.item = 0; p.member[0].account_id = account_id; - strzcpy(p.member[0].name, nick, 24); - strzcpy(p.member[0].map, map, 16); + p.member[0].name = nick; + p.member[0].map = map; p.member[0].leader = 1; p.member[0].online = 1; p.member[0].lv = lv; @@ -453,7 +455,7 @@ void mapif_parse_PartyInfo(int fd, int party_id) // パーティ追加要求 static void mapif_parse_PartyAddMember(int fd, int party_id, int account_id, - const char *nick, const char *map, int lv) + CharName nick, MapName map, int lv) { struct party *p = party_db.search(party_id); if (p == NULL) @@ -469,8 +471,8 @@ void mapif_parse_PartyAddMember(int fd, int party_id, int account_id, int flag = 0; p->member[i].account_id = account_id; - strzcpy(p->member[i].name, nick, 24); - strzcpy(p->member[i].map, map, 16); + p->member[i].name = nick; + p->member[i].map = map; p->member[i].leader = 0; p->member[i].online = 1; p->member[i].lv = lv; @@ -493,7 +495,7 @@ void mapif_parse_PartyAddMember(int fd, int party_id, int account_id, // パーティー設定変更要求 static void mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, - int exp, int item) + int exp, int item) { struct party *p = party_db.search(party_id); if (p == NULL) @@ -534,7 +536,7 @@ void mapif_parse_PartyLeave(int, int party_id, int account_id) // パーティマップ更新要求 static void mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, - const char *map, int online, int lv) + MapName map, int online, int lv) { struct party *p = party_db.search(party_id); if (p == NULL) @@ -546,7 +548,7 @@ void mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, continue; int flag = 0; - strzcpy(p->member[i].map, map, 16); + p->member[i].map = map; p->member[i].online = online; p->member[i].lv = lv; mapif_party_membermoved(p, i); @@ -576,14 +578,14 @@ void mapif_parse_BreakParty(int fd, int party_id) // パーティメッセージ送信 static -void mapif_parse_PartyMessage(int, int party_id, int account_id, const char *mes) +void mapif_parse_PartyMessage(int, int party_id, int account_id, XString mes) { mapif_party_message(party_id, account_id, mes); } // パーティチェック要求 static -void mapif_parse_PartyCheck(int, int party_id, int account_id, const char *nick) +void mapif_parse_PartyCheck(int, int party_id, int account_id, CharName nick) { party_check_conflict(party_id, account_id, nick); } @@ -600,12 +602,9 @@ int inter_party_parse_frommap(int fd) 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); + PartyName name = stringish<PartyName>(RFIFO_STRING<24>(fd, 6)); + CharName nick = stringish<CharName>(RFIFO_STRING<24>(fd, 30)); + MapName map = RFIFO_STRING<16>(fd, 54); uint16_t lv = RFIFOW(fd, 70); mapif_parse_CreateParty(fd, account, @@ -625,10 +624,8 @@ int inter_party_parse_frommap(int fd) { 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); + CharName nick = stringish<CharName>(RFIFO_STRING<24>(fd, 10)); + MapName map = RFIFO_STRING<16>(fd, 34); uint16_t lv = RFIFOW(fd, 50); mapif_parse_PartyAddMember(fd, party_id, @@ -664,8 +661,7 @@ int inter_party_parse_frommap(int fd) { int party_id = RFIFOL(fd, 2); int account_id = RFIFOL(fd, 6); - char map[16]; - RFIFO_STRING(fd, 10, map, 16); + MapName map = RFIFO_STRING<16>(fd, 10); uint8_t online = RFIFOB(fd, 26); uint16_t lv = RFIFOW(fd, 27); mapif_parse_PartyChangeMap(fd, @@ -687,8 +683,7 @@ int inter_party_parse_frommap(int fd) 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); + FString mes = RFIFO_STRING(fd, 12, len); mapif_parse_PartyMessage(fd, party_id, account_id, @@ -699,8 +694,7 @@ int inter_party_parse_frommap(int fd) { int party_id = RFIFOL(fd, 2); int account_id = RFIFOL(fd, 6); - char nick[24]; - RFIFO_STRING(fd, 10, nick, 24); + CharName nick = stringish<CharName>(RFIFO_STRING<24>(fd, 10)); mapif_parse_PartyCheck(fd, party_id, account_id, diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp index 8a59b49..d003250 100644 --- a/src/char/int_party.hpp +++ b/src/char/int_party.hpp @@ -1,6 +1,8 @@ #ifndef INT_PARTY_HPP #define INT_PARTY_HPP +#include "../common/strings.hpp" + int inter_party_init(void); int inter_party_save(void); @@ -8,6 +10,6 @@ int inter_party_parse_frommap(int fd); void inter_party_leave(int party_id, int account_id); -extern char party_txt[1024]; +extern FString party_txt; #endif // INT_PARTY_HPP diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp index 09ce9d4..aa605bf 100644 --- a/src/char/int_storage.cpp +++ b/src/char/int_storage.cpp @@ -9,6 +9,7 @@ #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/mmo.hpp" #include "../common/socket.hpp" @@ -17,16 +18,17 @@ // ファイル名のデフォルト // inter_config_read()で再設定される -char storage_txt[1024] = "save/storage.txt"; +FString storage_txt = "save/storage.txt"; static Map<int, struct storage> storage_db; // 倉庫データを文字列に変換 static -std::string storage_tostr(struct storage *p) +FString storage_tostr(struct storage *p) { - std::string str = STRPRINTF( + MString str; + str += STRPRINTF( "%d,%d\t", p->account_id, p->storage_amount); @@ -53,13 +55,13 @@ std::string storage_tostr(struct storage *p) str += '\t'; if (!f) - str.clear(); - return str; + return FString(); + return FString(str); } // 文字列を倉庫データに変換 static -bool extract(const_string str, struct storage *p) +bool extract(XString str, struct storage *p) { std::vector<struct item> storage_items; if (!extract(str, @@ -73,7 +75,7 @@ bool extract(const_string str, struct storage *p) if (p->account_id <= 0) return false; - if (storage_items.size() >= MAX_STORAGE) + if (storage_items.size() > MAX_STORAGE) return false; std::copy(storage_items.begin(), storage_items.end(), p->storage_); @@ -98,15 +100,15 @@ int inter_storage_init(void) { int c = 0; - std::ifstream in(storage_txt); + std::ifstream in(storage_txt.c_str()); if (!in.is_open()) { PRINTF("cant't read : %s\n", storage_txt); return 1; } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { struct storage s {}; if (extract(line, &s)) @@ -127,8 +129,8 @@ int inter_storage_init(void) static void inter_storage_save_sub(struct storage *data, FILE *fp) { - std::string line = storage_tostr(data); - if (!line.empty()) + FString line = storage_tostr(data); + if (line) FPRINTF(fp, "%s\n", line); } diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp index 691f16d..a03d70f 100644 --- a/src/char/int_storage.hpp +++ b/src/char/int_storage.hpp @@ -1,6 +1,8 @@ #ifndef INT_STORAGE_HPP #define INT_STORAGE_HPP +#include "../common/strings.hpp" + int inter_storage_init(void); int inter_storage_save(void); void inter_storage_delete(int account_id); @@ -8,6 +10,6 @@ struct storage *account2storage(int account_id); int inter_storage_parse_frommap(int fd); -extern char storage_txt[1024]; +extern FString storage_txt; #endif // INT_STORAGE_HPP diff --git a/src/char/inter.cpp b/src/char/inter.cpp index 68d81e8..3cb51e7 100644 --- a/src/char/inter.cpp +++ b/src/char/inter.cpp @@ -10,6 +10,7 @@ #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -25,10 +26,10 @@ // that is the waiting time of answers of all map-servers constexpr std::chrono::minutes WISDATA_TTL = std::chrono::minutes(1); -char inter_log_filename[1024] = "log/inter.log"; +FString inter_log_filename = "log/inter.log"; static -char accreg_txt[1024] = "save/accreg.txt"; +FString accreg_txt = "save/accreg.txt"; struct accreg { @@ -59,8 +60,8 @@ struct WisData { int id, fd, count; tick_t tick; - char src[24], dst[24]; - std::string msg; + CharName src, dst; + FString msg; }; static Map<int, struct WisData> wis_db; @@ -71,17 +72,18 @@ std::vector<int> wis_dellistv; // アカウント変数を文字列へ変換 static -std::string inter_accreg_tostr(struct accreg *reg) +FString inter_accreg_tostr(struct accreg *reg) { - std::string str STRPRINTF("%d\t", reg->account_id); + MString str; + str += STRPRINTF("%d\t", reg->account_id); for (int j = 0; j < reg->reg_num; j++) str += STRPRINTF("%s,%d ", reg->reg[j].str, reg->reg[j].value); - return str; + return FString(str); } // アカウント変数を文字列から変換 static -bool extract(const_string str, struct accreg *reg) +bool extract(XString str, struct accreg *reg) { std::vector<struct global_reg> vars; if (!extract(str, @@ -105,11 +107,11 @@ int inter_accreg_init(void) { int c = 0; - std::ifstream in(accreg_txt); + std::ifstream in(accreg_txt.c_str()); if (!in.is_open()) return 1; - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { struct accreg reg {}; if (extract(line, ®)) @@ -133,7 +135,7 @@ void inter_accreg_save_sub(struct accreg *reg, FILE *fp) { if (reg->reg_num > 0) { - std::string line = inter_accreg_tostr(reg); + FString line = inter_accreg_tostr(reg); fwrite(line.data(), 1, line.size(), fp); fputc('\n', fp); } @@ -166,33 +168,34 @@ int inter_accreg_save(void) *------------------------------------------ */ static -int inter_config_read(const char *cfgName) +int inter_config_read(ZString cfgName) { - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { PRINTF("file not found: %s\n", cfgName); return 1; } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; if (w1 == "storage_txt") { - strzcpy(storage_txt, w2.c_str(), sizeof(storage_txt)); + storage_txt = w2; } else if (w1 == "party_txt") { - strzcpy(party_txt, w2.c_str(), sizeof(party_txt)); + party_txt = w2; } else if (w1 == "accreg_txt") { - strzcpy(accreg_txt, w2.c_str(), sizeof(accreg_txt)); + accreg_txt = w2; } else if (w1 == "party_share_level") { @@ -202,15 +205,16 @@ int inter_config_read(const char *cfgName) } else if (w1 == "inter_log_filename") { - strzcpy(inter_log_filename, w2.c_str(), sizeof(inter_log_filename)); + inter_log_filename = w2; } else if (w1 == "import") { - inter_config_read(w2.c_str()); + inter_config_read(w2); } else { - PRINTF("WARNING: unknown inter config key: %s\n", w1); + FString w1z = w1; + PRINTF("WARNING: unknown inter config key: %s\n", w1z); } } @@ -218,25 +222,21 @@ int inter_config_read(const char *cfgName) } // セーブ -int inter_save(void) +void inter_save(void) { inter_party_save(); inter_storage_save(); inter_accreg_save(); - - return 0; } // 初期化 -int inter_init(const char *file) +void inter_init(ZString file) { inter_config_read(file); inter_party_init(); inter_storage_init(); inter_accreg_init(); - - return 0; } //-------------------------------------------------------- @@ -244,9 +244,9 @@ int inter_init(const char *file) // GMメッセージ送信 static -void mapif_GMmessage(const char *mes) +void mapif_GMmessage(XString mes) { - size_t str_len = strlen(mes) + 1; + size_t str_len = mes.size() + 1; size_t msg_len = str_len + 4; uint8_t buf[msg_len]; @@ -266,9 +266,9 @@ void mapif_wis_message(struct WisData *wd) WBUFW(buf, 0) = 0x3801; WBUFW(buf, 2) = 56 + str_size; WBUFL(buf, 4) = wd->id; - WBUF_STRING(buf, 8, wd->src, 24); - WBUF_STRING(buf, 32, wd->dst, 24); - WBUF_STRING(buf, 56, wd->msg.c_str(), str_size); + WBUF_STRING(buf, 8, wd->src.to__actual(), 24); + WBUF_STRING(buf, 32, wd->dst.to__actual(), 24); + WBUF_STRING(buf, 56, wd->msg, str_size); wd->count = mapif_sendall(buf, WBUFW(buf, 2)); } @@ -279,7 +279,7 @@ void mapif_wis_end(struct WisData *wd, int flag) uint8_t buf[27]; WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, wd->src, 24); + WBUF_STRING(buf, 2, wd->src.to__actual(), 24); WBUFB(buf, 26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(wd->fd, buf, 27); } @@ -362,8 +362,7 @@ void mapif_parse_GMmessage(int fd) { size_t msg_len = RFIFOW(fd, 2); size_t str_len = msg_len - 4; - char buf[str_len]; - RFIFO_STRING(fd, 4, buf, str_len); + FString buf = RFIFO_STRING(fd, 4, str_len); mapif_GMmessage(buf); } @@ -380,10 +379,8 @@ void mapif_parse_WisRequest(int fd) return; } - char from[24]; - char to[24]; - RFIFO_STRING(fd, 4, from, 24); - RFIFO_STRING(fd, 28, to, 24); + CharName from = stringish<CharName>(RFIFO_STRING<24>(fd, 4)); + CharName to = stringish<CharName>(RFIFO_STRING<24>(fd, 28)); // search if character exists before to ask all map-servers const mmo_charstatus *mcs = search_character(to); @@ -391,7 +388,7 @@ void mapif_parse_WisRequest(int fd) { uint8_t buf[27]; WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, from, 24); + WBUF_STRING(buf, 2, from.to__actual(), 24); WBUFB(buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); // Character exists. So, ask all map-servers @@ -399,19 +396,19 @@ void mapif_parse_WisRequest(int fd) else { // to be sure of the correct name, rewrite it - strzcpy(to, mcs->name, 24); + to = mcs->name; // if source is destination, don't ask other servers. - if (strcmp(from, to) == 0) + if (from == to) { uint8_t buf[27]; WBUFW(buf, 0) = 0x3802; - WBUF_STRING(buf, 2, from, 24); + WBUF_STRING(buf, 2, from.to__actual(), 24); WBUFB(buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); } else { - struct WisData wd; + struct WisData wd {}; // Whether the failure of previous wisp/page transmission (timeout) check_ttl_wisdata(); @@ -419,11 +416,9 @@ void mapif_parse_WisRequest(int fd) wd.id = ++wisid; wd.fd = 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); - wd.msg = std::string(tmpbuf); + wd.src = from; + wd.dst = to; + wd.msg = RFIFO_STRING(fd, 52, len); wd.tick = gettick(); wis_db.insert(wd.id, wd); mapif_wis_message(&wd); @@ -480,7 +475,7 @@ void mapif_parse_AccReg(int fd) for (j = 0, p = 8; j < ACCOUNT_REG_NUM && p < RFIFOW(fd, 2); j++, p += 36) { - RFIFO_STRING(fd, p, reg->reg[j].str, 32); + reg->reg[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p)); reg->reg[j].value = RFIFOL(fd, p + 32); } reg->reg_num = j; diff --git a/src/char/inter.hpp b/src/char/inter.hpp index 0adbf03..ce8447d 100644 --- a/src/char/inter.hpp +++ b/src/char/inter.hpp @@ -1,8 +1,10 @@ #ifndef INTER_HPP #define INTER_HPP -int inter_init(const char *file); -int inter_save(void); +#include "../common/strings.hpp" + +void inter_init(ZString file); +void inter_save(void); int inter_parse_frommap(int fd); int inter_check_length(int fd, int length); @@ -10,6 +12,6 @@ int inter_check_length(int fd, int length); #define inter_cfgName "conf/inter_athena.conf" extern int party_share_level; -extern char inter_log_filename[1024]; +extern FString inter_log_filename; #endif // INTER_HPP diff --git a/src/common/const_array.hpp b/src/common/const_array.hpp index a3a6d58..314eccf 100644 --- a/src/common/const_array.hpp +++ b/src/common/const_array.hpp @@ -25,11 +25,11 @@ #include <iterator> #include <ostream> -#include <string> #include <vector> #ifdef WORKAROUND_GCC46_COMPILER // constexpr is buggy with templates in this version +// Is this still needed now that const_string is removed? # define constexpr /* nothing */ #endif @@ -125,57 +125,8 @@ public: } }; -// subclass just provides a simpler name and some conversions -// Important note: it must be safe to dereference end, though -// the value is unspecified. -class const_string : public const_array<char> -{ -public: - // Implicit conversion from C string. - constexpr - const_string(const char *z) - : const_array<char>(z, z ? strlen(z) : 0) - {} - - // Same as parent constructor. - constexpr - const_string(const char *s, size_t l) - : const_array<char>(s, l) - {} - - // Same as parent constructor. - constexpr - const_string(const char *b, const char *e) - : const_array<char>(b, e) - {} - - // Same as parent constructor. - const_string(const std::vector<char> s) - : const_array<char>(s) - {} - - // Implicit conversion from C++ string. - const_string(const std::string& s) - : const_array<char>(s.data(), s.size()) - {} - - // but disallow converion from a temporary. - const_string(std::string&&) = delete; - - // allow being sloppy - constexpr - const_string(const_array<char> a) - : const_array<char>(a) - {} -}; #ifdef WORKAROUND_GCC46_COMPILER # undef constexpr #endif -inline -std::ostream& operator << (std::ostream& o, const_string s) -{ - return o.write(s.data(), s.size()); -} - #endif // CONST_ARRAY_HPP diff --git a/src/common/core.cpp b/src/common/core.cpp index 153414d..76aa09c 100644 --- a/src/common/core.cpp +++ b/src/common/core.cpp @@ -76,7 +76,11 @@ int main(int argc, char **argv) { do_socket(); - do_init(argc, argv); + // ZString args[argc]; is (deliberately!) not supported by clang yet + ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString))); + for (int i = 0; i < argc; ++i) + args[i] = ZString(ZString::really_construct_from_a_pointer, argv[i], nullptr); + do_init(argc, args); // set up exit handlers *after* the initialization has happened. // This is because term_func is likely to depend on successful init. diff --git a/src/common/core.hpp b/src/common/core.hpp index 0c11efb..f1473ed 100644 --- a/src/common/core.hpp +++ b/src/common/core.hpp @@ -3,6 +3,8 @@ #include "sanity.hpp" +#include "strings.hpp" + /// core.c contains a server-independent main() function /// and then runs a do_sendrecv loop @@ -12,7 +14,7 @@ extern bool runflag; /// This is an external function defined by each server /// This function must register stuff for the parse loop -extern int do_init(int, char **); +extern int do_init(int, ZString *); /// Cleanup function called whenever a signal kills us /// or when if we manage to exit() gracefully. diff --git a/src/common/cxxstdio.cpp b/src/common/cxxstdio.cpp deleted file mode 100644 index 8f4001f..0000000 --- a/src/common/cxxstdio.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "cxxstdio.hpp" -// cxxstdio.cpp - pass C++ types through scanf/printf -// -// 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 <cstdlib> - -namespace cxxstdio -{ -StringConverter::~StringConverter() -{ - if (mid) - { - out = mid; - free(mid); - } -} -} // namespace cxxstdio diff --git a/src/common/cxxstdio.hpp b/src/common/cxxstdio.hpp index 96c3ca2..89cc5de 100644 --- a/src/common/cxxstdio.hpp +++ b/src/common/cxxstdio.hpp @@ -24,37 +24,19 @@ #include <cstdarg> #include <cstdio> -#include <string> - #include "const_array.hpp" #include "utils2.hpp" namespace cxxstdio { + // other implementations of do_vprint or do_vscan are injected by ADL. inline __attribute__((format(printf, 2, 0))) int do_vprint(FILE *out, const char *fmt, va_list ap) { return vfprintf(out, fmt, ap); } - inline __attribute__((format(printf, 2, 0))) - int do_vprint(std::string& out, const char *fmt, va_list ap) - { - int len; - { - va_list ap2; - va_copy(ap2, ap); - len = vsnprintf(nullptr, 0, fmt, ap2); - va_end(ap2); - } - char buffer[len + 1]; - vsnprintf(buffer, len + 1, fmt, ap); - - out = buffer; - return len; - } - inline __attribute__((format(scanf, 2, 0))) int do_vscan(FILE *in, const char *fmt, va_list ap) { @@ -72,13 +54,6 @@ namespace cxxstdio int do_vscan(const char *, const char *, va_list) = delete; #endif - inline __attribute__((format(scanf, 2, 0))) - int do_vscan(const std::string& in, const char *fmt, va_list ap) - { - return vsscanf(in.c_str(), fmt, ap); - } - - template<class T> inline __attribute__((format(printf, 2, 3))) int do_print(T&& t, const char *fmt, ...) throw() @@ -104,13 +79,19 @@ namespace cxxstdio } - template<class T> - typename remove_enum<T>::type convert_for_printf(T v) + template<class T, typename=typename std::enable_if<!std::is_class<T>::value>::type> + typename remove_enum<T>::type decay_for_printf(T v) { typedef typename remove_enum<T>::type repr_type; return repr_type(v); } + template<class T, typename=decltype(decay_for_printf(std::declval<T&&>()))> + T&& convert_for_printf(T&& v) + { + return std::forward<T>(v); + } + template<class T, typename = typename std::enable_if<!std::is_enum<T>::value>::type> T& convert_for_scanf(T& v) { @@ -152,7 +133,7 @@ namespace cxxstdio } template<class E> constexpr - E get_max_value(E) + E get_enum_max_value(E) { return E::max_value; } @@ -199,34 +180,6 @@ namespace cxxstdio return v; } - - inline - const char *convert_for_printf(const std::string& s) - { - return s.c_str(); - } - - class StringConverter - { - std::string& out; - char *mid; - public: - StringConverter(std::string& s) - : out(s), mid(nullptr) - {} - ~StringConverter(); - char **operator &() - { - return ∣ - } - }; - - inline - StringConverter convert_for_scanf(std::string& s) - { - return StringConverter(s); - } - template<class Format> class PrintFormatter { @@ -238,7 +191,7 @@ namespace cxxstdio constexpr static const char *print_format = Format::print_format(); return do_print(std::forward<T>(t), print_format, - convert_for_printf(std::forward<A>(a))...); + decay_for_printf(convert_for_printf(std::forward<A>(a)))...); } }; @@ -257,7 +210,7 @@ namespace cxxstdio } }; -#define FPRINTF(file, fmt, ...) \ +#define XPRINTF(out, fmt, ...) \ ([&]() -> int \ { \ struct format_impl \ @@ -265,10 +218,10 @@ namespace cxxstdio constexpr static \ const char *print_format() { return fmt; } \ }; \ - return cxxstdio::PrintFormatter<format_impl>::print(file, ## __VA_ARGS__); \ + return cxxstdio::PrintFormatter<format_impl>::print(out, ## __VA_ARGS__); \ }()) -#define FSCANF(file, fmt, ...) \ +#define XSCANF(out, fmt, ...) \ ([&]() -> int \ { \ struct format_impl \ @@ -276,22 +229,33 @@ namespace cxxstdio constexpr static \ const char *scan_format() { return fmt; } \ }; \ - return cxxstdio::ScanFormatter<format_impl>::scan(file, ## __VA_ARGS__); \ + return cxxstdio::ScanFormatter<format_impl>::scan(out, ## __VA_ARGS__); \ }()) +#define FPRINTF(file, fmt, ...) XPRINTF(no_cast<FILE *>(file), fmt, ## __VA_ARGS__) +#define FSCANF(file, fmt, ...) XSCANF(no_cast<FILE *>(file), fmt, ## __VA_ARGS__) #define PRINTF(fmt, ...) FPRINTF(stdout, fmt, ## __VA_ARGS__) -#define SPRINTF(str, fmt, ...) FPRINTF(str, fmt, ## __VA_ARGS__) +#define SPRINTF(str, fmt, ...) XPRINTF(base_cast<FString&>(str), fmt, ## __VA_ARGS__) +#define SNPRINTF(str, n, fmt, ...) XPRINTF(base_cast<VString<n-1>&>(str), fmt, ## __VA_ARGS__) #define SCANF(fmt, ...) FSCANF(stdin, fmt, ## __VA_ARGS__) -#define SSCANF(str, fmt, ...) FSCANF(str, fmt, ## __VA_ARGS__) +#define SSCANF(str, fmt, ...) XSCANF(/*ZString or compatible*/str, fmt, ## __VA_ARGS__) #define STRPRINTF(fmt, ...) \ - ([&]() -> std::string \ + ([&]() -> FString \ { \ - std::string _out_impl; \ + FString _out_impl; \ SPRINTF(_out_impl, fmt, ## __VA_ARGS__);\ return _out_impl; \ }()) +#define STRNPRINTF(n, fmt, ...) \ + ([&]() -> VString<n - 1> \ + { \ + VString<n - 1> _out_impl; \ + SNPRINTF(_out_impl, n, fmt, ## __VA_ARGS__);\ + return _out_impl; \ + }()) + } // namespace cxxstdio #endif // CXXSTDIO_HPP diff --git a/src/common/cxxstdio_test.cpp b/src/common/cxxstdio_test.cpp new file mode 100644 index 0000000..9b6eeb2 --- /dev/null +++ b/src/common/cxxstdio_test.cpp @@ -0,0 +1,3 @@ +#include "cxxstdio.hpp" + +#include <gtest/gtest.h> diff --git a/src/common/dumb_ptr.hpp b/src/common/dumb_ptr.hpp index 8863ef2..fe5031a 100644 --- a/src/common/dumb_ptr.hpp +++ b/src/common/dumb_ptr.hpp @@ -202,25 +202,25 @@ struct dumb_string { return dumb_string::copy(sz, sz + strlen(sz)); } - static dumb_string copys(const std::string& s) + static dumb_string copys(XString s) { return dumb_string::copy(&*s.begin(), &*s.end()); } - static dumb_string copyn(const char *sn, size_t n) + static +#ifndef __clang__ + __attribute__((warning("shouldn't use this - slice instead"))) +#endif + dumb_string copyn(const char *sn, size_t n) { return dumb_string::copy(sn, sn + strnlen(sn, n)); } - static dumb_string copyc(const_string s) - { - return dumb_string::copy(s.begin(), s.end()); - } static - dumb_string fake(const char *p) + dumb_string fake(ZString p) { dumb_string rv; - size_t len = p ? strlen(p) : 0; - rv.impl = dumb_ptr<char[]>(const_cast<char *>(p), len); + size_t len = p.size(); + rv.impl = dumb_ptr<char[]>(const_cast<char *>(p.c_str()), len); return rv; } @@ -235,17 +235,17 @@ struct dumb_string const char *c_str() const { - return impl ? &impl[0] : ""; + return &impl[0]; } - std::string str() const + operator ZString() const { - return c_str(); + return ZString(ZString::really_construct_from_a_pointer, c_str(), nullptr); } - operator const_string() const + FString str() const { - return const_string(c_str()); + return ZString(*this); } char& operator[](size_t i) const @@ -262,117 +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) - { - return l.impl == r.impl; - } - friend bool operator != (dumb_string l, dumb_string r) - { - return !(l == r); - } -#endif }; -namespace operators -{ - inline - bool operator == (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) == 0; - } - inline - bool operator != (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) != 0; - } - inline - bool operator < (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) < 0; - } - inline - bool operator <= (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) <= 0; - } - inline - bool operator > (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) > 0; - } - inline - bool operator >= (dumb_string l, dumb_string r) - { - return strcmp(l.c_str(), r.c_str()) >= 0; - } - - inline - bool operator == (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) == 0; - } - inline - bool operator != (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) != 0; - } - inline - bool operator < (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) < 0; - } - inline - bool operator <= (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) <= 0; - } - inline - bool operator > (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) > 0; - } - inline - bool operator >= (const char *l, dumb_string r) - { - return strcmp(l, r.c_str()) >= 0; - } - - inline - bool operator == (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) == 0; - } - inline - bool operator != (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) != 0; - } - inline - bool operator < (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) < 0; - } - inline - bool operator <= (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) <= 0; - } - inline - bool operator > (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) > 0; - } - inline - bool operator >= (dumb_string l, const char *r) - { - return strcmp(l.c_str(), r) >= 0; - } -} - inline const char *convert_for_printf(dumb_string ds) { diff --git a/src/common/extract.cpp b/src/common/extract.cpp index 5e89e19..720e6df 100644 --- a/src/common/extract.cpp +++ b/src/common/extract.cpp @@ -18,28 +18,31 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -bool extract(const_string str, const_string *rv) +#include "../poison.hpp" + +bool extract(XString str, XString *rv) { *rv = str; return true; } -bool extract(const_string str, std::string *rv) +bool extract(XString str, FString *rv) { - *rv = std::string(str.begin(), str.end()); + *rv = str; return true; } -bool extract(const_string str, struct global_reg *var) +bool extract(XString str, struct global_reg *var) { return extract(str, record<','>(&var->str, &var->value)); } -bool extract(const_string str, struct item *it) +bool extract(XString str, struct item *it) { + it->broken = 0; return extract(str, - record<','>( + record<',', 11>( &it->id, &it->nameid, &it->amount, @@ -51,18 +54,5 @@ bool extract(const_string str, struct item *it) &it->card[1], &it->card[2], &it->card[3], - &it->broken)) - || extract(str, - record<','>( - &it->id, - &it->nameid, - &it->amount, - &it->equip, - &it->identify, - &it->refine, - &it->attribute, - &it->card[0], - &it->card[1], - &it->card[2], - &it->card[3])); + &it->broken)); } diff --git a/src/common/extract.hpp b/src/common/extract.hpp index ae1a74b..3c24693 100644 --- a/src/common/extract.hpp +++ b/src/common/extract.hpp @@ -27,14 +27,15 @@ #include "mmo.hpp" #include "utils.hpp" -template<class T, typename=typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value>::type> -bool extract(const_string str, T *iv) +template<class T, typename=typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && !std::is_same<T, bool>::value>::type> +bool extract(XString str, T *iv) { if (!str || str.size() > 20) return false; if (!((str.front() == '-' && std::is_signed<T>::value) || ('0' <= str.front() && str.front() <= '9'))) return false; + // needs a NUL, but can't always be given one. TODO VString? char buf[20 + 1]; std::copy(str.begin(), str.end(), buf); buf[str.size()] = '\0'; @@ -60,14 +61,14 @@ bool extract(const_string str, T *iv) } inline -bool extract(const_string str, TimeT *tv) +bool extract(XString str, TimeT *tv) { return extract(str, &tv->value); } // extra typename=void to workaround some duplicate overload rule template<class T, typename=typename std::enable_if<std::is_enum<T>::value>::type, typename=void> -bool extract(const_string str, T *iv) +bool extract(XString str, T *iv) { typedef typename underlying_type<T>::type U; U v; @@ -79,59 +80,90 @@ bool extract(const_string str, T *iv) return true; } -bool extract(const_string str, const_string *rv); +bool extract(XString str, XString *rv); -bool extract(const_string str, std::string *rv); +bool extract(XString str, FString *rv); -template<size_t N> -__attribute__((deprecated)) -bool extract(const_string str, char (*out)[N]) +template<uint8_t N> +bool extract(XString str, VString<N> *out) { - if (str.size() >= N) + if (str.size() > N) return false; - std::copy(str.begin(), str.end(), *out); - std::fill(*out + str.size() , *out + N, '\0'); + *out = str; return true; } +template<class T> +class LStripper +{ +public: + T impl; +}; + +template<class T> +LStripper<T> lstripping(T v) +{ + return {v}; +} + +template<class T> +bool extract(XString str, LStripper<T> out) +{ + return extract(str.lstrip(), out.impl); +} + // basically just a std::tuple // but it provides its data members publically -template<char split, class... T> +template<char split, int n, class... T> class Record; -template<char split> -class Record<split> +template<char split, int n> +class Record<split, n> { }; -template<char split, class F, class... R> -class Record<split, F, R...> +template<char split, int n, class F, class... R> +class Record<split, n, F, R...> { public: F frist; - Record<split, R...> rest; + Record<split, n - 1, R...> rest; public: Record(F f, R... r) : frist(f), rest(r...) {} }; template<char split, class... T> -Record<split, T...> record(T... t) +Record<split, sizeof...(T), T...> record(T... t) +{ + return Record<split, sizeof...(T), T...>(t...); +} +template<char split, int n, class... T> +Record<split, n, T...> record(T... t) { - return Record<split, T...>(t...); + static_assert(0 < n && n < sizeof...(T), "don't be silly"); + return Record<split, n, T...>(t...); } -template<char split> -bool extract(const_string str, Record<split>) +template<char split, int n> +bool extract(XString str, Record<split, n>) { return !str; } -template<char split, class F, class... R> -bool extract(const_string str, Record<split, F, R...> rec) + +template<char split, int n, class F, class... R> +bool extract(XString str, Record<split, n, F, R...> rec) { - const char *s = std::find(str.begin(), str.end(), split); + XString::iterator s = std::find(str.begin(), str.end(), split); + XString::iterator s2 = s; + if (s2 != str.end()) + ++s2; + XString head = str.xislice_h(s); + XString tail = str.xislice_t(s2); if (s == str.end()) - return sizeof...(R) == 0 && extract(str, rec.frist); - return extract(const_string(str.begin(), s), rec.frist) - && extract(const_string(s + 1, str.end()), rec.rest); + return (extract(head, rec.frist) && n <= 1) + || (!head && n <= 0); + + return (extract(head, rec.frist) || n <= 0) + && extract(tail, rec.rest); } template<char split, class T> @@ -147,20 +179,41 @@ VRecord<split, T> vrec(std::vector<T> *arr) } template<char split, class T> -bool extract(const_string str, VRecord<split, T> rec) +bool extract(XString str, VRecord<split, T> rec) { - if (str.empty()) + if (!str) return true; - const char *s = std::find(str.begin(), str.end(), split); + XString::iterator s = std::find(str.begin(), str.end(), split); rec.arr->emplace_back(); if (s == str.end()) return extract(str, &rec.arr->back()); - return extract(const_string(str.begin(), s), &rec.arr->back()) - && extract(const_string(s + 1, str.end()), rec); + return extract(str.xislice_h(s), &rec.arr->back()) + && extract(str.xislice_t(s + 1), rec); } -bool extract(const_string str, struct global_reg *var); +bool extract(XString str, struct global_reg *var); + +bool extract(XString str, struct item *it); + +inline +bool extract(XString str, MapName *m) +{ + VString<15> tmp; + bool rv = extract(str, &tmp); + *m = tmp; + return rv; +} -bool extract(const_string str, struct item *it); +inline +bool extract(XString str, CharName *out) +{ + VString<23> tmp; + if (extract(str, &tmp)) + { + *out = CharName(tmp); + return true; + } + return false; +} #endif // EXTRACT_HPP diff --git a/src/common/extract_test.cpp b/src/common/extract_test.cpp new file mode 100644 index 0000000..d8e9ebe --- /dev/null +++ b/src/common/extract_test.cpp @@ -0,0 +1,319 @@ +#include "extract.hpp" + +#include <gtest/gtest.h> + +TEST(extract, record_int) +{ + int x, y, z; + x = y = z = 0; + EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 2 ", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("", record<' '>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + + EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract(" ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + + EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(3, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(2, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract(" ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + EXPECT_FALSE(extract("", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; +} + +TEST(extract, record_str) +{ + XString x, y, z; + x = y = z = ""; + EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 ", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("", record<' '>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + + EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract(" ", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + + EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("3", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("2", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("1", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract(" ", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; + EXPECT_TRUE(extract("", record<' ', 1>(&x, &y, &z))); + EXPECT_EQ("", x); + EXPECT_EQ("", y); + EXPECT_EQ("", z); + x = y = z = ""; +} diff --git a/src/common/human_time_diff.hpp b/src/common/human_time_diff.hpp new file mode 100644 index 0000000..3fc0f09 --- /dev/null +++ b/src/common/human_time_diff.hpp @@ -0,0 +1,85 @@ +#ifndef TMWA_COMMON_HUMAN_TIME_DIFF_HPP +#define TMWA_COMMON_HUMAN_TIME_DIFF_HPP +// human_time_diff.hpp - broken deltas +// +// 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 "extract.hpp" +#include "strings.hpp" + +struct HumanTimeDiff +{ + short year, month, day, hour, minute, second; + + explicit + operator bool() + { + return year || month || day || hour || minute || second; + } + + bool operator !() + { + return !bool(*this); + } +}; + +inline +bool extract(XString str, HumanTimeDiff *iv) +{ + // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) + // there are NO spaces here + // parse by counting the number starts + auto is_num = [](char c) + { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; + if (!str || !is_num(str.front())) + return false; + *iv = HumanTimeDiff{}; + while (str) + { + auto it = std::find_if_not(str.begin(), str.end(), is_num); + auto it2 = std::find_if(it, str.end(), is_num); + XString number = str.xislice_h(it); + XString suffix = str.xislice(it, it2); + str = str.xislice_t(it2); + + short *ptr = nullptr; + if (suffix == "y" || suffix == "a") + ptr = &iv->year; + else if (suffix == "m") + ptr = &iv->month; + else if (suffix == "j" || suffix == "d") + ptr = &iv->day; + else if (suffix == "h") + ptr = &iv->hour; + else if (suffix == "mn") + ptr = &iv->minute; + else if (suffix == "s") + ptr = &iv->second; + else + return false; + if (number.startswith('+') && !number.startswith("+-")) + number = number.xslice_t(1); + if (*ptr || !extract(number, ptr)) + return false; + } + return true; +} + +#endif // TMWA_COMMON_HUMAN_TIME_DIFF_HPP diff --git a/src/common/human_time_diff_test.cpp b/src/common/human_time_diff_test.cpp new file mode 100644 index 0000000..d11a116 --- /dev/null +++ b/src/common/human_time_diff_test.cpp @@ -0,0 +1,84 @@ +#include "human_time_diff.hpp" + +#include <gtest/gtest.h> + +// a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) + +TEST(humantimediff, single) +{ + HumanTimeDiff diff; + + EXPECT_TRUE(extract("42y", &diff)); + EXPECT_EQ(42, diff.year); + EXPECT_EQ(0, diff.month); + EXPECT_EQ(0, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(0, diff.second); + + EXPECT_TRUE(extract("42m", &diff)); + EXPECT_EQ(0, diff.year); + EXPECT_EQ(42, diff.month); + EXPECT_EQ(0, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(0, diff.second); + + EXPECT_TRUE(extract("42d", &diff)); + EXPECT_EQ(0, diff.year); + EXPECT_EQ(0, diff.month); + EXPECT_EQ(42, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(0, diff.second); + + EXPECT_TRUE(extract("42h", &diff)); + EXPECT_EQ(0, diff.year); + EXPECT_EQ(0, diff.month); + EXPECT_EQ(0, diff.day); + EXPECT_EQ(42, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(0, diff.second); + + EXPECT_TRUE(extract("42mn", &diff)); + EXPECT_EQ(0, diff.year); + EXPECT_EQ(0, diff.month); + EXPECT_EQ(0, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(42, diff.minute); + EXPECT_EQ(0, diff.second); + + EXPECT_TRUE(extract("42s", &diff)); + EXPECT_EQ(0, diff.year); + EXPECT_EQ(0, diff.month); + EXPECT_EQ(0, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(42, diff.second); + + EXPECT_TRUE(extract("+42y", &diff)); + EXPECT_EQ(42, diff.year); + EXPECT_TRUE(extract("-42y", &diff)); + EXPECT_EQ(-42, diff.year); + EXPECT_FALSE(extract("++42y", &diff)); + EXPECT_FALSE(extract("+-42y", &diff)); + EXPECT_FALSE(extract("-+42y", &diff)); + EXPECT_FALSE(extract("--42y", &diff)); + EXPECT_FALSE(extract("4+2y", &diff)); + EXPECT_FALSE(extract("42z", &diff)); +} + +TEST(humantimediff, multiple) +{ + HumanTimeDiff diff; + + EXPECT_TRUE(extract("42y23m-2d", &diff)); + EXPECT_EQ(42, diff.year); + EXPECT_EQ(23, diff.month); + EXPECT_EQ(-2, diff.day); + EXPECT_EQ(0, diff.hour); + EXPECT_EQ(0, diff.minute); + EXPECT_EQ(0, diff.second); + EXPECT_FALSE(extract("1y2y", &diff)); +} + diff --git a/src/common/intern-pool.hpp b/src/common/intern-pool.hpp index caa54e4..db840a2 100644 --- a/src/common/intern-pool.hpp +++ b/src/common/intern-pool.hpp @@ -4,16 +4,19 @@ #include <cassert> #include <map> -#include <string> #include <vector> +#include "strings.hpp" + class InternPool { - std::map<std::string, size_t> known; - std::vector<std::string> names; + std::map<FString, size_t> known; + std::vector<FString> names; public: - size_t intern(const std::string& name) + size_t intern(XString name_) { + FString name = name_; + // hm, I could change this to do aliases auto pair = known.insert({name, known.size()}); if (pair.second) names.push_back(name); @@ -21,7 +24,7 @@ public: return pair.first->second; } - const std::string& outtern(size_t sz) const + ZString outtern(size_t sz) const { return names[sz]; } diff --git a/src/common/intern-pool_test.cpp b/src/common/intern-pool_test.cpp new file mode 100644 index 0000000..3bbca7b --- /dev/null +++ b/src/common/intern-pool_test.cpp @@ -0,0 +1,18 @@ +#include "intern-pool.hpp" + +#include <gtest/gtest.h> + +TEST(InternPool, whydoesthisalwaysneedasecondname) +{ + InternPool p; + EXPECT_EQ(0, p.size()); + EXPECT_EQ(0, p.intern("hello")); + EXPECT_EQ(0, p.intern("hello")); + EXPECT_EQ(1, p.size()); + EXPECT_EQ(1, p.intern("world")); + EXPECT_EQ(0, p.intern("hello")); + EXPECT_EQ(1, p.intern("world")); + EXPECT_EQ(2, p.size()); + EXPECT_EQ("hello", p.outtern(0)); + EXPECT_EQ("world", p.outtern(1)); +} diff --git a/src/common/io.hpp b/src/common/io.hpp new file mode 100644 index 0000000..1831651 --- /dev/null +++ b/src/common/io.hpp @@ -0,0 +1,26 @@ +#ifndef TMWA_COMMON_IO_HPP +#define TMWA_COMMON_IO_HPP + +#include <istream> +#include <ostream> + +#include "strings.hpp" + +namespace io +{ + inline + std::istream& getline(std::istream& in, FString& line) + { + std::string s; + if (std::getline(in, s)) + { + std::string::const_iterator begin = s.cbegin(), end = s.cend(); + if (begin != end && end[-1] == '\r') + --end; + line = FString(begin, end); + } + return in; + } +} // namespace io + +#endif //TMWA_COMMON_IO_HPP diff --git a/src/common/lock.cpp b/src/common/lock.cpp index 82856e1..f19cd92 100644 --- a/src/common/lock.cpp +++ b/src/common/lock.cpp @@ -17,17 +17,17 @@ const int backup_count = 10; /// (Until the file is closed, it keeps the old file) // Start writing a tmpfile -FILE *lock_fopen(const char *filename, int *info) +FILE *lock_fopen(ZString filename, int *info) { FILE *fp; int no = getpid(); // Get a filename that doesn't already exist - std::string newfile; + FString newfile; do { newfile = STRPRINTF("%s_%d.tmp", filename, no++); - fp = fopen_(newfile.c_str(), "wx"); + fp = fopen(newfile.c_str(), "wx"); } while (!fp); *info = --no; @@ -35,22 +35,22 @@ FILE *lock_fopen(const char *filename, int *info) } // Delete the old file and rename the new file -void lock_fclose(FILE *fp, const char *filename, int *info) +void lock_fclose(FILE *fp, ZString filename, int *info) { if (fp) { - fclose_(fp); + fclose(fp); int n = backup_count; - std::string old_filename = STRPRINTF("%s.%d", filename, n); + FString old_filename = STRPRINTF("%s.%d", filename, n); while (--n) { - std::string newer_filename = STRPRINTF("%s.%d", filename, n); + FString newer_filename = STRPRINTF("%s.%d", filename, n); rename(newer_filename.c_str(), old_filename.c_str()); old_filename = std::move(newer_filename); } - rename(filename, old_filename.c_str()); + rename(filename.c_str(), old_filename.c_str()); - std::string tmpfile = STRPRINTF("%s_%d.tmp", filename, *info); - rename(tmpfile.c_str(), filename); + FString tmpfile = STRPRINTF("%s_%d.tmp", filename, *info); + rename(tmpfile.c_str(), filename.c_str()); } } diff --git a/src/common/lock.hpp b/src/common/lock.hpp index f7ce2d8..df4d1f8 100644 --- a/src/common/lock.hpp +++ b/src/common/lock.hpp @@ -5,11 +5,13 @@ #include <cstdio> +#include "strings.hpp" + // TODO replace with a class /// Locked FILE I/O // Changes are made in a separate file until lock_fclose -FILE *lock_fopen(const char *filename, int *info); -void lock_fclose(FILE * fp, const char *filename, int *info); +FILE *lock_fopen(ZString filename, int *info); +void lock_fclose(FILE *fp, ZString filename, int *info); #endif // LOCK_HPP diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp index 582c152..ae134b7 100644 --- a/src/common/md5calc.cpp +++ b/src/common/md5calc.cpp @@ -2,6 +2,7 @@ #include <cstring> +#include "cxxstdio.hpp" #include "random.hpp" #include "utils.hpp" @@ -171,7 +172,7 @@ void MD5_do_block(MD5_state* state, MD5_block block) #undef d } -void MD5_to_bin(MD5_state state, uint8_t out[0x10]) +void MD5_to_bin(MD5_state state, md5_binary& out) { for (int i = 0; i < 0x10; i++) out[i] = state.val[i / 4] >> 8 * (i % 4); @@ -180,47 +181,47 @@ void MD5_to_bin(MD5_state state, uint8_t out[0x10]) static const char hex[] = "0123456789abcdef"; -void MD5_to_str(MD5_state state, char out[0x21]) +void MD5_to_str(MD5_state state, md5_string& out_) { - uint8_t bin[16]; + md5_binary bin; MD5_to_bin(state, bin); + char out[0x20]; for (int i = 0; i < 0x10; i++) out[2 * i] = hex[bin[i] >> 4], out[2 * i + 1] = hex[bin[i] & 0xf]; - out[0x20] = '\0'; + out_ = stringish<md5_string>(XString(out, out + 0x20, nullptr)); } -MD5_state MD5_from_string(const char* msg, const size_t msglen) +MD5_state MD5_from_string(XString msg) { MD5_state state; MD5_init(&state); MD5_block block; - size_t rem = msglen; - while (rem >= 64) + const uint64_t msg_full_len = msg.size(); + while (msg.size() >= 64) { for (int i = 0; i < 0x10; i++) X[i] = msg[4 * i + 0] | msg[4 * i + 1] << 8 | msg[4 * i + 2] << 16 | msg[4 * i + 3] << 24; MD5_do_block(&state, block); - msg += 64; - rem -= 64; + msg = msg.xslice_t(64); } // now pad 1-512 bits + the 64-bit length - may be two blocks uint8_t buf[0x40] = {}; - really_memcpy(buf, reinterpret_cast<const uint8_t *>(msg), rem); - buf[rem] = 0x80; // a single one bit - if (64 - rem > 8) + really_memcpy(buf, reinterpret_cast<const uint8_t *>(msg.data()), msg.size()); + buf[msg.size()] = 0x80; // a single one bit + if (64 - msg.size() > 8) { for (int i = 0; i < 8; i++) - buf[0x38 + i] = (static_cast<uint64_t>(msglen) * 8) >> (i * 8); + buf[0x38 + i] = (msg_full_len * 8) >> (i * 8); } for (int i = 0; i < 0x10; i++) X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); - if (64 - rem <= 8) + if (64 - msg.size() <= 8) { really_memset0(buf, 0x38); for (int i = 0; i < 8; i++) - buf[0x38 + i] = (static_cast<uint64_t>(msglen) * 8) >> (i * 8); + buf[0x38 + i] = (msg_full_len * 8) >> (i * 8); for (int i = 0; i < 0x10; i++) X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); @@ -228,12 +229,8 @@ MD5_state MD5_from_string(const char* msg, const size_t msglen) return state; } -// This could be reimplemented without the strlen() -MD5_state MD5_from_cstring(const char* msg) -{ - return MD5_from_string(msg, strlen(msg)); -} - +// TODO - refactor MD5 into a stream, and merge the implementations +// I once implemented an ostream that does it ... MD5_state MD5_from_FILE(FILE* in) { uint64_t total_len = 0; @@ -286,50 +283,53 @@ MD5_state MD5_from_FILE(FILE* in) // Hash a password with a salt. // Whoever wrote this FAILS programming -const char *MD5_saltcrypt(const char *key, const char *salt) +AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt) { - char buf[65]; + char cbuf[64] {}; // hash the key then the salt // buf ends up as a 64-char NUL-terminated string - MD5_to_str(MD5_from_cstring(key), buf); - MD5_to_str(MD5_from_cstring(salt), buf + 32); + md5_string tbuf, tbuf2; + MD5_to_str(MD5_from_string(key), tbuf); + MD5_to_str(MD5_from_string(salt), tbuf2); + const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf)); + auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it); + assert(it2 == std::end(cbuf)); + + md5_string tbuf3; + MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3); - // Hash the buffer back into sbuf - this is stupid - // (luckily, putting the result into itself is safe) - MD5_to_str(MD5_from_cstring(buf), buf + 32); + VString<31> obuf; - static char obuf[33]; // This truncates the string, but we have to keep it like that for compatibility - snprintf(obuf, 32, "!%s$%s", salt, buf + 32); - return obuf; + SNPRINTF(obuf, 32, "!%s$%s", salt, tbuf3); + return stringish<AccountCrypt>(obuf); } -const char *make_salt(void) +SaltString make_salt(void) { - static char salt[6]; + char salt[5]; for (int i = 0; i < 5; i++) // 126 would probably actually be okay salt[i] = random_::in(48, 125); - return salt; + return stringish<SaltString>(XString(salt + 0, salt + 5, nullptr)); } -bool pass_ok(const char *password, const char *crypted) +bool pass_ok(AccountPass password, AccountCrypt crypted) { - char buf[40]; - strzcpy(buf, crypted, 40); // crypted is like !salt$hash - char *salt = buf + 1; - *strchr(salt, '$') = '\0'; + auto begin = crypted.begin() + 1; + auto end = std::find(begin, crypted.end(), '$'); + SaltString salt = stringish<SaltString>(crypted.xislice(begin, end)); - return !strcmp(crypted, MD5_saltcrypt(password, salt)); + return crypted == MD5_saltcrypt(password, salt); } // [M|h]ashes up an IP address and a secret key // to return a hopefully unique masked IP. -struct in_addr MD5_ip(char *secret, struct in_addr ip) +struct in_addr MD5_ip(struct in_addr ip) { - uint8_t obuf[16]; + static SaltString secret = make_salt(); union { uint8_t bytes[4]; @@ -337,10 +337,10 @@ struct in_addr MD5_ip(char *secret, struct in_addr ip) } conv; // MD5sum a secret + the IP address - char ipbuf[32] {}; - snprintf(ipbuf, sizeof(ipbuf), "%u%s", ip.s_addr, secret); - /// TODO stop it from being a cstring - MD5_to_bin(MD5_from_cstring(ipbuf), obuf); + VString<31> ipbuf; + SNPRINTF(ipbuf, 32, "%u%s", ip.s_addr, secret); + md5_binary obuf; + MD5_to_bin(MD5_from_string(ipbuf), obuf); // Fold the md5sum to 32 bits, pack the bytes to an in_addr conv.bytes[0] = obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]; diff --git a/src/common/md5calc.hpp b/src/common/md5calc.hpp index de19e0f..98f44d6 100644 --- a/src/common/md5calc.hpp +++ b/src/common/md5calc.hpp @@ -9,44 +9,51 @@ #include <cstddef> #include <cstdio> +#include <array> + +#include "mmo.hpp" +#include "strings.hpp" + /// The digest state - becomes the output -typedef struct +struct MD5_state { // classically named {A,B,C,D} // but use an so we can index uint32_t val[4]; -} MD5_state; -typedef struct +}; +struct MD5_block { uint32_t data[16]; -} MD5_block; +}; + +struct md5_binary : std::array<uint8_t, 0x10> {}; +struct md5_string : VString<0x20> {}; +struct SaltString : VString<5> {}; // Implementation -void MD5_init(MD5_state* state); -void MD5_do_block(MD5_state* state, MD5_block block); +void MD5_init(MD5_state *state); +void MD5_do_block(MD5_state *state, MD5_block block); // Output formatting -void MD5_to_bin(MD5_state state, uint8_t out[0x10]); -void MD5_to_str(MD5_state state, char out[0x21]); +void MD5_to_bin(MD5_state state, md5_binary& out); +void MD5_to_str(MD5_state state, md5_string& out); // Convenience -MD5_state MD5_from_string(const char* msg, const size_t msglen); -MD5_state MD5_from_cstring(const char* msg); +MD5_state MD5_from_string(XString msg); MD5_state MD5_from_FILE(FILE* in); -// statically-allocated output // whoever wrote this fails basic understanding of -const char *MD5_saltcrypt(const char *key, const char *salt); +AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt); /// return some random characters (statically allocated) // Currently, returns a 5-char string -const char *make_salt(void); +SaltString make_salt(void); /// check plaintext password against saved saltcrypt -bool pass_ok(const char *password, const char *crypted); +bool pass_ok(AccountPass password, AccountCrypt crypted); /// This returns an in_addr because it is configurable whether it gets called at all -struct in_addr MD5_ip(char *secret, struct in_addr ip); +struct in_addr MD5_ip(struct in_addr ip); #endif // MD5CALC_HPP diff --git a/src/common/md5calc_test.cpp b/src/common/md5calc_test.cpp new file mode 100644 index 0000000..51b0b68 --- /dev/null +++ b/src/common/md5calc_test.cpp @@ -0,0 +1,27 @@ +#include "md5calc.hpp" + +#include <gtest/gtest.h> + +#include "utils.hpp" + +// This should be made part of the main API, +// but is not yet to keep the diff small. +// Edit: hack to fix the new strict comparison. +static +VString<32> MD5(XString in) +{ + md5_string out; + MD5_to_str(MD5_from_string(in), out); + return out; +} + +TEST(md5calc, rfc1321) +{ + EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e", MD5("")); + EXPECT_EQ("0cc175b9c0f1b6a831c399e269772661", MD5("a")); + EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", MD5("abc")); + EXPECT_EQ("f96b697d7cb7938d525a2f31aaf161d0", MD5("message digest")); + EXPECT_EQ("c3fcd3d76192e4007dfb496cca67e13b", MD5("abcdefghijklmnopqrstuvwxyz")); + EXPECT_EQ("d174ab98d277d9f5a5611c2c9f419d9f", MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); + EXPECT_EQ("57edf4a22be3c955ac49da2e2107b67a", MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890")); +} diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index 450aa61..89ff50a 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -4,7 +4,10 @@ # include "sanity.hpp" # include "timer.t.hpp" -# include "utils.hpp" +# include "utils2.hpp" + +// affects CharName +# define NAME_IGNORING_CASE 1 constexpr int FIFOSIZE_SERVERLINK = 256 * 1024; @@ -37,6 +40,105 @@ constexpr int MAX_PARTY = 12; # define CHAR_CONF_NAME "conf/char_athena.conf" +struct AccountName : VString<23> {}; +struct AccountPass : VString<23> {}; +struct AccountCrypt : VString<39> {}; +struct AccountEmail : VString<39> {}; +struct ServerName : VString<19> {}; +struct PartyName : VString<23> {}; +struct VarName : VString<31> {}; +template<class T> +T stringish(VString<sizeof(T) - 1> iv) +{ + T rv; + static_cast<VString<sizeof(T) - 1>&>(rv) = iv; + return rv; +} +#define DEFAULT_EMAIL stringish<AccountEmail>("a@a.com") + +// It is decreed: a mapname shall not contain an extension +class MapName : public strings::_crtp_string<MapName, MapName, ZString, XString> +{ + VString<15> _impl; +public: + MapName() = default; + MapName(VString<15> v) : _impl(v.oislice_h(std::find(v.begin(), v.end(), '.'))) {} + + iterator begin() const { return &*_impl.begin(); } + iterator end() const { return &*_impl.begin(); } + const char *c_str() const { return _impl.c_str(); } + + operator FString() const { return _impl; } + operator TString() const { return _impl; } + operator SString() const { return _impl; } + operator ZString() const { return _impl; } + operator XString() const { return _impl; } +}; +template<> +inline +MapName stringish<MapName>(VString<15> iv) +{ + return iv; +} +inline +const char *decay_for_printf(const MapName& vs) { return vs.c_str(); } + +// It is decreed: a charname is sometimes case sensitive +struct CharName +{ +private: + VString<23> _impl; +public: + CharName() = default; + explicit CharName(VString<23> name) + : _impl(name) + {} + + VString<23> to__actual() const + { + return _impl; + } + VString<23> to__lower() const + { + return _impl.to_lower(); + } + VString<23> to__upper() const + { + return _impl.to_upper(); + } + VString<23> to__canonical() const + { +#if NAME_IGNORING_CASE == 0 + return to__actual(); +#endif +#if NAME_IGNORING_CASE == 1 + return to__lower(); +#endif + } + + friend bool operator == (const CharName& l, const CharName& r) + { return l.to__canonical() == r.to__canonical(); } + friend bool operator != (const CharName& l, const CharName& r) + { return l.to__canonical() != r.to__canonical(); } + friend bool operator < (const CharName& l, const CharName& r) + { return l.to__canonical() < r.to__canonical(); } + friend bool operator <= (const CharName& l, const CharName& r) + { return l.to__canonical() <= r.to__canonical(); } + friend bool operator > (const CharName& l, const CharName& r) + { return l.to__canonical() > r.to__canonical(); } + friend bool operator >= (const CharName& l, const CharName& r) + { return l.to__canonical() >= r.to__canonical(); } + + friend + VString<23> convert_for_printf(const CharName& vs) { return vs.to__actual(); } +}; +template<> +inline +CharName stringish<CharName>(VString<23> iv) +{ + return CharName(iv); +} + namespace e { enum class EPOS : uint16_t @@ -78,7 +180,7 @@ struct item struct point { - char map_[16]; + MapName map_; short x, y; }; @@ -105,7 +207,7 @@ struct skill_value struct global_reg { - char str[32]; + VarName str; int value; }; @@ -182,7 +284,7 @@ struct mmo_charstatus short shield; short head_top, head_mid, head_bottom; - char name[24]; + CharName name; unsigned char base_level, job_level; earray<short, ATTR, ATTR::COUNT> attrs; unsigned char char_num, sex; @@ -221,7 +323,8 @@ struct GM_Account struct party_member { int account_id; - char name[24], map[24]; + CharName name; + MapName map; int leader, online, lv; struct map_session_data *sd; }; @@ -229,16 +332,10 @@ struct party_member struct party { int party_id; - char name[24]; + PartyName name; int exp; int item; struct party_member member[MAX_PARTY]; }; -struct square -{ - int val1[5]; - int val2[5]; -}; - #endif // MMO_HPP diff --git a/src/common/sanity.hpp b/src/common/sanity.hpp index 74e24df..3658f9f 100644 --- a/src/common/sanity.hpp +++ b/src/common/sanity.hpp @@ -22,29 +22,6 @@ # if __GNUC_MINOR__ < 6 && !defined(__clang__) # error "Please upgrade to at least GCC 4.6" # endif // __GNUC_MINOR__ < 6 && !defined(__clang__) -// temporary workaround for library issues -// since __GLIBCXX__ is hard to use -# if __GNUC_MINOR__ == 6 -# define WORKAROUND_GCC46_COMPILER -# endif // __GNUC_MINOR__ == 6 -# ifdef __GLIBCXX__ -// versions of libstdc++ from gcc -// 4.6.0, 4.6.1, 4.6.2, 4.6.3, 4.6.4 -# if __GLIBCXX__ == 20110325 \ - || __GLIBCXX__ == 20110627 \ - || __GLIBCXX__ == 20111026 \ - || __GLIBCXX__ == 20120301 \ - || __GLIBCXX__ == 20130412 \ - /* various Debian snapshots */ \ - || __GLIBCXX__ == 20121127 \ - || __GLIBCXX__ == 20130114 -# define WORKAROUND_GCC46_LIBRARY -# endif // __GLIBCXX__ == ... -# endif // defined __GLIBCXX__ -# if defined(WORKAROUND_GCC46_COMPILER) \ - && !defined(WORKAROUND_GCC46_LIBRARY) -# error "Unknown gcc 4.6.x release" -# endif // compiler and not library # endif // __GNUC__ == 4 # if not defined(__i386__) and not defined(__x86_64__) diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 214fb5a..2d08171 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -21,8 +21,6 @@ static fd_set readfds; int fd_max; -static -int currentuse; static const uint32_t RFIFO_SIZE = 65536; @@ -128,16 +126,17 @@ void connect_client(int listen_fd) perror("accept"); return; } - if (fd_max <= fd) - { - fd_max = fd + 1; - } - if (!free_fds()) + if (fd >= SOFT_LIMIT) { FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd); - delete_session(fd); + shutdown(fd, SHUT_RDWR); + close(fd); return; } + if (fd_max <= fd) + { + fd_max = fd + 1; + } const int yes = 1; /// Allow to bind() again after the server restarts. @@ -178,8 +177,6 @@ void connect_client(int listen_fd) session[fd]->client_addr = client_address; session[fd]->created = TimeT::now(); session[fd]->connected = 0; - - currentuse++; } int make_listen_port(uint16_t port) @@ -237,7 +234,6 @@ int make_listen_port(uint16_t port) session[fd]->created = TimeT::now(); session[fd]->connected = 1; - currentuse++; return fd; } @@ -295,7 +291,6 @@ int make_connection(uint32_t ip, uint16_t port) session[fd]->created = TimeT::now(); session[fd]->connected = 1; - currentuse++; return fd; } @@ -326,13 +321,6 @@ void delete_session(int fd) // just close() would try to keep sending buffers shutdown(fd, SHUT_RDWR); close(fd); - currentuse--; - if (currentuse < 0) - { - FPRINTF(stderr, "delete_session: current sessions negative!\n"); - currentuse = 0; - } - return; } void realloc_fifo(int fd, size_t rfifo_size, size_t wfifo_size) @@ -446,7 +434,6 @@ void do_socket(void) #pragma GCC diagnostic ignored "-Wold-style-cast" FD_ZERO(&readfds); #pragma GCC diagnostic pop - currentuse = 3; } void RFIFOSKIP(int fd, size_t len) @@ -460,23 +447,3 @@ void RFIFOSKIP(int fd, size_t len) abort(); } } - -void fclose_(FILE * fp) -{ - if (fclose(fp)) - perror("fclose"), abort(); - currentuse--; -} - -FILE *fopen_(const char *path, const char *mode) -{ - FILE *f = fopen(path, mode); - if (f) - currentuse++; - return f; -} - -bool free_fds(void) -{ - return currentuse < SOFT_LIMIT; -} diff --git a/src/common/socket.hpp b/src/common/socket.hpp index 2366373..dd1c872 100644 --- a/src/common/socket.hpp +++ b/src/common/socket.hpp @@ -96,12 +96,6 @@ void do_socket(void); // themselves as servers void set_defaultparse(void(*defaultparse)(int)); -/// Wrappers to track number of free FDs -void fclose_(FILE * fp); -FILE *fopen_(const char *path, const char *mode); - -bool free_fds(void); - template<class T> uint8_t *pod_addressof_m(T& structure) { @@ -149,10 +143,22 @@ void RFIFO_STRUCT(int fd, size_t pos, T& structure) { really_memcpy(pod_addressof_m(structure), static_cast<const uint8_t *>(RFIFOP(fd, pos)), sizeof(T)); } +template<uint8_t len> +inline +VString<len-1> RFIFO_STRING(int fd, size_t pos) +{ + const char *const begin = static_cast<const char *>(RFIFOP(fd, pos)); + const char *const end = begin + len-1; + const char *const mid = std::find(begin, end, '\0'); + return XString(begin, mid, nullptr); +} inline -void RFIFO_STRING(int fd, size_t pos, char *out, size_t len) +FString RFIFO_STRING(int fd, size_t pos, size_t len) { - strzcpy(out, static_cast<const char *>(RFIFOP(fd, pos)), len); + const char *const begin = static_cast<const char *>(RFIFOP(fd, pos)); + const char *const end = begin + len; + const char *const mid = std::find(begin, end, '\0'); + return XString(begin, mid, nullptr); } inline void RFIFO_BUF_CLONE(int fd, uint8_t *buf, size_t len) @@ -189,14 +195,27 @@ void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure) { really_memcpy(pod_addressof_m(structure), p + pos, sizeof(T)); } +template<uint8_t len> +inline +VString<len-1> RBUF_STRING(const uint8_t *p, size_t pos) +{ + const char *const begin = static_cast<const char *>(RBUFP(p, pos)); + const char *const end = begin + len-1; + const char *const mid = std::find(begin, end, '\0'); + return XString(begin, mid, nullptr); +} inline -void RBUF_STRING(const uint8_t *p, size_t pos, char *out, size_t len) +FString RBUF_STRING(const uint8_t *p, size_t pos, size_t len) { - strzcpy(out, static_cast<const char *>(RBUFP(p, pos)), len); + const char *const begin = static_cast<const char *>(RBUFP(p, pos)); + const char *const end = begin + len; + const char *const mid = std::find(begin, end, '\0'); + return XString(begin, mid, nullptr); } /// Unused - check how much data can be written +// the existence of this seems scary inline size_t WFIFOSPACE(int fd) { @@ -229,9 +248,12 @@ void WFIFO_STRUCT(int fd, size_t pos, T& structure) 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) +void WFIFO_STRING(int fd, size_t pos, XString s, size_t len) { - strzcpy(static_cast<char *>(WFIFOP(fd, pos)), s, len); + char *const begin = static_cast<char *>(WFIFOP(fd, pos)); + char *const end = begin + len; + char *const mid = std::copy(s.begin(), s.end(), begin); + std::fill(mid, end, '\0'); } inline void WFIFO_ZERO(int fd, size_t pos, size_t len) @@ -276,9 +298,12 @@ void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure) 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) +void WBUF_STRING(uint8_t *p, size_t pos, XString s, size_t len) { - strzcpy(static_cast<char *>(WBUFP(p, pos)), s, len); + char *const begin = static_cast<char *>(WBUFP(p, pos)); + char *const end = begin + len; + char *const mid = std::copy(s.begin(), s.end(), begin); + std::fill(mid, end, '\0'); } inline void WBUF_ZERO(uint8_t *p, size_t pos, size_t len) diff --git a/src/common/strings.hpp b/src/common/strings.hpp index 8562ec4..ead3f52 100644 --- a/src/common/strings.hpp +++ b/src/common/strings.hpp @@ -22,10 +22,17 @@ #include "sanity.hpp" #include <cassert> +#include <cstdarg> #include <cstring> +#include <algorithm> +#include <deque> #include <iterator> -#include <string> +#include <memory> +#include <type_traits> +#include <vector> + +#include "utils2.hpp" // 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 @@ -64,13 +71,13 @@ namespace strings _iterator(const char *p=nullptr) : _ptr(p) {} // iterator - reference operator *() { return *_ptr; } + reference operator *() const { 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; } + pointer operator->() const { return _ptr; } X operator++ (int) { X out = *this; ++*this; return out; } // forward iterator is mostly semantical, and the ctor is above // bidirectional iterator @@ -83,8 +90,8 @@ namespace strings 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; } + reference operator[](difference_type n) const { 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); } @@ -92,7 +99,7 @@ namespace strings /// 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> + template<class T, class O, class Z, class X=XString> class _crtp_string { public: @@ -108,22 +115,67 @@ namespace strings 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(); } + explicit + operator bool() const { return size(); } + bool operator !() const { 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; + Z xslice_t(size_t o) const; + X xslice_h(size_t o) const; + Z xrslice_t(size_t no) const; + X xrslice_h(size_t no) const; + Z xislice_t(iterator it) const; + X xislice_h(iterator it) const; + X xlslice(size_t o, size_t l) const; + X xpslice(size_t b, size_t e) const; + X xislice(iterator b, iterator e) const; + Z lstrip() const; + X rstrip() const; + X strip() const; + bool startswith(XString x) const; bool endswith(XString x) const; + bool startswith(char c) const; + bool endswith(char c) const; + + bool contains(char c) const; + bool contains_seq(XString s) const; + bool contains_any(XString s) const; + + bool has_print() const; + bool is_print() const; + __attribute__((deprecated)) + O to_print() const; + + bool is_graph() const; + bool has_graph() const; + + bool has_lower() const; + bool is_lower() const; + O to_lower() const; + + bool has_upper() const; + bool is_upper() const; + O to_upper() const; + + bool has_alpha() const; // equivalent to has_lower || has_upper + bool is_alpha() const; // NOT equivalent to is_lower || is_upper + + bool has_digit2() const; + bool is_digit2() const; + bool has_digit8() const; + bool is_digit8() const; + bool has_digit10() const; + bool is_digit10() const; + bool has_digit16() const; + bool is_digit16() const; + + bool has_alnum() const; // equivalent to has_alpha || has_digit10 + bool is_alnum() const; // NOT equivalent to is_alpha || is_digit10 }; @@ -134,53 +186,112 @@ namespace strings class MString { public: - typedef char *iterator; - typedef _iterator<MString> const_iterator; + typedef std::deque<char>::iterator iterator; + typedef std::deque<char>::const_iterator const_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; private: - std::string _hack; + std::deque<char> _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(); } + 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()); } + + size_t size() const { return _hack.size(); } + explicit + operator bool() const { return size(); } + bool operator !() const { return !size(); } + + MString& operator += (MString rhs) + { + _hack.insert(_hack.end(), rhs.begin(), rhs.end()); + return *this; + } + MString& operator += (char c) + { + _hack.push_back(c); + return *this; + } + MString& operator += (XString xs); + + void pop_back(size_t n=1) + { + while (n--) + _hack.pop_back(); + } + char& front() + { + return _hack.front(); + } + char& back() + { + return _hack.back(); + } }; /// 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> + class FString : public _crtp_string<FString, FString, ZString, XString> { - /*const*/ std::string _hack; + std::shared_ptr<std::vector<char>> _hack2; + + template<class It> + void _assign(It b, It e) + { + if (b == e) + { + // TODO use a special empty object + // return; + } + if (!std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) + { + // can't use std::distance + _hack2 = std::make_shared<std::vector<char>>(); + for (; b != e; ++b) + _hack2->push_back(*b); + _hack2->push_back('\0'); + _hack2->shrink_to_fit(); + } + size_t diff = std::distance(b, e); + _hack2 = std::make_shared<std::vector<char>>(diff + 1, '\0'); + std::copy(b, e, _hack2->begin()); + } public: -#ifndef __clang__ - __attribute__((warning("This should be removed in the next diff"))) -#endif - FString(std::string s) : _hack(std::move(s)) {} + FString() + { + const char *sadness = ""; + _assign(sadness, sadness); + } + + explicit FString(const MString& s) + { + _assign(s.begin(), s.end()); + } - 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) {} + FString(const char (&s)[n]) + { + _assign(s, s + strlen(s)); + } + template<class It> - FString(It b, It e) : _hack(b, e) {} + FString(It b, It e) + { + _assign(b, e); + } + - iterator begin() const { return &*_hack.begin(); } - iterator end() const { return &*_hack.end(); } + iterator begin() const { return &_hack2->begin()[0]; } + iterator end() const { return &_hack2->end()[-1]; } const FString *base() const { return this; } const char *c_str() const { return &*begin(); } @@ -188,13 +299,16 @@ namespace strings SString oslice_h(size_t o) const; TString orslice_t(size_t no) const; SString orslice_h(size_t no) const; + TString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; SString olslice(size_t o, size_t l) const; SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; }; /// An owning string that represents a tail slice of an FString. /// Guaranteed to be NUL-terminated. - class TString : public _crtp_string<TString> + class TString : public _crtp_string<TString, TString, ZString, XString> { friend class SString; FString _s; @@ -206,6 +320,8 @@ namespace strings TString(char (&s)[n]) = delete; template<size_t n> TString(const char (&s)[n]) : _s(s), _o(0) {} + //template<class It> + //TString(It b, It e) : _s(b, e), _o(0) {} iterator begin() const { return &_s.begin()[_o]; } iterator end() const { return &*_s.end(); } @@ -216,28 +332,32 @@ namespace strings SString oslice_h(size_t o) const; TString orslice_t(size_t no) const; SString orslice_h(size_t no) const; + TString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; SString olslice(size_t o, size_t l) const; SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; - operator FString() + operator FString() const { 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> + class SString : public _crtp_string<SString, SString, XString, XString> { 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(TString t) : _s(t._s), _b(0), _e(_s.size()) {} template<size_t n> SString(char (&s)[n]) = delete; template<size_t n> SString(const char (&s)[n]) : _s(s), _b(0), _e(_s.size()) {} - + //template<class It> + //SString(It b, It e) : _s(b, e), _b(0), _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]; } @@ -248,34 +368,34 @@ namespace strings SString oslice_h(size_t o) const; SString orslice_t(size_t no) const; SString orslice_h(size_t no) const; + SString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; SString olslice(size_t o, size_t l) const; SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; - operator FString() + operator FString() const { if (_b == 0 && _e == _s.size()) return _s; else return FString(begin(), end()); } - operator TString() + operator TString() const { 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> + class ZString : public _crtp_string<ZString, FString, ZString, XString> { iterator _b, _e; // optional const FString *_base; 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()), _base(nullptr) {} - enum { really_construct_from_a_pointer }; ZString() { *this = ZString(""); } // no MString ZString(const FString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} ZString(const TString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} ZString(const SString&) = delete; + // dangerous + ZString(const char *b, const char *e, const FString *base_) : _b(b), _e(e), _base(base_) {} ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_) : _b(s), _e(s + strlen(s)), _base(base_) {} template<size_t n> ZString(char (&s)[n]) = delete; @@ -291,27 +411,30 @@ namespace strings XString oslice_h(size_t o) const; ZString orslice_t(size_t no) const; XString orslice_h(size_t no) const; + ZString oislice_t(iterator it) const; + XString oislice_h(iterator it) const; XString olslice(size_t o, size_t l) const; XString opslice(size_t b, size_t e) const; + XString oislice(iterator b, iterator e) const; - operator FString() + operator FString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator TString() + operator TString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator SString() + operator SString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } }; /// 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> + class XString : public _crtp_string<XString, FString, XString, XString> { iterator _b, _e; // optional const FString *_base; public: // do I really want this? - XString() : _b(nullptr), _e(nullptr) {} + XString() : _b(""), _e(_b), _base() {} XString(std::nullptr_t) = delete; // no MString XString(const FString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} @@ -331,32 +454,34 @@ namespace strings iterator begin() const { return _b; } iterator end() const { return _e; } - const FString *base() const { return _base; }; + const FString *base() const { return _base; } 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 oislice_t(iterator it) const { return xislice_t(it); } + XString oislice_h(iterator it) const { return xislice_h(it); } 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); } + XString oislice(iterator b, iterator e) const { return xislice(b, e); } - operator FString() + operator FString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator TString() + operator TString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator SString() + operator SString() const { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator ZString() = delete; + operator ZString() const = delete; }; template<uint8_t n> - class VString : public _crtp_string<VString<n>> + class VString : public _crtp_string<VString<n>, VString<n>, ZString, XString> { char _data[n]; unsigned char _special; - typedef typename _crtp_string<VString<n>>::iterator iterator; public: - static_assert(n & 1, "Size should probably be odd."); + typedef typename _crtp_string<VString<n>, VString<n>, ZString, XString>::iterator iterator; VString(XString x) : _data(), _special() { if (x.size() > n) @@ -397,71 +522,181 @@ namespace strings { *this = XString(e, s, nullptr); } + VString(char c) + { + *this = XString(&c, &c + 1, nullptr); + } VString() { *this = XString(); } + // hopefully this is obvious iterator begin() const { return std::begin(_data); } iterator end() const { return std::end(_data) - _special; } - const FString *base() const { return nullptr; }; + const FString *base() const { return nullptr; } 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 oislice_t(iterator it) const { return this->xislice_t(it); } + VString oislice_h(iterator it) const { return this->xislice_h(it); } 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); } + VString oislice(iterator b, iterator e) const { return this->xislice(b, e); } operator FString() const { return FString(begin(), end()); } operator TString() const { return FString(begin(), end()); } operator SString() const { return FString(begin(), end()); } operator ZString() const { return ZString(_data); } operator XString() const { return XString(&*begin(), &*end(), nullptr); } - }; + template<uint8_t m> + operator VString<m>() const + { + static_assert(m > n, "can only grow"); + XString x = *this; + return VString<m>(XString(x)); + } + }; // not really intended for public use inline int xstr_compare(XString l, XString r) { - return std::lexicographical_compare( + bool less = std::lexicographical_compare( l.begin(), l.end(), r.begin(), r.end()); + bool greater = std::lexicographical_compare( + r.begin(), r.end(), + l.begin(), l.end()); + return greater - less; } + template<class L, class R> - bool operator == (const L& l, const R& r) + class string_comparison_allowed + { + constexpr static bool l_is_vstring_exact = std::is_same<VString<sizeof(L) - 1>, L>::value; + constexpr static bool l_is_vstring_approx = std::is_base_of<VString<sizeof(L) - 1>, L>::value; + constexpr static bool r_is_vstring_exact = std::is_same<VString<sizeof(R) - 1>, R>::value; + constexpr static bool r_is_vstring_approx = std::is_base_of<VString<sizeof(R) - 1>, R>::value; + + constexpr static bool l_is_restricted = l_is_vstring_approx && !l_is_vstring_exact; + constexpr static bool r_is_restricted = r_is_vstring_approx && !r_is_vstring_exact; + public: + constexpr static bool value = std::is_same<L, R>::value || (!l_is_restricted && !r_is_restricted); + }; + + struct _test : VString<1> {}; + struct _test2 : VString<1> {}; + + static_assert(string_comparison_allowed<_test, _test>::value, "tt"); + static_assert(string_comparison_allowed<VString<1>, VString<1>>::value, "vv"); + static_assert(!string_comparison_allowed<_test, XString>::value, "tx"); + static_assert(!string_comparison_allowed<_test, VString<1>>::value, "tv"); + static_assert(!string_comparison_allowed<_test, _test2>::value, "t2"); + static_assert(string_comparison_allowed<VString<1>, XString>::value, "vx"); + static_assert(string_comparison_allowed<XString, XString>::value, "xx"); + static_assert(string_comparison_allowed<XString, FString>::value, "xf"); + + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator == (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) == 0; } - template<class L, class R> - bool operator != (const L& l, const R& r) + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator != (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) != 0; } - template<class L, class R> - bool operator < (const L& l, const R& r) + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator < (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) < 0; } - template<class L, class R> - bool operator <= (const L& l, const R& r) + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator <= (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) <= 0; } - template<class L, class R> - bool operator > (const L& l, const R& r) + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator > (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) > 0; } - template<class L, class R> - bool operator >= (const L& l, const R& r) + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator >= (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) { return xstr_compare(l, r) >= 0; } + namespace detail + { + constexpr + bool is_print(char c) + { + return ' ' <= c && c <= '~'; + } + constexpr + bool is_graph(char c) + { + return is_print(c) && c != ' '; + } + constexpr + bool is_lower(char c) + { + return 'a' <= c && c <= 'z'; + } + constexpr + bool is_upper(char c) + { + return 'A' <= c && c <= 'Z'; + } + constexpr + bool is_alpha(char c) + { + return is_lower(c) || is_upper(c); + } + constexpr + bool is_digit2(char c) + { + return '0' <= c && c <= '1'; + } + constexpr + bool is_digit8(char c) + { + return '0' <= c && c <= '7'; + } + constexpr + bool is_digit10(char c) + { + return '0' <= c && c <= '9'; + } + constexpr + bool is_digit16(char c) + { + return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); + } + constexpr + bool is_alnum(char c) + { + return is_alpha(c) || is_digit10(c); + } + + constexpr + char to_lower(char c) + { + return is_upper(c) ? c | ' ' : c; + } + constexpr + char to_upper(char c) + { + return is_lower(c) ? c & ~' ' : c; + } + } // sadness typedef MString MS; @@ -472,30 +707,176 @@ namespace strings typedef XString XS; // _crtp_string - template<class T> - XS _crtp_string<T>::xslice_t(size_t o) const - { return XS(&begin()[o], &*end(), base()); } - template<class T> - XS _crtp_string<T>::xslice_h(size_t o) const - { return XS(&*begin(), &begin()[o], base()); } - template<class T> - XS _crtp_string<T>::xrslice_t(size_t no) const - { return XS(&end()[-no], &*end(), base()); } - template<class T> - XS _crtp_string<T>::xrslice_h(size_t no) const - { return XS(&*begin(), &end()[-no], base()); } - template<class T> - XS _crtp_string<T>::xlslice(size_t o, size_t l) const - { return XS(&begin()[o], &begin()[o + l], base()); } - template<class T> - XS _crtp_string<T>::xpslice(size_t b, size_t e) const - { return XS(&begin()[b], &begin()[e], base()); } - 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 + template<class T, class O, class Z, class X> + Z _crtp_string<T, O, Z, X>::xslice_t(size_t o) const + { return Z(&begin()[o], &*end(), base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xslice_h(size_t o) const + { return X(&*begin(), &begin()[o], base()); } + template<class T, class O, class Z, class X> + Z _crtp_string<T, O, Z, X>::xrslice_t(size_t no) const + { return Z(&end()[-no], &*end(), base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xrslice_h(size_t no) const + { return X(&*begin(), &end()[-no], base()); } + template<class T, class O, class Z, class X> + Z _crtp_string<T, O, Z, X>::xislice_t(iterator it) const + { return Z(&*it, &*end(), base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xislice_h(iterator it) const + { return X(&*begin(), &*it, base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xlslice(size_t o, size_t l) const + { return X(&begin()[o], &begin()[o + l], base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xpslice(size_t b, size_t e) const + { return X(&begin()[b], &begin()[e], base()); } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::xislice(iterator b, iterator e) const + { return X(&*b, &*e, base()); } + template<class T, class O, class Z, class X> + Z _crtp_string<T, O, Z, X>::lstrip() const + { + Z z = _ref(); + while (z.startswith(' ')) + z = z.xslice_t(1); + return z; + } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::rstrip() const + { + X x = _ref(); + while (x.endswith(' ')) + x = x.xrslice_h(1); + return x; + } + template<class T, class O, class Z, class X> + X _crtp_string<T, O, Z, X>::strip() const + { return lstrip().rstrip(); } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::startswith(XS x) const + { return size() >= x.size() && xslice_h(x.size()) == x; } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::endswith(XS x) const { return size() > x.size() && xrslice_t(x.size()) == x; } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::startswith(char c) const + { return size() && front() == c; } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::endswith(char c) const + { return size() && back() == c; } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::contains(char c) const + { return std::find(begin(), end(), c) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::contains_seq(XString s) const + { return std::search(begin(), end(), s.begin(), s.end()) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::contains_any(XString s) const + { return std::find_if(begin(), end(), [s](char c) { return s.contains(c); }) != end(); } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_print() const + { return std::find_if(begin(), end(), detail::is_print) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_print() const + { return std::find_if_not(begin(), end(), detail::is_print) == end(); } + template<class T, class O, class Z, class X> + O _crtp_string<T, O, Z, X>::to_print() const + { + if (is_print()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, [](char c) { return detail::is_print(c) ? c : '_'; }); + return XString(b, e, nullptr); + } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_graph() const + { return std::find_if(begin(), end(), detail::is_graph) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_graph() const + { return std::find_if_not(begin(), end(), detail::is_graph) == end(); } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_lower() const + { return std::find_if(begin(), end(), detail::is_lower) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_lower() const + { return std::find_if_not(begin(), end(), detail::is_lower) == end(); } + template<class T, class O, class Z, class X> + O _crtp_string<T, O, Z, X>::to_lower() const + { + if (!has_upper()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, detail::to_lower); + return XString(b, e, nullptr); + } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_upper() const + { return std::find_if(begin(), end(), detail::is_upper) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_upper() const + { return std::find_if_not(begin(), end(), detail::is_upper) == end(); } + template<class T, class O, class Z, class X> + O _crtp_string<T, O, Z, X>::to_upper() const + { + if (!has_lower()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, detail::to_upper); + return XString(b, e, nullptr); + } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_alpha() const + { return std::find_if(begin(), end(), detail::is_alpha) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_alpha() const + { return std::find_if_not(begin(), end(), detail::is_alpha) == end(); } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_digit2() const + { return std::find_if(begin(), end(), detail::is_digit2) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_digit2() const + { return std::find_if_not(begin(), end(), detail::is_digit2) == end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_digit8() const + { return std::find_if(begin(), end(), detail::is_digit8) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_digit8() const + { return std::find_if_not(begin(), end(), detail::is_digit8) == end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_digit10() const + { return std::find_if(begin(), end(), detail::is_digit10) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_digit10() const + { return std::find_if_not(begin(), end(), detail::is_digit10) == end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_digit16() const + { return std::find_if(begin(), end(), detail::is_digit16) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_digit16() const + { return std::find_if_not(begin(), end(), detail::is_digit16) == end(); } + + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::has_alnum() const + { return std::find_if(begin(), end(), detail::is_alnum) != end(); } + template<class T, class O, class Z, class X> + bool _crtp_string<T, O, Z, X>::is_alnum() const + { return std::find_if_not(begin(), end(), detail::is_alnum) == end(); } + + // MString + inline + MS& MS::operator += (XS x) + { + _hack.insert(_hack.end(), x.begin(), x.end()); + return *this; + } // FString inline @@ -511,11 +892,20 @@ namespace strings SS FS::orslice_h(size_t no) const { return SS(*this, 0, size() - no); } inline + TS FS::oislice_t(iterator it) const + { return TS(*this, it - begin()); } + inline + SS FS::oislice_h(iterator it) const + { return SS(*this, 0, it - begin()); } + 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); } + inline + SS FS::oislice(iterator b, iterator e) const + { return SS(*this, b - begin(), e - begin()); } // TString inline @@ -531,11 +921,20 @@ namespace strings SS TS::orslice_h(size_t no) const { return SS(_s, _o, _s.size() - no); } inline + TS TS::oislice_t(iterator it) const + { return TS(_s, _o + it - begin()); } + inline + SS TS::oislice_h(iterator it) const + { return SS(_s, _o, _o + it - begin()); } + 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); } + inline + SS TS::oislice(iterator b, iterator e) const + { return SS(_s, _o + b - begin(), _o + e - begin()); } // SString inline @@ -551,11 +950,20 @@ namespace strings SS SS::orslice_h(size_t no) const { return SS(_s, _b, _e - no); } inline + SS SS::oislice_t(iterator it) const + { return SS(_s, _b + it - begin(), _e); } + inline + SS SS::oislice_h(iterator it) const + { return SS(_s, _b, _b + it - begin()); } + 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); } + inline + SS SS::oislice(iterator b, iterator e) const + { return SS(_s, _b + b - begin(), _b + e - begin()); } // ZString inline @@ -571,22 +979,97 @@ namespace strings XS ZS::orslice_h(size_t no) const { return XS(&*begin(), &end()[-no], base()); } inline + ZS ZS::oislice_t(iterator it) const + { return ZS(really_construct_from_a_pointer, &*it, base()); } + inline + XS ZS::oislice_h(iterator it) const + { return XS(&*begin(), &*it, base()); } + inline XS ZS::olslice(size_t o, size_t l) const { return XS(&begin()[o], &begin()[o + l], base()); } inline XS ZS::opslice(size_t b, size_t e) const { return XS(&begin()[b], &begin()[e], base()); } + inline + XS ZS::oislice(iterator b, iterator e) const + { return XS(&*b, &*e, base()); } // cxxstdio helpers // I think the conversion will happen automatically. TODO test this. // Nope, it doesn't, since there's a template + // Actually, it might now. + inline + const char *decay_for_printf(const FString& fs) { return fs.c_str(); } inline - const char *convert_for_printf(const FString& fs) { return fs.c_str(); } + const char *decay_for_printf(const TString& ts) { return ts.c_str(); } inline - const char *convert_for_printf(const TString& ts) { return ts.c_str(); } + const char *decay_for_printf(const ZString& zs) { return zs.c_str(); } + template<uint8_t n> inline - const char *convert_for_printf(const ZString& zs) { return zs.c_str(); } + const char *decay_for_printf(const VString<n>& vs) { return vs.c_str(); } + + template<uint8_t len> + inline __attribute__((format(printf, 2, 0))) + int do_vprint(VString<len>& out, const char *fmt, va_list ap) + { + char buffer[len + 1]; + vsnprintf(buffer, len + 1, fmt, ap); + + out = const_(buffer); + return len; + } + + inline __attribute__((format(printf, 2, 0))) + int do_vprint(FString& out, const char *fmt, va_list ap) + { + int len; + { + va_list ap2; + va_copy(ap2, ap); + len = vsnprintf(nullptr, 0, fmt, ap2); + va_end(ap2); + } + char buffer[len + 1]; + vsnprintf(buffer, len + 1, fmt, ap); + + out = FString(buffer, buffer + len); + return len; + } + + inline __attribute__((format(scanf, 2, 0))) + int do_vscan(ZString in, const char *fmt, va_list ap) + { + return vsscanf(in.c_str(), fmt, ap); + } + + class StringConverter + { + FString& out; + char *mid; + public: + StringConverter(FString& s) + : out(s), mid(nullptr) + {} + ~StringConverter() + { + if (mid) + { + out = ZString(ZString::really_construct_from_a_pointer, mid, nullptr); + free(mid); + } + } + char **operator &() + { + return ∣ + } + }; + + inline + StringConverter convert_for_scanf(FString& s) + { + return StringConverter(s); + } } // namespace strings // owning diff --git a/src/common/strings2_test.cpp b/src/common/strings2_test.cpp new file mode 100644 index 0000000..fa4dc6f --- /dev/null +++ b/src/common/strings2_test.cpp @@ -0,0 +1,118 @@ +#include "strings.hpp" + +#include <gtest/gtest.h> + +TEST(StringTests, traits2) +{ + ZString print_non = "\t\e"; + ZString print_mix = "n\t"; + FString print_all = "n "; + EXPECT_FALSE(print_non.has_print()); + EXPECT_TRUE(print_mix.has_print()); + EXPECT_TRUE(print_all.has_print()); + EXPECT_FALSE(print_non.is_print()); + EXPECT_FALSE(print_mix.is_print()); + EXPECT_TRUE(print_all.is_print()); + EXPECT_EQ("__", print_non.to_print()); + EXPECT_EQ("n_", print_mix.to_print()); + EXPECT_EQ("n ", print_all.to_print()); + EXPECT_EQ(print_all.begin(), print_all.to_print().begin()); + + ZString graph_non = " \e"; + ZString graph_mix = "n "; + FString graph_all = "n."; + EXPECT_FALSE(graph_non.has_graph()); + EXPECT_TRUE(graph_mix.has_graph()); + EXPECT_TRUE(graph_all.has_graph()); + EXPECT_FALSE(graph_non.is_graph()); + EXPECT_FALSE(graph_mix.is_graph()); + EXPECT_TRUE(graph_all.is_graph()); + + ZString lower_non = "0A"; + ZString lower_mix = "Oa"; + FString lower_all = "oa"; + EXPECT_FALSE(lower_non.has_lower()); + EXPECT_TRUE(lower_mix.has_lower()); + EXPECT_TRUE(lower_all.has_lower()); + EXPECT_FALSE(lower_non.is_lower()); + EXPECT_FALSE(lower_mix.is_lower()); + EXPECT_TRUE(lower_all.is_lower()); + EXPECT_EQ("0a", lower_non.to_lower()); + EXPECT_EQ("oa", lower_mix.to_lower()); + EXPECT_EQ("oa", lower_all.to_lower()); + EXPECT_EQ(lower_all.begin(), lower_all.to_lower().begin()); + + ZString upper_non = "0a"; + ZString upper_mix = "oA"; + FString upper_all = "OA"; + EXPECT_FALSE(upper_non.has_upper()); + EXPECT_TRUE(upper_mix.has_upper()); + EXPECT_TRUE(upper_all.has_upper()); + EXPECT_FALSE(upper_non.is_upper()); + EXPECT_FALSE(upper_mix.is_upper()); + EXPECT_TRUE(upper_all.is_upper()); + EXPECT_EQ("0A", upper_non.to_upper()); + EXPECT_EQ("OA", upper_mix.to_upper()); + EXPECT_EQ("OA", upper_all.to_upper()); + EXPECT_EQ(upper_all.begin(), upper_all.to_upper().begin()); + + ZString alpha_non = " 0"; + ZString alpha_mix = "n "; + FString alpha_all = "nA"; + EXPECT_FALSE(alpha_non.has_alpha()); + EXPECT_TRUE(alpha_mix.has_alpha()); + EXPECT_TRUE(alpha_all.has_alpha()); + EXPECT_FALSE(alpha_non.is_alpha()); + EXPECT_FALSE(alpha_mix.is_alpha()); + EXPECT_TRUE(alpha_all.is_alpha()); + + ZString digit2_non = "a9"; + ZString digit2_mix = "20"; + FString digit2_all = "01"; + EXPECT_FALSE(digit2_non.has_digit2()); + EXPECT_TRUE(digit2_mix.has_digit2()); + EXPECT_TRUE(digit2_all.has_digit2()); + EXPECT_FALSE(digit2_non.is_digit2()); + EXPECT_FALSE(digit2_mix.is_digit2()); + EXPECT_TRUE(digit2_all.is_digit2()); + + ZString digit8_non = "a9"; + ZString digit8_mix = "80"; + FString digit8_all = "37"; + EXPECT_FALSE(digit8_non.has_digit8()); + EXPECT_TRUE(digit8_mix.has_digit8()); + EXPECT_TRUE(digit8_all.has_digit8()); + EXPECT_FALSE(digit8_non.is_digit8()); + EXPECT_FALSE(digit8_mix.is_digit8()); + EXPECT_TRUE(digit8_all.is_digit8()); + + ZString digit10_non = "az"; + ZString digit10_mix = "a9"; + FString digit10_all = "42"; + EXPECT_FALSE(digit10_non.has_digit10()); + EXPECT_TRUE(digit10_mix.has_digit10()); + EXPECT_TRUE(digit10_all.has_digit10()); + EXPECT_FALSE(digit10_non.is_digit10()); + EXPECT_FALSE(digit10_mix.is_digit10()); + EXPECT_TRUE(digit10_all.is_digit10()); + + ZString digit16_non = "gz"; + ZString digit16_mix = "ao"; + FString digit16_all = "be"; + EXPECT_FALSE(digit16_non.has_digit16()); + EXPECT_TRUE(digit16_mix.has_digit16()); + EXPECT_TRUE(digit16_all.has_digit16()); + EXPECT_FALSE(digit16_non.is_digit16()); + EXPECT_FALSE(digit16_mix.is_digit16()); + EXPECT_TRUE(digit16_all.is_digit16()); + + ZString alnum_non = " ."; + ZString alnum_mix = "n "; + FString alnum_all = "n0"; + EXPECT_FALSE(alnum_non.has_alnum()); + EXPECT_TRUE(alnum_mix.has_alnum()); + EXPECT_TRUE(alnum_all.has_alnum()); + EXPECT_FALSE(alnum_non.is_alnum()); + EXPECT_FALSE(alnum_mix.is_alnum()); + EXPECT_TRUE(alnum_all.is_alnum()); +} diff --git a/src/common/strings_test.cpp b/src/common/strings_test.cpp index b6a6f67..fa04f1c 100644 --- a/src/common/strings_test.cpp +++ b/src/common/strings_test.cpp @@ -1,4 +1,6 @@ -#include "../../src/common/strings.hpp" +#include "strings.hpp" + +#include <algorithm> #include <gtest/gtest.h> @@ -22,6 +24,118 @@ TYPED_TEST_P(StringTest, basic) const FString *base = hi.base(); } +TYPED_TEST_P(StringTest, order) +{ + TypeParam a; + TypeParam b("Hello"); + TypeParam c("Hello,"); + TypeParam d("World!"); + + // not using EXPECT_LT, etc. for better visibility + + EXPECT_FALSE(a < a); + EXPECT_TRUE(a < b); + EXPECT_TRUE(a < c); + EXPECT_TRUE(a < d); + EXPECT_FALSE(b < a); + EXPECT_FALSE(b < b); + EXPECT_TRUE(b < c); + EXPECT_TRUE(b < d); + EXPECT_FALSE(c < a); + EXPECT_FALSE(c < b); + EXPECT_FALSE(c < c); + EXPECT_TRUE(c < d); + EXPECT_FALSE(d < a); + EXPECT_FALSE(d < b); + EXPECT_FALSE(d < c); + EXPECT_FALSE(d < d); + + EXPECT_TRUE(a <= a); + EXPECT_TRUE(a <= b); + EXPECT_TRUE(a <= c); + EXPECT_TRUE(a <= d); + EXPECT_FALSE(b <= a); + EXPECT_TRUE(b <= b); + EXPECT_TRUE(b <= c); + EXPECT_TRUE(b <= d); + EXPECT_FALSE(c <= a); + EXPECT_FALSE(c <= b); + EXPECT_TRUE(c <= c); + EXPECT_TRUE(c <= d); + EXPECT_FALSE(d <= a); + EXPECT_FALSE(d <= b); + EXPECT_FALSE(d <= c); + EXPECT_TRUE(d <= d); + + EXPECT_TRUE(a >= a); + EXPECT_FALSE(a >= b); + EXPECT_FALSE(a >= c); + EXPECT_FALSE(a >= d); + EXPECT_TRUE(b >= a); + EXPECT_TRUE(b >= b); + EXPECT_FALSE(b >= c); + EXPECT_FALSE(b >= d); + EXPECT_TRUE(c >= a); + EXPECT_TRUE(c >= b); + EXPECT_TRUE(c >= c); + EXPECT_FALSE(c >= d); + EXPECT_TRUE(d >= a); + EXPECT_TRUE(d >= b); + EXPECT_TRUE(d >= c); + EXPECT_TRUE(d >= d); + + EXPECT_FALSE(a > a); + EXPECT_FALSE(a > b); + EXPECT_FALSE(a > c); + EXPECT_FALSE(a > d); + EXPECT_TRUE(b > a); + EXPECT_FALSE(b > b); + EXPECT_FALSE(b > c); + EXPECT_FALSE(b > d); + EXPECT_TRUE(c > a); + EXPECT_TRUE(c > b); + EXPECT_FALSE(c > c); + EXPECT_FALSE(c > d); + EXPECT_TRUE(d > a); + EXPECT_TRUE(d > b); + EXPECT_TRUE(d > c); + EXPECT_FALSE(d > d); + + EXPECT_TRUE(a == a); + EXPECT_FALSE(a == b); + EXPECT_FALSE(a == c); + EXPECT_FALSE(a == d); + EXPECT_FALSE(b == a); + EXPECT_TRUE(b == b); + EXPECT_FALSE(b == c); + EXPECT_FALSE(b == d); + EXPECT_FALSE(c == a); + EXPECT_FALSE(c == b); + EXPECT_TRUE(c == c); + EXPECT_FALSE(c == d); + EXPECT_FALSE(d == a); + EXPECT_FALSE(d == b); + EXPECT_FALSE(d == c); + EXPECT_TRUE(d == d); + + EXPECT_FALSE(a != a); + EXPECT_TRUE(a != b); + EXPECT_TRUE(a != c); + EXPECT_TRUE(a != d); + EXPECT_TRUE(b != a); + EXPECT_FALSE(b != b); + EXPECT_TRUE(b != c); + EXPECT_TRUE(b != d); + EXPECT_TRUE(c != a); + EXPECT_TRUE(c != b); + EXPECT_FALSE(c != c); + EXPECT_TRUE(c != d); + EXPECT_TRUE(d != a); + EXPECT_TRUE(d != b); + EXPECT_TRUE(d != c); + EXPECT_FALSE(d != d); +} + TYPED_TEST_P(StringTest, iterators) { TypeParam hi("Hello"); @@ -39,8 +153,12 @@ TYPED_TEST_P(StringTest, xslice) EXPECT_EQ("Hello,", hi.xslice_h(6)); EXPECT_EQ("World!", hi.xrslice_t(6)); EXPECT_EQ("Hello, ", hi.xrslice_h(6)); + typename TypeParam::iterator it = std::find(hi.begin(), hi.end(), ' '); + EXPECT_EQ(" World!", hi.xislice_t(it)); + EXPECT_EQ("Hello,", hi.xislice_h(it)); EXPECT_EQ("World", hi.xlslice(7, 5)); EXPECT_EQ("World", hi.xpslice(7, 12)); + EXPECT_EQ("World", hi.xislice(hi.begin() + 7, hi.begin() + 12)); EXPECT_TRUE(hi.startswith("Hello")); EXPECT_TRUE(hi.endswith("World!")); } @@ -52,8 +170,12 @@ TYPED_TEST_P(StringTest, oslice) EXPECT_EQ("Hello,", hi.oslice_h(6)); EXPECT_EQ("World!", hi.orslice_t(6)); EXPECT_EQ("Hello, ", hi.orslice_h(6)); + typename TypeParam::iterator it = std::find(hi.begin(), hi.end(), ' '); + EXPECT_EQ(" World!", hi.oislice_t(it)); + EXPECT_EQ("Hello,", hi.oislice_h(it)); EXPECT_EQ("World", hi.olslice(7, 5)); EXPECT_EQ("World", hi.opslice(7, 12)); + EXPECT_EQ("World", hi.oislice(hi.begin() + 7, hi.begin() + 12)); } TYPED_TEST_P(StringTest, convert) @@ -67,6 +189,8 @@ TYPED_TEST_P(StringTest, convert) ZString z = "z"; Xstring x = "x"; VString<255> v = "v"; + const char l[] = "l"; + VString<5> hi = "hello"; TypeParam f2 = f; TypeParam t2 = t; @@ -74,32 +198,40 @@ TYPED_TEST_P(StringTest, convert) TypeParam z2 = z; TypeParam x2 = x; TypeParam v2 = v; + TypeParam l2 = l; + TypeParam hi2 = hi; - EXPECT_EQ(f2, f); - EXPECT_EQ(t2, t); - EXPECT_EQ(s2, s); - EXPECT_EQ(z2, z); - EXPECT_EQ(x2, x); - EXPECT_EQ(v2, v); + EXPECT_EQ(f, f2); + EXPECT_EQ(t, t2); + EXPECT_EQ(s, s2); + EXPECT_EQ(z, z2); + EXPECT_EQ(x, x2); + EXPECT_EQ(v, v2); + EXPECT_EQ(l, l2); + EXPECT_EQ(hi, hi2); - TypeParam f3, t3, s3, z3, x3, v3; + TypeParam f3, t3, s3, z3, x3, v3, l3, hi3; f3 = f; t3 = t; s3 = s; z3 = z; x3 = x; v3 = v; + l3 = l; + hi3 = hi; - EXPECT_EQ(f3, f); - EXPECT_EQ(t3, t); - EXPECT_EQ(s3, s); - EXPECT_EQ(z3, z); - EXPECT_EQ(x3, x); - EXPECT_EQ(v3, v); + EXPECT_EQ(f, f3); + EXPECT_EQ(t, t3); + EXPECT_EQ(s, s3); + EXPECT_EQ(z, z3); + EXPECT_EQ(x, x3); + EXPECT_EQ(v, v3); + EXPECT_EQ(l, l3); + EXPECT_EQ(hi, hi3); } REGISTER_TYPED_TEST_CASE_P(StringTest, - basic, iterators, xslice, oslice, convert); + basic, order, iterators, xslice, oslice, convert); typedef ::testing::Types< FString, TString, SString, ZString, XString, VString<255> diff --git a/src/common/timer.cpp b/src/common/timer.cpp index ec1f6b2..c00f06d 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -184,10 +184,10 @@ interval_t do_timer(tick_t tick) return std::max(nextmin, std::chrono::milliseconds(10)); } -tick_t file_modified(const char *name) +tick_t file_modified(ZString name) { struct stat buf; - if (stat(name, &buf)) + if (stat(name.c_str(), &buf)) return tick_t(); return tick_t(std::chrono::seconds(buf.st_mtime)); } diff --git a/src/common/timer.hpp b/src/common/timer.hpp index c581377..b9c9588 100644 --- a/src/common/timer.hpp +++ b/src/common/timer.hpp @@ -5,6 +5,8 @@ # include "sanity.hpp" +# include "strings.hpp" + // updated automatically when using milli_clock::now() // which is done only by core.cpp extern tick_t gettick_cache; @@ -20,6 +22,6 @@ tick_t gettick(void) interval_t do_timer(tick_t tick); /// Stat a file, and return its modification time, truncated to seconds. -tick_t file_modified(const char *name); +tick_t file_modified(ZString name); #endif // TIMER_HPP diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 4e00808..c9c22b9 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -5,120 +5,97 @@ #include <algorithm> -#include "../poison.hpp" - -//----------------------------------------------------- -// Function to suppress control characters in a string. -//----------------------------------------------------- -int remove_control_chars(char *str) -{ - int i; - int change = 0; - - for (i = 0; str[i]; i++) - { - if (0 <= str[i] && str[i] < 32) - { - str[i] = '_'; - change = 1; - } - } +#include "cxxstdio.hpp" +#include "extract.hpp" - return change; -} +#include "../poison.hpp" //--------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //--------------------------------------------------- -int e_mail_check(const char *email) +bool e_mail_check(XString email) { - char ch; - const char *last_arobas; - // athena limits - if (strlen(email) < 3 || strlen(email) > 39) + if (email.size() < 3 || email.size() > 39) return 0; // part of RFC limits (official reference of e-mail description) - if (strchr(email, '@') == NULL || email[strlen(email) - 1] == '@') + XString::iterator at = std::find(email.begin(), email.end(), '@'); + if (at == email.end()) return 0; - - if (email[strlen(email) - 1] == '.') + XString username = email.xislice_h(at); + XString hostname = email.xislice_t(at + 1); + if (!username || !hostname) return 0; - - last_arobas = strrchr(email, '@'); - - if (strstr(last_arobas, "@.") != NULL || - strstr(last_arobas, "..") != NULL) + if (hostname.contains('@')) return 0; - - for (ch = 1; ch < 32; ch++) - { - if (strchr(last_arobas, ch) != NULL) - { - return 0; - } - } - - if (strchr(last_arobas, ' ') != NULL || - strchr(last_arobas, ';') != NULL) + if (hostname.front() == '.' || hostname.back() == '.') return 0; - - // all correct - return 1; + if (hostname.contains_seq("..")) + return 0; + if (email.contains_any(" ;")) + return 0; + return email.is_print(); } //------------------------------------------------- // Return numerical value of a switch configuration // on/off, english, français, deutsch, español //------------------------------------------------- -int config_switch (const char *str) +int config_switch (ZString str) { - if (strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0 - || strcasecmp(str, "oui") == 0 || strcasecmp(str, "ja") == 0 - || strcasecmp(str, "si") == 0) + if (str == "on" || str == "yes" + || str == "oui" || str == "ja" + || str == "si") return 1; - if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0 - || strcasecmp(str, "non") == 0 || strcasecmp(str, "nein") == 0) + if (str == "off" || str == "no" + || str == "non" || str == "nein") return 0; - return atoi(str); + int rv; + if (extract(str, &rv)) + return rv; + FPRINTF(stderr, "Fatal: bad option value %s", str); + abort(); } -const char *ip2str(struct in_addr ip, bool extra_dot) +IP_String ip2str(struct in_addr ip) +{ + const uint8_t *p = reinterpret_cast<const uint8_t *>(&ip); + + IP_String out; + SNPRINTF(out, 16, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + return out; +} +VString<16> ip2str_extradot(struct in_addr ip) { const uint8_t *p = reinterpret_cast<const uint8_t *>(&ip); - static char buf[17]; - if (extra_dot) - sprintf(buf, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); - else - sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - return buf; + VString<16> out; + SNPRINTF(out, 17, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); + return out; } -bool split_key_value(const std::string& line, std::string *w1, std::string *w2) +bool split_key_value(const FString& line, SString *w1, TString *w2) { - std::string::const_iterator begin = line.begin(), end = line.end(); + FString::iterator begin = line.begin(), end = line.end(); - if (line[0] == '/' && line[1] == '/') + if (line.startswith("//")) return false; - if (line.back() == '\r') - --end; - if (line.empty()) + if (begin == end) return false; if (std::find_if(begin, end, [](unsigned char c) { return c < ' '; } ) != line.end()) return false; - std::string::const_iterator colon = std::find(begin, end, ':'); + FString::iterator colon = std::find(begin, end, ':'); if (colon == end) return false; - w1->assign(begin, colon); + *w1 = line.oislice(begin, colon); ++colon; while (std::isspace(*colon)) ++colon; - w2->assign(colon, end); + *w2 = line.oislice(colon, end); return true; } @@ -128,18 +105,22 @@ static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); void stamp_time(timestamp_seconds_buffer& out, const TimeT *t) { struct tm when = t ? *t : TimeT::now(); - strftime(out, 20, "%Y-%m-%d %H:%M:%S", &when); + char buf[20]; + strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); + out = stringish<timestamp_seconds_buffer>(const_(buf)); } void stamp_time(timestamp_milliseconds_buffer& out) { struct timeval tv; gettimeofday(&tv, NULL); struct tm when = TimeT(tv.tv_sec); - strftime(out, 20, "%Y-%m-%d %H:%M:%S", &when); - sprintf(out + 19, ".%03d", int(tv.tv_usec / 1000)); + char buf[24]; + strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); + sprintf(buf + 19, ".%03d", static_cast<int>(tv.tv_usec / 1000)); + out = stringish<timestamp_milliseconds_buffer>(const_(buf)); } -void log_with_timestamp(FILE *out, const_string line) +void log_with_timestamp(FILE *out, XString line) { if (!line) { @@ -148,7 +129,7 @@ void log_with_timestamp(FILE *out, const_string line) } timestamp_milliseconds_buffer tmpstr; stamp_time(tmpstr); - fwrite(tmpstr, 1, sizeof(tmpstr), out); + fputs(tmpstr.c_str(), out); fputs(": ", out); fwrite(line.data(), 1, line.size(), out); if (line.back() != '\n') diff --git a/src/common/utils.hpp b/src/common/utils.hpp index ab32948..196bb3e 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -6,13 +6,15 @@ #include <cstdio> #include <cstring> -#include <string> #include <type_traits> #include "const_array.hpp" #include "operators.hpp" +#include "strings.hpp" #include "utils2.hpp" +struct IP_String : VString<15> {}; + template<class T> struct is_trivially_copyable : std::integral_constant<bool, @@ -22,23 +24,12 @@ struct is_trivially_copyable && __has_trivial_destructor(T)> {}; -int remove_control_chars(char *str); -int e_mail_check(const char *email); -int config_switch (const char *str); -const char *ip2str(struct in_addr ip, bool extra_dot = false); +bool e_mail_check(XString email); +int config_switch (ZString str); +IP_String ip2str(struct in_addr ip); +VString<15 + 1> ip2str_extradot(struct in_addr ip); -bool split_key_value(const std::string& line, std::string *w1, std::string *w2); - -inline -void strzcpy(char *dest, const char *src, size_t n) -{ - if (n) - { - // hmph - strncpy(dest, src, n - 1); - dest[n - 1] = '\0'; - } -} +bool split_key_value(const FString& line, SString *w1, TString *w2); inline void really_memcpy(uint8_t *dest, const uint8_t *src, size_t n) @@ -123,13 +114,14 @@ long long& convert_for_scanf(TimeT& t) return t.value; } -typedef char timestamp_seconds_buffer[20]; -typedef char timestamp_milliseconds_buffer[24]; +struct timestamp_seconds_buffer : VString<19> {}; +struct timestamp_milliseconds_buffer : VString<23> {}; void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr); void stamp_time(timestamp_milliseconds_buffer&); -void log_with_timestamp(FILE *out, const_string line); +void log_with_timestamp(FILE *out, XString line); +// TODO VString? #define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS" static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), "timestamp size"); @@ -138,6 +130,7 @@ static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), // sizeof: 01234567890123456789012345678 // str + sizeof: ^ // -1: ^ +// there's probably a better way to do this now #define REPLACE_TIMESTAMP(str, t) \ stamp_time( \ reinterpret_cast<timestamp_seconds_buffer *>( \ @@ -146,10 +139,4 @@ 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 d7d6f8a..119cc13 100644 --- a/src/common/utils2.hpp +++ b/src/common/utils2.hpp @@ -248,4 +248,33 @@ typename std::enable_if<is_array_of_unknown_bound<T>::value, std::unique_ptr<T, return std::unique_ptr<E[], D>(new E[sz]()); } +template<class T> +const T& const_(T& t) +{ + return t; +} + +template<class T, class U> +T no_cast(U&& u) +{ + typedef typename std::remove_reference<T>::type Ti; + typedef typename std::remove_reference<U>::type Ui; + typedef typename std::remove_cv<Ti>::type Tb; + typedef typename std::remove_cv<Ui>::type Ub; + static_assert(std::is_same<Tb, Ub>::value, "not no cast"); + return std::forward<U>(u); +} + +template<class T, class U> +T base_cast(U&& u) +{ + static_assert(std::is_reference<T>::value, "must base cast with references"); + typedef typename std::remove_reference<T>::type Ti; + typedef typename std::remove_reference<U>::type Ui; + typedef typename std::remove_cv<Ti>::type Tb; + typedef typename std::remove_cv<Ui>::type Ub; + static_assert(std::is_base_of<Tb, Ub>::value, "not base cast"); + return std::forward<U>(u); +} + #endif // UTILS2_HPP diff --git a/src/ladmin/ladmin.cpp b/src/ladmin/ladmin.cpp index 5f3ef7b..2581456 100644 --- a/src/ladmin/ladmin.cpp +++ b/src/ladmin/ladmin.cpp @@ -6,13 +6,17 @@ #include <cassert> #include <fstream> +#include <iostream> -#include "../common/cxxstdio.hpp" #include "../common/core.hpp" +#include "../common/cxxstdio.hpp" +#include "../common/human_time_diff.hpp" +#include "../common/io.hpp" #include "../common/md5calc.hpp" +#include "../common/mmo.hpp" #include "../common/socket.hpp" -#include "../common/version.hpp" #include "../common/utils.hpp" +#include "../common/version.hpp" #include "../poison.hpp" @@ -32,15 +36,13 @@ int eathena_interactive_session; // (see login_athena.conf, 'admin_state' parameter) //------------------------------------------------------------------------- static -char loginserverip[16] = "127.0.0.1"; // IP of login-server +IP_String loginserverip = stringish<IP_String>("127.0.0.1"); // IP of login-server static int loginserverport = 6900; // Port of login-server static -char loginserveradminpassword[24] = "admin"; // Administration password +AccountPass loginserveradminpassword = stringish<AccountPass>("admin"); // Administration password static -int passenc = 2; // Encoding type of the password -static -char ladmin_log_filename[1024] = "log/ladmin.log"; +FString ladmin_log_filename = "log/ladmin.log"; //------------------------------------------------------------------------- // LIST of COMMANDs that you can type at the prompt: // To use these commands you can only type only the first letters. @@ -228,7 +230,7 @@ int login_ip; static int bytes_to_read = 0; // flag to know if we waiting bytes from login-server static -char parameters[1024]; // needs to be global since it's passed to the parse function +TString parameters; // needs to be global since it's passed to the parse function // really should be added to session data static int list_first, list_last, list_type, list_count; // parameter to display a list of accounts @@ -247,311 +249,84 @@ void SessionDeleter::operator()(SessionData *) // Writing function of logs file //------------------------------ #define LADMIN_LOG(fmt, ...) \ - ladmin_log(static_cast<const std::string&>(STRPRINTF(fmt, ## __VA_ARGS__))) + ladmin_log(STRPRINTF(fmt, ## __VA_ARGS__)) static -void ladmin_log(const_string line) +void ladmin_log(XString line) { - FILE *logfp = fopen_(ladmin_log_filename, "a"); + FILE *logfp = fopen(ladmin_log_filename.c_str(), "a"); if (!logfp) return; log_with_timestamp(logfp, line); - fclose_(logfp); -} - -//--------------------------------------------- -// Function to return ordonal text of a number. -//--------------------------------------------- -static -const char *makeordinal(int number) -{ - if ((number % 10) < 4 && (number % 10) != 0 - && (number < 10 || number > 20)) - { - if ((number % 10) == 1) - return "st"; - else if ((number % 10) == 2) - return "nd"; - else - return "rd"; - } - else - { - return "th"; - } -} - -//----------------------------------------------------------------------------------------- -// Function to test of the validity of an account name (return 0 if incorrect, and 1 if ok) -//----------------------------------------------------------------------------------------- -static -int verify_accountname(const char *account_name) -{ - int i; - - for (i = 0; account_name[i]; i++) - { - if (account_name[i] < 32) - { - PRINTF("Illegal character found in the account name (%d%s character).\n", - i + 1, makeordinal(i + 1)); - LADMIN_LOG("Illegal character found in the account name (%d%s character).\n", - i + 1, makeordinal(i + 1)); - return 0; - } - } - - if (strlen(account_name) < 4) - { - PRINTF("Account name is too short. Please input an account name of 4-23 bytes.\n"); - LADMIN_LOG("Account name is too short. Please input an account name of 4-23 bytes.\n"); - return 0; - } - - if (strlen(account_name) > 23) - { - PRINTF("Account name is too long. Please input an account name of 4-23 bytes.\n"); - LADMIN_LOG("Account name is too long. Please input an account name of 4-23 bytes.\n"); - return 0; - } - - return 1; + fclose(logfp); } -//---------------------------------- -// Sub-function: Input of a password -//---------------------------------- static -int typepasswd(char *password) +bool qsplit(ZString src) { - char password1[1023] {}; - char password2[1023] {}; - int letter; - int i; - - LADMIN_LOG("No password was given. Request to obtain a password.\n"); - - PRINTF("\033[1;36m Type the password > \033[0;32;42m"); - i = 0; - while ((letter = getchar()) != '\n') - password1[i++] = letter; - PRINTF("\033[0m\033[1;36m Verify the password > \033[0;32;42m"); - i = 0; - while ((letter = getchar()) != '\n') - password2[i++] = letter; - - PRINTF("\033[0m"); - fflush(stdout); - fflush(stdin); - - if (strcmp(password1, password2) != 0) - { - PRINTF("Password verification failed. Please input same password.\n"); - LADMIN_LOG("Password verification failed. Please input same password.\n"); - LADMIN_LOG(" First password: %s, second password: %s.\n", - password1, password2); - return 0; - } - LADMIN_LOG("Typed password: %s.\n", password1); - strcpy(password, password1); - return 1; + return !src; } -//------------------------------------------------------------------------------------ -// Sub-function: Test of the validity of password (return 0 if incorrect, and 1 if ok) -//------------------------------------------------------------------------------------ +template<class F, class... R> static -int verify_password(const char *password) +bool qsplit(ZString src, F first, R... rest) { - int i; - - for (i = 0; password[i]; i++) - { - if (password[i] < 32) - { - PRINTF("Illegal character found in the password (%d%s character).\n", - i + 1, makeordinal(i + 1)); - LADMIN_LOG("Illegal character found in the password (%d%s character).\n", - i + 1, makeordinal(i + 1)); - return 0; - } + if (!src) + return false; + XString one; + if (src.startswith('\'')) + { + src = src.xslice_t(1); + auto it = std::find(src.begin(), src.end(), '\''); + if (it == src.end()) + return false; + one = src.xislice_h(it); + src = src.xislice_t(it + 1); + while (src.startswith(' ')) + src = src.xslice_t(1); + } + else if (src.startswith('"')) + { + src = src.xslice_t(1); + auto it = std::find(src.begin(), src.end(), '"'); + if (it == src.end()) + return false; + one = src.xislice_h(it); + src = src.xislice_t(it + 1); + while (src.startswith(' ')) + src = src.xslice_t(1); } - - if (strlen(password) < 4) - { - PRINTF("Account name is too short. Please input an account name of 4-23 bytes.\n"); - LADMIN_LOG("Account name is too short. Please input an account name of 4-23 bytes.\n"); - return 0; - } - - if (strlen(password) > 23) + else { - PRINTF("Password is too long. Please input a password of 4-23 bytes.\n"); - LADMIN_LOG("Password is too long. Please input a password of 4-23 bytes.\n"); - return 0; + auto it = std::find(src.begin(), src.end(), ' '); + one = src.xislice_h(it); + src = src.xislice_t(it); + while (src.startswith(' ')) + src = src.xslice_t(1); } - - return 1; -} - -//------------------------------------------------------------------ -// Sub-function: Check the name of a command (return complete name) -//----------------------------------------------------------------- -static -int check_command(char *command) -{ -// help - if (strncmp(command, "help", 1) == 0 - && strncmp(command, "help", strlen(command)) == 0) - strcpy(command, "help"); -// general commands - else if (strncmp(command, "add", 2) == 0 && strncmp(command, "add", strlen(command)) == 0) - strcpy(command, "add"); - else if ((strncmp(command, "ban", 3) == 0 - && strncmp(command, "ban", strlen(command)) == 0) - ||(strncmp(command, "banish", 4) == 0 - && strncmp(command, "banish", strlen(command)) == 0)) - strcpy(command, "ban"); - else if ((strncmp(command, "banadd", 4) == 0 && strncmp(command, "banadd", strlen(command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? - strcmp(command, "ba") == 0) - strcpy(command, "banadd"); - else if ((strncmp(command, "banset", 4) == 0 && strncmp(command, "banset", strlen(command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? - strcmp(command, "bs") == 0) - strcpy(command, "banset"); - else if (strncmp(command, "block", 2) == 0 - && strncmp(command, "block", strlen(command)) == 0) - strcpy(command, "block"); - else if (strncmp(command, "check", 2) == 0 && strncmp(command, "check", strlen(command)) == 0) // not 1 letter command: 'check' or 'create'? - strcpy(command, "check"); - else if (strncmp(command, "create", 2) == 0 && strncmp(command, "create", strlen(command)) == 0) // not 1 letter command: 'check' or 'create'? - strcpy(command, "create"); - else if (strncmp(command, "delete", 1) == 0 - && strncmp(command, "delete", strlen(command)) == 0) - strcpy(command, "delete"); - else if ((strncmp(command, "email", 2) == 0 && strncmp(command, "email", strlen(command)) == 0) || // not 1 letter command: 'email', 'end' or 'exit'? - (strncmp(command, "e-mail", 2) == 0 - && strncmp(command, "e-mail", strlen(command)) == 0)) - strcpy(command, "email"); - else if (strncmp(command, "getcount", 2) == 0 && strncmp(command, "getcount", strlen(command)) == 0) // not 1 letter command: 'getcount' or 'gm'? - strcpy(command, "getcount"); -// else if (strncmp(command, "gm", 2) == 0 && strncmp(command, "gm", strlen(command)) == 0) // not 1 letter command: 'getcount' or 'gm'? -// strcpy(command, "gm"); -// else if (strncmp(command, "id", 2) == 0 && strncmp(command, "id", strlen(command)) == 0) // not 1 letter command: 'id' or 'info'? -// strcpy(command, "id"); - else if (strncmp(command, "info", 2) == 0 && strncmp(command, "info", strlen(command)) == 0) // not 1 letter command: 'id' or 'info'? - strcpy(command, "info"); -// else if (strncmp(command, "kami", 4) == 0 && strncmp(command, "kami", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? -// strcpy(command, "kami"); -// else if (strncmp(command, "kamib", 5) == 0 && strncmp(command, "kamib", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? -// strcpy(command, "kamib"); - else if ((strncmp(command, "list", 2) == 0 && strncmp(command, "list", strlen(command)) == 0) || // 'list' is default list command - strcmp(command, "ls") == 0) - strcpy(command, "list"); - else if (strncmp(command, "itemfrob", 6) == 0) - strcpy(command, "itemfrob"); - else if ((strncmp(command, "listban", 5) == 0 - && strncmp(command, "listban", strlen(command)) == 0) - ||(strncmp(command, "lsban", 3) == 0 - && strncmp(command, "lsban", strlen(command)) == 0) - || strcmp(command, "lb") == 0) - strcpy(command, "listban"); - else if ((strncmp(command, "listgm", 5) == 0 - && strncmp(command, "listgm", strlen(command)) == 0) - ||(strncmp(command, "lsgm", 3) == 0 - && strncmp(command, "lsgm", strlen(command)) == 0) - || strcmp(command, "lg") == 0) - strcpy(command, "listgm"); - else if ((strncmp(command, "listok", 5) == 0 - && strncmp(command, "listok", strlen(command)) == 0) - ||(strncmp(command, "lsok", 3) == 0 - && strncmp(command, "lsok", strlen(command)) == 0) - || strcmp(command, "lo") == 0) - strcpy(command, "listok"); - else if (strncmp(command, "memo", 1) == 0 - && strncmp(command, "memo", strlen(command)) == 0) - strcpy(command, "memo"); - else if (strncmp(command, "name", 1) == 0 - && strncmp(command, "name", strlen(command)) == 0) - strcpy(command, "name"); - else if ((strncmp(command, "password", 1) == 0 - && strncmp(command, "password", strlen(command)) == 0) - || strcmp(command, "passwd") == 0) - strcpy(command, "password"); - else if (strncmp(command, "reloadgm", 1) == 0 - && strncmp(command, "reloadgm", strlen(command)) == 0) - strcpy(command, "reloadgm"); - else if (strncmp(command, "search", 3) == 0 && strncmp(command, "search", strlen(command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? - strcpy(command, "search"); // not 2 letters command: 'search' or 'sex'? -// else if (strncmp(command, "sex", 3) == 0 && strncmp(command, "sex", strlen(command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? -// strcpy(command, "sex"); // not 2 letters command: 'search' or 'sex'? - else if (strncmp(command, "state", 2) == 0 && strncmp(command, "state", strlen(command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? - strcpy(command, "state"); - else if ((strncmp(command, "timeadd", 5) == 0 && strncmp(command, "timeadd", strlen(command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? - strcmp(command, "ta") == 0) - strcpy(command, "timeadd"); - else if ((strncmp(command, "timeset", 5) == 0 && strncmp(command, "timeset", strlen(command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? - strcmp(command, "ts") == 0) - strcpy(command, "timeset"); - else if ((strncmp(command, "unban", 5) == 0 - && strncmp(command, "unban", strlen(command)) == 0) - ||(strncmp(command, "unbanish", 4) == 0 - && strncmp(command, "unbanish", strlen(command)) == 0)) - strcpy(command, "unban"); - else if (strncmp(command, "unblock", 4) == 0 - && strncmp(command, "unblock", strlen(command)) == 0) - strcpy(command, "unblock"); - else if (strncmp(command, "version", 1) == 0 - && strncmp(command, "version", strlen(command)) == 0) - strcpy(command, "version"); - else if (strncmp(command, "who", 1) == 0 - && strncmp(command, "who", strlen(command)) == 0) - strcpy(command, "who"); -// quit - else if (strncmp(command, "quit", 1) == 0 - && strncmp(command, "quit", strlen(command)) == 0) - strcpy(command, "quit"); - else if (strncmp(command, "exit", 2) == 0 && strncmp(command, "exit", strlen(command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? - strcpy(command, "exit"); - else if (strncmp(command, "end", 2) == 0 && strncmp(command, "end", strlen(command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? - strcpy(command, "end"); - - return 0; + return extract(one, first) && qsplit(src, rest...); } //----------------------------------------- // Sub-function: Display commands of ladmin //----------------------------------------- static -void display_help(const char *param) +void display_help(ZString param) { - char command[1023] {}; - int i; - - if (sscanf(param, "%s ", command) < 1 || strlen(command) == 0) - strcpy(command, ""); // any value that is not a command - - if (command[0] == '?') - { - strcpy(command, "help"); - } + XString command = param.xislice_h(std::find(param.begin(), param.end(), ' ')); - // lowercase for command - for (i = 0; command[i]; i++) - command[i] = tolower(command[i]); - - // Analyse of the command - check_command(command); // give complete name to the command + if (command.startswith('?')) + command = "help"; LADMIN_LOG("Displaying of the commands or a command.\n"); - if (strcmp(command, "help") == 0) + if (command == "help") { PRINTF("help/?\n"); PRINTF(" Display the description of the commands\n"); PRINTF("help/? [command]\n"); PRINTF(" Display the description of the specified command\n"); -// general commands } - else if (strcmp(command, "add") == 0) + else if (command == "add") { PRINTF("add <account_name> <sex> <password>\n"); PRINTF(" Create an account with the default email (a@a.com).\n"); @@ -561,13 +336,13 @@ void display_help(const char *param) PRINTF(" the input is done without displaying of the pressed keys.\n"); PRINTF(" <example> add testname Male testpass\n"); } - else if (strcmp(command, "ban") == 0) + else if (command == "ban") { PRINTF("ban/banish yyyy/mm/dd hh:mm:ss <account name>\n"); PRINTF(" Changes the final date of a banishment of an account.\n"); PRINTF(" Like banset, but <account name> is at end.\n"); } - else if (strcmp(command, "banadd") == 0) + else if (command == "banadd") { PRINTF("banadd <account_name> <modifier>\n"); PRINTF(" Adds or substracts time from the final date of a banishment of an account.\n"); @@ -586,7 +361,7 @@ void display_help(const char *param) PRINTF("NOTE: If you modify the final date of a non-banished account,\n"); PRINTF(" you fix the final date to (actual time +- adjustments)\n"); } - else if (strcmp(command, "banset") == 0) + else if (command == "banset") { PRINTF("banset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); PRINTF(" Changes the final date of a banishment of an account.\n"); @@ -594,13 +369,13 @@ void display_help(const char *param) PRINTF("banset <account_name> 0\n"); PRINTF(" Set a non-banished account (0 = unbanished).\n"); } - else if (strcmp(command, "block") == 0) + else if (command == "block") { PRINTF("block <account name>\n"); PRINTF(" Set state 5 (You have been blocked by the GM Team) to an account.\n"); PRINTF(" This command works like state <account_name> 5.\n"); } - else if (strcmp(command, "check") == 0) + else if (command == "check") { PRINTF("check <account_name> <password>\n"); PRINTF(" Check the validity of a password for an account.\n"); @@ -608,56 +383,56 @@ void display_help(const char *param) PRINTF(" It's the only method you have to know if a password is correct.\n"); PRINTF(" The other method is to have a ('physical') access to the accounts file.\n"); } - else if (strcmp(command, "create") == 0) + else if (command == "create") { PRINTF("create <account_name> <sex> <email> <password>\n"); PRINTF(" Like the 'add' command, but with e-mail moreover.\n"); PRINTF(" <example> create testname Male my@mail.com testpass\n"); } - else if (strcmp(command, "delete") == 0) + else if (command == "delete") { PRINTF("del <account name>\n"); PRINTF(" Remove an account.\n"); PRINTF(" This order requires confirmation. After confirmation, the account is deleted.\n"); } - else if (strcmp(command, "email") == 0) + else if (command == "email") { PRINTF("email <account_name> <email>\n"); PRINTF(" Modify the e-mail of an account.\n"); } - else if (strcmp(command, "getcount") == 0) + else if (command == "getcount") { PRINTF("getcount\n"); PRINTF(" Give the number of players online on all char-servers.\n"); } - else if (strcmp(command, "gm") == 0) + else if (command == "gm") { PRINTF("gm <account_name> [GM_level]\n"); PRINTF(" Modify the GM level of an account.\n"); PRINTF(" Default value remove GM level (GM level = 0).\n"); PRINTF(" <example> gm testname 80\n"); } - else if (strcmp(command, "id") == 0) + else if (command == "id") { PRINTF("id <account name>\n"); PRINTF(" Give the id of an account.\n"); } - else if (strcmp(command, "info") == 0) + else if (command == "info") { PRINTF("info <account_id>\n"); PRINTF(" Display complete information of an account.\n"); } - else if (strcmp(command, "kami") == 0) + else if (command == "kami") { PRINTF("kami <message>\n"); PRINTF(" Sends a broadcast message on all map-server (in yellow).\n"); } - else if (strcmp(command, "kamib") == 0) + else if (command == "kamib") { PRINTF("kamib <message>\n"); PRINTF(" Sends a broadcast message on all map-server (in blue).\n"); } - else if (strcmp(command, "list") == 0) + else if (command == "list") { PRINTF("list/ls [start_id [end_id]]\n"); PRINTF(" Display a list of accounts.\n"); @@ -665,67 +440,64 @@ void display_help(const char *param) PRINTF(" Research by name is not possible with this command.\n"); PRINTF(" <example> list 10 9999999\n"); } - else if (strcmp(command, "itemfrob") == 0) + else if (command == "itemfrob") { PRINTF("itemfrob <source-id> <dest-id>\n"); PRINTF(" Translates item IDs for all accounts.\n"); PRINTF(" Any items matching the source item ID will be mapped to the dest-id.\n"); PRINTF(" <example> itemfrob 500 700\n"); } - else if (strcmp(command, "listban") == 0) + else if (command == "listban") { PRINTF("listBan/lsBan [start_id [end_id]]\n"); PRINTF(" Like list/ls, but only for accounts with state or banished.\n"); } - else if (strcmp(command, "listgm") == 0) + else if (command == "listgm") { PRINTF("listGM/lsGM [start_id [end_id]]\n"); PRINTF(" Like list/ls, but only for GM accounts.\n"); } - else if (strcmp(command, "listok") == 0) + else if (command == "listok") { PRINTF("listOK/lsOK [start_id [end_id]]\n"); PRINTF(" Like list/ls, but only for accounts without state and not banished.\n"); } - else if (strcmp(command, "memo") == 0) + else if (command == "memo") { PRINTF("memo <account_name> <memo>\n"); PRINTF(" Modify the memo of an account.\n"); PRINTF(" 'memo': it can have until 253 characters (with spaces or not).\n"); } - else if (strcmp(command, "name") == 0) + else if (command == "name") { PRINTF("name <account_id>\n"); PRINTF(" Give the name of an account.\n"); } - else if (strcmp(command, "password") == 0) + else if (command == "password") { PRINTF("passwd <account_name> <new_password>\n"); PRINTF(" Change the password of an account.\n"); PRINTF(" When new password is omitted,\n"); PRINTF(" the input is done without displaying of the pressed keys.\n"); } - else if (strcmp(command, "reloadgm") == 0) + else if (command == "reloadgm") { PRINTF("reloadGM\n"); PRINTF(" Reload GM configuration file\n"); } - else if (strcmp(command, "search") == 0) + else if (command == "search") { PRINTF("search <expression>\n"); PRINTF(" Seek accounts.\n"); PRINTF(" Displays the accounts whose names correspond.\n"); -// PRINTF("search -r/-e/--expr/--regex <expression>\n"); -// PRINTF(" Seek accounts by regular expression.\n"); -// PRINTF(" Displays the accounts whose names correspond.\n"); } - else if (strcmp(command, "sex") == 0) + else if (command == "sex") { PRINTF("sex <account_name> <sex>\n"); PRINTF(" Modify the sex of an account.\n"); PRINTF(" <example> sex testname Male\n"); } - else if (strcmp(command, "state") == 0) + else if (command == "state") { PRINTF("state <account_name> <new_state> <error_message_#7>\n"); PRINTF(" Change the state of an account.\n"); @@ -746,7 +518,7 @@ void display_help(const char *param) PRINTF(" 'error_message_#7': message of the code error 6\n"); PRINTF(" = Your are Prohibited to log in until... (packet 0x006a)\n"); } - else if (strcmp(command, "timeadd") == 0) + else if (command == "timeadd") { PRINTF("timeadd <account_name> <modifier>\n"); PRINTF(" Adds or substracts time from the validity limit of an account.\n"); @@ -766,7 +538,7 @@ void display_help(const char *param) PRINTF(" If you want modify it, you want probably create a limited validity limit.\n"); PRINTF(" So, at first, you must set the validity limit to a date/time.\n"); } - else if (strcmp(command, "timeadd") == 0) + else if (command == "timeadd") { PRINTF("timeset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); PRINTF(" Changes the validity limit of an account.\n"); @@ -774,42 +546,40 @@ void display_help(const char *param) PRINTF("timeset <account_name> 0\n"); PRINTF(" Gives an unlimited validity limit (0 = unlimited).\n"); } - else if (strcmp(command, "unban") == 0) + else if (command == "unban") { PRINTF("unban/unbanish <account name>\n"); PRINTF(" Remove the banishment of an account.\n"); PRINTF(" This command works like banset <account_name> 0.\n"); } - else if (strcmp(command, "unblock") == 0) + else if (command == "unblock") { PRINTF("unblock <account name>\n"); PRINTF(" Set state 0 (Account ok) to an account.\n"); PRINTF(" This command works like state <account_name> 0.\n"); } - else if (strcmp(command, "version") == 0) + else if (command == "version") { PRINTF("version\n"); PRINTF(" Display the version of the login-server.\n"); } - else if (strcmp(command, "who") == 0) + else if (command == "who") { PRINTF("who <account name>\n"); PRINTF(" Displays complete information of an account.\n"); -// quit } - else if (strcmp(command, "quit") == 0 || - strcmp(command, "exit") == 0 || - strcmp(command, "end") == 0) + else if (command == "quit" + || command == "exit" + || command == "end") { PRINTF("quit/end/exit\n"); PRINTF(" End of the program of administration.\n"); -// unknown command } else { - if (strlen(command) > 0) + if (command) PRINTF("Unknown command [%s] for help. Displaying of all commands.\n", - command); + FString(command)); PRINTF(" help/? -- Display this help\n"); PRINTF(" help/? [command] -- Display the help of the command\n"); PRINTF(" add <account_name> <sex> <password> -- Create an account with default email\n"); @@ -842,7 +612,6 @@ void display_help(const char *param) PRINTF(" quit/end/exit -- End of the program of administation\n"); PRINTF(" reloadGM -- Reload GM configuration file\n"); PRINTF(" search <expression> -- Seek accounts\n"); -// PRINTF(" search -e/-r/--expr/--regex <expressn> -- Seek accounts by regular-expression\n"); PRINTF(" sex <nomcompte> <sexe> -- Modify the sex of an account\n"); PRINTF(" state <account_name> <new_state> <error_message_#7> -- Change the state\n"); PRINTF(" timeadd/ta <account_name> <modifier> -- Add or substract time from the\n"); @@ -862,195 +631,93 @@ void display_help(const char *param) // Sub-function: add an account //----------------------------- static -int addaccount(const char *param, int emailflag) +void addaccount(ZString param, int emailflag) { - char name[1023] {}; - char sex[1023] {}; - char email[1023] {}; - char password[1023] {}; + AccountName name; + VString<1> sex_; + XString email_; + AccountPass password; if (emailflag == 0) - { // add command - if (sscanf(param, "\"%[^\"]\" %s %[^\r\n]", name, sex, password) < 2 && // password can be void - sscanf(param, "'%[^']' %s %[^\r\n]", name, sex, password) < 2 && // password can be void - sscanf(param, "%s %s %[^\r\n]", name, sex, password) < 2) - { // password can be void + { + // add command + if (!qsplit(param, &name, &sex_, &password)) + { PRINTF("Please input an account name, a sex and a password.\n"); PRINTF("<example> add testname Male testpass\n"); LADMIN_LOG("Incomplete parameters to create an account ('add' command).\n"); - return 136; + return; } - strcpy(email, "a@a.com"); // default email + email_ = DEFAULT_EMAIL; } else - { // 1: create command - if (sscanf(param, "\"%[^\"]\" %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void - sscanf(param, "'%[^']' %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void - sscanf(param, "%s %s %s %[^\r\n]", name, sex, email, - password) < 3) - { // password can be void + { + // 1: create command + if (!qsplit(param, &name, &sex_, &email_, &password)) + { PRINTF("Please input an account name, a sex and a password.\n"); PRINTF("<example> create testname Male my@mail.com testpass\n"); LADMIN_LOG("Incomplete parameters to create an account ('create' command).\n"); - return 136; + return; } } - if (verify_accountname(name) == 0) - { - return 102; - } + char sex = sex_.front(); + if (!name.is_print()) + return; - sex[0] = toupper(sex[0]); - if (strchr("MF", sex[0]) == NULL) + if (XString("MF").contains(sex)) { - PRINTF("Illegal gender [%s]. Please input M or F.\n", sex); - LADMIN_LOG("Illegal gender [%s]. Please input M or F.\n", - sex); - return 103; + PRINTF("Illegal gender [%c]. Please input M or F.\n", sex); + LADMIN_LOG("Illegal gender [%c]. Please input M or F.\n", sex); + return; } - if (strlen(email) < 3) - { - PRINTF("Email is too short [%s]. Please input a valid e-mail.\n", - email); - LADMIN_LOG("Email is too short [%s]. Please input a valid e-mail.\n", - email); - return 109; - } - if (strlen(email) > 39) - { - PRINTF("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - LADMIN_LOG("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - return 109; - } - if (e_mail_check(email) == 0) + if (!e_mail_check(email_)) { PRINTF("Invalid email [%s]. Please input a valid e-mail.\n", - email); + FString(email_)); LADMIN_LOG("Invalid email [%s]. Please input a valid e-mail.\n", - email); - return 109; + FString(email_)); + return; } + AccountEmail email = stringish<AccountEmail>(email_); - if (strlen(password) == 0) - { - if (typepasswd(password) == 0) - return 108; - } - if (verify_password(password) == 0) - return 104; + if (!password.is_print()) + return; LADMIN_LOG("Request to login-server to create an account.\n"); WFIFOW(login_fd, 0) = 0x7930; WFIFO_STRING(login_fd, 2, name, 24); WFIFO_STRING(login_fd, 26, password, 24); - WFIFOB(login_fd, 50) = sex[0]; + WFIFOB(login_fd, 50) = sex; WFIFO_STRING(login_fd, 51, email, 40); WFIFOSET(login_fd, 91); bytes_to_read = 1; - - return 0; } //--------------------------------------------------------------------------------- // Sub-function: Add/substract time to the final date of a banishment of an account //--------------------------------------------------------------------------------- static -int banaddaccount(const char *param) +void banaddaccount(ZString param) { - char name[1023] {}; - char modif[1023] {}; - int year, month, day, hour, minute, second; - const char *p_modif; - int value, i; - - year = month = day = hour = minute = second = 0; + AccountName name; + HumanTimeDiff modif {}; - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && - sscanf(param, "'%[^']' %[^\r\n]", name, modif) < 2 && - sscanf(param, "%s %[^\r\n]", name, modif) < 2) + if (!qsplit(param, &name, &modif)) { PRINTF("Please input an account name and a modifier.\n"); PRINTF(" <example>: banadd testname +1m-2mn1s-6y\n"); PRINTF(" this example adds 1 month and 1 second, and substracts 2 minutes\n"); PRINTF(" and 6 years at the same time.\n"); LADMIN_LOG("Incomplete parameters to modify the ban date/time of an account ('banadd' command).\n"); - return 136; - } - if (verify_accountname(name) == 0) - { - return 102; - } - - // lowercase for modif - for (i = 0; modif[i]; i++) - modif[i] = tolower(modif[i]); - p_modif = modif; - while (strlen(p_modif) > 0) - { - value = atoi(p_modif); - if (value == 0) - { - p_modif++; - } - else - { - if (p_modif[0] == '-' || p_modif[0] == '+') - p_modif++; - while (strlen(p_modif) > 0 && p_modif[0] >= '0' - && p_modif[0] <= '9') - { - p_modif++; - } - if (p_modif[0] == 's') - { - second = value; - p_modif++; - } - else if (p_modif[0] == 'm' && p_modif[1] == 'n') - { - minute = value; - p_modif += 2; - } - else if (p_modif[0] == 'h') - { - hour = value; - p_modif++; - } - else if (p_modif[0] == 'd' || p_modif[0] == 'j') - { - day = value; - p_modif += 2; - } - else if (p_modif[0] == 'm') - { - month = value; - p_modif++; - } - else if (p_modif[0] == 'y' || p_modif[0] == 'a') - { - year = value; - p_modif++; - } - else - { - p_modif++; - } - } + return; } + if (!name.is_print()) + return; - PRINTF(" year: %d\n", year); - PRINTF(" month: %d\n", month); - PRINTF(" day: %d\n", day); - PRINTF(" hour: %d\n", hour); - PRINTF(" minute: %d\n", minute); - PRINTF(" second: %d\n", second); - - if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 - && second == 0) + if (!modif) { PRINTF("Please give an adjustment with this command:\n"); PRINTF(" Adjustment value (-1, 1, +1, etc...)\n"); @@ -1065,59 +732,16 @@ int banaddaccount(const char *param) PRINTF(" this example adds 1 month and 1 second, and substracts 2 minutes\n"); PRINTF(" and 6 years at the same time.\n"); LADMIN_LOG("No adjustment isn't an adjustment ('banadd' command).\n"); - return 137; - } - if (year > 127 || year < -127) - { - PRINTF("Please give a correct adjustment for the years (from -127 to 127).\n"); - LADMIN_LOG("Abnormal adjustement for the year ('banadd' command).\n"); - return 137; - } - if (month > 255 || month < -255) - { - PRINTF("Please give a correct adjustment for the months (from -255 to 255).\n"); - LADMIN_LOG("Abnormal adjustement for the month ('banadd' command).\n"); - return 137; - } - if (day > 32767 || day < -32767) - { - PRINTF("Please give a correct adjustment for the days (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the days ('banadd' command).\n"); - return 137; - } - if (hour > 32767 || hour < -32767) - { - PRINTF("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the hours ('banadd' command).\n"); - return 137; - } - if (minute > 32767 || minute < -32767) - { - PRINTF("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the minutes ('banadd' command).\n"); - return 137; - } - if (second > 32767 || second < -32767) - { - PRINTF("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the seconds ('banadd' command).\n"); - return 137; + return; } LADMIN_LOG("Request to login-server to modify a ban date/time.\n"); WFIFOW(login_fd, 0) = 0x794c; WFIFO_STRING(login_fd, 2, name, 24); - WFIFOW(login_fd, 26) = year; - WFIFOW(login_fd, 28) = month; - WFIFOW(login_fd, 30) = day; - WFIFOW(login_fd, 32) = hour; - WFIFOW(login_fd, 34) = minute; - WFIFOW(login_fd, 36) = second; + WFIFO_STRUCT(login_fd, 24, modif); WFIFOSET(login_fd, 38); bytes_to_read = 1; - - return 0; } //----------------------------------------------------------------------- @@ -1125,7 +749,7 @@ int banaddaccount(const char *param) // Set the final date of a banishment of an account //----------------------------------------------------------------------- static -int bansetaccountsub(const char *name, const char *date, const char *time_) +void bansetaccountsub(AccountName name, XString date, XString time_) { int year, month, day, hour, minute, second; year = month = day = hour = minute = second = 0; @@ -1134,24 +758,22 @@ int bansetaccountsub(const char *name, const char *date, const char *time_) TimeT ban_until_time = TimeT(); struct tm tmtime = ban_until_time; // initialize - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; - if (atoi(date) != 0 && - ((sscanf(date, "%d/%d/%d", &year, &month, &day) < 3 && - sscanf(date, "%d-%d-%d", &year, &month, &day) < 3 && - sscanf(date, "%d.%d.%d", &year, &month, &day) < 3) || - sscanf(time_, "%d:%d:%d", &hour, &minute, &second) < 3)) + if (date != "0" + && ((!extract(date, record<'/'>(&year, &month, &day)) + && !extract(date, record<'-'>(&year, &month, &day)) + && !extract(date, record<'.'>(&year, &month, &day))) + || !extract(time_, record<':'>(&hour, &minute, &second)))) { PRINTF("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); PRINTF("You can imput 0 instead of if you use 'banset' command.\n"); LADMIN_LOG("Invalid format for the date/time ('banset' or 'ban' command).\n"); - return 102; + return; } - if (atoi(date) == 0) + if (date == "0") { ban_until_time = TimeT(); } @@ -1169,40 +791,40 @@ int bansetaccountsub(const char *name, const char *date, const char *time_) { PRINTF("Please give a correct value for the month (from 1 to 12).\n"); LADMIN_LOG("Invalid month for the date ('banset' or 'ban' command).\n"); - return 102; + return; } month = month - 1; if (day < 1 || day > 31) { PRINTF("Please give a correct value for the day (from 1 to 31).\n"); LADMIN_LOG("Invalid day for the date ('banset' or 'ban' command).\n"); - return 102; + return; } if (((month == 3 || month == 5 || month == 8 || month == 10) - && day > 30) ||(month == 1 && day > 29)) + && day > 30) || (month == 1 && day > 29)) { PRINTF("Please give a correct value for a day of this month (%d).\n", month); LADMIN_LOG("Invalid day for this month ('banset' or 'ban' command).\n"); - return 102; + return; } if (hour < 0 || hour > 23) { PRINTF("Please give a correct value for the hour (from 0 to 23).\n"); LADMIN_LOG("Invalid hour for the time ('banset' or 'ban' command).\n"); - return 102; + return; } if (minute < 0 || minute > 59) { PRINTF("Please give a correct value for the minutes (from 0 to 59).\n"); LADMIN_LOG("Invalid minute for the time ('banset' or 'ban' command).\n"); - return 102; + return; } if (second < 0 || second > 59) { PRINTF("Please give a correct value for the seconds (from 0 to 59).\n"); LADMIN_LOG("Invalid second for the time ('banset' or 'ban' command).\n"); - return 102; + return; } tmtime.tm_year = year; tmtime.tm_mon = month; @@ -1218,7 +840,7 @@ int bansetaccountsub(const char *name, const char *date, const char *time_) PRINTF("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); PRINTF("You can imput 0 instead of if you use 'banset' command.\n"); LADMIN_LOG("Invalid date. ('banset' or 'ban' command).\n"); - return 102; + return; } } @@ -1229,23 +851,19 @@ int bansetaccountsub(const char *name, const char *date, const char *time_) WFIFOL(login_fd, 26) = static_cast<time_t>(ban_until_time); WFIFOSET(login_fd, 30); bytes_to_read = 1; - - return 0; } //--------------------------------------------------------------------- // Sub-function: Set the final date of a banishment of an account (ban) //--------------------------------------------------------------------- static -int banaccount(const char *param) +void banaccount(ZString param) { - char name[1023] {}; - char date[1023] {}; - char time_[1023] {}; + AccountName name; + XString date; + XString time_; - if (sscanf(param, "%s %s \"%[^\"]\"", date, time_, name) < 3 && - sscanf(param, "%s %s '%[^']'", date, time_, name) < 3 && - sscanf(param, "%s %s %[^\r\n]", date, time_, name) < 3) + if (!qsplit(param, &date, &time_, &name)) { PRINTF("Please input an account name, a date and a hour.\n"); PRINTF("<example>: banset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); @@ -1254,26 +872,27 @@ int banaccount(const char *param) PRINTF(" unban/unbanish <account name>\n"); PRINTF(" Default time [hh:mm:ss]: 23:59:59.\n"); LADMIN_LOG("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); - return 136; + return; } - return bansetaccountsub(name, date, time_); + if (!time_) + time_ = "23:59:59"; + + bansetaccountsub(name, date, time_); } //------------------------------------------------------------------------ // Sub-function: Set the final date of a banishment of an account (banset) //------------------------------------------------------------------------ static -int bansetaccount(const char *param) +void bansetaccount(ZString param) { - char name[1023] {}; - char date[1023] {}; - char time_[1023] {}; - - if (sscanf(param, "\"%[^\"]\" %s %[^\r\n]", name, date, time_) < 2 && // if date = 0, time_ can be void - sscanf(param, "'%[^']' %s %[^\r\n]", name, date, time_) < 2 && // if date = 0, time_ can be void - sscanf(param, "%s %s %[^\r\n]", name, date, time_) < 2) - { // if date = 0, time_ can be void + AccountName name; + XString date; + XString time_; + + if (!qsplit(param, &name, &date, &time_)) + { PRINTF("Please input an account name, a date and a hour.\n"); PRINTF("<example>: banset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); PRINTF(" banset <account_name> 0 (0 = un-banished)\n"); @@ -1281,27 +900,24 @@ int bansetaccount(const char *param) PRINTF(" unban/unbanish <account name>\n"); PRINTF(" Default time [hh:mm:ss]: 23:59:59.\n"); LADMIN_LOG("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); - return 136; + return; } - if (time_[0] == '\0') - strcpy(time_, "23:59:59"); + if (!time_) + time_ = "23:59:59"; - return bansetaccountsub(name, date, time_); + bansetaccountsub(name, date, time_); } //------------------------------------------------- // Sub-function: unbanishment of an account (unban) //------------------------------------------------- static -int unbanaccount(const char *param) +void unbanaccount(ZString param) { - char name[1023] {}; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<example>: banset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); @@ -1310,10 +926,10 @@ int unbanaccount(const char *param) PRINTF(" unban/unbanish <account name>\n"); PRINTF(" Default time [hh:mm:ss]: 23:59:59.\n"); LADMIN_LOG("Incomplete parameters to set a ban ('unban' command).\n"); - return 136; + return; } - return bansetaccountsub(name, "0", ""); + bansetaccountsub(name, "0", ""); } //--------------------------------------------------------- @@ -1321,33 +937,24 @@ int unbanaccount(const char *param) // (Note: never send back a password with login-server!! security of passwords) //--------------------------------------------------------- static -int checkaccount(const char *param) +void checkaccount(ZString param) { - char name[1023] {}; - char password[1023] {}; + AccountName name; + AccountPass password; - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && // password can be void - sscanf(param, "'%[^']' %[^\r\n]", name, password) < 1 && // password can be void - sscanf(param, "%s %[^\r\n]", name, password) < 1) - { // password can be void + if (!qsplit(param, &name, &password)) + { PRINTF("Please input an account name.\n"); PRINTF("<example> check testname password\n"); LADMIN_LOG("Incomplete parameters to check the password of an account ('check' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; - if (strlen(password) == 0) - { - if (typepasswd(password) == 0) - return 134; - } - if (verify_password(password) == 0) - return 131; + if (!password.is_print()) + return; LADMIN_LOG("Request to login-server to check a password.\n"); @@ -1356,53 +963,47 @@ int checkaccount(const char *param) WFIFO_STRING(login_fd, 26, password, 24); WFIFOSET(login_fd, 50); bytes_to_read = 1; - - return 0; } //------------------------------------------------ // Sub-function: Asking for deletion of an account //------------------------------------------------ static -int delaccount(const char *param) +void delaccount(ZString param) { - char name[1023] {}; - char letter; - int i; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<example> del testnametodelete\n"); LADMIN_LOG("No name given to delete an account ('delete' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; - char confirm[1023] {}; - while (confirm[0] != 'n' - && confirm[0] != 'y') + char confirm; + do { PRINTF("\033[1;36m ** Are you really sure to DELETE account [%s]? (y/n) > \033[0m", name); fflush(stdout); - strzcpy(confirm, "", sizeof(confirm)); - i = 0; - while ((letter = getchar()) != '\n') - confirm[i++] = letter; + int seek = getchar(); + confirm = seek; + if (seek == EOF) + confirm = 'n'; + else + while (seek != '\n' && seek != EOF) + seek = getchar(); } + while (!XString("yn").contains(confirm)); - if (confirm[0] == 'n') + if (confirm == 'n') { PRINTF("Deletion canceled.\n"); LADMIN_LOG("Deletion canceled by user ('delete' command).\n"); - return 121; + return; } LADMIN_LOG("Request to login-server to delete an acount.\n"); @@ -1411,58 +1012,36 @@ int delaccount(const char *param) WFIFO_STRING(login_fd, 2, name, 24); WFIFOSET(login_fd, 26); bytes_to_read = 1; - - return 0; } //---------------------------------------------------------- // Sub-function: Asking to modification of an account e-mail //---------------------------------------------------------- static -int changeemail(const char *param) +void changeemail(ZString param) { - char name[1023] {}; - char email[1023] {}; - - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, email) < 2 && - sscanf(param, "'%[^']' %[^\r\n]", name, email) < 2 && - sscanf(param, "%s %[^\r\n]", name, email) < 2) + AccountName name; + XString email_; + if (!qsplit(param, &name, &email_)) { PRINTF("Please input an account name and an email.\n"); PRINTF("<example> email testname newemail\n"); LADMIN_LOG("Incomplete parameters to change the email of an account ('email' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; - if (strlen(email) < 3) - { - PRINTF("Email is too short [%s]. Please input a valid e-mail.\n", - email); - LADMIN_LOG("Email is too short [%s]. Please input a valid e-mail.\n", - email); - return 109; - } - if (strlen(email) > 39) - { - PRINTF("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - LADMIN_LOG("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - return 109; - } - if (e_mail_check(email) == 0) + if (!e_mail_check(email_)) { PRINTF("Invalid email [%s]. Please input a valid e-mail.\n", - email); + FString(email_)); LADMIN_LOG("Invalid email [%s]. Please input a valid e-mail.\n", - email); - return 109; + FString(email_)); + return; } + AccountEmail email = stringish<AccountEmail>(email_); LADMIN_LOG("Request to login-server to change an email.\n"); @@ -1471,48 +1050,40 @@ int changeemail(const char *param) WFIFO_STRING(login_fd, 26, email, 40); WFIFOSET(login_fd, 66); bytes_to_read = 1; - - return 0; } //----------------------------------------------------- // Sub-function: Asking of the number of online players //----------------------------------------------------- static -int getlogincount(void) +void getlogincount(void) { LADMIN_LOG("Request to login-server to obtain the # of online players.\n"); WFIFOW(login_fd, 0) = 0x7938; WFIFOSET(login_fd, 2); bytes_to_read = 1; - - return 0; } //---------------------------------------------------------- // Sub-function: Asking to modify the GM level of an account //---------------------------------------------------------- static -int changegmlevel(const char *param) +void changegmlevel(ZString param) { - char name[1023] {}; + AccountName name; int GM_level = 0; - if (sscanf(param, "\"%[^\"]\" %d", name, &GM_level) < 1 && - sscanf(param, "'%[^']' %d", name, &GM_level) < 1 && - sscanf(param, "%s %d", name, &GM_level) < 1) + if (!qsplit(param, &name, &GM_level)) { PRINTF("Please input an account name and a GM level.\n"); PRINTF("<example> gm testname 80\n"); LADMIN_LOG("Incomplete parameters to change the GM level of an account ('gm' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; if (GM_level < 0 || GM_level > 99) { @@ -1520,7 +1091,7 @@ int changegmlevel(const char *param) GM_level); LADMIN_LOG("Illegal GM level [%d]. The value can be from 0 to 99.\n", GM_level); - return 103; + return; } LADMIN_LOG("Request to login-server to change a GM level.\n"); @@ -1530,32 +1101,27 @@ int changegmlevel(const char *param) WFIFOB(login_fd, 26) = GM_level; WFIFOSET(login_fd, 27); bytes_to_read = 1; - - return 0; } //--------------------------------------------- // Sub-function: Asking to obtain an account id //--------------------------------------------- static -int idaccount(const char *param) +void idaccount(ZString param) { - char name[1023] {}; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<example> id testname\n"); LADMIN_LOG("No name given to search an account id ('id' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) + if (!name.is_print()) { - return 102; + return; } LADMIN_LOG("Request to login-server to know an account id.\n"); @@ -1564,21 +1130,19 @@ int idaccount(const char *param) WFIFO_STRING(login_fd, 2, name, 24); WFIFOSET(login_fd, 26); bytes_to_read = 1; - - return 0; } //---------------------------------------------------------------------------- // Sub-function: Asking to displaying information about an account (by its id) //---------------------------------------------------------------------------- static -int infoaccount(int account_id) +void infoaccount(int account_id) { if (account_id < 0) { PRINTF("Please input a positive value for the id.\n"); LADMIN_LOG("Negative value was given to found the account.\n"); - return 136; + return; } LADMIN_LOG("Request to login-server to obtain information about an account (by its id).\n"); @@ -1587,40 +1151,31 @@ int infoaccount(int account_id) WFIFOL(login_fd, 2) = account_id; WFIFOSET(login_fd, 6); bytes_to_read = 1; - - return 0; } //--------------------------------------- // Sub-function: Send a broadcast message //--------------------------------------- static -int sendbroadcast(short type, const char *message) +void sendbroadcast(ZString message) { - if (strlen(message) == 0) + if (!message) { PRINTF("Please input a message.\n"); - if (type == 0) { PRINTF("<example> kami a message\n"); } - else - { - PRINTF("<example> kamib a message\n"); - } - LADMIN_LOG("The message is void ('kami(b)' command).\n"); - return 136; + LADMIN_LOG("The message is void ('kami' command).\n"); + return; } WFIFOW(login_fd, 0) = 0x794e; - WFIFOW(login_fd, 2) = type; - size_t len = strlen(message) + 1; + WFIFOW(login_fd, 2) = 0; + size_t len = message.size() + 1; WFIFOL(login_fd, 4) = len; WFIFO_STRING(login_fd, 8, message, len); WFIFOSET(login_fd, 8 + len); bytes_to_read = 1; - - return 0; } @@ -1628,11 +1183,9 @@ int sendbroadcast(short type, const char *message) // Sub-function: Asking to Displaying of the accounts list //-------------------------------------------------------- static -int listaccount(char *param, int type) +void listaccount(ZString param, int type) { //int list_first, list_last, list_type; // parameter to display a list of accounts - int i; - list_type = type; // set default values @@ -1645,8 +1198,6 @@ int listaccount(char *param, int type) } else if (list_type == 2) { // if search - for (i = 0; param[i]; i++) - param[i] = tolower(param[i]); // get all accounts = use default } else if (list_type == 3) @@ -1658,23 +1209,13 @@ int listaccount(char *param, int type) // get all accounts = use default } else - { // if list (list_type == 0) - switch (sscanf(param, "%d %d", &list_first, &list_last)) - { - case 0: - // get all accounts = use default - break; - case 1: - list_last = 0; - // use tests of the following value - FALLTHROUGH; - default: - if (list_first < 0) - list_first = 0; - if (list_last < list_first || list_last < 0) - list_last = 0; - break; - } + { + // if list (list_type == 0) + extract(param, record<' '>(&list_first, &list_last)); + if (list_first < 0) + list_first = 0; + if (list_last < list_first || list_last < 0) + list_last = 0; } LADMIN_LOG("Request to login-server to obtain the list of accounts from %d to %d.\n", @@ -1690,19 +1231,17 @@ int listaccount(char *param, int type) Iprintf("account_id GM user_name sex count state\n"); Iprintf("-------------------------------------------------------------------------------\n"); list_count = 0; - - return 0; } //-------------------------------------------------------- // Sub-function: Frobnicate items //-------------------------------------------------------- static -int itemfrob(const char *param) +int itemfrob(ZString param) { int source_id, dest_id; - if (sscanf(param, "%d %d", &source_id, &dest_id) < 2) + if (!extract(param, record<' '>(&source_id, &dest_id))) { PRINTF("You must provide the source and destination item IDs.\n"); return 1; @@ -1721,27 +1260,23 @@ int itemfrob(const char *param) // Sub-function: Asking to modify a memo field //-------------------------------------------- static -int changememo(const char *param) +void changememo(ZString param) { - char name[1023] {}; - char memo[1023] {}; + AccountName name; + XString memo; - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, memo) < 1 && // memo can be void - sscanf(param, "'%[^']' %[^\r\n]", name, memo) < 1 && // memo can be void - sscanf(param, "%s %[^\r\n]", name, memo) < 1) - { // memo can be void + if (!qsplit(param, &name, &memo) && !qsplit(param, &name)) + { PRINTF("Please input an account name and a memo.\n"); PRINTF("<example> memo testname new memo\n"); LADMIN_LOG("Incomplete parameters to change the memo of an account ('email' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; - size_t len = strlen(memo); + size_t len = memo.size(); size_t len1 = len + 1; if (len > 254) { @@ -1749,7 +1284,7 @@ int changememo(const char *param) PRINTF("Please input a memo of 254 bytes at the maximum.\n"); LADMIN_LOG("Email is too long (%zu characters). Please input a memo of 254 bytes at the maximum.\n", len); - return 102; + return; } LADMIN_LOG("Request to login-server to change a memo.\n"); @@ -1760,21 +1295,19 @@ int changememo(const char *param) WFIFO_STRING(login_fd, 28, memo, len); WFIFOSET(login_fd, 28 + len1); bytes_to_read = 1; - - return 0; } //----------------------------------------------- // Sub-function: Asking to obtain an account name //----------------------------------------------- static -int nameaccount(int id) +void nameaccount(int id) { if (id < 0) { PRINTF("Please input a positive value for the id.\n"); LADMIN_LOG("Negativ id given to search an account name ('name' command).\n"); - return 136; + return; } LADMIN_LOG("Request to login-server to know an account name.\n"); @@ -1783,8 +1316,6 @@ int nameaccount(int id) WFIFOL(login_fd, 2) = id; WFIFOSET(login_fd, 6); bytes_to_read = 1; - - return 0; } //------------------------------------------ @@ -1792,33 +1323,26 @@ int nameaccount(int id) // (Note: never send back a password with login-server!! security of passwords) //------------------------------------------ static -int changepasswd(const char *param) +void changepasswd(ZString param) { - char name[1023] {}; - char password[1023] {}; + AccountName name; + AccountPass password; - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && - sscanf(param, "'%[^']' %[^\r\n]", name, password) < 1 && - sscanf(param, "%s %[^\r\n]", name, password) < 1) + if (!qsplit(param, &name, &password)) { PRINTF("Please input an account name.\n"); PRINTF("<example> passwd testname newpassword\n"); LADMIN_LOG("Incomplete parameters to change the password of an account ('password' command).\n"); - return 136; + return; } - if (verify_accountname(name) == 0) + if (!name.is_print()) { - return 102; + return; } - if (strlen(password) == 0) - { - if (typepasswd(password) == 0) - return 134; - } - if (verify_password(password) == 0) - return 131; + if (!password.is_print()) + return; LADMIN_LOG("Request to login-server to change a password.\n"); @@ -1827,8 +1351,6 @@ int changepasswd(const char *param) WFIFO_STRING(login_fd, 26, password, 24); WFIFOSET(login_fd, 50); bytes_to_read = 1; - - return 0; } //---------------------------------------------------------------------- @@ -1836,7 +1358,7 @@ int changepasswd(const char *param) // this function have no answer //---------------------------------------------------------------------- static -int reloadGM(char *params) +void reloadGM(ZString params) { WFIFOW(login_fd, 0) = 0x7955; WFIFOSET(login_fd, 2); @@ -1846,52 +1368,45 @@ int reloadGM(char *params) PRINTF("Request to reload the GM configuration file sended.\n"); PRINTF("Check the actual GM accounts (after reloading):\n"); listaccount(params, 1); // 1: to list only GM - - return 180; } //----------------------------------------------------- // Sub-function: Asking to modify the sex of an account //----------------------------------------------------- static -int changesex(const char *param) +void changesex(ZString param) { - char name[1023] {}; - char sex[1023] {}; + AccountName name; + VString<1> sex_; - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, sex) < 2 && - sscanf(param, "'%[^']' %[^\r\n]", name, sex) < 2 && - sscanf(param, "%s %[^\r\n]", name, sex) < 2) + if (!qsplit(param, &name, &sex_)) { PRINTF("Please input an account name and a sex.\n"); PRINTF("<example> sex testname Male\n"); LADMIN_LOG("Incomplete parameters to change the sex of an account ('sex' command).\n"); - return 136; + return; } + char sex = sex_.front(); - if (verify_accountname(name) == 0) + if (name.is_print()) { - return 102; + return; } - sex[0] = toupper(sex[0]); - if (strchr("MF", sex[0]) == NULL) + if (!XString("MF").contains(sex)) { - PRINTF("Illegal gender [%s]. Please input M or F.\n", sex); - LADMIN_LOG("Illegal gender [%s]. Please input M or F.\n", - sex); - return 103; + PRINTF("Illegal gender [%c]. Please input M or F.\n", sex); + LADMIN_LOG("Illegal gender [%c]. Please input M or F.\n", sex); + return; } LADMIN_LOG("Request to login-server to change a sex.\n"); WFIFOW(login_fd, 0) = 0x793c; WFIFO_STRING(login_fd, 2, name, 24); - WFIFOB(login_fd, 26) = sex[0]; + WFIFOB(login_fd, 26) = sex; WFIFOSET(login_fd, 27); bytes_to_read = 1; - - return 0; } //------------------------------------------------------------------------- @@ -1899,10 +1414,8 @@ int changesex(const char *param) // Asking to modify the state of an account //------------------------------------------------------------------------- static -int changestatesub(const char *name, int state, const char *error_message7) +void changestatesub(AccountName name, int state, XString error_message) { - const char *error_message = error_message7; - if ((state < 0 || state > 9) && state != 100) { // Valid values: 0: ok, or value of the 0x006a packet + 1 PRINTF("Please input one of these states:\n"); @@ -1917,13 +1430,11 @@ int changestatesub(const char *name, int state, const char *error_message7) PRINTF(" block <account name>\n"); PRINTF(" unblock <account name>\n"); LADMIN_LOG("Invalid value for the state of an account ('state', 'block' or 'unblock' command).\n"); - return 151; + return; } - if (verify_accountname(name) == 0) - { - return 102; - } + if (!name.is_print()) + return; if (state != 7) { @@ -1931,17 +1442,17 @@ int changestatesub(const char *name, int state, const char *error_message7) } else { - if (strlen(error_message) < 1) + if (error_message.size() < 1) { PRINTF("Error message is too short. Please input a message of 1-19 bytes.\n"); LADMIN_LOG("Error message is too short. Please input a message of 1-19 bytes.\n"); - return 102; + return; } - if (strlen(error_message) > 19) + if (error_message.size() > 19) { PRINTF("Error message is too long. Please input a message of 1-19 bytes.\n"); LADMIN_LOG("Error message is too long. Please input a message of 1-19 bytes.\n"); - return 102; + return; } } @@ -1953,23 +1464,19 @@ int changestatesub(const char *name, int state, const char *error_message7) WFIFO_STRING(login_fd, 30, error_message, 20); WFIFOSET(login_fd, 50); bytes_to_read = 1; - - return 0; } //------------------------------------------------------- // Sub-function: Asking to modify the state of an account //------------------------------------------------------- static -int changestate(const char *param) +void changestate(ZString param) { - char name[1023] {}; - char error_message[1023] {}; + AccountName name; int state; + XString error_message; - if (sscanf(param, "\"%[^\"]\" %d %[^\r\n]", name, &state, error_message) < 2 - && sscanf(param, "'%[^']' %d %[^\r\n]", name, &state, error_message) < 2 - && sscanf(param, "%s %d %[^\r\n]", name, &state, error_message) < 2) + if (!qsplit(param, &name, &state, &error_message) && !qsplit(param, &name, &state)) { PRINTF("Please input an account name and a state.\n"); PRINTF("<examples> state testname 5\n"); @@ -1977,24 +1484,21 @@ int changestate(const char *param) PRINTF(" block <account name>\n"); PRINTF(" unblock <account name>\n"); LADMIN_LOG("Incomplete parameters to change the state of an account ('state' command).\n"); - return 136; + return; } - return changestatesub(name, state, error_message); + changestatesub(name, state, error_message); } //------------------------------------------- // Sub-function: Asking to unblock an account //------------------------------------------- static -int unblockaccount(const char *param) +void unblockaccount(ZString param) { - char name[1023] {}; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<examples> state testname 5\n"); @@ -2002,24 +1506,21 @@ int unblockaccount(const char *param) PRINTF(" block <account name>\n"); PRINTF(" unblock <account name>\n"); LADMIN_LOG("Incomplete parameters to change the state of an account ('unblock' command).\n"); - return 136; + return; } - return changestatesub(name, 0, "-"); // state 0, no error message + changestatesub(name, 0, "-"); // state 0, no error message } //------------------------------------------- // Sub-function: Asking to unblock an account //------------------------------------------- static -int blockaccount(const char *param) +void blockaccount(ZString param) { - char name[1023] {}; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<examples> state testname 5\n"); @@ -2027,108 +1528,36 @@ int blockaccount(const char *param) PRINTF(" block <account name>\n"); PRINTF(" unblock <account name>\n"); LADMIN_LOG("Incomplete parameters to change the state of an account ('block' command).\n"); - return 136; + return; } - return changestatesub(name, 5, "-"); // state 5, no error message + changestatesub(name, 5, "-"); // state 5, no error message } //--------------------------------------------------------------------- // Sub-function: Add/substract time to the validity limit of an account //--------------------------------------------------------------------- static -int timeaddaccount(const char *param) +void timeaddaccount(ZString param) { - char name[1023] {}; - char modif[1023] {}; - int year, month, day, hour, minute, second; - const char *p_modif; - int value, i; + AccountName name; + HumanTimeDiff modif {}; - year = month = day = hour = minute = second = 0; - - if (sscanf(param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && - sscanf(param, "'%[^']' %[^\r\n]", name, modif) < 2 && - sscanf(param, "%s %[^\r\n]", name, modif) < 2) + if (!qsplit(param, &name, &modif)) { PRINTF("Please input an account name and a modifier.\n"); PRINTF(" <example>: timeadd testname +1m-2mn1s-6y\n"); PRINTF(" this example adds 1 month and 1 second, and substracts 2 minutes\n"); PRINTF(" and 6 years at the same time.\n"); LADMIN_LOG("Incomplete parameters to modify a limit time ('timeadd' command).\n"); - return 136; - } - if (verify_accountname(name) == 0) - { - return 102; + return; } - - // lowercase for modif - for (i = 0; modif[i]; i++) - modif[i] = tolower(modif[i]); - p_modif = modif; - while (strlen(p_modif) > 0) + if (name.is_print()) { - value = atoi(p_modif); - if (value == 0) - { - p_modif++; - } - else - { - if (p_modif[0] == '-' || p_modif[0] == '+') - p_modif++; - while (strlen(p_modif) > 0 && p_modif[0] >= '0' - && p_modif[0] <= '9') - { - p_modif++; - } - if (p_modif[0] == 's') - { - second = value; - p_modif++; - } - else if (p_modif[0] == 'm' && p_modif[1] == 'n') - { - minute = value; - p_modif += 2; - } - else if (p_modif[0] == 'h') - { - hour = value; - p_modif++; - } - else if (p_modif[0] == 'd' || p_modif[0] == 'j') - { - day = value; - p_modif += 2; - } - else if (p_modif[0] == 'm') - { - month = value; - p_modif++; - } - else if (p_modif[0] == 'y' || p_modif[0] == 'a') - { - year = value; - p_modif++; - } - else - { - p_modif++; - } - } + return; } - PRINTF(" year: %d\n", year); - PRINTF(" month: %d\n", month); - PRINTF(" day: %d\n", day); - PRINTF(" hour: %d\n", hour); - PRINTF(" minute: %d\n", minute); - PRINTF(" second: %d\n", second); - - if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 - && second == 0) + if (!modif) { PRINTF("Please give an adjustment with this command:\n"); PRINTF(" Adjustment value (-1, 1, +1, etc...)\n"); @@ -2143,70 +1572,27 @@ int timeaddaccount(const char *param) PRINTF(" this example adds 1 month and 1 second, and substracts 2 minutes\n"); PRINTF(" and 6 years at the same time.\n"); LADMIN_LOG("No adjustment isn't an adjustment ('timeadd' command).\n"); - return 137; - } - if (year > 127 || year < -127) - { - PRINTF("Please give a correct adjustment for the years (from -127 to 127).\n"); - LADMIN_LOG("Abnormal adjustement for the year ('timeadd' command).\n"); - return 137; - } - if (month > 255 || month < -255) - { - PRINTF("Please give a correct adjustment for the months (from -255 to 255).\n"); - LADMIN_LOG("Abnormal adjustement for the month ('timeadd' command).\n"); - return 137; - } - if (day > 32767 || day < -32767) - { - PRINTF("Please give a correct adjustment for the days (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the days ('timeadd' command).\n"); - return 137; - } - if (hour > 32767 || hour < -32767) - { - PRINTF("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the hours ('timeadd' command).\n"); - return 137; - } - if (minute > 32767 || minute < -32767) - { - PRINTF("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the minutes ('timeadd' command).\n"); - return 137; - } - if (second > 32767 || second < -32767) - { - PRINTF("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); - LADMIN_LOG("Abnormal adjustement for the seconds ('timeadd' command).\n"); - return 137; + return; } LADMIN_LOG("Request to login-server to modify a time limit.\n"); WFIFOW(login_fd, 0) = 0x7950; WFIFO_STRING(login_fd, 2, name, 24); - WFIFOW(login_fd, 26) = year; - WFIFOW(login_fd, 28) = month; - WFIFOW(login_fd, 30) = day; - WFIFOW(login_fd, 32) = hour; - WFIFOW(login_fd, 34) = minute; - WFIFOW(login_fd, 36) = second; + WFIFO_STRUCT(login_fd, 26, modif); WFIFOSET(login_fd, 38); bytes_to_read = 1; - - return 0; } //------------------------------------------------- // Sub-function: Set a validity limit of an account //------------------------------------------------- static -int timesetaccount(const char *param) +void timesetaccount(ZString param) { - char name[1023] {}; - char date[1023] {}; - char time_[1023] {}; + AccountName name; + XString date; + XString time_; int year, month, day, hour, minute, second; year = month = day = hour = minute = second = 0; @@ -2215,38 +1601,33 @@ int timesetaccount(const char *param) TimeT connect_until_time = TimeT(); struct tm tmtime = connect_until_time; // initialize - if (sscanf(param, "\"%[^\"]\" %s %[^\r\n]", name, date, time_) < 2 && // if date = 0, time_ can be void - sscanf(param, "'%[^']' %s %[^\r\n]", name, date, time_) < 2 && // if date = 0, time_ can be void - sscanf(param, "%s %s %[^\r\n]", name, date, time_) < 2) - { // if date = 0, time_ can be void + if (!qsplit(param, &name, &date, &time_)) + { PRINTF("Please input an account name, a date and a hour.\n"); PRINTF("<example>: timeset <account_name> yyyy/mm/dd [hh:mm:ss]\n"); PRINTF(" timeset <account_name> 0 (0 = unlimited)\n"); PRINTF(" Default time [hh:mm:ss]: 23:59:59.\n"); LADMIN_LOG("Incomplete parameters to set a limit time ('timeset' command).\n"); - return 136; - } - if (verify_accountname(name) == 0) - { - return 102; + return; } + if (!name.is_print()) + return; - if (time_[0] == '\0') - strcpy(time_, "23:59:59"); + if (!time_) + time_ = "23:59:59"; - if (atoi(date) != 0 && - ((sscanf(date, "%d/%d/%d", &year, &month, &day) < 3 && - sscanf(date, "%d-%d-%d", &year, &month, &day) < 3 && - sscanf(date, "%d.%d.%d", &year, &month, &day) < 3 && - sscanf(date, "%d'%d'%d", &year, &month, &day) < 3) || - sscanf(time_, "%d:%d:%d", &hour, &minute, &second) < 3)) + if (date != "0" + && ((!extract(date, record<'/'>(&year, &month, &day)) + && !extract(date, record<'-'>(&year, &month, &day)) + && !extract(date, record<'.'>(&year, &month, &day))) + || !extract(time_, record<':'>(&hour, &minute, &second)))) { PRINTF("Please input 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); LADMIN_LOG("Invalid format for the date/time ('timeset' command).\n"); - return 102; + return; } - if (atoi(date) == 0) + if (date == "0") { connect_until_time = TimeT(); } @@ -2264,14 +1645,14 @@ int timesetaccount(const char *param) { PRINTF("Please give a correct value for the month (from 1 to 12).\n"); LADMIN_LOG("Invalid month for the date ('timeset' command).\n"); - return 102; + return; } month = month - 1; if (day < 1 || day > 31) { PRINTF("Please give a correct value for the day (from 1 to 31).\n"); LADMIN_LOG("Invalid day for the date ('timeset' command).\n"); - return 102; + return; } if (((month == 3 || month == 5 || month == 8 || month == 10) && day > 30) ||(month == 1 && day > 29)) @@ -2279,25 +1660,25 @@ int timesetaccount(const char *param) PRINTF("Please give a correct value for a day of this month (%d).\n", month); LADMIN_LOG("Invalid day for this month ('timeset' command).\n"); - return 102; + return; } if (hour < 0 || hour > 23) { PRINTF("Please give a correct value for the hour (from 0 to 23).\n"); LADMIN_LOG("Invalid hour for the time ('timeset' command).\n"); - return 102; + return; } if (minute < 0 || minute > 59) { PRINTF("Please give a correct value for the minutes (from 0 to 59).\n"); LADMIN_LOG("Invalid minute for the time ('timeset' command).\n"); - return 102; + return; } if (second < 0 || second > 59) { PRINTF("Please give a correct value for the seconds (from 0 to 59).\n"); LADMIN_LOG("Invalid second for the time ('timeset' command).\n"); - return 102; + return; } tmtime.tm_year = year; tmtime.tm_mon = month; @@ -2312,7 +1693,7 @@ int timesetaccount(const char *param) PRINTF("Invalid date.\n"); PRINTF("Please add 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); LADMIN_LOG("Invalid date. ('timeset' command).\n"); - return 102; + return; } } @@ -2323,31 +1704,26 @@ int timesetaccount(const char *param) WFIFOL(login_fd, 26) = static_cast<time_t>(connect_until_time); WFIFOSET(login_fd, 30); bytes_to_read = 1; - - return 0; } //------------------------------------------------------------------------------ // Sub-function: Asking to displaying information about an account (by its name) //------------------------------------------------------------------------------ static -int whoaccount(const char *param) +void whoaccount(ZString param) { - char name[1023] {}; + AccountName name; - if (strlen(param) == 0 || - (sscanf(param, "\"%[^\"]\"", name) < 1 && - sscanf(param, "'%[^']'", name) < 1 && - sscanf(param, "%[^\r\n]", name) < 1) || strlen(name) == 0) + if (!qsplit(param, &name)) { PRINTF("Please input an account name.\n"); PRINTF("<example> who testname\n"); LADMIN_LOG("No name was given to found the account.\n"); - return 136; + return; } - if (verify_accountname(name) == 0) + if (!name.is_print()) { - return 102; + return; } LADMIN_LOG("Request to login-server to obtain information about an account (by its name).\n"); @@ -2356,23 +1732,19 @@ int whoaccount(const char *param) WFIFO_STRING(login_fd, 2, name, 24); WFIFOSET(login_fd, 26); bytes_to_read = 1; - - return 0; } //-------------------------------------------------------- // Sub-function: Asking of the version of the login-server //-------------------------------------------------------- static -int checkloginversion(void) +void checkloginversion(void) { LADMIN_LOG("Request to login-server to obtain its version.\n"); WFIFOW(login_fd, 0) = 0x7530; WFIFOSET(login_fd, 2); bytes_to_read = 1; - - return 0; } //--------------------------------------------- @@ -2381,12 +1753,8 @@ int checkloginversion(void) // and analyse the command. //--------------------------------------------- static -int prompt(void) +void prompt(void) { - int i, j; - char buf[1024]; - char *p; - // while we don't wait new packets while (bytes_to_read == 0) { @@ -2404,246 +1772,117 @@ int prompt(void) fflush(stdout); // get command and parameter - strzcpy(buf, "", sizeof(buf)); - fflush(stdin); - if (!fgets(buf, 1023, stdin)) - exit(0); - buf[1023] = '\0'; + FString buf; + io::getline(std::cin, buf); Iprintf("\033[0m"); fflush(stdout); - if (!eathena_interactive_session && !strlen(buf)) + if (!eathena_interactive_session && !buf) exit(0); - // remove final \n - if ((p = strrchr(buf, '\n')) != NULL) - p[0] = '\0'; - // remove all control char - for (i = 0; buf[i]; i++) - if (buf[i] < 32) - { - // remove cursor control. - if (buf[i] == 27 - && buf[i + 1] == '[' - && (buf[i + 2] == 'H' // home position (cursor) - || buf[i + 2] == 'J' // clear screen - || buf[i + 2] == 'A' // up 1 line - || buf[i + 2] == 'B' // down 1 line - || buf[i + 2] == 'C' // right 1 position - || buf[i + 2] == 'D' // left 1 position - || buf[i + 2] == 'G')) // center cursor (windows) - { - for (j = i; buf[j]; j++) - buf[j] = buf[j + 3]; - } - else if (buf[i] == 27 && buf[i + 1] == '[' - && buf[i + 2] == '2' && buf[i + 3] == 'J') - { - // clear screen - for (j = i; buf[j]; j++) - buf[j] = buf[j + 4]; - } - else if (buf[i] == 27 - && buf[i + 1] == '[' - && buf[i + 3] == '~' - && (buf[i + 2] == '1' // home (windows) - || buf[i + 2] == '2' // insert (windows) - || buf[i + 2] == '3' // del (windows) - || buf[i + 2] == '4' // end (windows) - || buf[i + 2] == '5' // pgup (windows) - || buf[i + 2] == '6')) // pgdown (windows) - { - for (j = i; buf[j]; j++) - buf[j] = buf[j + 4]; - } - else - { - // remove other control char. - for (j = i; buf[j]; j++) - buf[j] = buf[j + 1]; - } - i--; - } + if (!buf.is_print()) + { + printf("Cowardly refusing to execute a command that includes control or non-ascii characters\n"); + LADMIN_LOG("Cowardly refusing to execute a command that includes control or non-ascii characters\n"); + continue; + } - char command[1024] {}; // extract command name and parameters - strzcpy(parameters, "", sizeof(parameters)); - sscanf(buf, "%1023s %[^\n]", command, parameters); - command[1023] = '\0'; - parameters[1023] = '\0'; + auto space = std::find(buf.begin(), buf.end(), ' '); + FString command = buf.xislice_h(space); + while (*space == ' ') + ++space; - // lowercase for command line - for (i = 0; command[i]; i++) - command[i] = tolower(command[i]); + parameters = buf.xislice_t(space); - if (command[0] == '?' || strlen(command) == 0) - { - strcpy(buf, "help"); - strcpy(command, "help"); - } + if (!command || command.startswith('?')) + command = "help"; - // Analyse of the command - check_command(command); // give complete name to the command - - if (strlen(parameters) == 0) + if (!parameters) { LADMIN_LOG("Command: '%s' (without parameters)\n", - command); + command); } else { LADMIN_LOG("Command: '%s', parameters: '%s'\n", - command, parameters); + command, parameters); } // Analyse of the command -// help - if (strcmp(command, "help") == 0) - { + if (command == "help") display_help(parameters); -// general commands - } - else if (strcmp(command, "add") == 0) - { + else if (command == "add") addaccount(parameters, 0); // 0: no email - } - else if (strcmp(command, "ban") == 0) - { + else if (command == "ban") banaccount(parameters); - } - else if (strcmp(command, "banadd") == 0) - { + else if (command == "banadd") banaddaccount(parameters); - } - else if (strcmp(command, "banset") == 0) - { + else if (command == "banset") bansetaccount(parameters); - } - else if (strcmp(command, "block") == 0) - { + else if (command == "block") blockaccount(parameters); - } - else if (strcmp(command, "check") == 0) - { + else if (command == "check") checkaccount(parameters); - } - else if (strcmp(command, "create") == 0) - { + else if (command == "create") addaccount(parameters, 1); // 1: with email - } - else if (strcmp(command, "delete") == 0) - { + else if (command == "delete") delaccount(parameters); - } - else if (strcmp(command, "email") == 0) - { + else if (command == "email") changeemail(parameters); - } - else if (strcmp(command, "getcount") == 0) - { + else if (command == "getcount") getlogincount(); - } - else if (strcmp(command, "gm") == 0) - { + else if (command == "gm") changegmlevel(parameters); - } - else if (strcmp(command, "id") == 0) - { + else if (command == "id") idaccount(parameters); - } - else if (strcmp(command, "info") == 0) - { - infoaccount(atoi(parameters)); - } - else if (strcmp(command, "kami") == 0) - { - sendbroadcast(0, parameters); // flag for normal - } - else if (strcmp(command, "kamib") == 0) - { - sendbroadcast(0x10, parameters); // flag for blue - } - else if (strcmp(command, "itemfrob") == 0) - { + else if (command == "info") + infoaccount(atoi(parameters.c_str())); + else if (command == "kami") + sendbroadcast(parameters); // flag for normal + else if (command == "itemfrob") itemfrob(parameters); // 0: to list all - } - else if (strcmp(command, "list") == 0) - { + else if (command == "list") listaccount(parameters, 0); // 0: to list all - } - else if (strcmp(command, "listban") == 0) - { + else if (command == "listban") listaccount(parameters, 3); // 3: to list only accounts with state or bannished - } - else if (strcmp(command, "listgm") == 0) - { + else if (command == "listgm") listaccount(parameters, 1); // 1: to list only GM - } - else if (strcmp(command, "listok") == 0) - { + else if (command == "listok") listaccount(parameters, 4); // 4: to list only accounts without state and not bannished - } - else if (strcmp(command, "memo") == 0) - { + else if (command == "memo") changememo(parameters); - } - else if (strcmp(command, "name") == 0) - { - nameaccount(atoi(parameters)); - } - else if (strcmp(command, "password") == 0) - { + else if (command == "name") + nameaccount(atoi(parameters.c_str())); + else if (command == "password") changepasswd(parameters); - } - else if (strcmp(command, "reloadgm") == 0) - { + else if (command == "reloadgm") reloadGM(parameters); - } - else if (strcmp(command, "search") == 0) - { // no regex in C version + else if (command == "search") listaccount(parameters, 2); // 2: to list with pattern - } - else if (strcmp(command, "sex") == 0) - { + else if (command == "sex") changesex(parameters); - } - else if (strcmp(command, "state") == 0) - { + else if (command == "state") changestate(parameters); - } - else if (strcmp(command, "timeadd") == 0) - { + else if (command == "timeadd") timeaddaccount(parameters); - } - else if (strcmp(command, "timeset") == 0) - { + else if (command == "timeset") timesetaccount(parameters); - } - else if (strcmp(command, "unban") == 0) - { + else if (command == "unban") unbanaccount(parameters); - } - else if (strcmp(command, "unblock") == 0) - { + else if (command == "unblock") unblockaccount(parameters); - } - else if (strcmp(command, "version") == 0) - { + else if (command == "version") checkloginversion(); - } - else if (strcmp(command, "who") == 0) - { + else if (command == "who") whoaccount(parameters); -// quit - } - else if (strcmp(command, "quit") == 0 || - strcmp(command, "exit") == 0 || - strcmp(command, "end") == 0) + else if (command == "quit" + || command == "exit" + || command == "end") { PRINTF("Bye.\n"); exit(0); -// unknown command } else { @@ -2651,8 +1890,6 @@ int prompt(void) LADMIN_LOG("Unknown command [%s].\n", buf); } } - - return 0; } //------------------------------------------------------------- @@ -2702,39 +1939,6 @@ void parse_fromlogin(int fd) RFIFOSKIP(fd, 3); break; - case 0x01dc: // answer of a coding key request - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd, 2)) - return; - { - char md5str[64] = ""; - size_t key_len = RFIFOW(fd, 2) - 4; - uint8_t md5bin[32]; - char md5key[key_len]; - RFIFO_STRING(fd, 4, md5key, key_len); - if (passenc == 1) - { - strcpy(md5str, md5key); - strcat(md5str, loginserveradminpassword); - } - else if (passenc == 2) - { - strcpy(md5str, loginserveradminpassword); - strcat(md5str, md5key); - } - MD5_to_bin(MD5_from_cstring(md5str), md5bin); - WFIFOW(login_fd, 0) = 0x7918; // Request for administation login (encrypted password) - WFIFOW(login_fd, 2) = passenc; // Encrypted type - really_memcpy(static_cast<uint8_t *>(WFIFOP(login_fd, 4)), md5bin, 16); - WFIFOSET(login_fd, 20); - Iprintf("Receiving of the MD5 key.\n"); - LADMIN_LOG("Receiving of the MD5 key.\n"); - Iprintf("Sending of the encrypted password...\n"); - LADMIN_LOG("Sending of the encrypted password...\n"); - } - bytes_to_read = 1; - RFIFOSKIP(fd, RFIFOW(fd, 2)); - break; - case 0x7531: // Displaying of the version of the login-server if (RFIFOREST(fd) < 10) return; @@ -2793,20 +1997,15 @@ void parse_fromlogin(int fd) LADMIN_LOG(" Receiving of a accounts list.\n"); for (i = 4; i < RFIFOW(fd, 2); i += 38) { - int j; - char userid[24]; - char lower_userid[24] {}; - RFIFO_STRING(fd, i + 5, userid, 24); - for (j = 0; userid[j]; j++) - lower_userid[j] = tolower(userid[j]); + AccountName userid = stringish<AccountName>(RFIFO_STRING<24>(fd, i + 5)); + VString<23> lower_userid = userid.to_lower(); list_first = RFIFOL(fd, i) + 1; // here are checks... - if (list_type == 0 || - (list_type == 1 && RFIFOB(fd, i + 4) > 0) || - (list_type == 2 - && strstr(lower_userid, parameters) != NULL) - ||(list_type == 3 && RFIFOL(fd, i + 34) != 0) - ||(list_type == 4 && RFIFOL(fd, i + 34) == 0)) + if (list_type == 0 + || (list_type == 1 && RFIFOB(fd, i + 4) > 0) + || (list_type == 2 && lower_userid.contains_seq(parameters)) + || (list_type == 3 && RFIFOL(fd, i + 34) != 0) + || (list_type == 4 && RFIFOL(fd, i + 34) == 0)) { PRINTF("%10d ", RFIFOL(fd, i)); if (RFIFOB(fd, i + 4) == 0) @@ -2880,8 +2079,7 @@ void parse_fromlogin(int fd) return; { int accid = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (accid == -1) { PRINTF("Account [%s] creation failed. Same account already exists.\n", @@ -2906,8 +2104,7 @@ void parse_fromlogin(int fd) return; { int accid = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (accid == -1) { PRINTF("Account [%s] deletion failed. Account doesn't exist.\n", @@ -2932,8 +2129,7 @@ void parse_fromlogin(int fd) return; { int accid = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (accid == -1) { PRINTF("Account [%s] password changing failed.\n", @@ -2960,8 +2156,7 @@ void parse_fromlogin(int fd) return; { int accid = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); int state = RFIFOL(fd, 30); if (accid == -1) { @@ -2972,7 +2167,8 @@ void parse_fromlogin(int fd) } else { - std::string tmpstr = STRPRINTF( + MString tmpstr; + tmpstr += STRPRINTF( "Account [%s] state successfully changed in [", name); switch (state) @@ -3012,8 +2208,9 @@ void parse_fromlogin(int fd) break; } tmpstr += ']'; - PRINTF("%s\n", tmpstr); - LADMIN_LOG("%s\n", tmpstr); + FString tmpstr_ = FString(tmpstr); + PRINTF("%s\n", tmpstr_); + LADMIN_LOG("%s\n", tmpstr_); } bytes_to_read = 0; } @@ -3037,8 +2234,7 @@ void parse_fromlogin(int fd) // Displaying of result for (int i = 4; i < RFIFOW(fd, 2); i += 32) { - char name[20]; - RFIFO_STRING(fd, i + 6, name, 20); + ServerName name = stringish<ServerName>(RFIFO_STRING<20>(fd, i + 6)); PRINTF(" %-20s : %5d\n", name, RFIFOW(fd, i + 26)); } @@ -3053,8 +2249,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("The account [%s] doesn't exist or the password is incorrect.\n", @@ -3079,8 +2274,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] sex changing failed.\n", @@ -3107,8 +2301,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] GM level changing failed.\n", @@ -3136,8 +2329,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] e-mail changing failed.\n", @@ -3164,8 +2356,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] memo changing failed. Account doesn't exist.\n", @@ -3190,8 +2381,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Unable to find the account [%s] id. Account doesn't exist.\n", @@ -3216,9 +2406,8 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); - if (strcmp(name, "") == 0) + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); + if (!name) { PRINTF("Unable to find the account [%d] name. Account doesn't exist.\n", account_id); @@ -3242,8 +2431,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (RFIFOL(fd, 2) == -1) { PRINTF("Account [%s] validity limit changing failed. Account doesn't exist.\n", @@ -3282,8 +2470,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", @@ -3322,8 +2509,7 @@ void parse_fromlogin(int fd) return; { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); if (account_id == -1) { PRINTF("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", @@ -3378,12 +2564,15 @@ void parse_fromlogin(int fd) case 0x7951: // answer of an account validity limit changing if (RFIFOREST(fd) < 34) return; - if (RFIFOL(fd, 2) == -1) + { + int account_id = RFIFOL(fd, 2); + AccountName name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); + if (account_id == -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 { @@ -3391,25 +2580,26 @@ void parse_fromlogin(int fd) if (!timestamp) { PRINTF("Validity limit of the account [%s][id: %d] unchanged.\n", - static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2)); + name, account_id); PRINTF("The account have an unlimited validity limit or\n"); PRINTF("the changing is impossible with the proposed adjustments.\n"); LADMIN_LOG("Validity limit of the account [%s][id: %d] unchanged. The account have an unlimited validity limit or the changing is impossible with the proposed adjustments.\n", - static_cast<const char *>(RFIFOP(fd, 6)), RFIFOL(fd, 2)); + name, account_id); } else { timestamp_seconds_buffer tmpstr; stamp_time(tmpstr, ×tamp); 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), + 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; @@ -3418,54 +2608,55 @@ void parse_fromlogin(int fd) || RFIFOREST(fd) < (150 + RFIFOW(fd, 148))) return; { - char userid[24], error_message[20], lastlogin[24], - last_ip[16], email[40], memo[255]; - TimeT ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - TimeT connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - RFIFO_STRING(fd, 7, userid, 24); - RFIFO_STRING(fd, 40, error_message, 20); - RFIFO_STRING(fd, 60, lastlogin, 24); - RFIFO_STRING(fd, 84, last_ip, 16); - RFIFO_STRING(fd, 100, email, 40); - connect_until_time = static_cast<time_t>(RFIFOL(fd, 140)); - ban_until_time = static_cast<time_t>(RFIFOL(fd, 144)); - RFIFO_STRING(fd, 150, memo, RFIFOW(fd, 148)); - if (RFIFOL(fd, 2) == -1) + int account_id = RFIFOL(fd, 2); + uint8_t gm = RFIFOB(fd, 6); + AccountName userid = stringish<AccountName>(RFIFO_STRING<24>(fd, 7)); + uint8_t sex = RFIFOB(fd, 31); + int connections = RFIFOL(fd, 32); + int state = RFIFOL(fd, 36); + timestamp_seconds_buffer error_message = stringish<timestamp_seconds_buffer>(RFIFO_STRING<20>(fd, 40)); + timestamp_milliseconds_buffer lastlogin = stringish<timestamp_milliseconds_buffer>(RFIFO_STRING<24>(fd, 60)); + IP_String last_ip = stringish<IP_String>(RFIFO_STRING<16>(fd, 84)); + AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 100)); + TimeT connect_until_time = static_cast<time_t>(RFIFOL(fd, 140)); + TimeT ban_until_time = static_cast<time_t>(RFIFOL(fd, 144)); + FString memo = RFIFO_STRING(fd, 150, RFIFOW(fd, 148)); + if (account_id == -1) { PRINTF("Unabled to find the account [%s]. Account doesn't exist.\n", - parameters); + userid); LADMIN_LOG("Unabled to find the account [%s]. Account doesn't exist.\n", - parameters); + userid); } - else if (strlen(userid) == 0) + else if (!userid) { - PRINTF("Unabled to find the account [id: %s]. Account doesn't exist.\n", - parameters); - LADMIN_LOG("Unabled to find the account [id: %s]. Account doesn't exist.\n", - parameters); + PRINTF("Unabled to find the account [id: %d]. Account doesn't exist.\n", + account_id); + LADMIN_LOG("Unabled to find the account [id: %d]. Account doesn't exist.\n", + account_id); } else { LADMIN_LOG("Receiving information about an account.\n"); PRINTF("The account is set with:\n"); - if (RFIFOB(fd, 6) == 0) + if (!gm) { - PRINTF(" Id: %d (non-GM)\n", RFIFOL(fd, 2)); + PRINTF(" Id: %d (non-GM)\n", account_id); } else { PRINTF(" Id: %d (GM level %d)\n", - RFIFOL(fd, 2), RFIFOB(fd, 6)); + account_id, gm); } PRINTF(" Name: '%s'\n", userid); - if (RFIFOB(fd, 31) == 0) + if (sex == 0) PRINTF(" Sex: Female\n"); - else if (RFIFOB(fd, 31) == 1) + else if (sex == 1) PRINTF(" Sex: Male\n"); else PRINTF(" Sex: Server\n"); PRINTF(" E-mail: %s\n", email); - switch (RFIFOL(fd, 36)) + switch (state) { case 0: PRINTF(" Statut: 0 [Account OK]\n"); @@ -3500,7 +2691,7 @@ void parse_fromlogin(int fd) break; default: // 100 PRINTF(" Statut: %d [This ID is totally erased]\n", - RFIFOL(fd, 36)); + state); break; } if (!ban_until_time) @@ -3513,12 +2704,12 @@ void parse_fromlogin(int fd) stamp_time(tmpstr, &ban_until_time); PRINTF(" Banishment: until %s.\n", tmpstr); } - if (RFIFOL(fd, 32) > 1) + if (connections > 1) PRINTF(" Count: %d connections.\n", - RFIFOL(fd, 32)); + connections); else PRINTF(" Count: %d connection.\n", - RFIFOL(fd, 32)); + connections); PRINTF(" Last connection at: %s (ip: %s)\n", lastlogin, last_ip); if (!connect_until_time) @@ -3563,7 +2754,6 @@ int Connect_login_server(void) if ((login_fd = make_connection(login_ip, loginserverport)) < 0) return 0; - if (passenc == 0) { WFIFOW(login_fd, 0) = 0x7918; // Request for administation login WFIFOW(login_fd, 2) = 0; // no encrypted @@ -3574,14 +2764,6 @@ int Connect_login_server(void) Iprintf("Sending of the password...\n"); LADMIN_LOG("Sending of the password...\n"); } - else - { - WFIFOW(login_fd, 0) = 0x791a; // Sending request about the coding key - WFIFOSET(login_fd, 2); - bytes_to_read = 1; - Iprintf("Request about the MD5 key...\n"); - LADMIN_LOG("Request about the MD5 key...\n"); - } return 0; } @@ -3590,9 +2772,9 @@ int Connect_login_server(void) // Reading general configuration file //----------------------------------- static -int ladmin_config_read(const char *cfgName) +int ladmin_config_read(ZString cfgName) { - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { PRINTF("\033[0mConfiguration file (%s) not found.\n", cfgName); @@ -3601,10 +2783,11 @@ int ladmin_config_read(const char *cfgName) Iprintf("\033[0m---Start reading of Ladmin configuration file (%s)\n", cfgName); - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; @@ -3619,14 +2802,14 @@ int ladmin_config_read(const char *cfgName) static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3])); - sprintf(loginserverip, "%d.%d.%d.%d", + SNPRINTF(loginserverip, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3])); } else - strzcpy(loginserverip, w2.c_str(), 16); + loginserverip = stringish<IP_String>(w2); } else if (w1 == "login_port") { @@ -3634,29 +2817,23 @@ int ladmin_config_read(const char *cfgName) } else if (w1 == "admin_pass") { - strzcpy(loginserveradminpassword, w2.c_str(), sizeof(loginserveradminpassword)); - } - else if (w1 == "passenc") - { - passenc = atoi(w2.c_str()); - if (passenc < 0 || passenc > 2) - passenc = 0; + loginserveradminpassword = stringish<AccountPass>(w2); } else if (w1 == "ladmin_log_filename") { - strzcpy(ladmin_log_filename, w2.c_str(), sizeof(ladmin_log_filename)); + ladmin_log_filename = w2; } else if (w1 == "import") { - ladmin_config_read(w2.c_str()); + ladmin_config_read(w2); } else { - PRINTF("WARNING: unknown ladmin config key: %s\n", w1); + PRINTF("WARNING: unknown ladmin config key: %s\n", FString(w1)); } } - login_ip = inet_addr(loginserverip); + login_ip = inet_addr(loginserverip.c_str()); Iprintf("---End reading of Ladmin configuration file.\n"); @@ -3683,7 +2860,7 @@ void term_func(void) //------------------------ // Main function of ladmin //------------------------ -int do_init(int argc, char **argv) +int do_init(int argc, ZString *argv) { eathena_interactive_session = isatty(0); // read ladmin configuration diff --git a/src/login/login.cpp b/src/login/login.cpp index b3c7790..852cd3d 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -18,6 +18,8 @@ #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" +#include "../common/human_time_diff.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/md5calc.hpp" #include "../common/mmo.hpp" @@ -39,21 +41,21 @@ constexpr int END_ACCOUNT_NUM = 100000000; struct mmo_account { - char userid[24]; - char passwd[24]; + AccountName userid; + AccountPass passwd; int passwdenc; long account_id; long login_id1; long login_id2; long char_id; - char lastlogin[24]; + timestamp_milliseconds_buffer lastlogin; int sex; }; struct mmo_char_server { - char name[20]; + ServerName name; long ip; short port; int users; @@ -70,24 +72,24 @@ int new_account_flag = 0; static int login_port = 6900; static -char lan_char_ip[16]; +IP_String lan_char_ip; static uint8_t subneti[4]; static uint8_t subnetmaski[4]; static -char update_host[128] = ""; +FString update_host; static -char main_server[20] = ""; +ServerName main_server; static -char account_filename[1024] = "save/account.txt"; +FString account_filename = "save/account.txt"; static -char GM_account_filename[1024] = "conf/GM_account.txt"; +FString GM_account_filename = "conf/GM_account.txt"; static -char login_log_filename[1024] = "log/login.log"; +FString login_log_filename = "log/login.log"; static -char login_log_unknown_packets_filename[1024] = "log/login_unknown_packets.log"; +FString login_log_unknown_packets_filename = "log/login_unknown_packets.log"; static int save_unknown_packets = 0; static @@ -124,7 +126,7 @@ enum class ACO }; // TODO: port the new code for this -typedef std::array<char, 128> AccessEntry; +struct AccessEntry : VString<127> {}; static ACO access_order = ACO::DENY_ALLOW; @@ -141,17 +143,13 @@ int start_limited_time = -1; // Starting additional sec from now for the limit static int check_ip_flag = 1; // It's to check IP of a player between login-server and char-server (part of anti-hacking system) - -struct login_session_data : SessionData -{ - int md5keylen; - char md5key[20]; -}; - -void SessionDeleter::operator()(SessionData *sd) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-noreturn" +void SessionDeleter::operator()(SessionData *) { - really_delete1 static_cast<login_session_data *>(sd); + assert(false && "login server does not have sessions anymore"); } +#pragma GCC diagnostic pop constexpr int AUTH_FIFO_SIZE = 256; struct @@ -165,15 +163,17 @@ int auth_fifo_pos = 0; struct AuthData { int account_id, sex; - char userid[24], pass[40], lastlogin[24]; + AccountName userid; + AccountCrypt pass; + timestamp_milliseconds_buffer lastlogin; int logincount; int state; // packet 0x006a value + 1 (0: compte OK) - char email[40]; // e-mail (by default: a@a.com) - char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) + AccountEmail email; // e-mail (by default: a@a.com) + timestamp_seconds_buffer error_message; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) TimeT ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) TimeT connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - char last_ip[16]; // save of last IP of connection - char memo[255]; // a memo field + IP_String last_ip; // save of last IP of connection + VString<254> memo; // a memo field int account_reg2_num; struct global_reg account_reg2[ACCOUNT_REG2_NUM]; }; @@ -183,9 +183,9 @@ std::vector<AuthData> auth_data; static int admin_state = 0; static -char admin_pass[24] = ""; +AccountPass admin_pass; static -char gm_pass[64] = ""; +FString gm_pass; static int level_new_gm = 60; @@ -213,15 +213,15 @@ using e::VERSION_2; // Writing function of logs file //------------------------------ #define LOGIN_LOG(fmt, ...) \ - login_log(static_cast<const std::string&>(STRPRINTF(fmt, ## __VA_ARGS__))) + login_log(STRPRINTF(fmt, ## __VA_ARGS__)) static -void login_log(const_string line) +void login_log(XString line) { - FILE *logfp = fopen_(login_log_filename, "a"); + FILE *logfp = fopen(login_log_filename.c_str(), "a"); if (!logfp) return; log_with_timestamp(logfp, line); - fclose_(logfp); + fclose(logfp); } //---------------------------------------------------------------------- @@ -252,7 +252,7 @@ int read_gm_account(void) creation_time_GM_account_file = file_modified(GM_account_filename); - if ((fp = fopen_(GM_account_filename, "r")) == NULL) + if ((fp = fopen(GM_account_filename.c_str(), "r")) == NULL) { PRINTF("read_gm_account: GM accounts file [%s] not found.\n", GM_account_filename); @@ -266,8 +266,7 @@ int read_gm_account(void) // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) while (fgets(line, sizeof(line) - 1, fp) && c < 4000) { - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' - || line[0] == '\n' || line[0] == '\r') + if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' || line[0] == '\n') continue; GM_Account p {}; if (sscanf(line, "%d %hhu", &p.account_id, &p.level) != 2 @@ -310,7 +309,7 @@ int read_gm_account(void) } } } - fclose_(fp); + fclose(fp); PRINTF("read_gm_account: file '%s' readed (%d GM accounts found).\n", GM_account_filename, c); @@ -325,7 +324,7 @@ int read_gm_account(void) // (ip: IP to be tested, str: mask x.x.x.x/# or x.x.x.x/y.y.y.y) //-------------------------------------------------------------- static -int check_ipmask(struct in_addr ip, const char *str) +int check_ipmask(struct in_addr ip, ZString str) { unsigned int mask = 0, ip2; uint8_t *p = reinterpret_cast<uint8_t *>(&ip2), @@ -333,17 +332,17 @@ int check_ipmask(struct in_addr ip, const char *str) int i = 0; unsigned int m; - if (sscanf(str, "%hhu.%hhu.%hhu.%hhu/%n", + if (SSCANF(str, "%hhu.%hhu.%hhu.%hhu/%n", &p[0], &p[1], &p[2], &p[3], &i) != 4 || i == 0) return 0; - if (sscanf(str + i, "%hhu.%hhu.%hhu.%hhu", + if (SSCANF(str.oslice_t(i), "%hhu.%hhu.%hhu.%hhu", &p2[0], &p2[1], &p2[2], &p2[3]) == 4) { mask = ntohl(mask); } - else if (sscanf(str + i, "%u", &m) == 1 && m <= 32) + else if (SSCANF(str.oslice_t(i), "%u", &m) == 1 && m <= 32) { for (i = 0; i < m && i < 32; i++) mask = (mask >> 1) | 0x80000000; @@ -386,13 +385,12 @@ bool check_ip(struct in_addr ip) // If we have an answer, there is no guarantee to have a 100% correct value. // And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. // So, DNS notation isn't authorised for ip checking. - const char *buf = ip2str(ip, true); + VString<16> buf = ip2str_extradot(ip); for (const AccessEntry& ae : access_allow) { - const char *p = ae.data(); -#warning "TODO remove the strncmp part and use an IPAddress4 class" - if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p)) +#warning "TODO use an IPAddress4 and IPMask4 class" + if (buf.startswith(ae) || check_ipmask(ip, ae)) { flag = ACF::ALLOW; if (access_order == ACO::ALLOW_DENY) @@ -404,8 +402,7 @@ bool check_ip(struct in_addr ip) for (const AccessEntry& ae : access_deny) { - const char *p = ae.data(); - if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p)) + if (buf.startswith(ae) || check_ipmask(ip, ae)) { flag = ACF::DENY; return 0; @@ -439,12 +436,11 @@ bool check_ladminip(struct in_addr ip) // If we have an answer, there is no guarantee to have a 100% correct value. // And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. // So, DNS notation isn't authorised for ip checking. - const char *buf = ip2str(ip, true); + VString<16> buf = ip2str_extradot(ip); for (const AccessEntry& ae : access_ladmin) { - const char *p = ae.data(); - if (strncmp(p, buf, strlen(p)) == 0 || check_ipmask(ip, p)) + if (buf.startswith(ae) || check_ipmask(ip, ae)) return true; } @@ -454,34 +450,18 @@ bool check_ladminip(struct in_addr ip) //----------------------------------------------- // Search an account id // (return account pointer or nullptr (if not found)) -// If exact account name is not found, -// the function checks without case sensitive -// and returns index if only 1 account is found -// and similar to the searched name. //----------------------------------------------- static -AuthData *search_account(const char *account_name) +AuthData *search_account(AccountName account_name) { - int quantity = 0; - AuthData *index = nullptr; for (AuthData& ad : auth_data) { - // Without case sensitive check (increase the number of similar account names found) - if (strcasecmp(ad.userid, account_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(ad.userid, account_name) == 0) + if (ad.userid == account_name) return &ad; - quantity++; - index = &ad; } } - // Here, the exact account name is not found - // We return the found index of a similar account ONLY if there is 1 similar account - if (quantity == 1) - return index; - // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found return nullptr; } @@ -489,9 +469,10 @@ AuthData *search_account(const char *account_name) // Create a string to save the account in the account file //-------------------------------------------------------- static -std::string mmo_auth_tostr(const AuthData *p) +FString mmo_auth_tostr(const AuthData *p) { - std::string str = STRPRINTF( + MString str; + str += STRPRINTF( "%d\t" "%s\t" "%s\t" @@ -524,14 +505,14 @@ std::string mmo_auth_tostr(const AuthData *p) str += STRPRINTF("%s,%d ", p->account_reg2[i].str, p->account_reg2[i].value); - return str; + return FString(str); } static -bool extract(const_string line, AuthData *ad) +bool extract(XString line, AuthData *ad) { std::vector<struct global_reg> vars; - const_string sex = nullptr; // really only 1 char + VString<1> sex; if (!extract(line, record<'\t'>( &ad->account_id, @@ -555,19 +536,22 @@ bool extract(const_string line, AuthData *ad) { if (adi.account_id == ad->account_id) return false; - if (strcmp(adi.userid, ad->userid) == 0) + if (adi.userid == ad->userid) return false; } // If a password is not encrypted, we encrypt it now. // A password beginning with ! and - in the memo field is our magic - if (ad->pass[0] != '!' && ad->memo[0] == '-') { - strcpy(ad->pass, MD5_saltcrypt(ad->pass, make_salt())); - ad->memo[0] = '!'; + if (ad->pass[0] != '!' && ad->memo[0] == '-') + { + XString pass = ad->pass; + AccountPass plain = stringish<AccountPass>(pass); + ad->pass = MD5_saltcrypt(plain, make_salt()); + ad->memo = '!'; } if (sex.size() != 1) return false; - switch(sex.front()) + switch (sex.front()) { case 'S': case 's': ad->sex = 2; break; case 'M': case 'm': ad->sex = 1; break; @@ -575,12 +559,12 @@ bool extract(const_string line, AuthData *ad) default: return false; } - if (e_mail_check(ad->email) == 0) - strzcpy(ad->email, "a@a.com", 40); + if (!e_mail_check(ad->email)) + ad->email = DEFAULT_EMAIL; - if (ad->error_message[0] == '\0' || ad->state != 7) + if (!ad->error_message || ad->state != 7) // 7, because state is packet 0x006a value + 1 - strzcpy(ad->error_message, "-", 20); + ad->error_message = stringish<timestamp_seconds_buffer>("-"); if (vars.size() > ACCOUNT_REG2_NUM) return false; @@ -599,7 +583,7 @@ int mmo_auth_init(void) int GM_count = 0; int server_count = 0; - std::ifstream in(account_filename); + std::ifstream in(account_filename.c_str()); if (!in.is_open()) { // no account file -> no account -> no login, including char-server (ERROR) @@ -608,19 +592,11 @@ int mmo_auth_init(void) return 0; } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - if (line[0] == '/' && line[1] == '/') + if (line.startswith("//")) continue; - if (line.back() == '\r') - { -#ifdef WORKAROUND_GCC46_LIBRARY - line.resize(line.size() - 1); -#else - line.pop_back(); -#endif - } if (std::find_if(line.begin(), line.end(), [](unsigned char c) { return c < ' ' && c != '\t'; } ) != line.end()) @@ -649,7 +625,7 @@ int mmo_auth_init(void) account_id_count = ad.account_id + 1; } - std::string str = STRPRINTF("%s has %zu accounts (%d GMs, %d servers)\n", + FString str = STRPRINTF("%s has %zu accounts (%d GMs, %d servers)\n", account_filename, auth_data.size(), GM_count, server_count); PRINTF("%s: %s\n", __PRETTY_FUNCTION__, str); LOGIN_LOG("%s\n", line); @@ -696,7 +672,7 @@ void mmo_auth_sync(void) if (ad.account_id < 0) continue; - std::string line = mmo_auth_tostr(&ad); + FString line = mmo_auth_tostr(&ad); FPRINTF(fp, "%s\n", line); } FPRINTF(fp, "%d\t%%newid%%\n", account_id_count); @@ -804,7 +780,7 @@ void check_GM_file(TimerData *, tick_t) // Account creation (with e-mail check) //------------------------------------- static -int mmo_auth_new(struct mmo_account *account, char sex, const char *email) +int mmo_auth_new(struct mmo_account *account, char sex, AccountEmail email) { while (isGM(account_id_count) > 0) account_id_count++; @@ -812,19 +788,19 @@ int mmo_auth_new(struct mmo_account *account, char sex, const char *email) struct AuthData ad {}; ad.account_id = account_id_count++; - strzcpy(ad.userid, account->userid, 24); - strzcpy(ad.pass, MD5_saltcrypt(account->passwd, make_salt()), 40); - strcpy(ad.lastlogin, "-"); + ad.userid = account->userid; + ad.pass = MD5_saltcrypt(account->passwd, make_salt()); + ad.lastlogin = stringish<timestamp_milliseconds_buffer>("-"); ad.sex = (sex == 'M'); ad.logincount = 0; ad.state = 0; - if (e_mail_check(email) == 0) - strzcpy(ad.email, "a@a.com", 40); + if (!e_mail_check(email)) + ad.email = DEFAULT_EMAIL; else - strzcpy(ad.email, email, 40); + ad.email = email; - strcpy(ad.error_message, "-"); + ad.error_message = stringish<timestamp_seconds_buffer>("-"); ad.ban_until_time = TimeT(); if (start_limited_time < 0) @@ -838,8 +814,8 @@ int mmo_auth_new(struct mmo_account *account, char sex, const char *email) ad.connect_until_time = timestamp; } - strcpy(ad.last_ip, "-"); - strcpy(ad.memo, "!"); + ad.last_ip = stringish<IP_String>("-"); + ad.memo = "!"; ad.account_reg2_num = 0; auth_data.push_back(ad); @@ -852,51 +828,30 @@ int mmo_auth_new(struct mmo_account *account, char sex, const char *email) static int mmo_auth(struct mmo_account *account, int fd) { - int len, newaccount = 0; -#ifdef PASSWDENC - char md5str[64], md5bin[32]; -#endif + char new_account_sex = '\0'; - const char *ip = ip2str(session[fd]->client_addr.sin_addr); + IP_String ip = ip2str(session[fd]->client_addr.sin_addr); - len = strlen(account->userid) - 2; // Account creation with _M/_F - if (account->passwdenc == 0 && account->userid[len] == '_' && - (account->userid[len + 1] == 'F' || account->userid[len + 1] == 'M') + if (account->passwdenc == 0 + && (account->userid.endswith("_F") || account->userid.endswith("_M")) && new_account_flag == 1 && account_id_count <= END_ACCOUNT_NUM - && len >= 4 && strlen(account->passwd) >= 4) + && (account->userid.size() - 2) >= 4 && account->passwd.size() >= 4) { - if (new_account_flag == 1) - newaccount = 1; - account->userid[len] = '\0'; + new_account_sex = account->userid.back(); + account->userid = stringish<AccountName>(account->userid.orslice_h(2)); } // Strict account search - AuthData *ad = nullptr; - for (AuthData& adi : auth_data) - { - if (strcmp(account->userid, adi.userid) == 0) - { - ad = &adi; - break; - } - } - // if there is no creation request and strict account search fails, we do a no sensitive case research for index - if (newaccount == 0 && !ad) - { - ad = search_account(account->userid); - if (ad) - strzcpy(account->userid, ad->userid, 24); - // for the possible tests/checks afterwards (copy correcte sensitive case). - } + AuthData *ad = search_account(account->userid); if (ad) { int encpasswdok = 0; - if (newaccount) + if (new_account_sex) { LOGIN_LOG("Attempt of creation of an already existant account (account: %s_%c, ip: %s)\n", - account->userid, account->userid[len + 1], ip); + account->userid, new_account_sex, ip); return 9; // 9 = Account already exists } if ((!pass_ok(account->passwd, ad->pass)) && !encpasswdok) @@ -965,7 +920,7 @@ int mmo_auth(struct mmo_account *account, int fd) } else { - if (newaccount == 0) + if (new_account_sex == '\0') { LOGIN_LOG("Unknown account (account: %s, ip: %s)\n", account->userid, ip); @@ -973,11 +928,10 @@ int mmo_auth(struct mmo_account *account, int fd) } else { - int new_id = - mmo_auth_new(account, account->userid[len + 1], "a@a.com"); + int new_id = mmo_auth_new(account, new_account_sex, DEFAULT_EMAIL); LOGIN_LOG("Account creation and authentification accepted (account %s (id: %d), sex: %c, connection with _F/_M, ip: %s)\n", account->userid, new_id, - account->userid[len + 1], ip); + new_account_sex, ip); ad = &auth_data.back(); } } @@ -988,10 +942,10 @@ int mmo_auth(struct mmo_account *account, int fd) account->account_id = ad->account_id; account->login_id1 = random_::generate(); account->login_id2 = random_::generate(); - strzcpy(account->lastlogin, ad->lastlogin, 24); - strzcpy(ad->lastlogin, tmpstr, 24); + account->lastlogin = ad->lastlogin; + ad->lastlogin = tmpstr; account->sex = ad->sex; - strzcpy(ad->last_ip, ip, 16); + ad->last_ip = ip; ad->logincount++; return -1; // account OK @@ -1029,7 +983,7 @@ void char_anti_freeze_system(TimerData *, tick_t) static void parse_fromchar(int fd) { - const char *ip = ip2str(session[fd]->client_addr.sin_addr); + IP_String ip = ip2str(session[fd]->client_addr.sin_addr); int id; for (id = 0; id < MAX_SERVERS; id++) @@ -1144,15 +1098,12 @@ void parse_fromchar(int fd) // we receive a e-mail creation of an account with a default e-mail (no answer) case 0x2715: - { - int acc; - char email[40]; if (RFIFOREST(fd) < 46) return; - acc = RFIFOL(fd, 2); // speed up - RFIFO_STRING(fd, 6, email, 40); - remove_control_chars(email); - if (e_mail_check(email) == 0) + { + int acc = RFIFOL(fd, 2); + AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 6)); + if (!e_mail_check(email)) 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); else @@ -1160,10 +1111,9 @@ void parse_fromchar(int fd) for (AuthData& ad : auth_data) { if (ad.account_id == acc - && (strcmp(ad.email, "a@a.com") == 0 - || ad.email[0] == '\0')) + && (ad.email == DEFAULT_EMAIL || !ad.email)) { - strzcpy(ad.email, email, 40); + ad.email = email; LOGIN_LOG("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, acc, email, ip); goto x2715_out; @@ -1181,15 +1131,17 @@ void parse_fromchar(int fd) case 0x2716: if (RFIFOREST(fd) < 6) return; + { + int account_id = RFIFOL(fd, 2); //PRINTF("parse_fromchar: E-mail/limited time request from '%s' server (concerned account: %d)\n", server[id].name, RFIFOL(fd,2)); for (const AuthData& ad : auth_data) { - if (ad.account_id == RFIFOL(fd, 2)) + if (ad.account_id == account_id) { LOGIN_LOG("Char-server '%s': e-mail of the account %d found (ip: %s).\n", - server[id].name, RFIFOL(fd, 2), ip); + server[id].name, account_id, ip); WFIFOW(fd, 0) = 0x2717; - WFIFOL(fd, 2) = RFIFOL(fd, 2); + WFIFOL(fd, 2) = account_id; WFIFO_STRING(fd, 6, ad.email, 40); WFIFOL(fd, 46) = static_cast<time_t>(ad.connect_until_time); WFIFOSET(fd, 50); @@ -1197,7 +1149,8 @@ void parse_fromchar(int fd) } } LOGIN_LOG("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", - server[id].name, RFIFOL(fd, 2), ip); + server[id].name, account_id, ip); + } x2716_end: RFIFOSKIP(fd, 6); break; @@ -1215,10 +1168,9 @@ void parse_fromchar(int fd) WBUFL(buf, 2) = acc; WBUFL(buf, 6) = 0; size_t len = RFIFOW(fd, 2) - 8; - char pass[len]; - RFIFO_STRING(fd, 8, pass, len); + FString pass = RFIFO_STRING(fd, 8, len); - if (strcmp(pass, gm_pass) == 0) + if (pass == gm_pass) { // only non-GM can become GM if (isGM(acc) == 0) @@ -1227,9 +1179,7 @@ void parse_fromchar(int fd) if (level_new_gm > 0) { // if we can open the file to add the new GM - if ((fp = - fopen_(GM_account_filename, - "a")) != NULL) + if ((fp = fopen(GM_account_filename.c_str(), "a")) != NULL) { timestamp_seconds_buffer tmpstr; stamp_time(tmpstr); @@ -1237,7 +1187,7 @@ void parse_fromchar(int fd) "\n// %s: @GM command on account %d\n%d %d\n", tmpstr, acc, acc, level_new_gm); - fclose_(fp); + fclose(fp); WBUFL(buf, 6) = level_new_gm; read_gm_account(); send_GM_accounts(); @@ -1288,20 +1238,16 @@ void parse_fromchar(int fd) if (RFIFOREST(fd) < 86) return; { - int acc; - char actual_email[40], new_email[40]; - acc = RFIFOL(fd, 2); - RFIFO_STRING(fd, 6, actual_email, 40); - remove_control_chars(actual_email); - RFIFO_STRING(fd, 46, new_email, 40); - remove_control_chars(new_email); - if (e_mail_check(actual_email) == 0) + int acc = RFIFOL(fd, 2); + AccountEmail actual_email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 6).to_print()); + AccountEmail new_email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 46)); + if (!e_mail_check(actual_email)) LOGIN_LOG("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, acc, ip); - else if (e_mail_check(new_email) == 0) + else if (!e_mail_check(new_email)) LOGIN_LOG("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, acc, ip); - else if (strcasecmp(new_email, "a@a.com") == 0) + else if (new_email == DEFAULT_EMAIL) LOGIN_LOG("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, acc, ip); else @@ -1310,9 +1256,9 @@ void parse_fromchar(int fd) { if (ad.account_id == acc) { - if (strcasecmp(ad.email, actual_email) == 0) + if (ad.email == actual_email) { - strzcpy(ad.email, new_email, 40); + ad.email = new_email; LOGIN_LOG("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, acc, ad.userid, new_email, ip); @@ -1396,12 +1342,14 @@ void parse_fromchar(int fd) else timestamp = ad.ban_until_time; struct tm tmtime = timestamp; - tmtime.tm_year += static_cast<short>(RFIFOW(fd, 6)); - tmtime.tm_mon += static_cast<short>(RFIFOW(fd, 8)); - tmtime.tm_mday += static_cast<short>(RFIFOW(fd, 10)); - tmtime.tm_hour += static_cast<short>(RFIFOW(fd, 12)); - tmtime.tm_min += static_cast<short>(RFIFOW(fd, 14)); - tmtime.tm_sec += static_cast<short>(RFIFOW(fd, 16)); + HumanTimeDiff ban_diff; + RFIFO_STRUCT(fd, 6, ban_diff); + tmtime.tm_year += ban_diff.year; + tmtime.tm_mon += ban_diff.month; + tmtime.tm_mday += ban_diff.day; + tmtime.tm_hour += ban_diff.hour; + tmtime.tm_min += ban_diff.minute; + tmtime.tm_sec += ban_diff.second; timestamp = tmtime; if (timestamp.okay()) { @@ -1521,8 +1469,7 @@ void parse_fromchar(int fd) p < len && j < ACCOUNT_REG2_NUM; p += 36, j++) { - RFIFO_STRING(fd, p, ad.account_reg2[j].str, 32); - remove_control_chars(ad.account_reg2[j].str); + ad.account_reg2[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p).to_print()); ad.account_reg2[j].value = RFIFOL(fd, p + 32); } ad.account_reg2_num = j; @@ -1577,13 +1524,9 @@ void parse_fromchar(int fd) if (RFIFOREST(fd) < 54) return; { - int acc; - char actual_pass[24], new_pass[24]; - acc = RFIFOL(fd, 2); - RFIFO_STRING(fd, 6, actual_pass, 24); - remove_control_chars(actual_pass); - RFIFO_STRING(fd, 30, new_pass, 24); - remove_control_chars(new_pass); + int acc = RFIFOL(fd, 2); + AccountPass actual_pass = stringish<AccountPass>(RFIFO_STRING<24>(fd, 6).to_print()); + AccountPass new_pass = stringish<AccountPass>(RFIFO_STRING<24>(fd, 30).to_print()); int status = 0; @@ -1593,12 +1536,12 @@ void parse_fromchar(int fd) { if (pass_ok(actual_pass, ad.pass)) { - if (strlen(new_pass) < 4) + if (new_pass.size() < 4) status = 3; else { status = 1; - strcpy(ad.pass, MD5_saltcrypt(new_pass, make_salt())); + ad.pass = MD5_saltcrypt(new_pass, make_salt()); LOGIN_LOG("Char-server '%s': Change pass success (account: %d (%s), ip: %s.\n", server[id].name, acc, ad.userid, ip); @@ -1626,8 +1569,7 @@ void parse_fromchar(int fd) default: { - FILE *logfp; - logfp = fopen_(login_log_unknown_packets_filename, "a"); + FILE *logfp = fopen(login_log_unknown_packets_filename.c_str(), "a"); if (logfp) { timestamp_milliseconds_buffer timestr; @@ -1657,7 +1599,7 @@ void parse_fromchar(int fd) else if ((i + 1) % 16 == 0) { FPRINTF(logfp, " %s\n", tmpstr); - strzcpy(tmpstr, "", 16 + 1); + std::fill(tmpstr + 0, tmpstr + 17, '\0'); } } if (i % 16 != 0) @@ -1671,7 +1613,7 @@ void parse_fromchar(int fd) FPRINTF(logfp, " %s\n", tmpstr); } FPRINTF(logfp, "\n"); - fclose_(logfp); + fclose(logfp); } } PRINTF("parse_fromchar: Unknown packet 0x%x (from a char-server)! -> disconnection.\n", @@ -1690,9 +1632,7 @@ void parse_fromchar(int fd) static void parse_admin(int fd) { - char account_name[24]; - - const char *ip = ip2str(session[fd]->client_addr.sin_addr); + IP_String ip = ip2str(session[fd]->client_addr.sin_addr); if (session[fd]->eof) { @@ -1792,14 +1732,14 @@ void parse_admin(int fd) return; { struct mmo_account ma; - RFIFO_STRING(fd, 2, ma.userid, 24); - RFIFO_STRING(fd, 26, ma.passwd, 24); - strzcpy(ma.lastlogin, "-", 24); + ma.userid = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); + ma.passwd = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26).to_print()); + ma.lastlogin = stringish<timestamp_milliseconds_buffer>("-"); ma.sex = RFIFOB(fd, 50); WFIFOW(fd, 0) = 0x7931; WFIFOL(fd, 2) = -1; WFIFO_STRING(fd, 6, ma.userid, 24); - if (strlen(ma.userid) < 4 || strlen(ma.passwd) < 4) + if (ma.userid.size() < 4 || ma.passwd.size() < 4) { LOGIN_LOG("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", ip); @@ -1816,11 +1756,9 @@ void parse_admin(int fd) } else { - remove_control_chars(ma.userid); - remove_control_chars(ma.passwd); for (const AuthData& ad : auth_data) { - if (strncmp(ad.userid, ma.userid, 24) == 0) + if (ad.userid == ma.userid) { LOGIN_LOG("'ladmin': Attempt to create an already existing account (account: %s ip: %s)\n", ad.userid, ip); @@ -1828,11 +1766,8 @@ void parse_admin(int fd) } } { - int new_id; - char email[40]; - RFIFO_STRING(fd, 51, email, 40); - remove_control_chars(email); - new_id = mmo_auth_new(&ma, ma.sex, email); + AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 51)); + int 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", ma.userid, new_id, ma.sex, auth_data.back().email, ip); @@ -1851,12 +1786,10 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7933; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); 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; @@ -1870,11 +1803,11 @@ void parse_admin(int fd) ad->userid, ad->account_id, ip); { - std::string buf2 = mmo_auth_tostr(ad); + FString buf2 = mmo_auth_tostr(ad); LOGIN_LOG("%s\n", buf2); } // delete account - strzcpy(ad->userid, "", 24); + ad->userid = AccountName(); ad->account_id = -1; } else @@ -1894,15 +1827,13 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7935; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); AuthData *ad = search_account(account_name); if (ad) { WFIFO_STRING(fd, 6, ad->userid, 24); - char plain[24]; - RFIFO_STRING(fd, 26, plain, 24); - strzcpy(ad->pass, MD5_saltcrypt(plain, make_salt()), 40); + AccountPass plain = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26)); + ad->pass = MD5_saltcrypt(plain, make_salt()); 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,18 +1853,15 @@ void parse_admin(int fd) if (RFIFOREST(fd) < 50) return; { - char error_message[20]; - int statut; WFIFOW(fd, 0) = 0x7937; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); - statut = RFIFOL(fd, 26); - 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 - strcpy(error_message, "-"); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); + int statut = RFIFOL(fd, 26); + timestamp_seconds_buffer error_message = stringish<timestamp_seconds_buffer>(RFIFO_STRING<20>(fd, 30).to_print()); + if (statut != 7 || !error_message) + { + // 7: // 6 = Your are Prohibited to log in until %s + error_message = stringish<timestamp_seconds_buffer>("-"); } AuthData *ad = search_account(account_name); if (ad) @@ -1941,7 +1869,7 @@ void parse_admin(int fd) WFIFO_STRING(fd, 6, ad->userid, 24); WFIFOL(fd, 2) = ad->account_id; if (ad->state == statut - && strcmp(ad->error_message, error_message) == 0) + && ad->error_message == error_message) LOGIN_LOG("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); else @@ -1967,7 +1895,7 @@ void parse_admin(int fd) auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) } ad->state = statut; - strzcpy(ad->error_message, error_message, 20); + ad->error_message = error_message; } } else @@ -2010,14 +1938,12 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x793b; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); const AuthData *ad = search_account(account_name); if (ad) { WFIFO_STRING(fd, 6, ad->userid, 24); - char pass[24]; - RFIFO_STRING(fd, 26, pass, 24); + AccountPass pass = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26)); if (pass_ok(pass, ad->pass)) { WFIFOL(fd, 2) = ad->account_id; @@ -2027,9 +1953,8 @@ void parse_admin(int fd) } else { - remove_control_chars(pass); LOGIN_LOG("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", - ad->userid, pass, ip); + ad->userid, pass.to_print(), ip); } } else @@ -2046,10 +1971,10 @@ void parse_admin(int fd) case 0x793c: // Request to modify sex if (RFIFOREST(fd) < 27) return; + { WFIFOW(fd, 0) = 0x793d; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); WFIFO_STRING(fd, 6, account_name, 24); { char sex; @@ -2103,16 +2028,17 @@ void parse_admin(int fd) } } WFIFOSET(fd, 30); + } RFIFOSKIP(fd, 27); break; case 0x793e: // Request to modify GM level if (RFIFOREST(fd) < 27) return; + { WFIFOW(fd, 0) = 0x793f; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); WFIFO_STRING(fd, 6, account_name, 24); { char new_gm_level; @@ -2137,13 +2063,9 @@ void parse_admin(int fd) char line[512]; int GM_account, GM_level; int modify_flag; - if ((fp2 = - lock_fopen(GM_account_filename, - &lock)) != NULL) + if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) { - if ((fp = - fopen_(GM_account_filename, - "r")) != NULL) + if ((fp = fopen(GM_account_filename.c_str(), "r")) != NULL) { timestamp_seconds_buffer tmpstr; stamp_time(tmpstr); @@ -2152,12 +2074,8 @@ void parse_admin(int fd) while (fgets(line, sizeof(line) - 1, fp)) { while (line[0] != '\0' - && (line[strlen(line) - 1] - == '\n' - || line[strlen(line) - - 1] == '\r')) - line[strlen(line) - 1] = - '\0'; + && line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; if ((line[0] == '/' && line[1] == '/') || line[0] == '\0') @@ -2209,7 +2127,7 @@ void parse_admin(int fd) tmpstr, acc, ad->userid, acc, new_gm_level); - fclose_(fp); + fclose(fp); } else { @@ -2249,33 +2167,32 @@ void parse_admin(int fd) } } WFIFOSET(fd, 30); + } RFIFOSKIP(fd, 27); break; case 0x7940: // Request to modify e-mail if (RFIFOREST(fd) < 66) return; + { WFIFOW(fd, 0) = 0x7941; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); WFIFO_STRING(fd, 6, account_name, 24); { - char email[40]; - RFIFO_STRING(fd, 26, email, 40); - if (e_mail_check(email) == 0) + AccountEmail email = stringish<AccountEmail>(RFIFO_STRING<40>(fd, 26)); + if (!e_mail_check(email)) { LOGIN_LOG("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); } else { - remove_control_chars(email); AuthData *ad = search_account(account_name); if (ad) { WFIFO_STRING(fd, 6, ad->userid, 24); - strzcpy(ad->email, email, 40); + ad->email = email; WFIFOL(fd, 2) = ad->account_id; LOGIN_LOG("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", ad->userid, email, ip); @@ -2288,6 +2205,7 @@ void parse_admin(int fd) } } WFIFOSET(fd, 30); + } RFIFOSKIP(fd, 66); break; @@ -2298,27 +2216,23 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7943; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); 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); + ad->memo = ""; if (RFIFOW(fd, 26) == 0) { - strzcpy(ad->memo, "!", size_of_memo); + ad->memo = "!"; } else { size_t len = RFIFOW(fd, 26); - if (len > size_of_memo) - len = size_of_memo; - RFIFO_STRING(fd, 28, ad->memo, len); + // may truncate + ad->memo = RFIFO_STRING(fd, 28, len); } - ad->memo[size_of_memo - 1] = '\0'; - remove_control_chars(ad->memo); + ad->memo = ad->memo.to_print(); WFIFOL(fd, 2) = ad->account_id; LOGIN_LOG("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", ad->userid, ad->memo, ip); @@ -2340,8 +2254,7 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7945; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); const AuthData *ad = search_account(account_name); if (ad) { @@ -2365,24 +2278,27 @@ void parse_admin(int fd) case 0x7946: // Request to found an account name if (RFIFOREST(fd) < 6) return; + { + int account_id = RFIFOL(fd, 2); WFIFOW(fd, 0) = 0x7947; - WFIFOL(fd, 2) = RFIFOL(fd, 2); + WFIFOL(fd, 2) = account_id; WFIFO_ZERO(fd, 6, 24); for (const AuthData& ad : auth_data) { - if (ad.account_id == RFIFOL(fd, 2)) + if (ad.account_id == account_id) { 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); + ad.userid, account_id, ip); goto x7946_out; } } LOGIN_LOG("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", - RFIFOL(fd, 2), ip); + account_id, ip); WFIFO_STRING(fd, 6, "", 24); x7946_out: WFIFOSET(fd, 30); + } RFIFOSKIP(fd, 6); break; @@ -2392,10 +2308,9 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7949; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); TimeT timestamp = static_cast<time_t>(RFIFOL(fd, 26)); - timestamp_seconds_buffer tmpstr = "unlimited"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("unlimited"); if (timestamp) stamp_time(tmpstr, ×tamp); AuthData *ad = search_account(account_name); @@ -2431,12 +2346,11 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x794b; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); TimeT timestamp = static_cast<time_t>(RFIFOL(fd, 26)); if (timestamp <= TimeT::now()) timestamp = TimeT(); - timestamp_seconds_buffer tmpstr = "no banishment"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("no banishment"); if (timestamp) stamp_time(tmpstr, ×tamp); AuthData *ad = search_account(account_name); @@ -2486,8 +2400,7 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x794d; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); AuthData *ad = search_account(account_name); if (ad) { @@ -2501,25 +2414,27 @@ void parse_admin(int fd) else timestamp = ad->ban_until_time; struct tm tmtime = timestamp; - tmtime.tm_year += static_cast<short>(RFIFOW(fd, 26)); - tmtime.tm_mon += static_cast<short>(RFIFOW(fd, 28)); - tmtime.tm_mday += static_cast<short>(RFIFOW(fd, 30)); - tmtime.tm_hour += static_cast<short>(RFIFOW(fd, 32)); - tmtime.tm_min += static_cast<short>(RFIFOW(fd, 34)); - tmtime.tm_sec += static_cast<short>(RFIFOW(fd, 36)); + HumanTimeDiff ban_diff; + RFIFO_STRUCT(fd, 26, ban_diff); + tmtime.tm_year += ban_diff.year; + tmtime.tm_mon += ban_diff.month; + tmtime.tm_mday += ban_diff.day; + tmtime.tm_hour += ban_diff.hour; + tmtime.tm_min += ban_diff.minute; + tmtime.tm_sec += ban_diff.second; timestamp = tmtime; if (timestamp.okay()) { if (timestamp <= now) timestamp = TimeT(); - timestamp_seconds_buffer tmpstr = "no banishment"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("no banishment"); if (timestamp) stamp_time(tmpstr, ×tamp); LOGIN_LOG("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %lld (%s), ip: %s)\n", ad->userid, - static_cast<short>(RFIFOW(fd, 26)), static_cast<short>(RFIFOW(fd, 28)), - static_cast<short>(RFIFOW(fd, 30)), static_cast<short>(RFIFOW(fd, 32)), - static_cast<short>(RFIFOW(fd, 34)), static_cast<short>(RFIFOW(fd, 36)), + ban_diff.year, ban_diff.month, + ban_diff.day, ban_diff.hour, + ban_diff.minute, ban_diff.second, timestamp, tmpstr, ip); @@ -2543,16 +2458,16 @@ void parse_admin(int fd) } else { - timestamp_seconds_buffer tmpstr = "no banishment"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("no banishment"); if (ad->ban_until_time) stamp_time(tmpstr, &ad->ban_until_time); LOGIN_LOG("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %lld (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", ad->userid, ad->ban_until_time, tmpstr, - static_cast<short>(RFIFOW(fd, 26)), static_cast<short>(RFIFOW(fd, 28)), - static_cast<short>(RFIFOW(fd, 30)), static_cast<short>(RFIFOW(fd, 32)), - static_cast<short>(RFIFOW(fd, 34)), static_cast<short>(RFIFOW(fd, 36)), + ban_diff.year, ban_diff.month, + ban_diff.day, ban_diff.hour, + ban_diff.minute, ban_diff.second, ip); } WFIFOL(fd, 30) = static_cast<time_t>(ad->ban_until_time); @@ -2595,24 +2510,15 @@ void parse_admin(int fd) WFIFOW(fd, 2) = 0; size_t len = RFIFOL(fd, 4); - char message[len]; - RFIFO_STRING(fd, 8, message, len); - remove_control_chars(message); - const char *message_ptr = message; + FString message = RFIFO_STRING(fd, 8, len).to_print(); LOGIN_LOG("'ladmin': Receiving a message for broadcast (message: %s, ip: %s)\n", - message_ptr, ip); + message, ip); // send same message to all char-servers (no answer) uint8_t buf[len + 8]; 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); @@ -2625,8 +2531,7 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7951; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); AuthData *ad = search_account(account_name); if (ad) { @@ -2645,17 +2550,19 @@ void parse_admin(int fd) if (!timestamp || timestamp < now) timestamp = now; struct tm tmtime = timestamp; - tmtime.tm_year += static_cast<short>(RFIFOW(fd, 26)); - tmtime.tm_mon += static_cast<short>(RFIFOW(fd, 28)); - tmtime.tm_mday += static_cast<short>(RFIFOW(fd, 30)); - tmtime.tm_hour += static_cast<short>(RFIFOW(fd, 32)); - tmtime.tm_min += static_cast<short>(RFIFOW(fd, 34)); - tmtime.tm_sec += static_cast<short>(RFIFOW(fd, 36)); + HumanTimeDiff v_diff; + RFIFO_STRUCT(fd, 26, v_diff); + tmtime.tm_year += v_diff.year; + tmtime.tm_mon += v_diff.month; + tmtime.tm_mday += v_diff.day; + tmtime.tm_hour += v_diff.hour; + tmtime.tm_min += v_diff.minute; + tmtime.tm_sec += v_diff.second; timestamp = tmtime; if (timestamp.okay()) { - timestamp_seconds_buffer tmpstr = "unlimited"; - timestamp_seconds_buffer tmpstr2 = "unlimited"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("unlimited"); + timestamp_seconds_buffer tmpstr2 = stringish<timestamp_seconds_buffer>("unlimited"); if (ad->connect_until_time) stamp_time(tmpstr, &ad->connect_until_time); if (timestamp) @@ -2664,12 +2571,12 @@ void parse_admin(int fd) ad->userid, ad->connect_until_time, tmpstr, - static_cast<short>(RFIFOW(fd, 26)), - static_cast<short>(RFIFOW(fd, 28)), - static_cast<short>(RFIFOW(fd, 30)), - static_cast<short>(RFIFOW(fd, 32)), - static_cast<short>(RFIFOW(fd, 34)), - static_cast<short>(RFIFOW(fd, 36)), + v_diff.year, + v_diff.month, + v_diff.day, + v_diff.hour, + v_diff.minute, + v_diff.second, timestamp, tmpstr2, ip); @@ -2678,19 +2585,19 @@ void parse_admin(int fd) } else { - timestamp_seconds_buffer tmpstr = "unlimited"; + timestamp_seconds_buffer tmpstr = stringish<timestamp_seconds_buffer>("unlimited"); if (ad->connect_until_time) stamp_time(tmpstr, &ad->connect_until_time); LOGIN_LOG("'ladmin': Impossible to adjust a validity limit (account: %s, %lld (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", ad->userid, ad->connect_until_time, tmpstr, - static_cast<short>(RFIFOW(fd, 26)), - static_cast<short>(RFIFOW(fd, 28)), - static_cast<short>(RFIFOW(fd, 30)), - static_cast<short>(RFIFOW(fd, 32)), - static_cast<short>(RFIFOW(fd, 34)), - static_cast<short>(RFIFOW(fd, 36)), + v_diff.year, + v_diff.month, + v_diff.day, + v_diff.hour, + v_diff.minute, + v_diff.second, ip); WFIFOL(fd, 30) = 0; } @@ -2714,8 +2621,7 @@ void parse_admin(int fd) { WFIFOW(fd, 0) = 0x7953; WFIFOL(fd, 2) = -1; - RFIFO_STRING(fd, 2, account_name, 24); - remove_control_chars(account_name); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); const AuthData *ad = search_account(account_name); if (ad) { @@ -2731,7 +2637,7 @@ 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 = ad->memo.size() + 1; WFIFOW(fd, 148) = 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", @@ -2774,7 +2680,7 @@ 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 = ad.memo.size() + 1; WFIFOW(fd, 148) = len; WFIFO_STRING(fd, 150, ad.memo, len); WFIFOSET(fd, 150 + len); @@ -2803,8 +2709,7 @@ void parse_admin(int fd) default: { - FILE *logfp; - logfp = fopen_(login_log_unknown_packets_filename, "a"); + FILE *logfp = fopen(login_log_unknown_packets_filename.c_str(), "a"); if (logfp) { timestamp_milliseconds_buffer timestr; @@ -2834,7 +2739,7 @@ void parse_admin(int fd) else if ((i + 1) % 16 == 0) { FPRINTF(logfp, " %s\n", tmpstr); - strzcpy(tmpstr, "", 16 + 1); + std::fill(tmpstr + 0, tmpstr + 17, '\0'); } } if (i % 16 != 0) @@ -2848,7 +2753,7 @@ void parse_admin(int fd) FPRINTF(logfp, " %s\n", tmpstr); } FPRINTF(logfp, "\n"); - fclose_(logfp); + fclose(logfp); } } LOGIN_LOG("'ladmin': End of connection, unknown packet (ip: %s)\n", @@ -2900,7 +2805,7 @@ void parse_login(int fd) int result, j; uint8_t *p = reinterpret_cast<uint8_t *>(&session[fd]->client_addr.sin_addr); - const char *ip = ip2str(session[fd]->client_addr.sin_addr); + IP_String ip = ip2str(session[fd]->client_addr.sin_addr); if (session[fd]->eof) { @@ -2916,8 +2821,7 @@ void parse_login(int fd) { if (RFIFOREST(fd) >= ((RFIFOW(fd, 0) == 0x64) ? 55 : 47)) { - char account_name[24]; - RFIFO_STRING(fd, 6, account_name, 24); + AccountName account_name = stringish<AccountName>(RFIFO_STRING<24>(fd, 6)); PRINTF("parse_login: connection #%d, packet: 0x%x (with being read: %zu), account: %s.\n", fd, RFIFOW(fd, 0), RFIFOREST(fd), account_name); @@ -2927,8 +2831,7 @@ void parse_login(int fd) { if (RFIFOREST(fd) >= 86) { - char server_name[16]; - RFIFO_STRING(fd, 60, server_name, 16); + ServerName server_name = stringish<ServerName>(RFIFO_STRING<20>(fd, 60)); PRINTF("parse_login: connection #%d, packet: 0x%x (with being read: %zu), server: %s.\n", fd, RFIFOW(fd, 0), RFIFOREST(fd), server_name); @@ -2957,10 +2860,8 @@ void parse_login(int fd) if (RFIFOREST(fd) < 55) return; - RFIFO_STRING(fd, 6, account.userid, 24); - remove_control_chars(account.userid); - RFIFO_STRING(fd, 30, account.passwd, 24); - remove_control_chars(account.passwd); + account.userid = stringish<AccountName>(RFIFO_STRING<24>(fd, 6).to_print()); + account.passwd = stringish<AccountPass>(RFIFO_STRING<24>(fd, 30).to_print()); account.passwdenc = 0; LOGIN_LOG("Request for connection (non encryption mode) of %s (ip: %s).\n", @@ -3022,10 +2923,9 @@ void parse_login(int fd) */ // if (version_2 & VERSION_2_UPDATEHOST) { - size_t host_len = strlen(update_host); - if (host_len > 0) + if (update_host) { - host_len++; + size_t host_len = update_host.size() + 1; WFIFOW(fd, 0) = 0x63; WFIFOW(fd, 2) = 4 + host_len; WFIFO_STRING(fd, 4, update_host, host_len); @@ -3041,7 +2941,7 @@ void parse_login(int fd) if (server_fd[i] >= 0) { if (lan_ip_check(p)) - WFIFOL(fd, 47 + server_num * 32) = inet_addr(lan_char_ip); + WFIFOL(fd, 47 + server_num * 32) = inet_addr(lan_char_ip.c_str()); else WFIFOL(fd, 47 + server_num * 32) = server[i].ip; WFIFOW(fd, 47 + server_num * 32 + 4) = server[i].port; @@ -3118,56 +3018,15 @@ void parse_login(int fd) RFIFOSKIP(fd, (RFIFOW(fd, 0) == 0x64) ? 55 : 47); break; - case 0x01db: // Sending request of the coding key - case 0x791a: // Sending request of the coding key (administration packet) - { - if (session[fd]->session_data) - { - PRINTF("login: abnormal request of MD5 key (already opened session).\n"); - session[fd]->eof = 1; - return; - } - std::unique_ptr<login_session_data, SessionDeleter> ld; - ld = make_unique<login_session_data, SessionDeleter>(); - if (RFIFOW(fd, 0) == 0x01db) - { - LOGIN_LOG("Sending request of the coding key (ip: %s)\n", - ip); - } - else - { - LOGIN_LOG("'ladmin': Sending request of the coding key (ip: %s)\n", - ip); - } - // TODO fix or get rid of this - // Creation of the coding key - strzcpy(ld->md5key, "", sizeof(ld->md5key)); - ld->md5keylen = random_::in(12, 15); - for (int i = 0; i < ld->md5keylen; i++) - ld->md5key[i] = random_::in(1, 255); - - RFIFOSKIP(fd, 2); - WFIFOW(fd, 0) = 0x01dc; - WFIFOW(fd, 2) = 4 + ld->md5keylen + 1; - WFIFO_STRING(fd, 4, ld->md5key, ld->md5keylen + 1); - WFIFOSET(fd, WFIFOW(fd, 2)); - session[fd]->session_data = std::move(ld); - } - break; - case 0x2710: // Connection request of a char-server if (RFIFOREST(fd) < 86) return; { int len; - char server_name[20]; - RFIFO_STRING(fd, 2, account.userid, 24); - remove_control_chars(account.userid); - RFIFO_STRING(fd, 26, account.passwd, 24); - remove_control_chars(account.passwd); + account.userid = stringish<AccountName>(RFIFO_STRING<24>(fd, 2).to_print()); + account.passwd = stringish<AccountPass>(RFIFO_STRING<24>(fd, 26).to_print()); account.passwdenc = 0; - RFIFO_STRING(fd, 60, server_name, 20); - remove_control_chars(server_name); + ServerName server_name = stringish<ServerName>(RFIFO_STRING<20>(fd, 60).to_print()); 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), RFIFOB(fd, 56), RFIFOB(fd, 57), RFIFOW(fd, 58), @@ -3178,7 +3037,7 @@ void parse_login(int fd) { // If this is the main server, and we don't already have a main server if (server_fd[0] <= 0 - && strcasecmp(server_name, main_server) == 0) + && server_name == main_server) { account.account_id = 0; } @@ -3208,7 +3067,7 @@ void parse_login(int fd) server[account.account_id] = mmo_char_server{}; server[account.account_id].ip = RFIFOL(fd, 54); server[account.account_id].port = RFIFOW(fd, 58); - strzcpy(server[account.account_id].name, server_name, 20); + server[account.account_id].name = server_name; server[account.account_id].users = 0; server[account.account_id].maintenance = RFIFOW(fd, 82); server[account.account_id].is_new = RFIFOW(fd, 84); @@ -3278,16 +3137,13 @@ void parse_login(int fd) } else { - struct login_session_data *ld = static_cast<login_session_data *>(session[fd]->session_data.get()); if (RFIFOW(fd, 2) == 0) { // non encrypted password - char password[24]; - RFIFO_STRING(fd, 4, password, 24); - remove_control_chars(password); + AccountPass password = stringish<AccountPass>(RFIFO_STRING<24>(fd, 4).to_print()); // If remote administration is enabled and password sent by client matches password read from login server configuration file if ((admin_state == 1) - && (strcmp(password, admin_pass) == 0)) + && (password == admin_pass)) { LOGIN_LOG("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", password, ip); @@ -3303,39 +3159,10 @@ void parse_login(int fd) password, ip); } else - { // encrypted password - if (!ld) - PRINTF("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); - else + { + // encrypted password { - char md5str[64] = ""; - uint8_t md5bin[32]; - if (RFIFOW(fd, 2) == 1) - { - strcpy(md5str, ld->md5key); // 20 - strcat(md5str, admin_pass); // 24 - } - else if (RFIFOW(fd, 2) == 2) - { - 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) - && 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); - PRINTF("Connection of a remote administration accepted (encrypted password).\n"); - WFIFOB(fd, 2) = 0; - session[fd]->func_parse = parse_admin; - } - else if (admin_state != 1) - LOGIN_LOG("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", - ip); - else - LOGIN_LOG("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", + LOGIN_LOG("'ladmin'-login: Connection in administration mode REFUSED - encrypted login is disabled (ip: %s)\n", ip); } } @@ -3347,8 +3174,7 @@ void parse_login(int fd) default: if (save_unknown_packets) { - FILE *logfp; - logfp = fopen_(login_log_unknown_packets_filename, "a"); + FILE *logfp = fopen(login_log_unknown_packets_filename.c_str(), "a"); if (logfp) { timestamp_milliseconds_buffer timestr; @@ -3381,7 +3207,7 @@ void parse_login(int fd) else if ((i + 1) % 16 == 0) { FPRINTF(logfp, " %s\n", tmpstr); - strzcpy(tmpstr, "", 16 + 1); + std::fill(tmpstr + 0, tmpstr + 17, '\0'); } } if (i % 16 != 0) @@ -3395,7 +3221,7 @@ void parse_login(int fd) FPRINTF(logfp, " %s\n", tmpstr); } FPRINTF(logfp, "\n"); - fclose_(logfp); + fclose(logfp); } } LOGIN_LOG("End of connection, unknown packet (ip: %s)\n", ip); @@ -3410,12 +3236,12 @@ void parse_login(int fd) // Reading Lan Support configuration //---------------------------------- static -int login_lan_config_read(const char *lancfgName) +int login_lan_config_read(ZString lancfgName) { struct hostent *h = NULL; // set default configuration - strcpy(lan_char_ip, "127.0.0.1"); + lan_char_ip = stringish<IP_String>("127.0.0.1"); subneti[0] = 127; subneti[1] = 0; subneti[2] = 0; @@ -3423,7 +3249,7 @@ int login_lan_config_read(const char *lancfgName) for (int j = 0; j < 4; j++) subnetmaski[j] = 255; - std::ifstream in(lancfgName); + std::ifstream in(lancfgName.c_str()); if (!in.is_open()) { @@ -3434,10 +3260,11 @@ int login_lan_config_read(const char *lancfgName) PRINTF("---Start reading Lan Support configuration file\n"); - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; @@ -3447,7 +3274,7 @@ int login_lan_config_read(const char *lancfgName) h = gethostbyname(w2.c_str()); if (h != NULL) { - sprintf(lan_char_ip, "%d.%d.%d.%d", + SNPRINTF(lan_char_ip, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), @@ -3455,7 +3282,7 @@ int login_lan_config_read(const char *lancfgName) } else { - strzcpy(lan_char_ip, w2.c_str(), sizeof(lan_char_ip)); + lan_char_ip = stringish<IP_String>(w2); } PRINTF("LAN IP of char-server: %s.\n", lan_char_ip); } @@ -3499,7 +3326,8 @@ int login_lan_config_read(const char *lancfgName) } else { - PRINTF("WARNING: unknown lan-config key: %s\n", w1); + FString w1z = w1; + PRINTF("WARNING: unknown lan-config key: %s\n", w1z); } } @@ -3513,7 +3341,7 @@ int login_lan_config_read(const char *lancfgName) // sub-network check of the char-server { unsigned char p[4]; - sscanf(lan_char_ip, "%hhu.%hhu.%hhu.%hhu", + SSCANF(lan_char_ip, "%hhu.%hhu.%hhu.%hhu", &p[0], &p[1], &p[2], &p[3]); PRINTF("LAN test of LAN IP of the char-server: "); if (lan_ip_check(p) == 0) @@ -3532,9 +3360,9 @@ int login_lan_config_read(const char *lancfgName) // Reading general configuration file //----------------------------------- static -int login_config_read(const char *cfgName) +int login_config_read(ZString cfgName) { - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { PRINTF("Configuration file (%s) not found.\n", cfgName); @@ -3543,20 +3371,21 @@ int login_config_read(const char *cfgName) PRINTF("---Start reading of Login Server configuration file (%s)\n", cfgName); - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; if (w1 == "admin_state") { - admin_state = config_switch(w2.c_str()); + admin_state = config_switch(w2); } else if (w1 == "admin_pass") { - strzcpy(admin_pass, w2.c_str(), sizeof(admin_pass)); + admin_pass = stringish<AccountPass>(w2); } else if (w1 == "ladminallowip") { @@ -3573,20 +3402,19 @@ int login_config_read(const char *cfgName) // set to all access_ladmin.push_back(AccessEntry()); } - else if (!w2.empty() + else if (w2 && !(access_ladmin.size() == 1 && access_ladmin.front() == AccessEntry())) { // don't add IP if already 'all' - AccessEntry n; - strzcpy(n.data(), w2.c_str(), sizeof(n)); + AccessEntry n = stringish<AccessEntry>(w2); access_ladmin.push_back(n); } } } else if (w1 == "gm_pass") { - strzcpy(gm_pass, w2.c_str(), sizeof(gm_pass)); + gm_pass = w2; } else if (w1 == "level_new_gm") { @@ -3594,7 +3422,7 @@ int login_config_read(const char *cfgName) } else if (w1 == "new_account") { - new_account_flag = config_switch(w2.c_str()); + new_account_flag = config_switch(w2); } else if (w1 == "login_port") { @@ -3602,11 +3430,11 @@ int login_config_read(const char *cfgName) } else if (w1 == "account_filename") { - strzcpy(account_filename, w2.c_str(), sizeof(account_filename)); + account_filename = w2; } else if (w1 == "gm_account_filename") { - strzcpy(GM_account_filename, w2.c_str(), sizeof(GM_account_filename)); + GM_account_filename = w2; } else if (w1 == "gm_account_filename_check_timer") { @@ -3614,28 +3442,27 @@ int login_config_read(const char *cfgName) } else if (w1 == "login_log_filename") { - strzcpy(login_log_filename, w2.c_str(), sizeof(login_log_filename)); + login_log_filename = w2; } else if (w1 == "login_log_unknown_packets_filename") { - strzcpy(login_log_unknown_packets_filename, w2.c_str(), - sizeof(login_log_unknown_packets_filename)); + login_log_unknown_packets_filename = w2; } else if (w1 == "save_unknown_packets") { - save_unknown_packets = config_switch(w2.c_str()); + save_unknown_packets = config_switch(w2); } else if (w1 == "display_parse_login") { - display_parse_login = config_switch(w2.c_str()); // 0: no, 1: yes + display_parse_login = config_switch(w2); // 0: no, 1: yes } else if (w1 == "display_parse_admin") { - display_parse_admin = config_switch(w2.c_str()); // 0: no, 1: yes + display_parse_admin = config_switch(w2); // 0: no, 1: yes } else if (w1 == "display_parse_fromchar") { - display_parse_fromchar = config_switch(w2.c_str()); // 0: no, 1: yes (without packet 0x2714), 2: all packets + display_parse_fromchar = config_switch(w2); // 0: no, 1: yes (without packet 0x2714), 2: all packets } else if (w1 == "min_level_to_connect") { @@ -3643,7 +3470,7 @@ int login_config_read(const char *cfgName) } else if (w1 == "add_to_unlimited_account") { - add_to_unlimited_account = config_switch(w2.c_str()); + add_to_unlimited_account = config_switch(w2); } else if (w1 == "start_limited_time") { @@ -3651,7 +3478,7 @@ int login_config_read(const char *cfgName) } else if (w1 == "check_ip_flag") { - check_ip_flag = config_switch(w2.c_str()); + check_ip_flag = config_switch(w2); } else if (w1 == "order") { @@ -3679,13 +3506,12 @@ int login_config_read(const char *cfgName) // set to all access_allow.push_back(AccessEntry()); } - else if (!w2.empty() + else if (w2 && !(access_allow.size() == 1 && access_allow.front() == AccessEntry())) { // don't add IP if already 'all' - AccessEntry n; - strzcpy(n.data(), w2.c_str(), sizeof(n)); + AccessEntry n = stringish<AccessEntry>(w2); access_allow.push_back(n); } } @@ -3705,20 +3531,19 @@ int login_config_read(const char *cfgName) // set to all access_deny.push_back(AccessEntry()); } - else if (!w2.empty() + else if (w2 && !(access_deny.size() == 1 && access_deny.front() == AccessEntry())) { // don't add IP if already 'all' - AccessEntry n; - strzcpy(n.data(), w2.c_str(), sizeof(n)); + AccessEntry n = stringish<AccessEntry>(w2); access_deny.push_back(n); } } } else if (w1 == "anti_freeze_enable") { - anti_freeze_enable = config_switch(w2.c_str()); + anti_freeze_enable = config_switch(w2); } else if (w1 == "anti_freeze_interval") { @@ -3728,19 +3553,20 @@ int login_config_read(const char *cfgName) } else if (w1 == "import") { - login_config_read(w2.c_str()); + login_config_read(w2); } else if (w1 == "update_host") { - strzcpy(update_host, w2.c_str(), sizeof(update_host)); + update_host = w2; } else if (w1 == "main_server") { - strzcpy(main_server, w2.c_str(), sizeof(main_server)); + main_server = stringish<ServerName>(w2); } else { - PRINTF("WARNING: unknown login config key: %s\n", w1); + FString w1z = w1; + PRINTF("WARNING: unknown login config key: %s\n", w1z); } } @@ -3763,23 +3589,23 @@ void display_conf_warnings(void) if (admin_state == 1) { - if (admin_pass[0] == '\0') + if (!admin_pass) { PRINTF("***WARNING: Administrator password is void (admin_pass).\n"); } - else if (strcmp(admin_pass, "admin") == 0) + else if (admin_pass == stringish<AccountPass>("admin")) { PRINTF("***WARNING: You are using the default administrator password (admin_pass).\n"); PRINTF(" We highly recommend that you change it.\n"); } } - if (gm_pass[0] == '\0') + if (!gm_pass) { PRINTF("***WARNING: 'To GM become' password is void (gm_pass).\n"); PRINTF(" We highly recommend that you set one password.\n"); } - else if (strcmp(gm_pass, "gm") == 0) + else if (gm_pass == "gm") { PRINTF("***WARNING: You are using the default GM password (gm_pass).\n"); PRINTF(" We highly recommend that you change it.\n"); @@ -3910,8 +3736,6 @@ void display_conf_warnings(void) PRINTF(" But, you refuse ALL IP!\n"); } } - - return; } //------------------------------- @@ -3929,13 +3753,13 @@ void save_config_in_log(void) if (admin_state != 1) LOGIN_LOG("- with no remote administration.\n"); - else if (admin_pass[0] == '\0') + else if (!admin_pass) LOGIN_LOG("- with a remote administration with a VOID password.\n"); - else if (strcmp(admin_pass, "admin") == 0) + else if (admin_pass == stringish<AccountPass>("admin")) LOGIN_LOG("- with a remote administration with the DEFAULT password.\n"); else LOGIN_LOG("- with a remote administration with the password of %zu character(s).\n", - strlen(admin_pass)); + admin_pass.size()); if (access_ladmin.empty() || (access_ladmin.size() == 1 && access_ladmin.front() == AccessEntry())) { @@ -3945,16 +3769,16 @@ void save_config_in_log(void) { LOGIN_LOG("- to accept following IP for remote administration:\n"); for (const AccessEntry& ae : access_ladmin) - LOGIN_LOG(" %s\n", ae.data()); + LOGIN_LOG(" %s\n", ae); } - if (gm_pass[0] == '\0') + if (!gm_pass) LOGIN_LOG("- with a VOID 'To GM become' password (gm_pass).\n"); - else if (strcmp(gm_pass, "gm") == 0) + else if (gm_pass == "gm") LOGIN_LOG("- with the DEFAULT 'To GM become' password (gm_pass).\n"); else LOGIN_LOG("- with a 'To GM become' password (gm_pass) of %zu character(s).\n", - strlen(gm_pass)); + gm_pass.size()); if (level_new_gm == 0) LOGIN_LOG("- to refuse any creation of GM with @gm.\n"); else @@ -4037,7 +3861,7 @@ void save_config_in_log(void) { LOGIN_LOG("- with the IP security order: 'deny,allow' (allow if not deny). Refused IP are:\n"); for (const AccessEntry& ae : access_deny) - LOGIN_LOG(" %s\n", ae.data()); + LOGIN_LOG(" %s\n", ae); } } else if (access_order == ACO::ALLOW_DENY) @@ -4054,7 +3878,7 @@ void save_config_in_log(void) { LOGIN_LOG("- with the IP security order: 'allow,deny' (deny if not allow). Authorised IP are:\n"); for (const AccessEntry& ae : access_allow) - LOGIN_LOG(" %s\n", ae.data()); + LOGIN_LOG(" %s\n", ae); } } else @@ -4078,11 +3902,11 @@ void save_config_in_log(void) { LOGIN_LOG(" Authorised IP are:\n"); for (const AccessEntry& ae : access_allow) - LOGIN_LOG(" %s\n", ae.data()); + LOGIN_LOG(" %s\n", ae); } LOGIN_LOG(" Refused IP are:\n"); for (const AccessEntry& ae : access_deny) - LOGIN_LOG(" %s\n", ae.data()); + LOGIN_LOG(" %s\n", ae); } } } @@ -4111,13 +3935,19 @@ void term_func(void) //------------------------------ // Main function of login-server //------------------------------ -int do_init(int argc, char **argv) +int do_init(int argc, ZString *argv) { // read login-server configuration - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + if (argc > 1) + login_config_read(argv[1]); + else + login_config_read(LOGIN_CONF_NAME); display_conf_warnings(); // not in login_config_read, because we can use 'import' option, and display same message twice or more save_config_in_log(); // not before, because log file name can be changed - login_lan_config_read((argc > 1) ? argv[1] : LAN_CONF_NAME); + if (argc > 2) + login_lan_config_read(argv[2]); + else + login_lan_config_read(LAN_CONF_NAME); for (int i = 0; i < AUTH_FIFO_SIZE; i++) auth_fifo[i].delflag = 1; diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 1926f83..18ea0e0 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -8,9 +8,12 @@ #include "../common/core.hpp" #include "../common/cxxstdio.hpp" +#include "../common/extract.hpp" +#include "../common/human_time_diff.hpp" +#include "../common/io.hpp" #include "../common/mmo.hpp" -#include "../common/random.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" #include "../common/utils2.hpp" @@ -34,7 +37,7 @@ #include "../poison.hpp" #define ATCOMMAND_FUNC(x) static \ -int atcommand_##x(const int fd, dumb_ptr<map_session_data> sd, const char *, const char *message) +int atcommand_##x(const int fd, dumb_ptr<map_session_data> sd, ZString message) ATCOMMAND_FUNC(setup); ATCOMMAND_FUNC(broadcast); ATCOMMAND_FUNC(localbroadcast); @@ -175,13 +178,16 @@ ATCOMMAND_FUNC(doomspot); *AtCommandInfo atcommand_info[]構造体の定義 *------------------------------------------ */ - struct AtCommandInfo { - const char *command; + ZString command; int level; - int(*proc)(const int, dumb_ptr<map_session_data>, - const char *command, const char *message); + int (*proc)(const int fd, dumb_ptr<map_session_data> sd, ZString message); + + + AtCommandInfo(ZString c, int l, int (*p)(const int, dumb_ptr<map_session_data>, ZString)) + : command(c), level(l), proc(p) + {} }; // First char of commands is configured in atcommand_athena.conf. Leave @ in this list for default value. @@ -335,9 +341,50 @@ AtCommandInfo atcommand_info[] = {"@doomspot", 60, atcommand_doomspot}, // add new commands before this line - {NULL, 1, NULL} + {ZString(), 1, nullptr} }; +// If your last arg is not a ZString, you probably wanted extract() +// but not always ... +static +bool asplit(ZString raw, ZString *last) +{ + *last = raw; + return true; +} + +// but this case is just so common and useful. In fact, is the previous ever used otherwise? +static +bool asplit(ZString raw, CharName *last) +{ + if (raw.size() < 4 || raw.size() > 23) + return false; + *last = stringish<CharName>(raw); + return true; +} + +// huh. +static +bool asplit(ZString raw, NpcName *last) +{ + if (!raw || raw.size() > 23) + return false; + *last = stringish<NpcName>(raw); + return true; +} + +// This differs from extract() in that it does not consume extra spaces. +template<class F, class... R, typename=typename std::enable_if<sizeof...(R) != 0>::type> +bool asplit(ZString raw, F *first_arg, R *... rest_args) +{ + ZString::iterator it = std::find(raw.begin(), raw.end(), ' '); + XString frist = raw.xislice_h(it); + while (*it == ' ') + ++it; + ZString rest = raw.xislice_t(it); + return extract(frist, first_arg) && asplit(rest, rest_args...); +} + /*========================================== * get_atcommand_level @コマンドの必要レベルを取得 *------------------------------------------ @@ -357,28 +404,28 @@ FILE *get_gm_log(); /*======================================== * At-command logging */ -void log_atcommand(dumb_ptr<map_session_data> sd, const_string cmd) +void log_atcommand(dumb_ptr<map_session_data> sd, XString cmd) { FILE *fp = get_gm_log(); if (!fp) return; timestamp_seconds_buffer tmpstr; stamp_time(tmpstr); - fprintf(fp, "[%s] %s(%d,%d) %s(%d) : ", + FPRINTF(fp, "[%s] %s(%d,%d) %s(%d) : ", tmpstr, sd->bl_m->name_, sd->bl_x, sd->bl_y, sd->status.name, sd->status.account_id); fwrite(cmd.data(), 1, cmd.size(), fp); } -std::string gm_logfile_name; +FString gm_logfile_name; /*========================================== * Log a timestamped line to GM log file *------------------------------------------ */ FILE *get_gm_log() { - if (gm_logfile_name.empty()) + if (!gm_logfile_name) return NULL; struct tm ctime = TimeT::now(); @@ -393,65 +440,56 @@ FILE *get_gm_log() return gm_logfile; last_logfile_nr = logfile_nr; - std::string fullname = STRPRINTF("%s.%04d-%02d", + FString fullname = STRPRINTF("%s.%04d-%02d", gm_logfile_name, year, month); if (gm_logfile) - fclose_(gm_logfile); + fclose(gm_logfile); - gm_logfile = fopen_(fullname.c_str(), "a"); + gm_logfile = fopen(fullname.c_str(), "a"); if (!gm_logfile) { perror("GM log file"); - gm_logfile_name.clear(); + gm_logfile_name = FString(); } return gm_logfile; } static -AtCommandInfo *atcommand(const int level, const char *message); +AtCommandInfo *atcommand(const int level, ZString message); /*========================================== *is_atcommand @コマンドに存在するかどうか確認する *------------------------------------------ */ bool is_atcommand(const int fd, dumb_ptr<map_session_data> sd, - const char *message, int gmlvl) + ZString message, int gmlvl) { nullpo_retr(false, sd); - if (!message || message[0] != '@') + if (!message.startswith('@')) return false; AtCommandInfo *info = atcommand(gmlvl > 0 ? gmlvl : pc_isGM(sd), message); if (!info) { - std::string output = STRPRINTF("GM command not found: %s", + FString output = STRPRINTF("GM command not found: %s", message); clif_displaymessage(fd, output); return true; // don't show in chat } { - const char *str = message; - const char *p = message; - // split the first word - while (*p && !isspace(*p)) - p++; - size_t len = p - str; - char command[len + 1]; - strzcpy(command, str, len + 1); - // skip the spaces; pass as argv - while (isspace(*p)) - p++; + XString command; + ZString arg; + asplit(message, &command, &arg); { - if (info->proc(fd, sd, command, p) != 0) + if (info->proc(fd, sd, arg) != 0) { // Command can not be executed - const char *command_ = command; - std::string output = STRPRINTF("%s failed.", command_); + FString output = STRPRINTF("%s failed.", FString(command)); clif_displaymessage(fd, output); } else @@ -469,28 +507,27 @@ bool is_atcommand(const int fd, dumb_ptr<map_session_data> sd, * *------------------------------------------ */ -AtCommandInfo *atcommand(const int level, const char *message) +AtCommandInfo *atcommand(const int level, ZString message) { - const char *p = message; + ZString p = message; if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd) return nullptr; - if (!p || !*p) + if (!p) { FPRINTF(stderr, "at command message is empty\n"); return nullptr; } - if (*p == '@') - { // check first char. - char command[101]; + if (p.startswith('@')) + { + ZString::iterator space = std::find(p.begin(), p.end(), ' '); + XString command = p.xislice_h(space); int i = 0; - sscanf(p, "%100s", command); - command[sizeof(command) - 1] = '\0'; while (atcommand_info[i].command) { - if (strcasecmp(command, atcommand_info[i].command) == 0 + if (command == atcommand_info[i].command && level >= atcommand_info[i].level) { return &atcommand_info[i]; @@ -522,12 +559,10 @@ void atkillmonster_sub(dumb_ptr<block_list> bl, int flag) *------------------------------------------ */ static -AtCommandInfo *get_atcommandinfo_byname(const char *name) +AtCommandInfo *get_atcommandinfo_byname(XString name) { - int i; - - for (i = 0; atcommand_info[i].command; i++) - if (strcasecmp(atcommand_info[i].command + 1, name) == 0) + for (int i = 0; atcommand_info[i].command; i++) + if (atcommand_info[i].command.xslice_t(1) == name) return &atcommand_info[i]; return NULL; @@ -537,39 +572,36 @@ AtCommandInfo *get_atcommandinfo_byname(const char *name) * *------------------------------------------ */ -int atcommand_config_read(const char *cfgName) +int atcommand_config_read(ZString cfgName) { - char line[1024], w1[1024], w2[1024]; - AtCommandInfo *p; - FILE *fp; - - if ((fp = fopen_(cfgName, "r")) == NULL) + std::ifstream in(cfgName.c_str()); + if (!in.is_open()) { PRINTF("At commands configuration file not found: %s\n", cfgName); return 1; } - while (fgets(line, sizeof(line) - 1, fp)) + FString line; + while (io::getline(in, line)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2) + SString w1; + TString w2; + if (!split_key_value(line, &w1, &w2)) continue; - p = get_atcommandinfo_byname(w1); + AtCommandInfo *p = get_atcommandinfo_byname(w1); if (p != NULL) { - p->level = atoi(w2); + p->level = atoi(w2.c_str()); if (p->level > 100) p->level = 100; else if (p->level < 0) p->level = 0; } - - if (strcasecmp(w1, "import") == 0) + else if (w1 == "import") atcommand_config_read(w2); + else + PRINTF("%s: bad line: %s\n", cfgName, line); } - fclose_(fp); return 0; } @@ -585,42 +617,41 @@ int atcommand_config_read(const char *cfgName) *------------------------------------------ */ int atcommand_setup(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; int level = 1; + CharName character; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &level, character) < 2) + if (!asplit(message, &level, &character)) { clif_displaymessage(fd, "Usage: @setup <level> <char name>"); return -1; } level--; - std::string buf; + FString buf; buf = STRPRINTF("-255 %s", character); - atcommand_character_baselevel(fd, sd, "@charbaselvl", buf.c_str()); + atcommand_character_baselevel(fd, sd, buf); buf = STRPRINTF("%d %s", level, character); - atcommand_character_baselevel(fd, sd, "@charbaselvl", buf.c_str()); + atcommand_character_baselevel(fd, sd, buf); // Emote skill buf = STRPRINTF("1 1 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf.c_str()); + atcommand_skill_learn(fd, sd, buf); // Trade skill buf = STRPRINTF("2 1 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf.c_str()); + atcommand_skill_learn(fd, sd, buf); // Party skill STRPRINTF("2 2 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf.c_str()); + atcommand_skill_learn(fd, sd, buf); STRPRINTF("018-1.gat 24 98 %s", character); - atcommand_charwarp(fd, sd, "@charwarp", buf.c_str()); + atcommand_charwarp(fd, sd, buf); - return (0); + return 0; } @@ -629,19 +660,16 @@ int atcommand_setup(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charwarp(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char map_name[100] {}; - char character[100] {}; + MapName map_name; + CharName character; int x = 0, y = 0; - dumb_ptr<map_session_data> pl_sd; - if (!message || !*message - || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, - character) < 4) + if (!asplit(message, &map_name, &x, &y, &character)) { clif_displaymessage(fd, - "Usage: @charwarp/@rura+ <mapname> <x> <y> <char name>"); + "Usage: @charwarp/@rura+ <mapname> <x> <y> <char name>"); return -1; } @@ -649,13 +677,13 @@ int atcommand_charwarp(const int fd, dumb_ptr<map_session_data> sd, x = random_::in(1, 399); if (y <= 0) y = random_::in(1, 399); - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) - { // you can rura+ only lower or same GM level + { + // you can rura+ only lower or same GM level if (x > 0 && x < 800 && y > 0 && y < 800) { map_local *m = map_mapname2mapid(map_name); @@ -663,14 +691,14 @@ int atcommand_charwarp(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp someone to this map."); + "You are not authorised to warp someone to this map."); return -1; } if (pl_sd->bl_m && pl_sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp this player from its actual map."); + "You are not authorised to warp this player from its actual map."); return -1; } if (pc_setpos(pl_sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0) @@ -710,16 +738,16 @@ int atcommand_charwarp(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_warp(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char map_name[100] {}; + MapName map_name; int x = 0, y = 0; - if (!message || !*message - || sscanf(message, "%99s %d %d", map_name, &x, &y) < 1) + if (!message + || !extract(message, record<' ', 1>(&map_name, &x, &y))) { clif_displaymessage(fd, - "Please, enter a map (usage: @warp <mapname> <x> <y>)."); + "Please, enter a map (usage: @warp <mapname> <x> <y>)."); return -1; } @@ -728,9 +756,6 @@ int atcommand_warp(const int fd, dumb_ptr<map_session_data> sd, if (y <= 0) y = random_::in(1, 399); - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); - if (x > 0 && x < 800 && y > 0 && y < 800) { map_local *m = map_mapname2mapid(map_name); @@ -738,14 +763,14 @@ int atcommand_warp(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you to this map."); + "You are not authorised to warp you to this map."); return -1; } if (sd->bl_m && sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."); return -1; } if (pc_setpos(sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0) @@ -770,20 +795,18 @@ int atcommand_warp(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_where(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; + extract(message, &character); - if (sscanf(message, "%99[^\n]", character) < 1) - strcpy(character, sd->status.name); - - if ((pl_sd = map_nick2sd(character)) != NULL && + dumb_ptr<map_session_data> pl_sd = character.to__actual() ? map_nick2sd(character) : sd; + if (pl_sd != NULL && !((battle_config.hide_GM_session || bool(pl_sd->status.option & Option::HIDE)) && (pc_isGM(pl_sd) > pc_isGM(sd)))) { // you can look only lower or same level - std::string output = STRPRINTF("%s: %s (%d,%d)", + FString output = STRPRINTF("%s: %s (%d,%d)", pl_sd->status.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(fd, output); @@ -802,36 +825,36 @@ int atcommand_where(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_goto(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>)."); + "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pl_sd->bl_m && pl_sd->bl_m->flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you to the map of this player."); + "You are not authorised to warp you to the map of this player."); return -1; } if (sd->bl_m && sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."); return -1; } pc_setpos(sd, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED); - std::string output = STRPRINTF("Jump to %s", character); + FString output = STRPRINTF("Jump to %s", character); clif_displaymessage(fd, output); } else @@ -848,10 +871,11 @@ int atcommand_goto(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_jump(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int x = 0, y = 0; - sscanf(message, "%d %d", &x, &y); + // may fail + extract(message, record<' '>(&x, &y)); if (x <= 0) x = random_::in(1, 399); @@ -863,18 +887,18 @@ int atcommand_jump(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you to your actual map."); + "You are not authorised to warp you to your actual map."); return -1; } if (sd->bl_m && sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."); return -1; } pc_setpos(sd, sd->mapname_, x, y, BeingRemoveWhy::WARPED); - std::string output = STRPRINTF("Jump to %d %d", x, y); + FString output = STRPRINTF("Jump to %d %d", x, y); clif_displaymessage(fd, output); } else @@ -891,17 +915,12 @@ int atcommand_jump(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_who(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count; int pl_GM_level, GM_level; - char match_text[100] {}; - char player_name[24] {}; - - if (sscanf(message, "%99[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (int j = 0; match_text[j]; j++) - match_text[j] = tolower(match_text[j]); + VString<23> match_text = message; + match_text = match_text.to_lower(); count = 0; GM_level = pc_isGM(sd); @@ -919,13 +938,11 @@ int atcommand_who(const int fd, dumb_ptr<map_session_data> sd, && (pl_GM_level > GM_level))) { // you can look only lower or same level - strzcpy(player_name, pl_sd->status.name, 24); - for (int j = 0; player_name[j]; j++) - player_name[j] = tolower(player_name[j]); - if (strstr(player_name, match_text) != NULL) + VString<23> player_name = pl_sd->status.name.to__lower(); + if (player_name.contains_seq(match_text)) { // search with no case sensitive - std::string output; + FString output; if (pl_GM_level > 0) output = STRPRINTF( "Name: %s (GM:%d) | Location: %s %d %d", @@ -949,7 +966,7 @@ int atcommand_who(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "1 player found."); else { - std::string output = STRPRINTF("%d players found.", count); + FString output = STRPRINTF("%d players found.", count); clif_displaymessage(fd, output); } @@ -961,18 +978,14 @@ int atcommand_who(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_whogroup(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count; int pl_GM_level, GM_level; - char match_text[100] {}; - char player_name[24] {}; struct party *p; - if (sscanf(message, "%99[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (int j = 0; match_text[j]; j++) - match_text[j] = tolower(match_text[j]); + VString<23> match_text = message; + match_text = match_text.to_lower(); count = 0; GM_level = pc_isGM(sd); @@ -990,15 +1003,13 @@ int atcommand_whogroup(const int fd, dumb_ptr<map_session_data> sd, && (pl_GM_level > GM_level))) { // you can look only lower or same level - strzcpy(player_name, pl_sd->status.name, 24); - for (int j = 0; player_name[j]; j++) - player_name[j] = tolower(player_name[j]); - if (strstr(player_name, match_text) != NULL) + VString<23> player_name = pl_sd->status.name.to__lower(); + if (player_name.contains_seq(match_text)) { // search with no case sensitive p = party_search(pl_sd->status.party_id); - const char *temp0 = p ? p->name : "None"; - std::string output; + PartyName temp0 = p ? p->name : stringish<PartyName>("None"); + FString output; if (pl_GM_level > 0) output = STRPRINTF( "Name: %s (GM:%d) | Party: '%s'", @@ -1016,7 +1027,7 @@ int atcommand_whogroup(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "1 player found."); else { - std::string output = STRPRINTF("%d players found.", count); + FString output = STRPRINTF("%d players found.", count); clif_displaymessage(fd, output); } @@ -1028,20 +1039,15 @@ int atcommand_whogroup(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_whomap(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count; int pl_GM_level, GM_level; map_local *map_id; - char map_name[100] {}; - if (!message || !*message) - map_id = sd->bl_m; - else { - sscanf(message, "%99s", map_name); - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); + MapName map_name; + extract(message, &map_name); map_id = map_mapname2mapid(map_name); if (map_id == nullptr) map_id = sd->bl_m; @@ -1064,7 +1070,7 @@ int atcommand_whomap(const int fd, dumb_ptr<map_session_data> sd, { // you can look only lower or same level if (pl_sd->bl_m == map_id) { - std::string output; + FString output; if (pl_GM_level > 0) output = STRPRINTF( "Name: %s (GM:%d) | Location: %s %d %d", @@ -1082,7 +1088,7 @@ int atcommand_whomap(const int fd, dumb_ptr<map_session_data> sd, } } - std::string output = STRPRINTF("%d players found in map '%s'.", + FString output = STRPRINTF("%d players found in map '%s'.", count, map_id->name_); clif_displaymessage(fd, output); @@ -1094,21 +1100,16 @@ int atcommand_whomap(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_whomapgroup(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count; int pl_GM_level, GM_level; - char map_name[100] {}; struct party *p; map_local *map_id; - if (!message || !*message) - map_id = sd->bl_m; - else { - sscanf(message, "%99s", map_name); - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); + MapName map_name; + extract(message, &map_name); map_id = map_mapname2mapid(map_name); if (map_id == nullptr) map_id = sd->bl_m; @@ -1133,8 +1134,8 @@ int atcommand_whomapgroup(const int fd, dumb_ptr<map_session_data> sd, if (pl_sd->bl_m == map_id) { p = party_search(pl_sd->status.party_id); - const char *temp0 = p ? p->name : "None"; - std::string output; + PartyName temp0 = p ? p->name : stringish<PartyName>("None"); + FString output; if (pl_GM_level > 0) output = STRPRINTF("Name: %s (GM:%d) | Party: '%s'", pl_sd->status.name, pl_GM_level, temp0); @@ -1148,7 +1149,7 @@ int atcommand_whomapgroup(const int fd, dumb_ptr<map_session_data> sd, } } - std::string output; + FString output; if (count == 0) output = STRPRINTF("No player found in map '%s'.", map_id->name_); else if (count == 1) @@ -1167,18 +1168,14 @@ int atcommand_whomapgroup(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_whogm(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count; int pl_GM_level, GM_level; - char match_text[100] {}; - char player_name[24] {}; struct party *p; - if (sscanf(message, "%99[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (int j = 0; match_text[j]; j++) - match_text[j] = tolower(match_text[j]); + VString<23> match_text = message; + match_text = match_text.to_lower(); count = 0; GM_level = pc_isGM(sd); @@ -1198,13 +1195,11 @@ int atcommand_whogm(const int fd, dumb_ptr<map_session_data> sd, && (pl_GM_level > GM_level))) { // you can look only lower or same level - strzcpy(player_name, pl_sd->status.name, 24); - for (int j = 0; player_name[j]; j++) - player_name[j] = tolower(player_name[j]); - if (strstr(player_name, match_text) != NULL) + VString<23> player_name = pl_sd->status.name.to__lower(); + if (player_name.contains_seq(match_text)) { // search with no case sensitive - std::string output; + FString output; output = STRPRINTF( "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_GM_level, @@ -1217,7 +1212,7 @@ int atcommand_whogm(const int fd, dumb_ptr<map_session_data> sd, pl_sd->status.job_level); clif_displaymessage(fd, output); p = party_search(pl_sd->status.party_id); - const char *temp0 = p ? p->name : "None"; + PartyName temp0 = p ? p->name : stringish<PartyName>("None"); output = STRPRINTF( " Party: '%s'", temp0); @@ -1235,7 +1230,7 @@ int atcommand_whogm(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "1 GM found."); else { - std::string output = STRPRINTF("%d GMs found.", count); + FString output = STRPRINTF("%d GMs found.", count); clif_displaymessage(fd, output); } @@ -1247,7 +1242,7 @@ int atcommand_whogm(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_save(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { nullpo_retr(-1, sd); @@ -1264,7 +1259,7 @@ int atcommand_save(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_load(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { map_local *m = map_mapname2mapid(sd->status.save_point.map_); if (m != nullptr && m->flag.nowarpto @@ -1294,11 +1289,11 @@ int atcommand_load(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_speed(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - if (!message || !*message) + if (!message) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a speed value (usage: @speed <%d-%d>).", static_cast<uint32_t>(MIN_WALK_SPEED.count()), static_cast<uint32_t>(MAX_WALK_SPEED.count())); @@ -1306,7 +1301,7 @@ int atcommand_speed(const int fd, dumb_ptr<map_session_data> sd, return -1; } - interval_t speed = static_cast<interval_t>(atoi(message)); + interval_t speed = static_cast<interval_t>(atoi(message.c_str())); if (speed >= MIN_WALK_SPEED && speed <= MAX_WALK_SPEED) { sd->speed = speed; @@ -1317,7 +1312,7 @@ int atcommand_speed(const int fd, dumb_ptr<map_session_data> sd, } else { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a valid speed value (usage: @speed <%d-%d>).", static_cast<uint32_t>(MIN_WALK_SPEED.count()), static_cast<uint32_t>(MAX_WALK_SPEED.count())); @@ -1333,7 +1328,7 @@ int atcommand_speed(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_storage(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { struct storage *stor; //changes from Freya/Yor nullpo_retr(-1, sd); @@ -1361,24 +1356,21 @@ int atcommand_storage(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_option(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - int param1_ = 0, param2_ = 0, param3_ = 0; nullpo_retr(-1, sd); - if (!message || !*message - || sscanf(message, "%d %d %d", ¶m1_, ¶m2_, ¶m3_) < 1 - || param1_ < 0 || param2_ < 0 || param3_ < 0) + Opt1 param1 = Opt1::ZERO; + Opt2 param2 = Opt2::ZERO; + Option param3 = Option::ZERO; + + if (!extract(message, record<',', 1>(¶m1, ¶m2, ¶m3))) { clif_displaymessage(fd, - "Please, enter at least a option (usage: @option <param1:0+> <param2:0+> <param3:0+>)."); + "Please, enter at least a option (usage: @option <param1:0+> <param2:0+> <param3:0+>)."); return -1; } - Opt1 param1 = Opt1(param1_); - Opt2 param2 = Opt2(param2_); - Option param3 = Option(param3_); - sd->opt1 = param1; sd->opt2 = param2; sd->status.option = param3; @@ -1395,7 +1387,7 @@ int atcommand_option(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_hide(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { if (bool(sd->status.option & Option::HIDE)) { @@ -1417,7 +1409,7 @@ int atcommand_hide(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_die(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { pc_damage(NULL, sd, sd->status.hp + 1); clif_displaymessage(fd, "A pity! You've died."); @@ -1430,19 +1422,19 @@ int atcommand_die(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_kill(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @kill <char name>)."); + "Please, enter a player name (usage: @kill <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same level @@ -1469,7 +1461,7 @@ int atcommand_kill(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_alive(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { sd->status.hp = sd->status.max_hp; sd->status.sp = sd->status.max_sp; @@ -1489,12 +1481,12 @@ int atcommand_alive(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_kami(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - if (!message || !*message) + if (!message) { clif_displaymessage(fd, - "Please, enter a message (usage: @kami <message>)."); + "Please, enter a message (usage: @kami <message>)."); return -1; } @@ -1508,11 +1500,11 @@ int atcommand_kami(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_heal(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int hp = 0, sp = 0; // [Valaris] thanks to fov - sscanf(message, "%d %d", &hp, &sp); + extract(message, record<' '>(&hp, &sp)); if (hp == 0 && sp == 0) { @@ -1556,18 +1548,17 @@ int atcommand_heal(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_item(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char item_name[100] {}; + ItemName item_name; int number = 0, item_id; struct item_data *item_data; int get_count, i; - if (!message || !*message - || sscanf(message, "%99s %d", item_name, &number) < 1) + if (!extract(message, record<' ', 1>(&item_name, &number))) { clif_displaymessage(fd, - "Please, enter an item name/id (usage: @item <item name or ID> [quantity])."); + "Please, enter an item name/id (usage: @item <item name or ID> [quantity])."); return -1; } @@ -1576,7 +1567,7 @@ int atcommand_item(const int fd, dumb_ptr<map_session_data> sd, item_id = 0; if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) + (item_data = itemdb_exists(atoi(item_name.c_str()))) != NULL) item_id = item_data->nameid; if (item_id >= 500) @@ -1615,7 +1606,7 @@ int atcommand_item(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_itemreset(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int i; @@ -1635,7 +1626,7 @@ int atcommand_itemreset(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_itemcheck(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { pc_checkitem(sd); @@ -1647,14 +1638,14 @@ int atcommand_itemcheck(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_baselevelup(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int level, i; - if (!message || !*message || (level = atoi(message)) == 0) + if (!extract(message, &level) || !level) { clif_displaymessage(fd, - "Please, enter a level adjustement (usage: @blvl <number of levels>)."); + "Please, enter a level adjustement (usage: @blvl <number of levels>)."); return -1; } @@ -1713,14 +1704,14 @@ int atcommand_baselevelup(const int fd, dumb_ptr<map_session_data> sd, // TODO: merge this with pc_setparam(SP::JOBLEVEL) // then fix the funny 50 and/or 10 limitation. int atcommand_joblevelup(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int up_level = 50, level; - if (!message || !*message || (level = atoi(message)) == 0) + if (!extract(message, &level) || !level) { clif_displaymessage(fd, - "Please, enter a level adjustement (usage: @jlvl <number of levels>)."); + "Please, enter a level adjustement (usage: @jlvl <number of levels>)."); return -1; } @@ -1775,20 +1766,23 @@ 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 *) + ZString) { - std::ifstream in(help_txt); + std::ifstream in(help_txt.c_str()); if (in.is_open()) { clif_displaymessage(fd, "Help commands:"); int gm_level = pc_isGM(sd); - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; - if (gm_level >= atoi(w1.c_str())) + int level; + extract(w1, &level); + if (gm_level >= level) clif_displaymessage(fd, w2); } } @@ -1806,14 +1800,12 @@ int atcommand_help(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_gm(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char password[100] {}; - - if (!message || !*message || sscanf(message, "%99[^\n]", password) < 1) + if (!message) { clif_displaymessage(fd, - "Please, enter a password (usage: @gm <password>)."); + "Please, enter a password (usage: @gm <password>)."); return -1; } @@ -1823,8 +1815,7 @@ int atcommand_gm(const int fd, dumb_ptr<map_session_data> sd, return -1; } else - chrif_changegm(sd->status.account_id, password, - strlen(password) + 1); + chrif_changegm(sd->status.account_id, message); return 0; } @@ -1834,7 +1825,7 @@ int atcommand_gm(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_pvpoff(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris] @@ -1874,7 +1865,7 @@ int atcommand_pvpoff(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_pvpon(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris] @@ -1918,15 +1909,13 @@ int atcommand_pvpon(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_model(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int hair_style = 0, hair_color = 0, cloth_color = 0; - if (!message || !*message - || sscanf(message, "%d %d %d", &hair_style, &hair_color, - &cloth_color) < 1) + if (!extract(message, record<' ', 1>(&hair_style, &hair_color, &cloth_color))) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter at least a value (usage: @model <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d>).", MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, @@ -1960,13 +1949,13 @@ int atcommand_model(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_dye(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int cloth_color = 0; - if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) + if (!extract(message, &cloth_color)) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a clothes color (usage: @dye/@ccolor <clothes color: %d-%d>).", MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); clif_displaymessage(fd, output); @@ -1994,13 +1983,13 @@ int atcommand_dye(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_hair_style(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int hair_style = 0; - if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) + if (!extract(message, &hair_style)) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a hair style (usage: @hairstyle/@hstyle <hair ID: %d-%d>).", MIN_HAIR_STYLE, MAX_HAIR_STYLE); clif_displaymessage(fd, output); @@ -2028,13 +2017,13 @@ int atcommand_hair_style(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_hair_color(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int hair_color = 0; - if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) + if (!extract(message, &hair_color)) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a hair color (usage: @haircolor/@hcolor <hair color: %d-%d>).", MIN_HAIR_COLOR, MAX_HAIR_COLOR); clif_displaymessage(fd, output); @@ -2062,9 +2051,9 @@ int atcommand_hair_color(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, - const char *command, const char *message) + ZString message) { - char monster[100] {}; + MobName monster; int mob_id; int number = 0; int x = 0, y = 0; @@ -2072,8 +2061,7 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, int i, j, k; int mx, my, range; - if (!message || !*message - || sscanf(message, "%99s %d %d %d", monster, &number, &x, &y) < 1) + if (!extract(message, record<' ', 1>(&monster, &number, &x, &y))) { clif_displaymessage(fd, "Give a monster name/id please."); return -1; @@ -2081,7 +2069,7 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, // If monster identifier/name argument is a name if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster)); + mob_id = mobdb_checkid(atoi(monster.c_str())); if (mob_id == 0) { @@ -2089,12 +2077,6 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, return -1; } - if (mob_id == 1288) - { - clif_displaymessage(fd, "Cannot spawn emperium."); - return -1; - } - if (number <= 0) number = 1; @@ -2104,8 +2086,8 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, number = battle_config.atc_spawn_quantity_limit; if (battle_config.etc_log) - PRINTF("%s monster='%s' id=%d count=%d (%d,%d)\n", command, monster, - mob_id, number, x, y); + PRINTF("@spawn monster='%s' id=%d count=%d (%d,%d)\n", + monster, mob_id, number, x, y); count = 0; range = sqrt(number) / 2; @@ -2125,7 +2107,7 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, my = sd->bl_y + random_::in(-range / 2, range / 2); else my = y; - k = mob_once_spawn(sd, "this", mx, my, "", mob_id, 1, ""); + k = mob_once_spawn(sd, MOB_THIS_MAP, mx, my, MobName(), mob_id, 1, NpcEvent()); } count += (k != 0) ? 1 : 0; } @@ -2135,7 +2117,7 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "All monster summoned!"); else { - std::string output = STRPRINTF("%d monster(s) summoned!", + FString output = STRPRINTF("%d monster(s) summoned!", count); clif_displaymessage(fd, output); } @@ -2154,17 +2136,12 @@ int atcommand_spawn(const int fd, dumb_ptr<map_session_data> sd, */ static void atcommand_killmonster_sub(const int fd, dumb_ptr<map_session_data> sd, - const char *message, const int drop) + ZString message, const int drop) { - char map_name[100] {}; - map_local *map_id; - if (!message || !*message || sscanf(message, "%99s", map_name) < 1) - map_id = sd->bl_m; - else { - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); + MapName map_name; + extract(message, &map_name); map_id = map_mapname2mapid(map_name); if (map_id == nullptr) map_id = sd->bl_m; @@ -2177,8 +2154,6 @@ void atcommand_killmonster_sub(const int fd, dumb_ptr<map_session_data> sd, BL::MOB); clif_displaymessage(fd, "All monsters killed!"); - - return; } /*========================================== @@ -2186,7 +2161,7 @@ void atcommand_killmonster_sub(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_killmonster(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { atcommand_killmonster_sub(fd, sd, message, 1); @@ -2202,7 +2177,7 @@ void atlist_nearby_sub(dumb_ptr<block_list> bl, int fd) { nullpo_retv(bl); - std::string buf = STRPRINTF(" - \"%s\"", + FString buf = STRPRINTF(" - \"%s\"", bl->as_player()->status.name); clif_displaymessage(fd, buf); } @@ -2212,7 +2187,7 @@ void atlist_nearby_sub(dumb_ptr<block_list> bl, int fd) *------------------------------------------ */ int atcommand_list_nearby(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { clif_displaymessage(fd, "Nearby players:"); map_foreachinarea(std::bind(atlist_nearby_sub, ph::_1, fd), @@ -2229,7 +2204,7 @@ int atcommand_list_nearby(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_killmonster2(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { atcommand_killmonster_sub(fd, sd, message, 0); @@ -2241,13 +2216,13 @@ int atcommand_killmonster2(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_gat(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int y; for (y = 2; y >= -2; y--) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", sd->bl_m->name_, sd->bl_x - 2, sd->bl_y + y, map_getcell(sd->bl_m, sd->bl_x - 2, sd->bl_y + y), @@ -2266,18 +2241,19 @@ int atcommand_gat(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_packet(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - int type = 0, flag = 0; + StatusChange type {}; + int flag = 0; - if (!message || !*message || sscanf(message, "%d %d", &type, &flag) < 2) + if (!extract(message, record<' '>(&type, &flag))) { clif_displaymessage(fd, - "Please, enter a status type/flag (usage: @packet <status type> <flag>)."); + "Please, enter a status type/flag (usage: @packet <status type> <flag>)."); return -1; } - clif_status_change(sd, StatusChange(type), flag); + clif_status_change(sd, type, flag); return 0; } @@ -2287,14 +2263,14 @@ int atcommand_packet(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_statuspoint(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int point, new_status_point; - if (!message || !*message || (point = atoi(message)) == 0) + if (!extract(message, &point) || point == 0) { clif_displaymessage(fd, - "Please, enter a number (usage: @stpoint <number of points>)."); + "Please, enter a number (usage: @stpoint <number of points>)."); return -1; } @@ -2327,14 +2303,14 @@ int atcommand_statuspoint(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_skillpoint(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int point, new_skill_point; - if (!message || !*message || (point = atoi(message)) == 0) + if (!extract(message, &point) || point == 0) { clif_displaymessage(fd, - "Please, enter a number (usage: @skpoint <number of points>)."); + "Please, enter a number (usage: @skpoint <number of points>)."); return -1; } @@ -2367,14 +2343,14 @@ int atcommand_skillpoint(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_zeny(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int zeny, new_zeny; - if (!message || !*message || (zeny = atoi(message)) == 0) + if (!extract(message, &zeny) || zeny == 0) { clif_displaymessage(fd, - "Please, enter an amount (usage: @zeny <amount>)."); + "Please, enter an amount (usage: @zeny <amount>)."); return -1; } @@ -2408,14 +2384,13 @@ int atcommand_zeny(const int fd, dumb_ptr<map_session_data> sd, */ template<ATTR attr> int atcommand_param(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int value = 0, new_value; - if (!message || !*message || sscanf(message, "%d", &value) < 1 + if (!extract(message, &value) || value == 0) { - // there was a clang bug here // fortunately, STRPRINTF was not actually needed clif_displaymessage(fd, @@ -2455,11 +2430,11 @@ int atcommand_param(const int fd, dumb_ptr<map_session_data> sd, */ //** Stat all by fritz (rewritten by [Yor]) int atcommand_all_stats(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int count, value = 0, new_value; - if (!message || !*message || sscanf(message, "%d", &value) < 1 + if (!extract(message, &value) || value == 0) value = battle_config.max_parameter; @@ -2501,19 +2476,19 @@ int atcommand_all_stats(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_recall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @recall <char name>)."); + "Please, enter a player name (usage: @recall <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can recall only lower or same level @@ -2521,18 +2496,18 @@ int atcommand_recall(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."); return -1; } if (pl_sd->bl_m && pl_sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp this player from its actual map."); + "You are not authorised to warp this player from its actual map."); return -1; } pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT); - std::string output = STRPRINTF("%s recalled!", character); + FString output = STRPRINTF("%s recalled!", character); clif_displaymessage(fd, output); } else @@ -2555,19 +2530,19 @@ int atcommand_recall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_revive(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @revive <char name>)."); + "Please, enter a player name (usage: @revive <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { pl_sd->status.hp = pl_sd->status.max_hp; pc_setstand(pl_sd); @@ -2592,21 +2567,21 @@ int atcommand_revive(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_stats(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charstats <char name>)."); + "Please, enter a player name (usage: @charstats <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { - std::string output; + FString output; output = STRPRINTF("'%s' stats:", pl_sd->status.name); clif_displaymessage(fd, output); output = STRPRINTF("Base Level - %d", pl_sd->status.base_level), @@ -2651,7 +2626,7 @@ int atcommand_character_stats(const int fd, dumb_ptr<map_session_data>, */ //** Character Stats All by fritz int atcommand_character_stats_all(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { int count; @@ -2663,13 +2638,13 @@ int atcommand_character_stats_all(const int fd, dumb_ptr<map_session_data>, dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(session[i]->session_data.get())); if (pl_sd && pl_sd->state.auth) { - std::string gmlevel; + FString gmlevel; if (pc_isGM(pl_sd) > 0) gmlevel = STRPRINTF("| GM Lvl: %d", pc_isGM(pl_sd)); else gmlevel = " "; - std::string output; + FString output; output = STRPRINTF( "Name: %s | BLvl: %d | Job: Novice/Human (Lvl: %d) | HP: %d/%d | SP: %d/%d", pl_sd->status.name, pl_sd->status.base_level, @@ -2698,7 +2673,7 @@ int atcommand_character_stats_all(const int fd, dumb_ptr<map_session_data>, clif_displaymessage(fd, "1 player found."); else { - std::string output = STRPRINTF("%d players found.", count); + FString output = STRPRINTF("%d players found.", count); clif_displaymessage(fd, output); } @@ -2710,26 +2685,21 @@ int atcommand_character_stats_all(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_character_option(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - int opt1_ = 0, opt2_ = 0, opt3_ = 0; - dumb_ptr<map_session_data> pl_sd; - - if (!message || !*message - || sscanf(message, "%d %d %d %99[^\n]", &opt1_, &opt2_, &opt3_, - character) < 4 || opt1_ < 0 || opt2_ < 0 || opt3_ < 0) + Opt1 opt1; + Opt2 opt2; + Option opt3; + CharName character; + if (!asplit(message, &opt1, &opt2, &opt3, &character)) { clif_displaymessage(fd, - "Please, enter valid options and a player name (usage: @charoption <param1> <param2> <param3> <charname>)."); + "Please, enter valid options and a player name (usage: @charoption <param1> <param2> <param3> <charname>)."); return -1; } - Opt1 opt1 = Opt1(opt1_); - Opt2 opt2 = Opt2(opt2_); - Option opt3 = Option(opt3_); - - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { @@ -2762,31 +2732,19 @@ int atcommand_character_option(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_change_sex(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charchangesex <name>)."); + "Please, enter a player name (usage: @charchangesex <name>)."); return -1; } - // check player name - if (strlen(character) < 4) { - clif_displaymessage(fd, "Sorry, but a player name have at least 4 characters."); - return -1; - } - else if (strlen(character) > 23) - { - clif_displaymessage(fd, "Sorry, but a player name have 23 characters maximum."); - return -1; - } - else - { - chrif_char_ask_name(sd->status.account_id, character, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex + chrif_char_ask_name(sd->status.account_id, character, 5, HumanTimeDiff()); // type: 5 - changesex clif_displaymessage(fd, "Character name sends to char-server to ask it."); } @@ -2799,31 +2757,19 @@ int atcommand_char_change_sex(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_block(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @block <name>)."); + "Please, enter a player name (usage: @block <name>)."); return -1; } - // check player name - if (strlen(character) < 4) { - clif_displaymessage(fd, "Sorry, but a player name have at least 4 characters."); - return -1; - } - else if (strlen(character) > 23) - { - clif_displaymessage(fd, "Sorry, but a player name have 23 characters maximum."); - return -1; - } - else - { - chrif_char_ask_name(sd->status.account_id, character, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + chrif_char_ask_name(sd->status.account_id, character, 1, HumanTimeDiff()); // type: 1 - block clif_displaymessage(fd, "Character name sends to char-server to ask it."); } @@ -2847,94 +2793,21 @@ int atcommand_char_block(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_ban(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char modif[100] {}; - char character[100] {}; - char *modif_p; - int year, month, day, hour, minute, second, value; + HumanTimeDiff modif; + CharName character; - if (!message || !*message - || sscanf(message, "%s %99[^\n]", modif, character) < 2) + if (!asplit(message, &modif, &character) + || !modif) { clif_displaymessage(fd, - "Please, enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <name>)."); - return -1; - } - - modif[sizeof(modif) - 1] = '\0'; - character[sizeof(character) - 1] = '\0'; - - modif_p = modif; - year = month = day = hour = minute = second = 0; - while (modif_p[0] != '\0') - { - value = atoi(modif_p); - if (value == 0) - modif_p++; - else - { - if (modif_p[0] == '-' || modif_p[0] == '+') - modif_p++; - while (modif_p[0] >= '0' && modif_p[0] <= '9') - modif_p++; - if (modif_p[0] == 's') - { - second = value; - modif_p++; - } - else if (modif_p[0] == 'm' && modif_p[1] == 'n') - { - minute = value; - modif_p = modif_p + 2; - } - else if (modif_p[0] == 'h') - { - hour = value; - modif_p++; - } - else if (modif_p[0] == 'd' || modif_p[0] == 'j') - { - day = value; - modif_p++; - } - else if (modif_p[0] == 'm') - { - month = value; - modif_p++; - } - else if (modif_p[0] == 'y' || modif_p[0] == 'a') - { - year = value; - modif_p++; - } - else if (modif_p[0] != '\0') - { - modif_p++; - } - } - } - if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 - && second == 0) - { - clif_displaymessage(fd, "Invalid time for ban command."); + "Please, enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <name>)."); return -1; } - // check player name - if (strlen(character) < 4) - { - clif_displaymessage(fd, "Sorry, but a player name have at least 4 characters."); - return -1; - } - else if (strlen(character) > 23) { - clif_displaymessage(fd, "Sorry, but a player name have 23 characters maximum."); - return -1; - } - else - { - chrif_char_ask_name(sd->status.account_id, character, 2, year, month, day, hour, minute, second); // type: 2 - ban + chrif_char_ask_name(sd->status.account_id, character, 2, modif); // type: 2 - ban clif_displaymessage(fd, "Character name sends to char-server to ask it."); } @@ -2946,32 +2819,20 @@ int atcommand_char_ban(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_unblock(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charunblock <player_name>)."); + "Please, enter a player name (usage: @charunblock <player_name>)."); return -1; } - // check player name - if (strlen(character) < 4) - { - clif_displaymessage(fd, "Sorry, but a player name have at least 4 characters."); - return -1; - } - else if (strlen(character) > 23) - { - clif_displaymessage(fd, "Sorry, but a player name have 23 characters maximum."); - return -1; - } - else { // send answer to login server via char-server - chrif_char_ask_name(sd->status.account_id, character, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock + chrif_char_ask_name(sd->status.account_id, character, 3, HumanTimeDiff()); // type: 3 - unblock clif_displaymessage(fd, "Character name sends to char-server to ask it."); } @@ -2983,32 +2844,20 @@ int atcommand_char_unblock(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_unban(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charunban <player_name>)."); + "Please, enter a player name (usage: @charunban <player_name>)."); return -1; } - // check player name - if (strlen(character) < 4) - { - clif_displaymessage(fd, "Sorry, but a player name have at least 4 characters."); - return -1; - } - else if (strlen(character) > 23) - { - clif_displaymessage(fd, "Sorry, but a player name have 23 characters maximum."); - return -1; - } - else { // send answer to login server via char-server - chrif_char_ask_name(sd->status.account_id, character, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban + chrif_char_ask_name(sd->status.account_id, character, 4, HumanTimeDiff()); // type: 4 - unban clif_displaymessage(fd, "Character name sends to char-server to ask it."); } @@ -3020,26 +2869,22 @@ int atcommand_char_unban(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_save(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char map_name[100] {}; - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + MapName map_name; + CharName character; int x = 0, y = 0; - if (!message || !*message - || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, - character) < 4 || x < 0 || y < 0) + if (!asplit(message, &map_name, &x, &y, &character) + || x < 0 || y < 0) { clif_displaymessage(fd, - "Please, enter a valid save point and a player name (usage: @charsave <map> <x> <y> <charname>)."); + "Please, enter a valid save point and a player name (usage: @charsave <map> <x> <y> <charname>)."); return -1; } - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); - - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { @@ -3056,7 +2901,7 @@ int atcommand_character_save(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to set this map as a save map."); + "You are not authorised to set this map as a save map."); return -1; } pc_setsavepoint(pl_sd, map_name, x, y); @@ -3083,7 +2928,7 @@ int atcommand_character_save(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_doom(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3108,7 +2953,7 @@ int atcommand_doom(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_doommap(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3152,7 +2997,7 @@ void atcommand_raise_sub(dumb_ptr<map_session_data> sd) *------------------------------------------ */ int atcommand_raise(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3171,7 +3016,7 @@ int atcommand_raise(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_raisemap(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3192,26 +3037,24 @@ int atcommand_raisemap(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_baselevel(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; int level = 0, i; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &level, character) < 2 + if (!asplit(message, &level, &character) || level == 0) { clif_displaymessage(fd, - "Please, enter a level adjustement and a player name (usage: @charblvl <#> <nickname>)."); + "Please, enter a level adjustement and a player name (usage: @charblvl <#> <nickname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change base level only lower or same gm level - if (level > 0) { if (pl_sd->status.base_level == battle_config.maximum_level) @@ -3262,7 +3105,7 @@ int atcommand_character_baselevel(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "Character's base level lowered."); } // Reset their stat points to prevent extra points from stacking - atcommand_charstreset(fd, sd,"@charstreset", character); + atcommand_charstreset(fd, sd, character.to__actual()); } else { @@ -3284,22 +3127,21 @@ int atcommand_character_baselevel(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_joblevel(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; int max_level = 50, level = 0; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &level, character) < 2 + if (!asplit(message, &level, &character) || level == 0) { clif_displaymessage(fd, - "Please, enter a level adjustement and a player name (usage: @charjlvl <#> <nickname>)."); + "Please, enter a level adjustement and a player name (usage: @charjlvl <#> <nickname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { @@ -3367,19 +3209,19 @@ int atcommand_character_joblevel(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_kick(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @kick <charname>)."); + "Please, enter a player name (usage: @kick <charname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) // you can kick only lower or same gm level clif_GM_kick(sd, pl_sd, 1); @@ -3403,7 +3245,7 @@ int atcommand_kick(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_kickall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3429,19 +3271,17 @@ int atcommand_kickall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_questskill(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - int skill_id_; + SkillID skill_id; - if (!message || !*message || (skill_id_ = atoi(message)) < 0) + if (!extract(message, &skill_id)) { clif_displaymessage(fd, - "Please, enter a quest skill number (usage: @questskill <#:0+>)."); + "Please, enter a quest skill number (usage: @questskill <#:0+>)."); return -1; } - SkillID skill_id = SkillID(skill_id_); - if (/*skill_id >= SkillID() &&*/ skill_id < SkillID::MAX_SKILL_DB) { if (skill_get_inf2(skill_id) & 0x01) @@ -3477,28 +3317,24 @@ int atcommand_questskill(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charquestskill(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; - int skill_id_ = 0; + CharName character; + SkillID skill_id; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &skill_id_, character) < 2 - || skill_id_ < 0) + if (!asplit(message, &skill_id, &character)) { clif_displaymessage(fd, - "Please, enter a quest skill number and a player name (usage: @charquestskill <#:0+> <char_name>)."); + "Please, enter a quest skill number and a player name (usage: @charquestskill <#:0+> <char_name>)."); return -1; } - SkillID skill_id = SkillID(skill_id_); - if (/*skill_id >= SkillID() &&*/ skill_id < SkillID::MAX_SKILL_DB) { if (skill_get_inf2(skill_id) & 0x01) { - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_checkskill(pl_sd, skill_id) == 0) { @@ -3537,19 +3373,17 @@ int atcommand_charquestskill(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_lostskill(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - int skill_id_; + SkillID skill_id; - if (!message || !*message || (skill_id_ = atoi(message)) < 0) + if (!extract(message, &skill_id)) { clif_displaymessage(fd, - "Please, enter a quest skill number (usage: @lostskill <#:0+>)."); + "Please, enter a quest skill number (usage: @lostskill <#:0+>)."); return -1; } - SkillID skill_id = SkillID(skill_id_); - if (/*skill_id >= SkillID() &&*/ skill_id < MAX_SKILL) { if (skill_get_inf2(skill_id) & 0x01) @@ -3587,28 +3421,24 @@ int atcommand_lostskill(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charlostskill(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; - int skill_id_ = 0; + CharName character; + SkillID skill_id; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &skill_id_, character) < 2 - || skill_id_ < 0) + if (!asplit(message, &skill_id, &character)) { clif_displaymessage(fd, - "Please, enter a quest skill number and a player name (usage: @charlostskill <#:0+> <char_name>)."); + "Please, enter a quest skill number and a player name (usage: @charlostskill <#:0+> <char_name>)."); return -1; } - SkillID skill_id = SkillID(skill_id_); - if (/*skill_id >= SkillID() &&*/ skill_id < MAX_SKILL) { if (skill_get_inf2(skill_id) & 0x01) { - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_checkskill(pl_sd, skill_id) > 0) { @@ -3649,14 +3479,14 @@ int atcommand_charlostskill(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_party(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char party[100] {}; + PartyName party; - if (!message || !*message || sscanf(message, "%99[^\n]", party) < 1) + if (!extract(message, &party) || !party) { clif_displaymessage(fd, - "Please, enter a party name (usage: @party <party_name>)."); + "Please, enter a party name (usage: @party <party_name>)."); return -1; } @@ -3670,7 +3500,7 @@ int atcommand_party(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_mapexit(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { @@ -3695,26 +3525,26 @@ int atcommand_mapexit(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_idsearch(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char item_name[100] {}; + ItemName item_name; int i, match; struct item_data *item; - if (!message || !*message || sscanf(message, "%99s", item_name) < 0) + if (!extract(message, &item_name) || !item_name) { clif_displaymessage(fd, - "Please, enter a part of item name (usage: @idsearch <part_of_item_name>)."); + "Please, enter a part of item name (usage: @idsearch <part_of_item_name>)."); return -1; } - std::string output = STRPRINTF("The reference result of '%s' (name: id):", item_name); + FString output = STRPRINTF("The reference result of '%s' (name: id):", item_name); clif_displaymessage(fd, output); match = 0; for (i = 0; i < 20000; i++) { if ((item = itemdb_exists(i)) != NULL - && strstr(item->jname, item_name) != NULL) + && item->jname.contains_seq(item_name)) { match++; output = STRPRINTF("%s: %d", item->jname, item->nameid); @@ -3732,24 +3562,24 @@ int atcommand_idsearch(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_charskreset(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charskreset <charname>)."); + "Please, enter a player name (usage: @charskreset <charname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset skill points only lower or same gm level pc_resetskill(pl_sd); - std::string output = STRPRINTF( + FString output = STRPRINTF( "'%s' skill points reseted!", character); clif_displaymessage(fd, output); } @@ -3773,24 +3603,24 @@ int atcommand_charskreset(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charstreset(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charstreset <charname>)."); + "Please, enter a player name (usage: @charstreset <charname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset stats points only lower or same gm level pc_resetstate(pl_sd); - std::string output = STRPRINTF( + FString output = STRPRINTF( "'%s' stats points reseted!", character); clif_displaymessage(fd, output); @@ -3815,27 +3645,27 @@ int atcommand_charstreset(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charreset(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charreset <charname>)."); + "Please, enter a player name (usage: @charreset <charname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level pc_resetstate(pl_sd); pc_resetskill(pl_sd); - pc_setglobalreg(pl_sd, "MAGIC_FLAGS", 0); // [Fate] Reset magic quest variables - pc_setglobalreg(pl_sd, "MAGIC_EXP", 0); // [Fate] Reset magic experience - std::string output = STRPRINTF( + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"), 0); // [Fate] Reset magic quest variables + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"), 0); // [Fate] Reset magic experience + FString output = STRPRINTF( "'%s' skill and stats points reseted!", character); clif_displaymessage(fd, output); } @@ -3859,19 +3689,19 @@ int atcommand_charreset(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_char_wipe(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charwipe <charname>)."); + "Please, enter a player name (usage: @charwipe <charname>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level @@ -3919,10 +3749,10 @@ int atcommand_char_wipe(const int fd, dumb_ptr<map_session_data> sd, pc_calcstatus(pl_sd, 0); pc_resetstate(pl_sd); pc_resetskill(pl_sd); - pc_setglobalreg(pl_sd, "MAGIC_FLAGS", 0); // [Fate] Reset magic quest variables - pc_setglobalreg(pl_sd, "MAGIC_EXP", 0); // [Fate] Reset magic experience + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"), 0); // [Fate] Reset magic quest variables + pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"), 0); // [Fate] Reset magic experience - std::string output = STRPRINTF("%s: wiped.", character); + FString output = STRPRINTF("%s: wiped.", character); clif_displaymessage(fd, output); } else @@ -3945,18 +3775,14 @@ int atcommand_char_wipe(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charmodel(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - int hair_style = 0, hair_color = 0, cloth_color = 0; - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + unsigned hair_style = 0, hair_color = 0, cloth_color = 0; + CharName character; - if (!message || !*message - || sscanf(message, "%d %d %d %99[^\n]", &hair_style, &hair_color, - &cloth_color, character) < 4 || hair_style < 0 - || hair_color < 0 || cloth_color < 0) + if (!asplit(message, &hair_style, &hair_color, &cloth_color, &character)) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Please, enter a valid model and a player name (usage: @charmodel <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d> <name>).", MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, @@ -3965,7 +3791,8 @@ int atcommand_charmodel(const int fd, dumb_ptr<map_session_data>, return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && @@ -3998,23 +3825,22 @@ int atcommand_charmodel(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_charskpoint(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; int new_skill_point; int point = 0; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &point, character) < 2 + if (!asplit(message, &point, &character) || point == 0) { clif_displaymessage(fd, - "Please, enter a number and a player name (usage: @charskpoint <amount> <name>)."); + "Please, enter a number and a player name (usage: @charskpoint <amount> <name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { new_skill_point = pl_sd->status.skill_point + point; if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) // fix positiv overflow @@ -4050,23 +3876,22 @@ int atcommand_charskpoint(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_charstpoint(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; int new_status_point; int point = 0; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &point, character) < 2 + if (!asplit(message, &point, &character) || point == 0) { clif_displaymessage(fd, - "Please, enter a number and a player name (usage: @charstpoint <amount> <name>)."); + "Please, enter a number and a player name (usage: @charstpoint <amount> <name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { new_status_point = pl_sd->status.status_point + point; if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) // fix positiv overflow @@ -4102,21 +3927,20 @@ int atcommand_charstpoint(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_charzeny(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; + CharName character; int zeny = 0, new_zeny; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &zeny, character) < 2 || zeny == 0) + if (!asplit(message, &zeny, &character) || zeny == 0) { clif_displaymessage(fd, - "Please, enter a number and a player name (usage: @charzeny <zeny> <name>)."); + "Please, enter a number and a player name (usage: @charzeny <zeny> <name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { new_zeny = pl_sd->status.zeny + zeny; if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow @@ -4152,7 +3976,7 @@ int atcommand_charzeny(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_recallall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int count; @@ -4160,7 +3984,7 @@ int atcommand_recallall(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."); return -1; } @@ -4187,7 +4011,7 @@ int atcommand_recallall(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "All characters recalled!"); if (count) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", count); clif_displaymessage(fd, output); @@ -4201,16 +4025,16 @@ int atcommand_recallall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_partyrecall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char party_name[100] {}; + PartyName party_name; struct party *p; int count; - if (!message || !*message || sscanf(message, "%99[^\n]", party_name) < 1) + if (!extract(message, &party_name) || !party_name) { clif_displaymessage(fd, - "Please, enter a party name/id (usage: @partyrecall <party_name/id>)."); + "Please, enter a party name/id (usage: @partyrecall <party_name/id>)."); return -1; } @@ -4218,12 +4042,12 @@ int atcommand_partyrecall(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp somenone to your actual map."); + "You are not authorised to warp somenone to your actual map."); return -1; } if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number - (p = party_search(atoi(message))) != NULL) + (p = party_search(atoi(message.c_str()))) != NULL) { count = 0; for (int i = 0; i < fd_max; i++) @@ -4242,7 +4066,7 @@ int atcommand_partyrecall(const int fd, dumb_ptr<map_session_data> sd, pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT); } } - std::string output = STRPRINTF("All online characters of the %s party are near you.", p->name); + FString output = STRPRINTF("All online characters of the %s party are near you.", p->name); clif_displaymessage(fd, output); if (count) { @@ -4266,7 +4090,7 @@ int atcommand_partyrecall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_reloaditemdb(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { itemdb_reload(); clif_displaymessage(fd, "Item database reloaded."); @@ -4279,7 +4103,7 @@ int atcommand_reloaditemdb(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_reloadmobdb(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { mob_reload(); clif_displaymessage(fd, "Monster database reloaded."); @@ -4292,7 +4116,7 @@ int atcommand_reloadmobdb(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_reloadskilldb(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { skill_reload(); clif_displaymessage(fd, "Skill database reloaded."); @@ -4305,7 +4129,7 @@ int atcommand_reloadskilldb(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_reloadscript(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { do_init_npc(); do_init_script(); @@ -4322,7 +4146,7 @@ int atcommand_reloadscript(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_reloadgmdb(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { chrif_reloadGMdb(); @@ -4340,26 +4164,24 @@ int atcommand_reloadgmdb(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_mapinfo(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { dumb_ptr<npc_data> nd = NULL; - char map_name[100] {}; + MapName map_name; const char *direction = NULL; int list = 0; - sscanf(message, "%d %99[^\n]", &list, map_name); + extract(message, record<' '>(&list, &map_name)); if (list < 0 || list > 3) { clif_displaymessage(fd, - "Please, enter at least a valid list number (usage: @mapinfo <0-3> [map])."); + "Please, enter at least a valid list number (usage: @mapinfo <0-3> [map])."); return -1; } - if (map_name[0] == '\0') - strcpy(map_name, sd->mapname_); - if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat) - strcat(map_name, ".gat"); + if (!map_name) + map_name = sd->mapname_; map_local *m_id = map_mapname2mapid(map_name); if (m_id != nullptr) @@ -4369,7 +4191,7 @@ int atcommand_mapinfo(const int fd, dumb_ptr<map_session_data> sd, } clif_displaymessage(fd, "------ Map Info ------"); - std::string output = STRPRINTF("Map Name: %s", map_name); + FString output = STRPRINTF("Map Name: %s", map_name); clif_displaymessage(fd, output); output = STRPRINTF("Players In Map: %d", m_id->users); clif_displaymessage(fd, output); @@ -4418,11 +4240,11 @@ int atcommand_mapinfo(const int fd, dumb_ptr<map_session_data> sd, continue; dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(session[i]->session_data.get())); if (pl_sd && pl_sd->state.auth - && strcmp(pl_sd->mapname_, map_name) == 0) + && pl_sd->mapname_ == map_name) { output = STRPRINTF( - "Player '%s' (session #%d) | Location: %d,%d", - pl_sd->status.name, i, pl_sd->bl_x, pl_sd->bl_y); + "Player '%s' (session #%d) | Location: %d,%d", + pl_sd->status.name, i, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(fd, output); } } @@ -4476,7 +4298,7 @@ int atcommand_mapinfo(const int fd, dumb_ptr<map_session_data> sd, break; default: // normally impossible to arrive here clif_displaymessage(fd, - "Please, enter at least a valid list number (usage: @mapinfo <0-2> [map])."); + "Please, enter at least a valid list number (usage: @mapinfo <0-2> [map])."); return -1; } @@ -4488,31 +4310,31 @@ int atcommand_mapinfo(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_partyspy(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char party_name[100] {}; - struct party *p; + PartyName party_name; - if (!message || !*message || sscanf(message, "%99[^\n]", party_name) < 1) + if (!extract(message, &party_name)) { clif_displaymessage(fd, - "Please, enter a party name/id (usage: @partyspy <party_name/id>)."); + "Please, enter a party name/id (usage: @partyspy <party_name/id>)."); return -1; } + struct party *p; if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number - (p = party_search(atoi(message))) != NULL) + (p = party_search(atoi(message.c_str()))) != NULL) { if (sd->partyspy == p->party_id) { sd->partyspy = 0; - std::string output = STRPRINTF("No longer spying on the %s party.", p->name); + FString output = STRPRINTF("No longer spying on the %s party.", p->name); clif_displaymessage(fd, output); } else { sd->partyspy = p->party_id; - std::string output = STRPRINTF("Spying on the %s party.", p->name); + FString output = STRPRINTF("Spying on the %s party.", p->name); clif_displaymessage(fd, output); } } @@ -4530,14 +4352,14 @@ int atcommand_partyspy(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_enablenpc(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char NPCname[100] {}; + NpcName NPCname; - if (!message || !*message || sscanf(message, "%99[^\n]", NPCname) < 1) + if (!extract(message, &NPCname) || !NPCname) { clif_displaymessage(fd, - "Please, enter a NPC name (usage: @npcon <NPC_name>)."); + "Please, enter a NPC name (usage: @npcon <NPC_name>)."); return -1; } @@ -4560,14 +4382,14 @@ int atcommand_enablenpc(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_disablenpc(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char NPCname[100] {}; + NpcName NPCname; - if (!message || !*message || sscanf(message, "%99[^\n]", NPCname) < 1) + if (!extract(message, &NPCname) || !NPCname) { clif_displaymessage(fd, - "Please, enter a NPC name (usage: @npcoff <NPC_name>)."); + "Please, enter a NPC name (usage: @npcoff <NPC_name>)."); return -1; } @@ -4591,11 +4413,11 @@ int atcommand_disablenpc(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_servertime(const int fd, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { timestamp_seconds_buffer tsbuf; stamp_time(tsbuf); - std::string temp = STRPRINTF("Server time: %s", tsbuf); + FString temp = STRPRINTF("Server time: %s", tsbuf); clif_displaymessage(fd, temp); { @@ -4614,31 +4436,29 @@ int atcommand_servertime(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_chardelitem(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; - char character[100] {}; - char item_name[100] {}; + CharName character; + ItemName item_name; int i, number = 0, item_id, item_position, count; struct item_data *item_data; - if (!message || !*message - || sscanf(message, "%s %d %99[^\n]", item_name, &number, - character) < 3 || number < 1) + if (!asplit(message, &item_name, &number, &character) || number < 1) { clif_displaymessage(fd, - "Please, enter an item name/id, a quantity and a player name (usage: @chardelitem <item_name_or_ID> <quantity> <player>)."); + "Please, enter an item name/id, a quantity and a player name (usage: @chardelitem <item_name_or_ID> <quantity> <player>)."); return -1; } item_id = 0; if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) + (item_data = itemdb_exists(atoi(item_name.c_str()))) != NULL) item_id = item_data->nameid; if (item_id > 500) { - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same level @@ -4652,7 +4472,7 @@ int atcommand_chardelitem(const int fd, dumb_ptr<map_session_data> sd, count++; item_position = pc_search_inventory(pl_sd, item_id); // for next loop } - std::string output = STRPRINTF( + FString output = STRPRINTF( "%d item(s) removed by a GM.", count); clif_displaymessage(pl_sd->fd, output); @@ -4695,16 +4515,16 @@ int atcommand_chardelitem(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_broadcast(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - if (!message || !*message) + if (!message) { clif_displaymessage(fd, - "Please, enter a message (usage: @broadcast <message>)."); + "Please, enter a message (usage: @broadcast <message>)."); return -1; } - std::string output = STRPRINTF("%s : %s", sd->status.name, message); + FString output = STRPRINTF("%s : %s", sd->status.name, message); intif_GMmessage(output); return 0; @@ -4715,16 +4535,16 @@ int atcommand_broadcast(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_localbroadcast(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - if (!message || !*message) + if (!message) { clif_displaymessage(fd, - "Please, enter a message (usage: @localbroadcast <message>)."); + "Please, enter a message (usage: @localbroadcast <message>)."); return -1; } - std::string output = STRPRINTF("%s : %s", sd->status.name, message); + FString output = STRPRINTF("%s : %s", sd->status.name, message); clif_GMmessage(sd, output, 1); // 1: ALL_SAMEMAP @@ -4736,35 +4556,34 @@ int atcommand_localbroadcast(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_email(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char actual_email[100] {}; - char new_email[100] {}; + AccountEmail actual_email; + AccountEmail new_email; - if (!message || !*message - || sscanf(message, "%99s %99s", actual_email, new_email) < 2) + if (!extract(message, record<' '>(&actual_email, &new_email))) { clif_displaymessage(fd, - "Please enter 2 emails (usage: @email <actual@email> <new@email>)."); + "Please enter 2 emails (usage: @email <actual@email> <new@email>)."); return -1; } - if (e_mail_check(actual_email) == 0) + if (!e_mail_check(actual_email)) { clif_displaymessage(fd, "Invalid actual email. If you have default e-mail, type a@a.com."); // Invalid actual email. If you have default e-mail, give a@a.com. return -1; } - else if (e_mail_check(new_email) == 0) + else if (!e_mail_check(new_email)) { clif_displaymessage(fd, "Invalid new email. Please enter a real e-mail."); return -1; } - else if (strcasecmp(new_email, "a@a.com") == 0) + else if (new_email == DEFAULT_EMAIL) { clif_displaymessage(fd, "New email must be a real e-mail."); return -1; } - else if (strcasecmp(actual_email, new_email) == 0) + else if (actual_email == new_email) { clif_displaymessage(fd, "New email must be different of the actual e-mail."); return -1; @@ -4783,14 +4602,14 @@ int atcommand_email(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_effect(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { int type = 0, flag = 0; - if (!message || !*message || sscanf(message, "%d %d", &type, &flag) < 2) + if (!extract(message, record<' '>(&type, &flag))) { clif_displaymessage(fd, - "Please, enter at least a option (usage: @effect <type+>)."); + "Please, enter at least a option (usage: @effect <type+>)."); return -1; } if (flag <= 0) @@ -4821,22 +4640,21 @@ int atcommand_effect(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; struct item_data *item_data, *item_temp; int i, j, count, counter, counter2; - char character[100] {}; - char equipstr[100]; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charitemlist <char name>)."); + "Please, enter a player name (usage: @charitemlist <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level @@ -4853,50 +4671,51 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, count++; if (count == 1) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "------ Items list of '%s' ------", pl_sd->status.name); clif_displaymessage(fd, output); } - EPOS equip; - if (bool(equip = pl_sd->status.inventory[i].equip)) + EPOS equip = pl_sd->status.inventory[i].equip; + MString equipstr; + if (bool(equip)) { - strcpy(equipstr, "| equiped: "); + equipstr += "| equiped: "; if (bool(equip & EPOS::GLOVES)) - strcat(equipstr, "robe/gargment, "); + equipstr += "robe/gargment, "; if (bool(equip & EPOS::CAPE)) - strcat(equipstr, "left accessory, "); + equipstr += "left accessory, "; if (bool(equip & EPOS::MISC1)) - strcat(equipstr, "body/armor, "); + equipstr += "body/armor, "; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::WEAPON) - strcat(equipstr, "right hand, "); + equipstr += "right hand, "; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::SHIELD) - strcat(equipstr, "left hand, "); + equipstr += "left hand, "; if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == (EPOS::WEAPON | EPOS::SHIELD)) - strcat(equipstr, "both hands, "); + equipstr += "both hands, "; if (bool(equip & EPOS::SHOES)) - strcat(equipstr, "feet, "); + equipstr += "feet, "; if (bool(equip & EPOS::MISC2)) - strcat(equipstr, "right accessory, "); + equipstr += "right accessory, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::LEGS) - strcat(equipstr, "lower head, "); + equipstr += "lower head, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::HAT) - strcat(equipstr, "top head, "); + equipstr += "top head, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::HAT | EPOS::LEGS)) - strcat(equipstr, "lower/top head, "); + equipstr += "lower/top head, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::TORSO) - strcat(equipstr, "mid head, "); + equipstr += "mid head, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::LEGS)) - strcat(equipstr, "lower/mid head, "); + equipstr += "lower/mid head, "; if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) - strcat(equipstr, "lower/mid/top head, "); + equipstr += "lower/mid/top head, "; // remove final ', ' - equipstr[strlen(equipstr) - 2] = '\0'; + equipstr.pop_back(2); } else - strzcpy(equipstr, "", sizeof(equipstr)); + equipstr = MString(); - std::string output; + FString output; if (sd->status.inventory[i].refine) output = STRPRINTF("%d %s %+d (%s %+d, id: %d) %s", pl_sd->status.inventory[i].amount, @@ -4904,15 +4723,17 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, pl_sd->status.inventory[i].refine, item_data->jname, pl_sd->status.inventory[i].refine, - pl_sd->status.inventory[i].nameid, equipstr); + pl_sd->status.inventory[i].nameid, + FString(equipstr)); else output = STRPRINTF("%d %s (%s, id: %d) %s", pl_sd->status.inventory[i].amount, item_data->name, item_data->jname, - pl_sd->status.inventory[i].nameid, equipstr); + pl_sd->status.inventory[i].nameid, + FString(equipstr)); clif_displaymessage(fd, output); - output.clear(); + MString voutput; counter2 = 0; for (j = 0; j < item_data->slot; j++) { @@ -4923,14 +4744,15 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, inventory[i].card[j])) != NULL) { - if (output.empty()) - output = STRPRINTF( - " -> (card(s): #%d %s (%s), ", + if (!voutput) + voutput += STRPRINTF( + " -> (card(s): " + "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname); else - output += STRPRINTF( + voutput += STRPRINTF( "#%d %s (%s), ", ++counter2, item_temp->name, @@ -4938,16 +4760,12 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, } } } - if (!output.empty()) + if (voutput) { // replace trailing ", " -#ifdef WORKAROUND_GCC46_LIBRARY - output.resize(output.size() - 1); -#else - output.pop_back(); -#endif - output.back() = ')'; - clif_displaymessage(fd, output); + voutput.pop_back(); + voutput.back() = ')'; + clif_displaymessage(fd, FString(voutput)); } } } @@ -4955,7 +4773,7 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, clif_displaymessage(fd, "No item found on this player."); else { - std::string output = STRPRINTF( + FString output = STRPRINTF( "%d item(s) found in %d kind(s) of items.", counter, count); clif_displaymessage(fd, output); @@ -4981,22 +4799,22 @@ int atcommand_character_item_list(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { struct storage *stor; - dumb_ptr<map_session_data> pl_sd; struct item_data *item_data, *item_temp; int i, j, count, counter, counter2; - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charitemlist <char name>)."); + "Please, enter a player name (usage: @charitemlist <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level @@ -5014,12 +4832,12 @@ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd count++; if (count == 1) { - std::string output = STRPRINTF( - "------ Storage items list of '%s' ------", - pl_sd->status.name); + FString output = STRPRINTF( + "------ Storage items list of '%s' ------", + pl_sd->status.name); clif_displaymessage(fd, output); } - std::string output; + FString output; if (stor->storage_[i].refine) output = STRPRINTF("%d %s %+d (%s %+d, id: %d)", stor->storage_[i].amount, @@ -5035,7 +4853,7 @@ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd stor->storage_[i].nameid); clif_displaymessage(fd, output); - output.clear(); + MString voutput; counter2 = 0; for (j = 0; j < item_data->slot; j++) { @@ -5046,14 +4864,15 @@ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd storage_[i].card[j])) != NULL) { - if (output.empty()) - output = STRPRINTF( - " -> (card(s): #%d %s (%s), ", + if (!voutput) + voutput += STRPRINTF( + " -> (card(s): " + "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname); else - output += STRPRINTF( + voutput += STRPRINTF( "#%d %s (%s), ", ++counter2, item_temp->name, @@ -5061,27 +4880,23 @@ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd } } } - if (!output.empty()) + if (voutput) { // replace last ", " -#ifdef WORKAROUND_GCC46_LIBRARY - output.resize(output.size() - 1); -#else - output.pop_back(); -#endif - output.back() = ')'; - clif_displaymessage(fd, output); + voutput.pop_back(); + voutput.back() = ')'; + clif_displaymessage(fd, FString(voutput)); } } } if (count == 0) clif_displaymessage(fd, - "No item found in the storage of this player."); + "No item found in the storage of this player."); else { - std::string output = STRPRINTF( - "%d item(s) found in %d kind(s) of items.", - counter, count); + FString output = STRPRINTF( + "%d item(s) found in %d kind(s) of items.", + counter, count); clif_displaymessage(fd, output); } } @@ -5111,21 +4926,21 @@ int atcommand_character_storage_list(const int fd, dumb_ptr<map_session_data> sd *------------------------------------------ */ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd; struct item_data *item_data, *item_temp; int i, j, count, counter, counter2; - char character[100] {}; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, - "Please, enter a player name (usage: @charitemlist <char name>)."); + "Please, enter a player name (usage: @charitemlist <char name>)."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level @@ -5141,13 +4956,13 @@ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, count++; if (count == 1) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "------ Cart items list of '%s' ------", pl_sd->status.name); clif_displaymessage(fd, output); } - std::string output; + FString output; if (pl_sd->status.cart[i].refine) output = STRPRINTF("%d %s %+d (%s %+d, id: %d)", pl_sd->status.cart[i].amount, @@ -5164,7 +4979,7 @@ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, pl_sd->status.cart[i].nameid); clif_displaymessage(fd, output); - output.clear(); + MString voutput; counter2 = 0; for (j = 0; j < item_data->slot; j++) { @@ -5174,14 +4989,15 @@ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, itemdb_search(pl_sd->status. cart[i].card[j])) != NULL) { - if (output.empty()) - output = STRPRINTF( - " -> (card(s): #%d %s (%s), ", + if (!voutput) + voutput += STRPRINTF( + " -> (card(s): " + "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname); else - output += STRPRINTF( + voutput += STRPRINTF( "#%d %s (%s), ", ++counter2, item_temp->name, @@ -5189,24 +5005,20 @@ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, } } } - if (!output.empty()) + if (voutput) { -#ifdef WORKAROUND_GCC46_LIBRARY - output.resize(output.size() - 1); -#else - output.pop_back(); -#endif - output.back() = '0'; - clif_displaymessage(fd, output); + voutput.pop_back(); + voutput.back() = '0'; + clif_displaymessage(fd, FString(voutput)); } } } if (count == 0) clif_displaymessage(fd, - "No item found in the cart of this player."); + "No item found in the cart of this player."); else { - std::string output = STRPRINTF("%d item(s) found in %d kind(s) of items.", + FString output = STRPRINTF("%d item(s) found in %d kind(s) of items.", counter, count); clif_displaymessage(fd, output); } @@ -5232,7 +5044,7 @@ int atcommand_character_cart_list(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_killer(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { sd->special_state.killer = !sd->special_state.killer; @@ -5250,7 +5062,7 @@ int atcommand_killer(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_killable(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { sd->special_state.killable = !sd->special_state.killable; @@ -5268,14 +5080,15 @@ int atcommand_killable(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charkillable(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd = NULL; + CharName character; - if (!message || !*message) + if (!asplit(message, &character)) return -1; - if ((pl_sd = map_nick2sd(message)) == NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd == NULL) return -1; pl_sd->special_state.killable = !pl_sd->special_state.killable; @@ -5295,19 +5108,16 @@ int atcommand_charkillable(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_npcmove(const int, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char character[100] {}; + NpcName character; int x = 0, y = 0; dumb_ptr<npc_data> nd = 0; if (sd == NULL) return -1; - if (!message || !*message) - return -1; - - if (sscanf(message, "%d %d %99[^\n]", &x, &y, character) < 3) + if (!asplit(message, &x, &y, &character)) return -1; nd = npc_name2id(character); @@ -5329,24 +5139,22 @@ int atcommand_npcmove(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_addwarp(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char mapname[30]; - int x, y, ret; + MapName mapname; + int x, y; - if (!message || !*message) + if (!extract(message, record<' '>(&mapname, &x, &y))) return -1; - if (sscanf(message, "%29s %d %d[^\n]", mapname, &x, &y) < 3) - return -1; - - std::string w1 = STRPRINTF("%s,%d,%d", sd->mapname_, sd->bl_x, sd->bl_y); - std::string w3 = STRPRINTF("%s%d%d%d%d", mapname, sd->bl_x, sd->bl_y, x, y); - std::string w4 = STRPRINTF("1,1,%s.gat,%d,%d", mapname, x, y); + FString w1 = STRPRINTF("%s,%d,%d", sd->mapname_, sd->bl_x, sd->bl_y); + FString w3 = STRPRINTF("%s%d%d%d%d", mapname, sd->bl_x, sd->bl_y, x, y); + FString w4 = STRPRINTF("1,1,%s.gat,%d,%d", mapname, x, y); - ret = npc_parse_warp(w1.c_str(), "warp", w3.c_str(), w4.c_str()); + NpcName w3name = stringish<NpcName>(w3); + int ret = npc_parse_warp(w1, ZString("warp"), w3name, w4); - std::string output = STRPRINTF("New warp NPC => %s", w3); + FString output = STRPRINTF("New warp NPC => %s", w3); clif_displaymessage(fd, output); return ret; @@ -5359,20 +5167,19 @@ int atcommand_addwarp(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_chareffect(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd = NULL; - char target[255]; + CharName target; int type = 0; - if (!message || !*message - || sscanf(message, "%d %s", &type, target) != 2) + if (!asplit(message, &type, &target)) { clif_displaymessage(fd, "usage: @chareffect <type+> <target>."); return -1; } - if ((pl_sd = map_nick2sd(target)) == NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(target); + if (pl_sd == NULL) return -1; clif_specialeffect(pl_sd, type, 0); @@ -5388,7 +5195,7 @@ int atcommand_chareffect(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_dropall(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int i; for (i = 0; i < MAX_INVENTORY; i++) @@ -5411,16 +5218,16 @@ int atcommand_dropall(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_chardropall(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - int i; - dumb_ptr<map_session_data> pl_sd = NULL; + CharName character; - if (!message || !*message) + if (!asplit(message, &character)) return -1; - if ((pl_sd = map_nick2sd(message)) == NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd == NULL) return -1; - for (i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < MAX_INVENTORY; i++) { if (pl_sd->status.inventory[i].amount) { @@ -5445,7 +5252,7 @@ int atcommand_chardropall(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_storeall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int i; nullpo_retr(-1, sd); @@ -5459,7 +5266,7 @@ int atcommand_storeall(const int fd, dumb_ptr<map_session_data> sd, return 0; case 1: //Failure clif_displaymessage(fd, - "You can't open the storage currently."); + "You can't open the storage currently."); return 1; } } @@ -5485,24 +5292,24 @@ int atcommand_storeall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_charstoreall(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - int i; - dumb_ptr<map_session_data> pl_sd = NULL; + CharName character; - if (!message || !*message) + if (!asplit(message, &character)) return -1; - if ((pl_sd = map_nick2sd(message)) == NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd == NULL) return -1; if (storage_storageopen(pl_sd) == 1) { clif_displaymessage(fd, - "Had to open the characters storage window..."); + "Had to open the characters storage window..."); clif_displaymessage(fd, "run this command again.."); return 0; } - for (i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < MAX_INVENTORY; i++) { if (pl_sd->status.inventory[i].amount) { @@ -5514,9 +5321,9 @@ int atcommand_charstoreall(const int fd, dumb_ptr<map_session_data> sd, storage_storageclose(pl_sd); clif_displaymessage(pl_sd->fd, - "Everything you own has been put away for safe keeping."); + "Everything you own has been put away for safe keeping."); clif_displaymessage(pl_sd->fd, - "go to the nearest kafka to retrieve it.."); + "go to the nearest kafka to retrieve it.."); clif_displaymessage(pl_sd->fd, " -- the management"); clif_displaymessage(fd, "It is done"); @@ -5529,7 +5336,7 @@ int atcommand_charstoreall(const int fd, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_rain(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int effno = 0; effno = 161; @@ -5547,7 +5354,7 @@ int atcommand_rain(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_snow(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int effno = 0; effno = 162; @@ -5565,7 +5372,7 @@ int atcommand_snow(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_sakura(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int effno = 0; effno = 163; @@ -5583,7 +5390,7 @@ int atcommand_sakura(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_fog(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int effno = 0; effno = 233; @@ -5602,7 +5409,7 @@ int atcommand_fog(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_leaves(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { int effno = 0; effno = 333; @@ -5620,24 +5427,21 @@ int atcommand_leaves(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_summon(const int, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char name[100]; + MobName name; int mob_id = 0; int x = 0; int y = 0; int id = 0; - dumb_ptr<mob_data> md; tick_t tick = gettick(); nullpo_retr(-1, sd); - if (!message || !*message) - return -1; - if (sscanf(message, "%99[^\n]", name) < 1) + if (!extract(message, &name) || !name) return -1; - if ((mob_id = atoi(name)) == 0) + if ((mob_id = atoi(name.c_str())) == 0) mob_id = mobdb_searchname(name); if (mob_id == 0) return -1; @@ -5645,8 +5449,9 @@ int atcommand_summon(const int, dumb_ptr<map_session_data> sd, x = sd->bl_x + random_::in(-5, 4); y = sd->bl_y + random_::in(-5, 4); - id = mob_once_spawn(sd, "this", x, y, "--ja--", mob_id, 1, ""); - if ((md = map_id_as_mob(id))) + id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent()); + dumb_ptr<mob_data> md = map_id_as_mob(id); + if (md) { md->master_id = sd->bl_id; md->state.special_mob_ai = 1; @@ -5670,19 +5475,19 @@ int atcommand_summon(const int, dumb_ptr<map_session_data> sd, *------------------------------------------ */ int atcommand_adjcmdlvl(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - int i, newlev; - char cmd[100]; + int newlev; + XString cmd; - if (!message || !*message || sscanf(message, "%d %s", &newlev, cmd) != 2) + if (!extract(message, record<' '>(&newlev, &cmd))) { clif_displaymessage(fd, "usage: @adjcmdlvl <lvl> <command>."); return -1; } - for (i = 0; atcommand_info[i].command; i++) - if (strcasecmp(cmd, atcommand_info[i].command + 1) == 0) + for (int i = 0; atcommand_info[i].command; i++) + if (cmd == atcommand_info[i].command.xslice_t(1)) { atcommand_info[i].level = newlev; clif_displaymessage(fd, "@command level changed."); @@ -5703,21 +5508,20 @@ int atcommand_adjcmdlvl(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_adjgmlvl(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { int newlev; - char user[100]; - dumb_ptr<map_session_data> pl_sd; + CharName user; - if (!message || !*message - || sscanf(message, "%d %s", &newlev, user) != 2 + if (!asplit(message, &newlev, &user) || newlev < 0 || newlev > 99) { clif_displaymessage(fd, "usage: @adjgmlvl <lvl> <user>."); return -1; } - if ((pl_sd = map_nick2sd(user)) == NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(user); + if (pl_sd == NULL) return -1; pc_set_gm_level(pl_sd->status.account_id, newlev); @@ -5735,13 +5539,15 @@ int atcommand_adjgmlvl(const int fd, dumb_ptr<map_session_data>, *------------------------------------------ */ int atcommand_trade(const int, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - dumb_ptr<map_session_data> pl_sd = NULL; + CharName character; - if (!message || !*message) + if (!asplit(message, &character)) return -1; - if ((pl_sd = map_nick2sd(message)) != NULL) + + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd) { trade_traderequest(sd, pl_sd->bl_id); return 0; @@ -5766,7 +5572,7 @@ constexpr size_t magic_skills_nr = sizeof(magic_skills) / sizeof(magic_skills[0]); static -const char *magic_skill_names[magic_skills_nr] = +ZString magic_skill_names[magic_skills_nr] = { "magic", "life", @@ -5777,20 +5583,20 @@ const char *magic_skill_names[magic_skills_nr] = }; int atcommand_magic_info(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100] {}; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, "Usage: @magicinfo <char_name>"); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd) { - std::string buf = STRPRINTF( + FString buf = STRPRINTF( "`%s' has the following magic skills:", character); clif_displaymessage(fd, buf); @@ -5821,30 +5627,27 @@ void set_skill(dumb_ptr<map_session_data> sd, SkillID i, int level) } int atcommand_set_magic(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100] {}; - char magic_type[20]; + CharName character; + XString magic_type; int value; - dumb_ptr<map_session_data> pl_sd; - if (!message || !*message - || sscanf(message, "%19s %i %99[^\n]", magic_type, &value, - character) < 1) + if (!asplit(message, &magic_type, &value, &character)) { clif_displaymessage(fd, - "Usage: @setmagic <school> <value> <char-name>, where <school> is either `magic', one of the school names, or `all'."); + "Usage: @setmagic <school> <value> <char-name>, where <school> is either `magic', one of the school names, or `all'."); return -1; } SkillID skill_index = SkillID::NEGATIVE; - if (!strcasecmp("all", magic_type)) + if ("all" == magic_type) skill_index = SkillID::ZERO; else { for (size_t i = 0; i < magic_skills_nr; i++) { - if (!strcasecmp(magic_skill_names[i], magic_type)) + if (magic_skill_names[i] == magic_type) { skill_index = magic_skills[i]; break; @@ -5855,11 +5658,12 @@ int atcommand_set_magic(const int fd, dumb_ptr<map_session_data>, if (skill_index == SkillID::NEGATIVE) { clif_displaymessage(fd, - "Incorrect school of magic. Use `magic', `nature', `life', `war', `transmute', `ether', or `all'."); + "Incorrect school of magic. Use `magic', `nature', `life', `war', `transmute', `ether', or `all'."); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (skill_index == SkillID::ZERO) for (SkillID sk : magic_skills) @@ -5877,32 +5681,32 @@ int atcommand_set_magic(const int fd, dumb_ptr<map_session_data>, } int atcommand_log(const int, dumb_ptr<map_session_data>, - const char *, const char *) + ZString) { return 0; // only used for (implicit) logging } int atcommand_tee(const int, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { - char data[strlen(message) + 28]; - strcpy(data, sd->status.name); - strcat(data, " : "); - strcat(data, message); - clif_message(sd, data); + MString data; + data += sd->status.name.to__actual(); + data += " : "; + data += message; + clif_message(sd, FString(data)); return 0; } int atcommand_invisible(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { pc_invisibility(sd, 1); return 0; } int atcommand_visible(const int, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { pc_invisibility(sd, 0); return 0; @@ -5910,7 +5714,6 @@ int atcommand_visible(const int, dumb_ptr<map_session_data> sd, static int atcommand_jump_iterate(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *, dumb_ptr<map_session_data> (*get_start)(void), dumb_ptr<map_session_data> (*get_next)(dumb_ptr<map_session_data>)) { @@ -5935,18 +5738,18 @@ int atcommand_jump_iterate(const int fd, dumb_ptr<map_session_data> sd, && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you to the map of this player."); + "You are not authorised to warp you to the map of this player."); return -1; } if (sd->bl_m && sd->bl_m->flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, - "You are not authorised to warp you from your actual map."); + "You are not authorised to warp you from your actual map."); return -1; } pc_setpos(sd, pl_sd->bl_m->name_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED); - std::string output = STRPRINTF("Jump to %s", pl_sd->status.name); + FString output = STRPRINTF("Jump to %s", pl_sd->status.name); clif_displaymessage(fd, output); sd->followtarget = pl_sd->bl_id; @@ -5954,33 +5757,23 @@ int atcommand_jump_iterate(const int fd, dumb_ptr<map_session_data> sd, return 0; } -int atcommand_iterate_forward_over_players(const int fd, - dumb_ptr<map_session_data> sd, - const char *command, - const char *message) +int atcommand_iterate_forward_over_players(const int fd, dumb_ptr<map_session_data> sd, ZString) { - return atcommand_jump_iterate(fd, sd, command, message, - map_get_first_session, - map_get_next_session); + return atcommand_jump_iterate(fd, sd, map_get_first_session, map_get_next_session); } -int atcommand_iterate_backwards_over_players(const int fd, - dumb_ptr<map_session_data> sd, - const char *command, - const char *message) +int atcommand_iterate_backwards_over_players(const int fd, dumb_ptr<map_session_data> sd, ZString) { - return atcommand_jump_iterate(fd, sd, command, message, - map_get_last_session, - map_get_prev_session); + return atcommand_jump_iterate(fd, sd, map_get_last_session, map_get_prev_session); } int atcommand_wgm(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *message) + ZString message) { if (tmw_CheckChatSpam(sd, message)) return 0; - tmw_GmHackMsg(STRPRINTF("[GM] %s: %s", sd->status.name, message).c_str()); + tmw_GmHackMsg(STRPRINTF("[GM] %s: %s", sd->status.name, message)); if (!pc_isGM(sd)) clif_displaymessage(fd, "Message sent."); @@ -5989,24 +5782,24 @@ int atcommand_wgm(const int fd, dumb_ptr<map_session_data> sd, int atcommand_skillpool_info(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100]; - dumb_ptr<map_session_data> pl_sd; + CharName character; - if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, "Usage: @sp-info <char_name>"); return -1; } - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { SkillID pool_skills[MAX_SKILL_POOL]; int pool_skills_nr = skill_pool(pl_sd, pool_skills); int i; - std::string buf = STRPRINTF( + FString buf = STRPRINTF( "Active skills %d out of %d for %s:", pool_skills_nr, skill_pool_max(pl_sd), character); clif_displaymessage(fd, buf); @@ -6044,22 +5837,19 @@ int atcommand_skillpool_info(const int fd, dumb_ptr<map_session_data>, } int atcommand_skillpool_focus(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100]; - int skill_; - dumb_ptr<map_session_data> pl_sd; + CharName character; + SkillID skill; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &skill_, character) < 1) + if (!asplit(message, &skill, &character)) { clif_displaymessage(fd, "Usage: @sp-focus <skill-nr> <char_name>"); return -1; } - SkillID skill = SkillID(skill_); - - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (skill_pool_activate(pl_sd, skill)) clif_displaymessage(fd, "Activation failed."); @@ -6073,22 +5863,19 @@ int atcommand_skillpool_focus(const int fd, dumb_ptr<map_session_data>, } int atcommand_skillpool_unfocus(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100]; - int skill_; - dumb_ptr<map_session_data> pl_sd; + CharName character; + SkillID skill; - if (!message || !*message - || sscanf(message, "%d %99[^\n]", &skill_, character) < 1) + if (!asplit(message, &skill, &character)) { clif_displaymessage(fd, "Usage: @sp-unfocus <skill-nr> <char_name>"); return -1; } - SkillID skill = SkillID(skill_); - - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { if (skill_pool_deactivate(pl_sd, skill)) clif_displaymessage(fd, "Deactivation failed."); @@ -6102,23 +5889,21 @@ int atcommand_skillpool_unfocus(const int fd, dumb_ptr<map_session_data>, } int atcommand_skill_learn(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { - char character[100]; - int skill_, level; - dumb_ptr<map_session_data> pl_sd; + CharName character; + SkillID skill; + int level; - if (!message || !*message - || sscanf(message, "%d %d %99[^\n]", &skill_, &level, character) < 1) + if (!asplit(message, &skill, &level, &character)) { clif_displaymessage(fd, - "Usage: @skill-learn <skill-nr> <level> <char_name>"); + "Usage: @skill-learn <skill-nr> <level> <char_name>"); return -1; } - SkillID skill = SkillID(skill_); - - if ((pl_sd = map_nick2sd(character)) != NULL) + dumb_ptr<map_session_data> pl_sd = map_nick2sd(character); + if (pl_sd != NULL) { set_skill(pl_sd, skill, level); clif_skillinfoblock(pl_sd); @@ -6130,14 +5915,14 @@ int atcommand_skill_learn(const int fd, dumb_ptr<map_session_data>, } int atcommand_ipcheck(const int fd, dumb_ptr<map_session_data>, - const char *, const char *message) + ZString message) { struct sockaddr_in sai; - char character[25] {}; + CharName character; socklen_t sa_len = sizeof(struct sockaddr); unsigned long ip; - if (sscanf(message, "%24[^\n]", character) < 1) + if (!asplit(message, &character)) { clif_displaymessage(fd, "Usage: @ipcheck <char name>"); return -1; @@ -6153,7 +5938,7 @@ int atcommand_ipcheck(const int fd, dumb_ptr<map_session_data>, if (getpeername(pl_sd->fd, reinterpret_cast<struct sockaddr *>(&sai), &sa_len)) { clif_displaymessage(fd, - "Guru Meditation Error: getpeername() failed"); + "Guru Meditation Error: getpeername() failed"); return -1; } @@ -6175,7 +5960,7 @@ int atcommand_ipcheck(const int fd, dumb_ptr<map_session_data>, // Is checking GM levels really needed here? if (ip == sai.sin_addr.s_addr) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Name: %s | Location: %s %d %d", pl_sd->status.name, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y); @@ -6189,7 +5974,7 @@ int atcommand_ipcheck(const int fd, dumb_ptr<map_session_data>, } int atcommand_doomspot(const int fd, dumb_ptr<map_session_data> sd, - const char *, const char *) + ZString) { for (int i = 0; i < fd_max; i++) { diff --git a/src/map/atcommand.hpp b/src/map/atcommand.hpp index d81f04d..7f31491 100644 --- a/src/map/atcommand.hpp +++ b/src/map/atcommand.hpp @@ -6,13 +6,13 @@ #include "map.hpp" bool is_atcommand(const int fd, dumb_ptr<map_session_data> sd, - const char *message, int gmlvl); + ZString message, int gmlvl); -int atcommand_config_read(const char *cfgName); +int atcommand_config_read(ZString cfgName); -void log_atcommand(dumb_ptr<map_session_data> sd, const_string cmd); +void log_atcommand(dumb_ptr<map_session_data> sd, XString cmd); // only used by map.cpp -extern std::string gm_logfile_name; +extern FString gm_logfile_name; #endif // ATCOMMAND_HPP diff --git a/src/map/battle.cpp b/src/map/battle.cpp index abef80b..4045348 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -5,8 +5,9 @@ #include <fstream> #include "../common/cxxstdio.hpp" -#include "../common/random.hpp" +#include "../common/io.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "clif.hpp" #include "itemdb.hpp" @@ -2290,7 +2291,7 @@ int battle_check_range(dumb_ptr<block_list> src, dumb_ptr<block_list> bl, * 設定ファイルを読み込む *------------------------------------------ */ -int battle_config_read(const char *cfgName) +int battle_config_read(ZString cfgName) { static int count = 0; @@ -2458,200 +2459,203 @@ int battle_config_read(const char *cfgName) battle_config.mob_splash_radius = -1; } - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { PRINTF("file not found: %s\n", cfgName); return 1; } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { +#define BATTLE_CONFIG_VAR2(name, varname) {{name}, &battle_config.varname} +#define BATTLE_CONFIG_VAR(name) BATTLE_CONFIG_VAR2(#name, name) // s/{"\([a-zA-Z_0-9]*\)", &battle_config.\1}/BATTLE_CONFIG_VAR(\1)/ const struct { - const char *str; + ZString str; int *val; } data[] = { - {"warp_point_debug", &battle_config.warp_point_debug}, - {"enemy_critical", &battle_config.enemy_critical}, - {"enemy_critical_rate", &battle_config.enemy_critical_rate}, - {"enemy_str", &battle_config.enemy_str}, - {"enemy_perfect_flee", &battle_config.enemy_perfect_flee}, - {"casting_rate", &battle_config.cast_rate}, - {"delay_rate", &battle_config.delay_rate}, - {"delay_dependon_dex", &battle_config.delay_dependon_dex}, - {"skill_delay_attack_enable", &battle_config.sdelay_attack_enable}, - {"left_cardfix_to_right", &battle_config.left_cardfix_to_right}, - {"player_skill_add_range", &battle_config.pc_skill_add_range}, - {"skill_out_range_consume", &battle_config.skill_out_range_consume}, - {"monster_skill_add_range", &battle_config.mob_skill_add_range}, - {"player_damage_delay", &battle_config.pc_damage_delay}, - {"defunit_not_enemy", &battle_config.defnotenemy}, - {"random_monster_checklv", &battle_config.random_monster_checklv}, - {"attribute_recover", &battle_config.attr_recover}, - {"flooritem_lifetime", &battle_config.flooritem_lifetime}, - {"item_auto_get", &battle_config.item_auto_get}, - {"drop_pickup_safety_zone", &battle_config.drop_pickup_safety_zone}, - {"item_first_get_time", &battle_config.item_first_get_time}, - {"item_second_get_time", &battle_config.item_second_get_time}, - {"item_third_get_time", &battle_config.item_third_get_time}, - {"base_exp_rate", &battle_config.base_exp_rate}, - {"job_exp_rate", &battle_config.job_exp_rate}, - {"gtb_pvp_only", &battle_config.gtb_pvp_only}, - {"death_penalty_type", &battle_config.death_penalty_type}, - {"death_penalty_base", &battle_config.death_penalty_base}, - {"death_penalty_job", &battle_config.death_penalty_job}, - {"zeny_penalty", &battle_config.zeny_penalty}, - {"restart_hp_rate", &battle_config.restart_hp_rate}, - {"restart_sp_rate", &battle_config.restart_sp_rate}, - {"monster_hp_rate", &battle_config.monster_hp_rate}, - {"monster_max_aspd", &battle_config.monster_max_aspd}, - {"atcommand_gm_only", &battle_config.atc_gmonly}, - {"atcommand_spawn_quantity_limit", &battle_config.atc_spawn_quantity_limit}, - {"gm_all_skill", &battle_config.gm_allskill}, - {"gm_all_skill_add_abra", &battle_config.gm_allskill_addabra}, - {"gm_all_equipment", &battle_config.gm_allequip}, - {"gm_skill_unconditional", &battle_config.gm_skilluncond}, - {"player_skillfree", &battle_config.skillfree}, - {"player_skillup_limit", &battle_config.skillup_limit}, - {"weapon_produce_rate", &battle_config.wp_rate}, - {"potion_produce_rate", &battle_config.pp_rate}, - {"monster_active_enable", &battle_config.monster_active_enable}, - {"mob_skill_use", &battle_config.mob_skill_use}, - {"mob_count_rate", &battle_config.mob_count_rate}, - {"quest_skill_learn", &battle_config.quest_skill_learn}, - {"quest_skill_reset", &battle_config.quest_skill_reset}, - {"basic_skill_check", &battle_config.basic_skill_check}, - {"player_invincible_time", &battle_config.pc_invincible_time}, - {"skill_min_damage", &battle_config.skill_min_damage}, - {"finger_offensive_type", &battle_config.finger_offensive_type}, - {"heal_exp", &battle_config.heal_exp}, - {"resurrection_exp", &battle_config.resurrection_exp}, - {"shop_exp", &battle_config.shop_exp}, - {"combo_delay_rate", &battle_config.combo_delay_rate}, - {"wedding_modifydisplay", &battle_config.wedding_modifydisplay}, - {"natural_healhp_interval", &battle_config.natural_healhp_interval}, - {"natural_healsp_interval", &battle_config.natural_healsp_interval}, - {"natural_heal_skill_interval", &battle_config.natural_heal_skill_interval}, - {"natural_heal_weight_rate", &battle_config.natural_heal_weight_rate}, - {"itemheal_regeneration_factor", &battle_config.itemheal_regeneration_factor}, - {"item_name_override_grffile", &battle_config.item_name_override_grffile}, - {"arrow_decrement", &battle_config.arrow_decrement}, - {"max_aspd", &battle_config.max_aspd}, - {"max_hp", &battle_config.max_hp}, - {"max_sp", &battle_config.max_sp}, - {"max_lv", &battle_config.max_lv}, - {"max_parameter", &battle_config.max_parameter}, - {"max_cart_weight", &battle_config.max_cart_weight}, - {"player_skill_log", &battle_config.pc_skill_log}, - {"monster_skill_log", &battle_config.mob_skill_log}, - {"battle_log", &battle_config.battle_log}, - {"save_log", &battle_config.save_log}, - {"error_log", &battle_config.error_log}, - {"etc_log", &battle_config.etc_log}, - {"save_clothcolor", &battle_config.save_clothcolor}, - {"undead_detect_type", &battle_config.undead_detect_type}, - {"player_auto_counter_type", &battle_config.pc_auto_counter_type}, - {"monster_auto_counter_type", &battle_config.monster_auto_counter_type}, - {"agi_penaly_type", &battle_config.agi_penaly_type}, - {"agi_penaly_count", &battle_config.agi_penaly_count}, - {"agi_penaly_num", &battle_config.agi_penaly_num}, - {"agi_penaly_count_lv", &battle_config.agi_penaly_count_lv}, - {"vit_penaly_type", &battle_config.vit_penaly_type}, - {"vit_penaly_count", &battle_config.vit_penaly_count}, - {"vit_penaly_num", &battle_config.vit_penaly_num}, - {"vit_penaly_count_lv", &battle_config.vit_penaly_count_lv}, - {"player_skill_reiteration", &battle_config.pc_skill_reiteration}, - {"monster_skill_reiteration", &battle_config.monster_skill_reiteration}, - {"player_skill_nofootset", &battle_config.pc_skill_nofootset}, - {"monster_skill_nofootset", &battle_config.monster_skill_nofootset}, - {"player_cloak_check_type", &battle_config.pc_cloak_check_type}, - {"monster_cloak_check_type", &battle_config.monster_cloak_check_type}, - {"mob_changetarget_byskill", &battle_config.mob_changetarget_byskill}, - {"player_attack_direction_change", &battle_config.pc_attack_direction_change}, - {"monster_attack_direction_change", &battle_config.monster_attack_direction_change}, - {"player_land_skill_limit", &battle_config.pc_land_skill_limit}, - {"monster_land_skill_limit", &battle_config.monster_land_skill_limit}, - {"party_skill_penaly", &battle_config.party_skill_penaly}, - {"monster_class_change_full_recover", &battle_config.monster_class_change_full_recover}, - {"produce_item_name_input", &battle_config.produce_item_name_input}, - {"produce_potion_name_input", &battle_config.produce_potion_name_input}, - {"making_arrow_name_input", &battle_config.making_arrow_name_input}, - {"holywater_name_input", &battle_config.holywater_name_input}, - {"display_delay_skill_fail", &battle_config.display_delay_skill_fail}, - {"chat_warpportal", &battle_config.chat_warpportal}, - {"mob_warpportal", &battle_config.mob_warpportal}, - {"dead_branch_active", &battle_config.dead_branch_active}, - {"show_steal_in_same_party", &battle_config.show_steal_in_same_party}, - {"enable_upper_class", &battle_config.enable_upper_class}, - {"mob_attack_attr_none", &battle_config.mob_attack_attr_none}, - {"mob_ghostring_fix", &battle_config.mob_ghostring_fix}, - {"pc_attack_attr_none", &battle_config.pc_attack_attr_none}, - {"gx_allhit", &battle_config.gx_allhit}, - {"gx_cardfix", &battle_config.gx_cardfix}, - {"gx_dupele", &battle_config.gx_dupele}, - {"gx_disptype", &battle_config.gx_disptype}, - {"player_skill_partner_check", &battle_config.player_skill_partner_check}, - {"hide_GM_session", &battle_config.hide_GM_session}, - {"unit_movement_type", &battle_config.unit_movement_type}, - {"invite_request_check", &battle_config.invite_request_check}, - {"skill_removetrap_type", &battle_config.skill_removetrap_type}, - {"disp_experience", &battle_config.disp_experience}, - {"riding_weight", &battle_config.riding_weight}, - {"prevent_logout", &battle_config.prevent_logout}, // Added by RoVeRT - {"alchemist_summon_reward", &battle_config.alchemist_summon_reward}, // [Valaris] - {"maximum_level", &battle_config.maximum_level}, // [Valaris] - {"drops_by_luk", &battle_config.drops_by_luk}, // [Valaris] - {"monsters_ignore_gm", &battle_config.monsters_ignore_gm}, // [Valaris] - {"pk_mode", &battle_config.pk_mode}, // [Valaris] - {"multi_level_up", &battle_config.multi_level_up}, // [Valaris] - {"backstab_bow_penalty", &battle_config.backstab_bow_penalty}, - {"show_mob_hp", &battle_config.show_mob_hp}, // [Valaris] - {"hack_info_GM_level", &battle_config.hack_info_GM_level}, // added by [Yor] - {"any_warp_GM_min_level", &battle_config.any_warp_GM_min_level}, // added by [Yor] - {"packet_ver_flag", &battle_config.packet_ver_flag}, // added by [Yor] - {"min_hair_style", &battle_config.min_hair_style}, // added by [MouseJstr] - {"max_hair_style", &battle_config.max_hair_style}, // added by [MouseJstr] - {"min_hair_color", &battle_config.min_hair_color}, // added by [MouseJstr] - {"max_hair_color", &battle_config.max_hair_color}, // added by [MouseJstr] - {"min_cloth_color", &battle_config.min_cloth_color}, // added by [MouseJstr] - {"max_cloth_color", &battle_config.max_cloth_color}, // added by [MouseJstr] - {"castrate_dex_scale", &battle_config.castrate_dex_scale}, // added by [MouseJstr] - {"area_size", &battle_config.area_size}, // added by [MouseJstr] - {"chat_lame_penalty", &battle_config.chat_lame_penalty}, - {"chat_spam_threshold", &battle_config.chat_spam_threshold}, - {"chat_spam_flood", &battle_config.chat_spam_flood}, - {"chat_spam_ban", &battle_config.chat_spam_ban}, - {"chat_spam_warn", &battle_config.chat_spam_warn}, - {"chat_maxline", &battle_config.chat_maxline}, - {"packet_spam_threshold", &battle_config.packet_spam_threshold}, - {"packet_spam_flood", &battle_config.packet_spam_flood}, - {"packet_spam_kick", &battle_config.packet_spam_kick}, - {"mask_ip_gms", &battle_config.mask_ip_gms}, - {"mob_splash_radius", &battle_config.mob_splash_radius}, + BATTLE_CONFIG_VAR(warp_point_debug), + BATTLE_CONFIG_VAR(enemy_critical), + BATTLE_CONFIG_VAR(enemy_critical_rate), + BATTLE_CONFIG_VAR(enemy_str), + BATTLE_CONFIG_VAR(enemy_perfect_flee), + BATTLE_CONFIG_VAR2("casting_rate", cast_rate), + BATTLE_CONFIG_VAR(delay_rate), + BATTLE_CONFIG_VAR(delay_dependon_dex), + BATTLE_CONFIG_VAR2("skill_delay_attack_enable", sdelay_attack_enable), + BATTLE_CONFIG_VAR(left_cardfix_to_right), + BATTLE_CONFIG_VAR2("player_skill_add_range", pc_skill_add_range), + BATTLE_CONFIG_VAR(skill_out_range_consume), + BATTLE_CONFIG_VAR2("monster_skill_add_range", mob_skill_add_range), + BATTLE_CONFIG_VAR2("player_damage_delay", pc_damage_delay), + BATTLE_CONFIG_VAR2("defunit_not_enemy", defnotenemy), + BATTLE_CONFIG_VAR(random_monster_checklv), + BATTLE_CONFIG_VAR2("attribute_recover", attr_recover), + BATTLE_CONFIG_VAR(flooritem_lifetime), + BATTLE_CONFIG_VAR(item_auto_get), + BATTLE_CONFIG_VAR(drop_pickup_safety_zone), + BATTLE_CONFIG_VAR(item_first_get_time), + BATTLE_CONFIG_VAR(item_second_get_time), + BATTLE_CONFIG_VAR(item_third_get_time), + BATTLE_CONFIG_VAR(base_exp_rate), + BATTLE_CONFIG_VAR(job_exp_rate), + BATTLE_CONFIG_VAR(gtb_pvp_only), + BATTLE_CONFIG_VAR(death_penalty_type), + BATTLE_CONFIG_VAR(death_penalty_base), + BATTLE_CONFIG_VAR(death_penalty_job), + BATTLE_CONFIG_VAR(zeny_penalty), + BATTLE_CONFIG_VAR(restart_hp_rate), + BATTLE_CONFIG_VAR(restart_sp_rate), + BATTLE_CONFIG_VAR(monster_hp_rate), + BATTLE_CONFIG_VAR(monster_max_aspd), + BATTLE_CONFIG_VAR2("atcommand_gm_only", atc_gmonly), + BATTLE_CONFIG_VAR2("atcommand_spawn_quantity_limit", atc_spawn_quantity_limit), + BATTLE_CONFIG_VAR2("gm_all_skill", gm_allskill), + BATTLE_CONFIG_VAR2("gm_all_skill_add_abra", gm_allskill_addabra), + BATTLE_CONFIG_VAR2("gm_all_equipment", gm_allequip), + BATTLE_CONFIG_VAR2("gm_skill_unconditional", gm_skilluncond), + BATTLE_CONFIG_VAR2("player_skillfree", skillfree), + BATTLE_CONFIG_VAR2("player_skillup_limit", skillup_limit), + BATTLE_CONFIG_VAR2("weapon_produce_rate", wp_rate), + BATTLE_CONFIG_VAR2("potion_produce_rate", pp_rate), + BATTLE_CONFIG_VAR(monster_active_enable), + BATTLE_CONFIG_VAR(mob_skill_use), + BATTLE_CONFIG_VAR(mob_count_rate), + BATTLE_CONFIG_VAR(quest_skill_learn), + BATTLE_CONFIG_VAR(quest_skill_reset), + BATTLE_CONFIG_VAR(basic_skill_check), + BATTLE_CONFIG_VAR2("player_invincible_time", pc_invincible_time), + BATTLE_CONFIG_VAR(skill_min_damage), + BATTLE_CONFIG_VAR(finger_offensive_type), + BATTLE_CONFIG_VAR(heal_exp), + BATTLE_CONFIG_VAR(resurrection_exp), + BATTLE_CONFIG_VAR(shop_exp), + BATTLE_CONFIG_VAR(combo_delay_rate), + BATTLE_CONFIG_VAR(wedding_modifydisplay), + BATTLE_CONFIG_VAR(natural_healhp_interval), + BATTLE_CONFIG_VAR(natural_healsp_interval), + BATTLE_CONFIG_VAR(natural_heal_skill_interval), + BATTLE_CONFIG_VAR(natural_heal_weight_rate), + BATTLE_CONFIG_VAR(itemheal_regeneration_factor), + BATTLE_CONFIG_VAR(item_name_override_grffile), + BATTLE_CONFIG_VAR(arrow_decrement), + BATTLE_CONFIG_VAR(max_aspd), + BATTLE_CONFIG_VAR(max_hp), + BATTLE_CONFIG_VAR(max_sp), + BATTLE_CONFIG_VAR(max_lv), + BATTLE_CONFIG_VAR(max_parameter), + BATTLE_CONFIG_VAR(max_cart_weight), + BATTLE_CONFIG_VAR2("player_skill_log", pc_skill_log), + BATTLE_CONFIG_VAR2("monster_skill_log", mob_skill_log), + BATTLE_CONFIG_VAR(battle_log), + BATTLE_CONFIG_VAR(save_log), + BATTLE_CONFIG_VAR(error_log), + BATTLE_CONFIG_VAR(etc_log), + BATTLE_CONFIG_VAR(save_clothcolor), + BATTLE_CONFIG_VAR(undead_detect_type), + BATTLE_CONFIG_VAR2("player_auto_counter_type", pc_auto_counter_type), + BATTLE_CONFIG_VAR(monster_auto_counter_type), + BATTLE_CONFIG_VAR(agi_penaly_type), + BATTLE_CONFIG_VAR(agi_penaly_count), + BATTLE_CONFIG_VAR(agi_penaly_num), + BATTLE_CONFIG_VAR(agi_penaly_count_lv), + BATTLE_CONFIG_VAR(vit_penaly_type), + BATTLE_CONFIG_VAR(vit_penaly_count), + BATTLE_CONFIG_VAR(vit_penaly_num), + BATTLE_CONFIG_VAR(vit_penaly_count_lv), + BATTLE_CONFIG_VAR2("player_skill_reiteration", pc_skill_reiteration), + BATTLE_CONFIG_VAR(monster_skill_reiteration), + BATTLE_CONFIG_VAR2("player_skill_nofootset", pc_skill_nofootset), + BATTLE_CONFIG_VAR(monster_skill_nofootset), + BATTLE_CONFIG_VAR2("player_cloak_check_type", pc_cloak_check_type), + BATTLE_CONFIG_VAR(monster_cloak_check_type), + BATTLE_CONFIG_VAR(mob_changetarget_byskill), + BATTLE_CONFIG_VAR2("player_attack_direction_change", pc_attack_direction_change), + BATTLE_CONFIG_VAR(monster_attack_direction_change), + BATTLE_CONFIG_VAR2("player_land_skill_limit", pc_land_skill_limit), + BATTLE_CONFIG_VAR(monster_land_skill_limit), + BATTLE_CONFIG_VAR(party_skill_penaly), + BATTLE_CONFIG_VAR(monster_class_change_full_recover), + BATTLE_CONFIG_VAR(produce_item_name_input), + BATTLE_CONFIG_VAR(produce_potion_name_input), + BATTLE_CONFIG_VAR(making_arrow_name_input), + BATTLE_CONFIG_VAR(holywater_name_input), + BATTLE_CONFIG_VAR(display_delay_skill_fail), + BATTLE_CONFIG_VAR(chat_warpportal), + BATTLE_CONFIG_VAR(mob_warpportal), + BATTLE_CONFIG_VAR(dead_branch_active), + BATTLE_CONFIG_VAR(show_steal_in_same_party), + BATTLE_CONFIG_VAR(enable_upper_class), + BATTLE_CONFIG_VAR(mob_attack_attr_none), + BATTLE_CONFIG_VAR(mob_ghostring_fix), + BATTLE_CONFIG_VAR(pc_attack_attr_none), + BATTLE_CONFIG_VAR(gx_allhit), + BATTLE_CONFIG_VAR(gx_cardfix), + BATTLE_CONFIG_VAR(gx_dupele), + BATTLE_CONFIG_VAR(gx_disptype), + BATTLE_CONFIG_VAR(player_skill_partner_check), + BATTLE_CONFIG_VAR(hide_GM_session), + BATTLE_CONFIG_VAR(unit_movement_type), + BATTLE_CONFIG_VAR(invite_request_check), + BATTLE_CONFIG_VAR(skill_removetrap_type), + BATTLE_CONFIG_VAR(disp_experience), + BATTLE_CONFIG_VAR(riding_weight), + BATTLE_CONFIG_VAR(prevent_logout), // Added by RoVeRT + BATTLE_CONFIG_VAR(alchemist_summon_reward), // [Valaris] + BATTLE_CONFIG_VAR(maximum_level), // [Valaris] + BATTLE_CONFIG_VAR(drops_by_luk), // [Valaris] + BATTLE_CONFIG_VAR(monsters_ignore_gm), // [Valaris] + BATTLE_CONFIG_VAR(pk_mode), // [Valaris] + BATTLE_CONFIG_VAR(multi_level_up), // [Valaris] + BATTLE_CONFIG_VAR(backstab_bow_penalty), + BATTLE_CONFIG_VAR(show_mob_hp), // [Valaris] + BATTLE_CONFIG_VAR(hack_info_GM_level), // added by [Yor] + BATTLE_CONFIG_VAR(any_warp_GM_min_level), // added by [Yor] + BATTLE_CONFIG_VAR(packet_ver_flag), // added by [Yor] + BATTLE_CONFIG_VAR(min_hair_style), // added by [MouseJstr] + BATTLE_CONFIG_VAR(max_hair_style), // added by [MouseJstr] + BATTLE_CONFIG_VAR(min_hair_color), // added by [MouseJstr] + BATTLE_CONFIG_VAR(max_hair_color), // added by [MouseJstr] + BATTLE_CONFIG_VAR(min_cloth_color), // added by [MouseJstr] + BATTLE_CONFIG_VAR(max_cloth_color), // added by [MouseJstr] + BATTLE_CONFIG_VAR(castrate_dex_scale), // added by [MouseJstr] + BATTLE_CONFIG_VAR(area_size), // added by [MouseJstr] + BATTLE_CONFIG_VAR(chat_lame_penalty), + BATTLE_CONFIG_VAR(chat_spam_threshold), + BATTLE_CONFIG_VAR(chat_spam_flood), + BATTLE_CONFIG_VAR(chat_spam_ban), + BATTLE_CONFIG_VAR(chat_spam_warn), + BATTLE_CONFIG_VAR(chat_maxline), + BATTLE_CONFIG_VAR(packet_spam_threshold), + BATTLE_CONFIG_VAR(packet_spam_flood), + BATTLE_CONFIG_VAR(packet_spam_kick), + BATTLE_CONFIG_VAR(mask_ip_gms), + BATTLE_CONFIG_VAR(mob_splash_radius), }; - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; if (w1 == "import") { - battle_config_read(w2.c_str()); + battle_config_read(w2); continue; } for (auto datum : data) if (w1 == datum.str) { - *datum.val = config_switch(w2.c_str()); + *datum.val = config_switch(w2); goto continue_outer; } - PRINTF("WARNING: unknown battle conf key: %s\n", w1); + PRINTF("WARNING: unknown battle conf key: %s\n", FString(w1)); continue_outer: ; diff --git a/src/map/battle.hpp b/src/map/battle.hpp index 0f9b2d1..6ed32fd 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -259,6 +259,6 @@ extern struct Battle_Config int mob_splash_radius; } battle_config; -int battle_config_read(const char *cfgName); +int battle_config_read(ZString cfgName); #endif // BATTLE_HPP diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index a1e0f55..126235c 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -32,13 +32,15 @@ const int packet_len_table[0x20] = int char_fd; static -char char_ip_str[16]; +IP_String char_ip_str; static int char_ip; static int char_port = 6121; static -char userid[24], passwd[24]; +AccountName userid; +static +AccountPass passwd; static int chrif_state; @@ -47,21 +49,21 @@ int chrif_state; * *------------------------------------------ */ -void chrif_setuserid(const char *id) +void chrif_setuserid(AccountName id) { - strzcpy(userid, id, sizeof(userid)); + userid = id; } /*========================================== * *------------------------------------------ */ -void chrif_setpasswd(const char *pwd) +void chrif_setpasswd(AccountPass pwd) { - strzcpy(passwd, pwd, sizeof(passwd)); + passwd = pwd; } -char *chrif_getpasswd(void) +AccountPass chrif_getpasswd(void) { return passwd; } @@ -70,10 +72,10 @@ char *chrif_getpasswd(void) * *------------------------------------------ */ -void chrif_setip(const char *ip) +void chrif_setip(IP_String ip) { - strzcpy(char_ip_str, ip, sizeof(char_ip_str)); - char_ip = inet_addr(char_ip_str); + char_ip_str = ip; + char_ip = inet_addr(char_ip_str.c_str()); } /*========================================== @@ -180,8 +182,7 @@ int chrif_recvmap(int fd) port = RFIFOW(fd, 8); for (i = 10, j = 0; i < RFIFOW(fd, 2); i += 16, j++) { - char map[16]; - RFIFO_STRING(fd, i, map, 16); + MapName map = RFIFO_STRING<16>(fd, i); map_setipport(map, ip, port); } if (battle_config.etc_log) @@ -194,8 +195,8 @@ int chrif_recvmap(int fd) * マップ鯖間移動のためのデータ準備要求 *------------------------------------------ */ -int chrif_changemapserver(dumb_ptr<map_session_data> sd, char *name, int x, - int y, struct in_addr ip, short port) +int chrif_changemapserver(dumb_ptr<map_session_data> sd, + MapName name, int x, int y, struct in_addr ip, short port) { int i, s_ip; @@ -245,8 +246,7 @@ int chrif_changemapserverack(int fd) pc_authfail(sd->fd); return 0; } - char mapname[16]; - RFIFO_STRING(fd, 18, mapname, 16); + MapName mapname = RFIFO_STRING<16>(fd, 18); uint16_t x = RFIFOW(fd, 34); uint16_t y = RFIFOW(fd, 36); auto ip = in_addr{RFIFOL(fd, 38)}; @@ -274,9 +274,9 @@ int chrif_connectack(int fd) chrif_sendmap(fd); PRINTF("chrif: OnCharIfInit event done. (%d events)\n", - npc_event_doall("OnCharIfInit")); + npc_event_doall(stringish<ScriptLabel>("OnCharIfInit"))); PRINTF("chrif: OnInterIfInit event done. (%d events)\n", - npc_event_doall("OnInterIfInit")); + npc_event_doall(stringish<ScriptLabel>("OnInterIfInit"))); // <Agit> Run Event [AgitInit] // PRINTF("NPC_Event:[OnAgitInit] do (%d) events (Agit Initialize).\n", npc_event_doall("OnAgitInit")); @@ -298,7 +298,7 @@ int chrif_sendmapack(int fd) exit(1); } - RFIFO_STRING(fd, 3, wisp_server_name, 24); + wisp_server_name = stringish<CharName>(RFIFO_STRING<24>(fd, 3)); chrif_state = 2; @@ -385,26 +385,25 @@ int chrif_searchcharid(int char_id) * GMに変化要求 *------------------------------------------ */ -int chrif_changegm(int id, const char *pass, int len) +void chrif_changegm(int id, ZString pass) { if (battle_config.etc_log) PRINTF("chrif_changegm: account: %d, password: '%s'.\n", id, pass); + size_t len = pass.size() + 1; WFIFOW(char_fd, 0) = 0x2b0a; WFIFOW(char_fd, 2) = len + 8; WFIFOL(char_fd, 4) = id; WFIFO_STRING(char_fd, 8, pass, len); WFIFOSET(char_fd, len + 8); - - return 0; } /*========================================== * Change Email *------------------------------------------ */ -int chrif_changeemail(int id, const char *actual_email, - const char *new_email) +void chrif_changeemail(int id, AccountEmail actual_email, + AccountEmail new_email) { if (battle_config.etc_log) PRINTF("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", @@ -415,8 +414,6 @@ int chrif_changeemail(int id, const char *actual_email, WFIFO_STRING(char_fd, 6, actual_email, 40); WFIFO_STRING(char_fd, 46, new_email, 40); WFIFOSET(char_fd, 86); - - return 0; } /*========================================== @@ -430,27 +427,17 @@ int chrif_changeemail(int id, const char *actual_email, * 5: changesex *------------------------------------------ */ -int chrif_char_ask_name(int id, char *character_name, short operation_type, - int year, int month, int day, int hour, int minute, - int second) +void chrif_char_ask_name(int id, CharName character_name, short operation_type, + HumanTimeDiff modif) { WFIFOW(char_fd, 0) = 0x2b0e; WFIFOL(char_fd, 2) = id; // account_id of who ask (for answer) -1 if nobody - WFIFO_STRING(char_fd, 6, character_name, 24); + WFIFO_STRING(char_fd, 6, character_name.to__actual(), 24); WFIFOW(char_fd, 30) = operation_type; // type of operation if (operation_type == 2) - { - WFIFOW(char_fd, 32) = year; - WFIFOW(char_fd, 34) = month; - WFIFOW(char_fd, 36) = day; - WFIFOW(char_fd, 38) = hour; - WFIFOW(char_fd, 40) = minute; - WFIFOW(char_fd, 42) = second; - } + WFIFO_STRUCT(char_fd, 32, modif); PRINTF("chrif : sended 0x2b0e\n"); WFIFOSET(char_fd, 44); - - return 0; } /*========================================== @@ -472,17 +459,13 @@ int chrif_char_ask_name(int id, char *character_name, short operation_type, static int chrif_char_ask_name_answer(int fd) { - int acc; - dumb_ptr<map_session_data> sd; - char player_name[24]; + int acc = RFIFOL(fd, 2); // account_id of who has asked (-1 if nobody) + CharName player_name = stringish<CharName>(RFIFO_STRING<24>(fd, 6)); - acc = RFIFOL(fd, 2); // account_id of who has asked (-1 if nobody) - RFIFO_STRING(fd, 6, player_name, 24); - - sd = map_id2sd(acc); + dumb_ptr<map_session_data> sd = map_id2sd(acc); if (acc >= 0 && sd != NULL) { - std::string output; + FString output; if (RFIFOW(fd, 32) == 1) // player not found output = STRPRINTF("The player '%s' doesn't exist.", player_name); @@ -597,7 +580,7 @@ int chrif_char_ask_name_answer(int fd) break; } } - if (!output.empty()) + if (output) clif_displaymessage(sd->fd, output); } else @@ -611,7 +594,7 @@ int chrif_char_ask_name_answer(int fd) *------------------------------------------ */ static -int chrif_changedgm(int fd) +void chrif_changedgm(int fd) { int acc, level; dumb_ptr<map_session_data> sd = NULL; @@ -631,8 +614,6 @@ int chrif_changedgm(int fd) else clif_displaymessage(sd->fd, "Failure of GM modification."); } - - return 0; } /*========================================== @@ -640,7 +621,7 @@ int chrif_changedgm(int fd) *------------------------------------------ */ static -int chrif_changedsex(int fd) +void chrif_changedsex(int fd) { int acc, sex, i; dumb_ptr<map_session_data> sd; @@ -678,8 +659,6 @@ int chrif_changedsex(int fd) PRINTF("chrif_changedsex failed.\n"); } } - - return 0; } /*========================================== @@ -726,11 +705,10 @@ int chrif_accountreg2(int fd) for (p = 8, j = 0; p < RFIFOW(fd, 2) && j < ACCOUNT_REG2_NUM; p += 36, j++) { - RFIFO_STRING(fd, p, sd->status.account_reg2[j].str, 32); + sd->status.account_reg2[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p)); sd->status.account_reg2[j].value = RFIFOL(fd, p + 32); } sd->status.account_reg2_num = j; -// PRINTF("chrif: accountreg2\n"); return 0; } @@ -1133,8 +1111,7 @@ void chrif_parse(int fd) case 0x2b09: { int charid = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); + CharName name = stringish<CharName>(RFIFO_STRING<24>(fd, 6)); map_addchariddb(charid, name); } break; diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index 6dca70c..97760c3 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -2,14 +2,15 @@ #define CHRIF_HPP #include "../common/dumb_ptr.hpp" +#include "../common/human_time_diff.hpp" #include "map.hpp" -void chrif_setuserid(const char *); -void chrif_setpasswd(const char *); -char *chrif_getpasswd(void); +void chrif_setuserid(AccountName); +void chrif_setpasswd(AccountPass); +AccountPass chrif_getpasswd(void); -void chrif_setip(const char *); +void chrif_setip(IP_String); void chrif_setport(int); int chrif_isconnect(void); @@ -19,15 +20,14 @@ int chrif_save(dumb_ptr<map_session_data>); int chrif_charselectreq(dumb_ptr<map_session_data>); int chrif_changemapserver(dumb_ptr<map_session_data> sd, - char *name, int x, int y, + MapName name, int x, int y, struct in_addr ip, short port); int chrif_searchcharid(int char_id); -int chrif_changegm(int id, const char *pass, int len); -int chrif_changeemail(int id, const char *actual_email, - const char *new_email); -int chrif_char_ask_name(int id, char *character_name, short operation_type, - int year, int month, int day, int hour, int minute, int second); +void chrif_changegm(int id, ZString pass); +void chrif_changeemail(int id, AccountEmail actual_email, AccountEmail new_email); +void chrif_char_ask_name(int id, CharName character_name, short operation_type, + HumanTimeDiff modif); int chrif_saveaccountreg2(dumb_ptr<map_session_data> sd); int chrif_reloadGMdb(void); int chrif_send_divorce(int char_id); diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 9f06bfc..494e09f 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -107,7 +107,7 @@ void WFIFOPOS2(int fd, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16 } static -char map_ip_str[16]; +IP_String map_ip_str; static struct in_addr map_ip; static @@ -121,10 +121,10 @@ int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, * map鯖のip設定 *------------------------------------------ */ -void clif_setip(const char *ip) +void clif_setip(IP_String ip) { - strzcpy(map_ip_str, ip, 16); - map_ip.s_addr = inet_addr(map_ip_str); + map_ip_str = ip; + map_ip.s_addr = inet_addr(map_ip_str.c_str()); } /*========================================== @@ -212,7 +212,7 @@ enum class ChatType }; static -std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type); +FString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type); /*========================================== * clif_sendでSendWho::AREA*指定時用 @@ -1096,7 +1096,7 @@ void clif_setwaitclose(int fd) * *------------------------------------------ */ -void clif_changemap(dumb_ptr<map_session_data> sd, const char *mapname, int x, int y) +void clif_changemap(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y) { nullpo_retv(sd); @@ -1113,8 +1113,8 @@ void clif_changemap(dumb_ptr<map_session_data> sd, const char *mapname, int x, i * *------------------------------------------ */ -void clif_changemapserver(dumb_ptr<map_session_data> sd, const char *mapname, int x, - int y, struct in_addr ip, int port) +void clif_changemapserver(dumb_ptr<map_session_data> sd, + MapName mapname, int x, int y, struct in_addr ip, int port) { nullpo_retv(sd); @@ -1228,125 +1228,103 @@ int clif_selllist(dumb_ptr<map_session_data> sd) * *------------------------------------------ */ -int clif_scriptmes(dumb_ptr<map_session_data> sd, int npcid, const char *mes) +void clif_scriptmes(dumb_ptr<map_session_data> sd, int npcid, XString mes) { - nullpo_ret(sd); + nullpo_retv(sd); int fd = sd->fd; - size_t len = strlen(mes) + 1; + size_t len = mes.size() + 1; WFIFOW(fd, 0) = 0xb4; WFIFOW(fd, 2) = len + 8; WFIFOL(fd, 4) = npcid; WFIFO_STRING(fd, 8, mes, len); WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_scriptnext(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptnext(dumb_ptr<map_session_data> sd, int npcid) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0xb5; WFIFOL(fd, 2) = npcid; WFIFOSET(fd, clif_parse_func_table[0xb5].len); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_scriptclose(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptclose(dumb_ptr<map_session_data> sd, int npcid) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0xb6; WFIFOL(fd, 2) = npcid; WFIFOSET(fd, clif_parse_func_table[0xb6].len); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_scriptmenu(dumb_ptr<map_session_data> sd, int npcid, const char *mes) +void clif_scriptmenu(dumb_ptr<map_session_data> sd, int npcid, XString mes) { - nullpo_ret(sd); + nullpo_retv(sd); int fd = sd->fd; - size_t len = strlen(mes) + 1; + size_t len = mes.size() + 1; WFIFOW(fd, 0) = 0xb7; WFIFOW(fd, 2) = len + 8; WFIFOL(fd, 4) = npcid; WFIFO_STRING(fd, 8, mes, len); WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_scriptinput(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinput(dumb_ptr<map_session_data> sd, int npcid) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0x142; WFIFOL(fd, 2) = npcid; WFIFOSET(fd, clif_parse_func_table[0x142].len); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0x1d4; WFIFOL(fd, 2) = npcid; WFIFOSET(fd, clif_parse_func_table[0x1d4].len); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_viewpoint(dumb_ptr<map_session_data> sd, int npc_id, int type, int x, - int y, int id, int color) +void clif_viewpoint(dumb_ptr<map_session_data> sd, int npc_id, int type, + int x, int y, int id, int color) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0x144; WFIFOL(fd, 2) = npc_id; WFIFOL(fd, 6) = type; @@ -1355,8 +1333,6 @@ int clif_viewpoint(dumb_ptr<map_session_data> sd, int npc_id, int type, int x, WFIFOB(fd, 18) = id; WFIFOL(fd, 19) = color; WFIFOSET(fd, clif_parse_func_table[0x144].len); - - return 0; } /*========================================== @@ -1432,29 +1408,25 @@ int clif_additem(dumb_ptr<map_session_data> sd, int n, int amount, PickupFail fa * *------------------------------------------ */ -int clif_delitem(dumb_ptr<map_session_data> sd, int n, int amount) +void clif_delitem(dumb_ptr<map_session_data> sd, int n, int amount) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0xaf; WFIFOW(fd, 2) = n + 2; WFIFOW(fd, 4) = amount; WFIFOSET(fd, clif_parse_func_table[0xaf].len); - - return 0; } /*========================================== * *------------------------------------------ */ -int clif_itemlist(dumb_ptr<map_session_data> sd) +void clif_itemlist(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retv(sd); int n = 0; int arrow = -1; @@ -1492,16 +1464,15 @@ int clif_itemlist(dumb_ptr<map_session_data> sd) } if (arrow >= 0) clif_arrowequip(sd, arrow); - return 0; } /*========================================== * *------------------------------------------ */ -int clif_equiplist(dumb_ptr<map_session_data> sd) +void clif_equiplist(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retv(sd); int fd = sd->fd; WFIFOW(fd, 0) = 0xa4; @@ -1549,7 +1520,6 @@ int clif_equiplist(dumb_ptr<map_session_data> sd) WFIFOW(fd, 2) = 4 + n * 20; WFIFOSET(fd, WFIFOW(fd, 2)); } - return 0; } /*========================================== @@ -2153,45 +2123,39 @@ 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) +void clif_traderequest(dumb_ptr<map_session_data> sd, CharName name) { - nullpo_ret(sd); + nullpo_retv(sd); int fd = sd->fd; WFIFOW(fd, 0) = 0xe5; - WFIFO_STRING(fd, 2, name, 24); + WFIFO_STRING(fd, 2, name.to__actual(), 24); WFIFOSET(fd, clif_parse_func_table[0xe5].len); - - return 0; } /*========================================== * 取り引き要求応答 *------------------------------------------ */ -int clif_tradestart(dumb_ptr<map_session_data> sd, int type) +void clif_tradestart(dumb_ptr<map_session_data> sd, int type) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0xe7; WFIFOB(fd, 2) = type; WFIFOSET(fd, clif_parse_func_table[0xe7].len); - - return 0; } /*========================================== * 相手方からのアイテム追加 *------------------------------------------ */ -int clif_tradeadditem(dumb_ptr<map_session_data> sd, - dumb_ptr<map_session_data> tsd, int index, int amount) +void clif_tradeadditem(dumb_ptr<map_session_data> sd, + dumb_ptr<map_session_data> tsd, int index, int amount) { - nullpo_ret(sd); - nullpo_ret(tsd); + nullpo_retv(sd); + nullpo_retv(tsd); int fd = tsd->fd; WFIFOW(fd, 0) = 0xe9; @@ -2235,8 +2199,6 @@ int clif_tradeadditem(dumb_ptr<map_session_data> sd, } } WFIFOSET(fd, clif_parse_func_table[0xe9].len); - - return 0; } /*========================================== @@ -2967,7 +2929,7 @@ int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag) * Send message (modified by [Yor]) *------------------------------------------ */ -void clif_displaymessage(int fd, ZString mes) +void clif_displaymessage(int fd, XString mes) { if (mes) { @@ -2975,7 +2937,7 @@ void clif_displaymessage(int fd, ZString 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.c_str(), str_len); + WFIFO_STRING(fd, 4, mes, str_len); WFIFOSET(fd, 4 + str_len); } } @@ -2984,14 +2946,14 @@ void clif_displaymessage(int fd, ZString mes) * 天の声を送信する *------------------------------------------ */ -void clif_GMmessage(dumb_ptr<block_list> bl, ZString mes, int flag) +void clif_GMmessage(dumb_ptr<block_list> bl, XString 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.c_str(), str_len); + WBUF_STRING(buf, 4, mes, str_len); flag &= 0x07; clif_send(buf, WBUFW(buf, 2), bl, (flag == 1) ? SendWho::ALL_SAMEMAP : @@ -3022,12 +2984,12 @@ void clif_resurrection(dumb_ptr<block_list> bl, int type) * Wisp/page is transmitted to the destination player *------------------------------------------ */ -void clif_wis_message(int fd, const char *nick, const char *mes) // R 0097 <len>.w <nick>.24B <message>.?B +void clif_wis_message(int fd, CharName nick, XString mes) // R 0097 <len>.w <nick>.24B <message>.?B { - size_t mes_len = strlen(mes) + 1; + size_t mes_len = mes.size() + 1; WFIFOW(fd, 0) = 0x97; WFIFOW(fd, 2) = mes_len + 24 + 4; - WFIFO_STRING(fd, 4, nick, 24); + WFIFO_STRING(fd, 4, nick.to__actual(), 24); WFIFO_STRING(fd, 28, mes, mes_len); WFIFOSET(fd, WFIFOW(fd, 2)); } @@ -3090,7 +3052,7 @@ int clif_party_info(struct party *p, int fd) if (sd == NULL) sd = dumb_ptr<map_session_data>(m->sd); WBUFL(buf, 28 + c * 46) = m->account_id; - WBUF_STRING(buf, 28 + c * 46 + 4, m->name, 24); + WBUF_STRING(buf, 28 + c * 46 + 4, m->name.to__actual(), 24); WBUF_STRING(buf, 28 + c * 46 + 28, m->map, 16); WBUFB(buf, 28 + c * 46 + 44) = (m->leader) ? 0 : 1; WBUFB(buf, 28 + c * 46 + 45) = (m->online) ? 0 : 1; @@ -3153,18 +3115,15 @@ void clif_party_invite(dumb_ptr<map_session_data> sd, * 4 The character is in the same party. *------------------------------------------ */ -int clif_party_inviteack(dumb_ptr<map_session_data> sd, const char *nick, int flag) +void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag) { - int fd; - - nullpo_ret(sd); + nullpo_retv(sd); - fd = sd->fd; + int fd = sd->fd; WFIFOW(fd, 0) = 0xfd; - WFIFO_STRING(fd, 2, nick, 24); + WFIFO_STRING(fd, 2, nick.to__actual(), 24); WFIFOB(fd, 26) = flag; WFIFOSET(fd, clif_parse_func_table[0xfd].len); - return 0; } /*========================================== @@ -3207,17 +3166,17 @@ void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag) * パーティ脱退(脱退前に呼ぶこと) *------------------------------------------ */ -int clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, - int account_id, const char *name, int flag) +void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, + int account_id, CharName name, int flag) { unsigned char buf[64]; int i; - nullpo_ret(p); + nullpo_retv(p); WBUFW(buf, 0) = 0x105; WBUFL(buf, 2) = account_id; - WBUF_STRING(buf, 6, name, 24); + WBUF_STRING(buf, 6, name.to__actual(), 24); WBUFB(buf, 30) = flag & 0x0f; if ((flag & 0xf0) == 0) @@ -3237,14 +3196,13 @@ int clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, WFIFO_BUF_CLONE(sd->fd, buf, clif_parse_func_table[0x105].len); WFIFOSET(sd->fd, clif_parse_func_table[0x105].len); } - return 0; } /*========================================== * パーティメッセージ送信 *------------------------------------------ */ -void clif_party_message(struct party *p, int account_id, const char *mes) +void clif_party_message(struct party *p, int account_id, XString mes) { // always set, but clang is not smart enough dumb_ptr<map_session_data> sd = nullptr; @@ -3260,7 +3218,7 @@ void clif_party_message(struct party *p, int account_id, const char *mes) } if (sd != NULL) { - size_t len = strlen(mes) + 1; + size_t len = mes.size() + 1; unsigned char buf[len + 8]; WBUFW(buf, 0) = 0x109; WBUFW(buf, 2) = len + 8; @@ -3748,12 +3706,12 @@ void clif_parse_GetCharNameRequest(int fd, dumb_ptr<map_session_data> sd) if (ssd->state.shroud_active) WFIFO_STRING(fd, 6, "", 24); else - WFIFO_STRING(fd, 6, ssd->status.name, 24); + WFIFO_STRING(fd, 6, ssd->status.name.to__actual(), 24); WFIFOSET(fd, clif_parse_func_table[0x95].len); struct party *p = NULL; - const char *party_name = ""; + PartyName party_name; int send = 0; @@ -3782,7 +3740,7 @@ void clif_parse_GetCharNameRequest(int fd, dumb_ptr<map_session_data> sd) // Mask the IP using the char-server password if (battle_config.mask_ip_gms) - ip = MD5_ip(chrif_getpasswd(), ssd->ip); + ip = MD5_ip(ssd->ip); WFIFOL(fd, 2) = account_id; WFIFOL(fd, 6) = ip.s_addr; @@ -3793,18 +3751,10 @@ void clif_parse_GetCharNameRequest(int fd, dumb_ptr<map_session_data> sd) break; case BL::NPC: { - char name[24]; - strzcpy(name, bl->as_npc()->name, 24); + NpcName name = bl->as_npc()->name; // [fate] elim hashed out/invisible names for the client - *strchrnul(name, '#') = '\0'; - for (char& c : name) - { - // [fate] Elim preceding underscores for (hackish) name position fine-tuning - if (c != '_') - break; - c = ' '; - } - WFIFO_STRING(fd, 6, name, 24); + auto it = std::find(name.begin(), name.end(), '#'); + WFIFO_STRING(fd, 6, name.oislice_h(it), 24); WFIFOSET(fd, clif_parse_func_table[0x95].len); } break; @@ -3838,20 +3788,20 @@ void clif_parse_GlobalMessage(int fd, dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - std::string mbuf = clif_validate_chat(sd, ChatType::Global); - if (mbuf.empty()) + FString mbuf = clif_validate_chat(sd, ChatType::Global); + if (!mbuf) { clif_displaymessage(fd, "Your message could not be sent."); return; } - if (is_atcommand(fd, sd, mbuf.c_str(), 0)) + if (is_atcommand(fd, sd, mbuf, 0)) return; if (!magic_message(sd, mbuf)) { /* Don't send chat that results in an automatic ban. */ - if (tmw_CheckChatSpam(sd, mbuf.c_str())) + if (tmw_CheckChatSpam(sd, mbuf)) { clif_displaymessage(fd, "Your message could not be sent."); return; @@ -3863,7 +3813,7 @@ void clif_parse_GlobalMessage(int fd, dumb_ptr<map_session_data> sd) WBUFW(sendbuf, 0) = 0x8d; WBUFW(sendbuf, 2) = mbuf_size + 8; /* Header(2) + length(2) + ID(4). */ WBUFL(sendbuf, 4) = sd->bl_id; - WBUF_STRING(sendbuf, 8, mbuf.c_str(), mbuf_size); + WBUF_STRING(sendbuf, 8, mbuf, mbuf_size); clif_send(sendbuf, mbuf_size + 8, sd, SendWho::AREA_CHAT_WOC); } @@ -3875,9 +3825,9 @@ void clif_parse_GlobalMessage(int fd, dumb_ptr<map_session_data> sd) WFIFOSET(fd, len); } -void clif_message(dumb_ptr<block_list> bl, const char *msg) +void clif_message(dumb_ptr<block_list> bl, XString msg) { - size_t msg_len = strlen(msg) + 1; + size_t msg_len = msg.size() + 1; uint8_t buf[512]; if (msg_len + 16 > 512) @@ -4079,20 +4029,20 @@ void clif_parse_Wis(int fd, dumb_ptr<map_session_data> sd) nullpo_retv(sd); - std::string mbuf = clif_validate_chat(sd, ChatType::Whisper); - if (mbuf.empty()) + FString mbuf = clif_validate_chat(sd, ChatType::Whisper); + if (!mbuf) { clif_displaymessage(fd, "Your message could not be sent."); return; } - if (is_atcommand(fd, sd, mbuf.c_str(), 0)) + if (is_atcommand(fd, sd, mbuf, 0)) { return; } /* Don't send chat that results in an automatic ban. */ - if (tmw_CheckChatSpam(sd, mbuf.c_str())) + if (tmw_CheckChatSpam(sd, mbuf)) { clif_displaymessage(fd, "Your message could not be sent."); return; @@ -4104,17 +4054,16 @@ void clif_parse_Wis(int fd, dumb_ptr<map_session_data> sd) * conflict (for instance, "Test" versus "test"), the char-server must * settle the discrepancy. */ - char tname[24]; - RFIFO_STRING(fd, 4, tname, 24); + CharName tname = stringish<CharName>(RFIFO_STRING<24>(fd, 4)); if (!(dstsd = map_nick2sd(tname)) - || strcmp(dstsd->status.name, tname) != 0) - intif_wis_message(sd, tname, mbuf.c_str()); + || dstsd->status.name != tname) + intif_wis_message(sd, tname, mbuf); else { /* Refuse messages addressed to self. */ if (dstsd->fd == fd) { - const char *mes = "You cannot page yourself."; + ZString mes = "You cannot page yourself."; clif_wis_message(fd, wisp_server_name, mes); } else @@ -4122,7 +4071,7 @@ void clif_parse_Wis(int fd, dumb_ptr<map_session_data> sd) { /* The player is not being ignored. */ { - clif_wis_message(dstsd->fd, sd->status.name, mbuf.c_str()); + clif_wis_message(dstsd->fd, sd->status.name, mbuf); /* The whisper was sent successfully. */ clif_wis_end(fd, 0); } @@ -4519,9 +4468,7 @@ void clif_parse_NpcStringInput(int fd, dumb_ptr<map_session_data> sd) */ if (len < 0) return; - char buf[len]; - RFIFO_STRING(fd, 8, buf, len); - sd->npc_str = buf; + sd->npc_str = RFIFO_STRING(fd, 8, len); map_scriptcont(sd, RFIFOL(fd, 4)); } @@ -4606,8 +4553,7 @@ 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) { - char name[24]; - RFIFO_STRING(fd, 2, name, 24); + PartyName name = stringish<PartyName>(RFIFO_STRING<24>(fd, 2)); party_create(sd, name); } else @@ -4667,9 +4613,8 @@ static void clif_parse_RemovePartyMember(int fd, dumb_ptr<map_session_data> sd) { int account_id = RFIFOL(fd, 2); - char name[24]; - RFIFO_STRING(fd, 6, name, 24); - party_removemember(sd, account_id, name); + // unused RFIFO_STRING<24>(fd, 6); + party_removemember(sd, account_id); } /*========================================== @@ -4695,24 +4640,24 @@ void clif_parse_PartyMessage(int fd, dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - std::string mbuf = clif_validate_chat(sd, ChatType::Party); - if (mbuf.empty()) + FString mbuf = clif_validate_chat(sd, ChatType::Party); + if (!mbuf) { clif_displaymessage(fd, "Your message could not be sent."); return; } - if (is_atcommand(fd, sd, mbuf.c_str(), 0)) + if (is_atcommand(fd, sd, mbuf, 0)) return; /* Don't send chat that results in an automatic ban. */ - if (tmw_CheckChatSpam(sd, mbuf.c_str())) + if (tmw_CheckChatSpam(sd, mbuf)) { clif_displaymessage(fd, "Your message could not be sent."); return; } - party_send_message(sd, mbuf.c_str()); + party_send_message(sd, mbuf); } func_table clif_parse_func_table[0x0220] = @@ -5361,19 +5306,19 @@ void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, const char *msg) * @return a dynamically allocated copy of the message, or empty string upon failure */ static -std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) +FString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) { - nullpo_retr(std::string(), sd); + nullpo_retr(FString(), sd); /* * Don't send chat in the period between the ban and the connection's * closure. */ if (sd->auto_ban_info.in_progress) - return std::string(); + return FString(); int fd = sd->fd; size_t msg_len = RFIFOW(fd, 2) - 4; - size_t name_len = strlen(sd->status.name); + size_t name_len = sd->status.name.to__actual().size(); /* * At least one character is required in all instances. * Notes for length checks: @@ -5393,14 +5338,14 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) if (!msg_len) { WARN_MALFORMED_MSG(sd, "no message sent"); - return std::string(); + return FString(); } /* The client sent (or claims to have sent) an empty message. */ if (msg_len == min_len) { WARN_MALFORMED_MSG(sd, "empty message"); - return std::string(); + return FString(); } /* The protocol specifies that the target must be 24 bytes long. */ @@ -5409,7 +5354,7 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) /* Disallow malformed messages. */ clif_setwaitclose(fd); WARN_MALFORMED_MSG(sd, "illegal target name"); - return std::string(); + return FString(); } size_t pstart = 4; @@ -5419,9 +5364,7 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) pstart += 24; buf_len -= 24; } - char pbuf[buf_len + 1]; - // I had to change strzcpy for this :( - RFIFO_STRING(fd, pstart, pbuf, buf_len + 1); + FString pbuf = RFIFO_STRING(fd, pstart, buf_len); /* * The client attempted to exceed the maximum message length. @@ -5433,22 +5376,22 @@ std::string clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) if (buf_len >= battle_config.chat_maxline) { WARN_MALFORMED_MSG(sd, "exceeded maximum message length"); - return std::string(); + return FString(); } if (type == ChatType::Global) { - XString p = ZString(ZString::really_construct_from_a_pointer, pbuf); - if (!(p.startswith(const_(sd->status.name)) && p.xslice_t(name_len).startswith(" : "))) + XString p = pbuf; + if (!(p.startswith(sd->status.name.to__actual()) && p.xslice_t(name_len).startswith(" : "))) { /* Disallow malformed/spoofed messages. */ clif_setwaitclose(fd); WARN_MALFORMED_MSG(sd, "spoofed name/invalid format"); - return std::string(); + return FString(); } /* Step beyond the separator. */ XString xs = p.xslice_t(name_len + 3); - return std::string(xs.begin(), xs.end()); + return xs; } return pbuf; } @@ -5483,10 +5426,8 @@ void clif_parse(int fd) { pc_logout(sd); clif_quitsave(fd, sd); - if (sd->status.name != NULL) - PRINTF("Player [%s] has logged off your server.\n", sd->status.name); // Player logout display [Valaris] - else - PRINTF("Player with account [%d] has logged off your server.\n", sd->bl_id); // Player logout display [Yor] + + PRINTF("Player [%s] has logged off your server.\n", sd->status.name); // Player logout display [Valaris] } else if (sd) { // not authentified! (refused by char-server or disconnect before to be authentified) @@ -5587,17 +5528,14 @@ void clif_parse(int fd) } if (sd && sd->state.auth) { - if (sd->status.name != NULL) - PRINTF("\nAccount ID %d, character ID %d, player name %s.\n", - sd->status.account_id, sd->status.char_id, - sd->status.name); - else - PRINTF("\nAccount ID %d.\n", sd->bl_id); + PRINTF("\nAccount ID %d, character ID %d, player name %s.\n", + sd->status.account_id, sd->status.char_id, + sd->status.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) PRINTF("\nAccount ID %d.\n", sd->bl_id); - if ((fp = fopen_(packet_txt, "a")) == NULL) + if ((fp = fopen(packet_txt, "a")) == NULL) { PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n", packet_txt); @@ -5609,16 +5547,11 @@ void clif_parse(int fd) stamp_time(now); if (sd && sd->state.auth) { - if (sd->status.name != NULL) - FPRINTF(fp, - "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", - now, - sd->status.account_id, - sd->status.char_id, sd->status.name); - else - FPRINTF(fp, - "%s\nPlayer with account ID %d sent wrong packet:\n", - now, sd->bl_id); + FPRINTF(fp, + "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", + now, + sd->status.account_id, + sd->status.char_id, sd->status.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) FPRINTF(fp, @@ -5634,7 +5567,7 @@ void clif_parse(int fd) FPRINTF(fp, "%02X ", RFIFOB(fd, i)); } FPRINTF(fp, "\n\n"); - fclose_(fp); + fclose(fp); } } #endif diff --git a/src/map/clif.hpp b/src/map/clif.hpp index b9e2233..20f9912 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -14,7 +14,7 @@ #include "pc.t.hpp" #include "skill.t.hpp" -void clif_setip(const char *); +void clif_setip(IP_String); void clif_setport(int); struct in_addr clif_getip(void); @@ -38,23 +38,23 @@ int clif_spawnmob(dumb_ptr<mob_data>); // area int clif_walkok(dumb_ptr<map_session_data>); // self int clif_movechar(dumb_ptr<map_session_data>); // area int clif_movemob(dumb_ptr<mob_data>); //area -void clif_changemap(dumb_ptr<map_session_data>, const char *, int, int); //self -void clif_changemapserver(dumb_ptr<map_session_data>, const char *, int, int, struct in_addr, int); //self +void clif_changemap(dumb_ptr<map_session_data>, MapName, int, int); //self +void clif_changemapserver(dumb_ptr<map_session_data>, MapName, int, int, struct in_addr, int); //self void clif_fixpos(dumb_ptr<block_list>); // area int clif_fixmobpos(dumb_ptr<mob_data> md); int clif_fixpcpos(dumb_ptr<map_session_data> sd); int clif_npcbuysell(dumb_ptr<map_session_data>, int); //self int clif_buylist(dumb_ptr<map_session_data>, dumb_ptr<npc_data_shop>); //self int clif_selllist(dumb_ptr<map_session_data>); //self -int clif_scriptmes(dumb_ptr<map_session_data>, int, const char *); //self -int clif_scriptnext(dumb_ptr<map_session_data>, int); //self -int clif_scriptclose(dumb_ptr<map_session_data>, int); //self -int clif_scriptmenu(dumb_ptr<map_session_data>, int, const char *); //self -int clif_scriptinput(dumb_ptr<map_session_data>, int); //self -int clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid); // self -int clif_viewpoint(dumb_ptr<map_session_data>, int, int, int, int, int, int); //self +void clif_scriptmes(dumb_ptr<map_session_data>, int, XString); //self +void clif_scriptnext(dumb_ptr<map_session_data>, int); //self +void clif_scriptclose(dumb_ptr<map_session_data>, int); //self +void clif_scriptmenu(dumb_ptr<map_session_data>, int, XString); //self +void clif_scriptinput(dumb_ptr<map_session_data>, int); //self +void clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid); // self +void clif_viewpoint(dumb_ptr<map_session_data>, int, int, int, int, int, int); //self int clif_additem(dumb_ptr<map_session_data>, int, int, PickupFail); //self -int clif_delitem(dumb_ptr<map_session_data>, int, int); //self +void clif_delitem(dumb_ptr<map_session_data>, int, int); //self int clif_updatestatus(dumb_ptr<map_session_data>, SP); //self int clif_damage(dumb_ptr<block_list>, dumb_ptr<block_list>, tick_t, interval_t, interval_t, @@ -79,9 +79,9 @@ void clif_emotion(dumb_ptr<block_list> bl, int type); void clif_sitting(int fd, dumb_ptr<map_session_data> sd); // trade -int clif_traderequest(dumb_ptr<map_session_data> sd, const char *name); -int clif_tradestart(dumb_ptr<map_session_data> sd, int type); -int clif_tradeadditem(dumb_ptr<map_session_data> sd, +void clif_traderequest(dumb_ptr<map_session_data> sd, CharName name); +void clif_tradestart(dumb_ptr<map_session_data> sd, int type); +void clif_tradeadditem(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int index, int amount); int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, int fail); @@ -122,11 +122,11 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag); -void clif_wis_message(int fd, const char *nick, const char *mes); +void clif_wis_message(int fd, CharName nick, XString mes); void clif_wis_end(int fd, int flag); -int clif_itemlist(dumb_ptr<map_session_data> sd); -int clif_equiplist(dumb_ptr<map_session_data> sd); +void clif_itemlist(dumb_ptr<map_session_data> sd); +void clif_equiplist(dumb_ptr<map_session_data> sd); int clif_mvp_effect(dumb_ptr<map_session_data> sd); @@ -137,22 +137,22 @@ int clif_party_created(dumb_ptr<map_session_data> sd, int flag); int clif_party_info(struct party *p, int fd); void clif_party_invite(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd); -int clif_party_inviteack(dumb_ptr<map_session_data> sd, const char *nick, int flag); +void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag); void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag); -int clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, - int account_id, const char *name, int flag); -void clif_party_message(struct party *p, int account_id, const char *mes); +void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, + int account_id, CharName name, int flag); +void clif_party_message(struct party *p, int account_id, XString mes); 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, ZString mes); -void clif_GMmessage(dumb_ptr<block_list> bl, ZString mes, int flag); +void clif_displaymessage(int fd, XString mes); +void clif_GMmessage(dumb_ptr<block_list> bl, XString 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] -void clif_message(dumb_ptr<block_list> bl, const char *msg); // messages (from mobs/npcs) [Valaris] +void clif_message(dumb_ptr<block_list> bl, XString msg); // messages (from mobs/npcs) [Valaris] int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int type); diff --git a/src/map/grfio.cpp b/src/map/grfio.cpp index a190d1b..cbb5a86 100644 --- a/src/map/grfio.cpp +++ b/src/map/grfio.cpp @@ -15,11 +15,12 @@ #include "../common/cxxstdio.hpp" #include "../common/extract.hpp" +#include "../common/io.hpp" #include "../poison.hpp" static -std::map<std::string, std::string> load_resnametable() +std::map<MapName, FString> load_resnametable() { std::ifstream in("data/resnametable.txt"); if (!in.is_open()) @@ -27,12 +28,13 @@ std::map<std::string, std::string> load_resnametable() fprintf(stderr, "Missing data/resnametable.txt"); abort(); } - std::map<std::string, std::string> out; + std::map<MapName, FString> out; - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string key, value; + MapName key; + FString value; if (!extract(line, record<'#'>(&key, &value))) continue; @@ -43,29 +45,32 @@ std::map<std::string, std::string> load_resnametable() /// Change *.gat to *.wlk static -std::string grfio_resnametable(const_string rname) +FString grfio_resnametable(MapName rname) { static - std::map<std::string, std::string> resnametable = load_resnametable(); + std::map<MapName, FString> resnametable = load_resnametable(); - return resnametable.at(std::string(rname.begin(), rname.end())); + return resnametable.at(rname); } -std::vector<uint8_t> grfio_reads(const_string rname) +std::vector<uint8_t> grfio_reads(MapName rname) { - std::string lfname = "data/" + grfio_resnametable(rname); + MString lfname_; + lfname_ += "data/"; + lfname_ += grfio_resnametable(rname); + FString lfname = FString(lfname_); int fd = open(lfname.c_str(), O_RDONLY); if (fd == -1) { FPRINTF(stderr, "Resource %s (file %s) not found\n", - std::string(rname.begin(), rname.end()), lfname); + rname, lfname); return {}; } off_t len = lseek(fd, 0, SEEK_END); assert (len != -1); std::vector<uint8_t> buffer(len); - int err = pread(fd, buffer.data(), len, 0); + ssize_t err = pread(fd, buffer.data(), len, 0); assert (err == len); close(fd); return buffer; diff --git a/src/map/grfio.hpp b/src/map/grfio.hpp index fd7b871..aa222c6 100644 --- a/src/map/grfio.hpp +++ b/src/map/grfio.hpp @@ -5,11 +5,12 @@ #include <vector> -#include "../common/const_array.hpp" +#include "../common/mmo.hpp" +#include "../common/strings.hpp" /// Load a resource into memory, subject to data/resnametable.txt. /// Normally, resourcename is xxx-y.gat and the file is xxx-y.wlk. /// Currently there is exactly one .wlk per .gat, but multiples are fine. -std::vector<uint8_t> grfio_reads(const_string resourcename); +std::vector<uint8_t> grfio_reads(MapName resourcename); #endif // GRFIO_HPP diff --git a/src/map/intif.cpp b/src/map/intif.cpp index 311c661..d22519b 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -36,25 +36,25 @@ const int packet_len_table[] = // inter serverへの送信 // Message for all GMs on all map servers -void intif_GMmessage(const_string mes) +void intif_GMmessage(XString mes) { WFIFOW(char_fd, 0) = 0x3000; size_t len = mes.size() + 1; WFIFOW(char_fd, 2) = 4 + len; - WFIFO_STRING(char_fd, 4, mes.data(), len); + WFIFO_STRING(char_fd, 4, mes, len); WFIFOSET(char_fd, WFIFOW(char_fd, 2)); } // The transmission of Wisp/Page to inter-server (player not found on this server) -void intif_wis_message(dumb_ptr<map_session_data> sd, const char *nick, const char *mes) +void intif_wis_message(dumb_ptr<map_session_data> sd, CharName nick, ZString mes) { nullpo_retv(sd); - size_t mes_len = strlen(mes) + 1; + size_t mes_len = mes.size() + 1; WFIFOW(char_fd, 0) = 0x3001; WFIFOW(char_fd, 2) = mes_len + 52; - WFIFO_STRING(char_fd, 4, sd->status.name, 24); - WFIFO_STRING(char_fd, 28, nick, 24); + WFIFO_STRING(char_fd, 4, sd->status.name.to__actual(), 24); + WFIFO_STRING(char_fd, 28, nick.to__actual(), 24); WFIFO_STRING(char_fd, 52, mes, mes_len); WFIFOSET(char_fd, WFIFOW(char_fd, 2)); @@ -77,19 +77,19 @@ void intif_wis_replay(int id, int flag) } // The transmission of GM only Wisp/Page from server to inter-server -void intif_wis_message_to_gm(const char *Wisp_name, int min_gm_level, const char *mes) +void intif_wis_message_to_gm(CharName Wisp_name, int min_gm_level, ZString mes) { - size_t mes_len = strlen(mes) + 1; + size_t mes_len = mes.size() + 1; WFIFOW(char_fd, 0) = 0x3003; WFIFOW(char_fd, 2) = mes_len + 30; - WFIFO_STRING(char_fd, 4, Wisp_name, 24); + WFIFO_STRING(char_fd, 4, Wisp_name.to__actual(), 24); WFIFOW(char_fd, 28) = min_gm_level; WFIFO_STRING(char_fd, 30, mes, mes_len); WFIFOSET(char_fd, WFIFOW(char_fd, 2)); if (battle_config.etc_log) PRINTF("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n", - Wisp_name, min_gm_level, mes); + Wisp_name, min_gm_level, mes); } // アカウント変数送信 @@ -140,14 +140,14 @@ void intif_send_storage(struct storage *stor) } // パーティ作成要求 -void intif_create_party(dumb_ptr<map_session_data> sd, const char *name) +void intif_create_party(dumb_ptr<map_session_data> sd, PartyName name) { nullpo_retv(sd); WFIFOW(char_fd, 0) = 0x3020; WFIFOL(char_fd, 2) = sd->status.account_id; WFIFO_STRING(char_fd, 6, name, 24); - WFIFO_STRING(char_fd, 30, sd->status.name, 24); + WFIFO_STRING(char_fd, 30, sd->status.name.to__actual(), 24); WFIFO_STRING(char_fd, 54, sd->bl_m->name_, 16); WFIFOW(char_fd, 70) = sd->status.base_level; WFIFOSET(char_fd, 72); @@ -171,7 +171,7 @@ void intif_party_addmember(int party_id, int account_id) WFIFOW(char_fd, 0) = 0x3022; WFIFOL(char_fd, 2) = party_id; WFIFOL(char_fd, 6) = account_id; - WFIFO_STRING(char_fd, 10, sd->status.name, 24); + WFIFO_STRING(char_fd, 10, sd->status.name.to__actual(), 24); WFIFO_STRING(char_fd, 34, sd->bl_m->name_, 16); WFIFOW(char_fd, 50) = sd->status.base_level; WFIFOSET(char_fd, 52); @@ -214,9 +214,9 @@ void intif_party_changemap(dumb_ptr<map_session_data> sd, int online) } // パーティ会話送信 -void intif_party_message(int party_id, int account_id, const char *mes) +void intif_party_message(int party_id, int account_id, XString mes) { - size_t len = strlen(mes) + 1; + size_t len = mes.size() + 1; WFIFOW(char_fd, 0) = 0x3027; WFIFOW(char_fd, 2) = len + 12; WFIFOL(char_fd, 4) = party_id; @@ -226,12 +226,12 @@ void intif_party_message(int party_id, int account_id, const char *mes) } // パーティ競合チェック要求 -void intif_party_checkconflict(int party_id, int account_id, const char *nick) +void intif_party_checkconflict(int party_id, int account_id, CharName nick) { WFIFOW(char_fd, 0) = 0x3028; WFIFOL(char_fd, 2) = party_id; WFIFOL(char_fd, 6) = account_id; - WFIFO_STRING(char_fd, 10, nick, 24); + WFIFO_STRING(char_fd, 10, nick.to__actual(), 24); WFIFOSET(char_fd, 34); } @@ -245,26 +245,22 @@ int intif_parse_WisMessage(int fd) // rewritten by [Yor] dumb_ptr<map_session_data> sd; - char from[24]; - RFIFO_STRING(fd, 8, from, 24); - char to[24]; - RFIFO_STRING(fd, 32, to, 24); + CharName from = stringish<CharName>(RFIFO_STRING<24>(fd, 8)); + CharName to = stringish<CharName>(RFIFO_STRING<24>(fd, 32)); size_t len = RFIFOW(fd, 2) - 56; - char buf[len]; - RFIFO_STRING(fd, 56, buf, len); + FString buf = RFIFO_STRING(fd, 56, len); if (battle_config.etc_log) { - const char *mes = buf; PRINTF("intif_parse_wismessage: id: %d, from: %s, to: %s, message: '%s'\n", RFIFOL(fd, 4), from, to, - mes); + buf); } sd = map_nick2sd(to); // Searching destination player - if (sd != NULL && strcmp(sd->status.name, to) == 0) + if (sd != NULL && sd->status.name == to) { // exactly same name (inter-server have checked the name before) { @@ -286,8 +282,7 @@ int intif_parse_WisEnd(int fd) { dumb_ptr<map_session_data> sd; - char name[24]; - RFIFO_STRING(fd, 2, name, 24); + CharName name = stringish<CharName>(RFIFO_STRING<24>(fd, 2)); 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 @@ -306,17 +301,15 @@ void mapif_parse_WisToGM(int fd) { // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B int min_gm_level, len; - char Wisp_name[24]; if (RFIFOW(fd, 2) - 30 <= 0) return; len = RFIFOW(fd, 2) - 30; - char message[len]; min_gm_level = RFIFOW(fd, 28); - RFIFO_STRING(fd, 4, Wisp_name, 24); - RFIFO_STRING(fd, 30, message, len); + CharName Wisp_name = stringish<CharName>(RFIFO_STRING<24>(fd, 4)); + FString message = RFIFO_STRING(fd, 30, len); // information is sended to all online GM for (int i = 0; i < fd_max; i++) { @@ -341,7 +334,7 @@ int intif_parse_AccountReg(int fd) for (p = 8, j = 0; p < RFIFOW(fd, 2) && j < ACCOUNT_REG_NUM; p += 36, j++) { - RFIFO_STRING(fd, p, sd->status.account_reg[j].str, 32); + sd->status.account_reg[j].str = stringish<VarName>(RFIFO_STRING<32>(fd, p)); sd->status.account_reg[j].value = RFIFOL(fd, p + 32); } sd->status.account_reg_num = j; @@ -420,8 +413,7 @@ void intif_parse_PartyCreated(int fd) 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); + PartyName name = stringish<PartyName>(RFIFO_STRING<24>(fd, 11)); party_created(account_id, fail, party_id, name); } @@ -474,8 +466,7 @@ 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); + CharName name = stringish<CharName>(RFIFO_STRING<24>(fd, 10)); if (battle_config.etc_log) PRINTF("intif: party member leaved %d %d %s\n", party_id, account_id, name); @@ -495,8 +486,7 @@ void intif_parse_PartyMove(int fd) { int party_id = RFIFOL(fd, 2); int account_id = RFIFOL(fd, 6); - char map[16]; - RFIFO_STRING(fd, 10, map, 16); + MapName map = stringish<MapName>(RFIFO_STRING<16>(fd, 10)); uint8_t online = RFIFOB(fd, 26); uint16_t lv = RFIFOW(fd, 27); party_recv_movemap(party_id, account_id, map, online, lv); @@ -507,8 +497,7 @@ static void intif_parse_PartyMessage(int fd) { size_t len = RFIFOW(fd, 2) - 12; - char buf[len]; - RFIFO_STRING(fd, 12, buf, len); + FString buf = RFIFO_STRING(fd, 12, len); party_recv_message(RFIFOL(fd, 4), RFIFOL(fd, 8), buf); } @@ -547,9 +536,8 @@ int intif_parse(int fd) { case 0x3800: { - 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); + FString mes = RFIFO_STRING(fd, 4, packet_len - 4); + clif_GMmessage(NULL, mes, 0); } break; case 0x3801: diff --git a/src/map/intif.hpp b/src/map/intif.hpp index 73a06e5..08added 100644 --- a/src/map/intif.hpp +++ b/src/map/intif.hpp @@ -7,10 +7,10 @@ int intif_parse(int fd); -void intif_GMmessage(const_string mes); +void intif_GMmessage(XString mes); -void intif_wis_message(dumb_ptr<map_session_data> sd, const char *nick, const char *mes); -void intif_wis_message_to_gm(const char *Wisp_name, int min_gm_level, const char *mes); +void intif_wis_message(dumb_ptr<map_session_data> sd, CharName nick, ZString mes); +void intif_wis_message_to_gm(CharName Wisp_name, int min_gm_level, ZString mes); void intif_saveaccountreg(dumb_ptr<map_session_data> sd); void intif_request_accountreg(dumb_ptr<map_session_data> sd); @@ -18,14 +18,14 @@ void intif_request_accountreg(dumb_ptr<map_session_data> sd); void intif_request_storage(int account_id); void intif_send_storage(struct storage *stor); -void intif_create_party(dumb_ptr<map_session_data> sd, const char *name); +void intif_create_party(dumb_ptr<map_session_data> sd, PartyName name); void intif_request_partyinfo(int party_id); void intif_party_addmember(int party_id, int account_id); void intif_party_changeoption(int party_id, int account_id, int exp, int item); void intif_party_leave(int party_id, int accound_id); void intif_party_changemap(dumb_ptr<map_session_data> sd, int online); -void intif_party_message(int party_id, int account_id, const char *mes); -void intif_party_checkconflict(int party_id, int account_id, const char *nick); +void intif_party_message(int party_id, int account_id, XString mes); +void intif_party_checkconflict(int party_id, int account_id, CharName nick); #endif // INTIF_HPP diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 570b517..cb47b21 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -3,10 +3,14 @@ #include <cstdlib> #include <cstring> +#include <fstream> + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" -#include "../common/random.hpp" +#include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "../common/socket.hpp" #include "../poison.hpp" @@ -33,9 +37,9 @@ int itemdb_readdb(void); */ // name = item alias, so we should find items aliases first. if not found then look for "jname" (full name) static -void itemdb_searchname_sub(struct item_data *item, const char *str, struct item_data **dst) +void itemdb_searchname_sub(struct item_data *item, ItemName str, struct item_data **dst) { - if (strcasecmp(item->name, str) == 0) //by lupus + if (item->name == str) *dst = item; } @@ -43,7 +47,7 @@ void itemdb_searchname_sub(struct item_data *item, const char *str, struct item_ * 名前で検索 *------------------------------------------ */ -struct item_data *itemdb_searchname(const char *str) +struct item_data *itemdb_searchname(ItemName str) { struct item_data *item = NULL; for (auto& pair : item_db) @@ -148,62 +152,70 @@ int itemdb_isequip3(int nameid) static int itemdb_readdb(void) { - FILE *fp; - char line[1024]; int ln = 0, lines = 0; - int nameid, j; - struct item_data *id; - int i = 0; - const char *filename[] = { "db/item_db.txt", "db/item_db2.txt" }; + const char *filename = "db/item_db.txt"; - for (i = 0; i < 2; i++) { + std::ifstream in(filename); - fp = fopen_(filename[i], "r"); - if (fp == NULL) + if (!in.is_open()) { - if (i > 0) - continue; - PRINTF("can't read %s\n", filename[i]); + PRINTF("can't read %s\n", filename); exit(1); } lines = 0; - while (fgets(line, 1020, fp)) + + FString line; + while (io::getline(in, line)) { lines++; - if (line[0] == '/' && line[1] == '/') + if (!line) continue; - char *str[32] {}; - char *p; - char *np; - for (j = 0, np = p = line; j < 17 && p; j++) + if (line.startswith("//")) + continue; + // a line is 17 normal fields followed by 2 {} fields + // the fields are separated by ", *", but there may be , + // in the {}. + + auto it = std::find(line.begin(), line.end(), '{'); + XString main_part = line.xislice_h(it).rstrip(); + // According to the code, tail_part may be empty. See later. + ZString tail_part = line.xislice_t(it); + + item_data idv {}; + if (!extract( + main_part, record<','>( + &idv.nameid, + lstripping(&idv.name), + lstripping(&idv.jname), + lstripping(&idv.type), + lstripping(&idv.value_buy), + lstripping(&idv.value_sell), + lstripping(&idv.weight), + lstripping(&idv.atk), + lstripping(&idv.def), + lstripping(&idv.range), + lstripping(&idv.magic_bonus), + lstripping(&idv.slot), + lstripping(&idv.sex), + lstripping(&idv.equip), + lstripping(&idv.wlv), + lstripping(&idv.elv), + lstripping(&idv.look) + ) + ) + ) { - while (*p == '\t' || *p == ' ') - p++; - str[j] = p; - p = strchr(p, ','); - if (p) - { - *p++ = 0; - np = p; - } - } - if (str[0] == NULL) + PRINTF("%s:%d: error: bad item line: %s\n", + filename, lines, line); continue; + } - nameid = atoi(str[0]); - if (nameid <= 0 || nameid >= 20000) - continue; ln++; - //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Gender,Loc,wLV,eLV,View - id = itemdb_search(nameid); - strzcpy(id->name, str[1], 24); - strzcpy(id->jname, str[2], 24); - id->type = ItemType(atoi(str[3])); - id->value_buy = atoi(str[4]); - id->value_sell = atoi(str[5]); + struct item_data *id = itemdb_search(idv.nameid); + *id = std::move(idv); if (id->value_buy == 0 && id->value_sell == 0) { } @@ -215,31 +227,20 @@ int itemdb_readdb(void) { id->value_sell = id->value_buy / 2; } - id->weight = atoi(str[6]); - id->atk = atoi(str[7]); - id->def = atoi(str[8]); - id->range = atoi(str[9]); - id->magic_bonus = atoi(str[10]); - id->slot = atoi(str[11]); - id->sex = atoi(str[12]); - id->equip = EPOS(atoi(str[13])); - id->wlv = atoi(str[14]); - id->elv = atoi(str[15]); - id->look = static_cast<ItemLook>(atoi(str[16])); id->use_script = NULL; id->equip_script = NULL; - if ((p = strchr(np, '{')) == NULL) + if (!tail_part) continue; - id->use_script = parse_script(p, lines); + id->use_script = parse_script(tail_part, lines); - if ((p = strchr(p + 1, '{')) == NULL) + tail_part = tail_part.xislice_t(std::find(tail_part.begin() + 1, tail_part.end(), '{')); + if (!tail_part) continue; - id->equip_script = parse_script(p, lines); + id->equip_script = parse_script(tail_part, lines); } - fclose_(fp); - PRINTF("read %s done (count=%d)\n", filename[i], ln); + PRINTF("read %s done (count=%d)\n", filename, ln); } return 0; } diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 17b2057..7e5aa34 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -9,9 +9,7 @@ struct item_data { int nameid; - char name[24], jname[24]; - char prefix[24], suffix[24]; - char cardillustname[64]; + ItemName name, jname; int value_buy; int value_sell; ItemType type; @@ -37,7 +35,7 @@ struct random_item_data int per; }; -struct item_data *itemdb_searchname(const char *name); +struct item_data *itemdb_searchname(ItemName name); struct item_data *itemdb_search(int nameid); struct item_data *itemdb_exists(int nameid); diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp index 9c9591b..76b86f8 100644 --- a/src/map/magic-expr-eval.hpp +++ b/src/map/magic-expr-eval.hpp @@ -7,7 +7,7 @@ /* Helper definitions for dealing with functions and operations */ -int magic_signature_check(const char *opname, const char *funname, const char *signature, +int magic_signature_check(ZString opname, ZString funname, ZString signature, int args_nr, val_t *args, int line, int column); void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, @@ -15,7 +15,7 @@ void magic_area_rect(map_local **m, int *x, int *y, int *width, int *height, #define ARGINT(x) args[x].v.v_int #define ARGDIR(x) args[x].v.v_dir -#define ARGSTR(x) args[x].v.v_string +#define ARGSTR(x) ZString(args[x].v.v_string) #define ARGENTITY(x) args[x].v.v_entity #define ARGLOCATION(x) args[x].v.v_location #define ARGAREA(x) args[x].v.v_area diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index 5aad257..872ba6f 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -87,12 +87,12 @@ void magic_clear_var(val_t *v) } static -const char *show_entity(dumb_ptr<block_list> entity) +FString show_entity(dumb_ptr<block_list> entity) { switch (entity->bl_type) { case BL::PC: - return entity->as_player()->status.name; + return entity->as_player()->status.name.to__actual(); case BL::NPC: return entity->as_npc()->name; case BL::MOB: @@ -104,23 +104,23 @@ const char *show_entity(dumb_ptr<block_list> entity) // return ((struct item_data *) (&entity->as_item()->item_data))->name; abort(); case BL::SPELL: - return "%invocation(ERROR:this-should-not-be-an-entity)"; + return {"%invocation(ERROR:this-should-not-be-an-entity)"}; default: - return "%unknown-entity"; + return {"%unknown-entity"}; } } static void stringify(val_t *v, int within_op) { - static const char *dirs[8] = - { - "south", "south-west", - "west", "north-west", - "north", "north-east", - "east", "south-east" - }; - std::string buf; + static earray<ZString, DIR, DIR::COUNT> dirs //= + {{ + {"south"}, {"south-west"}, + {"west"}, {"north-west"}, + {"north"}, {"north-east"}, + {"east"}, {"south-east"}, + }}; + FString buf; switch (v->ty) { @@ -136,7 +136,7 @@ void stringify(val_t *v, int within_op) return; case TYPE::DIR: - buf = dirs[v->v.v_int]; + buf = dirs[v->v.v_dir]; break; case TYPE::ENTITY: @@ -278,7 +278,10 @@ int fun_add(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) stringify(&args[1], 1); /* Yes, we could speed this up. */ // ugh - RESULTSTR = dumb_string::copys(ARGSTR(0).str() + ARGSTR(1).str()); + MString m; + m += ARGSTR(0); + m += ARGSTR(1); + RESULTSTR = dumb_string::copys(FString(m)); result->ty = TYPE::STRING; } return 0; @@ -351,7 +354,6 @@ int fun_gte(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { stringify(&args[0], 1); stringify(&args[1], 1); - using namespace operators; RESULTINT = ARGSTR(0) >= ARGSTR(1); } else @@ -370,7 +372,6 @@ int fun_gt(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { stringify(&args[0], 1); stringify(&args[1], 1); - using namespace operators; RESULTINT = ARGSTR(0) > ARGSTR(1); } else @@ -389,7 +390,6 @@ int fun_eq(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { stringify(&args[0], 1); stringify(&args[1], 1); - using namespace operators; RESULTINT = ARGSTR(0) == ARGSTR(1); } else if (ARG_TYPE(0) == TYPE::DIR && ARG_TYPE(1) == TYPE::DIR) @@ -652,7 +652,7 @@ int fun_name_of(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { if (ARG_TYPE(0) == TYPE::ENTITY) { - RESULTSTR = dumb_string::copy(show_entity(ARGENTITY(0))); + RESULTSTR = dumb_string::copys(show_entity(ARGENTITY(0))); return 0; } else if (ARG_TYPE(0) == TYPE::SPELL) @@ -745,7 +745,7 @@ magic_find_item(const_array<val_t> args, int index, struct item *item_, int *sta if (ARG_TYPE(index) == TYPE::INT) item_data = itemdb_exists(ARGINT(index)); else if (ARG_TYPE(index) == TYPE::STRING) - item_data = itemdb_searchname(ARGSTR(index).c_str()); + item_data = itemdb_searchname(stringish<ItemName>(ARGSTR(index))); else return -1; @@ -874,14 +874,16 @@ int fun_failed(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) static int fun_npc(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { - RESULTENTITY = npc_name2id(ARGSTR(0).c_str()); + NpcName name = stringish<NpcName>(ARGSTR(0)); + RESULTENTITY = npc_name2id(name); return RESULTENTITY == NULL; } static int fun_pc(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { - RESULTENTITY = map_nick2sd(ARGSTR(0).c_str()); + CharName name = stringish<CharName>(ARGSTR(0)); + RESULTENTITY = map_nick2sd(name); return RESULTENTITY == NULL; } @@ -913,7 +915,7 @@ int fun_rdistance(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) static int fun_anchor(dumb_ptr<env_t> env, val_t *result, const_array<val_t> args) { - dumb_ptr<teleport_anchor_t> anchor = magic_find_anchor(ARGSTR(0).str()); + dumb_ptr<teleport_anchor_t> anchor = magic_find_anchor(ARGSTR(0)); if (!anchor) return 1; @@ -997,12 +999,12 @@ static int fun_read_script_int(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { dumb_ptr<block_list> subject_p = ARGENTITY(0); - dumb_string var_name = ARGSTR(1); + VarName var_name = stringish<VarName>(ARGSTR(1)); if (subject_p->bl_type != BL::PC) return 1; - RESULTINT = pc_readglobalreg(subject_p->as_player(), var_name.c_str()); + RESULTINT = pc_readglobalreg(subject_p->as_player(), var_name); return 0; } @@ -1055,13 +1057,6 @@ int fun_element_level(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) } static -int fun_index(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) -{ - RESULTINT = ARGSPELL(0)->index_; - return 0; -} - -static int fun_is_exterior(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { #warning "Evil assumptions!" @@ -1136,7 +1131,7 @@ static int fun_map_nr(dumb_ptr<env_t>, val_t *result, const_array<val_t> args) { #warning "Evil assumptions!" - const char *mapname = ARGLOCATION(0).m->name_; + MapName mapname = ARGLOCATION(0).m->name_; RESULTINT = ((mapname[0] - '0') * 100) + ((mapname[1] - '0') * 10) + ((mapname[2] - '0')); @@ -1221,123 +1216,93 @@ int fun_extract_healer_xp(dumb_ptr<env_t>, val_t *result, const_array<val_t> arg return 0; } -static -fun_t functions[] = -{ - {"+", "..", '.', fun_add}, - {"-", "ii", 'i', fun_sub}, - {"*", "ii", 'i', fun_mul}, - {"/", "ii", 'i', fun_div}, - {"%", "ii", 'i', fun_mod}, - {"||", "ii", 'i', fun_or}, - {"&&", "ii", 'i', fun_and}, - {">", "..", 'i', fun_gt}, - {">=", "..", 'i', fun_gte}, - {"=", "..", 'i', fun_eq}, - {"|", "..", 'i', fun_bitor}, - {"&", "ii", 'i', fun_bitand}, - {"^", "ii", 'i', fun_bitxor}, - {"<<", "ii", 'i', fun_bitshl}, - {">>", "ii", 'i', fun_bitshr}, - {"not", "i", 'i', fun_not}, - {"neg", "i", 'i', fun_neg}, - {"max", "ii", 'i', fun_max}, - {"min", "ii", 'i', fun_min}, - {"is_in", "la", 'i', fun_is_in}, - {"if_then_else", "i__", '_', fun_if_then_else}, - {"skill", "ei", 'i', fun_skill}, - {"str", "e", 'i', fun_get_str}, - {"agi", "e", 'i', fun_get_agi}, - {"vit", "e", 'i', fun_get_vit}, - {"dex", "e", 'i', fun_get_dex}, - {"luk", "e", 'i', fun_get_luk}, - {"int", "e", 'i', fun_get_int}, - {"level", "e", 'i', fun_get_lv}, - {"mdef", "e", 'i', fun_get_mdef}, - {"def", "e", 'i', fun_get_def}, - {"hp", "e", 'i', fun_get_hp}, - {"max_hp", "e", 'i', fun_get_max_hp}, - {"sp", "e", 'i', fun_get_sp}, - {"max_sp", "e", 'i', fun_get_max_sp}, - {"dir", "e", 'd', fun_get_dir}, - {"name_of", ".", 's', fun_name_of}, - {"mob_id", "e", 'i', fun_mob_id}, - {"location", "e", 'l', fun_location}, - {"random", "i", 'i', fun_random}, - {"random_dir", "i", 'd', fun_random_dir}, - {"hash_entity", "e", 'i', fun_hash_entity}, - {"is_married", "e", 'i', fun_is_married}, - {"partner", "e", 'e', fun_partner}, - {"awayfrom", "ldi", 'l', fun_awayfrom}, - {"failed", "_", 'i', fun_failed}, - {"pc", "s", 'e', fun_pc}, - {"npc", "s", 'e', fun_npc}, - {"distance", "ll", 'i', fun_distance}, - {"rdistance", "ll", 'i', fun_rdistance}, - {"anchor", "s", 'a', fun_anchor}, - {"random_location", "a", 'l', fun_pick_location}, - {"script_int", "es", 'i', fun_read_script_int}, - {"rbox", "li", 'a', fun_rbox}, - {"count_item", "e.", 'i', fun_count_item}, - {"line_of_sight", "ll", 'i', fun_line_of_sight}, - {"running_status_update", "ei", 'i', fun_running_status_update}, - {"status_option", "ei", 'i', fun_status_option}, - {"element", "e", 'i', fun_element}, - {"element_level", "e", 'i', fun_element_level}, - {"has_shroud", "e", 'i', fun_has_shroud}, - {"is_equipped", "e.", 'i', fun_is_equipped}, - {"spell_index", "S", 'i', fun_index}, - {"is_exterior", "l", 'i', fun_is_exterior}, - {"contains_string", "ss", 'i', fun_contains_string}, - {"strstr", "ss", 'i', fun_strstr}, - {"strlen", "s", 'i', fun_strlen}, - {"substr", "sii", 's', fun_substr}, - {"sqrt", "i", 'i', fun_sqrt}, - {"map_level", "l", 'i', fun_map_level}, - {"map_nr", "l", 'i', fun_map_nr}, - {"dir_towards", "lli", 'd', fun_dir_towards}, - {"is_dead", "e", 'i', fun_is_dead}, - {"is_pc", "e", 'i', fun_is_pc}, - {"extract_healer_experience", "ei", 'i', fun_extract_healer_xp}, - {NULL, NULL, '.', NULL} +#define MAGIC_FUNCTION(name, args, ret, impl) {{name}, {{name}, {args}, ret, impl}} +#define MAGIC_FUNCTION1(name, args, ret) MAGIC_FUNCTION(#name, args, ret, fun_##name) +static +std::map<ZString, fun_t> functions = +{ + MAGIC_FUNCTION("+", "..", '.', fun_add), + MAGIC_FUNCTION("-", "ii", 'i', fun_sub), + MAGIC_FUNCTION("*", "ii", 'i', fun_mul), + MAGIC_FUNCTION("/", "ii", 'i', fun_div), + MAGIC_FUNCTION("%", "ii", 'i', fun_mod), + MAGIC_FUNCTION("||", "ii", 'i', fun_or), + MAGIC_FUNCTION("&&", "ii", 'i', fun_and), + MAGIC_FUNCTION(">", "..", 'i', fun_gt), + MAGIC_FUNCTION(">=", "..", 'i', fun_gte), + MAGIC_FUNCTION("=", "..", 'i', fun_eq), + MAGIC_FUNCTION("|", "..", 'i', fun_bitor), + MAGIC_FUNCTION("&", "ii", 'i', fun_bitand), + MAGIC_FUNCTION("^", "ii", 'i', fun_bitxor), + MAGIC_FUNCTION("<<", "ii", 'i', fun_bitshl), + MAGIC_FUNCTION(">>", "ii", 'i', fun_bitshr), + MAGIC_FUNCTION1(not, "i", 'i'), + MAGIC_FUNCTION1(neg, "i", 'i'), + MAGIC_FUNCTION1(max, "ii", 'i'), + MAGIC_FUNCTION1(min, "ii", 'i'), + MAGIC_FUNCTION1(is_in, "la", 'i'), + MAGIC_FUNCTION1(if_then_else, "i__", '_'), + MAGIC_FUNCTION1(skill, "ei", 'i'), + MAGIC_FUNCTION("str", "e", 'i', fun_get_str), + MAGIC_FUNCTION("agi", "e", 'i', fun_get_agi), + MAGIC_FUNCTION("vit", "e", 'i', fun_get_vit), + MAGIC_FUNCTION("dex", "e", 'i', fun_get_dex), + MAGIC_FUNCTION("luk", "e", 'i', fun_get_luk), + MAGIC_FUNCTION("int", "e", 'i', fun_get_int), + MAGIC_FUNCTION("level", "e", 'i', fun_get_lv), + MAGIC_FUNCTION("mdef", "e", 'i', fun_get_mdef), + MAGIC_FUNCTION("def", "e", 'i', fun_get_def), + MAGIC_FUNCTION("hp", "e", 'i', fun_get_hp), + MAGIC_FUNCTION("max_hp", "e", 'i', fun_get_max_hp), + MAGIC_FUNCTION("sp", "e", 'i', fun_get_sp), + MAGIC_FUNCTION("max_sp", "e", 'i', fun_get_max_sp), + MAGIC_FUNCTION("dir", "e", 'd', fun_get_dir), + MAGIC_FUNCTION1(name_of, ".", 's'), + MAGIC_FUNCTION1(mob_id, "e", 'i'), + MAGIC_FUNCTION1(location, "e", 'l'), + MAGIC_FUNCTION1(random, "i", 'i'), + MAGIC_FUNCTION1(random_dir, "i", 'd'), + MAGIC_FUNCTION1(hash_entity, "e", 'i'), + MAGIC_FUNCTION1(is_married, "e", 'i'), + MAGIC_FUNCTION1(partner, "e", 'e'), + MAGIC_FUNCTION1(awayfrom, "ldi", 'l'), + MAGIC_FUNCTION1(failed, "_", 'i'), + MAGIC_FUNCTION1(pc, "s", 'e'), + MAGIC_FUNCTION1(npc, "s", 'e'), + MAGIC_FUNCTION1(distance, "ll", 'i'), + MAGIC_FUNCTION1(rdistance, "ll", 'i'), + MAGIC_FUNCTION1(anchor, "s", 'a'), + MAGIC_FUNCTION("random_location", "a", 'l', fun_pick_location), + MAGIC_FUNCTION("script_int", "es", 'i', fun_read_script_int), + MAGIC_FUNCTION1(rbox, "li", 'a'), + MAGIC_FUNCTION1(count_item, "e.", 'i'), + MAGIC_FUNCTION1(line_of_sight, "ll", 'i'), + MAGIC_FUNCTION1(running_status_update, "ei", 'i'), + MAGIC_FUNCTION1(status_option, "ei", 'i'), + MAGIC_FUNCTION1(element, "e", 'i'), + MAGIC_FUNCTION1(element_level, "e", 'i'), + MAGIC_FUNCTION1(has_shroud, "e", 'i'), + MAGIC_FUNCTION1(is_equipped, "e.", 'i'), + MAGIC_FUNCTION1(is_exterior, "l", 'i'), + MAGIC_FUNCTION1(contains_string, "ss", 'i'), + MAGIC_FUNCTION1(strstr, "ss", 'i'), + MAGIC_FUNCTION1(strlen, "s", 'i'), + MAGIC_FUNCTION1(substr, "sii", 's'), + MAGIC_FUNCTION1(sqrt, "i", 'i'), + MAGIC_FUNCTION1(map_level, "l", 'i'), + MAGIC_FUNCTION1(map_nr, "l", 'i'), + MAGIC_FUNCTION1(dir_towards, "lli", 'd'), + MAGIC_FUNCTION1(is_dead, "e", 'i'), + MAGIC_FUNCTION1(is_pc, "e", 'i'), + MAGIC_FUNCTION("extract_healer_experience", "ei", 'i', fun_extract_healer_xp), }; -static -int functions_are_sorted = 0; - -static __attribute__((deprecated)) -int compare_fun(const void *lhs, const void *rhs) -{ - return strcmp(static_cast<const fun_t *>(lhs)->name, static_cast<const fun_t *>(rhs)->name); -} - -fun_t *magic_get_fun(const std::string& name, int *index) +fun_t *magic_get_fun(ZString name) { - static - int functions_nr; - fun_t *result; - fun_t key; - - if (!functions_are_sorted) - { - fun_t *it = functions; - - while (it->name) - ++it; - functions_nr = it - functions; - - qsort(functions, functions_nr, sizeof(fun_t), compare_fun); - functions_are_sorted = 1; - } - - key.name = name.c_str(); - result = static_cast<fun_t *>(bsearch(&key, functions, functions_nr, sizeof(fun_t), - compare_fun)); - - if (result && index) - *index = result - functions; - - return result; + auto it = functions.find(name); + if (it == functions.end()) + return nullptr; + return &it->second; } // 1 on failure @@ -1352,7 +1317,8 @@ int eval_location(dumb_ptr<env_t> env, location_t *dest, e_location_t *expr) if (CHECK_TYPE(&m, TYPE::STRING) && CHECK_TYPE(&x, TYPE::INT) && CHECK_TYPE(&y, TYPE::INT)) { - map_local *map_id = map_mapname2mapid(m.v.v_string.c_str()); + MapName name = VString<15>(ZString(m.v.v_string)); + map_local *map_id = map_mapname2mapid(name); magic_clear_var(&m); if (!map_id) return 1; @@ -1509,8 +1475,8 @@ TYPE type_key(char ty_key) } } -int magic_signature_check(const char *opname, const char *funname, const char *signature, - int args_nr, val_t *args, int line, int column) +int magic_signature_check(ZString opname, ZString funname, ZString signature, + int args_nr, val_t *args, int line, int column) { int i; for (i = 0; i < args_nr; i++) @@ -1620,7 +1586,7 @@ void magic_eval(dumb_ptr<env_t> env, val_t *dest, dumb_ptr<expr_t> expr) val_t arguments[MAX_ARGS]; int args_nr = expr->e.e_funapp.args_nr; int i; - fun_t *f = functions + expr->e.e_funapp.id; + fun_t *f = expr->e.e_funapp.funp; for (i = 0; i < args_nr; ++i) magic_eval(env, &arguments[i], expr->e.e_funapp.args[i]); @@ -1705,13 +1671,13 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) return result.v.v_int; } -std::string magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) +FString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr) { val_t result; magic_eval(env, &result, expr); if (result.ty == TYPE::FAIL || result.ty == TYPE::UNDEF) - return "?"; + return {"?"}; stringify(&result, 0); diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp index 7f3e1e1..2bffcbc 100644 --- a/src/map/magic-expr.hpp +++ b/src/map/magic-expr.hpp @@ -16,34 +16,34 @@ * . : any, except for fail/undef * _ : any, including fail, but not undef */ -typedef struct fun +struct fun_t { - const char *name; - const char *signature; + ZString name; + ZString signature; char ret_ty; int (*fun)(dumb_ptr<env_t> env, val_t *result, const_array<val_t> arga); -} fun_t; +}; -typedef struct op +struct op_t { - const char *name; - const char *signature; + ZString name; + ZString signature; int (*op)(dumb_ptr<env_t> env, const_array<val_t> arga); -} op_t; +}; /** * Retrieves a function by name * @param name The name to look up - * @return A function of that name, or NULL, and a function index + * @return A function of that name, or NULL. */ -fun_t *magic_get_fun(const std::string& name, int *index); +fun_t *magic_get_fun(ZString name); /** * Retrieves an operation by name * @param name The name to look up * @return An operation of that name, or NULL, and a function index */ -op_t *magic_get_op(const std::string& name, int *index); +op_t *magic_get_op(ZString name); /** * Evaluates an expression and stores the result in `dest' @@ -58,7 +58,7 @@ int magic_eval_int(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); /** * Evaluates an expression and coerces the result into a string */ -std::string magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); +FString magic_eval_str(dumb_ptr<env_t> env, dumb_ptr<expr_t> expr); dumb_ptr<expr_t> magic_new_expr(EXPR ty); diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp index 3d0c853..1a80617 100644 --- a/src/map/magic-interpreter-base.cpp +++ b/src/map/magic-interpreter-base.cpp @@ -62,16 +62,16 @@ void set_spell SETTER(dumb_ptr<spell_t>, TYPE::SPELL, v_spell) magic_conf_t magic_conf; /* Global magic conf */ env_t magic_default_env = { &magic_conf, NULL }; -const char *magic_find_invocation(const std::string& spellname) +FString magic_find_invocation(XString spellname) { auto it = magic_conf.spells_by_name.find(spellname); if (it != magic_conf.spells_by_name.end()) - return it->second->invocation.c_str(); + return it->second->invocation; - return NULL; + return FString(); } -dumb_ptr<spell_t> magic_find_spell(const std::string& invocation) +dumb_ptr<spell_t> magic_find_spell(XString invocation) { auto it = magic_conf.spells_by_invocation.find(invocation); if (it != magic_conf.spells_by_invocation.end()) @@ -84,17 +84,17 @@ dumb_ptr<spell_t> magic_find_spell(const std::string& invocation) /* Spell anchors */ /* -------------------------------------------------------------------------------- */ -const char *magic_find_anchor_invocation(const std::string& anchor_name) +FString magic_find_anchor_invocation(XString anchor_name) { auto it = magic_conf.anchors_by_name.find(anchor_name); if (it != magic_conf.anchors_by_name.end()) - return it->second->invocation.c_str(); + return it->second->invocation; - return NULL; + return FString(); } -dumb_ptr<teleport_anchor_t> magic_find_anchor(const std::string& name) +dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name) { auto it = magic_conf.anchors_by_invocation.find(name); if (it != magic_conf.anchors_by_invocation.end()) @@ -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, XString param) { dumb_ptr<env_t> env = alloc_env(conf); @@ -145,12 +145,13 @@ dumb_ptr<env_t> spell_create_env(magic_conf_t *conf, dumb_ptr<spell_t> spell, { case SPELLARG::STRING: - set_env_string(spell->arg, dumb_string::copyc(param)); + set_env_string(spell->arg, dumb_string::copys(param)); break; case SPELLARG::PC: { - dumb_ptr<map_session_data> subject = map_nick2sd(std::string(param.begin(), param.end()).c_str()); + CharName name = stringish<CharName>(param); + dumb_ptr<map_session_data> subject = map_nick2sd(name); if (!subject) subject = caster; set_env_entity(spell->arg, subject); diff --git a/src/map/magic-interpreter-parser.ypp b/src/map/magic-interpreter-parser.ypp index a392bc7..e6d69b4 100644 --- a/src/map/magic-interpreter-parser.ypp +++ b/src/map/magic-interpreter-parser.ypp @@ -19,21 +19,25 @@ // I still don't get why this is necessary. #define YYLEX_PARAM 0, 0 +// can't use src/warnings.hpp in generated code #pragma GCC diagnostic warning "-Wall" #pragma GCC diagnostic warning "-Wextra" #pragma GCC diagnostic warning "-Wformat" +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif static -size_t intern_id(const_string id_name); +size_t intern_id(ZString id_name); static -dumb_ptr<expr_t> fun_expr(const std::string& name, const_array<dumb_ptr<expr_t>> argv, int line, int column); +dumb_ptr<expr_t> fun_expr(FString name, const_array<dumb_ptr<expr_t>> argv, int line, int column); static dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> lhs, int id); static -void BIN_EXPR(dumb_ptr<expr_t> & x, const std::string& name, dumb_ptr<expr_t> arg1, dumb_ptr<expr_t> arg2, int line, int column) +void BIN_EXPR(dumb_ptr<expr_t>& x, FString name, dumb_ptr<expr_t> arg1, dumb_ptr<expr_t> arg2, int line, int column) { dumb_ptr<expr_t> e[2]; e[0] = arg1; @@ -72,7 +76,7 @@ static void add_teleport_anchor(dumb_ptr<teleport_anchor_t> anchor, int line_nr); static -dumb_ptr<effect_t> op_effect(const std::string& name, const_array<dumb_ptr<expr_t>> argv, int line, int column); +dumb_ptr<effect_t> op_effect(FString name, const_array<dumb_ptr<expr_t>> argv, int line, int column); // in magic-interpreter-lexer.cpp int magic_frontend_lex(YYSTYPE *, YYLTYPE *); @@ -81,13 +85,13 @@ static void install_proc(dumb_ptr<proc_t> proc); static -dumb_ptr<effect_t> call_proc(const_string name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column); +dumb_ptr<effect_t> call_proc(ZString name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column); static -void bind_constant(const std::string& name, val_t *val, int line_nr); +void bind_constant(FString name, val_t *val, int line_nr); static -val_t *find_constant(const std::string& name); +val_t *find_constant(FString name); } // %code @@ -919,7 +923,7 @@ item_name : STRING { - struct item_data *item = itemdb_searchname($1.c_str()); + struct item_data *item = itemdb_searchname(stringish<ItemName>(ZString($1))); if (!item) { fail(@1.first_line, @1.first_column, "Unknown item `%s'\n", $1.c_str()); @@ -1066,7 +1070,7 @@ effect | SCRIPT_DATA { $$ = new_effect(EFFECT::SCRIPT); - $$->e.e_script = dumb_ptr<const ScriptBuffer>(parse_script($1.c_str(), @1.first_line).release()); + $$->e.e_script = dumb_ptr<const ScriptBuffer>(parse_script(ZString($1), @1.first_line).release()); $1.delete_(); if ($$->e.e_script == NULL) fail(@1.first_line, @1.first_column, "Failed to compile script\n"); @@ -1098,9 +1102,8 @@ effect_list %% -size_t intern_id(const_string id_name_) +size_t intern_id(ZString id_name) { - std::string id_name(id_name_.begin(), id_name_.end()); size_t i; for (i = 0; i < magic_conf.varv.size(); i++) if (id_name == magic_conf.varv[i].name) @@ -1173,18 +1176,17 @@ dumb_ptr<expr_t> dot_expr(dumb_ptr<expr_t> expr, int id) return retval; } -dumb_ptr<expr_t> fun_expr(const std::string& name, const_array<dumb_ptr<expr_t>> argv, int line, int column) +dumb_ptr<expr_t> fun_expr(FString name, const_array<dumb_ptr<expr_t>> argv, int line, int column) { - int id; dumb_ptr<expr_t> expr; - fun_t *fun = magic_get_fun(name, &id); + fun_t *fun = magic_get_fun(name); if (!fun) fail(line, column, "Unknown function `%s'\n", name.c_str()); - else if (strlen(fun->signature) != argv.size()) + else if (fun->signature.size() != argv.size()) { fail(line, column, "Incorrect number of arguments to function `%s': Expected %zu, found %zu\n", - name.c_str(), strlen(fun->signature), argv.size()); + name.c_str(), fun->signature.size(), argv.size()); fun = NULL; } @@ -1193,7 +1195,7 @@ dumb_ptr<expr_t> fun_expr(const std::string& name, const_array<dumb_ptr<expr_t>> expr = magic_new_expr(EXPR::FUNAPP); expr->e.e_funapp.line_nr = line; expr->e.e_funapp.column = column; - expr->e.e_funapp.id = id; + expr->e.e_funapp.funp = fun; assert (argv.size() <= MAX_ARGS); expr->e.e_funapp.args_nr = argv.size(); @@ -1212,10 +1214,7 @@ dumb_ptr<expr_t> fun_expr(const std::string& name, const_array<dumb_ptr<expr_t>> dumb_ptr<spell_t> new_spell(dumb_ptr<spellguard_t> guard) { - static int spell_counter = 0; - auto retval = dumb_ptr<spell_t>::make(); - retval->index_ = ++spell_counter; retval->spellguard = guard; return retval; } @@ -1288,18 +1287,17 @@ dumb_ptr<effect_t> set_effect_continuation(dumb_ptr<effect_t> src, dumb_ptr<effe return retval; } -dumb_ptr<effect_t> op_effect(const std::string& name, const_array<dumb_ptr<expr_t>> argv, int line, int column) +dumb_ptr<effect_t> op_effect(FString name, const_array<dumb_ptr<expr_t>> argv, int line, int column) { - int id; dumb_ptr<effect_t> effect; - op_t *op = magic_get_op(name, &id); + op_t *op = magic_get_op(name); if (!op) fail(line, column, "Unknown operation `%s'\n", name.c_str()); - else if (strlen(op->signature) != argv.size()) + else if (op->signature.size() != argv.size()) { fail(line, column, "Incorrect number of arguments to operation `%s': Expected %zu, found %zu\n", - name.c_str(), strlen(op->signature), argv.size()); + name.c_str(), op->signature.size(), argv.size()); op = NULL; } @@ -1308,7 +1306,7 @@ dumb_ptr<effect_t> op_effect(const std::string& name, const_array<dumb_ptr<expr_ effect = new_effect(EFFECT::OP); effect->e.e_op.line_nr = line; effect->e.e_op.column = column; - effect->e.e_op.id = id; + effect->e.e_op.opp = op; assert (argv.size() <= MAX_ARGS); effect->e.e_op.args_nr = argv.size(); @@ -1321,7 +1319,7 @@ dumb_ptr<effect_t> op_effect(const std::string& name, const_array<dumb_ptr<expr_ } -std::map<std::string, proc_t> procs; +std::map<FString, proc_t> procs; // I think this was a memory leak (or undefined behavior) void install_proc(dumb_ptr<proc_t> proc) @@ -1329,9 +1327,8 @@ void install_proc(dumb_ptr<proc_t> proc) procs.insert({proc->name, std::move(*proc)}); } -dumb_ptr<effect_t> call_proc(const_string name_, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column) +dumb_ptr<effect_t> call_proc(ZString name, dumb_ptr<std::vector<dumb_ptr<expr_t>>> argvp, int line_nr, int column) { - std::string name(name_.begin(), name_.end()); auto pi = procs.find(name); if (pi == procs.end()) { @@ -1355,9 +1352,9 @@ dumb_ptr<effect_t> call_proc(const_string name_, dumb_ptr<std::vector<dumb_ptr<e return retval; } -std::map<std::string, val_t> const_defm; +std::map<FString, val_t> const_defm; -void bind_constant(const std::string& name, val_t *val, int line_nr) +void bind_constant(FString name, val_t *val, int line_nr) { if (!const_defm.insert({name, *val}).second) { @@ -1365,7 +1362,7 @@ void bind_constant(const std::string& name, val_t *val, int line_nr) } } -val_t *find_constant(const std::string& name) +val_t *find_constant(FString name) { auto it = const_defm.find(name); if (it != const_defm.end()) @@ -1379,7 +1376,7 @@ static int error_flag; inline -void INTERN_ASSERT(const char *name, int id) +void INTERN_ASSERT(ZString name, int id) { int zid = intern_id(name); if (zid != id) diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp index 9b60d998..13c91e9 100644 --- a/src/map/magic-interpreter.hpp +++ b/src/map/magic-interpreter.hpp @@ -10,6 +10,8 @@ #include "script.hpp" #include "skill.t.hpp" +struct fun_t; +struct op_t; struct expr_t; struct val_t; struct location_t; @@ -118,7 +120,8 @@ struct expr_t e_area_t e_area; struct { - int id, line_nr, column; + fun_t *funp; + int line_nr, column; int args_nr; dumb_ptr<expr_t> args[MAX_ARGS]; } e_funapp; @@ -169,7 +172,7 @@ struct effect_t dumb_ptr<const ScriptBuffer> e_script; struct { - int id; + op_t *opp; int args_nr; int line_nr, column; dumb_ptr<expr_t> args[MAX_ARGS]; @@ -238,9 +241,8 @@ struct letdef_t struct spell_t { - std::string name; - std::string invocation; - int index_; // Relative location in the definitions file + FString name; + FString invocation; SPELL_FLAG flags; int arg; SPELLARG spellarg_ty; @@ -256,8 +258,8 @@ struct spell_t struct teleport_anchor_t { - std::string name; - std::string invocation; + FString name; + FString invocation; dumb_ptr<expr_t> location; }; @@ -269,15 +271,15 @@ struct magic_conf_t { struct mcvar { - std::string name; + FString name; val_t val; }; // This should probably be done by a dedicated "intern pool" class std::vector<mcvar> varv; - std::map<std::string, dumb_ptr<spell_t>> spells_by_name, spells_by_invocation; + std::map<FString, dumb_ptr<spell_t>> spells_by_name, spells_by_invocation; - std::map<std::string, dumb_ptr<teleport_anchor_t>> anchors_by_name, anchors_by_invocation; + std::map<FString, dumb_ptr<teleport_anchor_t>> anchors_by_name, anchors_by_invocation; }; /* Execution environment */ @@ -390,10 +392,10 @@ extern env_t magic_default_env; /* Fake default environment */ */ void magic_add_component(dumb_ptr<component_t> *component_holder, int id, int count); -dumb_ptr<teleport_anchor_t> magic_find_anchor(const std::string& name); +dumb_ptr<teleport_anchor_t> magic_find_anchor(XString name); 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, XString param); void magic_free_env(dumb_ptr<env_t> env); @@ -419,7 +421,7 @@ int spell_unbind(dumb_ptr<map_session_data> subject, dumb_ptr<invocation> invoca */ dumb_ptr<invocation> spell_clone_effect(dumb_ptr<invocation> source); -dumb_ptr<spell_t> magic_find_spell(const std::string& invocation); +dumb_ptr<spell_t> magic_find_spell(XString invocation); /* The following is used only by the parser: */ struct args_rec_t @@ -429,7 +431,7 @@ struct args_rec_t struct proc_t { - std::string name; + FString name; std::vector<int> argv; dumb_ptr<effect_t> body; diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index 5d732c8..6b013ab 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -276,7 +276,7 @@ dumb_ptr<npc_data> local_spell_effect(map_local *m, int x, int y, int effect, /* 1 minute should be enough for all interesting spell effects, I hope */ std::chrono::seconds delay = std::chrono::seconds(30); dumb_ptr<npc_data> effect_npc = npc_spawn_text(m, x, y, - INVISIBLE_NPC, "", "?"); + INVISIBLE_NPC, NpcName(), "?"); int effect_npc_id = effect_npc->bl_id; entity_effect(effect_npc, effect, tdelay); @@ -415,8 +415,9 @@ int op_messenger_npc(dumb_ptr<env_t>, const_array<val_t> args) dumb_ptr<npc_data> npc; location_t *loc = &ARGLOCATION(0); + NpcName npcname = stringish<NpcName>(ARGSTR(2)); npc = npc_spawn_text(loc->m, loc->x, loc->y, - ARGINT(1), ARGSTR(2).c_str(), ARGSTR(3).c_str()); + ARGINT(1), npcname, ARGSTR(3)); Timer(gettick() + static_cast<interval_t>(ARGINT(4)), std::bind(timer_callback_kill_npc, ph::_1, ph::_2, @@ -446,13 +447,13 @@ void entity_warp(dumb_ptr<block_list> target, map_local *destm, int destx, int d pc_touch_all_relevant_npcs(character); // Note that touching NPCs may have triggered warping and thereby updated x and y: - const char *map_name = character->bl_m->name_; + MapName map_name = character->bl_m->name_; // Warp part #1: update relevant data, interrupt trading etc.: pc_setpos(character, map_name, character->bl_x, character->bl_y, BeingRemoveWhy::GONE); // Warp part #2: now notify the client clif_changemap(character, map_name, - character->bl_x, character->bl_y); + character->bl_x, character->bl_y); break; } case BL::MOB: @@ -688,8 +689,8 @@ int op_spawn(dumb_ptr<env_t>, const_array<val_t> args) int mob_id; dumb_ptr<mob_data> mob; - mob_id = mob_once_spawn(owner, loc.m->name_, loc.x, loc.y, "--ja--", // Is that needed? - monster_id, 1, ""); + mob_id = mob_once_spawn(owner, loc.m->name_, loc.x, loc.y, JAPANESE_NAME, // Is that needed? + monster_id, 1, NpcEvent()); mob = map_id_as_mob(mob_id); @@ -823,7 +824,8 @@ int op_set_script_variable(dumb_ptr<env_t>, const_array<val_t> args) if (!c) return 1; - pc_setglobalreg(c, ARGSTR(1).c_str(), ARGINT(2)); + VarName varname = stringish<VarName>(ARGSTR(1)); + pc_setglobalreg(c, varname, ARGINT(2)); return 0; } @@ -893,73 +895,43 @@ int op_gain_exp(dumb_ptr<env_t>, const_array<val_t> args) return 0; } +#define MAGIC_OPERATION(name, args, impl) {{name}, {{name}, {args}, impl}} +#define MAGIC_OPERATION1(name, args) MAGIC_OPERATION(#name, args, op_##name) static -op_t operations[] = -{ - {"sfx", ".ii", op_sfx}, - {"instaheal", "eii", op_instaheal}, - {"itemheal", "eii", op_itemheal}, - {"shroud", "ei", op_shroud}, - {"unshroud", "e", op_reveal}, - {"message", "es", op_message}, - {"messenger_npc", "lissi", op_messenger_npc}, - {"move", "ed", op_move}, - {"warp", "el", op_warp}, - {"banish", "e", op_banish}, - {"status_change", "eiiiiii", op_status_change}, - {"stop_status_change", "ei", op_stop_status_change}, - {"override_attack", "eiiiiii", op_override_attack}, - {"create_item", "e.i", op_create_item}, - {"aggravate", "eie", op_aggravate}, - {"spawn", "aeiiii", op_spawn}, - {"injure", "eeii", op_injure}, - {"emote", "ei", op_emote}, - {"set_script_variable", "esi", op_set_script_variable}, - {"set_hair_colour", "ei", op_set_hair_colour}, - {"set_hair_style", "ei", op_set_hair_style}, - {"drop_item", "l.ii", op_drop_item_for}, - {"drop_item_for", "l.iiei", op_drop_item_for}, - {"gain_experience", "eiii", op_gain_exp}, - {NULL, NULL, NULL} +std::map<ZString, op_t> operations = +{ + MAGIC_OPERATION1(sfx, ".ii"), + MAGIC_OPERATION1(instaheal, "eii"), + MAGIC_OPERATION1(itemheal, "eii"), + MAGIC_OPERATION1(shroud, "ei"), + MAGIC_OPERATION("unshroud", "e", op_reveal), + MAGIC_OPERATION1(message, "es"), + MAGIC_OPERATION1(messenger_npc, "lissi"), + MAGIC_OPERATION1(move, "ed"), + MAGIC_OPERATION1(warp, "el"), + MAGIC_OPERATION1(banish, "e"), + MAGIC_OPERATION1(status_change, "eiiiiii"), + MAGIC_OPERATION1(stop_status_change, "ei"), + MAGIC_OPERATION1(override_attack, "eiiiiii"), + MAGIC_OPERATION1(create_item, "e.i"), + MAGIC_OPERATION1(aggravate, "eie"), + MAGIC_OPERATION1(spawn, "aeiiii"), + MAGIC_OPERATION1(injure, "eeii"), + MAGIC_OPERATION1(emote, "ei"), + MAGIC_OPERATION1(set_script_variable, "esi"), + MAGIC_OPERATION1(set_hair_colour, "ei"), + MAGIC_OPERATION1(set_hair_style, "ei"), + MAGIC_OPERATION("drop_item", "l.ii", op_drop_item_for), + MAGIC_OPERATION1(drop_item_for, "l.iiei"), + MAGIC_OPERATION("gain_experience", "eiii", op_gain_exp), }; -static -int operations_sorted = 0; -static -int operation_count; - -static __attribute__((deprecated)) -int compare_operations(const void *lhs, const void *rhs) -{ - return strcmp(static_cast<const op_t *>(lhs)->name, static_cast<const op_t *>(rhs)->name); -} - -op_t *magic_get_op(const std::string& name, int *index) +op_t *magic_get_op(ZString name) { - op_t key; - - if (!operations_sorted) - { - op_t *opc = operations; - - while (opc->name) - ++opc; - - operation_count = opc - operations; - - qsort(operations, operation_count, sizeof(op_t), - compare_operations); - operations_sorted = 1; - } - - key.name = name.c_str(); - op_t *op = static_cast<op_t *>(bsearch(&key, operations, operation_count, sizeof(op_t), - compare_operations)); - - if (op && index) - *index = op - operations; - - return op; + auto it = operations.find(name); + if (it == operations.end()) + return nullptr; + return &it->second; } void spell_effect_report_termination(int invocation_id, int bl_id, @@ -1443,11 +1415,12 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) if (caster) { dumb_ptr<env_t> env = invocation_->env; - argrec_t arg[] = + ZString caster_name = (caster ? caster->status.name : CharName()).to__actual(); + argrec_t arg[3] = { {"@target", env->VAR(VAR_TARGET).ty == TYPE::ENTITY ? 0 : env->VAR(VAR_TARGET).v.v_int}, {"@caster", invocation_->caster}, - {"@caster_name$", caster ? caster->status.name : ""}, + {"@caster_name$", caster_name}, }; int message_recipient = env->VAR(VAR_SCRIPTTARGET).ty == @@ -1461,14 +1434,13 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) if (!invocation_->script_pos) // first time running this script? clif_spawn_fake_npc_for_player(recipient, - invocation_->bl_id); + invocation_->bl_id); // We have to do this or otherwise the client won't think that it's // dealing with an NPC int newpos = run_script_l( ScriptPointer(&*e->e.e_script, invocation_->script_pos), - message_recipient, - invocation_->bl_id, + message_recipient, invocation_->bl_id, 3, arg); /* Returns the new script position, or -1 once the script is finished */ if (newpos != -1) @@ -1492,7 +1464,7 @@ interval_t spell_run(dumb_ptr<invocation> invocation_, int allow_delete) case EFFECT::OP: { - op_t *op = &operations[e->e.e_op.id]; + op_t *op = e->e.e_op.opp; val_t args[MAX_ARGS]; for (i = 0; i < e->e.e_op.args_nr; i++) diff --git a/src/map/magic.cpp b/src/map/magic.cpp index e225830..9c07dd1 100644 --- a/src/map/magic.cpp +++ b/src/map/magic.cpp @@ -12,31 +12,29 @@ /// Return a pair of strings, {spellname, parameter} /// Parameter may be empty. static -std::pair<std::string, std::string> magic_tokenise(std::string src) +std::pair<XString, XString> magic_tokenise(XString src) { - std::string retval = std::move(src); - const std::string::iterator rvb = retval.begin(), rve = retval.end(); - std::string::iterator seeker = std::find(rvb, rve, ' '); + auto seeker = std::find(src.begin(), src.end(), ' '); - if (seeker == retval.end()) + if (seeker == src.end()) { - return {retval, std::string()}; + return {src, XString()}; } else { - std::string rv1(rvb, seeker); + XString rv1 = src.xislice_h(seeker); ++seeker; - while (seeker != rve && *seeker == ' ') + while (seeker != src.end() && *seeker == ' ') ++seeker; // Note: this very well could be empty - std::string rv2(seeker, rve); + XString rv2 = src.xislice_t(seeker); return {rv1, rv2}; } } -int magic_message(dumb_ptr<map_session_data> caster, const std::string& source_invocation) +int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation) { if (pc_isdead(caster)) return 0; @@ -52,8 +50,8 @@ int magic_message(dumb_ptr<map_session_data> caster, const std::string& source_i magic_unshroud(caster); auto pair = magic_tokenise(source_invocation); - std::string spell_invocation = std::move(pair.first); - std::string parameter = std::move(pair.second); + XString spell_invocation = pair.first; + XString parameter = pair.second; dumb_ptr<spell_t> spell = magic_find_spell(spell_invocation); diff --git a/src/map/magic.hpp b/src/map/magic.hpp index cec5bf4..5b10367 100644 --- a/src/map/magic.hpp +++ b/src/map/magic.hpp @@ -21,7 +21,7 @@ struct invocation; /* Spell invocation */ * \return 1 or -1 if the input message was magic and was handled by this function, 0 otherwise. -1 is returned when the * message should not be repeated. */ -int magic_message(dumb_ptr<map_session_data> caster, const std::string& source_invocation); +int magic_message(dumb_ptr<map_session_data> caster, XString source_invocation); /** * Removes the shroud from a character @@ -49,16 +49,16 @@ void do_init_magic(void); /** * Identifies the invocation used to trigger a spell * - * Returns NULL if not found + * Returns empty string if not found */ -const char *magic_find_invocation(const std::string& spellame); +FString magic_find_invocation(XString spellname); /** * Identifies the invocation used to denote a teleport location * - * Returns NULL if not found + * Returns empty string if not found */ -const char *magic_find_anchor_invocation(const std::string& teleport_location); +FString magic_find_anchor_invocation(XString teleport_location); /** * Execute a spell invocation and sets up timers to finish diff --git a/src/map/map.cpp b/src/map/map.cpp index fdae071..f2eefe5 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -15,6 +15,8 @@ #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/db.hpp" +#include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/random2.hpp" #include "../common/nullpo.hpp" #include "../common/socket.hpp" @@ -41,14 +43,14 @@ DMap<int, dumb_ptr<block_list>> id_db; -UPMap<std::string, map_abstract> maps_db; +UPMap<MapName, map_abstract> maps_db; static -DMap<std::string, dumb_ptr<map_session_data>> nick_db; +DMap<CharName, dumb_ptr<map_session_data>> nick_db; struct charid2nick { - char nick[24]; + CharName nick; int req_id; }; @@ -65,19 +67,25 @@ int first_free_object_id = 0, last_object_id = 0; interval_t autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; int save_settings = 0xFFFF; -char motd_txt[256] = "conf/motd.txt"; -char help_txt[256] = "conf/help.txt"; +FString motd_txt = "conf/motd.txt"; +FString help_txt = "conf/help.txt"; -char wisp_server_name[24] = "Server"; // can be modified in char-server configuration file +CharName wisp_server_name = stringish<CharName>("Server"); // can be modified in char-server configuration file static -void map_delmap(const std::string& mapname); +void map_delmap(MapName mapname); void SessionDeleter::operator()(SessionData *sd) { really_delete1 static_cast<map_session_data *>(sd); } +bool extract(XString str, NpcEvent *ev) +{ + XString mid; + return extract(str, record<':'>(&ev->npc, &mid, &ev->label)) && !mid; +} + /*========================================== * 全map鯖総計での接続数設定 * (char鯖から送られてくる) @@ -740,13 +748,13 @@ int map_addflooritem(struct item *item_data, int amount, * charid_dbへ追加(返信待ちがあれば返信) *------------------------------------------ */ -void map_addchariddb(int charid, const char *name) +void map_addchariddb(int charid, CharName name) { struct charid2nick *p = charid_db.search(charid); if (p == NULL) p = charid_db.init(charid); - strzcpy(p->nick, name, 24); + p->nick = name; p->req_id = 0; } @@ -876,14 +884,14 @@ dumb_ptr<map_session_data> map_id2sd(int id) * char_id番号の名前を探す *------------------------------------------ */ -char *map_charid2nick(int id) +CharName map_charid2nick(int id) { struct charid2nick *p = charid_db.search(id); if (p == NULL) - return NULL; + return CharName(); if (p->req_id != 0) - return NULL; + return CharName(); return p->nick; } @@ -958,40 +966,21 @@ dumb_ptr<map_session_data> map_get_prev_session(dumb_ptr<map_session_data> d) * return map_session_data pointer or NULL *------------------------------------------ */ -dumb_ptr<map_session_data> map_nick2sd(const char *nick) +dumb_ptr<map_session_data> map_nick2sd(CharName nick) { - int i, quantity = 0, nicklen; - dumb_ptr<map_session_data> sd = NULL; - - if (nick == NULL) - return NULL; - - nicklen = strlen(nick); - - for (i = 0; i < fd_max; i++) + for (int i = 0; i < fd_max; i++) { if (!session[i]) continue; map_session_data *pl_sd = static_cast<map_session_data *>(session[i]->session_data.get()); if (pl_sd && pl_sd->state.auth) { - // Without case sensitive check (increase the number of similar character names found) - if (strncasecmp(pl_sd->status.name, nick, nicklen) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(pl_sd->status.name, nick) == 0) + if (pl_sd->status.name == nick) return dumb_ptr<map_session_data>(pl_sd); - quantity++; - sd = dumb_ptr<map_session_data>(pl_sd); } } } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return sd; - - // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found return NULL; } @@ -1077,7 +1066,7 @@ void map_removenpc(void) * map名からmap番号へ変換 *------------------------------------------ */ -map_local *map_mapname2mapid(const char *name) +map_local *map_mapname2mapid(MapName name) { map_abstract *md = maps_db.get(name); if (md == NULL || md->gat == NULL) @@ -1089,7 +1078,7 @@ map_local *map_mapname2mapid(const char *name) * 他鯖map名からip,port変換 *------------------------------------------ */ -int map_mapname2ipport(const char *name, struct in_addr *ip, int *port) +int map_mapname2ipport(MapName name, struct in_addr *ip, int *port) { map_abstract *md = maps_db.get(name); if (md == NULL || md->gat) @@ -1198,14 +1187,14 @@ void map_setcell(map_local *m, int x, int y, MapCell t) * 他鯖管理のマップをdbに追加 *------------------------------------------ */ -int map_setipport(const char *name, struct in_addr ip, int port) +int map_setipport(MapName name, struct in_addr ip, int port) { map_abstract *md = maps_db.get(name); if (md == NULL) { // not exist -> add new data auto mdos = make_unique<map_remote>(); - strzcpy(mdos->name_, name, 16); + mdos->name_ = name; mdos->gat = NULL; mdos->ip = ip; mdos->port = port; @@ -1239,7 +1228,7 @@ int map_setipport(const char *name, struct in_addr ip, int port) *------------------------------------------ */ static -bool map_readmap(map_local *m, size_t num, const std::string& fn) +bool map_readmap(map_local *m, size_t num, MapName fn) { // read & convert fn std::vector<uint8_t> gat_v = grfio_reads(fn); @@ -1251,7 +1240,7 @@ bool map_readmap(map_local *m, size_t num, const std::string& fn) int ys = m->ys = gat_v[2] | gat_v[3] << 8; PRINTF("\rLoading Maps [%zu/%zu]: %-30s (%i, %i)", num, maps_db.size(), - std::string(fn.begin(), fn.end()), xs, ys); + fn, xs, ys); fflush(stdout); assert (s == xs * ys); @@ -1284,7 +1273,6 @@ int map_readallmap(void) for (auto& mit : maps_db) { - assert (strstr(mit.second->name_, ".gat") != NULL); { { map_local *ml = static_cast<map_local *>(mit.second.get()); @@ -1316,7 +1304,7 @@ int map_readallmap(void) *------------------------------------------ */ static -void map_addmap(const std::string& mapname) +void map_addmap(MapName mapname) { if (mapname == "clear") { @@ -1325,9 +1313,10 @@ void map_addmap(const std::string& mapname) } auto newmap = make_unique<map_local>(); - strzcpy(newmap->name_, mapname.c_str(), 16); - // novice challenge: figure out why this is necessary, and why it works - const char *name = newmap->name_; + newmap->name_ = mapname; + // novice challenge: figure out why this is necessary, + // and why the previous version worked + MapName name = newmap->name_; maps_db.put(name, std::move(newmap)); } @@ -1335,7 +1324,7 @@ void map_addmap(const std::string& mapname) * 読み込むmapを削除する *------------------------------------------ */ -void map_delmap(const std::string& mapname) +void map_delmap(MapName mapname) { if (mapname == "all") { @@ -1351,7 +1340,7 @@ constexpr int LOGFILE_SECONDS_PER_CHUNK_SHIFT = 10; static FILE *map_logfile = NULL; static -std::string map_logfile_name; +FString map_logfile_name; static long map_logfile_index; @@ -1360,7 +1349,7 @@ void map_close_logfile(void) { if (map_logfile) { - std::string filename = STRPRINTF("%s.%ld", map_logfile_name, map_logfile_index); + FString filename = STRPRINTF("%s.%ld", map_logfile_name, map_logfile_index); const char *args[] = { "gzip", @@ -1386,7 +1375,7 @@ void map_start_logfile(long index) { map_logfile_index = index; - std::string filename_buf = STRPRINTF( + FString filename_buf = STRPRINTF( "%s.%ld", map_logfile_name, map_logfile_index); @@ -1396,7 +1385,7 @@ void map_start_logfile(long index) } static -void map_set_logfile(std::string filename) +void map_set_logfile(FString filename) { struct timeval tv; @@ -1408,7 +1397,7 @@ void map_set_logfile(std::string filename) MAP_LOG("log-start v5"); } -void map_log(const_string line) +void map_log(XString line) { if (!map_logfile) return; @@ -1430,49 +1419,51 @@ void map_log(const_string line) *------------------------------------------ */ static -int map_config_read(const char *cfgName) +int map_config_read(ZString cfgName) { struct hostent *h = NULL; - std::ifstream in(cfgName); + std::ifstream in(cfgName.c_str()); if (!in.is_open()) { PRINTF("Map configuration file not found at: %s\n", cfgName); exit(1); } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string w1, w2; + SString w1; + TString w2; if (!split_key_value(line, &w1, &w2)) continue; if (w1 == "userid") { - chrif_setuserid(w2.c_str()); + AccountName name = stringish<AccountName>(w2); + chrif_setuserid(name); } else if (w1 == "passwd") { - chrif_setpasswd(w2.c_str()); + AccountPass pass = stringish<AccountPass>(w2); + chrif_setpasswd(pass); } else if (w1 == "char_ip") { h = gethostbyname(w2.c_str()); + IP_String w2ip; if (h != NULL) { - PRINTF("Character server IP address : %s -> %d.%d.%d.%d\n", - w2, - static_cast<uint8_t>(h->h_addr[0]), - static_cast<uint8_t>(h->h_addr[1]), - static_cast<uint8_t>(h->h_addr[2]), - static_cast<uint8_t>(h->h_addr[3])); - SPRINTF(w2, "%d.%d.%d.%d", - static_cast<uint8_t>(h->h_addr[0]), - static_cast<uint8_t>(h->h_addr[1]), - static_cast<uint8_t>(h->h_addr[2]), - static_cast<uint8_t>(h->h_addr[3])); + SNPRINTF(w2ip, 16, "%d.%d.%d.%d", + static_cast<uint8_t>(h->h_addr[0]), + static_cast<uint8_t>(h->h_addr[1]), + static_cast<uint8_t>(h->h_addr[2]), + static_cast<uint8_t>(h->h_addr[3])); + PRINTF("Character server IP address : %s -> %s\n", + w2, w2ip); } - chrif_setip(w2.c_str()); + else + w2ip = stringish<IP_String>(w2); + chrif_setip(w2ip); } else if (w1 == "char_port") { @@ -1481,20 +1472,20 @@ int map_config_read(const char *cfgName) else if (w1 == "map_ip") { h = gethostbyname(w2.c_str()); + IP_String w2ip; if (h != NULL) { - PRINTF("Map server IP address : %s -> %d.%d.%d.%d\n", w2, - static_cast<uint8_t>(h->h_addr[0]), - static_cast<uint8_t>(h->h_addr[1]), - static_cast<uint8_t>(h->h_addr[2]), - static_cast<uint8_t>(h->h_addr[3])); - SPRINTF(w2, "%d.%d.%d.%d", + SNPRINTF(w2ip, 16, "%d.%d.%d.%d", static_cast<uint8_t>(h->h_addr[0]), static_cast<uint8_t>(h->h_addr[1]), static_cast<uint8_t>(h->h_addr[2]), static_cast<uint8_t>(h->h_addr[3])); + PRINTF("Map server IP address : %s -> %s\n", + w2, w2ip); } - clif_setip(w2.c_str()); + else + w2ip = stringish<IP_String>(w2); + clif_setip(w2ip); } else if (w1 == "map_port") { @@ -1502,19 +1493,21 @@ int map_config_read(const char *cfgName) } else if (w1 == "map") { - map_addmap(w2.c_str()); + MapName name = VString<15>(w2); + map_addmap(name); } else if (w1 == "delmap") { - map_delmap(w2.c_str()); + MapName name = VString<15>(w2); + map_delmap(name); } else if (w1 == "npc") { - npc_addsrcfile(w2.c_str()); + npc_addsrcfile(w2); } else if (w1 == "delnpc") { - npc_delsrcfile(w2.c_str()); + npc_delsrcfile(w2); } else if (w1 == "autosave_time") { @@ -1524,15 +1517,15 @@ int map_config_read(const char *cfgName) } else if (w1 == "motd_txt") { - strzcpy(motd_txt, w2.c_str(), sizeof(motd_txt)); + motd_txt = w2; } else if (w1 == "help_txt") { - strzcpy(help_txt, w2.c_str(), sizeof(help_txt)); + help_txt = w2; } else if (w1 == "mapreg_txt") { - strzcpy(mapreg_txt, w2.c_str(), sizeof(mapreg_txt)); + mapreg_txt = w2; } else if (w1 == "gm_log") { @@ -1540,11 +1533,11 @@ int map_config_read(const char *cfgName) } else if (w1 == "log_file") { - map_set_logfile(w2.c_str()); + map_set_logfile(w2); } else if (w1 == "import") { - map_config_read(w2.c_str()); + map_config_read(w2); } } @@ -1632,26 +1625,26 @@ int compare_item(struct item *a, struct item *b) * Map-Server Init and Command-line Arguments [Valaris] *------------------------------------------------------ */ -int do_init(int argc, char *argv[]) +int do_init(int argc, ZString *argv) { int i; - const char *MAP_CONF_NAME = "conf/map_athena.conf"; - const char *BATTLE_CONF_FILENAME = "conf/battle_athena.conf"; - const char *ATCOMMAND_CONF_FILENAME = "conf/atcommand_athena.conf"; + ZString MAP_CONF_NAME = "conf/map_athena.conf"; + ZString BATTLE_CONF_FILENAME = "conf/battle_athena.conf"; + ZString ATCOMMAND_CONF_FILENAME = "conf/atcommand_athena.conf"; for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--h") == 0 - || strcmp(argv[i], "--?") == 0 || strcmp(argv[i], "/?") == 0) + if (argv[i] == "--help" || argv[i] == "-h" + || argv[i] == "-?" || argv[i] == "/?") map_helpscreen(); - else if (strcmp(argv[i], "--map_config") == 0) - MAP_CONF_NAME = argv[i + 1]; - else if (strcmp(argv[i], "--battle_config") == 0) - BATTLE_CONF_FILENAME = argv[i + 1]; - else if (strcmp(argv[i], "--atcommand_config") == 0) - ATCOMMAND_CONF_FILENAME = argv[i + 1]; + else if (argv[i] == "--map_config") + MAP_CONF_NAME = argv[++i]; + else if (argv[i] == "--battle_config") + BATTLE_CONF_FILENAME = argv[++i]; + else if (argv[i] == "--atcommand_config") + ATCOMMAND_CONF_FILENAME = argv[++i]; } map_config_read(MAP_CONF_NAME); diff --git a/src/map/map.hpp b/src/map/map.hpp index f0d0310..87bf1f9 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -8,9 +8,11 @@ #include <functional> #include <list> +#include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/matrix.hpp" #include "../common/socket.hpp" +#include "../common/strings.hpp" #include "../common/timer.t.hpp" #include "battle.t.hpp" @@ -33,6 +35,38 @@ constexpr int MAX_DROP_PER_MAP = 48; constexpr interval_t DEFAULT_AUTOSAVE_INTERVAL = std::chrono::minutes(1); +// formerly VString<49>, as name::label +struct NpcEvent +{ + NpcName npc; + ScriptLabel label; + + explicit operator bool() + { + return npc || label; + } + bool operator !() + { + return !bool(*this); + } + + friend bool operator == (const NpcEvent& l, const NpcEvent& r) + { + return l.npc == r.npc && l.label == r.label; + } + + friend bool operator < (const NpcEvent& l, const NpcEvent& r) + { + return l.npc < r.npc || (l.npc == r.npc && l.label < r.label); + } + + friend VString<49> convert_for_printf(NpcEvent ev) + { + return STRNPRINTF(50, "%s::%s", ev.npc, ev.label); + } +}; +bool extract(XString str, NpcEvent *ev); + struct map_session_data; struct npc_data; struct mob_data; @@ -71,16 +105,6 @@ struct walkpath_data unsigned char path_len, path_pos, path_half; DIR path[MAX_WALKPATH]; }; -struct script_reg -{ - int index; - int data; -}; -struct script_regstr -{ - int index; - char data[256]; -}; struct status_change { Timer timer; @@ -92,7 +116,6 @@ struct invocation; struct npc_data; struct item_data; -struct square; struct quick_regeneration { // [Fate] @@ -141,7 +164,7 @@ struct map_session_data : block_list, SessionData earray<short, EQUIP, EQUIP::COUNT> equip_index; int weight, max_weight; int cart_weight, cart_max_weight, cart_num, cart_max_num; - char mapname_[16]; + MapName mapname_; int fd, new_fd; short to_x, to_y; interval_t speed; @@ -161,7 +184,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; - std::string npc_str; + FString npc_str; struct { unsigned storage:1; @@ -236,7 +259,7 @@ struct map_session_data : block_list, SessionData DMap<SIR, int> regm; // can't be DMap because we want predictable .c_str()s // This could change once FString ensures CoW. - Map<SIR, std::string> regstrm; + Map<SIR, FString> regstrm; earray<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; short sc_count; @@ -252,15 +275,13 @@ struct map_session_data : block_list, SessionData int partyspy; // [Syrus22] - char message[80]; - int catch_target_class; int pvp_point, pvp_rank; Timer pvp_timer; int pvp_lastusers; - std::list<std::string> eventqueuel; + std::list<NpcEvent> eventqueuel; Timer eventtimer[MAX_EVENTTIMER]; struct @@ -272,7 +293,7 @@ struct map_session_data : block_list, SessionData TimeT chat_repeat_reset_due; int chat_lines_in; int chat_total_repeats; - char chat_lastmsg[513]; + FString chat_lastmsg; tick_t flood_rates[0x220]; TimeT packet_flood_reset_due; @@ -288,7 +309,7 @@ struct npc_timerevent_list }; struct npc_label_list { - char name[24]; + ScriptLabel name; int pos; }; struct npc_item_list @@ -307,15 +328,14 @@ struct npc_data : block_list short npc_class; DIR dir; interval_t speed; - char name[24]; - char exname[24]; + NpcName name; Opt1 opt1; Opt2 opt2; Opt3 opt3; Option option; short flag; - std::list<std::string> eventqueuel; + std::list<FString> eventqueuel; Timer eventtimer[MAX_EVENTTIMER]; short arenaflag; @@ -370,14 +390,14 @@ public: { short xs, ys; short x, y; - char name[16]; + MapName name; } warp; }; class npc_data_message : public npc_data { public: - std::string message; + FString message; }; constexpr int MOB_XP_BONUS_BASE = 1024; @@ -395,7 +415,7 @@ struct mob_data : block_list short x0, y0, xs, ys; interval_t delay1, delay2; } spawn; - char name[24]; + MobName name; struct { MS state; @@ -448,7 +468,7 @@ struct mob_data : block_list LevelElement def_ele; int master_id, master_dist; int exclusion_src, exclusion_party; - char npc_event[50]; + NpcEvent npc_event; // [Fate] mob-specific stats earray<unsigned short, mob_stat, mob_stat::LAST> stats; short size; @@ -461,14 +481,14 @@ struct BlockLists struct map_abstract { - char name_[16]; + MapName name_; // gat is NULL for map_remote and non-NULL or map_local std::unique_ptr<MapCell[]> gat; virtual ~map_abstract() {} }; extern -UPMap<std::string, map_abstract> maps_db; +UPMap<MapName, map_abstract> maps_db; struct map_local : map_abstract { @@ -537,10 +557,10 @@ struct flooritem_data : block_list extern interval_t autosave_interval; extern int save_settings; -extern char motd_txt[]; -extern char help_txt[]; +extern FString motd_txt; +extern FString help_txt; -extern char wisp_server_name[]; +extern CharName wisp_server_name; // 鯖全体情報 void map_setusers(int); @@ -587,13 +607,13 @@ void map_quit(dumb_ptr<map_session_data>); // npc int map_addnpc(map_local *, dumb_ptr<npc_data>); -void map_log(const_string line); +void map_log(XString line); #define MAP_LOG(format, ...) \ - map_log(static_cast<const std::string&>(STRPRINTF(format, ## __VA_ARGS__))) + map_log(STRPRINTF(format, ## __VA_ARGS__)) #define MAP_LOG_PC(sd, fmt, ...) \ MAP_LOG("PC%d %s:%d,%d " fmt, \ - sd->status.char_id, (sd->bl_m ? sd->bl_m->name_ : "undefined.gat"), sd->bl_x, sd->bl_y, ## __VA_ARGS__) + sd->status.char_id, (sd->bl_m ? sd->bl_m->name_ : stringish<MapName>("undefined.gat")), sd->bl_x, sd->bl_y, ## __VA_ARGS__) // 床アイテム関連 void map_clearflooritem_timer(TimerData *, tick_t, int); @@ -614,8 +634,8 @@ int map_addflooritem(struct item *, int, // キャラid=>キャラ名 変換関連 extern DMap<int, dumb_ptr<block_list>> id_db; -void map_addchariddb(int charid, const char *name); -char *map_charid2nick(int); +void map_addchariddb(int charid, CharName name); +CharName map_charid2nick(int); dumb_ptr<map_session_data> map_id2sd(int); dumb_ptr<block_list> map_id2bl(int); @@ -683,14 +703,14 @@ dumb_ptr<invocation> map_id_is_spell(int id) } -map_local *map_mapname2mapid(const char *); -int map_mapname2ipport(const char *, struct in_addr *, int *); -int map_setipport(const char *name, struct in_addr ip, int port); +map_local *map_mapname2mapid(MapName); +int map_mapname2ipport(MapName, struct in_addr *, int *); +int map_setipport(MapName name, struct in_addr ip, int port); void map_addiddb(dumb_ptr<block_list>); void map_deliddb(dumb_ptr<block_list> bl); void map_addnickdb(dumb_ptr<map_session_data>); int map_scriptcont(dumb_ptr<map_session_data> sd, int id); /* Continues a script either on a spell or on an NPC */ -dumb_ptr<map_session_data> map_nick2sd(const char *); +dumb_ptr<map_session_data> map_nick2sd(CharName); int compare_item(struct item *a, struct item *b); dumb_ptr<map_session_data> map_get_first_session(void); diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index d7b86ec..19f80c3 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -555,4 +555,9 @@ ENUM_BITWISE_OPERATORS(MapCell) } using e::MapCell; +struct MobName : VString<23> {}; +struct NpcName : VString<23> {}; +struct ScriptLabel : VString<23> {}; +struct ItemName : VString<23> {}; + #endif // MAP_T_HPP diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 345f5a6..a2122d6 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -7,10 +7,13 @@ #include <cstring> #include <algorithm> +#include <fstream> #include "../common/cxxstdio.hpp" -#include "../common/random.hpp" +#include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -53,14 +56,13 @@ int mobskill_use_id(dumb_ptr<mob_data> md, dumb_ptr<block_list> target, * Mob is searched with a name. *------------------------------------------ */ -int mobdb_searchname(const char *str) +int mobdb_searchname(MobName str) { int i; for (i = 0; i < sizeof(mob_db) / sizeof(mob_db[0]); i++) { - if (strcasecmp(mob_db[i].name, str) == 0 - || strcmp(mob_db[i].jname, str) == 0) + if (mob_db[i].name == str || mob_db[i].jname == str) return i; } @@ -88,16 +90,16 @@ void mob_init(dumb_ptr<mob_data> md); *------------------------------------------ */ static -void mob_spawn_dataset(dumb_ptr<mob_data> md, const char *mobname, int mob_class) +void mob_spawn_dataset(dumb_ptr<mob_data> md, MobName mobname, int mob_class) { nullpo_retv(md); - if (strcmp(mobname, "--en--") == 0) - strzcpy(md->name, mob_db[mob_class].name, 24); - else if (strcmp(mobname, "--ja--") == 0) - strzcpy(md->name, mob_db[mob_class].jname, 24); + if (mobname == ENGLISH_NAME) + md->name = mob_db[mob_class].name; + else if (mobname == JAPANESE_NAME) + md->name = mob_db[mob_class].jname; else - strzcpy(md->name, mobname, 24); + md->name = mobname; md->bl_prev = NULL; md->bl_next = NULL; @@ -362,15 +364,16 @@ void mob_init(dumb_ptr<mob_data> md) * The MOB appearance for one time (for scripts) *------------------------------------------ */ -int mob_once_spawn(dumb_ptr<map_session_data> sd, const char *mapname, - int x, int y, const char *mobname, int mob_class, int amount, - const char *event) +int mob_once_spawn(dumb_ptr<map_session_data> sd, + MapName mapname, int x, int y, + MobName mobname, int mob_class, int amount, + NpcEvent event) { dumb_ptr<mob_data> md = NULL; map_local *m; int count, r = mob_class; - if (sd && strcmp(mapname, "this") == 0) + if (sd && mapname == MOB_THIS_MAP) m = sd->bl_m; else m = map_mapname2mapid(mapname); @@ -410,7 +413,7 @@ int mob_once_spawn(dumb_ptr<map_session_data> sd, const char *mapname, md->spawn.delay1 = static_cast<interval_t>(-1); // Only once is a flag. md->spawn.delay2 = static_cast<interval_t>(-1); // Only once is a flag. - strzcpy(md->npc_event, event, 50); + md->npc_event = event; md->bl_type = BL::MOB; map_addiddb(md); @@ -423,15 +426,15 @@ int mob_once_spawn(dumb_ptr<map_session_data> sd, const char *mapname, * The MOB appearance for one time (& area specification for scripts) *------------------------------------------ */ -int mob_once_spawn_area(dumb_ptr<map_session_data> sd, const char *mapname, - int x0, int y0, int x1, int y1, - const char *mobname, int mob_class, int amount, - const char *event) +int mob_once_spawn_area(dumb_ptr<map_session_data> sd, + MapName mapname, int x0, int y0, int x1, int y1, + MobName mobname, int mob_class, int amount, + NpcEvent event) { int x, y, i, max, lx = -1, ly = -1, id = 0; map_local *m; - if (strcmp(mapname, "this") == 0) + if (mapname == MOB_THIS_MAP) m = sd->bl_m; else m = map_mapname2mapid(mapname); @@ -2624,7 +2627,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage, } // [MouseJstr] // SCRIPT実行 - if (md->npc_event[0]) + if (md->npc_event) { if (sd == NULL) { @@ -2877,7 +2880,7 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag) y = by; } - mob_spawn_dataset(md, "--ja--", mob_class); + mob_spawn_dataset(md, JAPANESE_NAME, mob_class); md->bl_prev = NULL; md->bl_next = NULL; md->bl_m = m; @@ -2893,7 +2896,7 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value, int amount, int flag) md->spawn.delay1 = static_cast<interval_t>(-1); // 一度のみフラグ md->spawn.delay2 = static_cast<interval_t>(-1); // 一度のみフラグ - strzcpy(md->npc_event, "", 50); + md->npc_event = NpcEvent(); md->bl_type = BL::MOB; map_addiddb(md); mob_spawn(md->bl_id); @@ -3341,8 +3344,8 @@ int mob_makedummymobdb(int mob_class) { int i; - sprintf(mob_db[mob_class].name, "mob%d", mob_class); - sprintf(mob_db[mob_class].jname, "mob%d", mob_class); + SNPRINTF(mob_db[mob_class].name, 24, "mob%d", mob_class); + SNPRINTF(mob_db[mob_class].jname, 24, "mob%d", mob_class); mob_db[mob_class].lv = 1; mob_db[mob_class].max_hp = 1000; mob_db[mob_class].max_sp = 1; @@ -3377,6 +3380,18 @@ int mob_makedummymobdb(int mob_class) return 0; } +static +bool extract(XString str, LevelElement *le) +{ + int tmp; + if (extract(str, &tmp)) + { + le->unpack(tmp); + return true; + } + return false; +} + /*========================================== * db/mob_db.txt reading *------------------------------------------ @@ -3384,57 +3399,95 @@ int mob_makedummymobdb(int mob_class) static int mob_readdb(void) { - FILE *fp; - char line[1024]; - const char *filename[] = { "db/mob_db.txt", "db/mob_db2.txt" }; + const char *filename = "db/mob_db.txt"; for (mob_db_& e : mob_db) e = mob_db_{}; - for (int j = 0; j < 2; j++) { - - fp = fopen_(filename[j], "r"); - if (fp == NULL) + std::ifstream in(filename); + if (!in.is_open()) { - if (j > 0) - continue; return -1; } - while (fgets(line, 1020, fp)) + FString line; + while (io::getline(in, line)) { int mob_class; - char *str[57], *p, *np; - if (line[0] == '/' && line[1] == '/') + if (line.startswith("//")) continue; + struct mob_db_ mdbv {}; + + XString ignore; + + extract(line, record<','>( + &mob_class, + lstripping(&mdbv.name), + lstripping(&mdbv.jname), + lstripping(&mdbv.lv), + lstripping(&mdbv.max_hp), + lstripping(&mdbv.max_sp), + lstripping(&mdbv.base_exp), + lstripping(&mdbv.job_exp), + lstripping(&mdbv.range), + lstripping(&mdbv.atk1), + lstripping(&mdbv.atk2), + lstripping(&mdbv.def), + lstripping(&mdbv.mdef), + lstripping(&mdbv.attrs[ATTR::STR]), + lstripping(&mdbv.attrs[ATTR::AGI]), + lstripping(&mdbv.attrs[ATTR::VIT]), + lstripping(&mdbv.attrs[ATTR::INT]), + lstripping(&mdbv.attrs[ATTR::DEX]), + lstripping(&mdbv.attrs[ATTR::LUK]), + lstripping(&mdbv.range2), + lstripping(&mdbv.range3), + lstripping(&mdbv.size), + lstripping(&mdbv.race), + lstripping(&mdbv.element), + lstripping(&mdbv.mode), + lstripping(&mdbv.speed), + lstripping(&mdbv.adelay), + lstripping(&mdbv.amotion), + lstripping(&mdbv.dmotion), + lstripping(&mdbv.dropitem[0].nameid), + lstripping(&mdbv.dropitem[0].p.num), + lstripping(&mdbv.dropitem[1].nameid), + lstripping(&mdbv.dropitem[1].p.num), + lstripping(&mdbv.dropitem[2].nameid), + lstripping(&mdbv.dropitem[2].p.num), + lstripping(&mdbv.dropitem[3].nameid), + lstripping(&mdbv.dropitem[3].p.num), + lstripping(&mdbv.dropitem[4].nameid), + lstripping(&mdbv.dropitem[4].p.num), + lstripping(&mdbv.dropitem[5].nameid), + lstripping(&mdbv.dropitem[5].p.num), + lstripping(&mdbv.dropitem[6].nameid), + lstripping(&mdbv.dropitem[6].p.num), + lstripping(&mdbv.dropitem[7].nameid), + lstripping(&mdbv.dropitem[7].p.num), + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + &ignore, + lstripping(&mdbv.mutations_nr), + lstripping(&mdbv.mutation_power) + ) + ); - p = line; - for (int i = 0; i < 57; i++) - { - while (*p == '\t' || *p == ' ') - p++; - if ((np = strchr(p, ',')) != NULL) - { - str[i] = p; - *np = 0; - p = np + 1; - } - else - str[i] = p; - } - - mob_class = atoi(str[0]); if (mob_class <= 1000 || mob_class > 2000) continue; - strzcpy(mob_db[mob_class].name, str[1], 24); - strzcpy(mob_db[mob_class].jname, str[2], 24); - mob_db[mob_class].lv = atoi(str[3]); - mob_db[mob_class].max_hp = atoi(str[4]); - mob_db[mob_class].max_sp = atoi(str[5]); + // TODO move this lower + mob_db[mob_class] = std::move(mdbv); - mob_db[mob_class].base_exp = atoi(str[6]); if (mob_db[mob_class].base_exp < 0) mob_db[mob_class].base_exp = 0; else if (mob_db[mob_class].base_exp > 0 @@ -3444,9 +3497,8 @@ int mob_readdb(void) battle_config.base_exp_rate / 100 < 0)) mob_db[mob_class].base_exp = 1000000000; else - mob_db[mob_class].base_exp *= battle_config.base_exp_rate / 100; + mob_db[mob_class].base_exp = mob_db[mob_class].base_exp * battle_config.base_exp_rate / 100; - mob_db[mob_class].job_exp = atoi(str[7]); if (mob_db[mob_class].job_exp < 0) mob_db[mob_class].job_exp = 0; else if (mob_db[mob_class].job_exp > 0 @@ -3456,40 +3508,16 @@ int mob_readdb(void) battle_config.job_exp_rate / 100 < 0)) mob_db[mob_class].job_exp = 1000000000; else - mob_db[mob_class].job_exp *= battle_config.job_exp_rate / 100; - - mob_db[mob_class].range = atoi(str[8]); - mob_db[mob_class].atk1 = atoi(str[9]); - mob_db[mob_class].atk2 = atoi(str[10]); - mob_db[mob_class].def = atoi(str[11]); - mob_db[mob_class].mdef = atoi(str[12]); - mob_db[mob_class].attrs[ATTR::STR] = atoi(str[13]); - mob_db[mob_class].attrs[ATTR::AGI] = atoi(str[14]); - mob_db[mob_class].attrs[ATTR::VIT] = atoi(str[15]); - mob_db[mob_class].attrs[ATTR::INT] = atoi(str[16]); - mob_db[mob_class].attrs[ATTR::DEX] = atoi(str[17]); - mob_db[mob_class].attrs[ATTR::LUK] = atoi(str[18]); - mob_db[mob_class].range2 = atoi(str[19]); - mob_db[mob_class].range3 = atoi(str[20]); - mob_db[mob_class].size = atoi(str[21]); // always 1 - mob_db[mob_class].race = static_cast<Race>(atoi(str[22])); - mob_db[mob_class].element = LevelElement::unpack(atoi(str[23])); - mob_db[mob_class].mode = static_cast<MobMode>(atoi(str[24])); - mob_db[mob_class].speed = atoi(str[25]); - mob_db[mob_class].adelay = atoi(str[26]); - mob_db[mob_class].amotion = atoi(str[27]); - mob_db[mob_class].dmotion = atoi(str[28]); + mob_db[mob_class].job_exp = mob_db[mob_class].job_exp * battle_config.job_exp_rate / 100; for (int i = 0; i < 8; i++) { - mob_db[mob_class].dropitem[i].nameid = atoi(str[29 + i * 2]); - int rate = atoi(str[30 + i * 2]); + int rate = mob_db[mob_class].dropitem[i].p.num; if (rate < 1) rate = 1; if (rate > 10000) rate = 10000; mob_db[mob_class].dropitem[i].p.num = rate; } - mob_db[mob_class].mutations_nr = atoi(str[55]); - mob_db[mob_class].mutation_power = atoi(str[56]); + mob_db[mob_class].skills.clear(); @@ -3506,22 +3534,14 @@ int mob_readdb(void) if (mob_db[mob_class].base_exp == 0) mob_db[mob_class].base_exp = mob_gen_exp(&mob_db[mob_class]); } - fclose_(fp); - PRINTF("read %s done\n", filename[j]); + PRINTF("read %s done\n", filename); } return 0; } -/*========================================== - * db/mob_skill_db.txt reading - *------------------------------------------ - */ -static -int mob_readskilldb(void) +template<> +bool extract<MobSkillCondition, void, void>(XString str, MobSkillCondition *msc) { - FILE *fp; - char line[1024]; - const struct { char str[32]; @@ -3534,6 +3554,18 @@ int mob_readskilldb(void) {"slavelt", MobSkillCondition::MSC_SLAVELT}, {"slavele", MobSkillCondition::MSC_SLAVELE}, }; + for (auto& pair : cond1) + if (str == pair.str) + { + *msc = pair.id; + return true; + } + return false; +} + +template<> +bool extract<MobSkillState, void, void>(XString str, MobSkillState *mss) +{ const struct { char str[32]; @@ -3545,6 +3577,18 @@ int mob_readskilldb(void) {"walk", MobSkillState::MSS_WALK}, {"attack", MobSkillState::MSS_ATTACK}, }; + for (auto& pair : state) + if (str == pair.str) + { + *mss = pair.id; + return true; + } + return false; +} + +template<> +bool extract<MobSkillTarget, void, void>(XString str, MobSkillTarget *mst) +{ const struct { char str[32]; @@ -3554,90 +3598,93 @@ int mob_readskilldb(void) {"target", MobSkillTarget::MST_TARGET}, {"self", MobSkillTarget::MST_SELF}, }; + for (auto& pair : target) + if (str == pair.str) + { + *mst = pair.id; + return true; + } + return false; +} - int x; - const char *filename[] = { "db/mob_skill_db.txt", "db/mob_skill_db2.txt" }; +/*========================================== + * db/mob_skill_db.txt reading + *------------------------------------------ + */ +static +int mob_readskilldb(void) +{ + const char *filename = "db/mob_skill_db.txt"; - for (x = 0; x < 2; x++) { - - fp = fopen_(filename[x], "r"); - if (fp == NULL) + std::ifstream in(filename); + if (!in.is_open()) { - if (x == 0) - PRINTF("can't read %s\n", filename[x]); - continue; + PRINTF("can't read %s\n", filename); + return 0; } - while (fgets(line, 1020, fp)) + FString line; + while (io::getline(in, line)) { int mob_id; - int j = 0; - - if (line[0] == '/' && line[1] == '/') - continue; - char *sp[20] {}; - char *p; - int i; - for (i = 0, p = line; i < 18 && p; i++) - { - sp[i] = p; - p = strchr(p, ','); - if (p != NULL) - *p++ = 0; - } - if ((mob_id = atoi(sp[0])) <= 0) + if (line.startswith("//")) continue; - if (strcmp(sp[1], "clear") == 0) + XString blah; + if (extract(line, record<','>(&mob_id, &blah)) && mob_id > 0 && blah == "clear") { mob_db[mob_id].skills.clear(); continue; } - mob_db[mob_id].skills.push_back(mob_skill{}); - struct mob_skill *ms = &mob_db[mob_id].skills.back(); - - ms->state = static_cast<MobSkillState>(atoi(sp[2])); - for (j = 0; j < sizeof(state) / sizeof(state[0]); j++) - { - if (strcmp(sp[2], state[j].str) == 0) - ms->state = state[j].id; - } - ms->skill_id = SkillID(atoi(sp[3])); - ms->skill_lv = atoi(sp[4]); - - ms->permillage = atoi(sp[5]); - ms->casttime = static_cast<interval_t>(atoi(sp[6])); - ms->delay = static_cast<interval_t>(atoi(sp[7])); - ms->cancel = atoi(sp[8]); - if (strcmp(sp[8], "yes") == 0) - ms->cancel = 1; - ms->target = static_cast<MobSkillTarget>(atoi(sp[9])); - for (j = 0; j < sizeof(target) / sizeof(target[0]); j++) - { - if (strcmp(sp[9], target[j].str) == 0) - ms->target = target[j].id; - } - ms->cond1 = MobSkillCondition::ANY; - for (j = 0; j < sizeof(cond1) / sizeof(cond1[0]); j++) - { - if (strcmp(sp[10], cond1[j].str) == 0) - ms->cond1 = cond1[j].id; - } - ms->cond2i = atoi(sp[11]); - ms->val[0] = atoi(sp[12]); - ms->val[1] = atoi(sp[13]); - ms->val[2] = atoi(sp[14]); - ms->val[3] = atoi(sp[15]); - ms->val[4] = atoi(sp[16]); - if (sp[17] != NULL && strlen(sp[17]) > 2) - ms->emotion = atoi(sp[17]); + struct mob_skill msv {}; + msv.emotion = -1; + int casttime, delay; + XString cancellable; + + if (!extract( + line, + record<',', 17>( + &mob_id, + &blah, + &msv.state, + &msv.skill_id, + &msv.skill_lv, + &msv.permillage, + &casttime, + &delay, + &cancellable, + &msv.target, + &msv.cond1, + &msv.cond2i, + &msv.val[0], + &msv.val[1], + &msv.val[2], + &msv.val[3], + &msv.val[4], + + &msv.emotion + ) + ) + ) + continue; + if (cancellable == "yes") + msv.cancel = true; + else if (cancellable == "no") + msv.cancel = false; else - ms->emotion = -1; + continue; + + msv.casttime = std::chrono::milliseconds(casttime); + msv.delay = std::chrono::milliseconds(delay); + + if (mob_id <= 0) + continue; + + mob_db[mob_id].skills.push_back(std::move(msv)); } - fclose_(fp); - PRINTF("read %s done\n", filename[x]); + PRINTF("read %s done\n", filename); } return 0; } diff --git a/src/map/mob.hpp b/src/map/mob.hpp index 66dbc53..bf53798 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -11,6 +11,10 @@ #include "map.hpp" #include "skill.t.hpp" +#define ENGLISH_NAME stringish<MobName>("--en--") +#define JAPANESE_NAME stringish<MobName>("--ja--") +#define MOB_THIS_MAP stringish<MapName>("this") + struct mob_skill { MobSkillState state; @@ -18,7 +22,7 @@ struct mob_skill short skill_lv; short permillage; interval_t casttime, delay; - short cancel; + bool cancel; MobSkillCondition cond1; int cond2i; MobSkillTarget target; @@ -28,7 +32,7 @@ struct mob_skill struct mob_db_ { - char name[24], jname[24]; + MobName name, jname; int lv; int max_hp, max_sp; int base_exp, job_exp; @@ -55,14 +59,16 @@ struct mob_db_ }; extern struct mob_db_ mob_db[]; -int mobdb_searchname(const char *str); +int mobdb_searchname(MobName str); int mobdb_checkid(const int id); int mob_once_spawn(dumb_ptr<map_session_data> sd, - const char *mapname, int x, int y, - const char *mobname, int class_, int amount, const char *event); + MapName mapname, int x, int y, + MobName mobname, int class_, int amount, + NpcEvent event); int mob_once_spawn_area(dumb_ptr<map_session_data> sd, - const char *mapname, int x0, int y0, int x1, int y1, - const char *mobname, int class_, int amount, const char *event); + MapName mapname, int x0, int y0, int x1, int y1, + MobName mobname, int class_, int amount, + NpcEvent event); int mob_target(dumb_ptr<mob_data> md, dumb_ptr<block_list> bl, int dist); int mob_stop_walking(dumb_ptr<mob_data> md, int type); diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 68b5ad7..41f0966 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -9,6 +9,7 @@ #include "../common/cxxstdio.hpp" #include "../common/db.hpp" +#include "../common/extract.hpp" #include "../common/nullpo.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -25,7 +26,7 @@ #include "../poison.hpp" static -std::list<std::string> npc_srcs; +std::list<FString> npc_srcs; static int npc_id = START_NPC_NUM; @@ -43,9 +44,9 @@ struct event_data int pos; }; static -Map<std::string, struct event_data> ev_db; +Map<NpcEvent, struct event_data> ev_db; static -DMap<std::string, dumb_ptr<npc_data>> npcname_db; +DMap<NpcName, dumb_ptr<npc_data>> npcname_db; // used for clock-based event triggers // only tm_min, tm_hour, and tm_mday are used @@ -62,7 +63,6 @@ static void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) { dumb_ptr<map_session_data> sd; - char aname[50] {}; nullpo_retv(bl); @@ -74,16 +74,17 @@ void npc_enable_sub(dumb_ptr<block_list> bl, dumb_ptr<npc_data> nd) if (nd->flag & 1) return; - strzcpy(aname, nd->name, sizeof(nd->name)); + NpcEvent aname; + aname.npc = nd->name; + aname.label = stringish<ScriptLabel>("OnTouch"); if (sd->areanpc_id == nd->bl_id) return; sd->areanpc_id = nd->bl_id; - strcat(aname, "::OnTouch"); npc_event(sd, aname, 0); } } -int npc_enable(const char *name, bool flag) +int npc_enable(NpcName name, bool flag) { dumb_ptr<npc_data> nd = npcname_db.get(name); if (nd == NULL) @@ -121,7 +122,7 @@ int npc_enable(const char *name, bool flag) * NPCを名前で探す *------------------------------------------ */ -dumb_ptr<npc_data> npc_name2id(const char *name) +dumb_ptr<npc_data> npc_name2id(NpcName name) { return npcname_db.get(name); } @@ -138,7 +139,7 @@ int npc_event_dequeue(dumb_ptr<map_session_data> sd) if (!sd->eventqueuel.empty()) { - if (!pc_addeventtimer(sd, std::chrono::milliseconds(100), sd->eventqueuel.front().c_str())) + if (!pc_addeventtimer(sd, std::chrono::milliseconds(100), sd->eventqueuel.front())) { PRINTF("npc_event_dequeue(): Event timer is full.\n"); return 0; @@ -163,7 +164,7 @@ int npc_delete(dumb_ptr<npc_data> nd) return 0; } -int npc_timer_event(const char *eventname) // Added by RoVeRT +void npc_timer_event(NpcEvent eventname) { struct event_data *ev = ev_db.search(eventname); dumb_ptr<npc_data_script> nd; @@ -171,13 +172,12 @@ int npc_timer_event(const char *eventname) // Added by RoVeRT if ((ev == NULL || (nd = ev->nd) == NULL)) { - PRINTF("npc_event: event not found [%s]\n", eventname); - return 0; + PRINTF("npc_event: event not found [%s]\n", + eventname); + return; } run_script(ScriptPointer(nd->scr.script.get(), ev->pos), nd->bl_id, nd->bl_id); - - return 0; } /*========================================== @@ -185,55 +185,51 @@ int npc_timer_event(const char *eventname) // Added by RoVeRT *------------------------------------------ */ static -void npc_event_doall_sub(const std::string& key, struct event_data *ev, - int *c, const char *name, int rid, int argc, argrec_t *argv) +void npc_event_doall_sub(NpcEvent key, struct event_data *ev, + int *c, ScriptLabel name, int rid, int argc, argrec_t *argv) { - const char *p = key.c_str(); + ScriptLabel p = key.label; nullpo_retv(ev); - if ((p = strchr(p, ':')) && p && strcasecmp(name, p) == 0) + if (name == p) { - run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, argc, - argv); + run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, + argc, argv); (*c)++; } } -int npc_event_doall_l(const char *name, int rid, int argc, argrec_t *args) +int npc_event_doall_l(ScriptLabel name, int rid, int argc, argrec_t *args) { int c = 0; - char buf[64] = "::"; - strzcpy(buf + 2, name, 62); for (auto& pair : ev_db) - npc_event_doall_sub(pair.first, &pair.second, &c, buf, rid, argc, args); + npc_event_doall_sub(pair.first, &pair.second, &c, name, rid, argc, args); return c; } static -void npc_event_do_sub(const std::string& key, struct event_data *ev, - int *c, const char *name, int rid, int argc, argrec_t *argv) +void npc_event_do_sub(NpcEvent key, struct event_data *ev, + int *c, NpcEvent name, int rid, int argc, argrec_t *argv) { - const char *p = key.c_str(); - nullpo_retv(ev); - if (p && strcasecmp(name, p) == 0) + if (name == key) { - run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, argc, - argv); + run_script_l(ScriptPointer(ev->nd->scr.script.get(), ev->pos), rid, ev->nd->bl_id, + argc, argv); (*c)++; } } -int npc_event_do_l(const char *name, int rid, int argc, argrec_t *args) +int npc_event_do_l(NpcEvent name, int rid, int argc, argrec_t *args) { int c = 0; - if (*name == ':' && name[1] == ':') + if (!name.npc) { - return npc_event_doall_l(name + 2, rid, argc, args); + return npc_event_doall_l(name.label, rid, argc, args); } for (auto& pair : ev_db) @@ -250,25 +246,23 @@ void npc_event_do_clock(TimerData *, tick_t) { struct tm t = TimeT::now(); + ScriptLabel buf; if (t.tm_min != ev_tm_b.tm_min) { - std::string buf; - buf = STRPRINTF("OnMinute%02d", t.tm_min); - npc_event_doall(buf.c_str()); - buf = STRPRINTF("OnClock%02d%02d", t.tm_hour, t.tm_min); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnMinute%02d", t.tm_min); + npc_event_doall(buf); + SNPRINTF(buf, 24, "OnClock%02d%02d", t.tm_hour, t.tm_min); + npc_event_doall(buf); } if (t.tm_hour != ev_tm_b.tm_hour) { - std::string buf; - buf = STRPRINTF("OnHour%02d", t.tm_hour); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnHour%02d", t.tm_hour); + npc_event_doall(buf); } if (t.tm_mday != ev_tm_b.tm_mday) { - std::string buf; - buf = STRPRINTF("OnDay%02d%02d", t.tm_mon + 1, t.tm_mday); - npc_event_doall(buf.c_str()); + SNPRINTF(buf, 24, "OnDay%02d%02d", t.tm_mon + 1, t.tm_mday); + npc_event_doall(buf); } ev_tm_b = t; } @@ -279,7 +273,7 @@ void npc_event_do_clock(TimerData *, tick_t) */ int npc_event_do_oninit(void) { - int c = npc_event_doall("OnInit"); + int c = npc_event_doall(stringish<ScriptLabel>("OnInit")); PRINTF("npc: OnInit Event done. (%d npc)\n", c); Timer(gettick() + std::chrono::milliseconds(100), @@ -414,41 +408,34 @@ void npc_settimerevent_tick(dumb_ptr<npc_data_script> nd, interval_t newtimer) * イベント型のNPC処理 *------------------------------------------ */ -int npc_event(dumb_ptr<map_session_data> sd, const char *eventname, - int mob_kill) +int npc_event(dumb_ptr<map_session_data> sd, NpcEvent eventname, + int mob_kill) { struct event_data *ev = ev_db.search(eventname); dumb_ptr<npc_data_script> nd; int xs, ys; - char mobevent[100]; if (sd == NULL) { PRINTF("npc_event nullpo?\n"); } - if (ev == NULL && eventname - && strcmp(((eventname) + strlen(eventname) - 9), "::OnTouch") == 0) + if (ev == NULL && eventname.label == stringish<ScriptLabel>("OnTouch")) return 1; if (ev == NULL || (nd = ev->nd) == NULL) { - if (mob_kill && (ev == NULL || (nd = ev->nd) == NULL)) + if (mob_kill) { - strcpy(mobevent, eventname); - strcat(mobevent, "::OnMyMobDead"); - ev = ev_db.search(mobevent); - if (ev == NULL || (nd = ev->nd) == NULL) { - if (strncasecmp(eventname, "GM_MONSTER", 10) != 0) - PRINTF("npc_event: event not found [%s]\n", mobevent); return 0; } } else { if (battle_config.error_log) - PRINTF("npc_event: event not found [%s]\n", eventname); + PRINTF("npc_event: event not found [%s]\n", + eventname); return 0; } } @@ -485,22 +472,19 @@ int npc_event(dumb_ptr<map_session_data> sd, const char *eventname, } static -void npc_command_sub(const std::string& key, struct event_data *ev, const char *npcname, const char *command) +void npc_command_sub(NpcEvent key, struct event_data *ev, NpcName npcname, XString command) { - const char *p = key.c_str(); - char temp[100]; - - if (strcmp(ev->nd->name, npcname) == 0 && (p = strchr(p, ':')) && p - && strncasecmp("::OnCommand", p, 10) == 0) + if (ev->nd->name == npcname + && key.label.startswith("OnCommand")) { - sscanf(&p[11], "%s", temp); + XString temp = key.label.xslice_t(9); - if (strcmp(command, temp) == 0) + if (command == temp) run_script(ScriptPointer(ev->nd->scr.script.get(), ev->pos), 0, ev->nd->bl_id); } } -int npc_command(dumb_ptr<map_session_data>, const char *npcname, const char *command) +int npc_command(dumb_ptr<map_session_data>, NpcName npcname, XString command) { for (auto& pair : ev_db) npc_command_sub(pair.first, &pair.second, npcname, command); @@ -575,14 +559,14 @@ int npc_touch_areanpc(dumb_ptr<map_session_data> sd, map_local *m, int x, int y) break; case NpcSubtype::SCRIPT: { - char aname[50] {}; - strzcpy(aname, m->npc[i]->name, 24); + NpcEvent aname; + aname.npc = m->npc[i]->name; + aname.label = stringish<ScriptLabel>("OnTouch"); if (sd->areanpc_id == m->npc[i]->bl_id) return 1; sd->areanpc_id = m->npc[i]->bl_id; - strcat(aname, "::OnTouch"); if (npc_event(sd, aname, 0) > 0) npc_click(sd, m->npc[i]->bl_id); break; @@ -658,9 +642,9 @@ int npc_click(dumb_ptr<map_session_data> sd, int id) sd->npc_pos = run_script(ScriptPointer(nd->as_script()->scr.script.get(), 0), sd->bl_id, id); break; case NpcSubtype::MESSAGE: - if (!nd->as_message()->message.empty()) + if (nd->as_message()->message) { - clif_scriptmes(sd, id, nd->as_message()->message.c_str()); + clif_scriptmes(sd, id, nd->as_message()->message); clif_scriptclose(sd, id); } break; @@ -893,9 +877,9 @@ void npc_clearsrcfile(void) * 読み込むnpcファイルの追加 *------------------------------------------ */ -void npc_addsrcfile(const char *name) +void npc_addsrcfile(FString name) { - if (strcasecmp(name, "clear") == 0) + if (name == "clear") { npc_clearsrcfile(); return; @@ -908,9 +892,9 @@ void npc_addsrcfile(const char *name) * 読み込むnpcファイルの削除 *------------------------------------------ */ -void npc_delsrcfile(const char *name) +void npc_delsrcfile(FString name) { - if (strcasecmp(name, "all") == 0) + if (name == "all") { npc_clearsrcfile(); return; @@ -930,17 +914,15 @@ void npc_delsrcfile(const char *name) * warp行解析 *------------------------------------------ */ -int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) +int npc_parse_warp(XString w1, XString, NpcName w3, XString w4) { int x, y, xs, ys, to_x, to_y; int i, j; - char mapname[24], to_mapname[24]; + MapName mapname, to_mapname; dumb_ptr<npc_data_warp> nd; - // 引数の個数チェック - if (sscanf(w1, "%[^,],%d,%d", mapname, &x, &y) != 3 || - sscanf(w4, "%d,%d,%[^,],%d,%d", &xs, &ys, to_mapname, &to_x, - &to_y) != 5) + if (!extract(w1, record<','>(&mapname, &x, &y)) || + !extract(w4, record<','>(&xs, &ys, &to_mapname, &to_x, &to_y))) { PRINTF("bad warp line : %s\n", w3); return 1; @@ -958,8 +940,7 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) nd->bl_y = y; nd->dir = DIR::S; nd->flag = 0; - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, w3, 24); + nd->name = w3; if (!battle_config.warp_point_debug) nd->npc_class = WARP_CLASS; @@ -970,7 +951,7 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - strzcpy(nd->warp.name, to_mapname, 16); + nd->warp.name = to_mapname; xs += 2; ys += 2; nd->warp.x = to_x; @@ -1004,24 +985,51 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4) return 0; } +static +bool extract(XString xs, npc_item_list *itv) +{ + XString name_or_id; + if (!extract(xs, record<':'>(&name_or_id, &itv->value))) + return false; + struct item_data *id = nullptr; + if (extract(name_or_id, &itv->nameid) && itv->nameid > 0) + goto return_true; + + id = itemdb_searchname(stringish<ItemName>(name_or_id.rstrip())); + if (id == NULL) + return false; + itv->nameid = id->nameid; + goto return_true; + +return_true: + if (itv->value < 0) + { + if (id == NULL) + id = itemdb_search(itv->nameid); + itv->value = id->value_buy * abs(itv->value); + } + return true; +} + /*========================================== * shop行解析 *------------------------------------------ */ static -int npc_parse_shop(char *w1, char *, char *w3, char *w4) +int npc_parse_shop(XString w1, XString, NpcName w3, ZString w4a) { - char *p; int x, y; DIR dir; - char mapname[24]; + MapName mapname; dumb_ptr<npc_data_shop> nd; + ZString::iterator w4comma; + int npc_class; - // 引数の個数チェック - int dir_; // TODO use SSCANF or extract - if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4 + int dir_; // TODO use enum directly in extract + if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) || dir_ < 0 || dir_ >= 8 - || strchr(w4, ',') == NULL) + || (w4comma = std::find(w4a.begin(), w4a.end(), ',')) == w4a.end() + || !extract(w4a.xislice_h(w4comma), &npc_class)) { PRINTF("bad shop line : %s\n", w3); return 1; @@ -1030,44 +1038,15 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) map_local *m = map_mapname2mapid(mapname); nd.new_(); - p = strchr(w4, ','); + ZString w4b = w4a.xislice_t(w4comma + 1); - while (p) + if (!extract(w4b, vrec<','>(&nd->shop_items))) { - int nameid, value; - char name[24]; - struct item_data *id = NULL; - p++; - if (sscanf(p, "%d:%d", &nameid, &value) == 2) - { - } - else if (sscanf(p, "%s :%d", name, &value) == 2) - { - id = itemdb_searchname(name); - if (id == NULL) - nameid = -1; - else - nameid = id->nameid; - } - else - break; - - if (nameid > 0) - { - npc_item_list sh_it; - sh_it.nameid = nameid; - if (value < 0) - { - if (id == NULL) - id = itemdb_search(nameid); - value = id->value_buy * abs(value); - - } - sh_it.value = value; - nd->shop_items.push_back(sh_it); - } - p = strchr(p, ','); + PRINTF("bad shop items : %s\n", w3); + PRINTF(" somewhere --> %s\n", w4b); + nd->shop_items.clear(); } + if (nd->shop_items.empty()) { nd.delete_(); @@ -1081,15 +1060,14 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) nd->bl_id = npc_get_new_npc_id(); nd->dir = dir; nd->flag = 0; - strzcpy(nd->name, w3, 24); - nd->npc_class = atoi(w4); + nd->name = w3; + nd->npc_class = npc_class; nd->speed = std::chrono::milliseconds(200); nd->option = Option::ZERO; nd->opt1 = Opt1::ZERO; nd->opt2 = Opt2::ZERO; nd->opt3 = Opt3::ZERO; - //PRINTF("shop npc %s %d read done\n",mapname,nd->bl_id); npc_shop++; nd->bl_type = BL::NPC; nd->npc_subtype = NpcSubtype::SHOP; @@ -1106,12 +1084,12 @@ int npc_parse_shop(char *w1, char *, char *w3, char *w4) *------------------------------------------ */ static -void npc_convertlabel_db(const std::string& lname, int pos, dumb_ptr<npc_data_script> nd) +void npc_convertlabel_db(ScriptLabel lname, int pos, dumb_ptr<npc_data_script> nd) { nullpo_retv(nd); struct npc_label_list eln {}; - strzcpy(eln.name, lname.c_str(), sizeof(eln.name)); + eln.name = lname; eln.pos = pos; nd->scr.label_listv.push_back(std::move(eln)); } @@ -1121,20 +1099,19 @@ void npc_convertlabel_db(const std::string& lname, int pos, dumb_ptr<npc_data_sc *------------------------------------------ */ static -int npc_parse_script(char *w1, char *w2, char *w3, char *w4, - const char *first_line, FILE * fp, int *lines) +int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, + XString first_line, FILE *fp, int *lines) { int x, y; DIR dir = DIR::S; map_local *m; int xs = 0, ys = 0, npc_class = 0; // [Valaris] thanks to fov - char mapname[24]; + MapName mapname; std::unique_ptr<const ScriptBuffer> script = NULL; dumb_ptr<npc_data_script> nd; int evflag = 0; - char *p; - if (strcmp(w1, "-") == 0) + if (w1 == "-") { x = 0; y = 0; @@ -1142,11 +1119,10 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, } else { - // 引数の個数チェック - int dir_; // TODO use SSCANF or extract - if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4 + int dir_; // TODO use enum directly in extract + if (!extract(w1, record<','>(&mapname, &x, &y, &dir_)) || dir_ < 0 || dir_ >= 8 - || (strcmp(w2, "script") == 0 && strchr(w4, ',') == NULL)) + || (w2 == "script" && !w4.contains(','))) { PRINTF("bad script line : %s\n", w3); return 1; @@ -1155,29 +1131,33 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, m = map_mapname2mapid(mapname); } - if (strcmp(w2, "script") == 0) + if (w2 == "script") { // may be empty - std::string srcbuf = strchrnul(first_line, '{'); + MString srcbuf; + srcbuf += first_line.xislice_t(std::find(first_line.begin(), first_line.end(), '{')); // Note: it was a bug that this was missing. I think. int startline = *lines; - while (1) + // while (!srcbuf.rstrip().endswith('}')) + while (true) { - size_t i = srcbuf.find_last_not_of(" \t\n\r\f\v"); - if (i != std::string::npos && srcbuf[i] == '}') + auto it = std::find_if_not(srcbuf.rbegin(), srcbuf.rend(), [](char c){ return c == ' ' || c == '\n'; }); + if (it != srcbuf.rend() && *it == '}') break; - char line[1024]; - if (!fgets(line, 1020, fp)) + + char line_[1024]; + if (!fgets(line_, 1020, fp)) // eof break; (*lines)++; if (feof(fp)) break; - if (srcbuf.empty()) + ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + if (!srcbuf) { // may be a no-op - srcbuf = strchrnul(line, '{'); + srcbuf += line.xislice_t(std::find(line.begin(), line.end(), '{')); // safe to execute more than once // But will usually only happen once startline = *lines; @@ -1185,7 +1165,7 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, else srcbuf += line; } - script = parse_script(srcbuf.c_str(), startline); + script = parse_script(FString(srcbuf), startline); if (script == NULL) // script parse error? return 1; @@ -1200,13 +1180,9 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, if (m == nullptr) { - // スクリプトコピー用のダミーNPC } - else if (sscanf(w4, "%d,%d,%d", &npc_class, &xs, &ys) == 3) + else if (extract(w4, record<','>(&npc_class, &xs, &ys))) { - // 接触型NPC - int i, j; - if (xs >= 0) xs = xs * 2 + 1; if (ys >= 0) @@ -1215,9 +1191,9 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, if (npc_class >= 0) { - for (i = 0; i < ys; i++) + for (int i = 0; i < ys; i++) { - for (j = 0; j < xs; j++) + for (int j = 0; j < xs; j++) { int x_lo = x - xs / 2; int y_lo = y - ys / 2; @@ -1235,32 +1211,24 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, nd->scr.ys = ys; } else - { // クリック型NPC - npc_class = atoi(w4); + { + npc_class = atoi(w4.c_str()); nd->scr.xs = 0; nd->scr.ys = 0; } if (npc_class < 0 && m != nullptr) - { // イベント型NPC + { evflag = 1; } - while ((p = strchr(w3, ':'))) - { - if (p[1] == ':') - break; - } - if (p) + if (w3.contains(':')) { - *p = 0; - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, p + 2, 24); + assert(false && "feature removed"); + abort(); } - else { - strzcpy(nd->name, w3, 24); - strzcpy(nd->exname, w3, 24); + nd->name = w3; } nd->bl_prev = nd->bl_next = NULL; @@ -1288,37 +1256,36 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, map_addblock(nd); if (evflag) - { // イベント型 + { struct event_data ev {}; ev.nd = nd; ev.pos = 0; - ev_db.insert(nd->exname, ev); + NpcEvent npcev; + npcev.npc = nd->name; + npcev.label = ScriptLabel(); + ev_db.insert(npcev, ev); } else clif_spawnnpc(nd); } - npcname_db.put(nd->exname, nd); + npcname_db.put(nd->name, nd); for (auto& pair : scriptlabel_db) npc_convertlabel_db(pair.first, pair.second, nd); for (npc_label_list& el : nd->scr.label_listv) { - char *lname = el.name; + ScriptLabel lname = el.name; int pos = el.pos; - if ((lname[0] == 'O' || lname[0] == 'o') - && (lname[1] == 'N' || lname[1] == 'n')) + if (lname.startswith("On")) { - if (strlen(lname) > 24) - { - PRINTF("npc_parse_script: label name error !\n"); - exit(1); - } struct event_data ev {}; ev.nd = nd; ev.pos = pos; - std::string buf = STRPRINTF("%s::%s", nd->exname, lname); + NpcEvent buf; + buf.npc = nd->name; + buf.label = lname; ev_db.insert(buf, ev); } } @@ -1327,10 +1294,10 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, // ラベルデータからタイマーイベント取り込み for (npc_label_list& el : nd->scr.label_listv) { - int t_ = 0, n = 0; - char *lname = el.name; + int t_ = 0; + ScriptLabel lname = el.name; int pos = el.pos; - if (sscanf(lname, "OnTimer%d%n", &t_, &n) == 1 && lname[n] == '\0') + if (lname.startswith("OnTimer") && extract(lname.xslice_t(7), &t_)) { interval_t t = static_cast<interval_t>(t_); @@ -1360,40 +1327,41 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4, *------------------------------------------ */ static -int npc_parse_function(char *, char *, char *w3, char *, - char *first_line, FILE * fp, int *lines) +int npc_parse_function(XString, XString, XString w3, ZString, + XString first_line, FILE *fp, int *lines) { - std::string srcbuf = strchrnul(first_line, '{'); + MString srcbuf; + srcbuf += first_line.xislice_t(std::find(first_line.begin(), first_line.end(), '{')); int startline = *lines; - while (1) + while (true) { - size_t i = srcbuf.find_last_not_of(" \t\n\r\f\v"); - if (i != std::string::npos && srcbuf[i] == '}') + auto it = std::find_if_not(srcbuf.rbegin(), srcbuf.rend(), [](char c){ return c == ' ' || c == '\n'; }); + if (it != srcbuf.rend() && *it == '}') break; - char line[1024]; - if (!fgets(line, 1020, fp)) + char line_[1024]; + if (!fgets(line_, 1020, fp)) break; (*lines)++; if (feof(fp)) break; - if (srcbuf.empty()) + ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + if (!srcbuf) { - srcbuf = strchrnul(line, '{'); + srcbuf += line.xislice_t(std::find(line.begin(), line.end(), '{')); startline = *lines; } else srcbuf += line; } - std::unique_ptr<const ScriptBuffer> script = parse_script(srcbuf.c_str(), startline); + std::unique_ptr<const ScriptBuffer> script = parse_script(FString(srcbuf), startline); if (script == NULL) { // script parse error? return 1; } - std::string p = w3; - userfunc_db.put(p, std::move(script)); + userfunc_db.put(w3, std::move(script)); return 0; } @@ -1403,20 +1371,18 @@ int npc_parse_function(char *, char *, char *w3, char *, *------------------------------------------ */ static -int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) +int npc_parse_mob(XString w1, XString, MobName w3, ZString w4) { int x, y, xs, ys, mob_class, num; int i; - char mapname[24]; - char eventname[24] = ""; + MapName mapname; + NpcEvent eventname; dumb_ptr<mob_data> md; xs = ys = 0; int delay1_ = 0, delay2_ = 0; - // 引数の個数チェック - if (sscanf(w1, "%[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 || - sscanf(w4, "%d,%d,%d,%d,%s", &mob_class, &num, &delay1_, &delay2_, - eventname) < 2) + if (!extract(w1, record<',', 3>(&mapname, &x, &y, &xs, &ys)) || + !extract(w4, record<',', 2>(&mob_class, &num, &delay1_, &delay2_, &eventname))) { PRINTF("bad monster line : %s\n", w3); return 1; @@ -1441,12 +1407,12 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) md->bl_m = m; md->bl_x = x; md->bl_y = y; - if (strcmp(w3, "--en--") == 0) - strzcpy(md->name, mob_db[mob_class].name, 24); - else if (strcmp(w3, "--ja--") == 0) - strzcpy(md->name, mob_db[mob_class].jname, 24); + if (w3 == ENGLISH_NAME) + md->name = mob_db[mob_class].name; + else if (w3 == JAPANESE_NAME) + md->name = mob_db[mob_class].jname; else - strzcpy(md->name, w3, 24); + md->name = w3; md->n = i; md->mob_class = mob_class; @@ -1466,10 +1432,7 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) md->lootitemv.clear(); - if (strlen(eventname) >= 4) - strzcpy(md->npc_event, eventname, 24); - else - strzcpy(md->npc_event, "", 24); + md->npc_event = eventname; md->bl_type = BL::MOB; map_addiddb(md); @@ -1487,123 +1450,121 @@ int npc_parse_mob(const char *w1, const char *, const char *w3, const char *w4) *------------------------------------------ */ static -int npc_parse_mapflag(char *w1, char *, char *w3, char *w4) +int npc_parse_mapflag(XString w1, XString, XString w3, ZString w4) { - char mapname[24], savemap[16]; + MapName mapname, savemap; int savex, savey; - // 引数の個数チェック -// if ( sscanf(w1,"%[^,],%d,%d,%d",mapname,&x,&y,&dir) != 4 ) - if (sscanf(w1, "%[^,]", mapname) != 1) + mapname = stringish<MapName>(w1); + if (!mapname) return 1; map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return 1; -//マップフラグ - if (strcasecmp(w3, "nosave") == 0) + if (w3 == "nosave") { - if (strcmp(w4, "SavePoint") == 0) + if (w4 == "SavePoint") { - strzcpy(m->save.map_, "SavePoint", 16); + m->save.map_ = stringish<MapName>("SavePoint"); m->save.x = -1; m->save.y = -1; } - else if (sscanf(w4, "%[^,],%d,%d", savemap, &savex, &savey) == 3) + else if (extract(w4, record<','>(&savemap, &savex, &savey))) { - strzcpy(m->save.map_, savemap, 16); + m->save.map_ = savemap; m->save.x = savex; m->save.y = savey; } m->flag.nosave = 1; } - else if (strcasecmp(w3, "nomemo") == 0) + else if (w3 == "nomemo") { m->flag.nomemo = 1; } - else if (strcasecmp(w3, "noteleport") == 0) + else if (w3 == "noteleport") { m->flag.noteleport = 1; } - else if (strcasecmp(w3, "nowarp") == 0) + else if (w3 == "nowarp") { m->flag.nowarp = 1; } - else if (strcasecmp(w3, "nowarpto") == 0) + else if (w3 == "nowarpto") { m->flag.nowarpto = 1; } - else if (strcasecmp(w3, "noreturn") == 0) + else if (w3 == "noreturn") { m->flag.noreturn = 1; } - else if (strcasecmp(w3, "monster_noteleport") == 0) + else if (w3 == "monster_noteleport") { m->flag.monster_noteleport = 1; } - else if (strcasecmp(w3, "nobranch") == 0) + else if (w3 == "nobranch") { m->flag.nobranch = 1; } - else if (strcasecmp(w3, "nopenalty") == 0) + else if (w3 == "nopenalty") { m->flag.nopenalty = 1; } - else if (strcasecmp(w3, "pvp") == 0) + else if (w3 == "pvp") { m->flag.pvp = 1; } - else if (strcasecmp(w3, "pvp_noparty") == 0) + else if (w3 == "pvp_noparty") { m->flag.pvp_noparty = 1; } - else if (strcasecmp(w3, "pvp_nocalcrank") == 0) + else if (w3 == "pvp_nocalcrank") { m->flag.pvp_nocalcrank = 1; } - else if (strcasecmp(w3, "nozenypenalty") == 0) + else if (w3 == "nozenypenalty") { m->flag.nozenypenalty = 1; } - else if (strcasecmp(w3, "notrade") == 0) + else if (w3 == "notrade") { m->flag.notrade = 1; } - else if (battle_config.pk_mode && strcasecmp(w3, "nopvp") == 0) + else if (battle_config.pk_mode && w3 == "nopvp") { // nopvp for pk mode [Valaris] m->flag.nopvp = 1; m->flag.pvp = 0; } - else if (strcasecmp(w3, "noicewall") == 0) + else if (w3 == "noicewall") { // noicewall [Valaris] m->flag.noicewall = 1; } - else if (strcasecmp(w3, "snow") == 0) + else if (w3 == "snow") { // snow [Valaris] m->flag.snow = 1; } - else if (strcasecmp(w3, "fog") == 0) + else if (w3 == "fog") { // fog [Valaris] m->flag.fog = 1; } - else if (strcasecmp(w3, "sakura") == 0) + else if (w3 == "sakura") { // sakura [Valaris] m->flag.sakura = 1; } - else if (strcasecmp(w3, "leaves") == 0) + else if (w3 == "leaves") { // leaves [Valaris] m->flag.leaves = 1; } - else if (strcasecmp(w3, "rain") == 0) + else if (w3 == "rain") { // rain [Valaris] m->flag.rain = 1; } - else if (strcasecmp(w3, "no_player_drops") == 0) + else if (w3 == "no_player_drops") { // no player drops [Jaxad0127] m->flag.no_player_drops = 1; } - else if (strcasecmp(w3, "town") == 0) + else if (w3 == "town") { // town/safe zone [remoitnane] m->flag.town = 1; } @@ -1612,7 +1573,7 @@ int npc_parse_mapflag(char *w1, char *, char *w3, char *w4) } dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, - int npc_class, const char *name, const char *message) + int npc_class, NpcName name, FString message) { dumb_ptr<npc_data_message> retval; retval.new_(); @@ -1623,8 +1584,7 @@ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, retval->bl_type = BL::NPC; retval->npc_subtype = NpcSubtype::MESSAGE; - strzcpy(retval->name, name, 24); - strzcpy(retval->exname, name, 24); + retval->name = name; if (message) retval->message = message; @@ -1656,7 +1616,7 @@ void npc_free_internal(dumb_ptr<npc_data> nd_) else if (nd_->npc_subtype == NpcSubtype::MESSAGE) { dumb_ptr<npc_data_message> nd = nd_->as_message(); - nd->message.clear(); + nd->message = FString(); } nd_.delete_(); } @@ -1699,100 +1659,91 @@ int do_init_npc(void) for (; !npc_srcs.empty(); npc_srcs.pop_front()) { - std::string& nsl = npc_srcs.front(); - FILE *fp = fopen_(nsl.c_str(), "r"); + FString nsl = npc_srcs.front(); + FILE *fp = fopen(nsl.c_str(), "r"); if (fp == NULL) { PRINTF("file not found : %s\n", nsl); exit(1); } int lines = 0; - char line[1024]; - while (fgets(line, 1020, fp)) + char line_[1024]; + while (fgets(line_, 1020, fp)) { - char w1[1024], w2[1024], w3[1024], w4[1024], mapname[1024]; - int i, j, w4pos, count; + // because it's still fgets + line_[strlen(line_) - 1] = '\0'; + ZString zline(ZString::really_construct_from_a_pointer, line_, nullptr); + XString w1, w2, w3, w4x; + ZString w4z; lines++; - if (line[0] == '/' && line[1] == '/') + if (!zline) + continue; + if (zline.startswith("//")) continue; - // 不要なスペースやタブの連続は詰める - for (i = j = 0; line[i]; i++) + + if (!extract(zline, record<'|', 3>(&w1, &w2, &w3, &w4x)) || !w1 || !w2 || !w3) { - if (line[i] == ' ') - { - if (! - ((line[i + 1] - && (isspace(line[i + 1]) || line[i + 1] == ',')) - || (j && line[j - 1] == ','))) - line[j++] = ' '; - } - else if (line[i] == '\t' || line[i] == '|') - { - if (!(j && (line[j - 1] == '\t' || line[j - 1] == '|'))) - line[j++] = '\t'; - } - else - line[j++] = line[i]; + FPRINTF(stderr, "%s:%d: Broken script line: %s\n", nsl, lines, zline); + continue; } - // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認 - if ((count = - sscanf(line, "%[^\t]\t%[^\t]\t%[^\t\r\n]\t%n%[^\t\r\n]", w1, - w2, w3, &w4pos, w4)) < 3 - && (count = - sscanf(line, "%s%s%s%n%s", w1, w2, w3, &w4pos, w4)) < 3) + if (&*w4x.end() == &*zline.end()) { - continue; + w4z = zline.xrslice_t(w4x.size()); } - // マップの存在確認 - if (strcmp(w1, "-") != 0 && strcasecmp(w1, "function") != 0) + assert(bool(w4x) == bool(w4z)); + + if (w1 != "-" && w1 != "function") { - sscanf(w1, "%[^,]", mapname); + auto comma = std::find(w1.begin(), w1.end(), ','); + MapName mapname = stringish<MapName>(w1.xislice_h(comma)); map_local *m = map_mapname2mapid(mapname); - if (strlen(mapname) > 16 || m == nullptr) + if (m == nullptr) { // "mapname" is not assigned to this server + FPRINTF(stderr, "%s:%d: Map not found: %s\n", nsl, lines, mapname); continue; } } - if (strcasecmp(w2, "warp") == 0 && count > 3) + if (w2 == "warp") { - npc_parse_warp(w1, w2, w3, w4); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_warp(w1, w2, npcname, w4z); } - else if (strcasecmp(w2, "shop") == 0 && count > 3) + else if (w2 == "shop") { - npc_parse_shop(w1, w2, w3, w4); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_shop(w1, w2, npcname, w4z); } - else if (strcasecmp(w2, "script") == 0 && count > 3) + else if (w2 == "script") { - if (strcasecmp(w1, "function") == 0) + if (w1 == "function") { - npc_parse_function(w1, w2, w3, w4, line + w4pos, fp, - &lines); + npc_parse_function(w1, w2, w3, w4z, + w4x, fp, &lines); } else { - npc_parse_script(w1, w2, w3, w4, line + w4pos, fp, - &lines); + NpcName npcname = stringish<NpcName>(w3); + npc_parse_script(w1, w2, npcname, w4z, + w4x, fp, &lines); } } - else if ((i = - 0, sscanf(w2, "duplicate%n", &i), (i > 0 - && w2[i] == '(')) - && count > 3) + else if (w2 == "monster") { - npc_parse_script(w1, w2, w3, w4, line + w4pos, fp, &lines); + MobName mobname = stringish<MobName>(w3); + npc_parse_mob(w1, w2, mobname, w4z); } - else if (strcasecmp(w2, "monster") == 0 && count > 3) + else if (w2 == "mapflag") { - npc_parse_mob(w1, w2, w3, w4); + npc_parse_mapflag(w1, w2, w3, w4z); } - else if (strcasecmp(w2, "mapflag") == 0 && count >= 3) + else { - npc_parse_mapflag(w1, w2, w3, w4); + PRINTF("odd script line: %s\n", zline); } } - fclose_(fp); + fclose(fp); PRINTF("\rLoading NPCs [%d]: %-54s", npc_id - START_NPC_NUM, nsl); fflush(stdout); diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 539152f..36f4e4d 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -15,19 +15,19 @@ constexpr int WARP_DEBUG_CLASS = 722; constexpr int INVISIBLE_CLASS = 32767; int npc_event_dequeue(dumb_ptr<map_session_data> sd); -int npc_event(dumb_ptr<map_session_data> sd, const char *npcname, int); -int npc_timer_event(const char *eventname); // Added by RoVeRT -int npc_command(dumb_ptr<map_session_data> sd, const char *npcname, const char *command); +int npc_event(dumb_ptr<map_session_data> sd, NpcEvent npcname, int); +void npc_timer_event(NpcEvent eventname); // Added by RoVeRT +int npc_command(dumb_ptr<map_session_data> sd, NpcName npcname, XString command); int npc_touch_areanpc(dumb_ptr<map_session_data>, map_local *, int, int); int npc_click(dumb_ptr<map_session_data>, int); int npc_scriptcont(dumb_ptr<map_session_data>, int); int npc_buysellsel(dumb_ptr<map_session_data>, int, int); int npc_buylist(dumb_ptr<map_session_data>, int, const uint16_t *); int npc_selllist(dumb_ptr<map_session_data>, int, const uint16_t *); -int npc_parse_warp(const char *w1, const char *w2, const char *w3, const char *w4); +int npc_parse_warp(XString w1, XString, NpcName w3, XString w4); -int npc_enable(const char *name, bool flag); -dumb_ptr<npc_data> npc_name2id(const char *name); +int npc_enable(NpcName name, bool flag); +dumb_ptr<npc_data> npc_name2id(NpcName name); int npc_get_new_npc_id(void); @@ -37,30 +37,27 @@ int npc_get_new_npc_id(void); * \param message The message to speak. If message is NULL, the NPC will not do anything at all. */ dumb_ptr<npc_data> npc_spawn_text(map_local *m, int x, int y, - int class_, const char *name, const char *message); // message is strdup'd within + int class_, NpcName name, FString message); /** * Uninstalls and frees an NPC */ void npc_free(dumb_ptr<npc_data> npc); -void npc_addsrcfile(const char *); -void npc_delsrcfile(const char *); +void npc_addsrcfile(FString); +void npc_delsrcfile(FString); int do_init_npc(void); int npc_event_do_oninit(void); -struct argrec; -int npc_event_doall_l(const char *name, int rid, - int argc, struct argrec *argv); -int npc_event_do_l(const char *name, int rid, - int argc, struct argrec *argv); +int npc_event_doall_l(ScriptLabel name, int rid, int argc, struct argrec_t *argv); +int npc_event_do_l(NpcEvent name, int rid, int argc, struct argrec_t *argv); inline -int npc_event_doall(const char *name) +int npc_event_doall(ScriptLabel name) { return npc_event_doall_l(name, 0, 0, NULL); } inline -int npc_event_do(const char *name) +int npc_event_do(NpcEvent name) { return npc_event_do_l(name, 0, 0, NULL); } diff --git a/src/map/party.cpp b/src/map/party.cpp index 62493c8..c6b0bcc 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -44,14 +44,14 @@ struct party *party_search(int party_id) } static -void party_searchname_sub(struct party *p, const char *str, struct party **dst) +void party_searchname_sub(struct party *p, PartyName str, struct party **dst) { - if (strcasecmp(p->name, str) == 0) + if (p->name == str) *dst = p; } // パーティ名検索 -struct party *party_searchname(const char *str) +struct party *party_searchname(PartyName str) { struct party *p = NULL; for (auto& pair : party_db) @@ -60,21 +60,19 @@ struct party *party_searchname(const char *str) } /* Process a party creation request. */ -int party_create(dumb_ptr<map_session_data> sd, const char *name) +int party_create(dumb_ptr<map_session_data> sd, PartyName name) { - char pname[24]; nullpo_ret(sd); - strzcpy(pname, name, 24); - tmw_TrimStr(pname); + name = stringish<PartyName>(name.strip()); /* The party name is empty/invalid. */ - if (!*pname) + if (!name) clif_party_created(sd, 1); /* Make sure the character isn't already in a party. */ if (sd->status.party_id == 0) - intif_create_party(sd, pname); + intif_create_party(sd, name); else clif_party_created(sd, 2); @@ -82,7 +80,7 @@ int party_create(dumb_ptr<map_session_data> sd, const char *name) } /* Relay the result of a party creation request. */ -void party_created(int account_id, int fail, int party_id, const char *name) +void party_created(int account_id, int fail, int party_id, PartyName name) { dumb_ptr<map_session_data> sd; sd = map_id2sd(account_id); @@ -103,7 +101,7 @@ void party_created(int account_id, int fail, int party_id, const char *name) p = party_db.init(party_id); p->party_id = party_id; - strzcpy(p->name, name, 24); + p->name = name; /* The party was created successfully. */ clif_party_created(sd, 0); @@ -139,7 +137,7 @@ int party_check_member(struct party *p) { // パーティにデータがあるか確認 if (p->member[j].account_id == sd->status.account_id) { - if (strcmp(p->member[j].name, sd->status.name) == 0) + if (p->member[j].name == sd->status.name) f = 0; // データがある else { @@ -369,7 +367,7 @@ int party_member_added(int party_id, int account_id, int flag) } // パーティ除名要求 -int party_removemember(dumb_ptr<map_session_data> sd, int account_id, const char *) +int party_removemember(dumb_ptr<map_session_data> sd, int account_id) { struct party *p; int i; @@ -420,7 +418,7 @@ int party_leave(dumb_ptr<map_session_data> sd) } // パーティメンバが脱退した -int party_member_leaved(int party_id, int account_id, const char *name) +int party_member_leaved(int party_id, int account_id, CharName name) { dumb_ptr<map_session_data> sd = map_id2sd(account_id); struct party *p = party_search(party_id); @@ -499,8 +497,8 @@ int party_optionchanged(int party_id, int account_id, int exp, int item, } // パーティメンバの移動通知 -void party_recv_movemap(int party_id, int account_id, const char *mapname, int online, - int lv) +void party_recv_movemap(int party_id, int account_id, MapName mapname, + int online, int lv) { struct party *p; int i; @@ -516,7 +514,7 @@ void party_recv_movemap(int party_id, int account_id, const char *mapname, int o } if (m->account_id == account_id) { - strzcpy(m->map, mapname, 16); + m->map = mapname; m->online = online; m->lv = lv; break; @@ -597,7 +595,7 @@ int party_send_logout(dumb_ptr<map_session_data> sd) } // パーティメッセージ送信 -void party_send_message(dumb_ptr<map_session_data> sd, const char *mes) +void party_send_message(dumb_ptr<map_session_data> sd, XString mes) { if (sd->status.party_id == 0) return; @@ -605,7 +603,7 @@ void party_send_message(dumb_ptr<map_session_data> sd, const char *mes) } // パーティメッセージ受信 -void party_recv_message(int party_id, int account_id, const char *mes) +void party_recv_message(int party_id, int account_id, XString mes) { struct party *p; if ((p = party_search(party_id)) == NULL) @@ -618,8 +616,8 @@ void party_check_conflict(dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - intif_party_checkconflict(sd->status.party_id, sd->status.account_id, - sd->status.name); + intif_party_checkconflict(sd->status.party_id, + sd->status.account_id, sd->status.name); } // 位置やHP通知用 diff --git a/src/map/party.hpp b/src/map/party.hpp index c27cc08..80679ad 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -11,22 +11,21 @@ struct block_list; void do_init_party(void); struct party *party_search(int party_id); -struct party *party_searchname(const char *str); +struct party *party_searchname(PartyName str); -int party_create(dumb_ptr<map_session_data> sd, const char *name); -void party_created(int account_id, int fail, int party_id, const char *name); +int party_create(dumb_ptr<map_session_data> sd, PartyName name); +void party_created(int account_id, int fail, int party_id, PartyName name); void party_request_info(int party_id); int party_invite(dumb_ptr<map_session_data> sd, int account_id); int party_member_added(int party_id, int account_id, int flag); int party_leave(dumb_ptr<map_session_data> sd); -int party_removemember(dumb_ptr<map_session_data> sd, int account_id, - const char *name); -int party_member_leaved(int party_id, int account_id, const char *name); +int party_removemember(dumb_ptr<map_session_data> sd, int account_id); +int party_member_leaved(int party_id, int account_id, CharName name); int party_reply_invite(dumb_ptr<map_session_data> sd, int account_id, int flag); int party_recv_noinfo(int party_id); int party_recv_info(const struct party *sp); -void party_recv_movemap(int party_id, int account_id, const char *map, +void party_recv_movemap(int party_id, int account_id, MapName map, int online, int lv); int party_broken(int party_id); int party_optionchanged(int party_id, int account_id, int exp, int item, @@ -36,8 +35,8 @@ int party_changeoption(dumb_ptr<map_session_data> sd, int exp, int item); int party_send_movemap(dumb_ptr<map_session_data> sd); int party_send_logout(dumb_ptr<map_session_data> sd); -void party_send_message(dumb_ptr<map_session_data> sd, const char *mes); -void party_recv_message(int party_id, int account_id, const char *mes); +void party_send_message(dumb_ptr<map_session_data> sd, XString mes); +void party_recv_message(int party_id, int account_id, XString mes); void party_send_xy_clear(struct party *p); void party_send_hp_check(dumb_ptr<block_list> bl, int party_id, int *flag); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 08f873a..8cc74b8 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -7,8 +7,9 @@ #include <fstream> #include "../common/cxxstdio.hpp" -#include "../common/random.hpp" +#include "../common/io.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -56,7 +57,7 @@ constexpr int MAGIC_SKILL_THRESHOLD = 200; MAP_LOG_PC(sd, "XP %d %d JOB %d %d %d ZENY %d + %d " suffix, \ sd->status.base_level, sd->status.base_exp, \ sd->status.job_level, sd->status.job_exp, sd->status.skill_point, \ - sd->status.zeny, pc_readaccountreg(sd, "BankAccount")) + sd->status.zeny, pc_readaccountreg(sd, stringish<VarName>("BankAccount"))) #define MAP_LOG_MAGIC(sd, suffix) \ MAP_LOG_PC(sd, "MAGIC %d %d %d %d %d %d EXP %d %d " suffix, \ @@ -66,8 +67,8 @@ constexpr int MAGIC_SKILL_THRESHOLD = 200; sd->status.skill[SkillID::TMW_MAGIC_TRANSMUTE].lv, \ sd->status.skill[SkillID::TMW_MAGIC_NATURE].lv, \ sd->status.skill[SkillID::TMW_MAGIC_ETHER].lv, \ - pc_readglobalreg(sd, "MAGIC_EXPERIENCE") & 0xffff, \ - (pc_readglobalreg(sd, "MAGIC_EXPERIENCE") >> 24) & 0xff) + pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE")) & 0xffff, \ + (pc_readglobalreg(sd, stringish<VarName>("MAGIC_EXPERIENCE")) >> 24) & 0xff) static //const int max_weight_base_0 = 20000; @@ -412,7 +413,7 @@ void pc_makesavestatus(dumb_ptr<map_session_data> sd) } else { - strzcpy(sd->status.last_point.map_, sd->mapname_, 16); + sd->status.last_point.map_ = sd->mapname_; sd->status.last_point.x = sd->bl_x; sd->status.last_point.y = sd->bl_y; } @@ -421,7 +422,7 @@ void pc_makesavestatus(dumb_ptr<map_session_data> sd) if (sd->bl_m->flag.nosave) { map_local *m = sd->bl_m; - if (strcmp(m->save.map_, "SavePoint") == 0) + if (m->save.map_ == "SavePoint") sd->status.last_point = sd->status.save_point; else sd->status.last_point = m->save; @@ -712,11 +713,11 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, clif_authok(sd); map_addnickdb(sd); - if (map_charid2nick(sd->status.char_id) == NULL) + if (!map_charid2nick(sd->status.char_id).to__actual()) map_addchariddb(sd->status.char_id, sd->status.name); //スパノビ用死にカウンターのスクリプト変数からの読み出しとsdへのセット - sd->die_counter = pc_readglobalreg(sd, "PC_DIE_COUNTER"); + sd->die_counter = pc_readglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER")); // ステータス初期計算など pc_calcstatus(sd, 1); @@ -732,12 +733,13 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, sd->status.name, sd->status.account_id); // TODO fix this to cache and use inotify + // this is far from the only such thing, but most of the others are logs { - std::ifstream in(motd_txt); + std::ifstream in(motd_txt.c_str()); if (in.is_open()) { - std::string buf; - while (std::getline(in, buf)) + FString buf; + while (io::getline(in, buf)) { clif_displaymessage(sd->fd, buf); } @@ -750,7 +752,7 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, sd->chat_reset_due = TimeT(); sd->chat_lines_in = sd->chat_total_repeats = 0; sd->chat_repeat_reset_due = TimeT(); - sd->chat_lastmsg[0] = '\0'; + sd->chat_lastmsg = FString(); for (tick_t& t : sd->flood_rates) t = tick_t(); @@ -768,7 +770,7 @@ int pc_authok(int id, int login_id2, TimeT connect_until_time, char tmpstr[] = WITH_TIMESTAMP("Your account time limit is: "); REPLACE_TIMESTAMP(tmpstr, connect_until_time); - clif_wis_message(sd->fd, wisp_server_name, tmpstr); + clif_wis_message(sd->fd, wisp_server_name, const_(tmpstr)); } pc_calcstatus(sd, 1); @@ -1024,16 +1026,16 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) int c = sd->status.inventory[index].card[j]; if (c > 0) { - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(i); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(i)}, + {"@itemId", sd->inventory_data[index]->nameid}, + }; if (i == EQUIP::SHIELD && sd->status.inventory[index].equip == EPOS::SHIELD) sd->state.lr_flag = 1; - run_script_l(ScriptPointer(itemdb_equipscript(c), 0), sd->bl_id, - 0, 2, arg); + run_script_l(ScriptPointer(itemdb_equipscript(c), 0), sd->bl_id, 0, + 2, arg); sd->state.lr_flag = 0; } } @@ -1050,13 +1052,13 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) { // カード int c = sd->status.inventory[index].card[j]; if (c > 0) { - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(i); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; - run_script_l(ScriptPointer(itemdb_equipscript(c), 0), sd->bl_id, - 0, 2, arg); + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(i)}, + {"@itemId", sd->inventory_data[index]->nameid} + }; + run_script_l(ScriptPointer(itemdb_equipscript(c), 0), sd->bl_id, 0, + 2, arg); } } } @@ -1113,23 +1115,25 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) sd->attackrange_ += sd->inventory_data[index]->range; sd->state.lr_flag = 1; { - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(i); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(i)}, + {"@itemId", sd->inventory_data[index]->nameid}, + }; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, 2, arg); + sd->bl_id, 0, + 2, arg); } sd->state.lr_flag = 0; } else - { //二刀流武器以外 - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(i); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; + { + //二刀流武器以外 + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(i)}, + {"@itemId", sd->inventory_data[index]->nameid}, + }; sd->watk += sd->inventory_data[index]->atk; sd->watk2 += (r = sd->status.inventory[index].refine) * // 精錬攻撃力 0; @@ -1142,21 +1146,23 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) } sd->attackrange += sd->inventory_data[index]->range; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, 2, arg); + sd->bl_id, 0, + 2, arg); } } else if (sd->inventory_data[index]->type == ItemType::ARMOR) { - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(i); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(i)}, + {"@itemId", sd->inventory_data[index]->nameid}, + }; sd->watk += sd->inventory_data[index]->atk; refinedef += sd->status.inventory[index].refine * 0; run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), - sd->bl_id, 0, 2, arg); + sd->bl_id, 0, + 2, arg); } } } @@ -1174,14 +1180,15 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first) index = sd->equip_index[EQUIP::ARROW]; if (sd->inventory_data[index]) { //まだ属性が入っていない - argrec_t arg[2]; - arg[0].name = "@slotId"; - arg[0].v.i = int(EQUIP::ARROW); - arg[1].name = "@itemId"; - arg[1].v.i = sd->inventory_data[index]->nameid; + argrec_t arg[2] = + { + {"@slotId", static_cast<int>(EQUIP::ARROW)}, + {"@itemId", sd->inventory_data[index]->nameid}, + }; sd->state.lr_flag = 2; - run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), sd->bl_id, - 0, 2, arg); + run_script_l(ScriptPointer(sd->inventory_data[index]->equip_script.get(), 0), + sd->bl_id, 0, + 2, arg); sd->state.lr_flag = 0; sd->arrow_atk += sd->inventory_data[index]->atk; } @@ -1888,7 +1895,6 @@ int pc_payzeny(dumb_ptr<map_session_data> sd, int zeny) { nullpo_ret(sd); -#warning "Why is this a double?" double z = sd->status.zeny; if (sd->status.zeny < zeny || z - zeny > MAX_ZENY) return 1; @@ -2270,10 +2276,10 @@ int pc_useitem(dumb_ptr<map_session_data> sd, int n) * PCの位置設定 *------------------------------------------ */ -int pc_setpos(dumb_ptr<map_session_data> sd, const char *mapname_org, int x, int y, - BeingRemoveWhy clrtype) +int pc_setpos(dumb_ptr<map_session_data> sd, + MapName mapname_org, int x, int y, BeingRemoveWhy clrtype) { - char mapname_[16]; + MapName mapname_; nullpo_ret(sd); @@ -2294,16 +2300,12 @@ int pc_setpos(dumb_ptr<map_session_data> sd, const char *mapname_org, int x, int // pc_setstand (sd); // [fate] Nothing wrong with warping while sitting } - strzcpy(mapname_, mapname_org, 16); - if (strstr(mapname_, ".gat") == NULL && strlen(mapname_) < 16 - 4) - { - strcat(mapname_, ".gat"); - } + mapname_ = mapname_org; map_local *m = map_mapname2mapid(mapname_); if (!m) { - if (sd->mapname_[0]) + if (sd->mapname_) { struct in_addr ip; int port; @@ -2312,7 +2314,7 @@ int pc_setpos(dumb_ptr<map_session_data> sd, const char *mapname_org, int x, int skill_stop_dancing(sd, 1); clif_clearchar(sd, clrtype); map_delblock(sd); - strzcpy(sd->mapname_, mapname_, 16); + sd->mapname_ = mapname_; sd->bl_x = x; sd->bl_y = y; sd->state.waitingdisconnect = 1; @@ -2359,7 +2361,7 @@ int pc_setpos(dumb_ptr<map_session_data> sd, const char *mapname_org, int x, int clif_changemap(sd, m->name_, x, y); // [MouseJstr] } - strzcpy(sd->mapname_, mapname_, 16); + sd->mapname_ = mapname_; sd->bl_m = m; sd->to_x = x; sd->to_y = y; @@ -3080,7 +3082,7 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, if (battle_config.disp_experience) { - std::string output = STRPRINTF( + FString output = STRPRINTF( "Experienced Gained Base:%d Job:%d", base_exp, job_exp); clif_displaymessage(sd->fd, output); @@ -3476,7 +3478,7 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, pc_stop_walking(sd, 0); skill_castcancel(sd, 0); // 詠唱の中止 clif_clearchar(sd, BeingRemoveWhy::DEAD); - pc_setglobalreg(sd, "PC_DIE_COUNTER", ++sd->die_counter); //死にカウンター書き込み + pc_setglobalreg(sd, stringish<VarName>("PC_DIE_COUNTER"), ++sd->die_counter); //死にカウンター書き込み skill_status_change_clear(sd, 0); // ステータス異常を解除する clif_updatestatus(sd, SP::HP); pc_calcstatus(sd, 0); @@ -3566,17 +3568,16 @@ int pc_damage(dumb_ptr<block_list> src, dumb_ptr<map_session_data> sd, if (src && src->bl_type == BL::PC) { // [Fate] PK death, trigger scripts - argrec_t arg[3]; - arg[0].name = "@killerrid"; - arg[0].v.i = src->bl_id; - arg[1].name = "@victimrid"; - arg[1].v.i = sd->bl_id; - arg[2].name = "@victimlvl"; - arg[2].v.i = sd->status.base_level; - npc_event_doall_l("OnPCKilledEvent", sd->bl_id, 3, arg); - npc_event_doall_l("OnPCKillEvent", src->bl_id, 3, arg); - } - npc_event_doall_l("OnPCDieEvent", sd->bl_id, 0, NULL); + argrec_t arg[3] = + { + {"@killerrid", src->bl_id}, + {"@victimrid", sd->bl_id}, + {"@victimlvl", sd->status.base_level}, + }; + npc_event_doall_l(stringish<ScriptLabel>("OnPCKilledEvent"), sd->bl_id, 3, arg); + npc_event_doall_l(stringish<ScriptLabel>("OnPCKillEvent"), src->bl_id, 3, arg); + } + npc_event_doall_l(stringish<ScriptLabel>("OnPCDieEvent"), sd->bl_id, 0, NULL); return 0; } @@ -4101,26 +4102,26 @@ void pc_setreg(dumb_ptr<map_session_data> sd, SIR reg, int val) * script用文字列変数の値を読む *------------------------------------------ */ -const char *pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg) +ZString pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg) { - nullpo_ret(sd); + nullpo_retr(ZString(), sd); - std::string *s = sd->regstrm.search(reg); + FString *s = sd->regstrm.search(reg); if (s) - return s->c_str(); + return *s; - return NULL; + return ZString(); } /*========================================== * script用文字列変数の値を設定 *------------------------------------------ */ -void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, const char *str) +void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, FString str) { nullpo_retv(sd); - if (!*str) + if (!str) { sd->regstrm.erase(reg); return; @@ -4133,7 +4134,7 @@ void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, const char *str) * script用グローバル変数の値を読む *------------------------------------------ */ -int pc_readglobalreg(dumb_ptr<map_session_data> sd, const char *reg) +int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; @@ -4141,7 +4142,7 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, const char *reg) for (i = 0; i < sd->status.global_reg_num; i++) { - if (strcmp(sd->status.global_reg[i].str, reg) == 0) + if (sd->status.global_reg[i].str == reg) return sd->status.global_reg[i].value; } @@ -4152,14 +4153,14 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, const char *reg) * script用グローバル変数の値を設定 *------------------------------------------ */ -int pc_setglobalreg(dumb_ptr<map_session_data> sd, const char *reg, int val) +int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; nullpo_ret(sd); //PC_DIE_COUNTERがスクリプトなどで変更された時の処理 - if (strcmp(reg, "PC_DIE_COUNTER") == 0 && sd->die_counter != val) + if (reg == stringish<VarName>("PC_DIE_COUNTER") && sd->die_counter != val) { sd->die_counter = val; pc_calcstatus(sd, 0); @@ -4168,7 +4169,7 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, const char *reg, int val) { for (i = 0; i < sd->status.global_reg_num; i++) { - if (strcmp(sd->status.global_reg[i].str, reg) == 0) + if (sd->status.global_reg[i].str == reg) { sd->status.global_reg[i] = sd->status.global_reg[sd->status.global_reg_num - 1]; @@ -4180,7 +4181,7 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, const char *reg, int val) } for (i = 0; i < sd->status.global_reg_num; i++) { - if (strcmp(sd->status.global_reg[i].str, reg) == 0) + if (sd->status.global_reg[i].str == reg) { sd->status.global_reg[i].value = val; return 0; @@ -4188,7 +4189,7 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, const char *reg, int val) } if (sd->status.global_reg_num < GLOBAL_REG_NUM) { - strcpy(sd->status.global_reg[i].str, reg); + sd->status.global_reg[i].str = reg; sd->status.global_reg[i].value = val; sd->status.global_reg_num++; return 0; @@ -4204,7 +4205,7 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, const char *reg, int val) * script用アカウント変数の値を読む *------------------------------------------ */ -int pc_readaccountreg(dumb_ptr<map_session_data> sd, const char *reg) +int pc_readaccountreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; @@ -4212,7 +4213,7 @@ int pc_readaccountreg(dumb_ptr<map_session_data> sd, const char *reg) for (i = 0; i < sd->status.account_reg_num; i++) { - if (strcmp(sd->status.account_reg[i].str, reg) == 0) + if (sd->status.account_reg[i].str == reg) return sd->status.account_reg[i].value; } @@ -4223,7 +4224,7 @@ int pc_readaccountreg(dumb_ptr<map_session_data> sd, const char *reg) * script用アカウント変数の値を設定 *------------------------------------------ */ -int pc_setaccountreg(dumb_ptr<map_session_data> sd, const char *reg, int val) +int pc_setaccountreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; @@ -4233,7 +4234,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, const char *reg, int val) { for (i = 0; i < sd->status.account_reg_num; i++) { - if (strcmp(sd->status.account_reg[i].str, reg) == 0) + if (sd->status.account_reg[i].str == reg) { sd->status.account_reg[i] = sd->status.account_reg[sd->status.account_reg_num - 1]; @@ -4246,7 +4247,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, const char *reg, int val) } for (i = 0; i < sd->status.account_reg_num; i++) { - if (strcmp(sd->status.account_reg[i].str, reg) == 0) + if (sd->status.account_reg[i].str == reg) { sd->status.account_reg[i].value = val; intif_saveaccountreg(sd); @@ -4255,7 +4256,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, const char *reg, int val) } if (sd->status.account_reg_num < ACCOUNT_REG_NUM) { - strcpy(sd->status.account_reg[i].str, reg); + sd->status.account_reg[i].str == reg; sd->status.account_reg[i].value = val; sd->status.account_reg_num++; intif_saveaccountreg(sd); @@ -4272,7 +4273,7 @@ int pc_setaccountreg(dumb_ptr<map_session_data> sd, const char *reg, int val) * script用アカウント変数2の値を読む *------------------------------------------ */ -int pc_readaccountreg2(dumb_ptr<map_session_data> sd, const char *reg) +int pc_readaccountreg2(dumb_ptr<map_session_data> sd, VarName reg) { int i; @@ -4280,7 +4281,7 @@ int pc_readaccountreg2(dumb_ptr<map_session_data> sd, const char *reg) for (i = 0; i < sd->status.account_reg2_num; i++) { - if (strcmp(sd->status.account_reg2[i].str, reg) == 0) + if (sd->status.account_reg2[i].str == reg) return sd->status.account_reg2[i].value; } @@ -4291,7 +4292,7 @@ int pc_readaccountreg2(dumb_ptr<map_session_data> sd, const char *reg) * script用アカウント変数2の値を設定 *------------------------------------------ */ -int pc_setaccountreg2(dumb_ptr<map_session_data> sd, const char *reg, int val) +int pc_setaccountreg2(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; @@ -4301,7 +4302,7 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, const char *reg, int val) { for (i = 0; i < sd->status.account_reg2_num; i++) { - if (strcmp(sd->status.account_reg2[i].str, reg) == 0) + if (sd->status.account_reg2[i].str == reg) { sd->status.account_reg2[i] = sd->status.account_reg2[sd->status.account_reg2_num - 1]; @@ -4314,7 +4315,7 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, const char *reg, int val) } for (i = 0; i < sd->status.account_reg2_num; i++) { - if (strcmp(sd->status.account_reg2[i].str, reg) == 0) + if (sd->status.account_reg2[i].str == reg) { sd->status.account_reg2[i].value = val; chrif_saveaccountreg2(sd); @@ -4323,7 +4324,7 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, const char *reg, int val) } if (sd->status.account_reg2_num < ACCOUNT_REG2_NUM) { - strcpy(sd->status.account_reg2[i].str, reg); + sd->status.account_reg2[i].str = reg; sd->status.account_reg2[i].value = val; sd->status.account_reg2_num++; chrif_saveaccountreg2(sd); @@ -4341,21 +4342,19 @@ int pc_setaccountreg2(dumb_ptr<map_session_data> sd, const char *reg, int val) *------------------------------------------ */ static -void pc_eventtimer(TimerData *, tick_t, int id, dumb_string data) +void pc_eventtimer(TimerData *, tick_t, int id, NpcEvent data) { dumb_ptr<map_session_data> sd = map_id2sd(id); assert (sd != NULL); - npc_event(sd, data.c_str(), 0); - - data.delete_(); + npc_event(sd, data, 0); } /*========================================== * イベントタイマー追加 *------------------------------------------ */ -int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, const char *name) +int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, NpcEvent name) { int i; @@ -4367,10 +4366,9 @@ int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, const char if (i < MAX_EVENTTIMER) { - dumb_string evname = dumb_string::copyn(name, 24); sd->eventtimer[i] = Timer(gettick() + tick, std::bind(pc_eventtimer, ph::_1, ph::_2, - sd->bl_id, evname)); + sd->bl_id, name)); return 1; } @@ -4869,13 +4867,12 @@ int pc_divorce(dumb_ptr<map_session_data> sd) dumb_ptr<map_session_data> pc_get_partner(dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> p_sd = NULL; - char *nick; if (sd == NULL || !pc_ismarried(sd)) return NULL; - nick = map_charid2nick(sd->status.partner_id); + CharName nick = map_charid2nick(sd->status.partner_id); - if (nick == NULL) + if (!nick.to__actual()) return NULL; if ((p_sd = map_nick2sd(nick)) == NULL) @@ -5167,11 +5164,11 @@ void pc_natural_heal(TimerData *, tick_t tick) * セーブポイントの保存 *------------------------------------------ */ -void pc_setsavepoint(dumb_ptr<map_session_data> sd, const char *mapname, int x, int y) +void pc_setsavepoint(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y) { nullpo_retv(sd); - strzcpy(sd->status.save_point.map_, mapname, 16); + sd->status.save_point.map_ = mapname; sd->status.save_point.x = x; sd->status.save_point.y = y; } @@ -5316,7 +5313,7 @@ int pc_logout(dumb_ptr<map_session_data> sd) // [fate] Player logs out } else #endif - pc_setglobalreg(sd, "MAGIC_CAST_TICK", 0); + pc_setglobalreg(sd, stringish<VarName>("MAGIC_CAST_TICK"), 0); MAP_LOG_STATS(sd, "LOGOUT"); return 0; diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 4ebfa1b..4796011 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -62,8 +62,8 @@ int pc_checkequip(dumb_ptr<map_session_data> sd, EPOS pos); int pc_walktoxy(dumb_ptr<map_session_data>, int, int); int pc_stop_walking(dumb_ptr<map_session_data>, int); int pc_movepos(dumb_ptr<map_session_data>, int, int); -int pc_setpos(dumb_ptr<map_session_data>, const char *, int, int, BeingRemoveWhy); -void pc_setsavepoint(dumb_ptr<map_session_data>, const char *, int, int); +int pc_setpos(dumb_ptr<map_session_data>, MapName, int, int, BeingRemoveWhy); +void pc_setsavepoint(dumb_ptr<map_session_data>, MapName, int, int); int pc_randomwarp(dumb_ptr<map_session_data> sd, BeingRemoveWhy type); ADDITEM pc_checkadditem(dumb_ptr<map_session_data>, int, int); @@ -120,17 +120,17 @@ int pc_readparam(dumb_ptr<map_session_data>, SP); int pc_setparam(dumb_ptr<map_session_data>, SP, int); int pc_readreg(dumb_ptr<map_session_data>, SIR); void pc_setreg(dumb_ptr<map_session_data>, SIR, int); -const char *pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg); -void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, const char *str); -int pc_readglobalreg(dumb_ptr<map_session_data>, const char *); -int pc_setglobalreg(dumb_ptr<map_session_data>, const char *, int); -int pc_readaccountreg(dumb_ptr<map_session_data>, const char *); -int pc_setaccountreg(dumb_ptr<map_session_data>, const char *, int); -int pc_readaccountreg2(dumb_ptr<map_session_data>, const char *); -int pc_setaccountreg2(dumb_ptr<map_session_data>, const char *, int); +ZString pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg); +void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, FString str); +int pc_readglobalreg(dumb_ptr<map_session_data>, VarName ); +int pc_setglobalreg(dumb_ptr<map_session_data>, VarName , int); +int pc_readaccountreg(dumb_ptr<map_session_data>, VarName ); +int pc_setaccountreg(dumb_ptr<map_session_data>, VarName , int); +int pc_readaccountreg2(dumb_ptr<map_session_data>, VarName ); +int pc_setaccountreg2(dumb_ptr<map_session_data>, VarName , int); int pc_addeventtimer(dumb_ptr<map_session_data> sd, interval_t tick, - const char *name); + NpcEvent name); int pc_cleareventtimer(dumb_ptr<map_session_data> sd); int pc_calc_pvprank(dumb_ptr<map_session_data> sd); diff --git a/src/map/script.cpp b/src/map/script.cpp index 854a42f..e82c843 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -13,6 +13,7 @@ #include "../common/db.hpp" #include "../common/extract.hpp" #include "../common/intern-pool.hpp" +#include "../common/io.hpp" #include "../common/lock.hpp" #include "../common/random.hpp" #include "../common/socket.hpp" @@ -42,27 +43,27 @@ constexpr bool DEBUG_RUN = false; struct str_data_t { ByteCode type; - std::string strs; + FString strs; int backpatch; int label_; int val; }; static -Map<std::string, str_data_t> str_datam; +Map<FString, str_data_t> str_datam; static str_data_t LABEL_NEXTLINE_; static DMap<SIR, int> mapreg_db; static -Map<SIR, std::string> mapregstr_db; +Map<SIR, FString> mapregstr_db; static int mapreg_dirty = -1; -char mapreg_txt[256] = "save/mapreg.txt"; +FString mapreg_txt = "save/mapreg.txt"; constexpr std::chrono::milliseconds MAPREG_AUTOSAVE_INTERVAL = std::chrono::seconds(10); -Map<std::string, int> scriptlabel_db; -UPMap<std::string, const ScriptBuffer> userfunc_db; +Map<ScriptLabel, int> scriptlabel_db; +UPMap<FString, const ScriptBuffer> userfunc_db; static const char *pos[11] = @@ -101,13 +102,13 @@ void run_func(ScriptState *st); static void mapreg_setreg(SIR num, int val); static -void mapreg_setregstr(SIR num, const char *str); +void mapreg_setregstr(SIR num, XString str); struct BuiltinFunction { void (*func)(ScriptState *); - const char *name; - const char *arg; + ZString name; + ZString arg; }; // defined later extern BuiltinFunction builtin_functions[]; @@ -132,29 +133,21 @@ enum class ByteCode : uint8_t }; static -str_data_t *search_strp(const std::string& p) +str_data_t *search_strp(XString p) { return str_datam.search(p); } static -str_data_t *add_strp(const std::string& p) +str_data_t *add_strp(XString p) { - // TODO remove lowcase - std::string lowcase = p; - for (char& c : lowcase) - c = tolower(c); - - if (str_data_t *rv = search_strp(lowcase)) - return rv; - - // ? if (str_data_t *rv = search_strp(p)) return rv; - str_data_t *datum = str_datam.init(p); + FString p2 = p; + str_data_t *datum = str_datam.init(p2); datum->type = ByteCode::NOP; - datum->strs = p; + datum->strs = p2; datum->backpatch = -1; datum->label_ = -1; return datum; @@ -266,7 +259,7 @@ void ScriptBuffer::set_label(str_data_t *ld, int pos_) *------------------------------------------ */ static -const char *skip_space(const char *p) +ZString::iterator skip_space(ZString::iterator p) { while (1) { @@ -296,7 +289,7 @@ const char *skip_space(const char *p) *------------------------------------------ */ static -const char *skip_word(const char *p) +ZString::iterator skip_word(ZString::iterator p) { // prefix if (*p == '$') @@ -320,8 +313,10 @@ const char *skip_word(const char *p) return p; } +// TODO: replace this whole mess with some sort of input stream that works +// a line at a time. static -const char *startptr; +ZString startptr; static int startline; @@ -331,30 +326,23 @@ int script_errors = 0; *------------------------------------------ */ static -void disp_error_message(const char *mes, const char *pos_) +void disp_error_message(ZString mes, ZString::iterator pos_) { script_errors++; + assert (startptr.begin() <= pos_ && pos_ <= startptr.end()); + int line; - const char *p; + ZString::iterator p; - for (line = startline, p = startptr; p && *p; line++) + for (line = startline, p = startptr.begin(); p != startptr.end(); line++) { - const char *linestart = p; - char *lineend = const_cast<char *>(strchr(p, '\n')); - // always initialized, but clang is not smart enough - char c = '\0'; - if (lineend) - { - c = *lineend; - *lineend = 0; - } - if (lineend == NULL || pos_ < lineend) + ZString::iterator linestart = p; + ZString::iterator lineend = std::find(p, startptr.end(), '\n'); + if (pos_ < lineend) { PRINTF("\n%s\nline %d : ", mes, line); - for (int i = 0; - (linestart[i] != '\r') && (linestart[i] != '\n') - && linestart[i]; i++) + for (int i = 0; linestart + i != lineend; i++) { if (linestart + i != pos_) PRINTF("%c", linestart[i]); @@ -362,11 +350,8 @@ void disp_error_message(const char *mes, const char *pos_) PRINTF("\'%c\'", linestart[i]); } PRINTF("\a\n"); - if (lineend) - *lineend = c; return; } - *lineend = c; p = lineend + 1; } } @@ -375,9 +360,8 @@ void disp_error_message(const char *mes, const char *pos_) * 項の解析 *------------------------------------------ */ -const char *ScriptBuffer::parse_simpleexpr(const char *p) +ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p) { - int i; p = skip_space(p); if (*p == ';' || *p == ',') @@ -399,9 +383,9 @@ const char *ScriptBuffer::parse_simpleexpr(const char *p) else if (isdigit(*p) || ((*p == '-' || *p == '+') && isdigit(p[1]))) { char *np; - i = strtoul(p, &np, 0); + int i = strtoul(&*p, &np, 0); add_scripti(i); - p = np; + p += np - &*p; } else if (*p == '"') { @@ -409,7 +393,7 @@ const char *ScriptBuffer::parse_simpleexpr(const char *p) p++; while (*p && *p != '"') { - if (p[-1] <= 0x7e && *p == '\\') + if (*p == '\\') p++; else if (*p == '\n') { @@ -429,13 +413,13 @@ const char *ScriptBuffer::parse_simpleexpr(const char *p) else { // label , register , function etc - const char *p2 = skip_word(p); + ZString::iterator p2 = skip_word(p); if (p2 == p) { disp_error_message("unexpected character", p); exit(1); } - std::string word(p, p2); + XString word(&*p, &*p2, nullptr); if (parse_cmd_if && (word == "callsub" || word == "callfunc")) { disp_error_message("callsub/callfunc not allowed in an if statement", p); @@ -476,7 +460,7 @@ const char *ScriptBuffer::parse_simpleexpr(const char *p) * 式の解析 *------------------------------------------ */ -const char *ScriptBuffer::parse_subexpr(const char *p, int limit) +ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit) { ByteCode op; int opl, len; @@ -485,7 +469,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) if (*p == '-') { - const char *tmpp = skip_space(p + 1); + ZString::iterator tmpp = skip_space(p + 1); if (*tmpp == ';' || *tmpp == ',') { add_scriptl(&LABEL_NEXTLINE_); @@ -493,7 +477,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) return p; } } - const char *tmpp = p; + ZString::iterator tmpp = p; if ((op = ByteCode::NEG, *p == '-') || (op = ByteCode::LNOT, *p == '!') || (op = ByteCode::NOT, *p == '~')) { @@ -528,7 +512,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) { int i = 0; str_data_t *funcp = parse_cmdp; - const char *plist[128]; + ZString::iterator plist[128]; if (funcp->type != ByteCode::FUNC_) { @@ -563,7 +547,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) if (funcp->type == ByteCode::FUNC_ && script_config.warn_func_mismatch_paramnum) { - const char *arg = builtin_functions[funcp->val].arg; + ZString arg = builtin_functions[funcp->val].arg; int j = 0; for (j = 0; arg[j]; j++) if (arg[j] == '*') @@ -571,7 +555,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) if ((arg[j] == 0 && i != j) || (arg[j] == '*' && i < j)) { disp_error_message("illegal number of parameters", - plist[(i < j) ? i : j]); + plist[std::min(i, j)]); } } } @@ -589,7 +573,7 @@ const char *ScriptBuffer::parse_subexpr(const char *p, int limit) * 式の評価 *------------------------------------------ */ -const char *ScriptBuffer::parse_expr(const char *p) +ZString::iterator ScriptBuffer::parse_expr(ZString::iterator p) { switch (*p) { @@ -610,10 +594,10 @@ const char *ScriptBuffer::parse_expr(const char *p) * 行の解析 *------------------------------------------ */ -const char *ScriptBuffer::parse_line(const char *p) +ZString::iterator ScriptBuffer::parse_line(ZString::iterator p) { int i = 0; - const char *plist[128]; + ZString::iterator plist[128]; p = skip_space(p); if (*p == ';') @@ -622,7 +606,7 @@ const char *ScriptBuffer::parse_line(const char *p) parse_cmd_if = 0; // warn_cmd_no_commaのために必要 // 最初は関数名 - const char *p2 = p; + ZString::iterator p2 = p; p = parse_simpleexpr(p); p = skip_space(p); @@ -634,7 +618,7 @@ const char *ScriptBuffer::parse_line(const char *p) } add_scriptc(ByteCode::ARG); - while (p && *p && *p != ';' && i < 128) + while (*p && *p != ';' && i < 128) { plist[i] = p; @@ -652,7 +636,7 @@ const char *ScriptBuffer::parse_line(const char *p) i++; } plist[i] = p; - if (!p || *(p++) != ';') + if (*(p++) != ';') { disp_error_message("need ';'", p); exit(1); @@ -662,7 +646,7 @@ const char *ScriptBuffer::parse_line(const char *p) if (cmd->type == ByteCode::FUNC_ && script_config.warn_cmd_mismatch_paramnum) { - const char *arg = builtin_functions[cmd->val].arg; + ZString arg = builtin_functions[cmd->val].arg; int j = 0; for (j = 0; arg[j]; j++) if (arg[j] == '*') @@ -670,7 +654,7 @@ const char *ScriptBuffer::parse_line(const char *p) if ((arg[j] == 0 && i != j) || (arg[j] == '*' && i < j)) { disp_error_message("illegal number of parameters", - plist[(i < j) ? i : j]); + plist[std::min(i, j)]); } } @@ -706,26 +690,24 @@ void read_constdb(void) return; } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - if (line[0] == '/' && line[1] == '/') + if (line.startswith("//")) continue; - std::string name; + FString name; int val; int type = 0; // if not provided if (SSCANF(line, "%m[A-Za-z0-9_] %i %i", &name, &val, &type) < 2) continue; - for (char& c : name) - c = tolower(c); str_data_t *n = add_strp(name); n->type = type ? ByteCode::PARAM_ : ByteCode::INT; n->val = val; } } -std::unique_ptr<const ScriptBuffer> parse_script(const char *src, int line) +std::unique_ptr<const ScriptBuffer> parse_script(ZString src, int line) { auto script_buf = make_unique<ScriptBuffer>(); script_buf->parse_script(src, line); @@ -736,9 +718,8 @@ std::unique_ptr<const ScriptBuffer> parse_script(const char *src, int line) * スクリプトの解析 *------------------------------------------ */ -void ScriptBuffer::parse_script(const char *src, int line) +void ScriptBuffer::parse_script(ZString src, int line) { - const char *p; static int first = 1; if (first) @@ -768,21 +749,20 @@ void ScriptBuffer::parse_script(const char *src, int line) startptr = src; startline = line; - p = src; + ZString::iterator p = src.begin(); p = skip_space(p); if (*p != '{') { disp_error_message("not found '{'", p); abort(); } - for (p++; p && *p && *p != '}';) + for (p++; *p && *p != '}';) { p = skip_space(p); - // labelだけ特殊処理 if (*skip_space(skip_word(p)) == ':') { - const char *tmpp = skip_word(p); - std::string str(p, tmpp); + ZString::iterator tmpp = skip_word(p); + XString str(&*p, &*tmpp, nullptr); str_data_t *ld = add_strp(str); bool e1 = ld->type != ByteCode::NOP; bool e2 = ld->type == ByteCode::POS; @@ -794,7 +774,7 @@ void ScriptBuffer::parse_script(const char *src, int line) exit(1); } set_label(ld, script_buf.size()); - scriptlabel_db.insert(str, script_buf.size()); + scriptlabel_db.insert(stringish<ScriptLabel>(str), script_buf.size()); p = tmpp + 1; continue; } @@ -894,7 +874,8 @@ void get_val(ScriptState *st, struct script_data *data) } else if (data->type == ByteCode::VARIABLE) { - const std::string& name = variable_names.outtern(data->u.reg.base()); + ZString name_ = variable_names.outtern(data->u.reg.base()); + VarName name = stringish<VarName>(name_); char prefix = name.front(); char postfix = name.back(); @@ -913,8 +894,8 @@ void get_val(ScriptState *st, struct script_data *data) } else if (prefix == '$') { - std::string *s = mapregstr_db.search(data->u.reg); - data->u.str = s ? dumb_string::fake(s->c_str()) : dumb_string(); + FString *s = mapregstr_db.search(data->u.reg); + data->u.str = s ? dumb_string::fake(*s) : dumb_string(); } else { @@ -941,18 +922,18 @@ void get_val(ScriptState *st, struct script_data *data) if (name[1] == '#') { if (sd) - data->u.numi = pc_readaccountreg2(sd, name.c_str()); + data->u.numi = pc_readaccountreg2(sd, name); } else { if (sd) - data->u.numi = pc_readaccountreg(sd, name.c_str()); + data->u.numi = pc_readaccountreg(sd, name); } } else { if (sd) - data->u.numi = pc_readglobalreg(sd, name.c_str()); + data->u.numi = pc_readglobalreg(sd, name); } } } @@ -988,7 +969,8 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip } assert (type == ByteCode::VARIABLE); - const std::string& name = variable_names.outtern(reg.base()); + ZString name_ = variable_names.outtern(reg.base()); + VarName name = stringish<VarName>(name_); char prefix = name.front(); char postfix = name.back(); @@ -997,11 +979,11 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip dumb_string str = vd.u.str; if (prefix == '@' || prefix == 'l') { - pc_setregstr(sd, reg, str.c_str()); + pc_setregstr(sd, reg, str.str()); } else if (prefix == '$') { - mapreg_setregstr(reg, str.c_str()); + mapreg_setregstr(reg, str.str()); } else { @@ -1023,13 +1005,13 @@ void set_reg(dumb_ptr<map_session_data> sd, ByteCode type, SIR reg, struct scrip else if (prefix == '#') { if (name[1] == '#') - pc_setaccountreg2(sd, name.c_str(), val); + pc_setaccountreg2(sd, name, val); else - pc_setaccountreg(sd, name.c_str(), val); + pc_setaccountreg(sd, name, val); } else { - pc_setglobalreg(sd, name.c_str(), val); + pc_setglobalreg(sd, name, val); } } } @@ -1063,7 +1045,7 @@ dumb_string conv_str(ScriptState *st, struct script_data *data) assert (data->type != ByteCode::RETINFO); if (data->type == ByteCode::INT) { - std::string buf = STRPRINTF("%d", data->u.numi); + FString buf = STRPRINTF("%d", data->u.numi); data->type = ByteCode::STR; data->u.str = dumb_string::copys(buf); } @@ -1193,7 +1175,7 @@ static void builtin_mes(ScriptState *st) { dumb_string mes = conv_str(st, &AARGO2(2)); - clif_scriptmes(script_rid2sd(st), st->oid, mes.c_str()); + clif_scriptmes(script_rid2sd(st), st->oid, ZString(mes)); } /*========================================== @@ -1334,17 +1316,17 @@ void builtin_menu(ScriptState *st) st->state = ScriptEndState::RERUNLINE; sd->state.menu_or_input = 1; - std::string buf; + MString buf; for (int i = st->start + 2; i < st->end; i += 2) { dumb_string choice_str = conv_str(st, &AARGO2(i - st->start)); if (!choice_str[0]) break; - buf += choice_str.c_str(); + buf += ZString(choice_str); buf += ':'; } - clif_scriptmenu(script_rid2sd(st), st->oid, buf.c_str()); + clif_scriptmenu(script_rid2sd(st), st->oid, FString(buf)); } else { @@ -1427,14 +1409,13 @@ void builtin_isat(ScriptState *st) int x, y; dumb_ptr<map_session_data> sd = script_rid2sd(st); - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); if (!sd) return; - using namespace operators; push_int(st->stack, ByteCode::INT, (x == sd->bl_x) && (y == sd->bl_y) && (str == sd->bl_m->name_)); @@ -1450,10 +1431,9 @@ void builtin_warp(ScriptState *st) int x, y; dumb_ptr<map_session_data> sd = script_rid2sd(st); - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); - using namespace operators; if (str == "Random") pc_randomwarp(sd, BeingRemoveWhy::WARPED); else if (str == "SavePoint") @@ -1461,19 +1441,19 @@ void builtin_warp(ScriptState *st) if (sd->bl_m->flag.noreturn) // 蝶禁止 return; - pc_setpos(sd, sd->status.save_point.map_, - sd->status.save_point.x, sd->status.save_point.y, BeingRemoveWhy::WARPED); + pc_setpos(sd, sd->status.save_point.map_, sd->status.save_point.x, sd->status.save_point.y, + BeingRemoveWhy::WARPED); } else if (str == "Save") { if (sd->bl_m->flag.noreturn) // 蝶禁止 return; - pc_setpos(sd, sd->status.save_point.map_, - sd->status.save_point.x, sd->status.save_point.y, BeingRemoveWhy::WARPED); + pc_setpos(sd, sd->status.save_point.map_, sd->status.save_point.x, sd->status.save_point.y, + BeingRemoveWhy::WARPED); } else - pc_setpos(sd, str.c_str(), x, y, BeingRemoveWhy::GONE); + pc_setpos(sd, str, x, y, BeingRemoveWhy::GONE); } /*========================================== @@ -1481,14 +1461,13 @@ void builtin_warp(ScriptState *st) *------------------------------------------ */ static -void builtin_areawarp_sub(dumb_ptr<block_list> bl, dumb_string mapname, int x, int y) +void builtin_areawarp_sub(dumb_ptr<block_list> bl, MapName mapname, int x, int y) { dumb_ptr<map_session_data> sd = bl->as_player(); - using namespace operators; if (mapname == "Random") pc_randomwarp(sd, BeingRemoveWhy::WARPED); else - pc_setpos(sd, mapname.c_str(), x, y, BeingRemoveWhy::GONE); + pc_setpos(sd, mapname, x, y, BeingRemoveWhy::GONE); } static @@ -1497,16 +1476,16 @@ void builtin_areawarp(ScriptState *st) int x, y; int x0, y0, x1, y1; - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = conv_num(st, &AARGO2(3)); y0 = conv_num(st, &AARGO2(4)); x1 = conv_num(st, &AARGO2(5)); y1 = conv_num(st, &AARGO2(6)); - dumb_string str = conv_str(st, &AARGO2(7)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(7)))); x = conv_num(st, &AARGO2(8)); y = conv_num(st, &AARGO2(9)); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return; @@ -1572,7 +1551,7 @@ void builtin_input(ScriptState *st) assert (type == ByteCode::VARIABLE); SIR reg = scrd.u.reg; - const std::string& name = variable_names.outtern(reg.base()); + ZString name = variable_names.outtern(reg.base()); // char prefix = name.front(); char postfix = name.back(); @@ -1583,7 +1562,7 @@ void builtin_input(ScriptState *st) sd->state.menu_or_input = 0; if (postfix == '$') { - set_reg(sd, type, reg, dumb_string::fake(sd->npc_str.c_str())); + set_reg(sd, type, reg, dumb_string::fake(sd->npc_str)); } else { @@ -1653,7 +1632,7 @@ void builtin_set(ScriptState *st) set_reg(sd, ByteCode::PARAM_, reg, val); return; } - const std::string& name = variable_names.outtern(reg.base()); + ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); @@ -1687,7 +1666,7 @@ void builtin_setarray(ScriptState *st) dumb_ptr<map_session_data> sd = NULL; assert (AARGO2(2).type == ByteCode::VARIABLE); SIR reg = AARGO2(2).u.reg; - const std::string& name = variable_names.outtern(reg.base()); + ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); @@ -1718,7 +1697,7 @@ void builtin_cleararray(ScriptState *st) dumb_ptr<map_session_data> sd = NULL; assert (AARGO2(2).type == ByteCode::VARIABLE); SIR reg = AARGO2(2).u.reg; - const std::string& name = variable_names.outtern(reg.base()); + ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); int sz = conv_num(st, &AARGO2(4)); @@ -1764,7 +1743,7 @@ void builtin_getarraysize(ScriptState *st) { assert (AARGO2(2).type == ByteCode::VARIABLE); SIR reg = AARGO2(2).u.reg; - const std::string& name = variable_names.outtern(reg.base()); + ZString name = variable_names.outtern(reg.base()); char prefix = name.front(); char postfix = name.back(); @@ -1838,8 +1817,8 @@ void builtin_countitem(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); if (item_data != NULL) nameid = item_data->nameid; } @@ -1878,8 +1857,8 @@ void builtin_checkweight(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); if (item_data) nameid = item_data->nameid; } @@ -1922,8 +1901,8 @@ void builtin_getitem(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); nameid = 727; //Default to iten if (item_data != NULL) nameid = item_data->nameid; @@ -1976,8 +1955,8 @@ void builtin_makeitem(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); nameid = 512; //Apple Item ID if (item_data) nameid = item_data->nameid; @@ -1986,16 +1965,15 @@ void builtin_makeitem(ScriptState *st) nameid = conv_num(st, data); amount = conv_num(st, &AARGO2(3)); - dumb_string mapname = conv_str(st, &AARGO2(4)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(4)))); x = conv_num(st, &AARGO2(5)); y = conv_num(st, &AARGO2(6)); map_local *m; - using namespace operators; - if (sd && mapname == "this") + if (sd && mapname == MOB_THIS_MAP) m = sd->bl_m; else - m = map_mapname2mapid(mapname.c_str()); + m = map_mapname2mapid(mapname); if (nameid > 0) { @@ -2028,8 +2006,8 @@ void builtin_delitem(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); //nameid=512; if (item_data) nameid = item_data->nameid; @@ -2087,7 +2065,7 @@ void builtin_readparam(ScriptState *st) SP type = SP(conv_num(st, &AARGO2(2))); if (HARGO2(3)) - sd = map_nick2sd(conv_str(st, &AARGO2(3)).c_str()); + sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARGO2(3))))); else sd = script_rid2sd(st); @@ -2113,7 +2091,7 @@ void builtin_getcharid(ScriptState *st) num = conv_num(st, &AARGO2(2)); if (HARGO2(3)) - sd = map_nick2sd(conv_str(st, &AARGO2(3)).c_str()); + sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARGO2(3))))); else sd = script_rid2sd(st); if (sd == NULL) @@ -2141,7 +2119,7 @@ dumb_string builtin_getpartyname_sub(int party_id) struct party *p = party_search(party_id); if (p) - return dumb_string::copy(p->name); + return dumb_string::copys(p->name); return dumb_string(); } @@ -2160,7 +2138,7 @@ void builtin_strcharinfo(ScriptState *st) num = conv_num(st, &AARGO2(2)); if (num == 0) { - dumb_string buf = dumb_string::copy(sd->status.name); + dumb_string buf = dumb_string::copys(sd->status.name.to__actual()); push_str(st->stack, ByteCode::STR, buf); } if (num == 1) @@ -2240,7 +2218,7 @@ void builtin_getequipname(ScriptState *st) dumb_ptr<map_session_data> sd; struct item_data *item; - std::string buf; + FString buf; sd = script_rid2sd(st); num = conv_num(st, &AARGO2(2)); @@ -2418,10 +2396,10 @@ void builtin_savepoint(ScriptState *st) { int x, y; - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); - pc_setsavepoint(script_rid2sd(st), str.c_str(), x, y); + pc_setsavepoint(script_rid2sd(st), str, x, y); } /*========================================== @@ -2551,19 +2529,19 @@ static void builtin_monster(ScriptState *st) { int mob_class, amount, x, y; - const char *event = ""; + NpcEvent event; - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x = conv_num(st, &AARGO2(3)); y = conv_num(st, &AARGO2(4)); - dumb_string str = conv_str(st, &AARGO2(5)); + MobName str = stringish<MobName>(ZString(conv_str(st, &AARGO2(5)))); mob_class = conv_num(st, &AARGO2(6)); amount = conv_num(st, &AARGO2(7)); if (HARGO2(8)) - event = conv_str(st, &AARGO2(8)).c_str(); + extract(ZString(conv_str(st, &AARGO2(8))), &event); - mob_once_spawn(map_id2sd(st->rid), mapname.c_str(), x, y, str.c_str(), mob_class, amount, - event); + mob_once_spawn(map_id2sd(st->rid), mapname, x, y, str, mob_class, amount, + event); } /*========================================== @@ -2574,21 +2552,21 @@ static void builtin_areamonster(ScriptState *st) { int mob_class, amount, x0, y0, x1, y1; - const char *event = ""; + NpcEvent event; - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = conv_num(st, &AARGO2(3)); y0 = conv_num(st, &AARGO2(4)); x1 = conv_num(st, &AARGO2(5)); y1 = conv_num(st, &AARGO2(6)); - dumb_string str = conv_str(st, &AARGO2(7)); + MobName str = stringish<MobName>(ZString(conv_str(st, &AARGO2(7)))); mob_class = conv_num(st, &AARGO2(8)); amount = conv_num(st, &AARGO2(9)); if (HARGO2(10)) - event = conv_str(st, &AARGO2(10)).c_str(); + extract(ZString(conv_str(st, &AARGO2(10))), &event); - mob_once_spawn_area(map_id2sd(st->rid), mapname.c_str(), x0, y0, x1, y1, str.c_str(), mob_class, - amount, event); + mob_once_spawn_area(map_id2sd(st->rid), mapname, x0, y0, x1, y1, str, mob_class, + amount, event); } /*========================================== @@ -2596,17 +2574,16 @@ void builtin_areamonster(ScriptState *st) *------------------------------------------ */ static -void builtin_killmonster_sub(dumb_ptr<block_list> bl, dumb_string event, int allflag) +void builtin_killmonster_sub(dumb_ptr<block_list> bl, NpcEvent event) { dumb_ptr<mob_data> md = bl->as_mob(); - if (!allflag) + if (event) { - using namespace operators; if (event == md->npc_event) mob_delete(md); return; } - else if (allflag) + else if (!event) { if (md->spawn.delay1 == static_cast<interval_t>(-1) && md->spawn.delay2 == static_cast<interval_t>(-1)) @@ -2618,17 +2595,16 @@ void builtin_killmonster_sub(dumb_ptr<block_list> bl, dumb_string event, int all static void builtin_killmonster(ScriptState *st) { - int allflag = 0; - dumb_string mapname = conv_str(st, &AARGO2(2)); - dumb_string event = conv_str(st, &AARGO2(3)); - using namespace operators; - if (event == "All") - allflag = 1; + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + ZString event_ = ZString(conv_str(st, &AARGO2(3))); + NpcEvent event; + if (event_ != "All") + extract(event_, &event); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return; - map_foreachinarea(std::bind(builtin_killmonster_sub, ph::_1, event, allflag), + map_foreachinarea(std::bind(builtin_killmonster_sub, ph::_1, event), m, 0, 0, m->xs, m->ys, @@ -2644,9 +2620,9 @@ void builtin_killmonsterall_sub(dumb_ptr<block_list> bl) static void builtin_killmonsterall(ScriptState *st) { - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return; map_foreachinarea(builtin_killmonsterall_sub, @@ -2663,8 +2639,10 @@ void builtin_killmonsterall(ScriptState *st) static void builtin_donpcevent(ScriptState *st) { - dumb_string event = conv_str(st, &AARGO2(2)); - npc_event_do(event.c_str()); + ZString event_ = ZString(conv_str(st, &AARGO2(2))); + NpcEvent event; + extract(event_, &event); + npc_event_do(event); } /*========================================== @@ -2675,8 +2653,10 @@ static void builtin_addtimer(ScriptState *st) { interval_t tick = static_cast<interval_t>(conv_num(st, &AARGO2(2))); - dumb_string event = conv_str(st, &AARGO2(3)); - pc_addeventtimer(script_rid2sd(st), tick, event.c_str()); + ZString event_ = ZString(conv_str(st, &AARGO2(3))); + NpcEvent event; + extract(event_, &event); + pc_addeventtimer(script_rid2sd(st), tick, event); } /*========================================== @@ -2688,7 +2668,7 @@ void builtin_initnpctimer(ScriptState *st) { dumb_ptr<npc_data> nd_; if (HARGO2(2)) - nd_ = npc_name2id(conv_str(st, &AARGO2(2)).c_str()); + nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(2))))); else nd_ = map_id_as_npc(st->oid); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); @@ -2707,7 +2687,7 @@ void builtin_startnpctimer(ScriptState *st) { dumb_ptr<npc_data> nd_; if (HARGO2(2)) - nd_ = npc_name2id(conv_str(st, &AARGO2(2)).c_str()); + nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(2))))); else nd_ = map_id_as_npc(st->oid); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); @@ -2725,7 +2705,7 @@ void builtin_stopnpctimer(ScriptState *st) { dumb_ptr<npc_data> nd_; if (HARGO2(2)) - nd_ = npc_name2id(conv_str(st, &AARGO2(2)).c_str()); + nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(2))))); else nd_ = map_id_as_npc(st->oid); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); @@ -2745,7 +2725,7 @@ void builtin_getnpctimer(ScriptState *st) int type = conv_num(st, &AARGO2(2)); int val = 0; if (HARGO2(3)) - nd_ = npc_name2id(conv_str(st, &AARGO2(3)).c_str()); + nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(3))))); else nd_ = map_id_as_npc(st->oid); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); @@ -2776,7 +2756,7 @@ void builtin_setnpctimer(ScriptState *st) dumb_ptr<npc_data> nd_; interval_t tick = static_cast<interval_t>(conv_num(st, &AARGO2(2))); if (HARGO2(3)) - nd_ = npc_name2id(conv_str(st, &AARGO2(3)).c_str()); + nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(3))))); else nd_ = map_id_as_npc(st->oid); assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT); @@ -2793,7 +2773,7 @@ static void builtin_announce(ScriptState *st) { int flag; - dumb_string str = conv_str(st, &AARGO2(2)); + ZString str = ZString(conv_str(st, &AARGO2(2))); flag = conv_num(st, &AARGO2(3)); if (flag & 0x0f) @@ -2814,7 +2794,7 @@ void builtin_announce(ScriptState *st) *------------------------------------------ */ static -void builtin_mapannounce_sub(dumb_ptr<block_list> bl, dumb_string str, int flag) +void builtin_mapannounce_sub(dumb_ptr<block_list> bl, XString str, int flag) { clif_GMmessage(bl, str, flag | 3); } @@ -2824,11 +2804,11 @@ void builtin_mapannounce(ScriptState *st) { int flag; - dumb_string mapname = conv_str(st, &AARGO2(2)); - dumb_string str = conv_str(st, &AARGO2(3)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + ZString str = ZString(conv_str(st, &AARGO2(3))); flag = conv_num(st, &AARGO2(4)); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return; map_foreachinarea(std::bind(builtin_mapannounce_sub, ph::_1, str, flag & 0x10), @@ -2867,8 +2847,8 @@ void builtin_getusers(ScriptState *st) static void builtin_getmapusers(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); - map_local *m = map_mapname2mapid(str.c_str()); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + map_local *m = map_mapname2mapid(str); if (m == nullptr) { push_int(st->stack, ByteCode::INT, -1); @@ -2898,7 +2878,7 @@ static void builtin_getareausers(ScriptState *st) { int x0, y0, x1, y1, users = 0; - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = conv_num(st, &AARGO2(3)); y0 = conv_num(st, &AARGO2(4)); x1 = conv_num(st, &AARGO2(5)); @@ -2909,7 +2889,7 @@ void builtin_getareausers(ScriptState *st) { living = conv_num(st, &AARGO2(7)); } - map_local *m = map_mapname2mapid(str.c_str()); + map_local *m = map_mapname2mapid(str); if (m == nullptr) { push_int(st->stack, ByteCode::INT, -1); @@ -2956,7 +2936,7 @@ void builtin_getareadropitem(ScriptState *st) int x0, y0, x1, y1, item, amount = 0, delitems = 0; struct script_data *data; - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = conv_num(st, &AARGO2(3)); y0 = conv_num(st, &AARGO2(4)); x1 = conv_num(st, &AARGO2(5)); @@ -2966,8 +2946,8 @@ void builtin_getareadropitem(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - struct item_data *item_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + struct item_data *item_data = itemdb_searchname(name); item = 512; if (item_data) item = item_data->nameid; @@ -2978,7 +2958,7 @@ void builtin_getareadropitem(ScriptState *st) if (HARGO2(8)) delitems = conv_num(st, &AARGO2(8)); - map_local *m = map_mapname2mapid(str.c_str()); + map_local *m = map_mapname2mapid(str); if (m == nullptr) { push_int(st->stack, ByteCode::INT, -1); @@ -3007,8 +2987,8 @@ void builtin_getareadropitem(ScriptState *st) static void builtin_enablenpc(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); - npc_enable(str.c_str(), 1); + NpcName str = stringish<NpcName>(ZString(conv_str(st, &AARGO2(2)))); + npc_enable(str, 1); } /*========================================== @@ -3018,8 +2998,8 @@ void builtin_enablenpc(ScriptState *st) static void builtin_disablenpc(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); - npc_enable(str.c_str(), 0); + NpcName str = stringish<NpcName>(ZString(conv_str(st, &AARGO2(2)))); + npc_enable(str, 0); } /*========================================== @@ -3118,7 +3098,7 @@ void builtin_changesex(ScriptState *st) sd->status.sex = 0; sd->sex = 0; } - chrif_char_ask_name(-1, sd->status.name, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex + chrif_char_ask_name(-1, sd->status.name, 5, HumanTimeDiff()); // type: 5 - changesex chrif_save(sd); } @@ -3187,9 +3167,9 @@ enum static void builtin_setmapflag(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); int i = conv_num(st, &AARGO2(3)); - map_local *m = map_mapname2mapid(str.c_str()); + map_local *m = map_mapname2mapid(str); if (m != nullptr) { switch (i) @@ -3247,9 +3227,9 @@ void builtin_setmapflag(ScriptState *st) static void builtin_removemapflag(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); int i = conv_num(st, &AARGO2(3)); - map_local *m = map_mapname2mapid(str.c_str()); + map_local *m = map_mapname2mapid(str); if (m != nullptr) { switch (i) @@ -3308,9 +3288,9 @@ void builtin_getmapflag(ScriptState *st) { int r = -1; - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); int i = conv_num(st, &AARGO2(3)); - map_local *m = map_mapname2mapid(str.c_str()); + map_local *m = map_mapname2mapid(str); if (m != nullptr) { switch (i) @@ -3369,8 +3349,8 @@ void builtin_getmapflag(ScriptState *st) static void builtin_pvpon(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); - map_local *m = map_mapname2mapid(str.c_str()); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + map_local *m = map_mapname2mapid(str); if (m != nullptr && !m->flag.pvp && !m->flag.nopvp) { m->flag.pvp = 1; @@ -3403,8 +3383,8 @@ void builtin_pvpon(ScriptState *st) static void builtin_pvpoff(ScriptState *st) { - dumb_string str = conv_str(st, &AARGO2(2)); - map_local *m = map_mapname2mapid(str.c_str()); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + map_local *m = map_mapname2mapid(str); if (m != nullptr && m->flag.pvp && m->flag.nopvp) { m->flag.pvp = 0; @@ -3450,13 +3430,13 @@ void builtin_mapwarp(ScriptState *st) // Added by RoVeRT int x, y; int x0, y0, x1, y1; - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = 0; y0 = 0; - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); x1 = m->xs; y1 = m->ys; - dumb_string str = conv_str(st, &AARGO2(3)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(3)))); x = conv_num(st, &AARGO2(4)); y = conv_num(st, &AARGO2(5)); @@ -3473,16 +3453,15 @@ void builtin_mapwarp(ScriptState *st) // Added by RoVeRT static void builtin_cmdothernpc(ScriptState *st) // Added by RoVeRT { - dumb_string npc = conv_str(st, &AARGO2(2)); - dumb_string command = conv_str(st, &AARGO2(3)); + NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARGO2(2)))); + ZString command = ZString(conv_str(st, &AARGO2(3))); - npc_command(map_id2sd(st->rid), npc.c_str(), command.c_str()); + npc_command(map_id2sd(st->rid), npc, command); } static -void builtin_mobcount_sub(dumb_ptr<block_list> bl, dumb_string event, int *c) +void builtin_mobcount_sub(dumb_ptr<block_list> bl, NpcEvent event, int *c) { - using namespace operators; if (event == bl->as_mob()->npc_event) (*c)++; } @@ -3491,10 +3470,12 @@ static void builtin_mobcount(ScriptState *st) // Added by RoVeRT { int c = 0; - dumb_string mapname = conv_str(st, &AARGO2(2)); - dumb_string event = conv_str(st, &AARGO2(3)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); + ZString event_ = ZString(conv_str(st, &AARGO2(3))); + NpcEvent event; + extract(event_, &event); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) { push_int(st->stack, ByteCode::INT, -1); @@ -3513,9 +3494,9 @@ void builtin_mobcount(ScriptState *st) // Added by RoVeRT static void builtin_marriage(ScriptState *st) { - dumb_string partner = conv_str(st, &AARGO2(2)); + CharName partner = stringish<CharName>(ZString(conv_str(st, &AARGO2(2)))); dumb_ptr<map_session_data> sd = script_rid2sd(st); - dumb_ptr<map_session_data> p_sd = map_nick2sd(partner.c_str()); + dumb_ptr<map_session_data> p_sd = map_nick2sd(partner); if (sd == NULL || p_sd == NULL || pc_marriage(sd, p_sd) < 0) { @@ -3557,8 +3538,8 @@ void builtin_getitemname(ScriptState *st) get_val(st, data); if (data->type == ByteCode::STR || data->type == ByteCode::CONSTSTR) { - dumb_string name = conv_str(st, data); - i_data = itemdb_searchname(name.c_str()); + ItemName name = stringish<ItemName>(ZString(conv_str(st, data))); + i_data = itemdb_searchname(name); } else { @@ -3568,9 +3549,9 @@ void builtin_getitemname(ScriptState *st) dumb_string item_name; if (i_data) - item_name = dumb_string::copy(i_data->jname); + item_name = dumb_string::copys(i_data->jname); else - item_name = dumb_string::copy("Unknown Item"); + item_name = dumb_string::copys("Unknown Item"); push_str(st->stack, ByteCode::STR, item_name); } @@ -3580,11 +3561,11 @@ void builtin_getspellinvocation(ScriptState *st) { dumb_string name = conv_str(st, &AARGO2(2)); - const char *invocation = magic_find_invocation(name.str()); + FString invocation = magic_find_invocation(name.str()); if (!invocation) invocation = "..."; - push_str(st->stack, ByteCode::STR, dumb_string::copy(invocation)); + push_str(st->stack, ByteCode::STR, dumb_string::copys(invocation)); } static @@ -3661,7 +3642,7 @@ void builtin_getactivatedpoolskilllist(ScriptState *st) pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"), count), static_cast<uint16_t>(sd->status.skill[skill_id].flags)); pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"), count), - skill_name(skill_id).c_str()); + skill_name(skill_id)); ++count; } } @@ -3692,7 +3673,7 @@ void builtin_getunactivatedpoolskilllist(ScriptState *st) pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"), count), static_cast<uint16_t>(sd->status.skill[skill_id].flags)); pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"), count), - skill_name(skill_id).c_str()); + skill_name(skill_id)); ++count; } } @@ -3737,7 +3718,7 @@ void builtin_misceffect(ScriptState *st) { int type; int id = 0; - dumb_string name; + CharName name; dumb_ptr<block_list> bl = NULL; type = conv_num(st, &AARGO2(2)); @@ -3749,14 +3730,14 @@ void builtin_misceffect(ScriptState *st) get_val(st, sdata); if (sdata->type == ByteCode::STR || sdata->type == ByteCode::CONSTSTR) - name = conv_str(st, sdata); + name = stringish<CharName>(ZString(conv_str(st, sdata))); else id = conv_num(st, sdata); } - if (name) + if (name.to__actual()) { - dumb_ptr<map_session_data> sd = map_nick2sd(name.c_str()); + dumb_ptr<map_session_data> sd = map_nick2sd(name); if (sd) bl = sd; } @@ -3867,7 +3848,7 @@ void builtin_gmcommand(ScriptState *st) sd = script_rid2sd(st); dumb_string cmd = conv_str(st, &AARGO2(2)); - is_atcommand(sd->fd, sd, cmd.c_str(), 99); + is_atcommand(sd->fd, sd, cmd, 99); } @@ -3884,8 +3865,8 @@ void builtin_npcwarp(ScriptState *st) x = conv_num(st, &AARGO2(2)); y = conv_num(st, &AARGO2(3)); - dumb_string npc = conv_str(st, &AARGO2(4)); - nd = npc_name2id(npc.c_str()); + NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARGO2(4)))); + nd = npc_name2id(npc); if (!nd) return; @@ -3898,12 +3879,12 @@ void builtin_npcwarp(ScriptState *st) || y < 0 || y > m->ys - 1) return; - npc_enable(npc.c_str(), 0); + npc_enable(npc, 0); map_delblock(nd); /* [Freeyorp] */ nd->bl_x = x; nd->bl_y = y; map_addblock(nd); - npc_enable(npc.c_str(), 1); + npc_enable(npc, 1); } @@ -3915,10 +3896,10 @@ void builtin_npcwarp(ScriptState *st) static void builtin_message(ScriptState *st) { - dumb_string player = conv_str(st, &AARGO2(2)); - dumb_string msg = conv_str(st, &AARGO2(3)); + CharName player = stringish<CharName>(ZString(conv_str(st, &AARGO2(2)))); + ZString msg = ZString(conv_str(st, &AARGO2(3))); - dumb_ptr<map_session_data> pl_sd = map_nick2sd(player.c_str()); + dumb_ptr<map_session_data> pl_sd = map_nick2sd(player); if (pl_sd == NULL) return; clif_displaymessage(pl_sd->fd, msg); @@ -3939,8 +3920,11 @@ void builtin_npctalk(ScriptState *st) if (nd) { - std::string message = std::string(nd->name) + " : " + str.c_str(); - clif_message(nd, message.c_str()); + MString message; + message += nd->name; + message += " : "; + message += ZString(str); + clif_message(nd, FString(message)); } } @@ -4008,7 +3992,7 @@ void builtin_getsavepoint(ScriptState *st) { case 0: { - dumb_string mapname = dumb_string::copy(sd->status.save_point.map_); + dumb_string mapname = dumb_string::copys(sd->status.save_point.map_); push_str(st->stack, ByteCode::STR, mapname); } break; @@ -4026,9 +4010,9 @@ void builtin_getsavepoint(ScriptState *st) *------------------------------------------ */ static -void builtin_areatimer_sub(dumb_ptr<block_list> bl, interval_t tick, dumb_string event) +void builtin_areatimer_sub(dumb_ptr<block_list> bl, interval_t tick, NpcEvent event) { - pc_addeventtimer(bl->as_player(), tick, event.c_str()); + pc_addeventtimer(bl->as_player(), tick, event); } static @@ -4036,15 +4020,17 @@ void builtin_areatimer(ScriptState *st) { int x0, y0, x1, y1; - dumb_string mapname = conv_str(st, &AARGO2(2)); + MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x0 = conv_num(st, &AARGO2(3)); y0 = conv_num(st, &AARGO2(4)); x1 = conv_num(st, &AARGO2(5)); y1 = conv_num(st, &AARGO2(6)); interval_t tick = static_cast<interval_t>(conv_num(st, &AARGO2(7))); - dumb_string event = conv_str(st, &AARGO2(8)); + ZString event_ = ZString(conv_str(st, &AARGO2(8))); + NpcEvent event; + extract(event_, &event); - map_local *m = map_mapname2mapid(mapname.c_str()); + map_local *m = map_mapname2mapid(mapname); if (m == nullptr) return; @@ -4065,7 +4051,7 @@ void builtin_isin(ScriptState *st) int x1, y1, x2, y2; dumb_ptr<map_session_data> sd = script_rid2sd(st); - dumb_string str = conv_str(st, &AARGO2(2)); + MapName str = stringish<MapName>(ZString(conv_str(st, &AARGO2(2)))); x1 = conv_num(st, &AARGO2(3)); y1 = conv_num(st, &AARGO2(4)); x2 = conv_num(st, &AARGO2(5)); @@ -4074,7 +4060,6 @@ void builtin_isin(ScriptState *st) if (!sd) return; - using namespace operators; push_int(st->stack, ByteCode::INT, (sd->bl_x >= x1 && sd->bl_x <= x2) && (sd->bl_y >= y1 && sd->bl_y <= y2) @@ -4091,7 +4076,7 @@ void builtin_shop(ScriptState *st) if (!sd) return; - nd = npc_name2id(conv_str(st, &AARGO2(2)).c_str()); + nd = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARGO2(2))))); if (!nd) return; @@ -4118,18 +4103,18 @@ void builtin_isdead(ScriptState *st) static void builtin_fakenpcname(ScriptState *st) { - dumb_string name = conv_str(st, &AARGO2(2)); - dumb_string newname = conv_str(st, &AARGO2(3)); + NpcName name = stringish<NpcName>(ZString(conv_str(st, &AARGO2(2)))); + NpcName newname = stringish<NpcName>(ZString(conv_str(st, &AARGO2(3)))); int newsprite = conv_num(st, &AARGO2(4)); - dumb_ptr<npc_data> nd = npc_name2id(name.c_str()); + dumb_ptr<npc_data> nd = npc_name2id(name); if (!nd) return; - strzcpy(nd->name, newname.c_str(), sizeof(nd->name)); + nd->name = newname; nd->npc_class = newsprite; // Refresh this npc - npc_enable(name.c_str(), 0); - npc_enable(name.c_str(), 1); + npc_enable(name, 0); + npc_enable(name, 1); } @@ -4254,13 +4239,15 @@ void op_add(ScriptState *st) { dumb_string sb = conv_str(st, &back); dumb_string sb1 = conv_str(st, &back1); - std::string buf = sb1.str() + sb.str(); + MString buf; + buf += ZString(sb1); + buf += ZString(sb); if (back1.type == ByteCode::STR) back1.u.str.delete_(); if (back.type == ByteCode::STR) back.u.str.delete_(); back1.type = ByteCode::STR; - back1.u.str = dumb_string::copys(buf); + back1.u.str = dumb_string::copys(FString(buf)); } } @@ -4269,11 +4256,12 @@ void op_add(ScriptState *st) *------------------------------------------ */ static -void op_2str(ScriptState *st, ByteCode op, dumb_string s1, dumb_string s2) +void op_2str(ScriptState *st, ByteCode op, dumb_string s1_, dumb_string s2_) { + ZString s1 = ZString(s1_); + ZString s2 = ZString(s2_); int a = 0; - using namespace operators; switch (op) { case ByteCode::EQ: @@ -4697,7 +4685,7 @@ int run_script(ScriptPointer sp, int rid, int oid) } int run_script_l(ScriptPointer sp, int rid, int oid, - int args_nr, argrec_t *args) + int args_nr, argrec_t *args) { struct script_stack stack; ScriptState st; @@ -4719,7 +4707,7 @@ int run_script_l(ScriptPointer sp, int rid, int oid, st.oid = oid; for (i = 0; i < args_nr; i++) { - if (args[i].name[strlen(args[i].name) - 1] == '$') + if (args[i].name.back() == '$') pc_setregstr(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.s); else pc_setreg(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.i); @@ -4745,9 +4733,9 @@ void mapreg_setreg(SIR reg, int val) * 文字列型マップ変数の変更 *------------------------------------------ */ -void mapreg_setregstr(SIR reg, const char *str) +void mapreg_setregstr(SIR reg, XString str) { - if (!str || !*str) + if (!str) mapregstr_db.erase(reg); else mapregstr_db.insert(reg, str); @@ -4762,15 +4750,15 @@ void mapreg_setregstr(SIR reg, const char *str) static void script_load_mapreg(void) { - std::ifstream in(mapreg_txt); + std::ifstream in(mapreg_txt.c_str()); if (!in.is_open()) return; - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string buf1, buf2; + XString buf1, buf2; int index = 0; if (extract(line, record<'\t'>( @@ -4798,7 +4786,7 @@ void script_load_mapreg(void) else { borken: - PRINTF("%s: %s broken data !\n", mapreg_txt, buf1); + PRINTF("%s: %s broken data !\n", mapreg_txt, FString(buf1)); continue; } } @@ -4813,7 +4801,7 @@ static void script_save_mapreg_intsub(SIR key, int data, FILE *fp) { int num = key.base(), i = key.index(); - const std::string& name = variable_names.outtern(num); + ZString name = variable_names.outtern(num); if (name[1] != '@') { if (i == 0) @@ -4824,10 +4812,10 @@ void script_save_mapreg_intsub(SIR key, int data, FILE *fp) } static -void script_save_mapreg_strsub(SIR key, const std::string& data, FILE *fp) +void script_save_mapreg_strsub(SIR key, ZString data, FILE *fp) { int num = key.base(), i = key.index(); - const std::string& name = variable_names.outtern(num); + ZString name = variable_names.outtern(num); if (name[1] != '@') { if (i == 0) @@ -4876,12 +4864,8 @@ void do_final_script(void) script_save_mapreg(); mapreg_db.clear(); - for (auto& pair : mapregstr_db) - pair.second.clear(); mapregstr_db.clear(); scriptlabel_db.clear(); - for (auto& pair : userfunc_db) - pair.second.reset(); userfunc_db.clear(); str_datam.clear(); @@ -4902,7 +4886,7 @@ void do_init_script(void) } #define BUILTIN(func, args) \ -{builtin_##func, #func, args} +{builtin_##func, {#func}, {args}} BuiltinFunction builtin_functions[] = { @@ -5022,5 +5006,5 @@ BuiltinFunction builtin_functions[] = BUILTIN(getx, ""), BUILTIN(gety, ""), BUILTIN(getmap, ""), - {NULL, NULL, NULL}, + {nullptr, ZString(), ZString()}, }; diff --git a/src/map/script.hpp b/src/map/script.hpp index 66939aa..4e8f9ac 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -4,11 +4,11 @@ #include <cstdint> #include <cstring> // for inlined get_str - TODO remove -#include <string> #include <vector> #include "../common/db.hpp" #include "../common/dumb_ptr.hpp" +#include "../common/utils.hpp" #include "map.t.hpp" @@ -25,17 +25,17 @@ public: void add_scripti(uint32_t a); void add_scriptl(str_data_t *a); void set_label(str_data_t *ld, int pos_); - const char *parse_simpleexpr(const char *p); - const char *parse_subexpr(const char *p, int limit); - const char *parse_expr(const char *p); - const char *parse_line(const char *p); - void parse_script(const char *src, int line); + ZString::iterator parse_simpleexpr(ZString::iterator p); + ZString::iterator parse_subexpr(ZString::iterator p, int limit); + ZString::iterator parse_expr(ZString::iterator p); + ZString::iterator parse_line(ZString::iterator p); + void parse_script(ZString src, int line); // consumption methods used only by script.cpp ByteCode operator[](size_t i) const { return script_buf[i]; } - const char *get_str(size_t i) const + ZString get_str(size_t i) const { - return reinterpret_cast<const char *>(&script_buf[i]); + return ZString(ZString::really_construct_from_a_pointer, reinterpret_cast<const char *>(&script_buf[i]), nullptr); } // method used elsewhere @@ -58,10 +58,10 @@ struct ScriptPointer ByteCode peek() const { return (*code)[pos]; } ByteCode pop() { return (*code)[pos++]; } - const char *pops() + ZString pops() { - const char *rv = code->get_str(pos); - pos += strlen(rv); + ZString rv = code->get_str(pos); + pos += rv.size(); ++pos; return rv; } @@ -129,33 +129,36 @@ public: int defsp, new_defsp; }; -std::unique_ptr<const ScriptBuffer> parse_script(const char *, int); -typedef struct argrec +std::unique_ptr<const ScriptBuffer> parse_script(ZString, int); +struct argrec_t { - const char *name; + ZString name; union _aru { int i; - const char *s; + ZString s; - _aru() = default; _aru(int n) : i(n) {} - _aru(const char *z) : s(z) {} + _aru(ZString z) : s(z) {} } v; -} argrec_t; + + argrec_t(ZString n, int i) : name(n), v(i) {} + argrec_t(ZString n, ZString z) : name(n), v(z) {} +}; int run_script_l(ScriptPointer, int, int, int, argrec_t *args); int run_script(ScriptPointer, int, int); +struct ScriptLabel; extern -Map<std::string, int> scriptlabel_db; +Map<ScriptLabel, int> scriptlabel_db; extern -UPMap<std::string, const ScriptBuffer> userfunc_db; +UPMap<FString, const ScriptBuffer> userfunc_db; void script_config_read(); void do_init_script(void); void do_final_script(void); -extern char mapreg_txt[256]; +extern FString mapreg_txt; extern int script_errors; diff --git a/src/map/skill.cpp b/src/map/skill.cpp index c4b1dc8..7489731 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -5,9 +5,13 @@ #include <cstring> #include <ctime> +#include <fstream> + #include "../common/cxxstdio.hpp" -#include "../common/random.hpp" +#include "../common/extract.hpp" +#include "../common/io.hpp" #include "../common/nullpo.hpp" +#include "../common/random.hpp" #include "../common/socket.hpp" #include "../common/timer.hpp" @@ -1144,24 +1148,24 @@ void skill_unit_timer_sub_ondelete(dumb_ptr<block_list> bl, */ static -SP scan_stat(char *statname) +SP scan_stat(XString statname) { - if (!strcasecmp(statname, "str")) + if (statname == "str") return SP::STR; - if (!strcasecmp(statname, "dex")) + if (statname == "dex") return SP::DEX; - if (!strcasecmp(statname, "agi")) + if (statname == "agi") return SP::AGI; - if (!strcasecmp(statname, "vit")) + if (statname == "vit") return SP::VIT; - if (!strcasecmp(statname, "int")) + if (statname == "int") return SP::INT; - if (!strcasecmp(statname, "luk")) + if (statname == "luk") return SP::LUK; - if (!strcasecmp(statname, "none")) + if (statname == "none") return SP::ZERO; - FPRINTF(stderr, "Unknown stat `%s'\n", statname); + FPRINTF(stderr, "Unknown stat `%s'\n", FString(statname)); return SP::ZERO; } @@ -1174,93 +1178,89 @@ SP scan_stat(char *statname) static int skill_readdb(void) { - int j; - FILE *fp; - char line[1024], *p; - /* The main skill database */ for (skill_db_& skdb : skill_db) skdb = skill_db_{}; - fp = fopen_("db/skill_db.txt", "r"); - if (fp == NULL) + std::ifstream in("db/skill_db.txt"); + if (!in) { PRINTF("can't read db/skill_db.txt\n"); return 1; } - while (fgets(line, 1020, fp)) + + FString line_; + while (io::getline(in, line_)) { - char *split[50]; - if (line[0] == '/' && line[1] == '/') + XString comment = "//"; + XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip(); + if (!line) continue; - for (j = 0, p = line; j < 18 && p; j++) - { - while (*p == '\t' || *p == ' ') - p++; - split[j] = p; - p = strchr(p, ','); - if (p) - *p++ = 0; - } - if (split[17] == NULL || j < 18) - { - FPRINTF(stderr, "Incomplete skill db data online (%d entries)\n", - j); - continue; - } - SkillID i = SkillID(atoi(split[0])); + struct skill_db_ skdb {}; + + SkillID i; + XString castcancel, ignore, flags, stat, desc; + if (!extract(line, + record<','>( + &i, + lstripping(&skdb.range_k), + lstripping(&skdb.hit), + lstripping(&skdb.inf), + lstripping(&skdb.pl), + lstripping(&skdb.nk), + lstripping(&skdb.max_raise), + lstripping(&skdb.max), + lstripping(&skdb.num_k), + lstripping(&castcancel), + lstripping(&skdb.cast_def_rate), + lstripping(&skdb.inf2), + lstripping(&skdb.maxcount), + lstripping(&ignore), // weapon/magic/misc/none + lstripping(&ignore), // blow count + lstripping(&flags), + lstripping(&stat), + lstripping(&desc) + ) + ) + ) + continue; if (/*i < SkillID() ||*/ i > SkillID::MAX_SKILL_DB) continue; - char *split2_0; - split2_0 = split[1]; - skill_db[i].range_k = atoi(split2_0); - skill_db[i].hit = atoi(split[2]); - skill_db[i].inf = atoi(split[3]); - skill_db[i].pl = atoi(split[4]); - skill_db[i].nk = atoi(split[5]); - skill_db[i].max_raise = atoi(split[6]); - skill_db[i].max = atoi(split[7]); - - split2_0 = split[8]; - skill_db[i].num_k = atoi(split2_0); - - if (strcasecmp(split[9], "yes") == 0) - skill_db[i].castcancel = 1; + if (castcancel == "yes") + skdb.castcancel = true; + else if (castcancel == "no") + skdb.castcancel = false; else - skill_db[i].castcancel = 0; - skill_db[i].cast_def_rate = atoi(split[10]); - skill_db[i].inf2 = atoi(split[11]); - skill_db[i].maxcount = atoi(split[12]); - // split[13] was one of: BF::WEAPON, BF::MAGIC, BF::MISC, BF::ZERO - // split[14] was colon-separated blow counts. - - if (!strcasecmp(split[15], "passive")) + continue; + + if (flags == "passive") { skill_pool_register(i); - skill_db[i].poolflags = SkillFlags::POOL_FLAG; + skdb.poolflags = SkillFlags::POOL_FLAG; } - else if (!strcasecmp(split[15], "active")) + else if (flags == "active") { skill_pool_register(i); - skill_db[i].poolflags = SkillFlags::POOL_FLAG | SkillFlags::POOL_ACTIVE; + skdb.poolflags = SkillFlags::POOL_FLAG | SkillFlags::POOL_ACTIVE; } + else if (flags == "no") + skdb.poolflags = SkillFlags::ZERO; else - skill_db[i].poolflags = SkillFlags::ZERO; + continue; - skill_db[i].stat = scan_stat(split[16]); + skdb.stat = scan_stat(stat); - std::string tmp = split[17]; - size_t space = tmp.find_first_of(" \t\n"); - if (space != std::string::npos) - tmp.resize(space); + MString tmp; + tmp += desc; for (char& c : tmp) if (c == '_') c = ' '; - skill_lookup_by_id(i).desc = std::move(tmp); + + skill_db[i] = skdb; + skill_lookup_by_id(i).desc = FString(tmp); } - fclose_(fp); PRINTF("read db/skill_db.txt done\n"); return 0; @@ -1299,10 +1299,10 @@ skill_name_db& skill_lookup_by_id(SkillID id) return skill_names[num_names - 1]; } -skill_name_db& skill_lookup_by_name(const char *name) +skill_name_db& skill_lookup_by_name(XString name) { for (skill_name_db& ner : skill_names) - if (!strcasecmp(name, ner.name.c_str()) || !strcasecmp(name, ner.desc.c_str())) + if (name == ner.name || name == ner.desc) return ner; return skill_names[num_names - 1]; } diff --git a/src/map/skill.hpp b/src/map/skill.hpp index c5a2f03..bcd0261 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -21,7 +21,8 @@ struct skill_db_ int num_k; int cast[MAX_SKILL_LEVEL], delay[MAX_SKILL_LEVEL]; int upkeep_time[MAX_SKILL_LEVEL], upkeep_time2[MAX_SKILL_LEVEL]; - int castcancel, cast_def_rate; + bool castcancel; + int cast_def_rate; int inf2, maxcount; int hp[MAX_SKILL_LEVEL], sp[MAX_SKILL_LEVEL], mhp[MAX_SKILL_LEVEL], hp_rate[MAX_SKILL_LEVEL], sp_rate[MAX_SKILL_LEVEL], @@ -49,7 +50,7 @@ struct skill_name_db extern struct skill_name_db skill_names[]; skill_name_db& skill_lookup_by_id(SkillID id); -skill_name_db& skill_lookup_by_name(const char *name); +skill_name_db& skill_lookup_by_name(XString name); struct block_list; struct map_session_data; diff --git a/src/map/tmw.cpp b/src/map/tmw.cpp index 7afe3ca..ed00110 100644 --- a/src/map/tmw.cpp +++ b/src/map/tmw.cpp @@ -17,14 +17,12 @@ #include "../poison.hpp" static -void tmw_AutoBan(dumb_ptr<map_session_data> sd, const char *reason, int length); +void tmw_AutoBan(dumb_ptr<map_session_data> sd, ZString reason, int length); static -int tmw_CheckChatLameness(dumb_ptr<map_session_data> sd, const char *message); -static -int tmw_ShorterStrlen(const char *s1, const char *s2); +bool tmw_CheckChatLameness(dumb_ptr<map_session_data> sd, XString message); -int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, const char *message) +int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, XString message) { nullpo_retr(1, sd); TimeT now = TimeT::now(); @@ -48,8 +46,7 @@ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, const char *message) sd->chat_lines_in++; // Penalty for repeats. - if (strncmp(sd->chat_lastmsg, message, - tmw_ShorterStrlen(sd->chat_lastmsg, message)) == 0) + if (sd->chat_lastmsg.startswith(message) || message.startswith(sd->chat_lastmsg)) { sd->chat_lines_in += battle_config.chat_lame_penalty; sd->chat_total_repeats++; @@ -63,7 +60,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; - strzcpy(sd->chat_lastmsg, message, battle_config.chat_maxline); + sd->chat_lastmsg = message; if (sd->chat_lines_in >= battle_config.chat_spam_flood || sd->chat_total_repeats >= battle_config.chat_spam_flood) @@ -86,73 +83,58 @@ int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, const char *message) return 0; } -void tmw_AutoBan(dumb_ptr<map_session_data> sd, const char *reason, int length) +void tmw_AutoBan(dumb_ptr<map_session_data> sd, ZString reason, int length) { if (length == 0 || sd->auto_ban_info.in_progress) return; sd->auto_ban_info.in_progress = 1; - std::string hack_msg = STRPRINTF("[GM] %s has been autobanned for %s spam", + FString hack_msg = STRPRINTF("[GM] %s has been autobanned for %s spam", sd->status.name, reason); - tmw_GmHackMsg(hack_msg.c_str()); + tmw_GmHackMsg(hack_msg); - std::string fake_command = STRPRINTF("@autoban %s %dh (%s spam)", + FString fake_command = STRPRINTF("@autoban %s %dh (%s spam)", sd->status.name, length, reason); log_atcommand(sd, fake_command); - std::string anotherbuf = STRPRINTF("You have been banned for %s spamming. Please do not spam.", + FString anotherbuf = STRPRINTF("You have been banned for %s spamming. Please do not spam.", reason); clif_displaymessage(sd->fd, anotherbuf); /* type: 2 - ban(year, month, day, hour, minute, second) */ - chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, length, 0, 0); + HumanTimeDiff ban_len {}; + ban_len.hour = length; + chrif_char_ask_name(-1, sd->status.name, 2, ban_len); clif_setwaitclose(sd->fd); } -// Compares the length of two strings and returns that of the shorter -int tmw_ShorterStrlen(const char *s1, const char *s2) -{ - int s1_len = strlen(s1); - int s2_len = strlen(s2); - return (s2_len >= s1_len ? s1_len : s2_len); -} - // Returns true if more than 50% of input message is caps or punctuation -int tmw_CheckChatLameness(dumb_ptr<map_session_data>, const char *message) +bool tmw_CheckChatLameness(dumb_ptr<map_session_data>, XString message) { - int count, lame; - - for (count = lame = 0; *message; message++, count++) - if (isupper(*message) || ispunct(*message)) - lame++; + int lame = 0; - if (count > 7 && lame > count / 2) - return (1); + for (char c : message) + { + if (c <= ' ') + continue; + if (c > '~') + continue; + if ('0' <= c && c <= '9') + continue; + if ('a' <= c && c <= 'z') + continue; + lame++; + } - return (0); + return message.size() > 7 && lame > message.size() / 2; } // Sends a whisper to all GMs -void tmw_GmHackMsg(const char *line) +void tmw_GmHackMsg(ZString line) { intif_wis_message_to_gm(wisp_server_name, - battle_config.hack_info_GM_level, - line); -} - -/* Remove leading and trailing spaces from a string, modifying in place. */ -void tmw_TrimStr(char *const ob) -{ - char *const oe = ob + strlen(ob); - char *nb = ob; - while (*nb && isspace(*nb)) - nb++; - char *ne = oe; - while (ne != nb && isspace(ne[-1])) - ne--; - // not like memcpy - allowed to overlap one way - char *zb = std::copy(nb, ne, ob); - std::fill(zb, oe, '\0'); + battle_config.hack_info_GM_level, + line); } diff --git a/src/map/tmw.hpp b/src/map/tmw.hpp index 5551504..5f1d215 100644 --- a/src/map/tmw.hpp +++ b/src/map/tmw.hpp @@ -6,8 +6,7 @@ #include "map.hpp" -int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, const char *message); -void tmw_GmHackMsg(const char *line); -void tmw_TrimStr(char *str); +int tmw_CheckChatSpam(dumb_ptr<map_session_data> sd, XString message); +void tmw_GmHackMsg(ZString line); #endif // TMW_HPP diff --git a/src/poison.hpp b/src/poison.hpp index 0a7cc57..e7cc4cc 100644 --- a/src/poison.hpp +++ b/src/poison.hpp @@ -6,6 +6,8 @@ // double (use a fixed class) #pragma GCC poison float +#pragma GCC poison dynamic_cast + // Local time is forbidden. #pragma GCC poison timelocal // timegm #pragma GCC poison mktime // timegm @@ -76,3 +78,10 @@ #pragma GCC poison memset #pragma GCC poison memcmp #pragma GCC poison strncpy // in favor of strzcpy + +#pragma GCC poison string // in favor of FString, MString, etc. +#pragma GCC poison strcasecmp +#pragma GCC poison toupper +#pragma GCC poison tolower +#pragma GCC poison isupper +#pragma GCC poison islower diff --git a/src/tool/eathena-monitor.cpp b/src/tool/eathena-monitor.cpp index 2196c7c..f6e8271 100644 --- a/src/tool/eathena-monitor.cpp +++ b/src/tool/eathena-monitor.cpp @@ -17,6 +17,7 @@ #include <fstream> #include "../common/cxxstdio.hpp" +#include "../common/io.hpp" #include "../common/utils.hpp" #include "../poison.hpp" @@ -29,30 +30,30 @@ // initialiized to $HOME/tmwserver static -std::string workdir; +FString workdir; //the rest are relative to workdir static -std::string login_server = LOGIN_SERVER; +FString login_server = LOGIN_SERVER; static -std::string map_server = MAP_SERVER; +FString map_server = MAP_SERVER; static -std::string char_server = CHAR_SERVER; +FString char_server = CHAR_SERVER; static pid_t pid_login, pid_map, pid_char; static -std::string make_path(const std::string& base, const std::string& path) +FString make_path(XString base, XString path) { - std::string out(base.size() + 1 + path.size(), '\0'); - std::string::iterator it = std::copy(base.begin(), base.end(), out.begin()); - *it++ = '/'; - std::copy(path.begin(), path.end(), it); - return out; + MString m; + m += base; + m += '/'; + m += path; + return FString(m); } static -void parse_option(const std::string& name, const std::string& value) +void parse_option(XString name, ZString value) { if (name == "login_server") login_server = value; @@ -63,23 +64,28 @@ void parse_option(const std::string& name, const std::string& value) else if (name == "workdir") workdir = value; else - FPRINTF(stderr, "WARNING: ingnoring invalid option '%s' : '%s'\n", name, value); + { + FString name_ = name; + FPRINTF(stderr, "WARNING: ingnoring invalid option '%s' : '%s'\n", + name_, value); + } } static -void read_config(const std::string& filename) +void read_config(ZString filename) { - std::ifstream in(filename); + std::ifstream in(filename.c_str()); if (!in.is_open()) { FPRINTF(stderr, "Monitor config file not found: %s\n", filename); exit(1); } - std::string line; - while (std::getline(in, line)) + FString line; + while (io::getline(in, line)) { - std::string name, value; + SString name; + TString value; if (!split_key_value(line, &name, &value)) continue; @@ -88,7 +94,8 @@ void read_config(const std::string& filename) } static -pid_t start_process(const std::string& exec) { +pid_t start_process(ZString exec) +{ const char *args[2] = {exec.c_str(), NULL}; pid_t pid = fork(); if (pid == -1) @@ -135,11 +142,11 @@ int main(int argc, char *argv[]) signal(SIGQUIT, stop_process); signal(SIGABRT, stop_process); - workdir = make_path(getenv("HOME"), "tmwserver"); + workdir = make_path(ZString(ZString::really_construct_from_a_pointer, getenv("HOME"), nullptr), "tmwserver"); - std::string config = CONFIG; + ZString config = CONFIG; if (argc > 1) - config = argv[1]; + config = ZString(ZString::really_construct_from_a_pointer, argv[1], nullptr); read_config(config); if (chdir(workdir.c_str()) < 0) diff --git a/src/warnings.hpp b/src/warnings.hpp index 9ce78ee..9f184a5 100644 --- a/src/warnings.hpp +++ b/src/warnings.hpp @@ -167,7 +167,8 @@ /// Warn about things that will change when compiling /// with an ABI-compliant compiler -I(-Wabi) +// see note about -fabi-version=6 in the makefile +E(-Wabi) /// Warn if a subobject has an abi_tag attribute that /// the complete object type does not have @@ -191,9 +192,10 @@ E(-Wbuiltin-macro-redefined) /// Warn about C++ constructs whose meaning differs /// between ISO C++ 1998 and ISO C++ 2011 -// This has gone funky lately. It probably doesn't do anything anyway. +// This has gone funky lately. It probably doesn't do anything useful anyway. //E(-Wc++0x-compat) //W(-Wc++11-compat) +I(-Wc++0x-compat) /// Warn about pointer casts which increase alignment X(-Wcast-align) @@ -298,7 +300,7 @@ E(-Wfloat-equal) // see below EG(-Wformat) // but gcc 4.8 warns on %ms, since we enabled -Wpedantic. -WG48(-Wformat) +//WG48(-Wformat) /// Warn about format strings that contain NUL bytes EG(-Wformat-contains-nul) @@ -474,7 +476,9 @@ E(-Wparentheses) /// Issue warnings needed for strict compliance to /// the standard -EG48(-Wpedantic) +//EG48(-Wpedantic) +// lots of minor extensions are used +IG48(-Wpedantic) // a bit too noisy XC(-Wpedantic) |