Rename several data structures
This commit is contained in:
parent
bb0b5a1bcc
commit
e69a1ceaa1
4 changed files with 259 additions and 257 deletions
192
gemtext-parser.c
192
gemtext-parser.c
|
@ -42,8 +42,10 @@ gemtextParser* gemtextParserNew(FILE *stream) {
|
|||
void gemtextParserDeinit(gemtextParser *parser) {
|
||||
fclose(parser->stream);
|
||||
free(parser->buffer.buf);
|
||||
if (parser->linkUrl != NULL) {
|
||||
if (parser->mode == linkMode && parser->linkUrl != NULL) {
|
||||
free(parser->linkUrl);
|
||||
} else if (parser->mode == preformattedMode && parser->altText != NULL) {
|
||||
free(parser->altText);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +54,7 @@ void gemtextParserDestroy(gemtextParser *parser) {
|
|||
free(parser);
|
||||
}
|
||||
|
||||
int gemtextLineQueueInit(gemtextLineQueue *queue) {
|
||||
int gemtextNodeQueueInit(gemtextNodeQueue *queue) {
|
||||
int ret;
|
||||
|
||||
queue->head = NULL;
|
||||
|
@ -63,82 +65,82 @@ int gemtextLineQueueInit(gemtextLineQueue *queue) {
|
|||
return pthread_cond_init(&queue->cond, NULL);
|
||||
}
|
||||
|
||||
void gemtextLineQueuePush(gemtextLineQueue *queue, gemtextLine *line) {
|
||||
void gemtextNodeQueuePush(gemtextNodeQueue *queue, gemtextNode *node) {
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
if (queue->tail == NULL) {
|
||||
queue->tail = queue->head = line;
|
||||
queue->tail = queue->head = node;
|
||||
} else {
|
||||
line->next = queue->tail;
|
||||
queue->tail->prev = line;
|
||||
queue->tail = line;
|
||||
node->next = queue->tail;
|
||||
queue->tail->prev = node;
|
||||
queue->tail = node;
|
||||
}
|
||||
queue->count++;
|
||||
pthread_mutex_unlock(&queue->mutex);
|
||||
}
|
||||
|
||||
gemtextLine* gemtextLineQueuePop(gemtextLineQueue *lq) {
|
||||
gemtextLine *line;
|
||||
gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *lq) {
|
||||
gemtextNode *node;
|
||||
|
||||
while (lq->count == 0)
|
||||
pthread_cond_wait(&lq->cond, &lq->mutex);
|
||||
pthread_mutex_lock(&lq->mutex);
|
||||
lq->count++;
|
||||
line = lq->head;
|
||||
if (line->lineType == endOfStream)
|
||||
return line;
|
||||
node = lq->head;
|
||||
if (node->nodeType == endOfStream)
|
||||
return node;
|
||||
if (lq->tail == lq->head) {
|
||||
lq->tail = lq->head = NULL;
|
||||
} else {
|
||||
lq->head = lq->head->prev;
|
||||
}
|
||||
pthread_mutex_unlock(&lq->mutex);
|
||||
line->prev = line->next = NULL;
|
||||
return line;
|
||||
node->prev = node->next = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
gemtextLine* gemtextLineQueueTryPop(gemtextLineQueue *lq) {
|
||||
gemtextLine *line;
|
||||
gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *lq) {
|
||||
gemtextNode *node;
|
||||
|
||||
if (lq->count == 0)
|
||||
return NULL;
|
||||
pthread_mutex_lock(&lq->mutex);
|
||||
lq->count++;
|
||||
line = lq->head;
|
||||
if (line->lineType == endOfStream)
|
||||
return line;
|
||||
node = lq->head;
|
||||
if (node->nodeType == endOfStream)
|
||||
return node;
|
||||
if (lq->tail == lq->head) {
|
||||
lq->tail = lq->head = NULL;
|
||||
} else {
|
||||
lq->head = lq->head->prev;
|
||||
}
|
||||
pthread_mutex_unlock(&lq->mutex);
|
||||
line->prev = line->next = NULL;
|
||||
return line;
|
||||
node->prev = node->next = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
void gemtextLineDeinit(gemtextLine *line) {
|
||||
switch (line->lineType) {
|
||||
case linkLine:
|
||||
if (line->link->display != NULL) {
|
||||
free(line->link->display);
|
||||
void gemtextNodeDeinit(gemtextNode *node) {
|
||||
switch (node->nodeType) {
|
||||
case linkNode:
|
||||
if (node->link->display != NULL) {
|
||||
free(node->link->display);
|
||||
}
|
||||
free(line->link->url);
|
||||
free(line->link);
|
||||
free(node->link->url);
|
||||
free(node->link);
|
||||
break;
|
||||
case preformattedLine:
|
||||
if (line->node->altText != NULL) {
|
||||
free(line->node->altText);
|
||||
case preformattedNode:
|
||||
if (node->block->altText != NULL) {
|
||||
free(node->block->altText);
|
||||
}
|
||||
free(line->node->body);
|
||||
free(line->node);
|
||||
free(node->block->body);
|
||||
free(node->block);
|
||||
break;
|
||||
case endOfStream:
|
||||
break;
|
||||
default:
|
||||
free(line->str);
|
||||
free(node->str);
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
free(node);
|
||||
}
|
||||
|
||||
int lineBufferExtend(lineBuffer *lb, size_t len) {
|
||||
|
@ -201,43 +203,43 @@ void lineBufferReset(lineBuffer *lb) {
|
|||
lb->cursor = lb->buf;
|
||||
}
|
||||
|
||||
int gemtextParserSendPreformatted(gemtextParser *parser, gemtextLineQueue *lq) {
|
||||
preformattedNode *node;
|
||||
gemtextLine *line;
|
||||
char *buf;
|
||||
int gemtextParserSendPreformatted(gemtextParser *parser, gemtextNodeQueue *lq) {
|
||||
preformattedBlock *block;
|
||||
gemtextNode *node;
|
||||
char *buf;
|
||||
|
||||
line = calloc(1, sizeof(gemtextLine));
|
||||
if (line == NULL) return errno;
|
||||
line->lineType = preformattedLine;
|
||||
node = calloc(1, sizeof(preformattedNode));
|
||||
node = calloc(1, sizeof(gemtextNode));
|
||||
if (node == NULL) return errno;
|
||||
node->nodeType = preformattedNode;
|
||||
block = calloc(1, sizeof(preformattedBlock));
|
||||
if (block == NULL) return errno;
|
||||
// back up our cursor four spaces and insert a lf char
|
||||
parser->buffer.cursor -= 4;
|
||||
parser->buffer.len -= 4;
|
||||
lineBufferAppendCharUnchecked(&parser->buffer, '\n');
|
||||
buf = strndup(parser->buffer.buf, parser->buffer.len);
|
||||
if (buf == NULL) return errno;
|
||||
node->altText = parser->altText;
|
||||
block->altText = parser->altText;
|
||||
parser->altText = NULL;
|
||||
node->body = buf;
|
||||
line->node = node;
|
||||
gemtextLineQueuePush(lq, line);
|
||||
block->body = buf;
|
||||
node->block = block;
|
||||
gemtextNodeQueuePush(lq, node);
|
||||
lineBufferReset(&parser->buffer);
|
||||
parser->state = lineStart;
|
||||
parser->mode = normalMode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gemtextParserSendLink(gemtextParser *parser, gemtextLineQueue *lq) {
|
||||
int gemtextParserSendLink(gemtextParser *parser, gemtextNodeQueue *lq) {
|
||||
gemtextLink *link;
|
||||
gemtextLine *line;
|
||||
gemtextNode *node;
|
||||
char *url = NULL, *display = NULL;
|
||||
|
||||
link = calloc(1, sizeof(gemtextLink));
|
||||
if (link == NULL) return errno;
|
||||
link->display = link->url = NULL;
|
||||
line = calloc(1, sizeof(gemtextLine));
|
||||
if (line == NULL) {
|
||||
node = calloc(1, sizeof(gemtextNode));
|
||||
if (node == NULL) {
|
||||
free(link);
|
||||
return errno;
|
||||
}
|
||||
|
@ -248,15 +250,15 @@ int gemtextParserSendLink(gemtextParser *parser, gemtextLineQueue *lq) {
|
|||
display = strndup(parser->buffer.buf, parser->buffer.len);
|
||||
if (display == NULL) {
|
||||
free(link);
|
||||
free(line);
|
||||
free(node);
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
link->url = url;
|
||||
link->display = display;
|
||||
line->lineType = linkLine;
|
||||
line->link = link;
|
||||
gemtextLineQueuePush(lq, line);
|
||||
node->nodeType = linkNode;
|
||||
node->link = link;
|
||||
gemtextNodeQueuePush(lq, node);
|
||||
lineBufferReset(&parser->buffer);
|
||||
parser->state = lineStart;
|
||||
parser->mode = normalMode;
|
||||
|
@ -264,17 +266,17 @@ int gemtextParserSendLink(gemtextParser *parser, gemtextLineQueue *lq) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gemtextParserSend(gemtextParser *parser, gemtextLineType lt, gemtextLineQueue *lq) {
|
||||
gemtextLine *line;
|
||||
int gemtextParserSend(gemtextParser *parser, gemtextNodeType lt, gemtextNodeQueue *lq) {
|
||||
gemtextNode *node;
|
||||
char *buf;
|
||||
|
||||
line = calloc(1, sizeof(gemtextLine));
|
||||
if (line == NULL) return errno;
|
||||
line->lineType = lt;
|
||||
node = calloc(1, sizeof(gemtextNode));
|
||||
if (node == NULL) return errno;
|
||||
node->nodeType = lt;
|
||||
buf = strndup(parser->buffer.buf, parser->buffer.len);
|
||||
if (buf == NULL) return errno;
|
||||
line->str = buf;
|
||||
gemtextLineQueuePush(lq, line);
|
||||
node->str = buf;
|
||||
gemtextNodeQueuePush(lq, node);
|
||||
lineBufferReset(&parser->buffer);
|
||||
parser->state = lineStart;
|
||||
parser->mode = normalMode;
|
||||
|
@ -306,7 +308,7 @@ void enterPreformattedMode(gemtextParser *parser) {
|
|||
lineBufferReset(&parser->buffer);
|
||||
}
|
||||
|
||||
int parseLink(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
||||
int parseLink(gemtextParser *parser, gemtextNodeQueue *lq, char c) {
|
||||
int ret = 0;
|
||||
char *buf = NULL;
|
||||
|
||||
|
@ -318,7 +320,7 @@ int parseLink(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
lineBufferAppendCharUnchecked(&parser->buffer, c);
|
||||
parser->state = normalState;
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
}
|
||||
break;
|
||||
case normalState:
|
||||
|
@ -355,7 +357,7 @@ int parseLink(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int parsePreformatted(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
||||
int parsePreformatted(gemtextParser *parser, gemtextNodeQueue *lq, char c) {
|
||||
char *buf = NULL;
|
||||
|
||||
assert(parser->mode == preformattedMode);
|
||||
|
@ -425,7 +427,7 @@ int parsePreformatted(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parseQuote(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
||||
int parseQuote(gemtextParser *parser, gemtextNodeQueue *lq, char c) {
|
||||
int ret = 0;
|
||||
|
||||
switch (parser->state) {
|
||||
|
@ -435,7 +437,7 @@ int parseQuote(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
lineBufferRewind(&parser->buffer);
|
||||
} else {
|
||||
lineBufferRewind(&parser->buffer);
|
||||
ret = gemtextParserSend(parser, quoteLine, lq);
|
||||
ret = gemtextParserSend(parser, quoteNode, lq);
|
||||
if (ret) return ret;
|
||||
ret = fseek(parser->stream, -1, SEEK_CUR);
|
||||
if (ret) return ret;
|
||||
|
@ -454,7 +456,7 @@ int parseQuote(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
parser->buffer.len--;
|
||||
parser->buffer.cursor--;
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
} else {
|
||||
parser->state = normalState;
|
||||
}
|
||||
|
@ -467,7 +469,7 @@ int parseQuote(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int parseGeneric(gemtextParser *parser, gemtextLineQueue *lq, gemtextLineType lt, char c) {
|
||||
int parseGeneric(gemtextParser *parser, gemtextNodeQueue *lq, gemtextNodeType lt, char c) {
|
||||
int ret = 0;
|
||||
|
||||
switch (parser->state) {
|
||||
|
@ -496,7 +498,7 @@ int parseGeneric(gemtextParser *parser, gemtextLineQueue *lq, gemtextLineType lt
|
|||
return ret;
|
||||
}
|
||||
|
||||
int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
||||
int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) {
|
||||
int ret;
|
||||
|
||||
switch (parser->state) {
|
||||
|
@ -522,7 +524,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
parser->state = firstBacktickChar;
|
||||
break;
|
||||
case '\n':
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
break;
|
||||
default:
|
||||
|
@ -534,7 +536,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
parser->mode = linkMode;
|
||||
parser->state = lineStart;
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else {
|
||||
parser->state = normalState;
|
||||
|
@ -544,7 +546,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
if (c == '#') {
|
||||
parser->state = secondHashChar;
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else {
|
||||
switchMode(parser, h1Mode, c);
|
||||
|
@ -556,7 +558,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
parser->state = trimStart;
|
||||
lineBufferReset(&parser->buffer);
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else {
|
||||
switchMode(parser, h2Mode, c);
|
||||
|
@ -564,7 +566,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
break;
|
||||
case thirdHashChar:
|
||||
if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else {
|
||||
switchMode(parser, h3Mode, c);
|
||||
|
@ -572,7 +574,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
break;
|
||||
case firstBacktickChar:
|
||||
if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else if (c == '`') {
|
||||
parser->state = secondBacktickChar;
|
||||
|
@ -585,7 +587,7 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
if (c == '`') {
|
||||
enterPreformattedMode(parser);
|
||||
} else if (c == '\n') {
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
if (ret) return ret;
|
||||
} else {
|
||||
parser->state = normalState;
|
||||
|
@ -598,10 +600,10 @@ int parseNormal(gemtextParser *parser, gemtextLineQueue *lq, char c) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq) {
|
||||
int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq) {
|
||||
char c;
|
||||
int ret;
|
||||
gemtextLine *line;
|
||||
gemtextNode *node;
|
||||
|
||||
for (;;) {
|
||||
ret = fread(&c, 1, 1, parser->stream);
|
||||
|
@ -615,38 +617,38 @@ int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq) {
|
|||
if (parser->state != lineStart && parser->state != trimStart) {
|
||||
switch (parser->mode) {
|
||||
case normalMode:
|
||||
ret = gemtextParserSend(parser, normalLine, lq);
|
||||
ret = gemtextParserSend(parser, normalNode, lq);
|
||||
break;
|
||||
case preformattedMode:
|
||||
ret = gemtextParserSendPreformatted(parser, lq);
|
||||
break;
|
||||
case quoteMode:
|
||||
ret = gemtextParserSend(parser, quoteLine, lq);
|
||||
ret = gemtextParserSend(parser, quoteNode, lq);
|
||||
break;
|
||||
case linkMode:
|
||||
ret = gemtextParserSendLink(parser, lq);
|
||||
break;
|
||||
case h1Mode:
|
||||
ret = gemtextParserSend(parser, h1Line, lq);
|
||||
ret = gemtextParserSend(parser, h1Node, lq);
|
||||
break;
|
||||
case h2Mode:
|
||||
ret = gemtextParserSend(parser, h2Line, lq);
|
||||
ret = gemtextParserSend(parser, h2Node, lq);
|
||||
break;
|
||||
case h3Mode:
|
||||
ret = gemtextParserSend(parser, h3Line, lq);
|
||||
ret = gemtextParserSend(parser, h3Node, lq);
|
||||
break;
|
||||
case listMode:
|
||||
ret = gemtextParserSend(parser, listLine, lq);
|
||||
ret = gemtextParserSend(parser, listNode, lq);
|
||||
break;
|
||||
}
|
||||
if (ret) return ret;
|
||||
}
|
||||
line = calloc(1, sizeof(gemtextLine));
|
||||
if (line == NULL) return errno;
|
||||
line->lineType = endOfStream;
|
||||
line->prev = line->next = NULL;
|
||||
line->str = NULL;
|
||||
gemtextLineQueuePush(lq, line);
|
||||
node = calloc(1, sizeof(gemtextNode));
|
||||
if (node == NULL) return errno;
|
||||
node->nodeType = endOfStream;
|
||||
node->prev = node->next = NULL;
|
||||
node->str = NULL;
|
||||
gemtextNodeQueuePush(lq, node);
|
||||
break;
|
||||
}
|
||||
switch (parser->mode) {
|
||||
|
@ -663,16 +665,16 @@ int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq) {
|
|||
ret = parseLink(parser, lq, c);
|
||||
break;
|
||||
case h1Mode:
|
||||
ret = parseGeneric(parser, lq, h1Line, c);
|
||||
ret = parseGeneric(parser, lq, h1Node, c);
|
||||
break;
|
||||
case h2Mode:
|
||||
ret = parseGeneric(parser, lq, h2Line, c);
|
||||
ret = parseGeneric(parser, lq, h2Node, c);
|
||||
break;
|
||||
case h3Mode:
|
||||
ret = parseGeneric(parser, lq, h3Line, c);
|
||||
ret = parseGeneric(parser, lq, h3Node, c);
|
||||
break;
|
||||
case listMode:
|
||||
ret = parseGeneric(parser, lq, listLine, c);
|
||||
ret = parseGeneric(parser, lq, listNode, c);
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
|
|
|
@ -47,17 +47,17 @@ typedef enum {
|
|||
* An enum type representing the various line types in gemtext markup
|
||||
*/
|
||||
typedef enum {
|
||||
normalLine = 0, ///< A normal text line
|
||||
linkLine = 1, ///< A link line
|
||||
listLine = 2, ///< A list member
|
||||
h1Line = 3, ///< An H1 heading
|
||||
h2Line = 4, ///< An H2 heading
|
||||
h3Line = 5, ///< An H3 heading
|
||||
preformattedLine = 6, ///< A preformatted text block
|
||||
quoteLine = 7, ///< A Quote block
|
||||
normalNode = 0, ///< A normal text line
|
||||
linkNode = 1, ///< A link line
|
||||
listNode = 2, ///< A list member
|
||||
h1Node = 3, ///< An H1 heading
|
||||
h2Node = 4, ///< An H2 heading
|
||||
h3Node = 5, ///< An H3 heading
|
||||
preformattedNode = 6, ///< A preformatted text block
|
||||
quoteNode = 7, ///< A Quote block
|
||||
endOfStream = 8, /**< Notifies the receiver that the stream is over and no
|
||||
more lines are to be expected */
|
||||
} gemtextLineType;
|
||||
} gemtextNodeType;
|
||||
|
||||
/**
|
||||
* A growable byte array
|
||||
|
@ -84,7 +84,7 @@ typedef struct {
|
|||
char *altText; /**< Some descriptive text to be read by screen readers if
|
||||
this is ascii art */
|
||||
char *body; ///< The body of the preformatted block
|
||||
} preformattedNode;
|
||||
} preformattedBlock;
|
||||
|
||||
/**
|
||||
* The main Gemtext parser
|
||||
|
@ -101,19 +101,19 @@ typedef struct {
|
|||
};
|
||||
} gemtextParser;
|
||||
|
||||
struct _gemtextLine {
|
||||
struct _gemtextLine *next; ///< The next line in the queue
|
||||
struct _gemtextLine *prev; ///< The previous line in the queue
|
||||
gemtextLineType lineType; ///< Identifies the type of line
|
||||
struct _gemtextNode {
|
||||
struct _gemtextNode *next; ///< The next line in the queue
|
||||
struct _gemtextNode *prev; ///< The previous line in the queue
|
||||
gemtextNodeType nodeType; ///< Identifies the type of line
|
||||
union {
|
||||
char *str; ///< The text body of most line types
|
||||
gemtextLink *link; ///< The body of a link line
|
||||
preformattedNode *node; ///< The body and alt text of a preformatted block
|
||||
char *str; ///< The text body of most line types
|
||||
gemtextLink *link; ///< The body of a link line
|
||||
preformattedBlock *block; ///< The body and alt text of a preformatted block
|
||||
};
|
||||
};
|
||||
|
||||
/** A Gemtext node */
|
||||
typedef struct _gemtextLine gemtextLine;
|
||||
typedef struct _gemtextNode gemtextNode;
|
||||
|
||||
/**
|
||||
* A fifo queue used to pass gemtextLine elements from the worker thread to the
|
||||
|
@ -123,9 +123,9 @@ typedef struct {
|
|||
pthread_cond_t cond; ///< Signals the rendering thread to wait for an incoming line
|
||||
size_t count; ///< The number of elements currently in the queue
|
||||
pthread_mutex_t mutex; ///< The lock ensuring exclusive access
|
||||
gemtextLine *head; ///< The oldest line in the queue
|
||||
gemtextLine *tail; ///< The newest line in the queue
|
||||
} gemtextLineQueue;
|
||||
gemtextNode *head; ///< The oldest line in the queue
|
||||
gemtextNode *tail; ///< The newest line in the queue
|
||||
} gemtextNodeQueue;
|
||||
|
||||
/**
|
||||
* Initialize a lineBuffer struct to it's default values.
|
||||
|
@ -166,13 +166,13 @@ void gemtextParserDeinit(gemtextParser *parser);
|
|||
void gemtextParserDestroy(gemtextParser *parser);
|
||||
|
||||
/**
|
||||
* Initializes a gemtextLineQueue with default values.
|
||||
* Initializes a gemtextNodeQueue with default values.
|
||||
* ### Return values
|
||||
* Returns 0 on success. If there is a failure initializing the internal
|
||||
* mutex or condition variable, an error code is returned instead.
|
||||
* \param queue The already allocated gemtextLineQueue
|
||||
* \param queue The already allocated gemtextNodeQueue
|
||||
*/
|
||||
int gemtextLineQueueInit(gemtextLineQueue *queue);
|
||||
int gemtextNodeQueueInit(gemtextNodeQueue *queue);
|
||||
|
||||
/**
|
||||
* Pushes a gemtextLine into the queue. This function will not fail, but
|
||||
|
@ -180,27 +180,27 @@ int gemtextLineQueueInit(gemtextLineQueue *queue);
|
|||
* \param queue The queue which will receive the gemtext line
|
||||
* \param line The gemtextLine to be queued
|
||||
*/
|
||||
void gemtextLineQueuePush(gemtextLineQueue *queue, gemtextLine *line);
|
||||
void gemtextNodeQueuePush(gemtextNodeQueue *queue, gemtextNode *node);
|
||||
|
||||
/**
|
||||
* Gets the oldest line inserted in the queue. This function will either
|
||||
* return a valid gemtextLine or block until one becomes available.
|
||||
* \param lq The queue from which we are attempting to pop a line
|
||||
*/
|
||||
gemtextLine* gemtextLineQueuePop(gemtextLineQueue *lq);
|
||||
gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *lq);
|
||||
|
||||
/**
|
||||
* Attempts to get the oldest line inserted in the queue. If there are no lines
|
||||
* left in the queue, returns NULL.
|
||||
* \param lq The queue from which we are attempting to pop a line
|
||||
*/
|
||||
gemtextLine* gemtextLineQueueTryPop(gemtextLineQueue *lq);
|
||||
gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *lq);
|
||||
|
||||
/**
|
||||
* Frees all memory associated with a gemtextLine structure
|
||||
* \param lq The gemtextLine to be de-allocated
|
||||
*/
|
||||
void gemtextLineDeinit(gemtextLine *line);
|
||||
void gemtextNodeDeinit(gemtextNode *node);
|
||||
|
||||
/**
|
||||
* Extends the LineBuffer lb by len bytes.
|
||||
|
@ -254,12 +254,12 @@ void lineBufferRewind(lineBuffer *lb);
|
|||
void lineBufferReset(lineBuffer *lb);
|
||||
|
||||
/**
|
||||
* Parses gemtext into a series of nodes to be places in the gemtextLineQueue lq.
|
||||
* Parses gemtext into a series of nodes to be places in the gemtextNodeQueue lq.
|
||||
* ### Return values
|
||||
* Returns 0 on success, any other number is an error code
|
||||
* \param parser A gemtextParser struct used to maintain state while parsing
|
||||
* \param lq A gemtextLineQueue which will receive gemtextLine elements as they are parsed
|
||||
* \param lq A gemtextNodeQueue which will receive gemtextLine elements as they are parsed
|
||||
*/
|
||||
int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq);
|
||||
int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,98 +4,98 @@
|
|||
#include <string.h>
|
||||
#include "gemtext-parser.h"
|
||||
|
||||
gemtextLineQueue lq;
|
||||
gemtextNodeQueue lq;
|
||||
gemtextParser parser;
|
||||
|
||||
int main() {
|
||||
int ret = 0;
|
||||
FILE *stream = NULL;
|
||||
gemtextLine *line = NULL;
|
||||
gemtextNode *node = NULL;
|
||||
|
||||
stream = fopen("test0.gmi", "r");
|
||||
assert(stream != NULL);
|
||||
ret = gemtextLineQueueInit(&lq);
|
||||
ret = gemtextNodeQueueInit(&lq);
|
||||
assert(ret == 0);
|
||||
ret = gemtextParserInit(&parser, stream);
|
||||
assert(ret == 0);
|
||||
ret = parseGemtext(&parser, &lq);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType = h1Line);
|
||||
assert(memcmp(line->str, "A Test Gemtext file", 19) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == h1Node);
|
||||
assert(memcmp(node->str, "A Test Gemtext file", 19) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType = h2Line);
|
||||
assert(memcmp(line->str, "Used for testing the parser in normal operation", 47) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == h2Node);
|
||||
assert(memcmp(node->str, "Used for testing the parser in normal operation", 47) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(*line->str == '\n');
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(*node->str == '\n');
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "This is", 7) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "This is", 7) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(*line->str == '\n');
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(*node->str == '\n');
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == quoteLine);
|
||||
assert(memcmp(line->str, "Walk before you run.\n- Anonymous", 32) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == quoteNode);
|
||||
assert(memcmp(node->str, "Walk before you run.\n- Anonymous", 32) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(*line->str == '\n');
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(*node->str == '\n');
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == h3Line);
|
||||
assert(memcmp(line->str, "Let's check a list", 18) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == h3Node);
|
||||
assert(memcmp(node->str, "Let's check a list", 18) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == listLine);
|
||||
assert(memcmp(line->str, "First item", 9) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == listNode);
|
||||
assert(memcmp(node->str, "First item", 9) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == listLine);
|
||||
assert(memcmp(line->str, "second item", 11) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == listNode);
|
||||
assert(memcmp(node->str, "second item", 11) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(*line->str == '\n');
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(*node->str == '\n');
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == linkLine);
|
||||
assert(memcmp(line->link->url, "gemini://example.org/test.gmi", 29) == 0);
|
||||
assert(memcmp(line->link->display, "This is a link", 14) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == linkNode);
|
||||
assert(memcmp(node->link->url, "gemini://example.org/test.gmi", 29) == 0);
|
||||
assert(memcmp(node->link->display, "This is a link", 14) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(*line->str == '\n');
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(*node->str == '\n');
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == preformattedLine);
|
||||
assert(memcmp(line->node->altText, "Test preformatted block", 23) == 0);
|
||||
assert(memcmp(line->node->body, "This is a preformatted block", 28) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == preformattedNode);
|
||||
assert(memcmp(node->block->altText, "Test preformatted block", 23) == 0);
|
||||
assert(memcmp(node->block->body, "This is a preformatted block", 28) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line != NULL);
|
||||
assert(line->lineType == endOfStream);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node != NULL);
|
||||
assert(node->nodeType == endOfStream);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
gemtextParserDeinit(&parser);
|
||||
return ret;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <string.h>
|
||||
#include "gemtext-parser.h"
|
||||
|
||||
gemtextLineQueue lq;
|
||||
gemtextNodeQueue lq;
|
||||
gemtextParser parser;
|
||||
|
||||
char * preBlk =
|
||||
|
@ -14,93 +14,93 @@ char * preBlk =
|
|||
int main() {
|
||||
int ret = 0;
|
||||
FILE *stream = NULL;
|
||||
gemtextLine *line = NULL;
|
||||
gemtextNode *node = NULL;
|
||||
|
||||
stream = fopen("test1.gmi", "r");
|
||||
assert(stream != NULL);
|
||||
ret = gemtextLineQueueInit(&lq);
|
||||
ret = gemtextNodeQueueInit(&lq);
|
||||
assert(ret == 0);
|
||||
ret = gemtextParserInit(&parser, stream);
|
||||
assert(ret == 0);
|
||||
ret = parseGemtext(&parser, &lq);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType = h1Line);
|
||||
assert(memcmp(line->str, "A more complicated example", 26) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType = h2Node);
|
||||
assert(memcmp(node->str, "A more complicated example", 26) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == listLine);
|
||||
assert(memcmp(line->str, "list item with no leading space", 30) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == listNode);
|
||||
assert(memcmp(node->str, "list item with no leading space", 30) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == listLine);
|
||||
assert(memcmp(line->str, "list item with several leading spaces", 37) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == listNode);
|
||||
assert(memcmp(node->str, "list item with several leading spaces", 37) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == h2Line);
|
||||
assert(memcmp(line->str, "After this H2, an empty quote", 29) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == h2Node);
|
||||
assert(memcmp(node->str, "After this H2, an empty quote", 29) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "\n", 1) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "\n", 1) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == h3Line);
|
||||
assert(memcmp(line->str, "Now we'll", 9) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == h3Node);
|
||||
assert(memcmp(node->str, "Now we'll", 9) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "``", 2) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "``", 2) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "=", 1) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "=", 1) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "And maybe", 9) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "And maybe", 9) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == linkLine);
|
||||
assert(memcmp(line->link->url, "spartan://example.org", 21) == 0);
|
||||
assert(line->link->display == NULL);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == linkNode);
|
||||
assert(memcmp(node->link->url, "spartan://example.org", 21) == 0);
|
||||
assert(node->link->display == NULL);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "Let's enter", 11) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "Let's enter", 11) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == preformattedLine);
|
||||
assert(line->node->altText == NULL);
|
||||
assert(memcmp(line->node->body, preBlk, 50) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == preformattedNode);
|
||||
assert(node->block->altText == NULL);
|
||||
assert(memcmp(node->block->body, preBlk, 50) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == normalLine);
|
||||
assert(memcmp(line->str, "And we'll finish", 16) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == normalNode);
|
||||
assert(memcmp(node->str, "And we'll finish", 16) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line->lineType == linkLine);
|
||||
assert(line->link->display == NULL);
|
||||
assert(memcmp(line->link->url, "finger://example.org/joe", 24) == 0);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node->nodeType == linkNode);
|
||||
assert(node->link->display == NULL);
|
||||
assert(memcmp(node->link->url, "finger://example.org/joe", 24) == 0);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
line = gemtextLineQueueTryPop(&lq);
|
||||
assert(line != NULL);
|
||||
assert(line->lineType == endOfStream);
|
||||
gemtextLineDeinit(line);
|
||||
node = gemtextNodeQueueTryPop(&lq);
|
||||
assert(node != NULL);
|
||||
assert(node->nodeType == endOfStream);
|
||||
gemtextNodeDeinit(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue