diff options
author | Haru <haru@dotalux.com> | 2014-05-09 07:37:53 +0200 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2014-05-09 07:40:43 +0200 |
commit | 5f1529083ad1f35a3ac66cc041ee74d6db2f3552 (patch) | |
tree | 32c4d73a7f68cd7a1a963e14e3972333758bb541 /src | |
parent | 581ff22b9bad7567a27980df31636f0c75ba5fc2 (diff) | |
download | hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.gz hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.bz2 hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.xz hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.zip |
Return EXIT_FAILURE if a script parse error occurred.
- This affects normal execution as well as ./script-checker runs.
Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/map/itemdb.c | 14 | ||||
-rw-r--r-- | src/map/map.c | 10 | ||||
-rw-r--r-- | src/map/npc.c | 239 | ||||
-rw-r--r-- | src/map/npc.h | 16 | ||||
-rw-r--r-- | src/map/pet.c | 4 | ||||
-rw-r--r-- | src/map/script.c | 19 | ||||
-rw-r--r-- | src/map/script.h | 2 |
7 files changed, 178 insertions, 126 deletions
diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 1bbe87a20..5eeb90be5 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1478,7 +1478,7 @@ void itemdb_read_combos() { CREATE(combo, struct item_combo, 1); combo->count = retcount; - combo->script = script->parse(str[1], filepath, lines, 0); + combo->script = script->parse(str[1], filepath, lines, 0, NULL); combo->id = itemdb->combo_count - 1; /* populate ->nameid field */ for( v = 0; v < retcount; v++ ) { @@ -1707,9 +1707,9 @@ int itemdb_readdb_sql_sub(Sql *handle, int n, const char *source) { SQL->GetData(handle, 19, &data, NULL); id.flag.no_refine = data && atoi(data) ? 0 : 1; SQL->GetData(handle, 20, &data, NULL); id.look = data ? atoi(data) : 0; SQL->GetData(handle, 21, &data, NULL); id.flag.bindonequip = data && atoi(data) ? 1 : 0; - SQL->GetData(handle, 22, &data, NULL); id.script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; - SQL->GetData(handle, 23, &data, NULL); id.equip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; - SQL->GetData(handle, 24, &data, NULL); id.unequip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; + SQL->GetData(handle, 22, &data, NULL); id.script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + SQL->GetData(handle, 23, &data, NULL); id.equip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + SQL->GetData(handle, 24, &data, NULL); id.unequip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; return itemdb->validate_entry(&id, n, source); } @@ -1875,13 +1875,13 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) id.flag.bindonequip = libconfig->setting_get_bool(t) ? 1 : 0; if( libconfig->setting_lookup_string(it, "Script", &str) ) - id.script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; + id.script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; if( libconfig->setting_lookup_string(it, "OnEquipScript", &str) ) - id.equip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; + id.equip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; if( libconfig->setting_lookup_string(it, "OnUnequipScript", &str) ) - id.unequip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS) : NULL; + id.unequip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; return itemdb->validate_entry(&id, n, source); } diff --git a/src/map/map.c b/src/map/map.c index a5ec6d83b..24a07699f 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3841,7 +3841,7 @@ void map_zone_remove(int m) { } } - npc->parse_mapflag(map->list[m].name,empty,flag,params,empty,empty,empty); + npc->parse_mapflag(map->list[m].name,empty,flag,params,empty,empty,empty, NULL); aFree(map->list[m].zone_mf[k]); map->list[m].zone_mf[k] = NULL; } @@ -4573,7 +4573,7 @@ void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const if( map->zone_mf_cache(m,flag,params) ) continue; - npc->parse_mapflag(map->list[m].name,empty,flag,params,start,buffer,filepath); + npc->parse_mapflag(map->list[m].name, empty, flag, params, start, buffer, filepath, NULL); } } /* used on npc load and reload to apply all "Normal" and "PK Mode" zones */ @@ -4601,7 +4601,7 @@ void map_zone_init(void) { if( map->list[j].zone == zone ) { if( map->zone_mf_cache(j,flag,params) ) break; - npc->parse_mapflag(map->list[j].name,empty,flag,params,empty,empty,empty); + npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL); } } } @@ -4623,7 +4623,7 @@ void map_zone_init(void) { if( map->list[j].zone == zone ) { if( map->zone_mf_cache(j,flag,params) ) break; - npc->parse_mapflag(map->list[j].name,empty,flag,params,empty,empty,empty); + npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL); } } } @@ -5810,7 +5810,7 @@ int do_init(int argc, char *argv[]) if (scriptcheck) { bool failed = load_extras_count > 0 ? false : true; for (i = 0; i < load_extras_count; i++) { - if (npc->parsesrcfile(load_extras[i], false) != 0) + if (npc->parsesrcfile(load_extras[i], false) != EXIT_SUCCESS) failed = true; } if (failed) diff --git a/src/map/npc.c b/src/map/npc.c index 43e4bcc88..27759d185 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2532,8 +2532,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short } /// Parses a warp npc. -const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int x, y, xs, ys, to_x, to_y, m; unsigned short i; char mapname[32], to_mapname[32]; @@ -2542,22 +2541,24 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s // w1=<from map name>,<fromX>,<fromY>,<facing> // w4=<spanx>,<spany>,<to map name>,<toX>,<toY> if( sscanf(w1, "%31[^,],%d,%d", mapname, &x, &y) != 3 - || sscanf(w4, "%d,%d,%31[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5 ) - { + || sscanf(w4, "%d,%d,%31[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5 + ) { ShowError("npc_parse_warp: Invalid warp definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } m = map->mapname2mapid(mapname); i = mapindex->name2id(to_mapname); - if( i == 0 ) - { + if( i == 0 ) { ShowError("npc_parse_warp: Unknown destination map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), to_mapname, w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { ShowError("npc_parse_warp: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');;//try next } @@ -2597,25 +2598,27 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s } /// Parses a shop/cashshop npc. -const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { //TODO: could be rewritten to NOT need this temp array [ultramage] - #define MAX_SHOPITEM 100 +#define MAX_SHOPITEM 100 struct npc_item_list items[MAX_SHOPITEM]; +#undef MAX_SHOPITEM char *p; int x, y, dir, m, i; struct npc_data *nd; enum npc_subtype type; - if( strcmp(w1,"-") == 0 ) {// 'floating' shop? + if( strcmp(w1,"-") == 0 ) { + // 'floating' shop? x = y = dir = 0; m = -1; } else {// w1=<map name>,<x>,<y>,<facing> char mapname[32]; if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 - || strchr(w4, ',') == NULL ) - { + || strchr(w4, ',') == NULL + ) { ShowError("npc_parse_shop: Invalid shop definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } @@ -2624,6 +2627,7 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { ShowError("npc_parse_shop: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');;//try next } @@ -2633,38 +2637,38 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s type = SHOP; p = strchr(w4,','); - for( i = 0; i < ARRAYLENGTH(items) && p; ++i ) - { + for( i = 0; i < ARRAYLENGTH(items) && p; ++i ) { int nameid, value; struct item_data* id; - if( sscanf(p, ",%d:%d", &nameid, &value) != 2 ) - { + if( sscanf(p, ",%d:%d", &nameid, &value) != 2 ) { ShowError("npc_parse_shop: Invalid item definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; break; } - if( (id = itemdb->exists(nameid)) == NULL ) - { + if( (id = itemdb->exists(nameid)) == NULL ) { ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%d').\n", filepath, strline(buffer,start-buffer), nameid); p = strchr(p+1,','); + if (retval) *retval = EXIT_FAILURE; continue; } - if( value < 0 ) - { + if( value < 0 ) { if( type == SHOP ) value = id->value_buy; else value = 0; // Cashshop doesn't have a "buy price" in the item_db } - if( type == SHOP && value == 0 ) - { // NPC selling items for free! + if( type == SHOP && value == 0 ) { + // NPC selling items for free! ShowWarning("npc_parse_shop: Item %s [%d] is being sold for FREE in file '%s', line '%d'.\n", id->name, nameid, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( type == SHOP && value*0.75 < id->value_sell*1.24 ) - {// Exploit possible: you can buy and sell back with profit + if( type == SHOP && value*0.75 < id->value_sell*1.24 ) { + // Exploit possible: you can buy and sell back with profit ShowWarning("npc_parse_shop: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) in file '%s', line '%d'.\n", id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } //for logs filters, atcommands and iteminfo script command if( id->maxchance == 0 ) @@ -2674,9 +2678,9 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s items[i].value = value; p = strchr(p+1,','); } - if( i == 0 ) - { + if( i == 0 ) { ShowWarning("npc_parse_shop: Ignoring empty shop in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// continue } @@ -2743,8 +2747,7 @@ void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath } // Skip the contents of a script. -const char* npc_skip_script(const char* start, const char* buffer, const char* filepath) -{ +const char* npc_skip_script(const char* start, const char* buffer, const char* filepath, int *retval) { const char* p; int curly_count; @@ -2753,9 +2756,9 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f // initial bracket (assumes the previous part is ok) p = strchr(start,'{'); - if( p == NULL ) - { + if( p == NULL ) { ShowError("npc_skip_script: Missing left curly in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } @@ -2775,16 +2778,15 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f {// string for( ++p; *p != '"' ; ++p ) { - if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) + if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) { ++p;// escape sequence (not part of a multibyte character) - else if( *p == '\0' ) - { + } else if( *p == '\0' ) { script->error(buffer, filepath, 0, "Unexpected end of string.", p); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue - } - else if( *p == '\n' ) - { + } else if( *p == '\n' ) { script->error(buffer, filepath, 0, "Unexpected newline at string.", p); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } } @@ -2792,6 +2794,7 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f else if( *p == '\0' ) {// end of buffer ShowError("Missing %d right curlys in file '%s', line '%d'.\n", curly_count, filepath, strline(buffer,p-buffer)); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } } @@ -2804,7 +2807,7 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f /// -%TAB%script%TAB%<NPC Name>%TAB%-1,{<code>} /// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,{<code>} /// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>,{<code>} -const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options) { +const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) { int x, y, dir = 0, m, xs = 0, ys = 0; // [Valaris] thanks to fov char mapname[32]; struct script_code *scriptroot; @@ -2824,6 +2827,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* } else {// npc in a map if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ) { ShowError("npc_parse_script: Invalid placement format for a script in file '%s', line '%d'. Skipping the rest of file...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// unknown format, don't continue } m = map->mapname2mapid(mapname); @@ -2834,15 +2838,16 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* if( strstr(w4,",{") == NULL || script_start == NULL || (end != NULL && script_start > end) ) { ShowError("npc_parse_script: Missing left curly ',{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } ++script_start; - end = npc->skip_script(script_start, buffer, filepath); + end = npc->skip_script(script_start, buffer, filepath, retval); if( end == NULL ) return NULL;// (simple) parse error, don't continue - scriptroot = script->parse(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB); + scriptroot = script->parse(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB, retval); label_list = NULL; label_list_num = 0; if( script->label_count ) { @@ -2906,6 +2911,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* if (npc->event_export(nd, i)) { ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n", nd->exname, nd->u.scr.label_list[i].name, filepath); + if (retval) *retval = EXIT_FAILURE; } npc->timerevent_export(nd, i); } @@ -2936,8 +2942,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* /// npc: -%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY> /// npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY> /// !!Only NPO_ONINIT is available trough options!! -const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options) -{ +const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) { int x, y, dir, m, xs = -1, ys = -1; char mapname[32]; char srcname[128]; @@ -2957,6 +2962,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch if( w2[length-1] != ')' || length <= 11 || length-11 >= sizeof(srcname) ) {// does not match 'duplicate(%127s)', name is empty or too long ShowError("npc_parse_script: bad duplicate name in file '%s', line '%d': %s\n", filepath, strline(buffer,start-buffer), w2); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } safestrncpy(srcname, w2+10, length-10); @@ -2964,6 +2970,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch dnd = npc->name2id(srcname); if( dnd == NULL) { ShowError("npc_parse_script: original npc not found for duplicate in file '%s', line '%d': %s\n", filepath, strline(buffer,start-buffer), srcname); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } src_id = dnd->bl.id; @@ -2979,6 +2986,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch dir = 0; } else if( fields != 4 ) {// <map name>,<x>,<y>,<facing> ShowError("npc_parse_duplicate: Invalid placement format for duplicate in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } m = map->mapname2mapid(mapname); @@ -2986,6 +2994,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { ShowError("npc_parse_duplicate: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return end;//try next } @@ -2993,6 +3002,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY> else if( type == WARP ) { ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } @@ -3069,6 +3079,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch if (npc->event_export(nd, i)) { ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n", nd->exname, nd->u.scr.label_list[i].name, filepath); + if (retval) *retval = EXIT_FAILURE; } npc->timerevent_export(nd, i); } @@ -3152,7 +3163,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) { else snprintf(w4, sizeof(w4), "%d", snd->class_); - npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE); + npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE, NULL); } return 0; @@ -3339,8 +3350,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c /// Parses a function. /// function%TAB%script%TAB%<function name>%TAB%{<code>} -const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { DBMap* func_db; DBData old_data; struct script_code *scriptroot; @@ -3349,18 +3359,18 @@ const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const cha script_start = strstr(start,"\t{"); end = strchr(start,'\n'); - if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) - { + if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) { ShowError("npc_parse_function: Missing left curly '%%TAB%%{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } ++script_start; - end = npc->skip_script(script_start,buffer,filepath); + end = npc->skip_script(script_start,buffer,filepath, retval); if( end == NULL ) return NULL;// (simple) parse error, don't continue - scriptroot = script->parse(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT); + scriptroot = script->parse(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT, retval); if( scriptroot == NULL )// parse error, continue return end; @@ -3394,7 +3404,7 @@ void npc_parse_mob2(struct spawn_data* mobspawn) } } -const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { +const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int num, class_, m,x,y,xs,ys, i,j; int mob_lv = -1, ai = -1, size = -1; char mapname[32], mobname[NAME_LENGTH]; @@ -3413,10 +3423,12 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st || sscanf(w4, "%d,%d,%u,%u,%127[^,],%d,%d[^\t\r\n]", &class_, &num, &mobspawn.delay1, &mobspawn.delay2, mobspawn.eventname, &size, &ai) < 2 ) { ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } if( mapindex->name2id(mapname) == 0 ) { ShowError("npc_parse_mob: Unknown map '%s' in file '%s', line '%d'.\n", mapname, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } m = map->mapname2mapid(mapname); @@ -3426,32 +3438,38 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st if( x < 0 || x >= map->list[mobspawn.m].xs || y < 0 || y >= map->list[mobspawn.m].ys ) { ShowError("npc_parse_mob: Spawn coordinates out of range: %s (%d,%d), map size is (%d,%d) - %s %s in file '%s', line '%d'.\n", map->list[mobspawn.m].name, x, y, (map->list[mobspawn.m].xs-1), (map->list[mobspawn.m].ys-1), w1, w3, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } // check monster ID if exists! if( mob->db_checkid(class_) == 0 ) { ShowError("npc_parse_mob: Unknown mob ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } if( num < 1 || num > 1000 ) { ShowError("npc_parse_mob: Invalid number of monsters %d, must be inside the range [1,1000] in file '%s', line '%d'.\n", num, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } if( (mobspawn.state.size < 0 || mobspawn.state.size > 2) && size != -1 ) { ShowError("npc_parse_mob: Invalid size number %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.size, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } if( (mobspawn.state.ai < 0 || mobspawn.state.ai > 4) && ai != -1 ) { ShowError("npc_parse_mob: Invalid ai %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.ai, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } if( (mob_lv == 0 || mob_lv > MAX_LEVEL) && mob_lv != -1 ) { ShowError("npc_parse_mob: Invalid level %d for mob ID %d in file '%s', line '%d'.\n", mob_lv, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } @@ -3482,6 +3500,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st if(mobspawn.delay1>0xfffffff || mobspawn.delay2>0xfffffff) { ShowError("npc_parse_mob: Invalid spawn delays %u %u in file '%s', line '%d'.\n", mobspawn.delay1, mobspawn.delay2, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } @@ -3496,6 +3515,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st //Verify dataset. if( !mob->parse_dataset(&mobspawn) ) { ShowError("npc_parse_mob: Invalid dataset for monster ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } @@ -3555,7 +3575,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st * eg : bat_c01 mapflag battleground 2 * also chking if mapflag conflict with another *------------------------------------------*/ -const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { +const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int16 m; char mapname[32]; int state = 1; @@ -3564,11 +3584,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( sscanf(w1, "%31[^,]", mapname) != 1 ) { ShowError("npc_parse_mapflag: Invalid mapflag definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } m = map->mapname2mapid(mapname); if( m < 0 ) { ShowWarning("npc_parse_mapflag: Unknown map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", mapname, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } @@ -3590,6 +3612,7 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char map->list[m].save.y = savey; if (!map->list[m].save.map) { ShowWarning("npc_parse_mapflag: Specified save point map '%s' for mapflag 'nosave' not found in file '%s', line '%d', using 'SavePoint'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", savemap, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; map->list[m].save.x = -1; map->list[m].save.y = -1; } @@ -3628,10 +3651,12 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char map->list[m].flag.gvg_dungeon = 0; map->list[m].flag.gvg_castle = 0; ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( state && map->list[m].flag.battleground ) { map->list[m].flag.battleground = 0; ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)) && map->list[m].zone != zone ) { map->zone_change(m,zone,start,buffer,filepath); @@ -3678,10 +3703,12 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( state && map->list[m].flag.pvp ) { map->list[m].flag.pvp = 0; ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( state && map->list[m].flag.battleground ) { map->list[m].flag.battleground = 0; ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)) && map->list[m].zone != zone ) { map->zone_change(m,zone,start,buffer,filepath); @@ -3710,12 +3737,14 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( map->list[m].flag.battleground && map->list[m].flag.pvp ) { map->list[m].flag.pvp = 0; ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( map->list[m].flag.battleground && (map->list[m].flag.gvg || map->list[m].flag.gvg_dungeon || map->list[m].flag.gvg_castle) ) { map->list[m].flag.gvg = 0; map->list[m].flag.gvg_dungeon = 0; map->list[m].flag.gvg_castle = 0; ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) && map->list[m].zone != zone ) { @@ -3818,10 +3847,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( modifier[0] == '\0' ) { ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) { ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n",skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else { int idx = map->list[m].unit_count; @@ -3874,10 +3906,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( modifier[0] == '\0' ) { ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if( !( skill_id = skill->name2id(skill_name) ) ) { ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else { int idx = map->list[m].skill_count; @@ -3916,6 +3951,7 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( !(zone = strdb_get(map->zone_db, w4)) ) { ShowWarning("npc_parse_mapflag: Invalid zone '%s'! removing flag from %s in file '%s', line '%d'.\n", w4, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if( map->list[m].zone != zone ) { map->zone_change(m,zone,start,buffer,filepath); } @@ -3939,15 +3975,25 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char map->list[m].flag.src4instance = (state) ? 1 : 0; } else if ( !strcmpi(w3,"nocashshop") ) { map->list[m].flag.nocashshop = (state) ? 1 : 0; - } else + } else { ShowError("npc_parse_mapflag: unrecognized mapflag '%s' in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + } return strchr(start,'\n');// continue } -//Read file and create npc/func/mapflag/monster... accordingly. -//@runOnInit should we exec OnInit when it's done ? +/** + * Parses a script file and creates NPCs/functions/mapflags/monsters/etc + * accordingly. + * + * @param filepath File name and path. + * @param runOnInit Whether the OnInit label should be called. + * @retval EXIT_SUCCESS if filepath was loaded correctly. + * @retval EXIT_FAILURE if there were errors/warnings when loading filepath. + */ int npc_parsesrcfile(const char* filepath, bool runOnInit) { + int success = EXIT_SUCCESS; int16 m, x, y; int lines = 0; FILE* fp; @@ -3957,10 +4003,9 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { // read whole file to buffer fp = fopen(filepath, "rb"); - if( fp == NULL ) - { + if( fp == NULL ) { ShowError("npc_parsesrcfile: File not found '%s'.\n", filepath); - return -1; + return EXIT_FAILURE; } fseek(fp, 0, SEEK_END); len = ftell(fp); @@ -3968,12 +4013,11 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { fseek(fp, 0, SEEK_SET); len = fread(buffer, sizeof(char), len, fp); buffer[len] = '\0'; - if( ferror(fp) ) - { + if( ferror(fp) ) { ShowError("npc_parsesrcfile: Failed to read file '%s' - %s\n", filepath, strerror(errno)); aFree(buffer); fclose(fp); - return -1; + return EXIT_FAILURE; } fclose(fp); @@ -3986,12 +4030,11 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { ShowError("npc_parsesrcfile: Detected unsupported UTF-8 BOM in file '%s'. Stopping (please consider using another character set.)\n", filepath); aFree(buffer); fclose(fp); - return -1; + return EXIT_FAILURE; } // parse buffer - for( p = script->skip_space(buffer); p && *p ; p = script->skip_space(p) ) - { + for( p = script->skip_space(buffer); p && *p ; p = script->skip_space(p) ) { int pos[9]; char w1[2048], w2[2048], w3[2048], w4[2048]; int i, count; @@ -4002,41 +4045,50 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { if( count < 0 ) { ShowError("npc_parsesrcfile: Parse error in file '%s', line '%d'. Stopping...\n", filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; break; } // fill w1 - if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 ) + if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 ) { ShowWarning("npc_parsesrcfile: w1 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[3]-pos[2], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[3]-pos[2], ARRAYLENGTH(w1)-1); memcpy(w1, p+pos[2], i*sizeof(char)); w1[i] = '\0'; // fill w2 - if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 ) + if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 ) { ShowWarning("npc_parsesrcfile: w2 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[5]-pos[4], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[5]-pos[4], ARRAYLENGTH(w2)-1); memcpy(w2, p+pos[4], i*sizeof(char)); w2[i] = '\0'; // fill w3 - if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 ) + if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 ) { ShowWarning("npc_parsesrcfile: w3 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[7]-pos[6], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[7]-pos[6], ARRAYLENGTH(w3)-1); memcpy(w3, p+pos[6], i*sizeof(char)); w3[i] = '\0'; // fill w4 (to end of line) - if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 ) + if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 ) { ShowWarning("npc_parsesrcfile: w4 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[1]-pos[8], filepath, strline(buffer,p-buffer)); - if( pos[8] != -1 ) - { + success = EXIT_FAILURE; + } + if( pos[8] != -1 ) { i = min(pos[1]-pos[8], ARRAYLENGTH(w4)-1); memcpy(w4, p+pos[8], i*sizeof(char)); w4[i] = '\0'; - } - else + } else { w4[0] = '\0'; + } - if( count < 3 ) - {// Unknown syntax + if( count < 3 ) { + // Unknown syntax ShowError("npc_parsesrcfile: Unknown syntax in file '%s', line '%d'. Stopping...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + success = EXIT_FAILURE; break; } @@ -4045,13 +4097,12 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { char mapname[MAP_NAME_LENGTH*2]; x = y = 0; sscanf(w1,"%23[^,],%hd,%hd[^,]",mapname,&x,&y); - if( !mapindex->name2id(mapname) ) - {// Incorrect map, we must skip the script info... + if( !mapindex->name2id(mapname) ) { + // Incorrect map, we must skip the script info... ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'. Skipping line...\n", mapname, filepath, strline(buffer,p-buffer)); - if( strcmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc->skip_script(p,buffer,filepath)) == NULL) - { + success = EXIT_FAILURE; + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } @@ -4061,10 +4112,8 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { m = map->mapname2mapid(mapname); if( m < 0 ) { // "mapname" is not assigned to this server, we must skip the script info... - if( strcmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc->skip_script(p,buffer,filepath)) == NULL) - { + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } @@ -4073,10 +4122,9 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { } if (x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys) { ShowError("npc_parsesrcfile: Unknown coordinates ('%d', '%d') for map '%s' in file '%s', line '%d'. Skipping line...\n", x, y, mapname, filepath, strline(buffer,p-buffer)); - if( strcmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc->skip_script(p,buffer,filepath)) == NULL) - { + success = EXIT_FAILURE; + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } @@ -4087,37 +4135,37 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { if( strcmp(w2,"warp") == 0 && count > 3 ) { - p = npc->parse_warp(w1,w2,w3,w4, p, buffer, filepath); + p = npc->parse_warp(w1,w2,w3,w4, p, buffer, filepath, &success); } else if( (strcmp(w2,"shop") == 0 || strcmp(w2,"cashshop") == 0) && count > 3 ) { - p = npc->parse_shop(w1,w2,w3,w4, p, buffer, filepath); + p = npc->parse_shop(w1,w2,w3,w4, p, buffer, filepath, &success); } else if( strcmp(w2,"script") == 0 && count > 3 ) { if( strcmp(w1,"function") == 0 ) { - p = npc->parse_function(w1, w2, w3, w4, p, buffer, filepath); + p = npc->parse_function(w1, w2, w3, w4, p, buffer, filepath, &success); } else { #ifdef ENABLE_CASE_CHECK if( strcasecmp(w1, "function") == 0 ) DeprecationWarning("npc_parsesrcfile", w1, "function", filepath, strline(buffer, p-buffer)); // TODO #endif // ENABLE_CASE_CHECK - p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit?NPO_ONINIT:NPO_NONE); + p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit?NPO_ONINIT:NPO_NONE, &success); } } else if( strcmp(w2,"trader") == 0 && count > 3 ) { - p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,(runOnInit?NPO_ONINIT:NPO_NONE)|NPO_TRADER); + p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,(runOnInit?NPO_ONINIT:NPO_NONE)|NPO_TRADER, &success); } else if( (i=0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) && count > 3 ) { - p = npc->parse_duplicate(w1,w2,w3,w4, p, buffer, filepath, (runOnInit?NPO_ONINIT:NPO_NONE)); + p = npc->parse_duplicate(w1,w2,w3,w4, p, buffer, filepath, (runOnInit?NPO_ONINIT:NPO_NONE), &success); } else if( (strcmp(w2,"monster") == 0 || strcmp(w2,"boss_monster") == 0) && count > 3 ) { - p = npc->parse_mob(w1, w2, w3, w4, p, buffer, filepath); + p = npc->parse_mob(w1, w2, w3, w4, p, buffer, filepath, &success); } else if( strcmp(w2,"mapflag") == 0 && count >= 3 ) { - p = npc->parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath); + p = npc->parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath, &success); } else { @@ -4139,11 +4187,12 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { #endif // ENABLE_CASE_CHECK ShowError("npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); p = strchr(p,'\n');// skip and continue + success = EXIT_FAILURE; } } aFree(buffer); - return 0; + return success; } int npc_script_event(struct map_session_data* sd, enum npce_event type) diff --git a/src/map/npc.h b/src/map/npc.h index d1e060a39..d11db0164 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -232,12 +232,12 @@ struct npc_interface { int (*parseview) (const char *w4, const char *start, const char *buffer, const char *filepath); bool (*viewisid) (const char *viewid); struct npc_data* (*add_warp) (char *name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y); - const char* (*parse_warp) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath); - const char* (*parse_shop) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath); + const char* (*parse_warp) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_shop) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); void (*convertlabel_db) (struct npc_label_list *label_list, const char *filepath); - const char* (*skip_script) (const char *start, const char *buffer, const char *filepath); - const char* (*parse_script) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int options); - const char* (*parse_duplicate) (char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options); + const char* (*skip_script) (const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_script) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int options, int *retval); + const char* (*parse_duplicate) (char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval); int (*duplicate4instance) (struct npc_data *snd, int16 m); void (*setcells) (struct npc_data *nd); int (*unsetcells_sub) (struct block_list *bl, va_list ap); @@ -246,10 +246,10 @@ struct npc_interface { void (*setdisplayname) (struct npc_data *nd, const char *newname); void (*setclass) (struct npc_data *nd, short class_); int (*do_atcmd_event) (struct map_session_data *sd, const char *command, const char *message, const char *eventname); - const char* (*parse_function) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath); + const char* (*parse_function) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); void (*parse_mob2) (struct spawn_data *mobspawn); - const char* (*parse_mob) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath); - const char* (*parse_mapflag) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath); + const char* (*parse_mob) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_mapflag) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); int (*parsesrcfile) (const char *filepath, bool runOnInit); int (*script_event) (struct map_session_data *sd, enum npce_event type); void (*read_event_script) (void); diff --git a/src/map/pet.c b/src/map/pet.c index b5870a858..993497434 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -1327,9 +1327,9 @@ int read_petdb() pet->db[j].equip_script = NULL; if( *str[20] ) - pet->db[j].pet_script = script->parse(str[20], filename[i], lines, 0); + pet->db[j].pet_script = script->parse(str[20], filename[i], lines, 0, NULL); if( *str[21] ) - pet->db[j].equip_script = script->parse(str[21], filename[i], lines, 0); + pet->db[j].equip_script = script->parse(str[21], filename[i], lines, 0, NULL); j++; entries++; diff --git a/src/map/script.c b/src/map/script.c index aea4d978f..aecdf9b28 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2242,8 +2242,7 @@ void script_warning(const char* src, const char* file, int start_line, const cha /*========================================== * Analysis of the script *------------------------------------------*/ -struct script_code* parse_script(const char *src,const char *file,int line,int options) -{ +struct script_code* parse_script(const char *src,const char *file,int line,int options, int *retval) { const char *p,*tmpp; int i; struct script_code* code = NULL; @@ -2289,6 +2288,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->parser_current_file = NULL; script->parser_current_line = 0; #endif // ENABLE_CASE_CHECK + if (retval) *retval = EXIT_FAILURE; return NULL; } @@ -2315,8 +2315,10 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o } else {// requires brackets around the script - if( *p != '{' ) + if( *p != '{' ) { disp_error_message("not found '{'",p); + if (retval) *retval = EXIT_FAILURE; + } p = script->skip_space(p+1); if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) {// empty script and can return NULL @@ -2391,13 +2393,14 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o else if( script->str_data[i].type == C_USERFUNC ) {// 'function name;' without follow-up code ShowError("parse_script: function '%s' declared but not defined.\n", script->str_buf+script->str_data[i].str); + if (retval) *retval = EXIT_FAILURE; unresolved_names = true; } } - if( unresolved_names ) - { + if( unresolved_names ) { disp_error_message("parse_script: unresolved function references", p); + if (retval) *retval = EXIT_FAILURE; } #ifdef SCRIPT_DEBUG_DISP @@ -4203,7 +4206,7 @@ void script_run_autobonus(const char *autobonus, int id, int pos) void script_add_autobonus(const char *autobonus) { if( strdb_get(script->autobonus_db, autobonus) == NULL ) { - struct script_code *scriptroot = script->parse(autobonus, "autobonus", 0, 0); + struct script_code *scriptroot = script->parse(autobonus, "autobonus", 0, 0, NULL); if( scriptroot ) strdb_put(script->autobonus_db, autobonus, scriptroot); @@ -11041,7 +11044,7 @@ BUILDIN(setmapflag) { char empty[1] = "\0"; char params[MAP_ZONE_MAPFLAG_LENGTH]; memcpy(params, val2, MAP_ZONE_MAPFLAG_LENGTH); - npc->parse_mapflag(map->list[m].name, empty, zone, params, empty, empty, empty); + npc->parse_mapflag(map->list[m].name, empty, zone, params, empty, empty, empty, NULL); } break; case MF_NOCOMMAND: map->list[m].nocommand = (val <= 0) ? 100 : val; break; @@ -15100,7 +15103,7 @@ BUILDIN(setitemscript) if(*dstscript) script->free_code(*dstscript); - *dstscript = new_bonus_script[0] ? script->parse(new_bonus_script, "script_setitemscript", 0, 0) : NULL; + *dstscript = new_bonus_script[0] ? script->parse(new_bonus_script, "script_setitemscript", 0, 0, NULL) : NULL; script_pushint(st,1); return true; } diff --git a/src/map/script.h b/src/map/script.h index eed0dbf1d..90b18d87f 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -564,7 +564,7 @@ struct script_interface { void (*final) (void); int (*reload) (void); /* parse */ - struct script_code* (*parse) (const char* src,const char* file,int line,int options); + struct script_code* (*parse) (const char* src,const char* file,int line,int options, int *retval); bool (*add_builtin) (const struct script_function *buildin, bool override); void (*parse_builtin) (void); const char* (*parse_subexpr) (const char* p,int limit); |