diff --git a/Makefile b/Makefile index 2f08020..115b79c 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,8 @@ .SUFFIXES: .SUFFIXES: .o .c -CFLAGS += -Wall -Werror +CFLAGS += -Wall +CFLAGS += -Werror CFLAGS += -Iinclude hdrs += include/gemtext-parser.h diff --git a/gemtext-parser.c b/gemtext-parser.c index fa162d9..f873883 100644 --- a/gemtext-parser.c +++ b/gemtext-parser.c @@ -1,3 +1,4 @@ +#include // errno #include // NULL, size_t #include // fclose #include // calloc, free @@ -64,7 +65,7 @@ gemtextLine* gemtextLineQueuePop(gemtextLineQueue *lq) { return line; } -lineBuffer* lineBufferInit() { +lineBuffer* lineBufferNew() { char *buf; lineBuffer *lb = calloc(1, sizeof(lineBuffer)); @@ -81,6 +82,16 @@ lineBuffer* lineBufferInit() { return lb; } +int lineBufferInit(lineBuffer *lb) { + char *buf = calloc(1, LBUF_SIZE); + if (buf == NULL) return 2; + lb->len = 0; + lb->capacity = LBUF_SIZE; + lb->buf = buf; + lb->cursor = buf; + return 0; +} + void lineBufferDeinit(lineBuffer *lb) { free(lb->buf); free(lb); @@ -143,6 +154,7 @@ void lineBufferReset(lineBuffer *lb) { gemtextLink* readLink(FILE *stream, lineBuffer *lb) { char c; + char *buf; int ret = 0; gemtextLink *link = calloc(1, sizeof(gemtextLink)); @@ -154,14 +166,16 @@ gemtextLink* readLink(FILE *stream, lineBuffer *lb) { case '\t': if (lb->len == 0) continue; - link->url = strndup(lb->buf, lb->len); + buf = strndup(lb->buf, lb->len); + link->url = buf; break; case '\n': if (lb->len == 0) { free(link); return NULL; } - link->url = strndup(lb->buf, lb->len); + buf = strndup(lb->buf, lb->len); + link->url = buf; return link; default: ret = lineBufferAppendChar(lb, c); @@ -190,11 +204,6 @@ gemtextLink* readLink(FILE *stream, lineBuffer *lb) { return link; } -int parseNormal(gemtextParser *parser, gemtextLineQueue *lq) { - // todo - return 0; -} - int parsePreformatted(gemtextParser *parser, gemtextLineQueue *lq) { // todo return 0; @@ -205,6 +214,130 @@ int parseQuote(gemtextParser *parser, gemtextLineQueue *lq) { return 0; } +int parseNormal(gemtextParser *parser, gemtextLineQueue *lq) { + char c; + int ret; + gemtextLine *line; + gemtextLink *link; + lineBuffer lb; + char *buf; + + ret = lineBufferInit(&lb); + if (ret != 0) return ret; + while (1) { + ret = fread(&c, 1, 1, parser->stream); + if (c != 1) { + line = calloc(1, sizeof(gemtextLine)); + if (line == NULL) return errno; + line->lineType = endOfStream; + line->prev = line->next = NULL; + line->str = NULL; + gemtextLineQueuePush(lq, line); + } + switch (parser->state) { + case lineStart: + switch (c) { + case '=': + ret = lineBufferAppendChar(&lb, c); + if (ret != 0) { + free(lb.buf); + return ret; + } + parser->state = firstLinkChar; + break; + case '>': + parser->mode = quoteMode; + ret = parseQuote(parser, lq); + if (ret != 0) { + free(lb.buf); + return ret; + } + break; + case '#': + ret = lineBufferAppendChar(&lb, c); + if (ret != 0) { + free(lb.buf); + return ret; + } + parser->state = firstHashChar; + break; + case '`': + ret = lineBufferAppendChar(&lb, c); + if (ret != 0) { + free(lb.buf); + return ret; + } + parser->state = firstBacktickChar; + break; + case '\n': + line = calloc(1, sizeof(gemtextLine)); + if (line == NULL) return errno; + line->lineType = normalLine; + buf = strndup("\n", 1); + if (buf == NULL) { + free(lb.buf); + return errno; + } + line->str = buf; + gemtextLineQueuePush(lq, line); + break; + default: + ret = lineBufferAppendChar(&lb, c); + if (ret != 0) { + free(lb.buf); + return ret; + } + parser->state = normalState; + break; + } + break; + case firstLinkChar: + ret = lineBufferAppendChar(&lb, c); + if (ret != 0) { + free(lb.buf); + return ret; + } + if (c == '>') { + parser->state = secondLinkChar; + } else if (c == '\n') { + // todo - send a 'normal' line to the lineQueue and reset the + // lineBuffer + } else { + parser->state = normalState; + } + case secondLinkChar: + line = calloc(1, sizeof(gemtextLine)); + if (line == NULL) return errno; + link = readLink(parser->stream, &lb); + if (link == NULL) { + line->lineType = normalLine; + buf = strndup(lb.buf, lb.len); + if (buf == NULL) { + free(lb.buf); + free(line); + return errno; + } + line->str = buf; + gemtextLineQueuePush(lq, line); + } else { + line->lineType = linkLine; + line->link = link; + gemtextLineQueuePush(lq, line); + } + lineBufferReset(&lb); + break; + case firstHashChar: + case secondHashChar: + case thirdHashChar: + case firstBacktickChar: + case secondBacktickChar: + case thirdBacktickChar: + case normalState: + } + } + return 0; +} + int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq) { // todo return 0; diff --git a/include/gemtext-parser.h b/include/gemtext-parser.h index e2a6567..c8d741f 100644 --- a/include/gemtext-parser.h +++ b/include/gemtext-parser.h @@ -1,9 +1,9 @@ #ifndef GEMTEXT_PARSER_H #define GEMTEXT_PARSER_H 1 -#include -#include -#include +#include // pthread_mutex_t, pthread_cond_t +#include // size_t +#include // FILE #define LBUF_SIZE 512 @@ -16,7 +16,7 @@ typedef enum { typedef enum { lineStart, firstLinkChar, - firstLinkWord, + secondLinkChar, firstHashChar, secondHashChar, thirdHashChar, @@ -60,7 +60,10 @@ struct _gemtextLine { struct _gemtextLine *next; struct _gemtextLine *prev; gemtextLineType lineType; - char *line; + union { + char *str; + gemtextLink *link; + }; }; typedef struct _gemtextLine gemtextLine;