Merge branch 'master' of gitorious.org:eressea/server

This commit is contained in:
Enno Rehling 2012-05-30 08:14:19 +02:00
commit af7d059834
36 changed files with 504 additions and 173 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<spellbook name="cerddor">
<spellbook name="tybied">
<entry spell="create_roi" level="6" />
<entry spell="earn_silver#tybied" level="1" />
<entry spell="create_aots" level="6" />

View File

@ -5,25 +5,179 @@ module("tests.spells", package.seeall, lunit.testcase)
function setup()
free_game()
settings.set("magic.fumble.enable", "0")
settings.set("magic.regeneration.enable", "0")
settings.set("rules.economy.food", "4")
end
function test_roi()
function test_spell_payment()
local r = region.create(0,0, "plain")
local f = faction.create("noreply@eressea.de", "human", "de")
local f = faction.create("spell_payment@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.race = "elf"
u:set_skill("magic", 10)
u:add_item("money", 3010)
f.magic = "gwyrrd"
u.magic = "gwyrrd"
u.aura = 200
u.ship = s1
u:set_skill("magic", 12)
u.magic = "gwyrrd" -- calls create_mage
u:add_spell("create_roi")
-- local err = u:add_spell("create_roi")
-- assert_equal(0, err)
local permaura = u:get_pooled("permaura")
u:add_item("money", 3000)
u.aura = 50
u:clear_orders()
u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ")
process_orders()
write_reports()
assert_equal(1, u:get_item("roi"))
assert_equal(0, u:get_item("money"))
assert_equal(0, u.aura)
assert_equal(permaura-1, u:get_pooled("permaura"))
end
function test_spell_not_found_no_payment()
local r = region.create(0,0, "plain")
local f = faction.create("spell_fails_no_payment@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 12)
local permaura = u:get_pooled("permaura")
u:add_item("money", 3000)
u.aura = 50
u:clear_orders()
u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ")
process_orders()
assert_equal(0, u:get_item("roi"))
assert_equal(3000, u:get_item("money"))
assert_equal(50, u.aura)
assert_equal(permaura, u:get_pooled("permaura"))
end
function test_create_firesword()
local r = region.create(0,0, "plain")
local f = faction.create("create_firesword@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 12)
u:add_spell("create_firesword")
u:cast_spell('create_firesword', 1)
assert_equal(1, u:get_item("firesword"))
end
function test_create_roi()
local r = region.create(0,0, "plain")
local f = faction.create("create_roi@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_roi')
u:cast_spell('create_roi')
assert_equal(1, u:get_item("roi"))
end
function test_create_roqf()
local r = region.create(0,0, "plain")
local f = faction.create("create_roqf@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_roqf')
u:cast_spell('create_roqf')
assert_equal(1, u:get_item("roqf"))
end
function test_create_aots()
local r = region.create(0,0, "plain")
local f = faction.create("create_aots@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_aots')
u:cast_spell('create_aots')
assert_equal(1, u:get_item("aots"))
end
function test_create_ror()
local r = region.create(0,0, "plain")
local f = faction.create("create_ror@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_ror')
u:cast_spell('create_ror')
assert_equal(1, u:get_item("ror"))
end
function test_create_magicherbbag()
local r = region.create(0,0, "plain")
local f = faction.create("create_magicherbbag@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_magicherbbag')
u:cast_spell('create_magicherbbag')
assert_equal(1, u:get_item("magicherbbag"))
end
function test_create_trollbelt()
local r = region.create(0,0, "plain")
local f = faction.create("create_trollbelt@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_trollbelt')
u:cast_spell('create_trollbelt')
assert_equal(1, u:get_item("trollbelt"))
end
function test_create_dreameye()
local r = region.create(0,0, "plain")
local f = faction.create("create_dreameye@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_dreameye')
u:cast_spell('create_dreameye')
assert_equal(1, u:get_item("dreameye"))
end
function test_create_antimagic()
local r = region.create(0,0, "plain")
local f = faction.create("create_antimagic@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_antimagic')
u:cast_spell('create_antimagic')
assert_equal(1, u:get_item("antimagic"))
end
function test_create_runesword()
local r = region.create(0,0, "plain")
local f = faction.create("create_runesword@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u.magic = "gwyrrd" -- calls create_mage
u:set_skill("magic", 10)
u:add_spell('create_runesword')
u:cast_spell('create_runesword')
assert_equal(1, u:get_item("runesword"))
end
function test_create_rop()
local r = region.create(0,0, "plain")
local f = faction.create("create_rop@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u:set_skill("magic", 10)
u:add_spell('create_rop')
u:cast_spell('create_rop')
assert_equal(1, u:get_item("rop"))
end

View File

@ -32,6 +32,7 @@ without prior permission by the authors of Eressea.
#include <kernel/pool.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/spellbook.h>
#include <kernel/ship.h>
#include <kernel/skill.h>
#include <kernel/spell.h>
@ -455,12 +456,11 @@ static int tolua_unit_addnotice(lua_State * L)
static void unit_castspell(unit * u, const char *name, int level)
{
quicklist *ql = spells;
int qi;
spell *sp = find_spell(name);
for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
spell *sp = (spell *) ql_get(ql, qi);
if (strcmp(name, sp->sname) == 0) {
if (sp) {
spellbook *book = unit_get_spellbook(u);
if (spellbook_get(book, sp)) {
if (!sp->cast) {
log_error("spell '%s' has no function.\n", sp->sname);
} else {

View File

@ -1070,7 +1070,7 @@ static int tolua_eventbus_register(lua_State * L)
{
void *sender = tolua_tousertype(L, 1, 0);
const char *event = tolua_tostring(L, 2, 0);
event_args *args = malloc(sizeof(event_args));
event_args *args = (event_args *)malloc(sizeof(event_args));
args->sendertype = sender ? tolua_typename(L, 1) : NULL;
lua_pushvalue(L, 3);
args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX);
@ -1259,10 +1259,8 @@ int tolua_eressea_open(lua_State * L)
tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36);
tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand);
tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs);
tolua_function(L, TOLUA_CAST "remove_empty_units",
tolua_remove_empty_units);
tolua_function(L, TOLUA_CAST "update_subscriptions",
tolua_update_subscriptions);
tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units);
tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions);
tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores);
tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners);
tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill);

View File

@ -15,13 +15,14 @@ without prior permission by the authors of Eressea.
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/functions.h>
#include <util/log.h>
#include <kernel/config.h>
#include <kernel/equipment.h>
#include <kernel/faction.h>
#include <kernel/magic.h>
#include <kernel/spell.h>
#include <kernel/race.h>
#include <kernel/unit.h>
#include <kernel/building.h>
@ -36,8 +37,7 @@ without prior permission by the authors of Eressea.
#include <assert.h>
static int
lua_giveitem(unit * s, unit * d, const item_type * itype, int n,
struct order *ord)
lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *ord)
{
lua_State *L = (lua_State *) global.vm_state;
char fname[64];
@ -45,11 +45,12 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n,
const char *iname = itype->rtype->_name[0];
assert(s != NULL);
strcat(strcpy(fname, iname), "_give");
strlcpy(fname, iname, sizeof(fname));
strlcat(fname, "_give", sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, s, TOLUA_CAST "unit");
tolua_pushusertype(L, d, TOLUA_CAST "unit");
tolua_pushstring(L, iname);
@ -77,11 +78,12 @@ static int limit_resource(const region * r, const resource_type * rtype)
int result = -1;
lua_State *L = (lua_State *) global.vm_state;
snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]);
strlcpy(fname, rtype->_name[0], sizeof(fname));
strlcat(fname, "_limit", sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)r, TOLUA_CAST "region");
if (lua_pcall(L, 1, 1, 0) != 0) {
@ -105,11 +107,13 @@ produce_resource(region * r, const resource_type * rtype, int norders)
{
lua_State *L = (lua_State *) global.vm_state;
char fname[64];
snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]);
strlcpy(fname, rtype->_name[0], sizeof(fname));
strlcat(fname, "_produce", sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)r, TOLUA_CAST "region");
tolua_pushnumber(L, (lua_Number) norders);
@ -138,7 +142,7 @@ static int lc_age(struct attrib *a)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
if (fparam) {
tolua_pushstring(L, fparam);
@ -199,7 +203,7 @@ static int lua_callspell(castorder * co)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
int nparam = 4;
tolua_pushusertype(L, r, TOLUA_CAST "region");
tolua_pushusertype(L, caster, TOLUA_CAST "unit");
@ -232,7 +236,8 @@ static int lua_callspell(castorder * co)
lua_pop(L, 1);
}
} else {
log_error("spell(%s) calling '%s': not a function.\n", unitname(caster), fname);
int ltype = lua_type(L, -1);
log_error("spell(%s) calling '%s': not a function, has type %d.\n", unitname(caster), fname, ltype);
lua_pop(L, 1);
}
@ -245,11 +250,13 @@ static int lua_initfamiliar(unit * u)
lua_State *L = (lua_State *) global.vm_state;
char fname[64];
int result = -1;
snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]);
strlcpy(fname, "initfamiliar_", sizeof(fname));
strlcat(fname, u->race->_name[0], sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, u, TOLUA_CAST "unit");
if (lua_pcall(L, 1, 1, 0) != 0) {
@ -267,7 +274,8 @@ static int lua_initfamiliar(unit * u)
create_mage(u, M_GRAY);
snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]);
strlcpy(fname, u->race->_name[0], sizeof(fname));
strlcat(fname, "_familiar", sizeof(fname));
equip_unit(u, get_equipment(fname));
return result;
}
@ -278,11 +286,13 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta)
lua_State *L = (lua_State *) global.vm_state;
int result = -1;
char fname[64];
snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]);
strlcpy(fname, rtype->_name[0], sizeof(fname));
strlcat(fname, "_changeresource", sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, u, TOLUA_CAST "unit");
tolua_pushnumber(L, (lua_Number) delta);
@ -307,11 +317,13 @@ static int lua_getresource(unit * u, const struct resource_type *rtype)
lua_State *L = (lua_State *) global.vm_state;
int result = -1;
char fname[64];
snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]);
strlcpy(fname, rtype->_name[0], sizeof(fname));
strlcat(fname, "_getresource", sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, u, TOLUA_CAST "unit");
if (lua_pcall(L, 1, 1, 0) != 0) {
@ -341,7 +353,7 @@ static boolean lua_canuse_item(const unit * u, const struct item_type *itype)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
tolua_pushstring(L, itype->rtype->_name[0]);
@ -371,7 +383,7 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)r, TOLUA_CAST "region");
tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction");
tolua_pushstring(L, rc ? rc->_name[0] : 0);
@ -398,11 +410,12 @@ static void lua_agebuilding(building * b)
lua_State *L = (lua_State *) global.vm_state;
char fname[64];
snprintf(fname, sizeof(fname), "age_%s", b->type->_name);
strlcpy(fname, "age_", sizeof(fname));
strlcat(fname, b->type->_name, sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
if (lua_pcall(L, 1, 0, 0) != 0) {
@ -424,7 +437,7 @@ static int lua_building_protection(building * b, unit * u)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
@ -451,7 +464,7 @@ static double lua_building_taxes(building * b, int level)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
tolua_pushnumber(L, level);
@ -478,7 +491,7 @@ static int lua_maintenance(const unit * u)
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
if (lua_pcall(L, 1, 1, 0) != 0) {
@ -502,11 +515,13 @@ static int lua_equipmentcallback(const struct equipment *eq, unit * u)
lua_State *L = (lua_State *) global.vm_state;
char fname[64];
int result = -1;
snprintf(fname, sizeof(fname), "equip_%s", eq->name);
strlcpy(fname, "equip_", sizeof(fname));
strlcat(fname, eq->name, sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
if (lua_pcall(L, 1, 1, 0) != 0) {
@ -532,11 +547,13 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount,
lua_State *L = (lua_State *) global.vm_state;
int result = 0;
char fname[64];
snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]);
strlcpy(fname, "use_", sizeof(fname));
strlcat(fname, itype->rtype->_name[0], sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
tolua_pushnumber(L, (lua_Number) amount);
@ -561,11 +578,13 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount)
lua_State *L = (lua_State *) global.vm_state;
int result = 0;
char fname[64];
snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]);
strlcpy(fname, "recruit_", sizeof(fname));
strlcat(fname, arch->name[0], sizeof(fname));
lua_pushstring(L, fname);
lua_rawget(L, LUA_GLOBALSINDEX);
if (lua_isfunction(L, 1)) {
if (lua_isfunction(L, -1)) {
tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
tolua_pushnumber(L, (lua_Number) amount);

View File

@ -5,6 +5,8 @@
#include <iniparser/iniparser.c>
#include <mt19937ar.c>
#include <util/bsdstring.c>
#include <util/console.c>
#include <util/attrib.c>
#include <util/base36.c>
@ -33,10 +35,5 @@
#include <util/xml.c>
#ifndef HAVE_INLINE
#include <util/bsdstring.c>
#include <util/strings.c>
#endif
#ifdef __GNUC__
#include <util/strncpy.c>
#endif

View File

@ -92,6 +92,7 @@
<ClCompile Include="gamecode\creport.c" />
<ClCompile Include="gamecode\economy.c" />
<ClCompile Include="eressea.c" />
<ClCompile Include="gamecode\economy_test.c" />
<ClCompile Include="gamecode\give.c" />
<ClCompile Include="gamecode\xmlreport.c" />
<ClCompile Include="gmtool.c" />

View File

@ -68,6 +68,9 @@
<ClCompile Include="gamecode\xmlreport.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gamecode\economy_test.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="gamecode\archetype.h">

View File

@ -55,6 +55,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/event.h>
#include <util/goodies.h>
#include <util/lists.h>
@ -264,7 +265,9 @@ static void add_recruits(unit * u, int number, int wanted)
unew = create_unit(r, u->faction, number, u->race, 0, NULL, u);
}
snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]);
strlcpy(equipment, "new_", sizeof(equipment));
strlcat(equipment, u->race->_name[0], sizeof(equipment));
strlcat(equipment, "_unit", sizeof(equipment));
equip_unit(unew, get_equipment(equipment));
if (unew->race->ec_flags & ECF_REC_HORSES) {
@ -626,17 +629,19 @@ static void friendly_takeover(region * r, faction * f)
}
}
static void give_control(unit * u, unit * u2)
void give_control(unit * u, unit * u2)
{
if (u->building && u->faction != u2->faction && rule_region_owners()) {
region *r = u->region;
faction *f = region_get_owner(r);
if (u->building) {
if (u->faction != u2->faction && rule_region_owners()) {
region *r = u->region;
faction *f = region_get_owner(r);
assert(u->building==u2->building);
if (f == u->faction) {
building *b = largestbuilding(r, &cmp_current_owner, false);
if (b == u->building) {
friendly_takeover(r, u2->faction);
assert(u->building==u2->building);
if (f == u->faction) {
building *b = largestbuilding(r, &cmp_current_owner, false);
if (b == u->building) {
friendly_takeover(r, u2->faction);
}
}
}
building_set_owner(u2);

View File

@ -55,6 +55,7 @@ extern "C" {
extern void split_allocations(struct region *r);
extern int recruit_archetypes(void);
extern int give_control_cmd(struct unit *u, struct order *ord);
extern void give_control(struct unit * u, struct unit * u2);
#ifdef __cplusplus
}

View File

@ -0,0 +1,60 @@
#include "platform.h"
#include "economy.h"
#include <kernel/unit.h>
#include <kernel/region.h>
#include <kernel/building.h>
#include <kernel/ship.h>
#include <cutest/CuTest.h>
#include <tests.h>
static void test_give_control_building(CuTest * tc)
{
unit *u1, *u2;
building *b;
struct faction *f;
region *r;
test_cleanup();
test_create_world();
f = test_create_faction(0);
r = findregion(0, 0);
b = test_create_building(r, 0);
u1 = test_create_unit(f, r);
u_set_building(u1, b);
u2 = test_create_unit(f, r);
u_set_building(u2, b);
CuAssertPtrEquals(tc, u1, building_owner(b));
give_control(u1, u2);
CuAssertPtrEquals(tc, u2, building_owner(b));
}
static void test_give_control_ship(CuTest * tc)
{
unit *u1, *u2;
ship *sh;
struct faction *f;
region *r;
test_cleanup();
test_create_world();
f = test_create_faction(0);
r = findregion(0, 0);
sh = test_create_ship(r, 0);
u1 = test_create_unit(f, r);
u_set_ship(u1, sh);
u2 = test_create_unit(f, r);
u_set_ship(u2, sh);
CuAssertPtrEquals(tc, u1, ship_owner(sh));
give_control(u1, u2);
CuAssertPtrEquals(tc, u2, ship_owner(sh));
}
CuSuite *get_economy_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_give_control_building);
SUITE_ADD_TEST(suite, test_give_control_ship);
return suite;
}

View File

@ -2302,21 +2302,21 @@ static boolean display_race(faction * f, unit * u, const race * rc)
/* hp_p : Trefferpunkte */
bytes =
snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale,
slprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale,
"stat_hitpoints"));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
/* b_attacke : Angriff */
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"),
slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"),
(rc->at_default + rc->at_bonus));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
/* b_defense : Verteidigung */
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"),
slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"),
(rc->df_default + rc->df_bonus));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
@ -2324,7 +2324,7 @@ static boolean display_race(faction * f, unit * u, const race * rc)
/* b_armor : Rüstung */
if (rc->armor > 0) {
bytes =
snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor);
slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
}

