Skip to content

Commit

Permalink
Improve stringparser and fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
katajakasa committed Jul 4, 2024
1 parent 471e0c9 commit 61c936b
Show file tree
Hide file tree
Showing 10 changed files with 446 additions and 347 deletions.
629 changes: 346 additions & 283 deletions src/formats/script.c

Large diffs are not rendered by default.

27 changes: 6 additions & 21 deletions src/formats/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#define SD_SCRIPT_H

#include "formats/taglist.h"
#include "utils/str.h"
#include "utils/vector.h"
#include <stddef.h>

#ifdef __cplusplus
Expand All @@ -35,8 +37,7 @@ typedef struct {
typedef struct {
int sprite; ///< Sprite ID that the frame relates to
int tick_len; ///< Length of the frame in ticks
int tag_count; ///< Amount of tags in this frame
sd_script_tag *tags; ///< A list of tags in this frame
vector tags; ///< A list of tags in this frame
} sd_script_frame;

/*! \brief Animation script
Expand All @@ -45,8 +46,7 @@ typedef struct {
* A valid string must contain at least a single frame.
*/
typedef struct {
int frame_count; ///< Amount of frames in the string
sd_script_frame *frames; ///< List of frames in this string
vector frames; ///< List of frames in this string
} sd_script;

/*! \brief Initialize script parser
Expand Down Expand Up @@ -102,24 +102,9 @@ int sd_script_decode(sd_script *script, const char *str, int *invalid_pos);
* \retval SD_SUCCESS Successful operation
*
* \param script Script structure to encode
* \param str Target string buffer. Make sure it's large enough!
* \param str Target string object. Must be initialized!
*/
int sd_script_encode(const sd_script *script, char *str, size_t len);

/*! \brief Find the encoded length of a script
*
* Returns the encoded length of the animation script. The length will be the EXACT size
* of the string, so you may need to add +1 to compensate for a trailing zero.
*
* The function will return 0 if there are no frames in the script, the frames are invalid,
* or the script variable is NULL.
*
* \sa sd_script_decode
*
* \param script Script structure to check
* \return Length of the encoded animation string.
*/
int sd_script_encoded_length(const sd_script *script);
int sd_script_encode(const sd_script *script, str *dst);

/*! \brief Find the total duration of the script
*
Expand Down
4 changes: 2 additions & 2 deletions src/game/protos/player.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ void player_set_delay(object *obj, int delay) {
#ifdef DEBUGMODE
void player_describe_frame(const sd_script_frame *frame) {
DEBUG("Frame %c%d", 65 + frame->sprite, frame->tick_len);
for(int i = 0; i < frame->tag_count; i++) {
sd_script_tag *tag = &frame->tags[i];
for(int i = 0; i < vector_size(&frame->tags); i++) {
sd_script_tag *tag = vector_get(&frame->tags, i);
if(tag->has_param) {
DEBUG(" %3s%5d %s", tag->key, tag->value, tag->desc);
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/utils/miscmath.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "utils/miscmath.h"
#include <limits.h>
#include <math.h>

int clamp(int val, int min, int max) {
Expand All @@ -17,6 +18,14 @@ float clampf(float val, float min, float max) {
return val;
}

int clamp_long_to_int(long val) {
if(val > INT_MAX)
return INT_MAX;
if(val < INT_MIN)
return INT_MIN;
return val;
}

int max3(int a, int b, int c) {
int max = a;
if(b > max)
Expand Down
1 change: 1 addition & 0 deletions src/utils/miscmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ float clampf(float val, float _min, float _max);
int clamp(int val, int _min, int _max);
int max2(int a, int b);
int min2(int a, int b);
int clamp_long_to_int(long val);

#endif // MISCMATH_H
23 changes: 21 additions & 2 deletions src/utils/str.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "utils/str.h"
#include "utils/allocator.h"
#include "utils/log.h"
#include "utils/miscmath.h"

#include <assert.h>
#include <ctype.h>
Expand Down Expand Up @@ -69,8 +70,9 @@ void str_from_format(str *dst, const char *format, ...) {

void str_from_slice(str *dst, const str *src, size_t start, size_t end) {
assert(dst != src);
assert(end <= src->len);
assert(start < end);
if(end > src->len)
end = src->len;
size_t len = end - start;
STR_ALLOC(dst, len);
memcpy(dst->data, src->data + start, len);
Expand Down Expand Up @@ -114,7 +116,7 @@ static size_t _strip_size(const str *src, bool left) {
}

void str_rstrip(str *dst) {
// This is simple, just reduce sice and set ending 0.
// This is simple, just reduce size and set ending 0.
size_t skip = _strip_size(dst, false);
STR_REALLOC(dst, skip + 1);
STR_ZERO(dst);
Expand Down Expand Up @@ -159,6 +161,14 @@ static bool _find_next(const str *string, char find, size_t *pos) {
return false;
}

void str_cut(str *dst, size_t len) {
if(len > dst->len)
len = dst->len;
dst->len -= len;
STR_REALLOC(dst, dst->len);
STR_ZERO(dst);
}

void str_replace(str *dst, const char *seek, const char *replacement, int limit) {
size_t seek_len = strlen(seek);
size_t replacement_len = strlen(replacement);
Expand Down Expand Up @@ -264,6 +274,15 @@ bool str_to_long(const str *string, long *result) {
return (string->data != end);
}

bool str_to_int(const str *string, int *result) {
long value;
bool got = str_to_long(string, &value);
if(got) {
*result = clamp_long_to_int(value);
}
return got;
}

const char *str_c(const str *string) {
// At the moment, the internal representation of
// string is compatible with C strings. So just return
Expand Down
18 changes: 18 additions & 0 deletions src/utils/str.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ void str_from_format(str *dst, const char *format, ...);
*/
void str_from_slice(str *dst, const str *src, size_t start, size_t end);

/**
* @brief Cut away amount of characters from the end of the string.
* @details If cut amount is larger than the length of the string, the whole string will be cleared.
* @param dst String to cut
* @param len Amount to cut
*/
void str_cut(str *dst, size_t len);

/**
* @brief Free string object
* @details Frees up any memory used by the string object. Usage of the string after freeing it
Expand Down Expand Up @@ -186,6 +194,16 @@ bool str_to_float(const str *string, float *m);
*/
bool str_to_long(const str *string, long *m);

/**
* @brief Convert string to int
* @details Returns true if conversion was a success, false if not.
* @param string String to convert
* @param m Result value
* @return true If success
* @return false If failure (result value is invalid)
*/
bool str_to_int(const str *string, int *m);

/**
* @brief Returns a C string compatible represantation of a string object.
* @details Note! This will become invalid if any changes are performanced on the string
Expand Down
58 changes: 30 additions & 28 deletions testing/test_script.c
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
#include "formats/error.h"
#include "formats/script.h"
#include "misc/parser_test_strings.h"
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>

sd_script script;

#define OK_STR "s05bpd1bps1bpn64A100-s1sf3B10-C34"
#define OK_STR_ENC "s5bpd1bps1bpn64A100-s1sf3B10-C34"

static int get_tag_count(const sd_script *scr, int frame_id) {
sd_script_frame *frame = vector_get(&scr->frames, frame_id);
CU_ASSERT_PTR_NOT_NULL(frame);
return vector_size(&frame->tags);
}

void test_script_create(void) {
CU_ASSERT(sd_script_create(&script) == SD_SUCCESS);
CU_ASSERT(sd_script_create(NULL) == SD_INVALID_INPUT);
CU_ASSERT(script.frame_count == 0);
CU_ASSERT(vector_size(&script.frames) == 0);
}

void test_script_decode(void) {
CU_ASSERT(sd_script_decode(&script, NULL, NULL) == SD_INVALID_INPUT);
CU_ASSERT(sd_script_decode(NULL, OK_STR, NULL) == SD_INVALID_INPUT);
CU_ASSERT(sd_script_decode(&script, OK_STR, NULL) == SD_SUCCESS);
CU_ASSERT(script.frame_count == 3);
CU_ASSERT(script.frames[0].tag_count == 4);
CU_ASSERT(script.frames[1].tag_count == 2);
CU_ASSERT(script.frames[2].tag_count == 0);
CU_ASSERT(vector_size(&script.frames) == 3);
CU_ASSERT(get_tag_count(&script, 0) == 4);
CU_ASSERT(get_tag_count(&script, 1) == 2);
CU_ASSERT(get_tag_count(&script, 2) == 0);
}

void test_total_ticks(void) {
Expand All @@ -47,16 +52,12 @@ void test_tick_len_at_frame(void) {
CU_ASSERT(sd_script_get_tick_len_at_frame(&script, 2) == 34);
}

void test_script_encoded_length(void) {
int len = sd_script_encoded_length(&script);
CU_ASSERT(len = strlen(OK_STR_ENC));
}

void test_script_encode(void) {
char buf[1024];
memset(buf, 0, 1024);
CU_ASSERT(sd_script_encode(&script, buf, 1024) == SD_SUCCESS);
CU_ASSERT(strcmp(OK_STR_ENC, buf) == 0);
str dst;
str_create(&dst);
CU_ASSERT(sd_script_encode(&script, &dst) == SD_SUCCESS);
CU_ASSERT(strcmp(OK_STR_ENC, str_c(&dst)) == 0);
str_free(&dst);
}

void test_script_get_frame(void) {
Expand Down Expand Up @@ -178,17 +179,21 @@ void test_script_free(void) {
}

void test_script_all(void) {
char buf[1024];
str dst;
int fail_at;
for(int i = 0; i < TEST_STRING_COUNT; i++) {
str_create(&dst);
sd_script s;
CU_ASSERT_FATAL(sd_script_create(&s) == SD_SUCCESS);
int ret = sd_script_decode(&s, test_strings[i], NULL);
int ret = sd_script_decode(&s, test_strings[i], &fail_at);
if(ret == SD_SUCCESS) {
CU_ASSERT(sd_script_encode(&s, buf, 1024) == SD_SUCCESS);
CU_ASSERT(sd_script_encode(&s, &dst) == SD_SUCCESS);
} else {
printf("%s - (%d - %c)\n", test_strings[i], fail_at, test_strings[i][fail_at]);
CU_FAIL("Parser failed. Broken string ?");
}
sd_script_free(&s);
str_free(&dst);
}
}

Expand Down Expand Up @@ -230,7 +235,7 @@ void test_set_tag(void) {
CU_ASSERT(sd_script_get(sd_script_get_frame(&script, 1), "sf") == 3);

// Check tag count
CU_ASSERT(script.frames[1].tag_count == 3);
CU_ASSERT_EQUAL(get_tag_count(&script, 1), 3);

// Bad input values
CU_ASSERT(sd_script_set_tag(NULL, 1, "bpd", 50) == SD_INVALID_INPUT);
Expand Down Expand Up @@ -277,30 +282,30 @@ void test_delete_tag(void) {
CU_ASSERT(sd_script_create(&s) == SD_SUCCESS);
CU_ASSERT(sd_script_append_frame(&s, 100, 0) == SD_SUCCESS);
CU_ASSERT(sd_script_set_tag(&s, 0, "bpn", 10) == SD_SUCCESS);
CU_ASSERT(s.frames[0].tag_count == 1);
CU_ASSERT(get_tag_count(&s, 0) == 1);
CU_ASSERT(sd_script_set_tag(&s, 0, "s", 15) == SD_SUCCESS);
CU_ASSERT(s.frames[0].tag_count == 2);
CU_ASSERT(get_tag_count(&s, 0) == 2);
CU_ASSERT(sd_script_set_tag(&s, 0, "sf", 100) == SD_SUCCESS);
CU_ASSERT(s.frames[0].tag_count == 3);
CU_ASSERT(get_tag_count(&s, 0) == 3);

// Real tests
CU_ASSERT(sd_script_delete_tag(&s, 0, "bpn") == SD_SUCCESS);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "bpn") == 0);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "s") == 15);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "sf") == 100);
CU_ASSERT(s.frames[0].tag_count == 2);
CU_ASSERT(get_tag_count(&s, 0) == 2);

CU_ASSERT(sd_script_delete_tag(&s, 0, "s") == SD_SUCCESS);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "bpn") == 0);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "s") == 0);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "sf") == 100);
CU_ASSERT(s.frames[0].tag_count == 1);
CU_ASSERT(get_tag_count(&s, 0) == 1);

CU_ASSERT(sd_script_delete_tag(&s, 0, "sf") == SD_SUCCESS);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "bpn") == 0);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "s") == 0);
CU_ASSERT(sd_script_get(sd_script_get_frame(&s, 0), "sf") == 0);
CU_ASSERT(s.frames[0].tag_count == 0);
CU_ASSERT(get_tag_count(&s, 0) == 0);

sd_script_free(&s);
}
Expand Down Expand Up @@ -363,9 +368,6 @@ void script_test_suite(CU_pSuite suite) {
if(CU_add_test(suite, "test of sd_script_get_tick_len_at_frame", test_tick_len_at_frame) == NULL) {
return;
}
if(CU_add_test(suite, "test of sd_script_encoded_length", test_script_encoded_length) == NULL) {
return;
}
if(CU_add_test(suite, "test of sd_script_encode", test_script_encode) == NULL) {
return;
}
Expand Down
13 changes: 8 additions & 5 deletions tools/shared/animation_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,20 @@ void anim_pop(sd_animation *ani) {
printf("Last sprite popped from animation. Animation now has %d sprites.\n", ani->sprite_count);
}

void string_strip(char *str, size_t len, const char *tag) {
void string_strip(char *input, size_t len, const char *tag) {
sd_script s;
sd_script_create(&s);
sd_script_decode(&s, str, NULL);
sd_script_decode(&s, input, NULL);

for(int i = 0; i < s.frame_count; i++) {
for(int i = 0; i < vector_size(&s.frames); i++) {
sd_script_delete_tag(&s, i, tag);
}

// Dont bother with resizing the result
sd_script_encode(&s, str, len);
str dst;
str_create(&dst);
sd_script_encode(&s, &dst);
strncpy(input, str_c(&dst), len);
str_free(&dst);
sd_script_free(&s);
}

Expand Down
11 changes: 5 additions & 6 deletions tools/stringparser/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
#include "formats/script.h"
#include <argtable2.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
// commandline argument parser options
struct arg_lit *help = arg_lit0("h", "help", "print this help and exit");
struct arg_lit *vers = arg_lit0("v", "version", "print version information and exit");
struct arg_str *astr = arg_str1("s", "str", "<str>", "Animation string");
struct arg_str *astr = arg_str1(NULL, NULL, "<str>", "Animation string");
struct arg_end *end = arg_end(20);
void *argtable[] = {help, vers, astr, end};
const char *progname = "omf_parse";
Expand Down Expand Up @@ -82,11 +81,11 @@ int main(int argc, char *argv[]) {
goto exit_1;
}

for(int frame_id = 0; frame_id < script.frame_count; frame_id++) {
sd_script_frame *frame = &script.frames[frame_id];
for(int frame_id = 0; frame_id < vector_size(&script.frames); frame_id++) {
sd_script_frame *frame = vector_get(&script.frames, frame_id);
printf("%d. Frame %d: '%c%d'\n", frame_id, frame->sprite, (char)(frame->sprite + 65), frame->tick_len);
for(int tag_id = 0; tag_id < frame->tag_count; tag_id++) {
sd_script_tag *tag = &frame->tags[tag_id];
for(int tag_id = 0; tag_id < vector_size(&frame->tags); tag_id++) {
sd_script_tag *tag = vector_get(&frame->tags, tag_id);
if(tag->desc == NULL) {
tag->desc = "";
}
Expand Down

0 comments on commit 61c936b

Please sign in to comment.