diff options
Diffstat (limited to 'src/map/map.c')
-rw-r--r-- | src/map/map.c | 1150 |
1 files changed, 794 insertions, 356 deletions
diff --git a/src/map/map.c b/src/map/map.c index 3dad25fce..16d5e645d 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -69,6 +69,7 @@ #include "common/random.h" #include "common/showmsg.h" #include "common/socket.h" // WFIFO*() +#include "common/sql.h" #include "common/strlib.h" #include "common/timer.h" #include "common/utils.h" @@ -78,6 +79,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #ifndef _WIN32 #include <unistd.h> #endif @@ -192,6 +194,7 @@ void map_update_cell_bl( struct block_list *bl, bool increase ) { #ifdef CELL_NOSTACK int pos; + nullpo_retv(bl); if( bl->m < 0 || bl->x < 0 || bl->x >= map->list[bl->m].xs || bl->y < 0 || bl->y >= map->list[bl->m].ys || !(bl->type&BL_CHAR) ) @@ -308,9 +311,14 @@ int map_delblock(struct block_list* bl) * (which are executed by default on BL_CHAR types) *------------------------------------------*/ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { - int x0 = bl->x, y0 = bl->y; struct status_change *sc = NULL; - int moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE); + int x0, y0; + int moveblock; + + nullpo_ret(bl); + x0 = bl->x; + y0 = bl->y; + moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE); if (!bl->prev) { //Block not in map, just update coordinates, but do naught else. @@ -329,6 +337,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { //status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); + status_change_end(bl, SC_SU_STOOP, INVALID_TIMER); if (sc && sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER); @@ -476,6 +485,8 @@ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x, int16 m,bx,by; struct block_list *bl; struct skill_unit *su; + + nullpo_retr(NULL, target); m = target->m; if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys)) @@ -674,49 +685,95 @@ static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int ( x1 = min(x1, map->list[m].xs - 1); y1 = min(y1, map->list[m].ys - 1); - for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++) { - for (bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++) { - if (type&~BL_MOB) { - for (bl = map->list[m].block[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { - if (bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { - if( map->bl_list_count >= map->bl_list_size ) - map_bl_list_expand(); - if (func) { - va_start(args, func); - if (func(bl, args)) { + { + const int x0b = x0 / BLOCK_SIZE; + const int x1b = x1 / BLOCK_SIZE; + const int y0b = y0 / BLOCK_SIZE; + const int y1b = y1 / BLOCK_SIZE; + const struct map_data *const listm = &map->list[m]; + const int bxs0 = listm->bxs; + + // duplication for better performance + if (func != NULL) { + if (type & ~BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (bl->type & type && x >= x0 && x <= x1 && y >= y0 && y <= y1) { + va_start(args, func); + if (func(bl, args)) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } + } + } + } + } + if (type & BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block_mob[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (x >= x0 && x <= x1 && y >= y0 && y <= y1) { + va_start(args, func); + if (func(bl, args)) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } + } + } + } + } + } else { // func != NULL + if (type & ~BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (bl->type & type && x >= x0 && x <= x1 && y >= y0 && y <= y1) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); map->bl_list[map->bl_list_count++] = bl; found++; } - va_end(args); - } else { - map->bl_list[map->bl_list_count++] = bl; - found++; } } } } - if (type&BL_MOB) { // TODO: fix this code duplication - for (bl = map->list[m].block_mob[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { - if (bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { - if( map->bl_list_count >= map->bl_list_size ) - map_bl_list_expand(); - if (func) { - va_start(args, func); - if (func(bl, args)) { + if (type & BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block_mob[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (x >= x0 && x <= x1 && y >= y0 && y <= y1) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); map->bl_list[map->bl_list_count++] = bl; found++; } - va_end(args); - } else { - map->bl_list[map->bl_list_count++] = bl; - found++; } } } } } } - return found; } @@ -853,6 +910,9 @@ static int bl_vgetall_inshootrange(struct block_list *bl, va_list args) struct block_list *center = va_arg(args, struct block_list*); #ifdef CIRCULAR_AREA int range = va_arg(args, int); + nullpo_ret(center); + nullpo_ret(bl); + if (!check_distance_bl(center, bl, range)) return 0; #endif @@ -1040,6 +1100,9 @@ static int bl_vgetall_inmovearea(struct block_list *bl, va_list args) struct block_list *center = va_arg(args, struct block_list*); int range = va_arg(args, int); + nullpo_ret(bl); + nullpo_ret(center); + if ((dx > 0 && bl->x < center->x - range + dx) || (dx < 0 && bl->x > center->x + range + dx) || (dy > 0 && bl->y < center->y - range + dy) || @@ -1202,11 +1265,15 @@ static int bl_vgetall_inpath(struct block_list *bl, va_list args) int len_limit = va_arg(args, int); int magnitude2 = va_arg(args, int); - int xi = bl->x; - int yi = bl->y; + int xi; + int yi; int xu, yu; + int k; - int k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); + nullpo_ret(bl); + xi = bl->x; + yi = bl->y; + k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); if ( k < 0 || k > len_limit ) //Since more skills use this, check for ending point as well. return 0; @@ -1421,6 +1488,9 @@ int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 int free_cell,i,j; int free_cells[9][2]; + nullpo_ret(x); + nullpo_ret(y); + for(free_cell=0,i=-1;i<=1;i++){ if(i+*y<0 || i+*y>=map->list[m].ys) continue; @@ -1467,6 +1537,9 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 int rx2 = 2*rx+1; int ry2 = 2*ry+1; + nullpo_ret(x); + nullpo_ret(y); + if( !src && (!(flag&1) || flag&2) ) { ShowDebug("map_search_freecell: Incorrect usage! When src is NULL, flag has to be &1 and can't have &2\n"); @@ -1477,6 +1550,7 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 bx = *x; by = *y; } else { + nullpo_ret(src); bx = src->x; by = src->y; m = src->m; @@ -1533,10 +1607,15 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag) { uint8 dir = 6; - int16 tx = *x; - int16 ty = *y; + int16 tx; + int16 ty; int costrange = 10; + nullpo_ret(x); + nullpo_ret(y); + tx = *x; + ty = *y; + if(!map->count_oncell(m, tx, ty, type, flag)) return true; //Current cell is free @@ -1657,7 +1736,7 @@ int map_addflooritem(const struct block_list *bl, struct item *item_data, int am /** * @see DBCreateData */ -DBData create_charid2nick(DBKey key, va_list args) +struct DBData create_charid2nick(union DBKey key, va_list args) { struct charid2nick *p; CREATE(p, struct charid2nick, 1); @@ -1694,7 +1773,7 @@ void map_delnickdb(int charid, const char* name) { struct charid2nick* p; struct charid_request* req; - DBData data; + struct DBData data; if (!map->nick_db->remove(map->nick_db, DB->i2key(charid), &data) || (p = DB->data2ptr(&data)) == NULL) return; @@ -1793,6 +1872,8 @@ void map_deliddb(struct block_list *bl) int map_quit(struct map_session_data *sd) { int i; + nullpo_ret(sd); + if(!sd->state.active) { //Removing a player that is not active. struct auth_node *node = chrif->search(sd->status.account_id); if (node && node->char_id == sd->status.char_id && @@ -1849,6 +1930,7 @@ int map_quit(struct map_session_data *sd) { case SC_GDSKILL_REGENERATION: if( !sd->sc.data[i]->val4 ) break; + FALLTHROUGH default: status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER); } @@ -2166,9 +2248,9 @@ struct map_session_data * map_nick2sd(const char *nick) /*========================================== * Convext Mirror *------------------------------------------*/ -struct mob_data * map_getmob_boss(int16 m) +struct mob_data *map_getmob_boss(int16 m) { - DBIterator* iter; + struct DBIterator *iter; struct mob_data *md = NULL; bool found = false; @@ -2230,11 +2312,11 @@ uint32 map_race_id2mask(int race) /// Applies func to all the players in the db. /// Stops iterating if func returns -1. -void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) { - DBIterator* iter; - struct map_session_data* sd; +void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->pc_db); + struct map_session_data *sd = NULL; - iter = db_iterator(map->pc_db); for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) { va_list argscopy; @@ -2262,11 +2344,11 @@ void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) /// Applies func to all the mobs in the db. /// Stops iterating if func returns -1. -void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) { - DBIterator* iter; - struct mob_data* md; +void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->mobid_db); + struct mob_data *md = NULL; - iter = db_iterator(map->mobid_db); for (md = dbi_first(iter); dbi_exists(iter); md = dbi_next(iter)) { va_list argscopy; int ret; @@ -2293,11 +2375,11 @@ void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) { /// Applies func to all the npcs in the db. /// Stops iterating if func returns -1. -void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->id_db); + struct block_list *bl = NULL; - iter = db_iterator(map->id_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { if (bl->type == BL_NPC) { struct npc_data *nd = BL_UCAST(BL_NPC, bl); @@ -2327,11 +2409,11 @@ void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating gif func returns -1. -void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->regen_db); + struct block_list *bl = NULL; - iter = db_iterator(map->regen_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { va_list argscopy; int ret; @@ -2358,11 +2440,11 @@ void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating if func returns -1. -void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->id_db); + struct block_list *bl = NULL; - iter = db_iterator(map->id_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { va_list argscopy; int ret; @@ -2389,11 +2471,10 @@ void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) { /// Iterator. /// Can filter by bl type. -struct s_mapiterator -{ - enum e_mapitflags flags;// flags for special behaviour - enum bl_type types;// what bl types to return - DBIterator* dbi;// database iterator +struct s_mapiterator { + enum e_mapitflags flags; ///< flags for special behaviour + enum bl_type types; ///< what bl types to return + struct DBIterator *dbi; ///< database iterator }; /// Returns true if the block_list matches the description in the iterator. @@ -2547,6 +2628,7 @@ bool map_addnpc(int16 m,struct npc_data *nd) { // Returns the index of successful, or -1 if the list was full. int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { int i; + nullpo_retr(-1, spawn); ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map->list[m].moblist[i] == NULL ); if( i < MAX_MOB_LIST_PER_MAP ) { map->list[m].moblist[i] = spawn; @@ -2628,6 +2710,7 @@ int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) { } void map_removemobs(int16 m) { + Assert_retv(m >= 0 && m < map->count); if (map->list[m].mob_delete_timer != INVALID_TIMER) // should never happen return; //Mobs are already scheduled for removal @@ -2662,6 +2745,8 @@ int16 map_mapindex2mapid(unsigned short map_index) { int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) { struct map_data_other_server *mdos; + nullpo_retr(-1, ip); + nullpo_retr(-1, port); mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)name); if(mdos==NULL || mdos->cell) //If gat isn't null, this is a local map. return -1; @@ -2737,11 +2822,19 @@ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) *------------------------------------------*/ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) { - short xi = *x-bl->x; - short yi = *y-bl->y; + short xi; + short yi; short i=0; - int dist2 = xi*xi + yi*yi; - short dist = (short)sqrt((float)dist2); + int dist2; + short dist; + + nullpo_ret(bl); + nullpo_ret(x); + nullpo_ret(y); + xi = *x-bl->x; + yi = *y-bl->y; + dist2 = xi*xi + yi*yi; + dist = (short)sqrt((float)dist2); if (dist < 1) dist =1; @@ -2794,7 +2887,10 @@ int map_cell2gat(struct mapcell cell) { return 1; // default to 'wall' } void map_cellfromcache(struct map_data *m) { - struct map_cache_map_info *info = (struct map_cache_map_info *)m->cellPos; + struct map_cache_map_info *info; + + nullpo_retv(m); + info = (struct map_cache_map_info *)m->cellPos; if (info) { char decode_buffer[MAX_MAP_SIZE]; @@ -2804,7 +2900,7 @@ void map_cellfromcache(struct map_data *m) { size = (unsigned long)info->xs*(unsigned long)info->ys; // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo] - decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len); + grfio->decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len); CREATE(m->cell, struct mapcell, size); // Set cell properties @@ -2897,6 +2993,7 @@ int map_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 /* [Ind/Hercules] */ int map_sub_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) { + nullpo_ret(m); map->cellfromcache(m); m->getcellp = map->getcellp; m->setcell = map->setcell; @@ -2963,6 +3060,9 @@ void map_setgatcell(int16 m, int16 x, int16 y, int gat) { *------------------------------------------*/ void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) { + nullpo_retv(x1); + nullpo_retv(y1); + if( dir == 0 || dir == 4 ) *x1 = x; // Keep X else if( dir > 0 && dir < 4 ) @@ -3022,12 +3122,15 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable return true; } -void map_iwall_get(struct map_session_data *sd) { +void map_iwall_get(struct map_session_data *sd) +{ struct iwall_data *iwall; - DBIterator* iter; + struct DBIterator *iter; int16 x1, y1; int i; + nullpo_retv(sd); + if( map->list[sd->bl.m].iwall_num < 1 ) return; @@ -3068,7 +3171,7 @@ void map_iwall_remove(const char *wall_name) /** * @see DBCreateData */ -DBData create_map_data_other_server(DBKey key, va_list args) +struct DBData create_map_data_other_server(union DBKey key, va_list args) { struct map_data_other_server *mdos; unsigned short map_index = (unsigned short)key.ui; @@ -3103,9 +3206,10 @@ int map_setipport(unsigned short map_index, uint32 ip, uint16 port) * Delete all the other maps server management * @see DBApply */ -int map_eraseallipport_sub(DBKey key, DBData *data, va_list va) +int map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va) { struct map_data_other_server *mdos = DB->data2ptr(data); + nullpo_ret(mdos); if(mdos->cell == NULL) { db_remove(map->map_db,key); aFree(mdos); @@ -3192,6 +3296,9 @@ int map_readfromcache(struct map_data *m, char *buffer) { struct map_cache_map_info *info = NULL; char *p = buffer + sizeof(struct map_cache_main_header); + nullpo_ret(m); + nullpo_ret(buffer); + for(i = 0; i < header->map_count; i++) { info = (struct map_cache_map_info *)p; @@ -3226,22 +3333,46 @@ int map_readfromcache(struct map_data *m, char *buffer) { return 0; // Not found } -int map_addmap(const char* mapname) { +/** + * Adds a new empty map to the map list. + * + * Assumes that there's enough space in the map list. + * + * @param mapname The new map's name. + * @return success state. + */ +int map_addmap(const char *mapname) +{ map->list[map->count].instance_id = -1; mapindex->getmapname(mapname, map->list[map->count++].name); return 0; } -void map_delmapid(int id) { +/** + * Removes a map from the map list. + * + * @param id The map ID. + */ +void map_delmapid(int id) +{ + Assert_retv(id >= 0 && id < map->count); ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map->list[id].name); memmove(map->list+id, map->list+id+1, sizeof(map->list[0])*(map->count-id-1)); map->count--; } -int map_delmap(char* mapname) { +/** + * Removes a map fromt he map list. + * + * @param mapname The name of the map to remove. + * @return the number of removed maps. + */ +int map_delmap(const char *mapname) +{ int i; char map_name[MAP_NAME_LENGTH]; + nullpo_ret(mapname); if (strcmpi(mapname, "all") == 0) { map->count = 0; return 0; @@ -3263,6 +3394,8 @@ int map_delmap(char* mapname) { void map_zone_clear_single(struct map_zone_data *zone) { int i; + nullpo_retv(zone); + for(i = 0; i < zone->disabled_skills_count; i++) { aFree(zone->disabled_skills[i]); } @@ -3300,9 +3433,10 @@ void map_zone_clear_single(struct map_zone_data *zone) { /** * **/ -void map_zone_db_clear(void) { - struct map_zone_data *zone; - DBIterator *iter = db_iterator(map->zone_db); +void map_zone_db_clear(void) +{ + struct DBIterator *iter = db_iterator(map->zone_db); + struct map_zone_data *zone = NULL; for(zone = dbi_first(iter); dbi_exists(iter); zone = dbi_next(iter)) { map->zone_clear_single(zone); @@ -3319,6 +3453,7 @@ void map_zone_db_clear(void) { } void map_clean(int i) { int v; + Assert_retv(i >= 0 && i < map->count); if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell); if(map->list[i].block) aFree(map->list[i].block); if(map->list[i].block_mob) aFree(map->list[i].block_mob); @@ -3515,16 +3650,18 @@ void map_flags_init(void) { int map_waterheight(char* mapname) { char fn[256]; - char *rsw, *found; + char *rsw = NULL; + const char *found; + nullpo_retr(NO_WATER, mapname); //Look up for the rsw snprintf(fn, sizeof(fn), "data\\%s.rsw", mapname); - if ( (found = grfio_find_file(fn)) ) + if ((found = grfio->find_file(fn))) safestrncpy(fn, found, sizeof(fn)); // replace with real name // read & convert fn - rsw = (char *) grfio_read (fn); + rsw = grfio_read(fn); if (rsw) { //Load water height from file int wh = (int) *(float*)(rsw+166); @@ -3545,9 +3682,10 @@ int map_readgat (struct map_data* m) int water_height; size_t xy, off, num_cells; + nullpo_ret(m); sprintf(filename, "data\\%s.gat", m->name); - gat = (uint8 *) grfio_read(filename); + gat = grfio_read(filename); if (gat == NULL) return 0; @@ -3582,10 +3720,12 @@ int map_readgat (struct map_data* m) * Add/Remove map to the map_db *--------------------------------------*/ void map_addmap2db(struct map_data *m) { + nullpo_retv(m); map->index2mapid[m->index] = m->m; } void map_removemapdb(struct map_data *m) { + nullpo_retv(m); map->index2mapid[m->index] = -1; } @@ -3600,8 +3740,8 @@ int map_readallmaps (void) { if( map->enable_grf ) ShowStatus("Loading maps (using GRF files)...\n"); else { - char mapcachefilepath[254]; - sprintf(mapcachefilepath,"%s/%s%s",map->db_path,DBPATH,"map_cache.dat"); + char mapcachefilepath[256]; + snprintf(mapcachefilepath, 256, "%s/%s%s", map->db_path, DBPATH, "map_cache.dat"); ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath); if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) { ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath); @@ -3683,177 +3823,387 @@ int map_readallmaps (void) { return 0; } -/*========================================== - * Read map server configuration files (conf/map_server.conf...) - *------------------------------------------*/ -int map_config_read(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; +/** + * Reads 'map_configuration/console' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read_console(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; - fp = fopen(cfgName,"r"); - if( fp == NULL ) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return 1; + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/console")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/console was not found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + libconfig->setting_lookup_bool_real(setting, "stdout_with_ansisequence", &showmsg->stdout_with_ansisequence); + if (libconfig->setting_lookup_int(setting, "console_silent", &showmsg->silent) == CONFIG_TRUE) { + if (showmsg->silent) // only bother if its actually enabled + ShowInfo("Console Silent Setting: %d\n", showmsg->silent); + } + libconfig->setting_lookup_mutable_string(setting, "timestamp_format", showmsg->timestamp_format, sizeof(showmsg->timestamp_format)); + libconfig->setting_lookup_int(setting, "console_msg_log", &showmsg->console_log); - if (line[0] == '/' && line[1] == '/') - continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) - continue; + return true; +} - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; - - if(strcmpi(w1,"timestamp_format")==0) - safestrncpy(showmsg->timestamp_format, w2, 20); - else if(strcmpi(w1,"stdout_with_ansisequence")==0) - showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false; - else if(strcmpi(w1,"console_silent")==0) { - showmsg->silent = atoi(w2); - if (showmsg->silent) // only bother if its actually enabled - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if (strcmpi(w1, "userid")==0) - chrif->setuserid(w2); - else if (strcmpi(w1, "passwd") == 0) - chrif->setpasswd(w2); - else if (strcmpi(w1, "char_ip") == 0) - map->char_ip_set = chrif->setip(w2); - else if (strcmpi(w1, "char_port") == 0) - chrif->setport(atoi(w2)); - else if (strcmpi(w1, "map_ip") == 0) - map->ip_set = clif->setip(w2); - else if (strcmpi(w1, "bind_ip") == 0) - clif->setbindip(w2); - else if (strcmpi(w1, "map_port") == 0) { - clif->setport(atoi(w2)); - map->port = (atoi(w2)); - } else if (strcmpi(w1, "map") == 0) - map->count++; - else if (strcmpi(w1, "delmap") == 0) - map->count--; - else if (strcmpi(w1, "npc") == 0) - npc->addsrcfile(w2); - else if (strcmpi(w1, "delnpc") == 0) - npc->delsrcfile(w2); - else if (strcmpi(w1, "autosave_time") == 0) { - map->autosave_interval = atoi(w2); - if (map->autosave_interval < 1) //Revert to default saving. - map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - else - map->autosave_interval *= 1000; //Pass from sec to ms - } else if (strcmpi(w1, "minsave_time") == 0) { - map->minsave_interval= atoi(w2); - if (map->minsave_interval < 1) - map->minsave_interval = 1; - } else if (strcmpi(w1, "save_settings") == 0) - map->save_settings = atoi(w2); - else if (strcmpi(w1, "help_txt") == 0) - strcpy(map->help_txt, w2); - else if (strcmpi(w1, "help2_txt") == 0) - strcpy(map->help2_txt, w2); - else if (strcmpi(w1, "charhelp_txt") == 0) - strcpy(map->charhelp_txt, w2); - else if(strcmpi(w1,"db_path") == 0) - safestrncpy(map->db_path,w2,255); - else if (strcmpi(w1, "enable_spy") == 0) - map->enable_spy = config_switch(w2); - else if (strcmpi(w1, "use_grf") == 0) - map->enable_grf = config_switch(w2); - else if (strcmpi(w1, "console_msg_log") == 0) - showmsg->console_log = atoi(w2);//[Ind] - else if (strcmpi(w1, "default_language") == 0) - safestrncpy(map->default_lang_str, w2, sizeof(map->default_lang_str)); - else if (strcmpi(w1, "import") == 0) - map->config_read(w2); +/** + * Reads 'map_configuration/sql_connection' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read_connection(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/sql_connection")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/sql_connection was not found in %s!\n", filename); + ShowWarning("map_config_read_connection: Defaulting sql_connection...\n"); + return false; + } + + libconfig->setting_lookup_int(setting, "db_port", &map->server_port); + libconfig->setting_lookup_mutable_string(setting, "db_hostname", map->server_ip, sizeof(map->server_ip)); + libconfig->setting_lookup_mutable_string(setting, "db_username", map->server_id, sizeof(map->server_id)); + libconfig->setting_lookup_mutable_string(setting, "db_password", map->server_pw, sizeof(map->server_pw)); + libconfig->setting_lookup_mutable_string(setting, "db_database", map->server_db, sizeof(map->server_db)); + libconfig->setting_lookup_mutable_string(setting, "default_codepage", map->default_codepage, sizeof(map->default_codepage)); + return true; +} + +/** + * Reads 'map_configuration/inter' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read_inter(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + const char *str = NULL; + char temp[24]; + uint16 port; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/inter")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/inter was not found in %s!\n", filename); + return false; + } + + // Login information + if (libconfig->setting_lookup_mutable_string(setting, "userid", temp, sizeof(temp)) == CONFIG_TRUE) + chrif->setuserid(temp); + if (libconfig->setting_lookup_mutable_string(setting, "passwd", temp, sizeof(temp)) == CONFIG_TRUE) + chrif->setpasswd(temp); + + // Char and map-server information + if (libconfig->setting_lookup_string(setting, "char_ip", &str) == CONFIG_TRUE) + map->char_ip_set = chrif->setip(str); + if (libconfig->setting_lookup_uint16(setting, "char_port", &port) == CONFIG_TRUE) + chrif->setport(port); + + if (libconfig->setting_lookup_string(setting, "map_ip", &str) == CONFIG_TRUE) + map->ip_set = clif->setip(str); + if (libconfig->setting_lookup_uint16(setting, "map_port", &port) == CONFIG_TRUE) { + clif->setport(port); + map->port = port; + } + if (libconfig->setting_lookup_string(setting, "bind_ip", &str) == CONFIG_TRUE) + clif->setbindip(str); + + return true; +} + +/** + * Reads 'map_configuration/database' and initializes required variables + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read_database(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/database")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/database was not found in %s!\n", filename); + return false; + } + libconfig->setting_lookup_mutable_string(setting, "db_path", map->db_path, sizeof(map->db_path)); + libconfig->setting_lookup_int(setting, "save_settings", &map->save_settings); + + if (libconfig->setting_lookup_int(setting, "autosave_time", &map->autosave_interval) == CONFIG_TRUE) { + if (map->autosave_interval < 1) // Revert to default saving + map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + map->autosave_interval *= 1000; // Pass from s to ms + } + if (libconfig->setting_lookup_int(setting, "minsave_time", &map->minsave_interval) == CONFIG_TRUE) { + if (map->minsave_interval < 1) + map->minsave_interval = 1; } - fclose(fp); - return 0; + return true; } -int map_config_read_sub(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - fp = fopen(cfgName,"r"); - if (fp == NULL) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return 1; +/** + * Reads 'map_configuration/map_list'/'map_configuration/map_removed' and adds + * or removes maps from map-server. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read_map_list(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + int i, count = 0; + struct DBMap *deleted_maps; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + deleted_maps = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, MAP_NAME_LENGTH); + + // Remove maps + if ((setting = libconfig->lookup(config, "map_configuration/map_removed")) != NULL) { + count = libconfig->setting_length(setting); + for (i = 0; i < count; i++) { + const char *mapname; + + if ((mapname = libconfig->setting_get_string_elem(setting, i)) == NULL || mapname[0] == '\0') + continue; + + strdb_put(deleted_maps, mapname, NULL); + + if (imported) // Map list is empty on the first run, only do this for imported files. + map->delmap(mapname); + } + } + + if ((setting = libconfig->lookup(config, "map_configuration/map_list")) == NULL) { + db_destroy(deleted_maps); + if (imported) + return true; + ShowError("map_config_read_map_list: map_configuration/map_list was not found in %s!\n", filename); + return false; + } + + // Add maps to map->list + count = libconfig->setting_length(setting); + + if (count <= 0) { + db_destroy(deleted_maps); + if (imported) + return true; + ShowWarning("map_config_read_map_list: no maps found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + RECREATE(map->list, struct map_data, map->count + count); // TODO: VECTOR candidate + + for (i = 0; i < count; i++) { + const char *mapname; - if (line[0] == '/' && line[1] == '/') + if ((mapname = libconfig->setting_get_string_elem(setting, i)) == NULL || mapname[0] == '\0') continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) + + if (strdb_exists(deleted_maps, mapname)) continue; - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; + map->addmap(mapname); + } + + RECREATE(map->list, struct map_data, map->count); + + db_destroy(deleted_maps); + return true; +} + +/** + * Reads map-server configuration files (map-server.conf) and initialises + * required variables. + * + * @param filename Path to configuration file. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_config_read(const char *filename, bool imported) +{ + struct config_t config; + struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; + + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; + + if ((setting = libconfig->lookup(&config, "map_configuration")) == NULL) { + libconfig->destroy(&config); + if (imported) + return true; + ShowError("map_config_read: map_configuration was not found in %s!\n", filename); + return false; + } - if (strcmpi(w1, "map") == 0) - map->addmap(w2); - else if (strcmpi(w1, "delmap") == 0) - map->delmap(w2); - else if (strcmpi(w1, "import") == 0) - map->config_read_sub(w2); + libconfig->setting_lookup_mutable_string(setting, "help_txt", map->help_txt, sizeof(map->help_txt)); + libconfig->setting_lookup_mutable_string(setting, "charhelp_txt", map->charhelp_txt, sizeof(map->charhelp_txt)); + libconfig->setting_lookup_bool(setting, "enable_spy", &map->enable_spy); + libconfig->setting_lookup_bool(setting, "use_grf", &map->enable_grf); + libconfig->setting_lookup_mutable_string(setting, "default_language", map->default_lang_str, sizeof(map->default_lang_str)); + + if (!map_config_read_console(filename, &config, imported)) + retval = false; + if (!map_config_read_connection(filename, &config, imported)) + retval = false; + if (!map_config_read_inter(filename, &config, imported)) + retval = false; + if (!map_config_read_database(filename, &config, imported)) + retval = false; + if (!map_config_read_map_list(filename, &config, imported)) + retval = false; + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, map->MAP_CONF_NAME) == 0) { + ShowWarning("map_config_read: Loop detected! Skipping 'import'...\n"); + } else { + if (!map->config_read(import, true)) + retval = false; + } } - fclose(fp); - return 0; + libconfig->destroy(&config); + return retval; } -void map_reloadnpc_sub(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - fp = fopen(cfgName,"r"); - if (fp == NULL) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return; +/** + * Reads 'npc_global_list'/'npc_removed_list' and adds or removes NPC sources + * from map-server. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool map_read_npclist(const char *filename, bool imported) +{ + struct config_t config; + struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; + bool remove_all = false; + + struct DBMap *deleted_npcs; + + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; + + deleted_npcs = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); + + // Remove NPCs + if ((setting = libconfig->lookup(&config, "npc_removed_list")) != NULL) { + int i, del_count = libconfig->setting_length(setting); + for (i = 0; i < del_count; i++) { + const char *scriptname; + + if ((scriptname = libconfig->setting_get_string_elem(setting, i)) == NULL || scriptname[0] == '\0') + continue; + + if (strcmp(scriptname, "all") == 0) { + remove_all = true; + npc->clearsrcfile(); + } else { + strdb_put(deleted_npcs, scriptname, NULL); + npc->delsrcfile(scriptname); + } + } } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + if ((setting = libconfig->lookup(&config, "npc_global_list")) != NULL) { + int i, count = libconfig->setting_length(setting); + if (count <= 0) { + if (!imported) { + ShowWarning("map_read_npclist: no NPCs found in %s!\n", filename); + retval = false; + } + } + for (i = 0; i < count; i++) { + const char *scriptname; + + if ((scriptname = libconfig->setting_get_string_elem(setting, i)) == NULL || scriptname[0] == '\0') + continue; - if (line[0] == '/' && line[1] == '/') - continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) - continue; + if (remove_all || strdb_exists(deleted_npcs, scriptname)) + continue; - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; - - if (strcmpi(w1, "npc") == 0) - npc->addsrcfile(w2); - else if (strcmpi(w1, "import") == 0) - map->reloadnpc_sub(w2); - else if (strcmpi(w1, "delnpc") == 0) - npc->delsrcfile(w2); - else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + npc->addsrcfile(scriptname); + } + } else { + ShowError("map_read_npclist: npc_global_list was not found in %s!\n", filename); + retval = false; + } + + db_destroy(deleted_npcs); + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + const char *base_npclist = NULL; +#ifdef RENEWAL + base_npclist = "npc/re/scripts_main.conf"; +#else + base_npclist = "npc/pre-re/scripts_main.conf"; +#endif + if (strcmp(import, filename) == 0 || strcmp(import, base_npclist) == 0) { + ShowWarning("map_read_npclist: Loop detected! Skipping 'import'...\n"); + } else { + if (!map->read_npclist(import, true)) + retval = false; + } } - fclose(fp); + libconfig->destroy(&config); + return retval; } /** @@ -3864,12 +4214,12 @@ void map_reloadnpc_sub(char *cfgName) { void map_reloadnpc(bool clear) { int i; if (clear) - npc->addsrcfile("clear"); // this will clear the current script list + npc->clearsrcfile(); #ifdef RENEWAL - map->reloadnpc_sub("npc/re/scripts_main.conf"); + map->read_npclist("npc/re/scripts_main.conf", false); #else - map->reloadnpc_sub("npc/pre-re/scripts_main.conf"); + map->read_npclist("npc/pre-re/scripts_main.conf", false); #endif // Append extra scripts @@ -3878,62 +4228,126 @@ void map_reloadnpc(bool clear) { } } -int inter_config_read(char *cfgName) { - char line[1024],w1[1024],w2[1024]; - FILE *fp; +/** + * Reads inter-server.conf and initializes required variables. + * + * @param filename Path to configuration file + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool inter_config_read(const char *filename, bool imported) +{ + struct config_t config; + const struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; - if (!(fp = fopen(cfgName,"r"))) { - ShowError("File not found: %s\n",cfgName); - return 1; + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; + + if ((setting = libconfig->lookup(&config, "inter_configuration")) == NULL) { + libconfig->destroy(&config); + if (imported) + return true; + ShowError("inter_config_read: inter_configuration was not found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2) < 2) - continue; - /* map sql stuff */ - if(strcmpi(w1,"map_server_ip")==0) - safestrncpy(map->server_ip, w2, sizeof(map->server_ip)); - else if(strcmpi(w1,"map_server_port")==0) - map->server_port=atoi(w2); - else if(strcmpi(w1,"map_server_id")==0) - safestrncpy(map->server_id, w2, sizeof(map->server_id)); - else if(strcmpi(w1,"map_server_pw")==0) - safestrncpy(map->server_pw, w2, sizeof(map->server_pw)); - else if(strcmpi(w1,"map_server_db")==0) - safestrncpy(map->server_db, w2, sizeof(map->server_db)); - else if(strcmpi(w1,"default_codepage")==0) - safestrncpy(map->default_codepage, w2, sizeof(map->default_codepage)); - else if(strcmpi(w1,"autotrade_merchants_db")==0) - safestrncpy(map->autotrade_merchants_db, w2, sizeof(map->autotrade_merchants_db)); - else if(strcmpi(w1,"autotrade_data_db")==0) - safestrncpy(map->autotrade_data_db, w2, sizeof(map->autotrade_data_db)); - else if(strcmpi(w1,"npc_market_data_db")==0) - safestrncpy(map->npc_market_data_db, w2, sizeof(map->npc_market_data_db)); - /* sql log db */ - else if(strcmpi(w1,"log_db_ip")==0) - safestrncpy(logs->db_ip, w2, sizeof(logs->db_ip)); - else if(strcmpi(w1,"log_db_id")==0) - safestrncpy(logs->db_id, w2, sizeof(logs->db_id)); - else if(strcmpi(w1,"log_db_pw")==0) - safestrncpy(logs->db_pw, w2, sizeof(logs->db_pw)); - else if(strcmpi(w1,"log_db_port")==0) - logs->db_port = atoi(w2); - else if(strcmpi(w1,"log_db_db")==0) - safestrncpy(logs->db_name, w2, sizeof(logs->db_name)); - /* mapreg */ - else if( mapreg->config_read(w1,w2) ) - continue; - /* import */ - else if(strcmpi(w1,"import")==0) - map->inter_config_read(w2); - else - HPM->parseConf(w1, w2, HPCT_MAP_INTER); + if (!map->inter_config_read_database_names(filename, &config, imported)) + retval = false; + if (!map->inter_config_read_connection(filename, &config, imported)) + retval = false; + + if (!HPM->parse_conf(&config, filename, HPCT_MAP_INTER, imported)) + retval = false; + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, map->INTER_CONF_NAME) == 0) { + ShowWarning("inter_config_read: Loop detected in %s! Skipping 'import'...\n", filename); + } else { + if (!map->inter_config_read(import, true)) + retval = false; + } } - fclose(fp); - return 0; + libconfig->destroy(&config); + return retval; +} + +/** + * Reads the 'inter_configuration/log/sql_connection' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool inter_config_read_connection(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "inter_configuration/log/sql_connection")) == NULL) { + if (imported) + return true; + ShowError("inter_config_read: inter_configuration/log/sql_connection was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_int(setting, "db_port", &logs->db_port); + libconfig->setting_lookup_mutable_string(setting, "db_hostname", logs->db_ip, sizeof(logs->db_ip)); + libconfig->setting_lookup_mutable_string(setting, "db_username", logs->db_id, sizeof(logs->db_id)); + libconfig->setting_lookup_mutable_string(setting, "db_password", logs->db_pw, sizeof(logs->db_pw)); + libconfig->setting_lookup_mutable_string(setting, "db_database", logs->db_name, sizeof(logs->db_name)); + + return true; +} + +/** + * Reads the 'inter_configuration/database_names' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool inter_config_read_database_names(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + bool retval = true; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "inter_configuration/database_names")) == NULL) { + if (imported) + return true; + ShowError("inter_config_read: inter_configuration/database_names was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_mutable_string(setting, "autotrade_merchants_db", map->autotrade_merchants_db, sizeof(map->autotrade_merchants_db)); + libconfig->setting_lookup_mutable_string(setting, "autotrade_data_db", map->autotrade_data_db, sizeof(map->autotrade_data_db)); + libconfig->setting_lookup_mutable_string(setting, "npc_market_data_db", map->npc_market_data_db, sizeof(map->npc_market_data_db)); + + if (!mapreg->config_read(filename, setting, imported)) + retval = false; + + if ((setting = libconfig->lookup(config, "inter_configuration/database_names/registry")) == NULL) { + if (imported) + return retval; + ShowError("inter_config_read: inter_configuration/database_names/registry was not found in %s!\n", filename); + return false; + } + return retval; } /*======================================= @@ -3979,7 +4393,10 @@ struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone struct map_zone_data *zone = NULL; int cursor, i, j; - sprintf(newzone, "%s+%s",main->name,other->name); + nullpo_retr(NULL, main); + nullpo_retr(NULL, other); + + snprintf(newzone, MAP_ZONE_NAME_LENGTH, "%s+%s", main->name, other->name); if( (zone = strdb_get(map->zone_db, newzone)) ) return zone;/* this zone has already been merged */ @@ -4072,6 +4489,7 @@ void map_zone_change2(int m, struct map_zone_data *zone) { const char *empty = ""; + Assert_retv(m >= 0 && m < map->count); if( map->list[m].zone == zone ) return; @@ -4089,6 +4507,7 @@ void map_zone_change2(int m, struct map_zone_data *zone) } /* when changing from a mapflag to another during runtime */ void map_zone_change(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) { + Assert_retv(m >= 0 && m < map->count); map->list[m].prev_zone = map->list[m].zone; if( map->list[m].zone_mf_count ) @@ -4101,6 +4520,7 @@ void map_zone_remove(int m) char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; unsigned short k; const char *empty = ""; + Assert_retv(m >= 0 && m < map->count); for(k = 0; k < map->list[m].zone_mf_count; k++) { size_t len = strlen(map->list[m].zone_mf[k]),j; params[0] = '\0'; @@ -4123,6 +4543,7 @@ void map_zone_remove(int m) map->list[m].zone_mf_count = 0; } static inline void map_zone_mf_cache_add(int m, char *rflag) { + Assert_retv(m >= 0 && m < map->count); RECREATE(map->list[m].zone_mf, char *, ++map->list[m].zone_mf_count); CREATE(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH); safestrncpy(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], rflag, MAP_ZONE_MAPFLAG_LENGTH); @@ -4133,6 +4554,10 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { char rflag[MAP_ZONE_MAPFLAG_LENGTH]; int state = 1; + nullpo_retr(false, flag); + nullpo_retr(false, params); + Assert_retr(false, m >= 0 && m < map->count); + if (params[0] != '\0' && !strcmpi(params, "off")) state = 0; @@ -4829,6 +5254,8 @@ void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const int i; const char *empty = ""; char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; + Assert_retv(m >= 0 && m < map->count); + nullpo_retv(zone); map->list[m].zone = zone; for(i = 0; i < zone->mapflags_count; i++) { size_t len = strlen(zone->mapflags[i]); @@ -4939,8 +5366,9 @@ unsigned short map_zone_str2skillid(const char *name) { enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *subtype) { char temp[200], *parse; enum bl_type bl = BL_NUL; - *subtype = MZS_NONE; + nullpo_retr(BL_NUL, subtype); + *subtype = MZS_NONE; if( !entry ) return BL_NUL; @@ -4982,27 +5410,27 @@ enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *su } /* [Ind/Hercules] */ void read_map_zone_db(void) { - config_t map_zone_db; - config_setting_t *zones = NULL; + struct config_t map_zone_db; + struct config_setting_t *zones = NULL; /* TODO: #ifndef required for re/pre-re */ #ifdef RENEWAL const char *config_filename = "db/re/map_zone_db.conf"; // FIXME hardcoded name #else const char *config_filename = "db/pre-re/map_zone_db.conf"; // FIXME hardcoded name #endif - if (libconfig->read_file(&map_zone_db, config_filename)) + if (!libconfig->load_file(&map_zone_db, config_filename)) return; zones = libconfig->lookup(&map_zone_db, "zones"); if (zones != NULL) { struct map_zone_data *zone; - config_setting_t *zone_e; - config_setting_t *skills; - config_setting_t *items; - config_setting_t *mapflags; - config_setting_t *commands; - config_setting_t *caps; + struct config_setting_t *zone_e; + struct config_setting_t *skills; + struct config_setting_t *items; + struct config_setting_t *mapflags; + struct config_setting_t *commands; + struct config_setting_t *caps; const char *name; const char *zonename; int i,h,v,j; @@ -5017,7 +5445,7 @@ void read_map_zone_db(void) { zone_e = libconfig->setting_get_elem(zones, i); if (!libconfig->setting_lookup_string(zone_e, "name", &zonename)) { - ShowError("map_zone_db: missing zone name, skipping... (%s:%d)\n", + ShowError("map_zone_db: missing zone name, skipping... (%s:%u)\n", config_setting_source_file(zone_e), config_setting_source_line(zone_e)); libconfig->setting_remove_elem(zones,i);/* remove from the tree */ --zone_count; @@ -5054,7 +5482,7 @@ void read_map_zone_db(void) { disabled_skills_count = libconfig->setting_length(skills); /* validate */ for(h = 0; h < libconfig->setting_length(skills); h++) { - config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); + struct config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); name = config_setting_name(skillinfo); if( !map->zone_str2skillid(name) ) { ShowError("map_zone_db: unknown skill (%s) in disabled_skills for zone '%s', skipping skill...\n",name,zone->name); @@ -5069,7 +5497,7 @@ void read_map_zone_db(void) { /* all ok, process */ CREATE( zone->disabled_skills, struct map_zone_disabled_skill_entry *, disabled_skills_count ); for(h = 0, v = 0; h < libconfig->setting_length(skills); h++) { - config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); + struct config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); struct map_zone_disabled_skill_entry * entry; enum bl_type type; name = config_setting_name(skillinfo); @@ -5092,7 +5520,7 @@ void read_map_zone_db(void) { disabled_items_count = libconfig->setting_length(items); /* validate */ for(h = 0; h < libconfig->setting_length(items); h++) { - config_setting_t *item = libconfig->setting_get_elem(items, h); + struct config_setting_t *item = libconfig->setting_get_elem(items, h); name = config_setting_name(item); if( !map->zone_str2itemid(name) ) { ShowError("map_zone_db: unknown item (%s) in disabled_items for zone '%s', skipping item...\n",name,zone->name); @@ -5111,7 +5539,7 @@ void read_map_zone_db(void) { CREATE(zone->cant_disable_items, int, zone->cant_disable_items_count); } for(h = 0, v = 0, j = 0; h < libconfig->setting_length(items); h++) { - config_setting_t *item = libconfig->setting_get_elem(items, h); + struct config_setting_t *item = libconfig->setting_get_elem(items, h); name = config_setting_name(item); if( libconfig->setting_get_bool(item) ) { /* only add if enabled */ @@ -5143,7 +5571,7 @@ void read_map_zone_db(void) { disabled_commands_count = libconfig->setting_length(commands); /* validate */ for(h = 0; h < libconfig->setting_length(commands); h++) { - config_setting_t *command = libconfig->setting_get_elem(commands, h); + struct config_setting_t *command = libconfig->setting_get_elem(commands, h); name = config_setting_name(command); if( !atcommand->exists(name) ) { ShowError("map_zone_db: unknown command '%s' in disabled_commands for zone '%s', skipping entry...\n",name,zone->name); @@ -5158,7 +5586,7 @@ void read_map_zone_db(void) { /* all ok, process */ CREATE( zone->disabled_commands, struct map_zone_disabled_command_entry *, disabled_commands_count ); for(h = 0, v = 0; h < libconfig->setting_length(commands); h++) { - config_setting_t *command = libconfig->setting_get_elem(commands, h); + struct config_setting_t *command = libconfig->setting_get_elem(commands, h); struct map_zone_disabled_command_entry * entry; int group_lv; name = config_setting_name(command); @@ -5179,7 +5607,7 @@ void read_map_zone_db(void) { capped_skills_count = libconfig->setting_length(caps); /* validate */ for(h = 0; h < libconfig->setting_length(caps); h++) { - config_setting_t *cap = libconfig->setting_get_elem(caps, h); + struct config_setting_t *cap = libconfig->setting_get_elem(caps, h); name = config_setting_name(cap); if( !map->zone_str2skillid(name) ) { ShowError("map_zone_db: unknown skill (%s) in skill_damage_cap for zone '%s', skipping skill...\n",name,zone->name); @@ -5194,7 +5622,7 @@ void read_map_zone_db(void) { /* all ok, process */ CREATE( zone->capped_skills, struct map_zone_skill_damage_cap_entry *, capped_skills_count ); for(h = 0, v = 0; h < libconfig->setting_length(caps); h++) { - config_setting_t *cap = libconfig->setting_get_elem(caps, h); + struct config_setting_t *cap = libconfig->setting_get_elem(caps, h); struct map_zone_skill_damage_cap_entry * entry; enum bl_type type; name = config_setting_name(cap); @@ -5219,8 +5647,8 @@ void read_map_zone_db(void) { /* process inheritance, aka loop through the whole thing again :P */ for (i = 0; i < zone_count; ++i) { - config_setting_t *inherit_tree = NULL; - config_setting_t *new_entry = NULL; + struct config_setting_t *inherit_tree = NULL; + struct config_setting_t *new_entry = NULL; int inherit_count; zone_e = libconfig->setting_get_elem(zones, i); @@ -5278,7 +5706,7 @@ void read_map_zone_db(void) { for(j = 0; j < disabled_skills_count_i; j++) { int k; for(k = 0; k < disabled_skills_count; k++) { - config_setting_t *skillinfo = libconfig->setting_get_elem(skills, k); + struct config_setting_t *skillinfo = libconfig->setting_get_elem(skills, k); if( map->zone_str2skillid(config_setting_name(skillinfo)) == izone->disabled_skills[j]->nameid ) { break; } @@ -5302,7 +5730,7 @@ void read_map_zone_db(void) { for(j = 0; j < disabled_items_count_i; j++) { int k; for(k = 0; k < disabled_items_count; k++) { - config_setting_t *item = libconfig->setting_get_elem(items, k); + struct config_setting_t *item = libconfig->setting_get_elem(items, k); name = config_setting_name(item); @@ -5348,7 +5776,7 @@ void read_map_zone_db(void) { for(j = 0; j < disabled_commands_count_i; j++) { int k; for(k = 0; k < disabled_commands_count; k++) { - config_setting_t *command = libconfig->setting_get_elem(commands, k); + struct config_setting_t *command = libconfig->setting_get_elem(commands, k); if( atcommand->exists(config_setting_name(command))->func == izone->disabled_commands[j]->cmd ) { break; } @@ -5372,7 +5800,7 @@ void read_map_zone_db(void) { for(j = 0; j < capped_skills_count_i; j++) { int k; for(k = 0; k < capped_skills_count; k++) { - config_setting_t *cap = libconfig->setting_get_elem(caps, k); + struct config_setting_t *cap = libconfig->setting_get_elem(caps, k); if( map->zone_str2skillid(config_setting_name(cap)) == izone->capped_skills[j]->nameid ) { break; } @@ -5414,6 +5842,8 @@ int map_get_new_bonus_id (void) { void map_add_questinfo(int m, struct questinfo *qi) { unsigned short i; + nullpo_retv(qi); + Assert_retv(m >= 0 && m < map->count); /* duplicate, override */ for(i = 0; i < map->list[m].qi_count; i++) { if( map->list[m].qi_data[i].nd == qi->nd ) @@ -5429,6 +5859,7 @@ void map_add_questinfo(int m, struct questinfo *qi) { bool map_remove_questinfo(int m, struct npc_data *nd) { unsigned short i; + Assert_retr(false, m >= 0 && m < map->count); for(i = 0; i < map->list[m].qi_count; i++) { struct questinfo *qi = &map->list[m].qi_data[i]; if( qi->nd == nd ) { @@ -5445,7 +5876,8 @@ bool map_remove_questinfo(int m, struct npc_data *nd) { /** * @see DBApply */ -int map_db_final(DBKey key, DBData *data, va_list ap) { +int map_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct map_data_other_server *mdos = DB->data2ptr(data); if(mdos && iMalloc->verify_ptr(mdos) && mdos->cell == NULL) @@ -5457,7 +5889,7 @@ int map_db_final(DBKey key, DBData *data, va_list ap) { /** * @see DBApply */ -int nick_db_final(DBKey key, DBData *data, va_list args) +int nick_db_final(union DBKey key, struct DBData *data, va_list args) { struct charid2nick* p = DB->data2ptr(data); struct charid_request* req; @@ -5504,7 +5936,8 @@ int cleanup_sub(struct block_list *bl, va_list ap) { /** * @see DBApply */ -int cleanup_db_sub(DBKey key, DBData *data, va_list va) { +int cleanup_db_sub(union DBKey key, struct DBData *data, va_list va) +{ return map->cleanup_sub(DB->data2ptr(data), va); } @@ -5585,8 +6018,8 @@ int do_final(void) { map->map_db->destroy(map->map_db, map->db_final); mapindex->final(); - if(map->enable_grf) - grfio_final(); + if (map->enable_grf) + grfio->final(); db_destroy(map->id_db); db_destroy(map->pc_db); @@ -5910,22 +6343,6 @@ static CMDLINEARG(loadscript) } /** - * --generate-translations - * - * Creates "./generated_translations.pot" - * @see cmdline->exec - **/ -static CMDLINEARG(generatetranslations) { - script->lang_export_file = aStrdup("./generated_translations.pot"); - - if( !(script->lang_export_fp = fopen(script->lang_export_file,"wb")) ) { - ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file); - } - core->runflag = CORE_ST_STOP; - return true; -} - -/** * Defines the local command line arguments */ void cmdline_args_init_local(void) @@ -5941,7 +6358,6 @@ void cmdline_args_init_local(void) CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT); CMDLINEARG_DEF2(load-script, loadscript, "Loads an additional script (can be repeated).", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); - CMDLINEARG_DEF2(generate-translations, generatetranslations, "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.", CMDLINE_OPT_NORMAL); } int do_init(int argc, char *argv[]) @@ -5955,12 +6371,12 @@ int do_init(int argc, char *argv[]) map_load_defaults(); - map->INTER_CONF_NAME = aStrdup("conf/inter-server.conf"); - map->LOG_CONF_NAME = aStrdup("conf/logs.conf"); - map->MAP_CONF_NAME = aStrdup("conf/map-server.conf"); - map->BATTLE_CONF_FILENAME = aStrdup("conf/battle.conf"); + map->INTER_CONF_NAME = aStrdup("conf/common/inter-server.conf"); + map->LOG_CONF_NAME = aStrdup("conf/map/logs.conf"); + map->MAP_CONF_NAME = aStrdup("conf/map/map-server.conf"); + map->BATTLE_CONF_FILENAME = aStrdup("conf/map/battle.conf"); map->ATCOMMAND_CONF_FILENAME = aStrdup("conf/atcommand.conf"); - map->SCRIPT_CONF_NAME = aStrdup("conf/script.conf"); + map->SCRIPT_CONF_NAME = aStrdup("conf/map/script.conf"); map->MSG_CONF_NAME = aStrdup("conf/messages.conf"); map->GRF_PATH_FILENAME = aStrdup("conf/grf-files.txt"); @@ -5973,10 +6389,30 @@ int do_init(int argc, char *argv[]) cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL); minimal = map->minimal;/* temp (perhaps make minimal a mask with options of what to load? e.g. plugin 1 does minimal |= mob_db; */ if (!minimal) { - map->config_read(map->MAP_CONF_NAME); - CREATE(map->list,struct map_data,map->count); - map->count = 0; - map->config_read_sub(map->MAP_CONF_NAME); + map->config_read(map->MAP_CONF_NAME, false); + + { + // TODO: Remove this when no longer needed. +#define CHECK_OLD_LOCAL_CONF(oldname, newname) do { \ + if (stat((oldname), &fileinfo) == 0 && fileinfo.st_size > 0) { \ + ShowWarning("An old configuration file \"%s\" was found.\n", (oldname)); \ + ShowWarning("If it contains settings you wish to keep, please merge them into \"%s\".\n", (newname)); \ + ShowWarning("Otherwise, just delete it.\n"); \ + ShowInfo("Resuming in 10 seconds...\n"); \ + HSleep(10); \ + } \ +} while (0) + struct stat fileinfo; + + CHECK_OLD_LOCAL_CONF("conf/import/map_conf.txt", "conf/import/map-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/inter_conf.txt", "conf/import/inter-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/log_conf.txt", "conf/import/logs.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/script_conf.txt", "conf/import/script.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/packet_conf.txt", "conf/import/socket.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/battle_conf.txt", "conf/import/battle.conf"); + +#undef CHECK_OLD_LOCAL_CONF + } // loads npcs map->reloadnpc(false); @@ -5987,7 +6423,9 @@ int do_init(int argc, char *argv[]) char ip_str[16]; sockt->ip2str(sockt->addr_[0], ip_str); - ShowWarning("Not all IP addresses in /conf/map-server.conf configured, auto-detecting...\n"); +#ifndef BUILDBOT + ShowWarning("Not all IP addresses in /conf/map/map-server.conf configured, auto-detecting...\n"); +#endif if (sockt->naddr_ == 0) ShowError("Unable to determine your IP address...\n"); @@ -6002,12 +6440,12 @@ int do_init(int argc, char *argv[]) chrif->setip(ip_str); } - battle->config_read(map->BATTLE_CONF_FILENAME); + battle->config_read(map->BATTLE_CONF_FILENAME, false); atcommand->msg_read(map->MSG_CONF_NAME, false); - map->inter_config_read(map->INTER_CONF_NAME); - logs->config_read(map->LOG_CONF_NAME); + map->inter_config_read(map->INTER_CONF_NAME, false); + logs->config_read(map->LOG_CONF_NAME, false); } - script->config_read(map->SCRIPT_CONF_NAME); + script->config_read(map->SCRIPT_CONF_NAME, false); map->id_db = idb_alloc(DB_OPT_BASE); map->pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable map->id2sd() use. [Skotlex] @@ -6045,8 +6483,8 @@ int do_init(int argc, char *argv[]) } } - if(map->enable_grf) - grfio_init(map->GRF_PATH_FILENAME); + if (map->enable_grf) + grfio->init(map->GRF_PATH_FILENAME); map->readallmaps(); @@ -6151,7 +6589,6 @@ void map_defaults(void) { sprintf(map->db_path ,"db"); sprintf(map->help_txt ,"conf/help.txt"); - sprintf(map->help2_txt ,"conf/help2.txt"); sprintf(map->charhelp_txt ,"conf/charhelp.txt"); sprintf(map->wisp_server_name ,"Server"); // can be modified in char-server configuration file @@ -6164,12 +6601,12 @@ void map_defaults(void) { map->night_flag = 0; // 0=day, 1=night [Yor] map->enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] - map->INTER_CONF_NAME="conf/inter-server.conf"; - map->LOG_CONF_NAME="conf/logs.conf"; - map->MAP_CONF_NAME = "conf/map-server.conf"; - map->BATTLE_CONF_FILENAME = "conf/battle.conf"; + map->INTER_CONF_NAME="conf/common/inter-server.conf"; + map->LOG_CONF_NAME="conf/map/logs.conf"; + map->MAP_CONF_NAME = "conf/map/map-server.conf"; + map->BATTLE_CONF_FILENAME = "conf/map/battle.conf"; map->ATCOMMAND_CONF_FILENAME = "conf/atcommand.conf"; - map->SCRIPT_CONF_NAME = "conf/script.conf"; + map->SCRIPT_CONF_NAME = "conf/map/script.conf"; map->MSG_CONF_NAME = "conf/messages.conf"; map->GRF_PATH_FILENAME = "conf/grf-files.txt"; @@ -6375,9 +6812,10 @@ void map_defaults(void) { map->readgat = map_readgat; map->readallmaps = map_readallmaps; map->config_read = map_config_read; - map->config_read_sub = map_config_read_sub; - map->reloadnpc_sub = map_reloadnpc_sub; + map->read_npclist = map_read_npclist; map->inter_config_read = inter_config_read; + map->inter_config_read_database_names = inter_config_read_database_names; + map->inter_config_read_connection = inter_config_read_connection; map->sql_init = map_sql_init; map->sql_close = map_sql_close; map->zone_mf_cache = map_zone_mf_cache; |