View File

@ -235,9 +235,9 @@ void find_manual(region * r, unit * u)
break;
}
snprintf(zLocation, sizeof(zLocation), "manual_location_%d",
slprintf(zLocation, sizeof(zLocation), "manual_location_%d",
(int)(rng_int() % 4));
snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]);
slprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]);
msg = msg_message("find_manual", "unit location book", u, zLocation, zBook);
r_addmessage(r, u->faction, msg);

View File

@ -31,6 +31,7 @@ without prior permission by the authors of Eressea.
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/language.h>
#include <util/parser.h>
#include <util/quicklist.h>
@ -394,8 +395,7 @@ const char *alliancename(const alliance * al)
char *ibuf = idbuf[(++nextbuf) % 8];
if (al && al->name) {
snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id));
ibuf[sizeof(name) - 1] = 0;
slprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id));
} else {
return NULL;
}

View File

@ -211,13 +211,7 @@ static char *sidename(side * s)
static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */
bufno = bufno % 4;
if (s->stealthfaction) {
snprintf(sidename_buf[bufno], SIDENAMEBUFLEN,
"%s", factionname(s->stealthfaction));
} else {
snprintf(sidename_buf[bufno], SIDENAMEBUFLEN,
"%s", factionname(s->faction));
}
strlcpy(sidename_buf[bufno], factionname(s->stealthfaction?s->stealthfaction:s->faction), SIDENAMEBUFLEN);
return sidename_buf[bufno++];
}
@ -3850,9 +3844,8 @@ static int battle_report(battle * b)
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
}
snprintf(buffer, sizeof(buffer), "%s %2d(%s): ",
slprintf(buffer, sizeof(buffer), "%s %2d(%s): ",
loc_army, army_index(s), abbrev);
buffer[sizeof(buffer) - 1] = 0;
bytes = (int)strlcpy(bufp, buffer, size);
if (wrptr(&bufp, &size, bytes) != 0)

View File

@ -613,8 +613,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize)
const char *write_buildingname(const building * b, char *ibuf, size_t size)
{
snprintf((char *)ibuf, size, "%s (%s)", b->name, itoa36(b->no));
ibuf[size - 1] = 0;
slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no));
return ibuf;
}

