forked from github/server
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
9055d1aaaa
22 changed files with 387 additions and 165 deletions
2
clibs
2
clibs
|
@ -1 +1 @@
|
|||
Subproject commit 147584ad70b220abf6a4e97ca76e785729b9ac32
|
||||
Subproject commit f9842e07a442c5453c270badf25ab72633b4edf5
|
|
@ -308,7 +308,7 @@ msgstr "\"$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($
|
|||
msgid "error5"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht.\""
|
||||
|
||||
msgid "tactics_lost"
|
||||
msgid "para_tactics_lost"
|
||||
msgstr "\"$unit($unit) konnte dem Gegner eine Falle stellen.\""
|
||||
|
||||
msgid "error_lowstealth"
|
||||
|
@ -1052,7 +1052,7 @@ msgstr "\"Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen
|
|||
msgid "recruit_archetype"
|
||||
msgstr "\"$unit($unit) rekrutiert $int($amount) $localize($archetype).\""
|
||||
|
||||
msgid "tactics_won"
|
||||
msgid "para_tactics_won"
|
||||
msgstr "\"$unit($unit) überrascht den Gegner.\""
|
||||
|
||||
msgid "raindance_effect"
|
||||
|
|
|
@ -308,7 +308,7 @@ msgstr "\"$unit($mage) shrouds the equipment of $unit($target) in shadows.\""
|
|||
msgid "error5"
|
||||
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The building is not ours.\""
|
||||
|
||||
msgid "tactics_lost"
|
||||
msgid "para_tactics_lost"
|
||||
msgstr "\"$unit($unit) lured the enemy into an ambush.\""
|
||||
|
||||
msgid "error_lowstealth"
|
||||
|
@ -1052,7 +1052,7 @@ msgstr "\"This region was cursed by the gods. Stinking vapors billow over the de
|
|||
msgid "recruit_archetype"
|
||||
msgstr "\"$unit($unit) recruits $int($amount) $localize($archetype).\""
|
||||
|
||||
msgid "tactics_won"
|
||||
msgid "para_tactics_won"
|
||||
msgstr "\"$unit($unit) surprises the enemies.\""
|
||||
|
||||
msgid "raindance_effect"
|
||||
|
|
|
@ -17,9 +17,7 @@ msgstr "Rostiges Kettenhemd"
|
|||
msgctxt "spellinfo"
|
||||
msgid "destroy_magic"
|
||||
msgstr ""
|
||||
"Dieser Zauber ermöglicht dem Magier, Verzauberungen "
|
||||
"einer Einheit, eines Schiffes, Gebäudes oder auch "
|
||||
"der Region aufzulösen."
|
||||
"Dieser Zauber ermöglicht dem Magier, Verzauberungen einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen."
|
||||
|
||||
msgctxt "spell"
|
||||
msgid "shadowknights"
|
||||
|
@ -168,9 +166,6 @@ msgstr "TRÄNKE"
|
|||
msgid "northwest"
|
||||
msgstr "Nordwesten"
|
||||
|
||||
msgid "spinx09"
|
||||
msgstr "Das Schiff mit dem Stern im Wappen liegt neben dem der einen Mandelkern hat"
|
||||
|
||||
msgctxt "iteminfo"
|
||||
msgid "cookie"
|
||||
msgstr "Kleines trockenes Dauergebäck, m od. s; - u. -es, - u. -e"
|
||||
|
|
|
@ -486,3 +486,13 @@ function test_rising_undead()
|
|||
assert_equal(2, u.number)
|
||||
assert_equal(u.number, u:get_item('rustysword'))
|
||||
end
|
||||
|
||||
function test_dwarf_mining()
|
||||
local f = faction.create('dwarf')
|
||||
local r = region.create(0, 0, 'plain')
|
||||
local u = unit.create(f, r)
|
||||
u.name = 'Xolgrim'
|
||||
u:set_skill('mining', 2)
|
||||
assert_equal(2, u:get_skill('mining'))
|
||||
assert_equal(4, u:eff_skill('mining'))
|
||||
end
|
||||
|
|
|
@ -2960,10 +2960,10 @@ static void print_stats(battle * b)
|
|||
unit *u = tf->unit;
|
||||
message *m = NULL;
|
||||
if (!is_attacker(tf)) {
|
||||
m = msg_message("tactics_lost", "unit", u);
|
||||
m = msg_message("para_tactics_lost", "unit", u);
|
||||
}
|
||||
else {
|
||||
m = msg_message("tactics_won", "unit", u);
|
||||
m = msg_message("para_tactics_won", "unit", u);
|
||||
}
|
||||
message_all(b, m);
|
||||
msg_release(m);
|
||||
|
|
|
@ -517,7 +517,7 @@ static void report_crtypes(FILE * F, const struct locale *lang)
|
|||
assert(hash > 0);
|
||||
fprintf(F, "MESSAGETYPE %d\n", hash);
|
||||
fputc('\"', F);
|
||||
fputs(str_escape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F);
|
||||
fputs(crescape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F);
|
||||
fputs("\";text\n", F);
|
||||
fprintf(F, "\"%s\";section\n", kmt->mtype->section);
|
||||
}
|
||||
|
|
|
@ -85,13 +85,15 @@ static void test_steal_okay(CuTest * tc) {
|
|||
struct steal env;
|
||||
race *rc;
|
||||
struct terrain_type *ter;
|
||||
message *msg;
|
||||
|
||||
test_setup();
|
||||
ter = test_create_terrain("plain", LAND_REGION);
|
||||
rc = test_create_race("human");
|
||||
rc->flags = 0;
|
||||
setup_steal(&env, ter, rc);
|
||||
CuAssertPtrEquals(tc, 0, steal_message(env.u, 0));
|
||||
CuAssertPtrEquals(tc, NULL, msg = steal_message(env.u, 0));
|
||||
assert(!msg);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -739,6 +741,7 @@ static void test_expand_production(CuTest *tc) {
|
|||
CuAssertPtrEquals(tc, u, results[0]->unit);
|
||||
CuAssertPtrEquals(tc, u, results[1]->unit);
|
||||
CuAssertIntEquals(tc, 0, u->n);
|
||||
free(results);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "alchemy.h"
|
||||
|
||||
#include "modules/score.h"
|
||||
|
||||
#include "kernel/build.h"
|
||||
#include "kernel/building.h"
|
||||
#include "kernel/item.h"
|
||||
|
@ -229,6 +231,9 @@ static void handle_item(parseinfo *pi, const XML_Char *el, const XML_Char **attr
|
|||
handle_bad_input(pi, el, attr[i]);
|
||||
}
|
||||
}
|
||||
if (itype->score == 0) {
|
||||
itype->score = default_score(itype);
|
||||
}
|
||||
itype->flags = flags;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,12 +40,15 @@ static void setup_give(struct give *env) {
|
|||
|
||||
env->r = test_create_region(0, 0, ter);
|
||||
env->src = test_create_unit(env->f1, env->r);
|
||||
env->dst = env->f2 ? test_create_unit(env->f2, env->r) : 0;
|
||||
env->itype = it_get_or_create(rt_get_or_create("money"));
|
||||
env->itype->flags |= ITF_HERB;
|
||||
if (env->f1 && env->f2) {
|
||||
if (env->f2) {
|
||||
ally * al = ally_add(&env->f2->allies, env->f1);
|
||||
al->status = HELP_GIVE;
|
||||
env->dst = test_create_unit(env->f2, env->r);
|
||||
}
|
||||
else {
|
||||
env->dst = NULL;
|
||||
}
|
||||
if (env->lang) {
|
||||
locale_setstring(env->lang, env->itype->rtype->_name, "SILBER");
|
||||
|
@ -139,10 +142,12 @@ static void test_give_unit_to_ocean(CuTest * tc) {
|
|||
|
||||
static void test_give_men(CuTest * tc) {
|
||||
struct give env = { 0 };
|
||||
message * msg;
|
||||
test_setup_ex(tc);
|
||||
env.f2 = env.f1 = test_create_faction(NULL);
|
||||
setup_give(&env);
|
||||
CuAssertPtrEquals(tc, 0, give_men(1, env.src, env.dst, NULL));
|
||||
CuAssertPtrEquals(tc, NULL, msg = give_men(1, env.src, env.dst, NULL));
|
||||
assert(!msg);
|
||||
CuAssertIntEquals(tc, 2, env.dst->number);
|
||||
CuAssertIntEquals(tc, 0, env.src->number);
|
||||
test_teardown();
|
||||
|
@ -222,10 +227,13 @@ static void test_give_men_in_ocean(CuTest * tc) {
|
|||
|
||||
static void test_give_men_too_many(CuTest * tc) {
|
||||
struct give env = { 0 };
|
||||
message * msg;
|
||||
|
||||
test_setup_ex(tc);
|
||||
env.f2 = env.f1 = test_create_faction(NULL);
|
||||
setup_give(&env);
|
||||
CuAssertPtrEquals(tc, 0, give_men(2, env.src, env.dst, NULL));
|
||||
CuAssertPtrEquals(tc, NULL, msg = give_men(2, env.src, env.dst, NULL));
|
||||
assert(!msg);
|
||||
CuAssertIntEquals(tc, 2, env.dst->number);
|
||||
CuAssertIntEquals(tc, 0, env.src->number);
|
||||
test_teardown();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void test_missing_message(CuTest *tc) {
|
||||
message *msg;
|
||||
|
||||
|
@ -78,6 +80,7 @@ static void test_merge_split(CuTest *tc) {
|
|||
static void test_noerror(CuTest *tc) {
|
||||
unit *u;
|
||||
struct locale *lang;
|
||||
message *msg;
|
||||
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
|
@ -85,8 +88,10 @@ static void test_noerror(CuTest *tc) {
|
|||
u->thisorder = parse_order("!@move", lang);
|
||||
CuAssertIntEquals(tc, K_MOVE | CMD_QUIET | CMD_PERSIST, u->thisorder->command);
|
||||
CuAssertTrue(tc, !is_persistent(u->thisorder));
|
||||
CuAssertPtrEquals(tc, NULL, msg_error(u, u->thisorder, 100));
|
||||
CuAssertPtrEquals(tc, NULL, msg_feedback(u, u->thisorder, "error_unit_not_found", NULL));
|
||||
CuAssertPtrEquals(tc, NULL, msg = msg_error(u, u->thisorder, 100));
|
||||
assert(!msg);
|
||||
CuAssertPtrEquals(tc, NULL, msg = msg_feedback(u, u->thisorder, "error_unit_not_found", NULL));
|
||||
assert(!msg);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,15 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si
|
|||
return sbuffer;
|
||||
}
|
||||
|
||||
const char *crescape(const char *str, char *buffer, size_t size) {
|
||||
const char *replace = "\"\\";
|
||||
const char * pos = strpbrk(str, replace);
|
||||
if (!pos) {
|
||||
return str;
|
||||
}
|
||||
return str_escape_ex(str, buffer, size, replace);
|
||||
}
|
||||
|
||||
int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape)
|
||||
{
|
||||
const char *text;
|
||||
|
@ -151,7 +160,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
|
|||
char obuf[1024];
|
||||
swrite(" ", 1, 1, out);
|
||||
if (escape) {
|
||||
text = str_escape(text, obuf, sizeof(obuf));
|
||||
text = crescape(text, obuf, sizeof(obuf));
|
||||
}
|
||||
swrite(text, 1, strlen(text), out);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ extern "C" {
|
|||
bool is_exclusive(const order * ord);
|
||||
bool is_repeated(keyword_t kwd);
|
||||
bool is_long(keyword_t kwd);
|
||||
const char *crescape(const char *str, char *buffer, size_t size);
|
||||
|
||||
char *write_order(const order * ord, const struct locale *lang,
|
||||
char *buffer, size_t size);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <tests.h>
|
||||
#include <CuTest.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void test_create_order(CuTest *tc) {
|
||||
char cmd[32];
|
||||
|
@ -239,6 +240,7 @@ static void test_is_persistent(CuTest *tc) {
|
|||
|
||||
ord = parse_order("@invalid", lang);
|
||||
CuAssertPtrEquals(tc, NULL, ord);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("give", lang);
|
||||
CuAssertIntEquals(tc, K_GIVE, ord->command);
|
||||
|
@ -290,6 +292,7 @@ static void test_is_silent(CuTest *tc) {
|
|||
|
||||
ord = parse_order("@invalid", lang);
|
||||
CuAssertPtrEquals(tc, NULL, ord);
|
||||
free_order(ord);
|
||||
|
||||
ord = parse_order("// comment", lang);
|
||||
CuAssertTrue(tc, is_persistent(ord));
|
||||
|
@ -482,10 +485,60 @@ static void test_study_order_unknown_quoted(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_create_order_long(CuTest *tc) {
|
||||
char buffer[2048];
|
||||
order *ord;
|
||||
struct locale *lang;
|
||||
stream out;
|
||||
const char * longstr = "// BESCHREIBEN EINHEIT \"In weià ƒ ƒ ƒ ƒ ƒ ƒ &#"
|
||||
"131;ƒƒƒƒƒƒ?e GewÃ
"
|
||||
"1;ƒƒƒƒƒƒƒƒƒÃƒƒƒ"
|
||||
"ƒƒƒƒƒƒƒƒƒÃƒƒƒ&#"
|
||||
"131;ƒƒƒƒƒƒ‚Ã
"
|
||||
"1;ƒƒƒƒ‚Ã"
|
||||
"ƒ‚ÂÃ&"
|
||||
"#131;ƒƒƒ‚ÂÃ&#"
|
||||
"131;ƒƒ‚ÂÂÃ&#"
|
||||
"130;¢‚Ã&"
|
||||
"#131;ƒ‚Ã"
|
||||
"31;‚ÂÃ
"
|
||||
"1;ƒƒƒƒƒƒƒ‚Ã"
|
||||
"ƒƒƒ‚[...]hB��2�xa�Hv$P�xa��A���A��";
|
||||
test_setup();
|
||||
lang = test_create_locale();
|
||||
ord = parse_order(longstr, lang);
|
||||
CuAssertIntEquals(tc, 0, ord->command);
|
||||
mstream_init(&out);
|
||||
stream_order(&out, ord, lang, true);
|
||||
out.api->rewind(out.handle);
|
||||
out.api->readln(out.handle, buffer, sizeof(buffer));
|
||||
mstream_done(&out);
|
||||
free_order(ord);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_crescape(CuTest *tc) {
|
||||
char buffer[16];
|
||||
const char *input = "12345678901234567890";
|
||||
|
||||
CuAssertStrEquals(tc, "1234", crescape("1234", buffer, 16));
|
||||
CuAssertPtrEquals(tc, (void *)input, (void *)crescape(input, buffer, 16));
|
||||
|
||||
CuAssertStrEquals(tc, "\\\"1234\\\"", crescape("\"1234\"", buffer, 16));
|
||||
CuAssertStrEquals(tc, "\\\"1234\\\"", buffer);
|
||||
|
||||
CuAssertStrEquals(tc, "\\\"1234", crescape("\"1234\"", buffer, 8));
|
||||
|
||||
/* unlike in C strings, only " and \ are escaped: */
|
||||
CuAssertStrEquals(tc, "\\\"\\\\\n\r\'", crescape("\"\\\n\r\'", buffer, 16));
|
||||
}
|
||||
|
||||
CuSuite *get_order_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_crescape);
|
||||
SUITE_ADD_TEST(suite, test_create_order);
|
||||
SUITE_ADD_TEST(suite, test_create_order_long);
|
||||
SUITE_ADD_TEST(suite, test_study_orders);
|
||||
SUITE_ADD_TEST(suite, test_study_order);
|
||||
SUITE_ADD_TEST(suite, test_study_order_unknown);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#ifndef ERESSEA_VERSION
|
||||
/* the version number, if it was not passed to make with -D */
|
||||
#define ERESSEA_VERSION "3.16.0"
|
||||
#define ERESSEA_VERSION "3.17.0"
|
||||
#endif
|
||||
|
||||
const char *eressea_version(void) {
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
static int read_permissions(variant *var, void *owner, struct gamedata *data)
|
||||
{
|
||||
attrib *a;
|
||||
attrib *a = NULL;
|
||||
UNUSED_ARG(var);
|
||||
read_attribs(data, &a, owner);
|
||||
a_remove(&a, a);
|
||||
|
|
|
@ -172,8 +172,8 @@ static order *monster_attack(unit * u, const unit * target)
|
|||
if (monster_is_waiting(u))
|
||||
return NULL;
|
||||
|
||||
if (u->region->land) {
|
||||
assert(u->region->flags & RF_GUARDED);
|
||||
if (u->region->land && (u->region->flags & RF_GUARDED) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return create_order(K_ATTACK, u->faction->locale, "%i", target->no);
|
||||
}
|
||||
|
|
15
src/report.c
15
src/report.c
|
@ -723,8 +723,9 @@ rp_messages(struct stream *out, message_list * msgs, faction * viewer, int inden
|
|||
int k = 0;
|
||||
struct mlist *m = msgs->begin;
|
||||
while (m) {
|
||||
/* messagetype * mt = m->type; */
|
||||
if (!categorized || strcmp(m->msg->type->section, section) == 0) {
|
||||
/* categorized messages need a section: */
|
||||
assert(!categorized || (m->msg->type->section != NULL));
|
||||
if (!categorized || m->msg->type->section == section) {
|
||||
char lbuf[8192];
|
||||
|
||||
if (!k && categorized) {
|
||||
|
@ -1037,6 +1038,9 @@ void report_region(struct stream *out, const region * r, faction * f)
|
|||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
if (is_mourning(r, turn + 1)) {
|
||||
bytes = (int)str_strlcpy(bufp, " ", size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mourning"), size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
|
@ -1877,6 +1881,9 @@ nr_building(struct stream *out, const region *r, const building *b, const factio
|
|||
}
|
||||
|
||||
if (!building_finished(b)) {
|
||||
bytes = (int)str_strlcpy(bufp, " ", size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
bytes = (int)str_strlcpy(bufp, LOC(lang, "nr_building_inprogress"), size);
|
||||
if (wrptr(&bufp, &size, bytes) != 0)
|
||||
WARN_STATIC_BUFFER();
|
||||
|
@ -2306,11 +2313,11 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
message_list *mlist = r_getmessages(r, f);
|
||||
if (mlist) {
|
||||
struct mlist **split = merge_messages(mlist, r->msgs);
|
||||
rp_messages(out, mlist, f, 0, true);
|
||||
rp_messages(out, mlist, f, 0, false);
|
||||
split_messages(mlist, split);
|
||||
}
|
||||
else {
|
||||
rp_messages(out, r->msgs, f, 0, true);
|
||||
rp_messages(out, r->msgs, f, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <platform.h>
|
||||
#endif
|
||||
#include "strings.h"
|
||||
#include "assert.h"
|
||||
|
||||
/* libc includes */
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
@ -111,7 +111,8 @@ size_t str_slprintf(char * dst, size_t size, const char * format, ...)
|
|||
return (size_t)result;
|
||||
}
|
||||
|
||||
void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value)
|
||||
void str_replace(char *buffer, size_t size, const char *tmpl, const char *var,
|
||||
const char *value)
|
||||
{
|
||||
size_t val_len = strlen(value);
|
||||
size_t var_len = strlen(var);
|
||||
|
@ -154,28 +155,28 @@ int str_hash(const char *s)
|
|||
return key & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
const char *str_escape(const char *str, char *buffer,
|
||||
size_t len)
|
||||
const char *str_escape_wrong(const char *str, char *buffer, size_t len)
|
||||
{
|
||||
const char *handle_start = strchr(str, '\"');
|
||||
if (!handle_start) handle_start = strchr(str, '\\');
|
||||
assert(buffer);
|
||||
if (handle_start) {
|
||||
const char *p;
|
||||
char *o;
|
||||
const char *p = str;
|
||||
char *o = buffer;
|
||||
size_t skip = handle_start - str;
|
||||
|
||||
if (skip > len) {
|
||||
skip = len;
|
||||
}
|
||||
if (skip > 0) {
|
||||
memcpy(buffer, str, skip);
|
||||
o = buffer + skip;
|
||||
p = str + skip;
|
||||
o += skip;
|
||||
p += skip;
|
||||
len -= skip;
|
||||
}
|
||||
do {
|
||||
if (*p == '\"' || *p == '\\') {
|
||||
if (len < 2) {
|
||||
*o = '\0';
|
||||
break;
|
||||
}
|
||||
(*o++) = '\\';
|
||||
|
@ -183,13 +184,15 @@ const char *str_escape(const char *str, char *buffer,
|
|||
}
|
||||
else {
|
||||
if (len < 1) {
|
||||
*o = '\0';
|
||||
break;
|
||||
}
|
||||
--len;
|
||||
}
|
||||
if (len > 0) {
|
||||
(*o++) = (*p);
|
||||
} while (*p++);
|
||||
}
|
||||
} while (len > 0 && *p++);
|
||||
*o = '\0';
|
||||
return buffer;
|
||||
}
|
||||
return str;
|
||||
|
@ -306,3 +309,100 @@ char *str_unescape(char *str) {
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars)
|
||||
{
|
||||
size_t slen = strlen(str);
|
||||
const char *read = str;
|
||||
char *write = buffer;
|
||||
if (size < 1) {
|
||||
return NULL;
|
||||
}
|
||||
while (slen > 0 && size > 1 && *read) {
|
||||
const char *pos = strpbrk(read, chars);
|
||||
size_t len = size;
|
||||
if (pos) {
|
||||
len = pos - read;
|
||||
}
|
||||
if (len < size) {
|
||||
unsigned char ch = *(const unsigned char *)pos;
|
||||
if (len > 0) {
|
||||
if (len > slen) {
|
||||
len = slen;
|
||||
}
|
||||
memmove(write, read, len);
|
||||
slen -= len;
|
||||
write += len;
|
||||
read += len;
|
||||
size -= len;
|
||||
}
|
||||
switch (ch) {
|
||||
case '\t':
|
||||
if (size > 2) {
|
||||
*write++ = '\\';
|
||||
*write++ = 't';
|
||||
size -= 2;
|
||||
}
|
||||
else size = 1;
|
||||
break;
|
||||
case '\n':
|
||||
if (size > 2) {
|
||||
*write++ = '\\';
|
||||
*write++ = 'n';
|
||||
size -= 2;
|
||||
}
|
||||
else size = 1;
|
||||
break;
|
||||
case '\r':
|
||||
if (size > 2) {
|
||||
*write++ = '\\';
|
||||
*write++ = 'r';
|
||||
size -= 2;
|
||||
}
|
||||
else size = 1;
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
if (size > 2) {
|
||||
*write++ = '\\';
|
||||
*write++ = ch;
|
||||
size -= 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (size > 5) {
|
||||
int n = sprintf(write, "\\%03o", ch);
|
||||
if (n > 0) {
|
||||
assert(n == 5);
|
||||
write += n;
|
||||
size -= n;
|
||||
}
|
||||
else size = 1;
|
||||
}
|
||||
else size = 1;
|
||||
}
|
||||
++read;
|
||||
--slen;
|
||||
} else {
|
||||
/* end of buffer space */
|
||||
len = size - 1;
|
||||
if (len > 0) {
|
||||
if (len > slen) {
|
||||
len = slen;
|
||||
}
|
||||
memmove(write, read, len);
|
||||
write += len;
|
||||
size -= len;
|
||||
slen -= len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*write = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char *str_escape(const char *str, char *buffer, size_t size) {
|
||||
return str_escape_ex(str, buffer, size, "\n\t\r\'\"\\");
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ extern "C" {
|
|||
size_t str_strlcat(char *dst, const char *src, size_t len);
|
||||
char *str_strdup(const char *s);
|
||||
|
||||
const char *str_escape(const char *str, char *buffer, size_t len);
|
||||
const char *str_escape(const char *str, char *buffer, size_t size);
|
||||
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars);
|
||||
char *str_unescape(char *str);
|
||||
|
||||
unsigned int jenkins_hash(unsigned int a);
|
||||
|
|
|
@ -22,12 +22,36 @@ static void test_str_unescape(CuTest * tc)
|
|||
CuAssertStrEquals(tc, "\"\\\n\t\ra", scratch);
|
||||
}
|
||||
|
||||
static void test_str_escape_ex(CuTest * tc)
|
||||
{
|
||||
char scratch[16];
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, (void *)str_escape_ex("1234", scratch, 0, "\\\""));
|
||||
memset(scratch, 0, sizeof(scratch));
|
||||
CuAssertStrEquals(tc, "1234", (void *)str_escape_ex("1234\000abcd", scratch, 16, "\\\""));
|
||||
CuAssertIntEquals(tc, 0, scratch[5]);
|
||||
}
|
||||
|
||||
static void test_str_escape(CuTest * tc)
|
||||
{
|
||||
char scratch[64];
|
||||
CuAssertStrEquals(tc, "12345678901234567890", str_escape("12345678901234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "123456789\\\"12345", str_escape("123456789\"1234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "1234567890123456", str_escape("1234567890123456\"890", scratch, 16));
|
||||
char scratch[16];
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, (void *)str_escape("1234", scratch, 0));
|
||||
CuAssertStrEquals(tc, "", str_escape("1234", scratch, 1));
|
||||
CuAssertStrEquals(tc, "1", str_escape("1234", scratch, 2));
|
||||
CuAssertStrEquals(tc, "\\n", str_escape("\n234", scratch, 3));
|
||||
|
||||
CuAssertStrEquals(tc, "\\n\\r\\t\\\\\\\"\\\'", str_escape("\n\r\t\\\"\'", scratch, 16));
|
||||
CuAssertStrEquals(tc, "12345678", str_escape("12345678", scratch, 16));
|
||||
CuAssertStrEquals(tc, "123456789012345", str_escape("123456789012345", scratch, 16));
|
||||
CuAssertStrEquals(tc, "12345678901234", str_escape("12345678901234\n", scratch, 15));
|
||||
CuAssertStrEquals(tc, "123456789012345", str_escape("12345678901234567890", scratch, 16));
|
||||
|
||||
CuAssertStrEquals(tc, "\\\\\\\"234", str_escape("\\\"234567890", scratch, 8));
|
||||
CuAssertStrEquals(tc, "\\\"\\\\234", str_escape("\"\\234567890", scratch, 8));
|
||||
CuAssertStrEquals(tc, "123456789012345", str_escape("12345678901234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "123456789\\\"1234", str_escape("123456789\"1234567890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "123456789012345", str_escape("1234567890123456\"890", scratch, 16));
|
||||
CuAssertStrEquals(tc, "hello world", str_escape("hello world", scratch, sizeof(scratch)));
|
||||
CuAssertStrEquals(tc, "hello \\\"world\\\"", str_escape("hello \"world\"", scratch, sizeof(scratch)));
|
||||
CuAssertStrEquals(tc, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch)));
|
||||
|
@ -135,6 +159,7 @@ CuSuite *get_strings_suite(void)
|
|||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_str_hash);
|
||||
SUITE_ADD_TEST(suite, test_str_escape);
|
||||
SUITE_ADD_TEST(suite, test_str_escape_ex);
|
||||
SUITE_ADD_TEST(suite, test_str_unescape);
|
||||
SUITE_ADD_TEST(suite, test_str_replace);
|
||||
SUITE_ADD_TEST(suite, test_str_slprintf);
|
||||
|
|
Loading…
Reference in a new issue