mirror of
https://github.com/depp/syncfiles.git
synced 2024-11-26 00:49:17 +00:00
164 lines
4.0 KiB
C
164 lines
4.0 KiB
C
|
// Copyright 2023 Dietrich Epp.
|
||
|
// This file is part of SyncFiles. SyncFiles is licensed under the terms of the
|
||
|
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
|
||
|
#include "macos/pstrbuilder.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
// =============================================================================
|
||
|
// Temporary buffer for Pascal strings
|
||
|
|
||
|
static size_t PStrBufPos;
|
||
|
static unsigned char PStrBuf[1024];
|
||
|
|
||
|
static const unsigned char *P2CStr(const char *str)
|
||
|
{
|
||
|
size_t len;
|
||
|
unsigned char *ptr;
|
||
|
|
||
|
len = strlen(str);
|
||
|
if (len > 255) {
|
||
|
fputs("Error: PStr too long\n", stderr);
|
||
|
exit(1);
|
||
|
}
|
||
|
if (len + 1 > sizeof(PStrBuf) - PStrBufPos) {
|
||
|
fputs("Error: PStr overflow\n", stderr);
|
||
|
exit(1);
|
||
|
}
|
||
|
ptr = PStrBuf + PStrBufPos;
|
||
|
*ptr = len;
|
||
|
memcpy(ptr + 1, str, len);
|
||
|
PStrBufPos += len + 1;
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
static void PStrReset(void)
|
||
|
{
|
||
|
PStrBufPos = 0;
|
||
|
}
|
||
|
|
||
|
#define PSTR(x) P2CStr(x)
|
||
|
#define PSTR_RESET() PStrReset()
|
||
|
|
||
|
// =============================================================================
|
||
|
|
||
|
static Boolean TestFailed;
|
||
|
|
||
|
static void PrintQuoted(const unsigned char *str)
|
||
|
{
|
||
|
const unsigned char *ptr = str + 1;
|
||
|
const unsigned char *end = ptr + str[0];
|
||
|
int ch;
|
||
|
|
||
|
for (; ptr < end; ptr++) {
|
||
|
ch = *ptr;
|
||
|
if (32 <= ch && ch <= 126) {
|
||
|
if (ch == '\\' || ch == '"') {
|
||
|
fputc('\\', stderr);
|
||
|
}
|
||
|
fputc(ch, stderr);
|
||
|
} else {
|
||
|
fprintf(stderr, "\\x%02x", ch);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void TestString(int lineno, const struct PStrBuilder *buf,
|
||
|
const unsigned char *expect, Boolean expect_truncated)
|
||
|
{
|
||
|
if (memcmp(buf->data, expect, expect[0] + 1) != 0 ||
|
||
|
buf->truncated != expect_truncated) {
|
||
|
fprintf(stderr, "%s:%d: Incorrect result\n", __FILE__, lineno);
|
||
|
fputs(" expect: \"", stderr);
|
||
|
PrintQuoted(expect);
|
||
|
fprintf(stderr, "\" (truncated=%d)\n", expect_truncated);
|
||
|
fputs(" got: \"", stderr);
|
||
|
PrintQuoted(buf->data);
|
||
|
fprintf(stderr, "\" (truncated=%d)\n", buf->truncated);
|
||
|
TestFailed = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define TEST_STRING(buf, expect, expect_truncated) \
|
||
|
TestString(__LINE__, buf, expect, expect_truncated)
|
||
|
|
||
|
#define STR50 "0123456789abcdef0123456789abcdef0123456789abcdef0."
|
||
|
#define STR250 STR50 STR50 STR50 STR50 STR50
|
||
|
|
||
|
static void Clear(struct PStrBuilder *buf, const unsigned char **params)
|
||
|
{
|
||
|
int i;
|
||
|
buf->data[0] = 0;
|
||
|
buf->truncated = false;
|
||
|
for (i = 0; i < 9; i++) {
|
||
|
params[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
struct PStrBuilder buf;
|
||
|
const unsigned char *params[9];
|
||
|
|
||
|
(void)argc;
|
||
|
(void)argv;
|
||
|
|
||
|
Clear(&buf, params);
|
||
|
TEST_STRING(&buf, PSTR(""), false);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// Append string to empty buffer.
|
||
|
PStrAppend(&buf, PSTR("String1"));
|
||
|
TEST_STRING(&buf, PSTR("String1"), false);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// Append string to non-empty buffer.
|
||
|
PStrAppend(&buf, PSTR("String2"));
|
||
|
TEST_STRING(&buf, PSTR("String1String2"), false);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// Append string with parameters.
|
||
|
Clear(&buf, params);
|
||
|
PStrAppend(&buf, PSTR("initial: "));
|
||
|
params[0] = PSTR("(param1)");
|
||
|
params[1] = PSTR("(param2)");
|
||
|
params[8] = PSTR("(param9)");
|
||
|
PStrAppendSubstitute(&buf, PSTR("^1 ^9 -> ^2"), 9, params);
|
||
|
TEST_STRING(&buf, PSTR("initial: (param1) (param9) -> (param2)"), false);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// Missing parameters are left alone, including NULL parameters.
|
||
|
Clear(&buf, params);
|
||
|
params[0] = PSTR("param1");
|
||
|
PStrAppendSubstitute(&buf, PSTR("^0 ^1 ^2 ^3 ^9"), 2, params);
|
||
|
TEST_STRING(&buf, PSTR("^0 param1 ^2 ^3 ^9"), false);
|
||
|
|
||
|
// String length 255 works.
|
||
|
Clear(&buf, params);
|
||
|
PStrAppend(&buf, PSTR(STR250));
|
||
|
PStrAppend(&buf, PSTR("VWXYZ"));
|
||
|
TEST_STRING(&buf, PSTR(STR250 "VWXYZ"), false);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// String length 256 is truncated.
|
||
|
PStrAppend(&buf, PSTR("."));
|
||
|
TEST_STRING(&buf, PSTR(STR250 "VWXY\xc9"), true);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
// Truncate with parameters.
|
||
|
Clear(&buf, params);
|
||
|
params[0] = PSTR(STR50);
|
||
|
PStrAppendSubstitute(&buf, PSTR("^1^1^1^1^1^1"), 1, params);
|
||
|
TEST_STRING(&buf, PSTR(STR250 "0123\xc9"), true);
|
||
|
PSTR_RESET();
|
||
|
|
||
|
fputs("OK?\n", stderr);
|
||
|
if (TestFailed) {
|
||
|
fputs("Test failed\n", stderr);
|
||
|
exit(1);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|