View File

@ -1653,8 +1653,7 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
char *write_unitname(const unit * u, char *buffer, size_t size)
{
snprintf((char *)buffer, size, "%s (%s)", (const char *)u->name,
itoa36(u->no));
slprintf(buffer, size, "%s (%s)", (const char *)u->name, itoa36(u->no));
buffer[size - 1] = 0;
return buffer;
}

View File

@ -532,7 +532,7 @@ static const char *b_nameroad(const connection * b, const region * r,
} else {
int percent = MAX(1, 100 * local / r->terrain->max_road);
if (local) {
snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border",
slprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border",
"a_road_percent")), percent);
} else {
return LOC(f->locale, mkname("border", "a_road_connection"));

View File

@ -153,8 +153,7 @@ const char *factionname(const faction * f)
char *ibuf = idbuf[(++nextbuf) % 8];
if (f && f->name) {
snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no));
ibuf[sizeof(name) - 1] = 0;
slprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no));
} else {
strcpy(ibuf, "Unbekannte Partei (?)");
}
@ -226,7 +225,7 @@ faction *addfaction(const char *email, const char *password,
addlist(&factions, f);
fhash(f);
snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f));
slprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f));
f->name = strdup(buf);
return f;

View File

@ -889,6 +889,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range)
int k;
int resuse;
assert(cast_level>0);
for (k = 0; sp->components[k].type; k++) {
if (sp->components[k].type == r_aura) {
resuse = spellcost(u, sp) * range;
@ -1394,7 +1395,7 @@ static void do_fumble(castorder * co)
case 5:
case 6:
/* Spruch gelingt, aber alle Magiepunkte weg */
sp->cast(co);
co->level = sp->cast(co);
set_spellpoints(u, 0);
ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell",
u, r, sp));
@ -1405,7 +1406,7 @@ static void do_fumble(castorder * co)
case 9:
default:
/* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */
sp->cast(co);
co->level = sp->cast(co);
ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell",
u, r, sp));
countspells(u, 3);
@ -1452,6 +1453,9 @@ void regeneration_magiepunkte(void)
double reg_aura;
int regen;
double mod;
int regen_enabled = get_param_int(global.parameters, "magic.regeneration.enable", 1);
if (!regen_enabled) return;
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
@ -2836,10 +2840,13 @@ void magic(void)
}
}
}
pay_spell(u, sp, co->level, co->distance);
/* erst bezahlen, dann Kostenzähler erhöhen */
if (fumbled)
if (fumbled) {
do_fumble(co);
}
if (co->level>0) {
pay_spell(u, sp, co->level, co->distance);
}
countspells(u, 1);
}
}

