/* retoor <retoor@molodetz.nl> */
#include "repl.h"
#include "lorex.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INPUT 4096
static void print_banner(void) {
printf("lorex v%s - regex interpreter\n", LOREX_VERSION);
printf("commands: :q quit, :h help, :p <pattern> set pattern, :m <text> match, :s <text> search\n\n");
}
static void print_help(void) {
printf("lorex REPL commands:\n");
printf(" :q quit\n");
printf(" :h show this help\n");
printf(" :p <regex> compile and set pattern\n");
printf(" :m <text> match text against pattern (anchored)\n");
printf(" :s <text> search for pattern in text\n");
printf(" <text> search for pattern in text\n\n");
printf("regex syntax:\n");
printf(" . any character\n");
printf(" * zero or more\n");
printf(" + one or more\n");
printf(" ? zero or one\n");
printf(" | alternation\n");
printf(" () grouping\n");
printf(" [] character class\n");
printf(" [^] negated class\n");
printf(" ^ start anchor\n");
printf(" $ end anchor\n");
printf(" {n} exactly n\n");
printf(" {n,} n or more\n");
printf(" {n,m} n to m\n");
printf(" \\d digit\n");
printf(" \\w word character\n");
printf(" \\s whitespace\n");
printf(" \\D \\W \\S negated classes\n\n");
}
static void print_match(const char *text, lorex_match_t *result) {
if (!result->matched) {
printf("no match\n");
return;
}
printf("match: \"");
for (size_t i = result->match_start; i < result->match_end; i++) {
printf("%c", text[i]);
}
printf("\" [%zu-%zu]\n", result->match_start, result->match_end);
for (size_t i = 0; i < result->group_count; i++) {
if (result->groups[i].matched) {
printf(" group %zu: \"", i);
for (size_t j = result->groups[i].start; j < result->groups[i].end; j++) {
printf("%c", text[j]);
}
printf("\" [%zu-%zu]\n", result->groups[i].start, result->groups[i].end);
}
}
}
static char *read_line(void) {
static char buffer[MAX_INPUT];
printf("> ");
fflush(stdout);
if (!fgets(buffer, MAX_INPUT, stdin)) {
return NULL;
}
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
}
return buffer;
}
void repl_run(void) {
print_banner();
lorex_regex_t *regex = NULL;
char *line;
while ((line = read_line()) != NULL) {
if (strlen(line) == 0) continue;
if (strcmp(line, ":q") == 0 || strcmp(line, ":quit") == 0) {
break;
}
if (strcmp(line, ":h") == 0 || strcmp(line, ":help") == 0) {
print_help();
continue;
}
if (strncmp(line, ":p ", 3) == 0) {
const char *pattern = line + 3;
while (*pattern == ' ') pattern++;
if (regex) {
lorex_free(regex);
regex = NULL;
}
lorex_error_t error;
regex = lorex_compile(pattern, &error);
if (!regex) {
printf("error: %s\n", lorex_error_string(error));
} else {
printf("pattern compiled: %s\n", pattern);
}
continue;
}
if (strncmp(line, ":m ", 3) == 0) {
if (!regex) {
printf("error: no pattern set (use :p <pattern>)\n");
continue;
}
const char *text = line + 3;
while (*text == ' ') text++;
lorex_match_t result;
lorex_match(regex, text, &result);
print_match(text, &result);
continue;
}
if (strncmp(line, ":s ", 3) == 0) {
if (!regex) {
printf("error: no pattern set (use :p <pattern>)\n");
continue;
}
const char *text = line + 3;
while (*text == ' ') text++;
lorex_match_t result;
lorex_search(regex, text, &result);
print_match(text, &result);
continue;
}
if (line[0] == ':') {
printf("unknown command: %s\n", line);
continue;
}
if (!regex) {
printf("error: no pattern set (use :p <pattern>)\n");
continue;
}
lorex_match_t result;
lorex_search(regex, line, &result);
print_match(line, &result);
}
if (regex) {
lorex_free(regex);
}
printf("\n");
}