Skip to content

Commit

Permalink
Add registration mechanism for custom node flags
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinbackhouse committed Dec 1, 2022
1 parent 9f02cba commit 420c20a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 7 deletions.
1 change: 1 addition & 0 deletions api_test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,7 @@ int main() {
int retval;
test_batch_runner *runner = test_batch_runner_new();

cmark_init_standard_node_flags();
version(runner);
constructor(runner);
accessors(runner);
Expand Down
4 changes: 4 additions & 0 deletions extensions/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include "table.h"
#include "cmark-gfm-core-extensions.h"

// Custom node flag, initialized in `create_table_extension`.
static cmark_node__internal_flags CMARK_NODE__TABLE_VISITED;

cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
CMARK_NODE_TABLE_CELL;

Expand Down Expand Up @@ -790,6 +793,7 @@ static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
cmark_syntax_extension *create_table_extension(void) {
cmark_syntax_extension *self = cmark_syntax_extension_new("table");

cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED);
cmark_syntax_extension_set_match_block_func(self, matches);
cmark_syntax_extension_set_open_block_func(self, try_opening_table_block);
cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
Expand Down
1 change: 1 addition & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ int main(int argc, char *argv[]) {
}
#endif

cmark_init_standard_node_flags();
cmark_gfm_core_extensions_ensure_registered();

#ifdef USE_PLEDGE
Expand Down
34 changes: 34 additions & 0 deletions src/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,40 @@ static void S_node_unlink(cmark_node *node);

#define NODE_MEM(node) cmark_node_mem(node)

cmark_node__internal_flags CMARK_NODE__OPEN = 0;
cmark_node__internal_flags CMARK_NODE__LAST_LINE_BLANK = 0;
cmark_node__internal_flags CMARK_NODE__LAST_LINE_CHECKED = 0;

void cmark_register_node_flag(cmark_node__internal_flags *flags) {
static uint8_t shift = 0;

// flags should be a pointer to a global variable and this function
// should only be called once to initialize its value.
if (*flags) {
fprintf(stderr, "flag initialization error in cmark_register_node_flag\n");
abort();
}

// Check that we haven't run out of bits.
if (shift >= 8 * sizeof(cmark_node__internal_flags)) {
fprintf(stderr, "too many flags in cmark_register_node_flag\n");
abort();
}

*flags = (cmark_node__internal_flags)1 << shift;
shift++;
}

void cmark_init_standard_node_flags() {
static int initialized = 0;
if (!initialized) {
initialized = 1;
cmark_register_node_flag(&CMARK_NODE__OPEN);
cmark_register_node_flag(&CMARK_NODE__LAST_LINE_BLANK);
cmark_register_node_flag(&CMARK_NODE__LAST_LINE_CHECKED);
}
}

bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
if (child_type == CMARK_NODE_DOCUMENT) {
return false;
Expand Down
33 changes: 26 additions & 7 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,7 @@ typedef struct {
cmark_chunk on_exit;
} cmark_custom;

enum cmark_node__internal_flags {
CMARK_NODE__OPEN = (1 << 0),
CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
CMARK_NODE__TABLE_VISITED = (1 << 3),
};
typedef uint16_t cmark_node__internal_flags;

struct cmark_node {
cmark_strbuf content;
Expand All @@ -73,7 +68,7 @@ struct cmark_node {
int end_column;
int internal_offset;
uint16_t type;
uint16_t flags;
cmark_node__internal_flags flags;

cmark_syntax_extension *extension;

Expand All @@ -96,6 +91,30 @@ struct cmark_node {
} as;
};

/**
* Syntax extensions can use this function to register a custom node
* flag. The flags are stored in the `flags` field of the `cmark_node`
* struct. The `flags` parameter should be the address of a global variable
* which will store the flag value.
*/
CMARK_GFM_EXPORT
void cmark_register_node_flag(cmark_node__internal_flags *flags);

/**
* Standard node flags. (Initialized using `cmark_init_standard_node_flags`.)
*/
extern cmark_node__internal_flags CMARK_NODE__OPEN;
extern cmark_node__internal_flags CMARK_NODE__LAST_LINE_BLANK;
extern cmark_node__internal_flags CMARK_NODE__LAST_LINE_CHECKED;

/**
* Uses `cmark_register_node_flag` to initialize the standard node flags.
* This function should be called at program startup time. Calling it
* multiple times has no additional effect.
*/
CMARK_GFM_EXPORT
void cmark_init_standard_node_flags();

static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
return node->content.mem;
}
Expand Down
2 changes: 2 additions & 0 deletions test/cmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def pipe_through_prog(prog, text):

def parse(lib, extlib, text, extensions):
cmark_gfm_core_extensions_ensure_registered = extlib.cmark_gfm_core_extensions_ensure_registered
cmark_init_standard_node_flags = lib.cmark_init_standard_node_flags

find_syntax_extension = lib.cmark_find_syntax_extension
find_syntax_extension.restype = c_void_p
Expand All @@ -32,6 +33,7 @@ def parse(lib, extlib, text, extensions):
parser_finish.restype = c_void_p
parser_finish.argtypes = [c_void_p]

cmark_init_standard_node_flags()
cmark_gfm_core_extensions_ensure_registered()

parser = parser_new(0)
Expand Down

0 comments on commit 420c20a

Please sign in to comment.