View File

@ -152,19 +152,9 @@ void test_pay_spell_failure(CuTest * tc)
CuAssertIntEquals(tc, 3, change_resource(u, rt_find("aura"), 3));
CuAssertIntEquals(tc, 2, change_resource(u, rt_find("horse"), 1));
level = eff_spelllevel(u, sp, 3, 1);
CuAssertIntEquals(tc, 0, level);
pay_spell(u, sp, level, 1);
CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); /* seems we even pay this at level 0 */
CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura")));
CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse")));
level = eff_spelllevel(u, sp, 2, 1);
CuAssertIntEquals(tc, 0, level);
pay_spell(u, sp, level, 1);
CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money")));
CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura")));
CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse")));
CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 3, 1));
CuAssertIntEquals(tc, 0, change_resource(u, rt_find("money"), -1));
CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 2, 1));
}
void test_getspell_unit(CuTest * tc)

View File

@ -2398,9 +2398,7 @@ static int hunt(unit * u, order * ord)
}
bufp = command;
bytes =
snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]),
LOC(u->faction->locale, directions[dir]));
bytes = slprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), LOC(u->faction->locale, directions[dir]));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();

View File

@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <util/attrib.h>
#include <util/bsdstring.h>
#include <util/goodies.h>
#include <util/lists.h>
#include <util/log.h>
@ -114,15 +115,14 @@ const char *write_regionname(const region * r, const faction * f, char *buffer,
char *buf = (char *)buffer;
const struct locale *lang = f ? f->locale : 0;
if (r == NULL) {
strcpy(buf, "(null)");
strlcpy(buf, "(null)", size);
} else {
plane *pl = rplane(r);
int nx = r->x, ny = r->y;
pnormalize(&nx, &ny, pl);
adjust_coordinates(f, &nx, &ny, pl, r);
snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny);
slprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny);
}
buf[size - 1] = 0;
return buffer;
}

