diff --git a/gemtext-parser.c b/gemtext-parser.c index 2b0224d..cc5518d 100644 --- a/gemtext-parser.c +++ b/gemtext-parser.c @@ -21,7 +21,7 @@ int gemtextParserInit(gemtextParser *parser, FILE *stream) { int ret = 0; parser->stream = stream; - parser->mode = normalMode; + parser->nodeType = unset; parser->state = lineStart; parser->linkUrl = NULL; ret = lineBufferInit(&parser->buffer); @@ -42,9 +42,9 @@ gemtextParser* gemtextParserNew(FILE *stream) { void gemtextParserDeinit(gemtextParser *parser) { fclose(parser->stream); free(parser->buffer.buf); - if (parser->mode == linkMode && parser->linkUrl != NULL) { + if (parser->nodeType == linkNode && parser->linkUrl != NULL) { free(parser->linkUrl); - } else if (parser->mode == preformattedMode && parser->altText != NULL) { + } else if (parser->nodeType == preformattedNode && parser->altText != NULL) { free(parser->altText); } } @@ -54,66 +54,66 @@ void gemtextParserDestroy(gemtextParser *parser) { free(parser); } -int gemtextNodeQueueInit(gemtextNodeQueue *queue) { +int gemtextNodeQueueInit(gemtextNodeQueue *nq) { int ret; - queue->head = NULL; - queue->tail = NULL; - ret = pthread_mutex_init(&queue->mutex, NULL); + nq->head = NULL; + nq->tail = NULL; + ret = pthread_mutex_init(&nq->mutex, NULL); if (ret != 0) return ret; - return pthread_cond_init(&queue->cond, NULL); + return pthread_cond_init(&nq->cond, NULL); } -void gemtextNodeQueuePush(gemtextNodeQueue *queue, gemtextNode *node) { - pthread_mutex_lock(&queue->mutex); - if (queue->tail == NULL) { - queue->tail = queue->head = node; +void gemtextNodeQueuePush(gemtextNodeQueue *nq, gemtextNode *node) { + pthread_mutex_lock(&nq->mutex); + if (nq->tail == NULL) { + nq->tail = nq->head = node; } else { - node->next = queue->tail; - queue->tail->prev = node; - queue->tail = node; + node->next = nq->tail; + nq->tail->prev = node; + nq->tail = node; } - queue->count++; - pthread_mutex_unlock(&queue->mutex); + nq->count++; + pthread_mutex_unlock(&nq->mutex); } -gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *lq) { +gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *nq) { gemtextNode *node; - while (lq->count == 0) - pthread_cond_wait(&lq->cond, &lq->mutex); - pthread_mutex_lock(&lq->mutex); - lq->count++; - node = lq->head; + while (nq->count == 0) + pthread_cond_wait(&nq->cond, &nq->mutex); + pthread_mutex_lock(&nq->mutex); + nq->count++; + node = nq->head; if (node->nodeType == endOfStream) return node; - if (lq->tail == lq->head) { - lq->tail = lq->head = NULL; + if (nq->tail == nq->head) { + nq->tail = nq->head = NULL; } else { - lq->head = lq->head->prev; + nq->head = nq->head->prev; } - pthread_mutex_unlock(&lq->mutex); + pthread_mutex_unlock(&nq->mutex); node->prev = node->next = NULL; return node; } -gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *lq) { +gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *nq) { gemtextNode *node; - if (lq->count == 0) + if (nq->count == 0) return NULL; - pthread_mutex_lock(&lq->mutex); - lq->count++; - node = lq->head; + pthread_mutex_lock(&nq->mutex); + nq->count++; + node = nq->head; if (node->nodeType == endOfStream) return node; - if (lq->tail == lq->head) { - lq->tail = lq->head = NULL; + if (nq->tail == nq->head) { + nq->tail = nq->head = NULL; } else { - lq->head = lq->head->prev; + nq->head = nq->head->prev; } - pthread_mutex_unlock(&lq->mutex); + pthread_mutex_unlock(&nq->mutex); node->prev = node->next = NULL; return node; } @@ -203,7 +203,7 @@ void lineBufferReset(lineBuffer *lb) { lb->cursor = lb->buf; } -int gemtextParserSendPreformatted(gemtextParser *parser, gemtextNodeQueue *lq) { +int gemtextParserSendPreformatted(gemtextParser *parser, gemtextNodeQueue *nq) { preformattedBlock *block; gemtextNode *node; char *buf; @@ -223,14 +223,14 @@ int gemtextParserSendPreformatted(gemtextParser *parser, gemtextNodeQueue *lq) { parser->altText = NULL; block->body = buf; node->block = block; - gemtextNodeQueuePush(lq, node); + gemtextNodeQueuePush(nq, node); lineBufferReset(&parser->buffer); parser->state = lineStart; - parser->mode = normalMode; + parser->nodeType = unset; return 0; } -int gemtextParserSendLink(gemtextParser *parser, gemtextNodeQueue *lq) { +int gemtextParserSendLink(gemtextParser *parser, gemtextNodeQueue *nq) { gemtextLink *link; gemtextNode *node; char *url = NULL, *display = NULL; @@ -258,28 +258,28 @@ int gemtextParserSendLink(gemtextParser *parser, gemtextNodeQueue *lq) { link->display = display; node->nodeType = linkNode; node->link = link; - gemtextNodeQueuePush(lq, node); + gemtextNodeQueuePush(nq, node); lineBufferReset(&parser->buffer); parser->state = lineStart; - parser->mode = normalMode; + parser->nodeType = unset; parser->linkUrl = NULL; return 0; } -int gemtextParserSend(gemtextParser *parser, gemtextNodeType lt, gemtextNodeQueue *lq) { +int gemtextParserSend(gemtextParser *parser, gemtextNodeQueue *nq) { gemtextNode *node; char *buf; node = calloc(1, sizeof(gemtextNode)); if (node == NULL) return errno; - node->nodeType = lt; + node->nodeType = parser->nodeType; buf = strndup(parser->buffer.buf, parser->buffer.len); if (buf == NULL) return errno; node->str = buf; - gemtextNodeQueuePush(lq, node); + gemtextNodeQueuePush(nq, node); lineBufferReset(&parser->buffer); parser->state = lineStart; - parser->mode = normalMode; + parser->nodeType = unset; return 0; } @@ -287,7 +287,7 @@ void logParseError(int err) { //todo } -void switchMode(gemtextParser *parser, gemtextParserMode mode, char c) { +void switchMode(gemtextParser *parser, gemtextNodeType node_type, char c) { lineBufferReset(&parser->buffer); switch (c) { case ' ': @@ -299,11 +299,11 @@ void switchMode(gemtextParser *parser, gemtextParserMode mode, char c) { lineBufferAppendCharUnchecked(&parser->buffer, c); parser->state = normalState; } - parser->mode = mode; + parser->nodeType = node_type; } void enterPreformattedMode(gemtextParser *parser) { - parser->mode = preformattedMode; + parser->nodeType = preformattedNode; parser->state = trimStart; lineBufferReset(&parser->buffer); } @@ -312,15 +312,15 @@ int parseLink(gemtextParser *parser, gemtextNodeQueue *lq, char c) { int ret = 0; char *buf = NULL; - assert(parser->mode == linkMode); + assert(parser->nodeType == linkNode); switch (parser->state) { - case lineStart: + case lineStart: if (c != ' ' && c != '\t') { lineBufferReset(&parser->buffer); lineBufferAppendCharUnchecked(&parser->buffer, c); parser->state = normalState; } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + ret = gemtextParserSend(parser, lq); } break; case normalState: @@ -360,7 +360,7 @@ int parseLink(gemtextParser *parser, gemtextNodeQueue *lq, char c) { int parsePreformatted(gemtextParser *parser, gemtextNodeQueue *lq, char c) { char *buf = NULL; - assert(parser->mode == preformattedMode); + assert(parser->nodeType == preformattedNode); switch (parser->state) { case trimStart: if (c == '\n') { @@ -437,12 +437,12 @@ int parseQuote(gemtextParser *parser, gemtextNodeQueue *lq, char c) { lineBufferRewind(&parser->buffer); } else { lineBufferRewind(&parser->buffer); - ret = gemtextParserSend(parser, quoteNode, lq); + ret = gemtextParserSend(parser, lq); if (ret) return ret; ret = fseek(parser->stream, -1, SEEK_CUR); if (ret) return ret; parser->state = lineStart; - parser->mode = normalMode; + parser->nodeType = normalNode; } break; case normalState: @@ -456,7 +456,10 @@ int parseQuote(gemtextParser *parser, gemtextNodeQueue *lq, char c) { parser->buffer.len--; parser->buffer.cursor--; } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + if (parser->buffer.len == 1) { + parser->nodeType = normalNode; + } + ret = gemtextParserSend(parser, lq); } else { parser->state = normalState; } @@ -469,7 +472,7 @@ int parseQuote(gemtextParser *parser, gemtextNodeQueue *lq, char c) { return ret; } -int parseGeneric(gemtextParser *parser, gemtextNodeQueue *lq, gemtextNodeType lt, char c) { +int parseGeneric(gemtextParser *parser, gemtextNodeQueue *nq, char c) { int ret = 0; switch (parser->state) { @@ -480,14 +483,14 @@ int parseGeneric(gemtextParser *parser, gemtextNodeQueue *lq, gemtextNodeType lt parser->buffer.len--; parser->buffer.cursor--; } else if (c == '\n') { - ret = gemtextParserSend(parser, lt, lq); + ret = gemtextParserSend(parser, nq); } else { parser->state = normalState; } break; case normalState: if (c == '\n') { - ret = gemtextParserSend(parser, lt, lq); + ret = gemtextParserSend(parser, nq); } break; default: @@ -498,7 +501,7 @@ int parseGeneric(gemtextParser *parser, gemtextNodeQueue *lq, gemtextNodeType lt return ret; } -int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { +int parseNormal(gemtextParser *parser, gemtextNodeQueue *nq, char c) { int ret; switch (parser->state) { @@ -508,12 +511,12 @@ int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { parser->state = firstLinkChar; break; case '>': - parser->mode = quoteMode; + parser->nodeType = quoteNode; parser->state = trimStart; lineBufferRewind(&parser->buffer); break; case '*': - parser->mode = listMode; + parser->nodeType = listNode; parser->state = trimStart; lineBufferRewind(&parser->buffer); break; @@ -524,7 +527,8 @@ int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { parser->state = firstBacktickChar; break; case '\n': - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; break; default: @@ -533,10 +537,11 @@ int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { break; case firstLinkChar: if (c == '>') { - parser->mode = linkMode; + parser->nodeType = linkNode; parser->state = lineStart; } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else { parser->state = normalState; @@ -546,52 +551,57 @@ int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { if (c == '#') { parser->state = secondHashChar; } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else { - switchMode(parser, h1Mode, c); + switchMode(parser, h1Node, c); } break; case secondHashChar: if (c == '#') { - parser->mode = h3Mode; + parser->nodeType = h3Node; parser->state = trimStart; lineBufferReset(&parser->buffer); } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else { - switchMode(parser, h2Mode, c); + switchMode(parser, h2Node, c); } break; case thirdHashChar: if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else { - switchMode(parser, h3Mode, c); + switchMode(parser, h3Node, c); } break; case firstBacktickChar: if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else if (c == '`') { parser->state = secondBacktickChar; } else { parser->state = normalState; - parser->mode = normalMode; + parser->nodeType = normalNode; } break; case secondBacktickChar: if (c == '`') { enterPreformattedMode(parser); } else if (c == '\n') { - ret = gemtextParserSend(parser, normalNode, lq); + parser->nodeType = normalNode; + ret = gemtextParserSend(parser, nq); if (ret) return ret; } else { parser->state = normalState; - parser->mode = normalMode; + parser->nodeType = normalNode; } break; default: @@ -600,7 +610,7 @@ int parseNormal(gemtextParser *parser, gemtextNodeQueue *lq, char c) { return 0; } -int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq) { +int parseGemtext(gemtextParser *parser, gemtextNodeQueue *nq) { char c; int ret; gemtextNode *node; @@ -615,30 +625,15 @@ int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq) { } } else { if (parser->state != lineStart && parser->state != trimStart) { - switch (parser->mode) { - case normalMode: - ret = gemtextParserSend(parser, normalNode, lq); + switch (parser->nodeType) { + case preformattedNode: + ret = gemtextParserSendPreformatted(parser, nq); break; - case preformattedMode: - ret = gemtextParserSendPreformatted(parser, lq); + case linkNode: + ret = gemtextParserSendLink(parser, nq); break; - case quoteMode: - ret = gemtextParserSend(parser, quoteNode, lq); - break; - case linkMode: - ret = gemtextParserSendLink(parser, lq); - break; - case h1Mode: - ret = gemtextParserSend(parser, h1Node, lq); - break; - case h2Mode: - ret = gemtextParserSend(parser, h2Node, lq); - break; - case h3Mode: - ret = gemtextParserSend(parser, h3Node, lq); - break; - case listMode: - ret = gemtextParserSend(parser, listNode, lq); + default: + ret = gemtextParserSend(parser, nq); break; } if (ret) return ret; @@ -648,33 +643,25 @@ int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq) { node->nodeType = endOfStream; node->prev = node->next = NULL; node->str = NULL; - gemtextNodeQueuePush(lq, node); + gemtextNodeQueuePush(nq, node); break; } - switch (parser->mode) { - case normalMode: - ret = parseNormal(parser, lq, c); + switch (parser->nodeType) { + case unset: + case normalNode: + ret = parseNormal(parser, nq, c); break; - case preformattedMode: - ret = parsePreformatted(parser, lq, c); + case preformattedNode: + ret = parsePreformatted(parser, nq, c); break; - case quoteMode: - ret = parseQuote(parser, lq, c); + case quoteNode: + ret = parseQuote(parser, nq, c); break; - case linkMode: - ret = parseLink(parser, lq, c); + case linkNode: + ret = parseLink(parser, nq, c); break; - case h1Mode: - ret = parseGeneric(parser, lq, h1Node, c); - break; - case h2Mode: - ret = parseGeneric(parser, lq, h2Node, c); - break; - case h3Mode: - ret = parseGeneric(parser, lq, h3Node, c); - break; - case listMode: - ret = parseGeneric(parser, lq, listNode, c); + default: + ret = parseGeneric(parser, nq, c); break; } if (ret) { diff --git a/include/gemtext-parser.h b/include/gemtext-parser.h index ab0ade2..48f99cf 100644 --- a/include/gemtext-parser.h +++ b/include/gemtext-parser.h @@ -10,19 +10,6 @@ #define LBUF_SIZE 512 ///< The default size of a lineBuffer -/** The main modes which the parser can operate in */ -typedef enum { - normalMode, /**< A normal text line is being parsed, or the parser is - still determining the line type */ - preformattedMode, ///< A Preformatted block is being parsed - quoteMode, ///< A Quote block is being parsed - linkMode, ///< A hyperlink is being parsed - h1Mode, ///< An H1 heading is being parsed - h2Mode, ///< An H2 heading is being parsed - h3Mode, ///< An H3 heading is being parsed - listMode, ///< A list member is being parsed -} gemtextParserMode; - /** An enumeration representing the state of the parsing action. These values * are to be taken in context with the current gemtextParserMode */ typedef enum { @@ -47,15 +34,16 @@ typedef enum { * An enum type representing the various line types in gemtext markup */ typedef enum { - 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 + unset = 0, ///< The node type has not yet been set + normalNode = 1, ///< A normal text line + linkNode = 2, ///< A link line + listNode = 3, ///< A list member + h1Node = 4, ///< An H1 heading + h2Node = 5, ///< An H2 heading + h3Node = 6, ///< An H3 heading + preformattedNode = 7, ///< A preformatted text block + quoteNode = 8, ///< A Quote block + endOfStream = 9, /**< Notifies the receiver that the stream is over and no more lines are to be expected */ } gemtextNodeType; @@ -91,7 +79,7 @@ typedef struct { */ typedef struct { FILE *stream; /**< A stream of bytes to read gemtext from */ - gemtextParserMode mode; /**< The current parsing mode */ + gemtextNodeType nodeType; /**< The current parsing mode */ gemtextParserState state; /**< The state of the parser within each mode */ lineBuffer buffer; /**< The internal buffer used to store bytes until a gemtextLine is ready to be sent */ @@ -170,31 +158,31 @@ void gemtextParserDestroy(gemtextParser *parser); * ### 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 gemtextNodeQueue + * \param nq The already allocated gemtextNodeQueue */ -int gemtextNodeQueueInit(gemtextNodeQueue *queue); +int gemtextNodeQueueInit(gemtextNodeQueue *nq); /** * Pushes a gemtextLine into the queue. This function will not fail, but * can block if another thread holds the gemtextQueue's internal mutex. - * \param queue The queue which will receive the gemtext line - * \param line The gemtextLine to be queued + * \param nq The queue which will receive the gemtext line + * \param node The gemtextNode to be queued */ -void gemtextNodeQueuePush(gemtextNodeQueue *queue, gemtextNode *node); +void gemtextNodeQueuePush(gemtextNodeQueue *nq, 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 + * \param nq The queue from which we are attempting to pop a line */ -gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *lq); +gemtextNode* gemtextNodeQueuePop(gemtextNodeQueue *nq); /** * 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 + * \param nq The queue from which we are attempting to pop a line */ -gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *lq); +gemtextNode* gemtextNodeQueueTryPop(gemtextNodeQueue *nq); /** * Frees all memory associated with a gemtextLine structure @@ -258,8 +246,8 @@ void lineBufferReset(lineBuffer *lb); * ### 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 gemtextNodeQueue which will receive gemtextLine elements as they are parsed + * \param nq A gemtextNodeQueue which will receive gemtextLine elements as they are parsed */ -int parseGemtext(gemtextParser *parser, gemtextNodeQueue *lq); +int parseGemtext(gemtextParser *parser, gemtextNodeQueue *nq); #endif