1525 lines
53 KiB
Diff
1525 lines
53 KiB
Diff
From 0a48ebe68bf2750ae2c8045c6341ebd3184d5e2c Mon Sep 17 00:00:00 2001
|
|
From: Emil Williams <emilwilliams@tuta.io>
|
|
Date: Mon, 18 Dec 2023 21:48:58 +0000
|
|
Subject: [PATCH] updoot
|
|
|
|
---
|
|
Makefile | 47 ++++---
|
|
source/bot.c | 306 +++++++++++++++++++++++++++++++++++++++++++
|
|
source/bot.h | 299 +-----------------------------------------
|
|
source/config.inc | 13 +-
|
|
source/log.c | 19 +++
|
|
source/log.h | 19 +--
|
|
source/main.c | 27 +---
|
|
source/syntax.c | 322 +++++++++++++++++++++++++++++++++++++++++++++
|
|
source/syntax.h | 324 +++-------------------------------------------
|
|
9 files changed, 710 insertions(+), 666 deletions(-)
|
|
create mode 100644 source/bot.c
|
|
create mode 100644 source/log.c
|
|
create mode 100644 source/syntax.c
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index cfc8215..49019a9 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,38 +1,43 @@
|
|
-.PHONY: clean run test
|
|
+INSTALL_TARGET := /etc/init.d/hibot
|
|
+OUT := hibot
|
|
+
|
|
+WRAP := valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all
|
|
+CFLAGS += -std=gnu99 -fno-builtin
|
|
+CPPFLAGS += -DPROGRAM_NAME=\"${OUT}\" -D_GNU_SOURCE -I/usr/include/libircclient/
|
|
+LDLIBS := -lircclient
|
|
|
|
-WRAP := valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all
|
|
-CFLAGS += -fno-builtin -I/usr/include/libircclient/
|
|
ifeq ($(DEBUG), 1)
|
|
- CFLAGS += -Wall -Wextra -Wpedantic
|
|
- CFLAGS += -DDEBUG -O0 -ggdb -fno-inline
|
|
+ CFLAGS += -Wall -Wextra -Wpedantic -O0 -ggdb -fno-inline
|
|
+ CPPFLAGS += -DDEBUG
|
|
else
|
|
CFLAGS += -O3 -fno-stack-protector
|
|
endif
|
|
|
|
-LDLIBS := -lircclient
|
|
-
|
|
-INSTALL_TARGET := /etc/init.d/hibot
|
|
-OUT := hibot
|
|
-
|
|
SOURCE.d := source/
|
|
-SOURCE := main.c
|
|
-SOURCE := $(addprefix ${SOURCE.d}, ${SOURCE})
|
|
+SOURCE := main.c syntax.c bot.c log.c
|
|
+OBJECT := $(addprefix ${SOURCE.d}, ${SOURCE:.c=.o})
|
|
HEADER := config.inc version.inc log.h bot.h syntax.h
|
|
HEADER := $(addprefix ${SOURCE.d}, ${HEADER})
|
|
|
|
-${OUT}: ${SOURCE} ${HEADER}
|
|
- ${CC} ${CFLAGS} -o $@ ${SOURCE} ${LDLIBS}
|
|
+CC := ${CC} ${CFLAGS}
|
|
|
|
-run: ${OUT}
|
|
- ./${OUT} irc.rizon.net:6665 "#/g/test"
|
|
+%.o: %.c
|
|
+ ${CC} ${CPPFLAGS} -c -o $@ $<
|
|
|
|
-test: ${OUT}
|
|
- ${WRAP} ${OUT} irc.rizon.net:6665 "#/g/test"
|
|
+${OUT}: ${HEADER} | ${OBJECT}
|
|
+ ${CC} -flto=auto -o $@ $| ${LDLIBS}
|
|
+
|
|
+clean:
|
|
+ ${RM} ${OBJECT} ${OUT} ${INSTALL_TARGET}
|
|
|
|
install:
|
|
m4 script/hibot.m4 > ${INSTALL_TARGET}
|
|
chmod 755 ${INSTALL_TARGET}
|
|
|
|
-clean:
|
|
- -rm ${OUT}
|
|
- -rm ${INSTALL_TARGET}
|
|
+run: ${OUT}
|
|
+ ./${OUT} irc.rizon.net:6665 "#/g/test"
|
|
+
|
|
+test: ${OUT}
|
|
+ ${WRAP} ${OUT} irc.rizon.net:6665 "#/g/test"
|
|
+
|
|
+.PHONY: clean run test install
|
|
diff --git a/source/bot.c b/source/bot.c
|
|
new file mode 100644
|
|
index 0000000..2bfe0ae
|
|
--- /dev/null
|
|
+++ b/source/bot.c
|
|
@@ -0,0 +1,306 @@
|
|
+#include "log.h"
|
|
+#include "bot.h"
|
|
+#include "syntax.h"
|
|
+#include "config.inc"
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+char * channel;
|
|
+char * server;
|
|
+char * port;
|
|
+
|
|
+static inline
|
|
+void irc_message(const char * const message) {
|
|
+ irc_cmd_msg(session, channel, message);
|
|
+}
|
|
+
|
|
+static inline
|
|
+void irc_private_message(const char * const user, const char * const message) {
|
|
+ irc_cmd_msg(session, user, message);
|
|
+}
|
|
+
|
|
+static inline
|
|
+char * username_root(const char * const fullname){
|
|
+ char * r = (char *)fullname;
|
|
+ while (*(r++) != '!') { ; }
|
|
+ asprintf(&r, "From %.*s:", (int)(r - fullname)-1, fullname);
|
|
+ return r;
|
|
+}
|
|
+
|
|
+typedef struct {
|
|
+ int is_active;
|
|
+ char * user;
|
|
+ language_t language;
|
|
+ struct itimerval timer;
|
|
+ char * buffer[128]; // XXX: no overflow detection/avertion
|
|
+ unsigned int buffer_head; // is implemented on this bunch
|
|
+} request_t;
|
|
+
|
|
+void init_request(request_t * request) {
|
|
+ request->is_active = 0;
|
|
+ request->timer.it_value.tv_sec = 0;
|
|
+ request->timer.it_value.tv_usec = 0;
|
|
+ request->timer.it_interval.tv_sec = 0;
|
|
+ request->timer.it_interval.tv_usec = 0;
|
|
+ request->buffer_head = 0;
|
|
+}
|
|
+
|
|
+request_t request_queue__[message_queue_size];
|
|
+request_t * request_queue[message_queue_size];
|
|
+unsigned int request_queue_head = 0;
|
|
+
|
|
+static inline
|
|
+void touch_request_timer(request_t * request) {
|
|
+ request->timer.it_value.tv_sec = message_timeout;
|
|
+ setitimer(ITIMER_REAL, &(request->timer), NULL);
|
|
+}
|
|
+
|
|
+void activate_request(request_t * request) {
|
|
+ request->is_active = 1;
|
|
+
|
|
+ /* message header */
|
|
+ char * short_name = username_root(request->user);
|
|
+ irc_message(short_name);
|
|
+ free(short_name);
|
|
+}
|
|
+
|
|
+request_t * take_request(const char * const user, language_t language) {
|
|
+ for (unsigned int i = 0; i < request_queue_head; i++) {
|
|
+ if(!strcmp(request_queue[i]->user, user)) {
|
|
+ return request_queue[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (request_queue_head == message_queue_size) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ request_t * request = request_queue[request_queue_head];
|
|
+
|
|
+ request->language = language;
|
|
+ request->user = strdup(user);
|
|
+
|
|
+ if (request_queue_head == 0) {
|
|
+ activate_request(request);
|
|
+ }
|
|
+
|
|
+ ++request_queue_head;
|
|
+
|
|
+ char * log_message;
|
|
+ asprintf(&log_message, "Took message: %p (%d)", (void*)request, request_queue_head);
|
|
+ log_notice(log_message);
|
|
+ free(log_message);
|
|
+
|
|
+ return request;
|
|
+}
|
|
+
|
|
+void drop_reqest() {
|
|
+ request_t * request = request_queue[0];
|
|
+
|
|
+ if (message_queue_size > 1) {
|
|
+ for (unsigned int i = 0; i < request_queue_head; i++) {
|
|
+ request_queue[i] = request_queue[i+1];
|
|
+ }
|
|
+ request_queue[request_queue_head] = request;
|
|
+ }
|
|
+
|
|
+ --request_queue_head;
|
|
+
|
|
+ request->is_active = 0;
|
|
+ free(request->user);
|
|
+
|
|
+ if (request_queue_head) {
|
|
+ activate_request(request_queue[0]);
|
|
+ for (unsigned int i = 0; i < request_queue[0]->buffer_head; i++) {
|
|
+ irc_message(request_queue[0]->buffer[i]);
|
|
+ free(request_queue[0]->buffer[i]);
|
|
+ }
|
|
+ request_queue[0]->buffer_head = 0;
|
|
+ touch_request_timer(request_queue[0]);
|
|
+ }
|
|
+
|
|
+ char * log_message;
|
|
+ asprintf(&log_message, "Dropped message: %p (%d)", (void*)request, request_queue_head);
|
|
+ log_notice(log_message);
|
|
+ free(log_message);
|
|
+}
|
|
+
|
|
+void on_message_timeout(int unused) {
|
|
+ (void)unused;
|
|
+
|
|
+ /* message footer */
|
|
+ irc_message("--");
|
|
+
|
|
+ drop_reqest(request_queue);
|
|
+}
|
|
+
|
|
+static
|
|
+language_t translate_language(const char * const language) {
|
|
+ if (!strcmp(language, "C") || !strcmp(language, "C++")) {
|
|
+ return C;
|
|
+ } else if (!strcmp(language, "ADA")) {
|
|
+ return ADA;
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static
|
|
+void irc_help() {
|
|
+ irc_message(PROGRAM_NAME " "
|
|
+#include "version.inc"
|
|
+ );
|
|
+ irc_message(PROGRAM_NAME " is a code highlighting IRC bot."
|
|
+ " You may direct message it with your code or commands."
|
|
+ );
|
|
+ irc_message("Syntax:");
|
|
+ irc_message(" !help // print help");
|
|
+ irc_message(" !<language> // set language for next message");
|
|
+ irc_message(" <code> // echo this code");
|
|
+ irc_message(" !<language> <code> // set language and echo code");
|
|
+ irc_message("--");
|
|
+}
|
|
+
|
|
+// XXX: msg ChanServ IDENTIFY?
|
|
+static
|
|
+void event_connect(irc_session_t * session,
|
|
+ const char * event,
|
|
+ const char * origin,
|
|
+ const char ** params,
|
|
+ unsigned int count) {
|
|
+ (void)event;
|
|
+ (void)origin;
|
|
+ (void)params;
|
|
+ (void)count;
|
|
+
|
|
+ log_notice("IRC connection secured.");
|
|
+ irc_cmd_join(session, channel, 0);
|
|
+ char * buffer;
|
|
+ asprintf(&buffer, "Joined destination channel: `%s`.", channel);
|
|
+ log_notice(buffer);
|
|
+ free(buffer);
|
|
+}
|
|
+
|
|
+static
|
|
+void event_privmsg(irc_session_t * session,
|
|
+ const char * event,
|
|
+ const char * origin,
|
|
+ const char ** params,
|
|
+ unsigned int count) {
|
|
+ (void)session;
|
|
+ (void)event;
|
|
+ (void)count;
|
|
+
|
|
+ char * const message_guard = strdup(params[1]);
|
|
+ char * message = message_guard;
|
|
+ char * terminator;
|
|
+
|
|
+ int is_code = 1;
|
|
+
|
|
+ /* Is command */
|
|
+ if (*message == '!') {
|
|
+ terminator = message;
|
|
+ while (*terminator != ' ') {
|
|
+ if (*terminator == '\0') {
|
|
+ is_code = 0;
|
|
+ break;
|
|
+ }
|
|
+ ++terminator;
|
|
+ }
|
|
+ *terminator = '\0';
|
|
+ /* */
|
|
+ if (!strcmp(message, "!help")) {
|
|
+ irc_help();
|
|
+ goto END;
|
|
+ }
|
|
+ /* get language */
|
|
+ for (char * s = message + 1; *s != '\0'; s++) {
|
|
+ *s = toupper(*s);
|
|
+ }
|
|
+ int l = translate_language(message + 1);
|
|
+ message = terminator + 1;
|
|
+ if (l != -1) {
|
|
+ language = l;
|
|
+ syntax_count = 0;
|
|
+ syntax_functions[language]();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Is code */
|
|
+ if (is_code) {
|
|
+ request_t * request = take_request(origin, language);
|
|
+ if (!request) {
|
|
+ irc_private_message(origin, message_queue_full_message);
|
|
+ goto END;
|
|
+ }
|
|
+
|
|
+ if (request->is_active) {
|
|
+ touch_request_timer(request);
|
|
+ irc_message(syntax_highlight(message));
|
|
+ } else {
|
|
+ request->buffer[request->buffer_head++] = strdup(syntax_highlight(message));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ END:
|
|
+ free(message_guard);
|
|
+}
|
|
+
|
|
+static
|
|
+void event_channel(irc_session_t * session,
|
|
+ const char * event,
|
|
+ const char * origin,
|
|
+ const char ** params,
|
|
+ unsigned int count) {
|
|
+ (void) session;
|
|
+ (void) event;
|
|
+ (void) origin;
|
|
+ (void) count;
|
|
+
|
|
+ const char * const message = params[1];
|
|
+
|
|
+ if (!strncmp(message, "!help", sizeof("!help")-1)) {
|
|
+ irc_help();
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+int connect_bot(const char * const server, const short port) {
|
|
+ memset(&callbacks, 0, sizeof(callbacks));
|
|
+ callbacks.event_connect = event_connect;
|
|
+ callbacks.event_privmsg = event_privmsg;
|
|
+ callbacks.event_channel = event_channel;
|
|
+ session = irc_create_session(&callbacks);
|
|
+
|
|
+ if (!session) {
|
|
+ log_error("Error creating IRC session.");
|
|
+ return 1;
|
|
+ } else {
|
|
+ log_notice("IRC Session initialized.");
|
|
+ }
|
|
+
|
|
+ for (unsigned int i = 0; i < message_queue_size; i++) {
|
|
+ request_queue[i] = &request_queue__[i];
|
|
+ init_request(request_queue[i]);
|
|
+ }
|
|
+ signal(SIGALRM, on_message_timeout);
|
|
+
|
|
+ irc_connect(session,
|
|
+ server,
|
|
+ port,
|
|
+ config_password,
|
|
+ config_username,
|
|
+ config_username,
|
|
+ config_username
|
|
+ );
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int connection_loop(void) {
|
|
+ if (irc_run(session) != 0) {
|
|
+ log_error("Error running IRC session\n"
|
|
+ "Possible issue: bad URL, no network connection,"
|
|
+ "bad port, or refused connection.");
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
diff --git a/source/bot.h b/source/bot.h
|
|
index 76d5512..c89987c 100644
|
|
--- a/source/bot.h
|
|
+++ b/source/bot.h
|
|
@@ -8,304 +8,19 @@
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
|
|
+#include "syntax.h"
|
|
+
|
|
extern syntax_setter_t syntax_functions[];
|
|
|
|
static irc_session_t * session;
|
|
static irc_callbacks_t callbacks;
|
|
|
|
-static inline
|
|
-void irc_message(const char * const message) {
|
|
- irc_cmd_msg(session, channel, message);
|
|
-}
|
|
-
|
|
-static inline
|
|
-void irc_private_message(const char * const user, const char * const message) {
|
|
- irc_cmd_msg(session, user, message);
|
|
-}
|
|
-
|
|
-static inline
|
|
-char * username_root(const char * const fullname){
|
|
- char * r = (char *)fullname;
|
|
- while (*(r++) != '!') { ; }
|
|
- asprintf(&r, "From %.*s:", (int)(r - fullname)-1, fullname);
|
|
- return r;
|
|
-}
|
|
-
|
|
-typedef struct {
|
|
- int is_active;
|
|
- char * user;
|
|
- language_t language;
|
|
- struct itimerval timer;
|
|
- char * buffer[128]; // XXX: no overflow detection/avertion
|
|
- unsigned int buffer_head; // is implemented on this bunch
|
|
-} request_t;
|
|
-
|
|
-void init_request(request_t * request) {
|
|
- request->is_active = 0;
|
|
- request->timer.it_value.tv_sec = 0;
|
|
- request->timer.it_value.tv_usec = 0;
|
|
- request->timer.it_interval.tv_sec = 0;
|
|
- request->timer.it_interval.tv_usec = 0;
|
|
- request->buffer_head = 0;
|
|
-}
|
|
-
|
|
-request_t request_queue__[message_queue_size];
|
|
-request_t * request_queue[message_queue_size];
|
|
-unsigned int request_queue_head = 0;
|
|
-
|
|
-static inline
|
|
-void touch_request_timer(request_t * request) {
|
|
- request->timer.it_value.tv_sec = message_timeout;
|
|
- setitimer(ITIMER_REAL, &(request->timer), NULL);
|
|
-}
|
|
-
|
|
-void activate_request(request_t * request) {
|
|
- request->is_active = 1;
|
|
-
|
|
- /* message header */
|
|
- char * short_name = username_root(request->user);
|
|
- irc_message(short_name);
|
|
- free(short_name);
|
|
-}
|
|
-
|
|
-request_t * take_request(const char * const user, language_t language) {
|
|
- for (unsigned int i = 0; i < request_queue_head; i++) {
|
|
- if(!strcmp(request_queue[i]->user, user)) {
|
|
- return request_queue[i];
|
|
- }
|
|
- }
|
|
-
|
|
- if (request_queue_head == message_queue_size) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- request_t * request = request_queue[request_queue_head];
|
|
-
|
|
- request->language = language;
|
|
- request->user = strdup(user);
|
|
-
|
|
- if (request_queue_head == 0) {
|
|
- activate_request(request);
|
|
- }
|
|
-
|
|
- ++request_queue_head;
|
|
-
|
|
- char * log_message;
|
|
- asprintf(&log_message, "Took message: %p (%d)", (void*)request, request_queue_head);
|
|
- log_notice(log_message);
|
|
- free(log_message);
|
|
-
|
|
- return request;
|
|
-}
|
|
-
|
|
-void drop_reqest() {
|
|
- request_t * request = request_queue[0];
|
|
-
|
|
- if (message_queue_size > 1) {
|
|
- for (unsigned int i = 0; i < request_queue_head; i++) {
|
|
- request_queue[i] = request_queue[i+1];
|
|
- }
|
|
- request_queue[request_queue_head] = request;
|
|
- }
|
|
-
|
|
- --request_queue_head;
|
|
-
|
|
- request->is_active = 0;
|
|
- free(request->user);
|
|
-
|
|
- if (request_queue_head) {
|
|
- activate_request(request_queue[0]);
|
|
- for (unsigned int i = 0; i < request_queue[0]->buffer_head; i++) {
|
|
- irc_message(request_queue[0]->buffer[i]);
|
|
- free(request_queue[0]->buffer[i]);
|
|
- }
|
|
- request_queue[0]->buffer_head = 0;
|
|
- touch_request_timer(request_queue[0]);
|
|
- }
|
|
-
|
|
- char * log_message;
|
|
- asprintf(&log_message, "Dropped message: %p (%d)", (void*)request, request_queue_head);
|
|
- log_notice(log_message);
|
|
- free(log_message);
|
|
-}
|
|
-
|
|
-void on_message_timeout(int unused) {
|
|
- (void)unused;
|
|
-
|
|
- /* message footer */
|
|
- irc_message("--");
|
|
-
|
|
- drop_reqest(request_queue);
|
|
-}
|
|
-
|
|
-static
|
|
-language_t translate_language(const char * const language) {
|
|
- if (!strcmp(language, "C") || !strcmp(language, "C++")) {
|
|
- return C;
|
|
- } else if (!strcmp(language, "ADA")) {
|
|
- return ADA;
|
|
- }
|
|
- return -1;
|
|
-}
|
|
-
|
|
-static
|
|
-void irc_help() {
|
|
- irc_message(PROGRAM_NAME " "
|
|
-#include "version.inc"
|
|
- );
|
|
- irc_message(PROGRAM_NAME " is a code highlighting IRC bot."
|
|
- " You may direct message it with your code or commands."
|
|
- );
|
|
- irc_message("Syntax:");
|
|
- irc_message(" !help // print help");
|
|
- irc_message(" !<language> // set language for next message");
|
|
- irc_message(" <code> // echo this code");
|
|
- irc_message(" !<language> <code> // set language and echo code");
|
|
- irc_message("--");
|
|
-}
|
|
-
|
|
-// XXX: msg ChanServ IDENTIFY?
|
|
-static
|
|
-void event_connect(irc_session_t * session,
|
|
- const char * event,
|
|
- const char * origin,
|
|
- const char ** params,
|
|
- unsigned int count) {
|
|
- (void)event;
|
|
- (void)origin;
|
|
- (void)params;
|
|
- (void)count;
|
|
-
|
|
- log_notice("IRC connection secured.");
|
|
- irc_cmd_join(session, channel, 0);
|
|
- char * buffer;
|
|
- asprintf(&buffer, "Joined destination channel: `%s`.", channel);
|
|
- log_notice(buffer);
|
|
- free(buffer);
|
|
-}
|
|
-
|
|
-static
|
|
-void event_privmsg(irc_session_t * session,
|
|
- const char * event,
|
|
- const char * origin,
|
|
- const char ** params,
|
|
- unsigned int count) {
|
|
- (void)session;
|
|
- (void)event;
|
|
- (void)count;
|
|
-
|
|
- char * const message_guard = strdup(params[1]);
|
|
- char * message = message_guard;
|
|
- char * terminator;
|
|
- int is_code = 1;
|
|
-
|
|
- /* Is command */
|
|
- if (*message == '!') {
|
|
- terminator = message;
|
|
- while (*terminator != ' ') {
|
|
- if (*terminator == '\0') {
|
|
- is_code = 0;
|
|
- break;
|
|
- }
|
|
- ++terminator;
|
|
- }
|
|
- *terminator = '\0';
|
|
- /* */
|
|
- if (!strcmp(message, "!help")) {
|
|
- irc_help();
|
|
- goto END;
|
|
- }
|
|
- /* get language */
|
|
- for (char * s = message + 1; *s != '\0'; s++) {
|
|
- *s = toupper(*s);
|
|
- }
|
|
- int l = translate_language(message + 1);
|
|
- message = terminator + 1;
|
|
- if (l != -1) {
|
|
- language = l;
|
|
- syntax_count = 0;
|
|
- syntax_functions[language]();
|
|
- }
|
|
- }
|
|
-
|
|
- /* Is code */
|
|
- if (is_code) {
|
|
- request_t * request = take_request(origin, language);
|
|
- if (!request) {
|
|
- irc_private_message(origin, message_queue_full_message);
|
|
- goto END;
|
|
- }
|
|
-
|
|
- if (request->is_active) {
|
|
- touch_request_timer(request);
|
|
- irc_message(syntax_highlight(message));
|
|
- } else {
|
|
- request->buffer[request->buffer_head++] = strdup(syntax_highlight(message));
|
|
- }
|
|
- }
|
|
-
|
|
- END:
|
|
- free(message_guard);
|
|
-}
|
|
-
|
|
-static
|
|
-void event_channel(irc_session_t * session,
|
|
- const char * event,
|
|
- const char * origin,
|
|
- const char ** params,
|
|
- unsigned int count) {
|
|
- (void) session;
|
|
- (void) event;
|
|
- (void) origin;
|
|
- (void) count;
|
|
-
|
|
- const char * const message = params[1];
|
|
-
|
|
- if (!strncmp(message, "!help", sizeof("!help")-1)) {
|
|
- irc_help();
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
-int connect_bot(const char * const server, const short port) {
|
|
- memset(&callbacks, 0, sizeof(callbacks));
|
|
- callbacks.event_connect = event_connect;
|
|
- callbacks.event_privmsg = event_privmsg;
|
|
- callbacks.event_channel = event_channel;
|
|
- session = irc_create_session(&callbacks);
|
|
-
|
|
- if (!session) {
|
|
- log_error("Error creating IRC session.");
|
|
- return 1;
|
|
- } else {
|
|
- log_notice("IRC Session initialized.");
|
|
- }
|
|
-
|
|
- for (unsigned int i = 0; i < message_queue_size; i++) {
|
|
- request_queue[i] = &request_queue__[i];
|
|
- init_request(request_queue[i]);
|
|
- }
|
|
- signal(SIGALRM, on_message_timeout);
|
|
-
|
|
- irc_connect(session,
|
|
- server,
|
|
- port,
|
|
- password,
|
|
- username,
|
|
- username,
|
|
- username
|
|
- );
|
|
-
|
|
- return 0;
|
|
-}
|
|
+extern char * channel;
|
|
+extern char * server;
|
|
+extern char * port;
|
|
|
|
-int connection_loop(void) {
|
|
- if (irc_run(session) != 0) {
|
|
- log_error("Error running IRC session\n"
|
|
- "Possible issue: bad URL, no network connection, bad port, refused connection.");
|
|
- }
|
|
- return 0;
|
|
-}
|
|
+extern int connect_bot(const char * const server, const short port);
|
|
+extern int connection_loop(void);
|
|
|
|
#define BOT_H
|
|
#endif
|
|
diff --git a/source/config.inc b/source/config.inc
|
|
index a9de7c4..3ae29a3 100644
|
|
--- a/source/config.inc
|
|
+++ b/source/config.inc
|
|
@@ -1,12 +1,17 @@
|
|
#ifndef CONFIG_INC
|
|
|
|
-const char * const username = PROGRAM_NAME;
|
|
-const char * const password = "";
|
|
-const int message_timeout = 3;
|
|
-const char * const message_queue_full_message = "Air space too crowded in this area.";
|
|
+#ifndef PROGRAM_NAME
|
|
+# define PROGRAM_NAME "hibot"
|
|
+#endif
|
|
+
|
|
#define message_queue_size 3
|
|
#define DEFAULT_LANGUAGE C
|
|
#define LOG_FILE stdout
|
|
|
|
+#define config_username PROGRAM_NAME
|
|
+#define config_password ""
|
|
+#define message_timeout 3
|
|
+#define message_queue_full_message "Air space too crowded in this area."
|
|
+
|
|
#define CONFIG_INC
|
|
#endif
|
|
diff --git a/source/log.c b/source/log.c
|
|
new file mode 100644
|
|
index 0000000..9e9c078
|
|
--- /dev/null
|
|
+++ b/source/log.c
|
|
@@ -0,0 +1,19 @@
|
|
+#include "log.h"
|
|
+
|
|
+FILE * log_file;
|
|
+
|
|
+static
|
|
+void log(const char * const message, const char * const color) {
|
|
+ fputs(color, log_file);
|
|
+ fputs(message, log_file);
|
|
+ fputs("\033[0m\n", log_file);
|
|
+ fflush(log_file);
|
|
+}
|
|
+
|
|
+void log_notice(const char * const message) {
|
|
+ log("", message);
|
|
+}
|
|
+
|
|
+void log_error(const char * const message) {
|
|
+ log("\033[33m", message);
|
|
+}
|
|
diff --git a/source/log.h b/source/log.h
|
|
index 8e894b9..f983bc3 100644
|
|
--- a/source/log.h
|
|
+++ b/source/log.h
|
|
@@ -2,23 +2,10 @@
|
|
|
|
#include <stdio.h>
|
|
|
|
-FILE * log_file;
|
|
+extern FILE * log_file;
|
|
|
|
-static
|
|
-void log(const char * const message, const char * const color) {
|
|
- fputs(color, log_file);
|
|
- fputs(message, log_file);
|
|
- fputs("\033[0m\n", log_file);
|
|
- fflush(log_file);
|
|
-}
|
|
-
|
|
-void log_notice(const char * const message) {
|
|
- log("", message);
|
|
-}
|
|
-
|
|
-void log_error(const char * const message) {
|
|
- log("\033[33m", message);
|
|
-}
|
|
+extern void log_notice(const char * const message);
|
|
+extern void log_error(const char * const message);
|
|
|
|
#define LOG_H
|
|
#endif
|
|
diff --git a/source/main.c b/source/main.c
|
|
index c8d1872..33d4ade 100644
|
|
--- a/source/main.c
|
|
+++ b/source/main.c
|
|
@@ -1,31 +1,9 @@
|
|
-#define PROGRAM_NAME "hibot"
|
|
-#define _GNU_SOURCE
|
|
-
|
|
#include "config.inc"
|
|
|
|
-char * channel;
|
|
-char * server;
|
|
-char * port;
|
|
-
|
|
-typedef enum {
|
|
- C,
|
|
- ADA,
|
|
-} language_t;
|
|
-
|
|
-language_t language = DEFAULT_LANGUAGE;
|
|
-
|
|
-typedef void (*syntax_setter_t)(void);
|
|
-
|
|
#include "log.h"
|
|
#include "syntax.h"
|
|
#include "bot.h"
|
|
|
|
-syntax_setter_t syntax_functions[] = {
|
|
- [C] = &syntax_c,
|
|
- [ADA] = &syntax_ada,
|
|
-};
|
|
-
|
|
-
|
|
const char help_message[] =
|
|
PROGRAM_NAME " <server>:<port> <channel>"
|
|
;
|
|
@@ -38,11 +16,10 @@ signed main(int argc, char * * argv) {
|
|
channel = argv[2];
|
|
server = strdup(argv[1]);
|
|
port = strchr(server, ':');
|
|
- if (port) {
|
|
- *port = '\0';
|
|
- } else {
|
|
+ if (!port) {
|
|
goto USAGE_ERROR;
|
|
}
|
|
+ *port = '\0';
|
|
++port;
|
|
int port_i = 0;
|
|
if(!sscanf(port, "%hd", &port_i)) {
|
|
diff --git a/source/syntax.c b/source/syntax.c
|
|
new file mode 100644
|
|
index 0000000..557279d
|
|
--- /dev/null
|
|
+++ b/source/syntax.c
|
|
@@ -0,0 +1,322 @@
|
|
+#include "config.inc"
|
|
+
|
|
+#include "syntax.h"
|
|
+
|
|
+language_t language = DEFAULT_LANGUAGE;
|
|
+
|
|
+size_t syntax_count = 0;
|
|
+
|
|
+syntax_setter_t syntax_functions[] = {
|
|
+ [C] = &syntax_c,
|
|
+ [ADA] = &syntax_ada,
|
|
+};
|
|
+
|
|
+static int syntax_enrange [SYNTAX_LIMIT];
|
|
+static int syntax_derange [SYNTAX_LIMIT];
|
|
+static char syntax_begin [SYNTAX_LIMIT] [96];
|
|
+static char syntax_end [SYNTAX_LIMIT] [96];
|
|
+static char syntax_escape [SYNTAX_LIMIT];
|
|
+static char * syntax_colour [SYNTAX_LIMIT];
|
|
+
|
|
+static int character_compare_array (char character, char * character_array) {
|
|
+ size_t i = 0;
|
|
+
|
|
+ do {
|
|
+ if (character == character_array [i]) {
|
|
+ return (1);
|
|
+ }
|
|
+ } while (++i != strlen (character_array));
|
|
+
|
|
+ return (0);
|
|
+}
|
|
+
|
|
+static void syntax_rule (int enrange,
|
|
+ int derange,
|
|
+ char * begin,
|
|
+ char * end,
|
|
+ char escape,
|
|
+ char * colour) {
|
|
+ if (syntax_count >= SYNTAX_LIMIT) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ strncpy (syntax_begin [syntax_count], begin, 96);
|
|
+ strncpy (syntax_end [syntax_count], end, 96);
|
|
+
|
|
+ syntax_enrange [syntax_count] = enrange;
|
|
+ syntax_derange [syntax_count] = derange;
|
|
+ syntax_escape [syntax_count] = escape;
|
|
+ syntax_colour [syntax_count] = colour;
|
|
+
|
|
+ ++syntax_count;
|
|
+}
|
|
+
|
|
+static size_t syntax_loop (char * string,
|
|
+ size_t * length) {
|
|
+ size_t offset, subset, select;
|
|
+
|
|
+ for (select = offset = 0; select != syntax_count; ++select) {
|
|
+ if (syntax_enrange [select] == 0) {
|
|
+ if (syntax_derange [select] == 0) {
|
|
+ if (strncmp (string, syntax_begin [select], strlen (syntax_begin [select])) == 0) {
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ if ((strncmp (string, syntax_begin [select], strlen (syntax_begin [select])) == 0)
|
|
+ && (character_compare_array (string [offset + strlen (syntax_begin [select])], syntax_end [select]) == 1)) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ for (subset = 0; subset != strlen (syntax_begin [select]); ++subset) {
|
|
+ if (string [offset] == syntax_begin [select] [subset]) {
|
|
+ goto selected;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ selected:
|
|
+
|
|
+ if (select >= syntax_count) {
|
|
+ * length = 1;
|
|
+ return (select);
|
|
+ }
|
|
+
|
|
+ for (offset = 1; string [offset - 1] != '\0'; ++offset) {
|
|
+ if (string [offset] == syntax_escape [select]) {
|
|
+ ++offset;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (syntax_derange [select] == 0) {
|
|
+ if (strncmp (& string [offset], syntax_end [select], strlen (syntax_end [select])) == 0) {
|
|
+ * length = offset + strlen (syntax_end [select]);
|
|
+ goto finished;
|
|
+ }
|
|
+ } else {
|
|
+ subset = 0;
|
|
+ if (strcmp (syntax_end [select], "")) {
|
|
+ do {
|
|
+ if (string [offset] == syntax_end [select] [subset]) {
|
|
+ * length = offset;
|
|
+ goto finished;
|
|
+ }
|
|
+ } while (++subset != strlen (syntax_end [select]));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ finished:
|
|
+
|
|
+ return (select);
|
|
+}
|
|
+
|
|
+void syntax_c (void) {
|
|
+ char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
|
|
+
|
|
+ char * keywords [] = {
|
|
+ "register", "volatile", "auto", "const", "static", "extern", "if", "else",
|
|
+ "do", "while", "for", "continue", "switch", "case", "default", "break",
|
|
+ "enum", "union", "struct", "typedef", "goto", "void", "return", "sizeof",
|
|
+ "char", "short", "int", "long", "signed", "unsigned", "float", "double"
|
|
+ };
|
|
+
|
|
+ size_t word;
|
|
+
|
|
+ syntax_rule (0, 0, "/*", "*/", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "//", "\n", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "#", "\n", '\\', COLOUR_YELLOW);
|
|
+ syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
+ syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
+
|
|
+ for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
+ syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
+ }
|
|
+
|
|
+ syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
+ syntax_rule (1, 0, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN);
|
|
+
|
|
+ syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
+ syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
+}
|
|
+
|
|
+void syntax_ada (void) {
|
|
+ char * separators = ".,:;<=>+-*/&|()\" \t\r\n";
|
|
+
|
|
+ char * keywords [] = {
|
|
+ "abort", "else", "new", "return", "abs", "elsif", "not", "reverse",
|
|
+ "abstract", "end", "null", "accept", "entry", "select", "access", "of",
|
|
+ "separate", "aliased", "exit", "or", "some", "all", "others", "subtype",
|
|
+ "and", "for", "out", "array", "function", "at", "tagged", "generic",
|
|
+ "package", "task", "begin", "goto", "pragma", "body", "private", "then",
|
|
+ "type", "case", "in", "constant", "until", "is", "raise", "use",
|
|
+ "if", "declare", "range", "delay", "limited", "record", "when", "delta",
|
|
+ "loop", "rem", "while", "digits", "renames", "with", "do", "mod",
|
|
+ "requeue", "xor", "procedure", "protected", "interface", "synchronized", "exception", "overriding",
|
|
+ "terminate"
|
|
+ };
|
|
+
|
|
+ size_t word;
|
|
+
|
|
+ syntax_rule (0, 0, "--", "\n", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
+ syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
+
|
|
+ for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
+ syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
+ }
|
|
+
|
|
+ syntax_rule (1, 0, "()", "", '\0', COLOUR_BLUE);
|
|
+ syntax_rule (1, 0, ".,:;<=>+-*/&|'", "", '\0', COLOUR_CYAN);
|
|
+
|
|
+ syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
+ syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
+}
|
|
+
|
|
+void syntax_cpp (void) {
|
|
+ char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
|
|
+
|
|
+ char * keywords [] = {
|
|
+ "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept",
|
|
+ "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char",
|
|
+ "char8_t", "char16_t", "char32_t", "class", "compl", "concept", "const", "consteval",
|
|
+ "constexpr", "constinit", "const_cast", "continue", "co_await", "co_return", "co_yield", "decltype",
|
|
+ "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit",
|
|
+ "export", "extern", "false", "float", "for", "friend", "goto", "if",
|
|
+ "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
|
|
+ "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public",
|
|
+ "reflexpr", "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof",
|
|
+ "static", "static_assert", "static_cast", "struct", "switch", "synchronized", "template", "this",
|
|
+ "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union",
|
|
+ "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor",
|
|
+ "xor_eq", "final", "override", "import", "module", "transaction_safe"
|
|
+ };
|
|
+
|
|
+ char * specials [] = {
|
|
+ "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
|
|
+ "FILE", "std", "typeof", "cout", "cin", "endl", "timespec", "tm"
|
|
+ /* TODO: I don't really care about this, but some people do, Anon please add what you find interesting in here... */
|
|
+ };
|
|
+
|
|
+ size_t word;
|
|
+
|
|
+ syntax_rule (0, 0, "/*", "*/", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "//", "\n", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "#", "\n", '\\', COLOUR_YELLOW);
|
|
+ syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
+ syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
+
|
|
+ for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
+ syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
+ }
|
|
+
|
|
+ for (word = 0; word != sizeof (specials) / sizeof (specials [0]); ++word) {
|
|
+ syntax_rule (0, 1, specials [word], separators, '\0', COLOUR_CYAN);
|
|
+ }
|
|
+
|
|
+ syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
+ syntax_rule (1, 0, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN);
|
|
+
|
|
+ syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
+ syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
+}
|
|
+
|
|
+void syntax_fasm (void) {
|
|
+ char * separators = ".,+-=:;(){}[]%$<> \t\r\n";
|
|
+
|
|
+ char * instructions [] = {
|
|
+ "mov", "movabs", "movapd", "movaps", "movebe", "movsd", "movsx", "movzx",
|
|
+ "movsxd", "movd", "movq", "movs", "movsb", "movsw", "movsd", "movsq",
|
|
+ "cmovmp", "cmovrcxz", "cmovc", "cmovnc", "cmove", "cmovne", "cmovz", "cmovnz",
|
|
+ "cmovg", "cmovng", "cmovge", "cmovnge", "cmovl", "cmovnl", "cmovle", "cmovnle",
|
|
+ "cmova", "cmovna", "cmovae", "cmovnae", "cmovb", "cmovnb", "cmovbe", "cmovnbe",
|
|
+ "cmovs", "cmovns", "cmovo", "cmovno", "cmovp", "cmovnp", "cmovpo", "cmovpe",
|
|
+ "cmp", "cmps", "cmpsb", "cmpsw", "cmpsd", "cmpsq", "cmpxchg", "lea",
|
|
+ "monitor", "cpuid", "in", "out", "syscall", "sysenter", "sysret", "sysexit",
|
|
+ "swap", "bswap", "pop", "push", "call", "ret", "enter", "leave",
|
|
+ "and", "or", "not", "neg", "sal", "sar", "shl", "shr",
|
|
+ "inc", "dec", "add", "sub", "mul", "div", "imul", "idiv",
|
|
+ "nop", "fnop", "adc", "sbb", "aaa", "aas", "aam", "aad",
|
|
+ "jmp", "jrcxz", "jc", "jnc", "je", "jne", "jz", "jnz",
|
|
+ "jg", "jng", "jge", "jnge", "jl", "jnl", "jle", "jnle",
|
|
+ "ja", "jna", "jae", "jnae", "jb", "jnb", "jbe", "jnbe",
|
|
+ "js", "jns", "jo", "jno", "jp", "jnp", "jpo", "jpe",
|
|
+ "rep", "repe", "repz", "repne", "repnz", "loop", "loope", "loopne"
|
|
+ };
|
|
+
|
|
+ char * registers [] = {
|
|
+ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
|
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
|
+ "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
|
|
+ "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
|
|
+ "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
|
|
+ "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
|
|
+ "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
|
|
+ "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b",
|
|
+ "ah", "ch", "dh", "bh"
|
|
+ };
|
|
+
|
|
+ char * keywords [] = {
|
|
+ "format", "executable", "readable", "writable", "segment", "sector", "entry", "macro",
|
|
+ "db", "dw", "dd", "dq", "rb", "rw", "rd", "rq"
|
|
+ };
|
|
+
|
|
+ size_t word;
|
|
+
|
|
+ syntax_rule (0, 0, ";", "\n", '\0', COLOUR_GREY);
|
|
+ syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
+ syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
+
|
|
+ for (word = 0; word != sizeof (instructions) / sizeof (instructions [0]); ++word) {
|
|
+ syntax_rule (0, 1, instructions [word], separators, '\0', COLOUR_YELLOW);
|
|
+ }
|
|
+
|
|
+ for (word = 0; word != sizeof (registers) / sizeof (registers [0]); ++word) {
|
|
+ syntax_rule (0, 1, registers [word], separators, '\0', COLOUR_CYAN);
|
|
+ }
|
|
+
|
|
+ for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
+ syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
+ }
|
|
+
|
|
+ syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
+ syntax_rule (1, 0, ".,+-=:;%$<>", "", '\0', COLOUR_CYAN);
|
|
+
|
|
+ syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
+ syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
+ syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
+}
|
|
+
|
|
+char * syntax_highlight (char * code) {
|
|
+ static char buffer [4096] = "";
|
|
+ static char string [4096] = "";
|
|
+
|
|
+ size_t select, length, offset;
|
|
+
|
|
+ memset (buffer, 0, sizeof (buffer));
|
|
+ memset (string, 0, sizeof (string));
|
|
+
|
|
+ strcpy (string, code);
|
|
+
|
|
+ for (offset = 0; offset < strlen (string); offset += length) {
|
|
+ select = syntax_loop (& string [offset], & length);
|
|
+
|
|
+ if (select < syntax_count) {
|
|
+ strncat (buffer, "\003", 1);
|
|
+ strncat (buffer, syntax_colour [select], 2);
|
|
+ strncat (buffer, & string [offset], length);
|
|
+ strncat (buffer, "\017", 1);
|
|
+ } else {
|
|
+ strncat (buffer, & string [offset], length);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (buffer);
|
|
+}
|
|
diff --git a/source/syntax.h b/source/syntax.h
|
|
index 502d202..81ddc7b 100644
|
|
--- a/source/syntax.h
|
|
+++ b/source/syntax.h
|
|
@@ -1,3 +1,5 @@
|
|
+#ifndef SYNTAX_H
|
|
+
|
|
#include <string.h>
|
|
|
|
#define SYNTAX_LIMIT (256)
|
|
@@ -14,319 +16,25 @@
|
|
#define COLOUR_PINK ("13")
|
|
#define COLOUR_GREY ("14")
|
|
|
|
+typedef enum {
|
|
+ C,
|
|
+ ADA,
|
|
+} language_t;
|
|
+
|
|
+typedef void (*syntax_setter_t)(void);
|
|
+
|
|
extern void syntax_c (void);
|
|
extern void syntax_ada (void);
|
|
+extern void syntax_fasm (void);
|
|
+extern void syntax_cpp (void);
|
|
|
|
extern char * syntax_highlight (char * string);
|
|
|
|
-static size_t syntax_count = 0;
|
|
-
|
|
-static int syntax_enrange [SYNTAX_LIMIT];
|
|
-static int syntax_derange [SYNTAX_LIMIT];
|
|
-static char syntax_begin [SYNTAX_LIMIT] [96];
|
|
-static char syntax_end [SYNTAX_LIMIT] [96];
|
|
-static char syntax_escape [SYNTAX_LIMIT];
|
|
-static char * syntax_colour [SYNTAX_LIMIT];
|
|
-
|
|
-static int character_compare_array (char character, char * character_array) {
|
|
- size_t i = 0;
|
|
-
|
|
- do {
|
|
- if (character == character_array [i]) {
|
|
- return (1);
|
|
- }
|
|
- } while (++i != strlen (character_array));
|
|
-
|
|
- return (0);
|
|
-}
|
|
-
|
|
-static void syntax_rule (int enrange,
|
|
- int derange,
|
|
- char * begin,
|
|
- char * end,
|
|
- char escape,
|
|
- char * colour) {
|
|
- if (syntax_count >= SYNTAX_LIMIT) {
|
|
- return;
|
|
- }
|
|
-
|
|
- strncpy (syntax_begin [syntax_count], begin, 96);
|
|
- strncpy (syntax_end [syntax_count], end, 96);
|
|
-
|
|
- syntax_enrange [syntax_count] = enrange;
|
|
- syntax_derange [syntax_count] = derange;
|
|
- syntax_escape [syntax_count] = escape;
|
|
- syntax_colour [syntax_count] = colour;
|
|
-
|
|
- ++syntax_count;
|
|
-}
|
|
-
|
|
-static size_t syntax_loop (char * string,
|
|
- size_t * length) {
|
|
- size_t offset, subset, select;
|
|
-
|
|
- for (select = offset = 0; select != syntax_count; ++select) {
|
|
- if (syntax_enrange [select] == 0) {
|
|
- if (syntax_derange [select] == 0) {
|
|
- if (strncmp (string, syntax_begin [select], strlen (syntax_begin [select])) == 0) {
|
|
- break;
|
|
- }
|
|
- } else {
|
|
- if ((strncmp (string, syntax_begin [select], strlen (syntax_begin [select])) == 0)
|
|
- && (character_compare_array (string [offset + strlen (syntax_begin [select])], syntax_end [select]) == 1)) {
|
|
- break;
|
|
- }
|
|
- }
|
|
- } else {
|
|
- for (subset = 0; subset != strlen (syntax_begin [select]); ++subset) {
|
|
- if (string [offset] == syntax_begin [select] [subset]) {
|
|
- goto selected;
|
|
- }
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- selected:
|
|
-
|
|
- if (select >= syntax_count) {
|
|
- * length = 1;
|
|
- return (select);
|
|
- }
|
|
-
|
|
- for (offset = 1; string [offset - 1] != '\0'; ++offset) {
|
|
- if (string [offset] == syntax_escape [select]) {
|
|
- ++offset;
|
|
- continue;
|
|
- }
|
|
-
|
|
- if (syntax_derange [select] == 0) {
|
|
- if (strncmp (& string [offset], syntax_end [select], strlen (syntax_end [select])) == 0) {
|
|
- * length = offset + strlen (syntax_end [select]);
|
|
- goto finished;
|
|
- }
|
|
- } else {
|
|
- subset = 0;
|
|
- if (strcmp (syntax_end [select], "") == 0) {
|
|
- break;
|
|
- } do {
|
|
- if (string [offset] == syntax_end [select] [subset]) {
|
|
- * length = offset;
|
|
- goto finished;
|
|
- }
|
|
- } while (++subset != strlen (syntax_end [select]));
|
|
- }
|
|
- }
|
|
-
|
|
- finished:
|
|
-
|
|
- return (select);
|
|
-}
|
|
-
|
|
-void syntax_c (void) {
|
|
- char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
|
|
-
|
|
- char * keywords [] = {
|
|
- "register", "volatile", "auto", "const", "static", "extern", "if", "else",
|
|
- "do", "while", "for", "continue", "switch", "case", "default", "break",
|
|
- "enum", "union", "struct", "typedef", "goto", "void", "return", "sizeof",
|
|
- "char", "short", "int", "long", "signed", "unsigned", "float", "double"
|
|
- };
|
|
-
|
|
- size_t word;
|
|
-
|
|
- syntax_rule (0, 0, "/*", "*/", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "//", "\n", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "#", "\n", '\\', COLOUR_YELLOW);
|
|
- syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
- syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
-
|
|
- for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
- syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
- }
|
|
-
|
|
- syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
- syntax_rule (1, 0, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN);
|
|
-
|
|
- syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
- syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
-}
|
|
-
|
|
-void syntax_ada (void) {
|
|
- char * separators = ".,:;<=>+-*/&|()\" \t\r\n";
|
|
-
|
|
- char * keywords [] = {
|
|
- "abort", "else", "new", "return", "abs", "elsif", "not", "reverse",
|
|
- "abstract", "end", "null", "accept", "entry", "select", "access", "of",
|
|
- "separate", "aliased", "exit", "or", "some", "all", "others", "subtype",
|
|
- "and", "for", "out", "array", "function", "at", "tagged", "generic",
|
|
- "package", "task", "begin", "goto", "pragma", "body", "private", "then",
|
|
- "type", "case", "in", "constant", "until", "is", "raise", "use",
|
|
- "if", "declare", "range", "delay", "limited", "record", "when", "delta",
|
|
- "loop", "rem", "while", "digits", "renames", "with", "do", "mod",
|
|
- "requeue", "xor", "procedure", "protected", "interface", "synchronized", "exception", "overriding",
|
|
- "terminate"
|
|
- };
|
|
-
|
|
- size_t word;
|
|
-
|
|
- syntax_rule (0, 0, "--", "\n", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
- syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
-
|
|
- for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
- syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
- }
|
|
-
|
|
- syntax_rule (1, 0, "()", "", '\0', COLOUR_BLUE);
|
|
- syntax_rule (1, 0, ".,:;<=>+-*/&|'", "", '\0', COLOUR_CYAN);
|
|
-
|
|
- syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
- syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
-}
|
|
-
|
|
-void syntax_cpp (void) {
|
|
- char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
|
|
-
|
|
- char * keywords [] = {
|
|
- "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept",
|
|
- "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char",
|
|
- "char8_t", "char16_t", "char32_t", "class", "compl", "concept", "const", "consteval",
|
|
- "constexpr", "constinit", "const_cast", "continue", "co_await", "co_return", "co_yield", "decltype",
|
|
- "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit",
|
|
- "export", "extern", "false", "float", "for", "friend", "goto", "if",
|
|
- "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
|
|
- "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public",
|
|
- "reflexpr", "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof",
|
|
- "static", "static_assert", "static_cast", "struct", "switch", "synchronized", "template", "this",
|
|
- "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union",
|
|
- "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor",
|
|
- "xor_eq", "final", "override", "import", "module", "transaction_safe"
|
|
- };
|
|
-
|
|
- char * specials [] = {
|
|
- "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
|
|
- "FILE", "std", "typeof", "cout", "cin", "endl", "timespec", "tm"
|
|
- /* TODO: I don't really care about this, but some people do, Anon please add what you find interesting in here... */
|
|
- };
|
|
-
|
|
- size_t word;
|
|
-
|
|
- syntax_rule (0, 0, "/*", "*/", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "//", "\n", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "#", "\n", '\\', COLOUR_YELLOW);
|
|
- syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
- syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
-
|
|
- for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
- syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
- }
|
|
-
|
|
- for (word = 0; word != sizeof (specials) / sizeof (specials [0]); ++word) {
|
|
- syntax_rule (0, 1, specials [word], separators, '\0', COLOUR_CYAN);
|
|
- }
|
|
-
|
|
- syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
- syntax_rule (1, 0, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN);
|
|
-
|
|
- syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
- syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
-}
|
|
-
|
|
-void syntax_fasm (void) {
|
|
- char * separators = ".,+-=:;(){}[]%$<> \t\r\n";
|
|
-
|
|
- char * instructions [] = {
|
|
- "mov", "movabs", "movapd", "movaps", "movebe", "movsd", "movsx", "movzx",
|
|
- "movsxd", "movd", "movq", "movs", "movsb", "movsw", "movsd", "movsq",
|
|
- "cmovmp", "cmovrcxz", "cmovc", "cmovnc", "cmove", "cmovne", "cmovz", "cmovnz",
|
|
- "cmovg", "cmovng", "cmovge", "cmovnge", "cmovl", "cmovnl", "cmovle", "cmovnle",
|
|
- "cmova", "cmovna", "cmovae", "cmovnae", "cmovb", "cmovnb", "cmovbe", "cmovnbe",
|
|
- "cmovs", "cmovns", "cmovo", "cmovno", "cmovp", "cmovnp", "cmovpo", "cmovpe",
|
|
- "cmp", "cmps", "cmpsb", "cmpsw", "cmpsd", "cmpsq", "cmpxchg", "lea",
|
|
- "monitor", "cpuid", "in", "out", "syscall", "sysenter", "sysret", "sysexit",
|
|
- "swap", "bswap", "pop", "push", "call", "ret", "enter", "leave",
|
|
- "and", "or", "not", "neg", "sal", "sar", "shl", "shr",
|
|
- "inc", "dec", "add", "sub", "mul", "div", "imul", "idiv",
|
|
- "nop", "fnop", "adc", "sbb", "aaa", "aas", "aam", "aad",
|
|
- "jmp", "jrcxz", "jc", "jnc", "je", "jne", "jz", "jnz",
|
|
- "jg", "jng", "jge", "jnge", "jl", "jnl", "jle", "jnle",
|
|
- "ja", "jna", "jae", "jnae", "jb", "jnb", "jbe", "jnbe",
|
|
- "js", "jns", "jo", "jno", "jp", "jnp", "jpo", "jpe",
|
|
- "rep", "repe", "repz", "repne", "repnz", "loop", "loope", "loopne"
|
|
- };
|
|
-
|
|
- char * registers [] = {
|
|
- "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
|
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
|
- "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
|
|
- "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
|
|
- "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
|
|
- "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
|
|
- "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
|
|
- "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b",
|
|
- "ah", "ch", "dh", "bh"
|
|
- };
|
|
-
|
|
- char * keywords [] = {
|
|
- "format", "executable", "readable", "writable", "segment", "sector", "entry", "macro",
|
|
- "db", "dw", "dd", "dq", "rb", "rw", "rd", "rq"
|
|
- };
|
|
-
|
|
- size_t word;
|
|
-
|
|
- syntax_rule (0, 0, ";", "\n", '\0', COLOUR_GREY);
|
|
- syntax_rule (0, 0, "'", "'", '\\', COLOUR_PINK);
|
|
- syntax_rule (0, 0, "\"", "\"", '\\', COLOUR_PINK);
|
|
-
|
|
- for (word = 0; word != sizeof (instructions) / sizeof (instructions [0]); ++word) {
|
|
- syntax_rule (0, 1, instructions [word], separators, '\0', COLOUR_YELLOW);
|
|
- }
|
|
-
|
|
- for (word = 0; word != sizeof (registers) / sizeof (registers [0]); ++word) {
|
|
- syntax_rule (0, 1, registers [word], separators, '\0', COLOUR_CYAN);
|
|
- }
|
|
-
|
|
- for (word = 0; word != sizeof (keywords) / sizeof (keywords [0]); ++word) {
|
|
- syntax_rule (0, 1, keywords [word], separators, '\0', COLOUR_YELLOW);
|
|
- }
|
|
-
|
|
- syntax_rule (1, 0, "()[]{}", "", '\0', COLOUR_BLUE);
|
|
- syntax_rule (1, 0, ".,+-=:;%$<>", "", '\0', COLOUR_CYAN);
|
|
-
|
|
- syntax_rule (1, 1, "0123456789", separators, '\0', COLOUR_PINK);
|
|
- syntax_rule (1, 1, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE);
|
|
- syntax_rule (1, 1, "_", separators, '\0', COLOUR_WHITE);
|
|
-}
|
|
-
|
|
-char * syntax_highlight (char * code) {
|
|
- static char buffer [4096] = "";
|
|
- static char string [4096] = "";
|
|
-
|
|
- size_t select, length, offset;
|
|
-
|
|
- memset (buffer, 0, sizeof (buffer));
|
|
- memset (string, 0, sizeof (string));
|
|
-
|
|
- strcpy (string, code);
|
|
+extern size_t syntax_count;
|
|
|
|
- for (offset = 0; offset < strlen (string); offset += length) {
|
|
- select = syntax_loop (& string [offset], & length);
|
|
+extern language_t language;
|
|
|
|
- if (select < syntax_count) {
|
|
- strncat (buffer, "\003", 1);
|
|
- strncat (buffer, syntax_colour [select], 2);
|
|
- strncat (buffer, & string [offset], (size_t) length);
|
|
- strncat (buffer, "\017", 1);
|
|
- } else {
|
|
- strncat (buffer, & string [offset], (size_t) length);
|
|
- }
|
|
- }
|
|
+extern syntax_setter_t syntax_functions[];
|
|
|
|
- return (buffer);
|
|
-}
|
|
+#define SYNTAX_H
|
|
+#endif
|
|
--
|
|
2.39.2
|
|
|