Added documentation via doxygen

This commit is contained in:
Nathan Fisher 2023-10-11 00:28:53 -04:00
parent c6605630b5
commit 0a1a4e8803
5 changed files with 3045 additions and 66 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ test/*
*.a *.a
*.so *.so
*.core *.core
doc

2822
Doxyfile Normal file

File diff suppressed because it is too large Load diff

View file

@ -53,7 +53,10 @@ static: $(staticlib)
$(staticlib): $(objs) $(staticlib): $(objs)
$(AR) rcs $@ $? $(AR) rcs $@ $?
clean: docs: Doxyfile $(hdrs)
rm -rf $(objs) $(staticlib) doxygen
.PHONY: all clean clean:
rm -rf $(objs) $(staticlib) doc
.PHONY: all docs clean

View file

@ -17,18 +17,25 @@ int lineBufferInit(lineBuffer *lb) {
return 0; return 0;
} }
gemtextParser* gemtextParserInit(FILE *stream) { int gemtextParserInit(gemtextParser *parser, FILE *stream) {
gemtextParser *parser = calloc(1, sizeof(gemtextParser)); int ret = 0;
if (parser == NULL)
return NULL;
parser->stream = stream; parser->stream = stream;
parser->mode = normalMode; parser->mode = normalMode;
parser->state = lineStart; parser->state = lineStart;
if (lineBufferInit(&parser->buffer) != 0) { parser->linkUrl = NULL;
ret = lineBufferInit(&parser->buffer);
return ret;
}
gemtextParser* gemtextParserNew(FILE *stream) {
gemtextParser *parser = calloc(1, sizeof(gemtextParser));
if (parser == NULL)
return NULL;
if (gemtextParserInit(parser, stream) != 0) {
free(parser); free(parser);
return NULL; return NULL;
} }
parser->linkUrl = NULL;
return parser; return parser;
} }

View file

@ -1,3 +1,6 @@
/** \file gemtext-parser.h
* \brief A fast Gemtext markup parser
*/
#ifndef GEMTEXT_PARSER_H #ifndef GEMTEXT_PARSER_H
#define GEMTEXT_PARSER_H 1 #define GEMTEXT_PARSER_H 1
@ -5,95 +8,238 @@
#include <stddef.h> // size_t #include <stddef.h> // size_t
#include <stdio.h> // FILE #include <stdio.h> // FILE
#define LBUF_SIZE 512 #define LBUF_SIZE 512 ///< The default size of a lineBuffer
/** The main modes which the parser can operate in */
typedef enum { typedef enum {
normalMode, normalMode, /**< A normal text line is being parsed, or the parser is
preformattedMode, still determining the line type */
quoteMode, preformattedMode, ///< A Preformatted block is being parsed
linkMode, quoteMode, ///< A Quote block is being parsed
h1Mode, linkMode, ///< A hyperlink is being parsed
h2Mode, h1Mode, ///< An H1 heading is being parsed
h3Mode, h2Mode, ///< An H2 heading is being parsed
listMode, h3Mode, ///< An H3 heading is being parsed
listMode, ///< A list member is being parsed
} gemtextParserMode; } gemtextParserMode;
/** An enumeration representing the state of the parsing action. These values
* are to be taken in context with the current gemtextParserMode */
typedef enum { typedef enum {
lineStart, lineStart, ///< The cursor is at the start of a new line
lineEnd, lineEnd, ///< The cursor is at the end of a line
firstLinkChar, firstLinkChar, ///< The first link character was the previous character
linkDisplayStart, linkDisplayStart, /**< The url of a link has been parsed and the cursor is at the
linkDisplay, beginning of the display element */
firstHashChar, linkDisplay, ///< The link's display element is being parsed
secondHashChar, firstHashChar, ///< A Single '#' character has been encountered
thirdHashChar, secondHashChar, ///< Two '#' characters have been encountered sequentially
firstBacktickChar, thirdHashChar, ///< Three '#' characters have been encountered sequentially
secondBacktickChar, firstBacktickChar, ///< A single '`' character has been encountered
thirdBacktickChar, secondBacktickChar, ///< Two '`' characters have been encountered sequentially
preformattedAlt, thirdBacktickChar, ///< Three '`' characters have been encountered sequentially
trimStart, preformattedAlt, ///< A Preformatted block's alt text is being parsed
normalState, trimStart, ///< The *mode* is known and leading whitespace is being trimmed
normalState, ///< The *mode* is known and normal parsing is occurring
} gemtextParserState; } gemtextParserState;
/**
* An enum type representing the various line types in gemtext markup
*/
typedef enum { typedef enum {
normalLine, normalLine, ///< A normal text line
linkLine, linkLine, ///< A link line
listLine, listLine, ///< A list member
h1Line, h1Line, ///< An H1 heading
h2Line, h2Line, ///< An H2 heading
h3Line, h3Line, ///< An H3 heading
preformattedLine, preformattedLine, ///< A preformatted text block
quoteLine, quoteLine, ///< A Quote block
endOfStream, endOfStream, /**< Notifies the receiver that the stream is over and no
more lines are to be expected */
} gemtextLineType; } gemtextLineType;
/**
* A growable byte array
*/
typedef struct { typedef struct {
size_t capacity; size_t capacity; ///< The current capacity of the internal buffer
size_t len; size_t len; ///< The actual number of bytes currently in use
char *cursor; char *cursor; ///< A pointer to the next byte to be used in the internal buffer
char *buf; char *buf; ///< A Pointer to the beginning of the internal buffer
} lineBuffer; } lineBuffer;
/**
* A Gemtext link element
*/
typedef struct { typedef struct {
char *url; char *url; ///< The url of the gemtext link
char *display; char *display; ///< Optional text to be displayed in lieu of the url
} gemtextLink; } gemtextLink;
/**
* A block of preformatted text
*/
typedef struct { typedef struct {
char *altText; char *altText; /**< Some descriptive text to be read by screen readers if
char *body; this is ascii art */
char *body; ///< The body of the preformatted block
} preformattedNode; } preformattedNode;
/**
* The main Gemtext parser
*/
typedef struct { typedef struct {
FILE *stream; FILE *stream; /**< A stream of bytes to read gemtext from */
gemtextParserMode mode; gemtextParserMode mode; /**< The current parsing mode */
gemtextParserState state; gemtextParserState state; /**< The state of the parser within each mode */
lineBuffer buffer; lineBuffer buffer; /**< The internal buffer used to store bytes until
a gemtextLine is ready to be sent */
union { union {
char *linkUrl; char *linkUrl; /**< The url portion of a linkLine */
char *altText; char *altText; /**< The alt text associated with a preformatted block */
}; };
} gemtextParser; } gemtextParser;
struct _gemtextLine { struct _gemtextLine {
struct _gemtextLine *next; struct _gemtextLine *next; ///< The next line in the queue
struct _gemtextLine *prev; struct _gemtextLine *prev; ///< The previous line in the queue
gemtextLineType lineType; gemtextLineType lineType; ///< Identifies the type of line
union { union {
char *str; char *str; ///< The text body of most line types
gemtextLink *link; gemtextLink *link; ///< The body of a link line
preformattedNode *node; preformattedNode *node; ///< The body and alt text of a preformatted block
}; };
}; };
/** A Gemtext node */
typedef struct _gemtextLine gemtextLine; typedef struct _gemtextLine gemtextLine;
/**
* A fifo queue used to pass gemtextLine elements from the worker thread to the
* rendering thread.
*/
typedef struct { typedef struct {
pthread_cond_t cond; pthread_cond_t cond; ///< Signals the rendering thread to wait for an incoming line
size_t count; size_t count; ///< The number of elements currently in the queue
pthread_mutex_t mutex; pthread_mutex_t mutex; ///< The lock ensuring exclusive access
gemtextLine *head; gemtextLine *head; ///< The oldest line in the queue
gemtextLine *tail; gemtextLine *tail; ///< The newest line in the queue
} gemtextLineQueue; } gemtextLineQueue;
/**
* Initialize a lineBuffer struct to it's default values.
* ### Return values
* Returns 0 for success, 2 if memory allocation fails.
* \param lb A pointer to an already allocated lineBuffer
*/
int lineBufferInit(lineBuffer *lb);
/**
* Initialize a gemtextParser to it's default values.
* ### Return values
* Returns 0 upon success, 2 if memory allocation for the internal
* buffer fails.
* \param parser A pointer to an already allocated gemtextParser
* \param stream A FILE which we whose bytes will be read and parsed as gemtext lines
*/
int gemtextParserInit(gemtextParser *parser, FILE *stream);
/**
* Creates a new gemtextParser and initializes it to default values.
* If memory allocation fails a NULL pointer will be returned.
* \param stream The FILE stream which we will read and parse as gemtext lines
*/
gemtextParser* gemtextParserNew(FILE *stream);
/**
* Frees all memory associated with this gemtextParser.
* \param parser The gemtextParser to be freed
*/
void gemtextParserDeinit(gemtextParser *parser);
/**
* Initializes a gemtextLineQueue 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
*/
int gemtextLineQueueInit(gemtextLineQueue *queue);
/**
* 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
*/
void gemtextLineQueuePush(gemtextLineQueue *queue, gemtextLine *line);
/**
* 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);
/**
* Extends the LineBuffer lb by len bytes.
* ### Return values
* Returns 0 upon success, or 2 if memory allocation fails.
* \param lb The buffer to be extended
* \param len The number of bytes to extend the buffer by
*/
int lineBufferExtend(lineBuffer *lb, size_t len);
/**
* Appends a character c to the lineBuffer lb. If there is no space left in the
* internal buffer, it will be re-allocated first.
* ### Return values
* Returns 0 for success, or 2 if memory allocation fails.
* \param lb The buffer we are appending to
* \param c The character to be appended to this buffer
*/
int lineBufferAppendChar(lineBuffer *lb, char c);
/**
* Appends a character c to the lineBuffer c without checking if there is space
* available first.
* > **Warning!** Due to the fact that this function is unchecked, it should
* > only be called if you are absolutely certain that there is space remaining
* > in the internal buffer, such as after calling lineBufferRewind to move the
* > cursor back by one character. Failure to follow this warning may result in
* > *buffer overflow* memory access violation.
*/
void lineBufferAppendCharUnchecked(lineBuffer *lb, char c);
/**
* Appends a string beginning at the pointer *c of len bytes to lineBuffer lb.
* ### Return values
* Returns 0 on success, or 2 for memory allocation errors.
* \param lb The buffer we are appending to
* \param c A pointer to an array of chars
* \param len The number of bytes to append from c
*/
int lineBufferAppendString(lineBuffer *lb, char *c, size_t len);
/**
* Rewinds the internal cursor pointer and count for lineBuffer lb by 1.
*/
void lineBufferRewind(lineBuffer *lb);
/**
* Resets the internal count of lineBuffer lb to 0 and moves it's cursor back
* to the start of the internal buffer.
*/
void lineBufferReset(lineBuffer *lb);
/**
* Parses gemtext into a series of nodes to be places in the gemtextLineQueue 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
*/
int parseGemtext(gemtextParser *parser, gemtextLineQueue *lq);
#endif #endif