View File

@ -1858,8 +1858,9 @@ const char *trailinto(const region * r, const struct locale *lang)
size_t
f_regionid(const region * r, const faction * f, char *buffer, size_t size)
{
size_t len;
if (!r) {
strncpy(buffer, "(Chaos)", size);
len = strlcpy(buffer, "(Chaos)", size);
} else {
plane *pl = rplane(r);
const char *name = pl ? pl->name : 0;
@ -1867,12 +1868,12 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size)
int named = (name && name[0]);
pnormalize(&nx, &ny, pl);
adjust_coordinates(f, &nx, &ny, pl, r);
strncpy(buffer, rname(r, f->locale), size);
buffer[size - 1] = 0;
sprintf(buffer + strlen(buffer), " (%d,%d%s%s)", nx, ny, named ? "," : "",
(named) ? name : "");
len = strlcpy(buffer, rname(r, f?f->locale:0), size);
snprintf(buffer + len, size-len, " (%d,%d%s%s)", nx, ny, named ? "," : "", (named) ? name : "");
buffer[size-1] = 0;
len=strlen(buffer);
}
return strlen(buffer);
return len;
}
static char *f_regionid_s(const region * r, const faction * f)

View File

@ -52,9 +52,32 @@ static void test_reorder_units(CuTest * tc)
CuAssertPtrEquals(tc, 0, u0->next);
}
static void test_regionid(CuTest * tc) {
size_t len;
const struct terrain_type * plain;
struct region * r;
char buffer[64];
test_cleanup();
plain = test_create_terrain("plain", 0);
r = test_create_region(0, 0, plain);
memset(buffer, 0xff, sizeof(buffer));
len = f_regionid(r, 0, buffer, sizeof(buffer));
CuAssertIntEquals(tc, 11, len);
CuAssertStrEquals(tc, "plain (0,0)", buffer);
memset(buffer, -1, sizeof(buffer));
len = f_regionid(r, 0, buffer, 11);
CuAssertIntEquals(tc, 10, len);
CuAssertStrEquals(tc, "plain (0,0", buffer);
CuAssertIntEquals(tc, -1, buffer[11]);
}
CuSuite *get_reports_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_reorder_units);
SUITE_ADD_TEST(suite, test_regionid);
return suite;
}

