mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
psyc_text + tests
This commit is contained in:
parent
aa98e00fba
commit
804a2ab394
7 changed files with 279 additions and 40 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@ test/testMatch
|
||||||
test/testParser
|
test/testParser
|
||||||
test/testRender
|
test/testRender
|
||||||
test/testServer
|
test/testServer
|
||||||
|
test/testText
|
||||||
test/isRoutingVar
|
test/isRoutingVar
|
||||||
test/getVarType
|
test/getVarType
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ typedef struct
|
||||||
psycListFlag flag;
|
psycListFlag flag;
|
||||||
} psycList;
|
} psycList;
|
||||||
|
|
||||||
/* intermediate struct for a PSYC packet */
|
/** intermediate struct for a PSYC packet */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
psycHeader routing; ///< Routing header.
|
psycHeader routing; ///< Routing header.
|
||||||
|
@ -234,34 +234,4 @@ int psyc_inherits(char *sho, size_t slen,
|
||||||
int psyc_matches(char *sho, size_t slen,
|
int psyc_matches(char *sho, size_t slen,
|
||||||
char *lon, size_t llen);
|
char *lon, size_t llen);
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for psyc_text() that produces a value for a match.
|
|
||||||
*
|
|
||||||
* The application looks up a match such as _fruit from [_fruit] and
|
|
||||||
* if found writes its current value from its variable store into the
|
|
||||||
* outgoing buffer.. "Apple" for example. The template returns the
|
|
||||||
* number of bytes written. 0 is a legal return value. Should the
|
|
||||||
* callback return -1, psyc_text leaves the original template text as is.
|
|
||||||
*/
|
|
||||||
typedef int (*psyctextCB)(char *match, size_t mlen,
|
|
||||||
char **buffer, size_t *blen);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills out text templates by asking a callback for content.
|
|
||||||
*
|
|
||||||
* Copies the contents of the template into the buffer while looking
|
|
||||||
* for braceOpen and braceClose strings and calling the callback for
|
|
||||||
* each enclosed string between these braces. Should the callback
|
|
||||||
* return -1, the original template text is copied as is.
|
|
||||||
*
|
|
||||||
* By default PSYC's "[" and "]" are used but you can provide any other
|
|
||||||
* brace strings such as "${" and "}" or "<!--" and "-->".
|
|
||||||
*
|
|
||||||
* See also http://about.psyc.eu/psyctext
|
|
||||||
*/
|
|
||||||
int psyc_text(char *template, size_t tlen,
|
|
||||||
char **buffer, size_t *blen,
|
|
||||||
psyctextCB lookupValue,
|
|
||||||
char *braceOpen, char *braceClose);
|
|
||||||
|
|
||||||
#endif // PSYC_H
|
#endif // PSYC_H
|
||||||
|
|
71
include/psyc/text.h
Normal file
71
include/psyc/text.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* The return value definitions for the PSYC text parsing function.
|
||||||
|
* @see psyc_text()
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PSYC_TEXT_NO_SUBST = -1,
|
||||||
|
PSYC_TEXT_COMPLETE = 0,
|
||||||
|
PSYC_TEXT_INCOMPLETE = 1,
|
||||||
|
} psycTextRC;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PSYC_TEXT_VALUE_NOT_FOUND = -1,
|
||||||
|
PSYC_TEXT_VALUE_FOUND = 0,
|
||||||
|
} psycTextValueRC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for keeping PSYC text parser state.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t cursor; ///< current position in the template
|
||||||
|
size_t written; ///< number of bytes written to buffer
|
||||||
|
psycString template; ///< template to parse
|
||||||
|
psycString buffer; ///< buffer for writing to
|
||||||
|
psycString open;
|
||||||
|
psycString close;
|
||||||
|
} psycTextState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for psyc_text() that produces a value for a match.
|
||||||
|
*
|
||||||
|
* The application looks up a match such as _fruit from [_fruit] and
|
||||||
|
* if found writes its current value from its variable store into the
|
||||||
|
* outgoing buffer.. "Apple" for example. The template returns the
|
||||||
|
* number of bytes written. 0 is a legal return value. Should the
|
||||||
|
* callback return -1, psyc_text leaves the original template text as is.
|
||||||
|
*/
|
||||||
|
typedef psycTextValueRC (*psycTextCB)(char *name, size_t len, psycString *value);
|
||||||
|
|
||||||
|
inline void psyc_initTextState (psycTextState *state,
|
||||||
|
char *template, size_t tlen,
|
||||||
|
char *buffer, size_t blen);
|
||||||
|
|
||||||
|
inline void psyc_initTextState2 (psycTextState* state,
|
||||||
|
char *template, size_t tlen,
|
||||||
|
char *buffer, size_t blen,
|
||||||
|
char *open, size_t openlen,
|
||||||
|
char *close, size_t closelen);
|
||||||
|
|
||||||
|
inline void psyc_setTextBuffer (psycTextState *state, psycString buffer);
|
||||||
|
|
||||||
|
inline void psyc_setTextBuffer2 (psycTextState *state, char *buffer, size_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills out text templates by asking a callback for content.
|
||||||
|
*
|
||||||
|
* Copies the contents of the template into the buffer while looking
|
||||||
|
* for braceOpen and braceClose strings and calling the callback for
|
||||||
|
* each enclosed string between these braces. Should the callback
|
||||||
|
* return -1, the original template text is copied as is.
|
||||||
|
*
|
||||||
|
* By default PSYC's "[" and "]" are used but you can provide any other
|
||||||
|
* brace strings such as "${" and "}" or "<!--" and "-->".
|
||||||
|
*
|
||||||
|
* See also http://about.psyc.eu/psyctext
|
||||||
|
*/
|
||||||
|
|
||||||
|
psycTextRC psyc_text(psycTextState *state, psycTextCB getValue);
|
|
@ -3,8 +3,8 @@ DEBUG = 2
|
||||||
CFLAGS = -I../include -Wall ${OPT}
|
CFLAGS = -I../include -Wall ${OPT}
|
||||||
DIET = diet
|
DIET = diet
|
||||||
|
|
||||||
S = packet.c misc.c parser.c match.c render.c memmem.c itoa.c variable.c
|
S = packet.c misc.c parser.c match.c render.c memmem.c itoa.c variable.c text.c
|
||||||
O = packet.o misc.o parser.o match.o render.o memmem.o itoa.o variable.o
|
O = packet.o misc.o parser.o match.o render.o memmem.o itoa.o variable.o text.o
|
||||||
|
|
||||||
all: CC := ${WRAPPER} ${CC}
|
all: CC := ${WRAPPER} ${CC}
|
||||||
all: lib
|
all: lib
|
||||||
|
|
119
src/text.c
119
src/text.c
|
@ -1,9 +1,116 @@
|
||||||
/* psyc_text() */
|
#include <psyc/lib.h>
|
||||||
|
#include <psyc/text.h>
|
||||||
|
|
||||||
int psyc_text(char *template, size_t tlen,
|
inline void psyc_initTextState (psycTextState *state,
|
||||||
char **buffer, size_t *blen,
|
char *template, size_t tlen,
|
||||||
psyctextCB lookupValue,
|
char *buffer, size_t blen)
|
||||||
char *braceOpen, char *braceClose)
|
|
||||||
{
|
{
|
||||||
|
state->cursor = state->written = 0;
|
||||||
|
state->template = psyc_newString(template, tlen);
|
||||||
|
state->buffer = psyc_newString(buffer, blen);
|
||||||
|
state->open = psyc_newString("[", 1);
|
||||||
|
state->close = psyc_newString("]", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void psyc_initTextState2 (psycTextState* state,
|
||||||
|
char *template, size_t tlen,
|
||||||
|
char *buffer, size_t blen,
|
||||||
|
char *open, size_t openlen,
|
||||||
|
char *close, size_t closelen)
|
||||||
|
{
|
||||||
|
state->template = psyc_newString(template, tlen);
|
||||||
|
state->buffer = psyc_newString(buffer, blen);
|
||||||
|
state->open = psyc_newString(open, openlen);
|
||||||
|
state->close = psyc_newString(close, closelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void psyc_setTextBuffer (psycTextState* state, psycString buffer)
|
||||||
|
{
|
||||||
|
state->buffer = buffer;
|
||||||
|
state->written = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void psyc_setTextBuffer2 (psycTextState* state, char *buffer, size_t length)
|
||||||
|
{
|
||||||
|
psyc_setTextBuffer(state, psyc_newString(buffer, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
psycTextRC psyc_text (psycTextState *state, psycTextCB getValue)
|
||||||
|
{
|
||||||
|
char *start = state->template.ptr, *end; // start & end of variable name
|
||||||
|
char *prev = state->template.ptr + state->cursor;
|
||||||
|
psycString value;
|
||||||
|
int ret;
|
||||||
|
size_t len;
|
||||||
|
uint8_t no_subst = (state->cursor == 0); // whether we can return NO_SUBST
|
||||||
|
|
||||||
|
while (state->cursor < state->template.length)
|
||||||
|
{
|
||||||
|
start = memmem(state->template.ptr + state->cursor,
|
||||||
|
state->template.length - state->cursor,
|
||||||
|
state->open.ptr, state->open.length);
|
||||||
|
if (!start)
|
||||||
|
break;
|
||||||
|
|
||||||
|
state->cursor = (start - state->template.ptr) + state->open.length;
|
||||||
|
if (state->cursor >= state->template.length)
|
||||||
|
break; // [ at the end
|
||||||
|
|
||||||
|
end = memmem(state->template.ptr + state->cursor,
|
||||||
|
state->template.length - state->cursor,
|
||||||
|
state->close.ptr, state->close.length);
|
||||||
|
state->cursor = (end - state->template.ptr) + state->close.length;
|
||||||
|
|
||||||
|
if (!end)
|
||||||
|
break; // ] not found
|
||||||
|
if (start + state->open.length == end)
|
||||||
|
{
|
||||||
|
state->cursor += state->close.length;
|
||||||
|
continue; // [] is invalid, name can't be empty
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = getValue(start + state->open.length, end - start - state->open.length, &value);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
continue; // value not found, no substitution
|
||||||
|
|
||||||
|
// first copy the part in the template from the previous subst. to the current one
|
||||||
|
// if there's enough buffer space for that
|
||||||
|
len = start - prev;
|
||||||
|
if (state->written + len > state->buffer.length)
|
||||||
|
{
|
||||||
|
state->cursor = prev - state->template.ptr;
|
||||||
|
return PSYC_TEXT_INCOMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((void *)(state->buffer.ptr + state->written), prev, len);
|
||||||
|
state->written += len;
|
||||||
|
|
||||||
|
// now substitute the value if there's enough buffer space
|
||||||
|
if (state->written + value.length > state->buffer.length)
|
||||||
|
{
|
||||||
|
state->cursor = start - state->template.ptr;
|
||||||
|
return PSYC_TEXT_INCOMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((void *)(state->buffer.ptr + state->written), value.ptr, value.length);
|
||||||
|
state->written += value.length;
|
||||||
|
|
||||||
|
// mark the start of the next chunk of text in the template
|
||||||
|
prev = state->template.ptr + state->cursor;
|
||||||
|
no_subst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_subst)
|
||||||
|
return PSYC_TEXT_NO_SUBST;
|
||||||
|
|
||||||
|
// copy the rest of the template after the last var
|
||||||
|
len = state->template.length - (prev - state->template.ptr);
|
||||||
|
if (state->written + len > state->buffer.length)
|
||||||
|
return PSYC_TEXT_INCOMPLETE;
|
||||||
|
|
||||||
|
memcpy((void *)(state->buffer.ptr + state->written), prev, len);
|
||||||
|
state->written += len;
|
||||||
|
|
||||||
|
return PSYC_TEXT_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ DEBUG = 2
|
||||||
CFLAGS = -I../include -Wall ${OPT}
|
CFLAGS = -I../include -Wall ${OPT}
|
||||||
LDFLAGS = -L../lib
|
LDFLAGS = -L../lib
|
||||||
LOADLIBES = -lpsyc -lm
|
LOADLIBES = -lpsyc -lm
|
||||||
TARGETS = testServer testParser testMatch testRender isRoutingVar getVarType
|
TARGETS = testServer testParser testMatch testRender testText isRoutingVar getVarType
|
||||||
WRAPPER =
|
WRAPPER =
|
||||||
DIET = diet
|
DIET = diet
|
||||||
PORT = 4440
|
PORT = 4440
|
||||||
|
|
90
test/testText.c
Normal file
90
test/testText.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include <psyc/lib.h>
|
||||||
|
#include <psyc/text.h>
|
||||||
|
|
||||||
|
#define BUFSIZE 512
|
||||||
|
|
||||||
|
uint8_t verbose;
|
||||||
|
|
||||||
|
psycTextValueRC getValueFooBar (char *name, size_t len, psycString *value)
|
||||||
|
{
|
||||||
|
value->ptr = "Foo Bar";
|
||||||
|
value->length = 7;
|
||||||
|
return PSYC_TEXT_VALUE_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
psycTextValueRC getValueEmpty (char *name, size_t len, psycString *value)
|
||||||
|
{
|
||||||
|
value->ptr = "";
|
||||||
|
value->length = 0;
|
||||||
|
return PSYC_TEXT_VALUE_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
psycTextValueRC getValueNotFound (char *name, size_t len, psycString *value)
|
||||||
|
{
|
||||||
|
return PSYC_TEXT_VALUE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int testText (char *template, size_t tmplen, char *buffer, size_t buflen, psycString *result, psycTextCB getValue)
|
||||||
|
{
|
||||||
|
psycTextState state;
|
||||||
|
size_t length = 0;
|
||||||
|
psycTextRC ret;
|
||||||
|
|
||||||
|
psyc_initTextState(&state, template, tmplen, buffer, buflen);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = psyc_text(&state, getValue);
|
||||||
|
length += state.written;
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case PSYC_TEXT_INCOMPLETE:
|
||||||
|
if (verbose)
|
||||||
|
printf("# %.*s...\n", (int)length, buffer);
|
||||||
|
psyc_setTextBuffer2(&state, buffer + length, BUFSIZE - length);
|
||||||
|
break;
|
||||||
|
case PSYC_TEXT_COMPLETE:
|
||||||
|
if (verbose)
|
||||||
|
printf("%.*s\n", (int)length, buffer);
|
||||||
|
result->length = length;
|
||||||
|
result->ptr = buffer;
|
||||||
|
return ret;
|
||||||
|
case PSYC_TEXT_NO_SUBST:
|
||||||
|
if (verbose)
|
||||||
|
printf("%.*s\n", (int)tmplen, template);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ret == PSYC_TEXT_INCOMPLETE);
|
||||||
|
|
||||||
|
return -2; // shouldn't be reached
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
verbose = argc > 1;
|
||||||
|
char buffer[BUFSIZE];
|
||||||
|
psycString result;
|
||||||
|
|
||||||
|
char *str = "Hello [_foo] & [_bar]!";
|
||||||
|
size_t len = strlen(str);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
testText(str, len, buffer, BUFSIZE, &result, &getValueFooBar);
|
||||||
|
if (memcmp(result.ptr, PSYC_C2ARG("Hello Foo Bar & Foo Bar!")))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
testText(str, len, buffer, BUFSIZE, &result, &getValueEmpty);
|
||||||
|
if (memcmp(result.ptr, PSYC_C2ARG("Hello & !")))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (testText(str, len, buffer, BUFSIZE, &result, &getValueNotFound) != PSYC_TEXT_NO_SUBST)
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
for (i = 1; i < 22; i++)
|
||||||
|
{
|
||||||
|
testText(str, len, buffer, i, &result, &getValueFooBar);
|
||||||
|
if (memcmp(result.ptr, PSYC_C2ARG("Hello Foo Bar & Foo Bar!")))
|
||||||
|
return 10 + i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue