#include #include #include #include "parser.h" int ConsumeWhitespace(char* s) { int i = 0; while (s[i]) { switch (s[i]) { case ' ': case '\t': case '\r': break; default: goto end; } i++; } end: return i; } /* Return a pointer to the first line-ending character * in this line (i.e. CR in case of CRLF, LF in case of just LF, * or NUL if this line does not end with CR or LF). */ char* LineEnd(char* line) { while (*line) { switch (*line) { case '\r': if (line[1] == '\n') return line; break; case '\n': return line; break; default: break; } line++; } return line; } /* A la glibc 2.11 strchrnul */ char* strchrnul(const char* s, int c) { while (*s && (*s != c)) s++; return (char*)s; } /* Parse a line in-place, without allocating any new memory */ enum parse_result ParseLine(struct parse_state* s, struct line* l) { int i = 0, link_end; char* line; char* line_end; char* line_next; enum parse_result res = PARSE_LINE; line = s->buf; line_end = LineEnd(s->buf); if (*line_end == 0) line_next = line_end; else if (*line_end == '\n') line_next = line_end + 1; else if (*line_end == '\r') line_next = line_end + 2; *line_end = 0; if (strncmp(line, "```", 3) == 0) { s->preformatted = !s->preformatted; res = PARSE_NOLINE; } else if (s->preformatted) { l->type = LT_PRETEXT; l->text = line; } else if (*line == '>') { i++; i += ConsumeWhitespace(&line[i]); l->type = LT_QUOTE; l->text = &line[i]; } else if (*line == '#') { i = strchrnul(line, ' ') - line; if (i > 3) i = 3; l->level = i; i += ConsumeWhitespace(&line[i]); l->text = &line[i]; l->type = LT_HEADING; } else if (*line == '*') { i++; i += ConsumeWhitespace(&line[i]); l->type = LT_LISTITEM; l->text = &line[i]; } else if (strncmp(line, "=>", 2) == 0) { l->type = LT_LINK; i = 2; i += ConsumeWhitespace(&line[i]); l->url = &line[i]; for (; line[i] && !isspace(line[i]); i++); if (line[i] == 0) { /* no title */ l->text = l->url; } else { line[i++] = 0; l->text = &line[i]; } } else { /* just text */ l->type = LT_TEXT; l->text = line; } s->buf = line_next; return res; }