View File

@ -1552,7 +1552,8 @@ int readgame(const char *filename, int mode, int backup)
store->r_str_buf(store, basefile, sizeof(basefile));
if (strcmp(game_name, basefile) != 0) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%s.xml", game_name);
strlcpy(buffer, game_name, sizeof(buffer));
strlcat(buffer, ".xml", sizeof(buffer));
if (strcmp(basefile, buffer) != 0) {
log_warning("game mismatch: datafile contains %s, game is %s\n", basefile, game_name);
printf("WARNING: any key to continue, Ctrl-C to stop\n");

View File

@ -233,8 +233,7 @@ void free_ships(void)
const char *write_shipname(const ship * sh, char *ibuf, size_t size)
{
snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no));
ibuf[size - 1] = 0;
slprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no));
return ibuf;
}

View File

@ -3,6 +3,7 @@
#include <kernel/spell.h>
#include <kernel/magic.h>
#include <util/quicklist.h>
#include <util/log.h>
#include "spellbook.h"
@ -21,8 +22,11 @@ void spellbook_add(spellbook *sb, struct spell * sp, int level)
spellbook_entry * sbe;
assert(sb && sp && level>0);
assert(!spellbook_get(sb, sp));
#ifndef NDEBUG
if (spellbook_get(sb, sp)) {
log_error("duplicate spell in spellbook '%s': '%s'\n", sb->name, sp->sname);
}
#endif
sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry));
sbe->sp = sp;
sbe->level = level;

View File

@ -44,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <util/attrib.h>
#include <util/base36.h>
#include <util/bsdstring.h>
#include <util/event.h>
#include <util/goodies.h>
#include <util/language.h>
@ -1424,7 +1425,9 @@ void name_unit(unit * u)
} else {
result = parameters[P_UNIT];
}
snprintf(name, sizeof(name), "%s %s", result, itoa36(u->no));
strlcpy(name, result, sizeof(name));
strlcat(name, " ", sizeof(name));
strlcat(name, itoa36(u->no), sizeof(name));
unit_setname(u, name);
}
}

View File

@ -6,6 +6,7 @@
#include "tests_test.c"
#include <util/base36_test.c>
#include <util/bsdstring_test.c>
#include <util/functions_test.c>
#include <util/quicklist_test.c>
#include <util/umlaut_test.c>
@ -21,6 +22,7 @@
#include <kernel/equipment_test.c>
#include <kernel/reports_test.c>
#include <kernel/spellbook_test.c>
#include <gamecode/economy_test.c>
#include <gamecode/laws_test.c>
#include <gamecode/market_test.c>
@ -48,6 +50,7 @@ int RunAllTests(void)
CuSuiteAddSuite(suite, get_tests_suite());
/* util */
CuSuiteAddSuite(suite, get_base36_suite());
CuSuiteAddSuite(suite, get_bsdstring_suite());
CuSuiteAddSuite(suite, get_quicklist_suite());
CuSuiteAddSuite(suite, get_functions_suite());
CuSuiteAddSuite(suite, get_umlaut_suite());
@ -67,6 +70,7 @@ int RunAllTests(void)
/* gamecode */
CuSuiteAddSuite(suite, get_market_suite());
CuSuiteAddSuite(suite, get_laws_suite());
CuSuiteAddSuite(suite, get_economy_suite());
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
@ -137,15 +141,15 @@ test_create_terrain(const char * name, unsigned int flags)
building * test_create_building(region * r, const building_type * btype)
{
building * b = new_building(btype, r, default_locale);
b->size = btype->maxsize>0?btype->maxsize:1;
building * b = new_building(btype?btype:bt_find("castle"), r, default_locale);
b->size = b->type->maxsize>0?b->type->maxsize:1;
return b;
}
ship * test_create_ship(region * r, const ship_type * stype)
{
ship * s = new_ship(stype, r, default_locale);
s->size = stype->construction?stype->construction->maxsize:1;
ship * s = new_ship(stype?stype:st_find("boat"), r, default_locale);
s->size = s->type->construction?s->type->construction->maxsize:1;
return s;
}

View File

@ -125,6 +125,7 @@
<ClCompile Include="util\base36.c" />
<ClCompile Include="util\base36_test.c" />
<ClCompile Include="util\bsdstring.c" />
<ClCompile Include="util\bsdstring_test.c" />
<ClCompile Include="util\console.c" />
<ClCompile Include="util\critbit.c" />
<ClCompile Include="util\crmessage.c" />

View File

@ -208,5 +208,8 @@
<ClCompile Include="util\umlaut_test.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="util\bsdstring_test.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -2,12 +2,11 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdarg.h>
#ifndef HAVE_INLINE
#include "bsdstring.h"
#endif
INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes)
int wrptr(char **ptr, size_t * size, int bytes)
{
assert(bytes >= 0 || !"you're not using snprintf right, maybe?");
@ -29,8 +28,9 @@ INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes)
return ENAMETOOLONG;
}
#if !defined(HAVE_STRLCPY)
INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz)
#ifndef HAVE_STRLCPY
#define HAVE_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz)
{ /* copied from OpenBSD source code */
register char *d = dst;
register const char *s = src;
@ -53,8 +53,11 @@ INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz)
return (s - src - 1); /* count does not include NUL */
}
#endif
INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz)
#ifndef HAVE_STRLCAT
#define HAVE_STRLCAT
size_t strlcat(char *dst, const char *src, size_t siz)
{
register char *d = dst;
register const char *s = src;
@ -81,3 +84,23 @@ INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz)
return (dlen + (s - src)); /* count does not include NUL */
}
#endif
#ifndef HAVE_SLPRINTF
#define HAVE_SLPRINTF
size_t slprintf(char * dst, size_t size, const char * format, ...)
{
va_list args;
int result;
va_start(args, format);
result = vsnprintf(dst, size, format, args);
if (result<0 || result>=(int)size) {
dst[size-1]='\0';
return size;
}
va_start(args, format);
va_end(args);
return (size_t)result;
}
#endif

View File

@ -1,19 +1,20 @@
#ifndef UTIL_BSDSTRING_H
#define UTIL_BSDSTRING_H
#ifdef HAVE_INLINE
# include "bsdstring.c"
#else
extern size_t strlcpy(char *dst, const char *src, size_t siz);
extern size_t strlcat(char *dst, const char *src, size_t siz);
extern int wrptr(char **ptr, size_t * size, int bytes);
#ifndef HAVE_STRLCPY
extern size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_STRLCAT
extern size_t strlcat(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_SLPRINTF
extern size_t slprintf(char * dst, size_t size, const char * format, ...);
#endif
#define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__)
#if !defined(HAVE_STRLPRINTF)
# define HAVE_STRLPRINTF
# define slprintf snprintf
#endif
#endif

68
src/util/bsdstring_test.c Normal file
View File

@ -0,0 +1,68 @@
#include <cutest/CuTest.h>
#include "bsdstring.h"
#include <string.h>
static void test_strlcat(CuTest * tc)
{
char buffer[32];
memset(buffer, -2, sizeof(buffer));
buffer[0] = '\0';
CuAssertIntEquals(tc, 4, strlcat(buffer, "herp", 4));
CuAssertStrEquals(tc, "her", buffer);
buffer[0] = '\0';
CuAssertIntEquals(tc, 4, strlcat(buffer, "herp", 8));
CuAssertStrEquals(tc, "herp", buffer);
CuAssertIntEquals(tc, -2, buffer[5]);
CuAssertIntEquals(tc, 8, strlcat(buffer, "derp", 8));
CuAssertStrEquals(tc, "herpder", buffer);
CuAssertIntEquals(tc, -2, buffer[8]);
}
static void test_strlcpy(CuTest * tc)
{
char buffer[32];
memset(buffer, -2, sizeof(buffer));
CuAssertIntEquals(tc, 4, strlcpy(buffer, "herp", 4));
CuAssertStrEquals(tc, "her", buffer);
CuAssertIntEquals(tc, 4, strlcpy(buffer, "herp", 8));
CuAssertStrEquals(tc, "herp", buffer);
CuAssertIntEquals(tc, -2, buffer[5]);
CuAssertIntEquals(tc, 8, strlcpy(buffer, "herpderp", 8));
CuAssertStrEquals(tc, "herpder", buffer);
CuAssertIntEquals(tc, -2, buffer[8]);
}
static void test_slprintf(CuTest * tc)
{
char buffer[32];
memset(buffer, -2, sizeof(buffer));
CuAssertTrue(tc, slprintf(buffer, 4, "%s", "herpderp")>3);
CuAssertStrEquals(tc, "her", buffer);
CuAssertIntEquals(tc, 4, slprintf(buffer, 8, "%s", "herp"));
CuAssertStrEquals(tc, "herp", buffer);
CuAssertIntEquals(tc, -2, buffer[5]);
CuAssertIntEquals(tc, 8, slprintf(buffer, 8, "%s", "herpderp"));
CuAssertStrEquals(tc, "herpder", buffer);
CuAssertIntEquals(tc, -2, buffer[8]);
}
CuSuite *get_bsdstring_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_strlcat);
SUITE_ADD_TEST(suite, test_strlcpy);
SUITE_ADD_TEST(suite, test_slprintf);
return suite;
}

View File

@ -1,23 +0,0 @@
/*
* Faster replacement for ISO-C strncpy, does not pad with zeros
*/
#include <stddef.h>
char *strncpy(char *to, const char *from, size_t size)
{
char *t = to, *f = (char *)from;
int copied = 0;
while (copied < size) {
*t = *f;
if (*f == '\0')
break;
t++;
f++;
copied++;
}
return to;
}