aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--draw.c138
-rw-r--r--driver.c184
-rw-r--r--main.c337
-rw-r--r--sayeth.h56
4 files changed, 395 insertions, 320 deletions
diff --git a/draw.c b/draw.c
new file mode 100644
index 0000000..55c840f
--- /dev/null
+++ b/draw.c
@@ -0,0 +1,138 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "sayeth.h"
+
+size_t START_Y_BOX = 0;
+size_t START_Y_CARET = 0;
+size_t START_Y_DATA = 0;
+const char *A_TAB = " ";
+char wspace = ' ';
+char box_top_left = '\0';
+char box_top = '\0';
+char box_top_right = '\0';
+char box_side = '\0';
+char box_bottom_left = '\0';
+char box_bottom = '\0';
+char box_bottom_right = '\0';
+
+void box_draw_top(size_t y, size_t longest) {
+ repchar(wspace, y);
+ repchar(box_top_left, 1);
+ repchar(box_top, longest);
+ repchar(box_top_right, 1);
+}
+
+void box_draw_bottom(size_t y, size_t longest) {
+ repchar(wspace, y);
+ repchar(box_bottom_left, 1);
+ repchar(box_bottom, longest);
+ repchar(box_bottom_right, 1);
+}
+
+void box_draw_next_line(size_t y) {
+ repchar(wspace, y);
+ repchar(box_side, 1);
+}
+
+void box_draw_end_line(size_t longest, size_t len) {
+ repchar(wspace, longest - len);
+ repchar(box_side, 1);
+}
+
+int box_printf(const char *fmt, ...) {
+ int count;
+ va_list list;
+ va_start(list, fmt);
+ size_t len = 0;
+ char data[INPUT_BUFSIZ] = {0};
+ char output[INPUT_BUFSIZ] = {0};
+ count = vsnprintf(data, sizeof(data) - 1, fmt, list);
+
+ // convert tabs to spaces
+ for (size_t i = 0, n = 0; i < strlen(data) && n < sizeof(output); i++, n++) {
+ if (data[i] == '\t') {
+ strcat(&output[n], A_TAB);
+ n = n + strlen(A_TAB) - 1;
+ continue;
+ }
+ output[n] = data[i];
+ }
+
+ size_t longest = get_longest_line(output);
+
+ box_draw_top(START_Y_BOX, longest);
+ puts("");
+
+ for (size_t i = 0; i < strlen(output); i++) {
+ if (i == strlen(output) - 1) {
+ box_draw_end_line(longest, len);
+ continue;
+ }
+
+ if (len == 0) {
+ box_draw_next_line(START_Y_BOX);
+ }
+
+ if (output[i] == '\n') {
+ box_draw_end_line(longest, len);
+ putc('\n', stdout);
+ len = 0;
+ continue;
+ }
+
+ putc(output[i], stdout);
+
+ len++;
+ }
+ puts("");
+ box_draw_bottom(START_Y_BOX, longest);
+
+ va_end(list);
+ return count;
+}
+
+void caret_draw(char *data, size_t indent, size_t attached) {
+ if (!strlen(data))
+ return;
+
+ if (!attached)
+ repchar(wspace, START_Y_BOX);
+
+ for (size_t i = 0; i < strlen(data); i++) {
+ if (data[i] == '\\' && isalpha(data[i + 1])) {
+ i++;
+ switch (data[i]) {
+ case 'n':
+ putc('\n', stdout);
+ if (i == strlen(data) - 1)
+ continue;
+ repchar(wspace, indent);
+ continue;
+ default:
+ continue;
+ }
+ }
+ putc(data[i], stdout);
+ }
+}
+
+
+void data_draw(char *data, size_t indent) {
+ size_t len = 0;
+ for (size_t i = 0; i < strlen(data); i++) {
+ if (len == 0) {
+ repchar(wspace, indent);
+ }
+
+ if (data[i] == '\n') {
+ putc('\n', stdout);
+ len = 0;
+ continue;
+ }
+
+ putc(data[i], stdout);
+ len++;
+ }
+}
diff --git a/driver.c b/driver.c
new file mode 100644
index 0000000..e308397
--- /dev/null
+++ b/driver.c
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sayeth.h"
+
+extern size_t START_Y_BOX;
+extern size_t START_Y_CARET;
+extern size_t START_Y_DATA;
+extern const char *A_TAB;
+extern char wspace;
+extern char box_top_left;
+extern char box_top;
+extern char box_top_right;
+extern char box_side;
+extern char box_bottom_left;
+extern char box_bottom;
+extern char box_bottom_right;
+
+struct Driver **drivers = NULL;
+size_t drivers_alloc = DRIVERS_ALLOC_DEFAULT;
+size_t drivers_used = 0;
+
+struct Driver *driver_load(char *filename) {
+ FILE *fp = NULL;
+ struct Driver *driver = NULL;
+
+ driver = calloc(1, sizeof(*driver));
+ if (!driver) {
+ return NULL;
+ }
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < 9; i++) {
+ char buf[INPUT_BUFSIZ] = {0};
+ ssize_t lastpos = ftell(fp);
+ if (fgets(buf, sizeof(buf) - 1, fp) == NULL) {
+ break;
+ }
+ if (!strlen(buf) || buf[0] == '#') {
+ i--;
+ continue;
+ }
+ buf[strlen(buf) - 1] = '\0';
+ switch (i) {
+ case 0:
+ driver->name = strdup(buf);
+ if (!driver->name) {
+ fclose(fp);
+ return NULL;
+ }
+ break;
+ case 1:
+ driver->box_indent = strtol(buf, NULL, 10);
+ break;
+ case 2:
+ driver->box_elements = strdup(buf);
+ if (!driver->box_elements) {
+ fclose(fp);
+ return NULL;
+ }
+ break;
+ case 3:
+ driver->caret_pos = strtol(buf, NULL, 10);
+ break;
+ case 4:
+ driver->caret_indent = strtol(buf, NULL, 10);
+ break;
+ case 5:
+ driver->caret_attached = strtol(buf, NULL, 10);
+ break;
+ case 6:
+ driver->caret = strdup(buf);
+ if (!driver->caret) {
+ fclose(fp);
+ return NULL;
+ }
+ break;
+ case 7:
+ driver->data_indent = strtol(buf, 0, 10);
+ break;
+ case 8:
+ driver->data = calloc(DATA_BUFSIZ, sizeof(*driver->data));
+ if (!driver->data) {
+ fclose(fp);
+ return NULL;
+ }
+ // rewind to beginning of the data section
+ fseek(fp, lastpos, SEEK_SET);
+ fread(driver->data, 1, DATA_BUFSIZ - 1, fp);
+ break;
+ default:
+ break;
+ }
+ }
+ fclose(fp);
+ return driver;
+}
+
+int driver_register(struct Driver *driver) {
+ if (!drivers) {
+ drivers = calloc(drivers_alloc, sizeof(**drivers));
+ }
+
+ if (drivers_used > drivers_alloc) {
+ struct Driver **tmp;
+ drivers_alloc += DRIVERS_ALLOC_DEFAULT;
+ tmp = realloc(drivers, (sizeof(**drivers) * drivers_alloc));
+ if (!tmp) {
+ return -1;
+ }
+ drivers = tmp;
+
+ for (size_t i = drivers_used; i < drivers_alloc; i++) {
+ drivers[i] = calloc(1, sizeof(*drivers[i]));
+ if (!drivers[i])
+ return -2;
+ }
+ }
+
+ drivers[drivers_used] = calloc(1, sizeof(*drivers[0]));
+ if (!drivers[drivers_used])
+ return -2;
+ memcpy(drivers[drivers_used], driver, sizeof(*drivers[0]));
+ drivers_used++;
+ return 0;
+}
+
+void drivers_free() {
+ for (size_t i = 0; i < drivers_alloc; i++) {
+ if (drivers[i]) {
+ if (drivers[i]->name)
+ free(drivers[i]->name);
+ if (drivers[i]->data)
+ free(drivers[i]->data);
+ if (drivers[i]->caret)
+ free(drivers[i]->caret);
+ if (drivers[i]->box_elements)
+ free(drivers[i]->box_elements);
+ free(drivers[i]);
+ }
+ }
+ free(drivers);
+}
+void driver_run(struct Driver *driver, char *input) {
+ char *elem = driver->box_elements;
+ box_top_left = elem[0];
+ box_top = elem[1];
+ box_top_right = elem[2];
+ box_side = elem[3];
+ box_bottom_left = elem[4];
+ box_bottom = elem[5];
+ box_bottom_right = elem[6];
+ START_Y_BOX = driver->box_indent;
+ START_Y_CARET = driver->caret_indent;
+ START_Y_DATA = driver->data_indent;
+
+ if (!driver->caret_pos) {
+ box_printf("%s", input);
+ caret_draw(driver->caret, START_Y_CARET, driver->caret_attached);
+ }
+
+ if (driver->data) {
+ data_draw(driver->data, START_Y_DATA);
+ }
+
+ if (driver->caret_pos) {
+ caret_draw(driver->caret, START_Y_CARET, driver->caret_attached);
+ box_printf("%s", input);
+ }
+}
+
+struct Driver *driver_lookup(char *name) {
+ for (size_t i = 0; drivers[i] != NULL; i++) {
+ if (!strcmp(drivers[i]->name, name)) {
+ return drivers[i];
+ }
+ }
+ return NULL;
+}
+
diff --git a/main.c b/main.c
index 911b313..ada0c16 100644
--- a/main.c
+++ b/main.c
@@ -1,47 +1,23 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <unistd.h>
-#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include "config.h"
-
-#define INPUT_BUFSIZ 4096
-#define DATA_BUFSIZ 8192
-#define DRIVERS_ALLOC_DEFAULT 128
-
-size_t START_Y_BOX = 0;
-size_t START_Y_CARET = 0;
-size_t START_Y_DATA = 0;
-const char *A_TAB = " ";
-char wspace = ' ';
-char box_top_left = '\0';
-char box_top = '\0';
-char box_top_right = '\0';
-char box_side = '\0';
-char box_bottom_left = '\0';
-char box_bottom = '\0';
-char box_bottom_right = '\0';
-
-struct Driver {
- char *name;
- size_t box_indent;
- char *box_elements;
- size_t caret_pos;
- size_t caret_indent;
- size_t caret_attached;
- char *caret;
- size_t data_indent;
- char *data;
-};
-struct Driver **drivers = NULL;
-size_t drivers_alloc = DRIVERS_ALLOC_DEFAULT;
-size_t drivers_used = 0;
-
-
+#include "sayeth.h"
+
+extern char wspace;
+extern struct Driver **drivers;
+extern size_t drivers_alloc;
+extern size_t drivers_used;
+
+/***
+ * Repeat a character
+ * @param ch character to repeat
+ * @param limit number of times to repeat
+ */
void repchar(char ch, size_t limit) {
while (limit > 0) {
putc(ch, stdout);
@@ -49,6 +25,11 @@ void repchar(char ch, size_t limit) {
}
}
+/***
+ * Find the longest line in a string
+ * @param s the string
+ * @return longest line
+ */
size_t get_longest_line(char *s) {
size_t *lengths;
size_t len;
@@ -89,81 +70,6 @@ size_t get_longest_line(char *s) {
return longest;
}
-void box_draw_top(size_t y, size_t longest) {
- repchar(wspace, y);
- repchar(box_top_left, 1);
- repchar(box_top, longest);
- repchar(box_top_right, 1);
-}
-
-void box_draw_bottom(size_t y, size_t longest) {
- repchar(wspace, y);
- repchar(box_bottom_left, 1);
- repchar(box_bottom, longest);
- repchar(box_bottom_right, 1);
-}
-
-void box_draw_next_line(size_t y) {
- repchar(wspace, y);
- repchar(box_side, 1);
-}
-
-void box_draw_end_line(size_t longest, size_t len) {
- repchar(wspace, longest - len);
- repchar(box_side, 1);
-}
-
-int boxprintf(const char *fmt, ...) {
- int count;
- va_list list;
- va_start(list, fmt);
- size_t len = 0;
- char data[INPUT_BUFSIZ] = {0};
- char output[INPUT_BUFSIZ] = {0};
- count = vsnprintf(data, sizeof(data) - 1, fmt, list);
-
- // convert tabs to spaces
- for (size_t i = 0, n = 0; i < strlen(data) && n < sizeof(output); i++, n++) {
- if (data[i] == '\t') {
- strcat(&output[n], A_TAB);
- n = n + strlen(A_TAB) - 1;
- continue;
- }
- output[n] = data[i];
- }
-
- size_t longest = get_longest_line(output);
-
- box_draw_top(START_Y_BOX, longest);
- puts("");
-
- for (size_t i = 0; i < strlen(output); i++) {
- if (i == strlen(output) - 1) {
- box_draw_end_line(longest, len);
- continue;
- }
-
- if (len == 0) {
- box_draw_next_line(START_Y_BOX);
- }
-
- if (output[i] == '\n') {
- box_draw_end_line(longest, len);
- putc('\n', stdout);
- len = 0;
- continue;
- }
-
- putc(output[i], stdout);
-
- len++;
- }
- puts("");
- box_draw_bottom(START_Y_BOX, longest);
-
- va_end(list);
- return count;
-}
void usage(char *prog) {
printf("usage: %s [-d driver_name] [-w] [-] {input}\n"
@@ -175,213 +81,6 @@ void usage(char *prog) {
"input A quoted string\n", prog);
}
-void caret_draw(char *data, size_t indent, size_t attached) {
- if (!strlen(data))
- return;
-
- if (!attached)
- repchar(wspace, START_Y_BOX);
-
- for (size_t i = 0; i < strlen(data); i++) {
- if (data[i] == '\\' && isalpha(data[i + 1])) {
- i++;
- switch (data[i]) {
- case 'n':
- putc('\n', stdout);
- if (i == strlen(data) - 1)
- continue;
- repchar(wspace, indent);
- continue;
- default:
- continue;
- }
- }
- putc(data[i], stdout);
- }
-}
-
-
-struct Driver *driver_load(char *filename) {
- FILE *fp = NULL;
- struct Driver *driver = NULL;
-
- driver = calloc(1, sizeof(*driver));
- if (!driver) {
- return NULL;
- }
-
- fp = fopen(filename, "r");
- if (!fp) {
- return NULL;
- }
-
- for (size_t i = 0; i < 9; i++) {
- char buf[INPUT_BUFSIZ] = {0};
- ssize_t lastpos = ftell(fp);
- if (fgets(buf, sizeof(buf) - 1, fp) == NULL) {
- break;
- }
- if (!strlen(buf) || buf[0] == '#') {
- i--;
- continue;
- }
- buf[strlen(buf) - 1] = '\0';
- switch (i) {
- case 0:
- driver->name = strdup(buf);
- if (!driver->name) {
- fclose(fp);
- return NULL;
- }
- break;
- case 1:
- driver->box_indent = strtol(buf, NULL, 10);
- break;
- case 2:
- driver->box_elements = strdup(buf);
- if (!driver->box_elements) {
- fclose(fp);
- return NULL;
- }
- break;
- case 3:
- driver->caret_pos = strtol(buf, NULL, 10);
- break;
- case 4:
- driver->caret_indent = strtol(buf, NULL, 10);
- break;
- case 5:
- driver->caret_attached = strtol(buf, NULL, 10);
- break;
- case 6:
- driver->caret = strdup(buf);
- if (!driver->caret) {
- fclose(fp);
- return NULL;
- }
- break;
- case 7:
- driver->data_indent = strtol(buf, 0, 10);
- break;
- case 8:
- driver->data = calloc(DATA_BUFSIZ, sizeof(*driver->data));
- if (!driver->data) {
- fclose(fp);
- return NULL;
- }
- // rewind to beginning of the data section
- fseek(fp, lastpos, SEEK_SET);
- fread(driver->data, 1, DATA_BUFSIZ - 1, fp);
- break;
- default:
- break;
- }
- }
- fclose(fp);
- return driver;
-}
-
-int driver_register(struct Driver *driver) {
- if (!drivers) {
- drivers = calloc(drivers_alloc, sizeof(**drivers));
- }
-
- if (drivers_used > drivers_alloc) {
- struct Driver **tmp;
- drivers_alloc += DRIVERS_ALLOC_DEFAULT;
- tmp = realloc(drivers, (sizeof(**drivers) * drivers_alloc));
- if (!tmp) {
- return -1;
- }
- drivers = tmp;
-
- for (size_t i = drivers_used; i < drivers_alloc; i++) {
- drivers[i] = calloc(1, sizeof(*drivers[i]));
- if (!drivers[i])
- return -2;
- }
- }
-
- drivers[drivers_used] = calloc(1, sizeof(*drivers[0]));
- if (!drivers[drivers_used])
- return -2;
- memcpy(drivers[drivers_used], driver, sizeof(*drivers[0]));
- drivers_used++;
- return 0;
-}
-
-void drivers_free() {
- for (size_t i = 0; i < drivers_alloc; i++) {
- if (drivers[i]) {
- if (drivers[i]->name)
- free(drivers[i]->name);
- if (drivers[i]->data)
- free(drivers[i]->data);
- if (drivers[i]->caret)
- free(drivers[i]->caret);
- if (drivers[i]->box_elements)
- free(drivers[i]->box_elements);
- free(drivers[i]);
- }
- }
- free(drivers);
-}
-
-void data_draw(char *data, size_t indent) {
- size_t len = 0;
- for (size_t i = 0; i < strlen(data); i++) {
- if (len == 0) {
- repchar(wspace, indent);
- }
-
- if (data[i] == '\n') {
- putc('\n', stdout);
- len = 0;
- continue;
- }
-
- putc(data[i], stdout);
- len++;
- }
-}
-
-void driver_run(struct Driver *driver, char *input) {
- char *elem = driver->box_elements;
- box_top_left = elem[0];
- box_top = elem[1];
- box_top_right = elem[2];
- box_side = elem[3];
- box_bottom_left = elem[4];
- box_bottom = elem[5];
- box_bottom_right = elem[6];
- START_Y_BOX = driver->box_indent;
- START_Y_CARET = driver->caret_indent;
- START_Y_DATA = driver->data_indent;
-
- if (!driver->caret_pos) {
- boxprintf("%s", input);
- caret_draw(driver->caret, START_Y_CARET, driver->caret_attached);
- }
-
- if (driver->data) {
- data_draw(driver->data, START_Y_DATA);
- }
-
- if (driver->caret_pos) {
- caret_draw(driver->caret, START_Y_CARET, driver->caret_attached);
- boxprintf("%s", input);
- }
-}
-
-struct Driver *driver_lookup(char *name) {
- for (size_t i = 0; drivers[i] != NULL; i++) {
- if (!strcmp(drivers[i]->name, name)) {
- return drivers[i];
- }
- }
- return NULL;
-}
-
int main(int argc, char *argv[]) {
char driver_name[255] = {0};
char input[INPUT_BUFSIZ] = {0};
@@ -414,12 +113,10 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "option requires value\n");
usage(argv[0]);
exit(1);
- break;
case '?':
fprintf(stderr, "unknown option: %c\n", optopt);
usage(argv[0]);
exit(1);
- break;
default:
usage(argv[0]);
exit(1);
diff --git a/sayeth.h b/sayeth.h
new file mode 100644
index 0000000..dea73c9
--- /dev/null
+++ b/sayeth.h
@@ -0,0 +1,56 @@
+#ifndef SAYETH_SAYETH_H
+#define SAYETH_SAYETH_H
+#include <stdlib.h>
+
+// Maximum length of input text
+#define INPUT_BUFSIZ 4096
+
+// Maximum length of art data
+#define DATA_BUFSIZ 8192
+
+// Seed global driver array with n records
+#define DRIVERS_ALLOC_DEFAULT 128
+
+struct Driver {
+ char *name; // Driver name (passed to '-d' argument)
+ size_t box_indent; // Shift box n columns to the right
+ char *box_elements; // Border characters
+ // top left, top, top right, sides, bottom left, bottom, bottom right
+ // e.g. "/-\|\-/'
+ /*
+ * /--------\
+ * | |
+ * \--------/
+ */
+ size_t caret_pos; // Above or below the box
+ size_t caret_indent; // Shift caret n columns to the right
+ size_t caret_attached; // Inject a new line *after* art data, or not?
+ char *caret; // Caret characters
+ // e.g. "\n \ |\n \ |\n \|\n"
+ /*
+ * \ |
+ * \ |
+ * \|
+ */
+ size_t data_indent; // Shift art data n columns to the right
+ char *data; // Art data (up to size: DATA_BUFSIZ - 1)
+};
+
+void repchar(char ch, size_t limit);
+size_t get_longest_line(char *s);
+
+struct Driver *driver_load(char *filename);
+struct Driver *driver_lookup(char *name);
+int driver_register(struct Driver *driver);
+void driver_run(struct Driver *driver, char *input);
+void drivers_free(void);
+
+void box_draw_top(size_t y, size_t longest);
+void box_draw_bottom(size_t y, size_t longest);
+void box_draw_next_line(size_t y);
+void box_draw_end_line(size_t longest, size_t len);
+int box_printf(const char *fmt, ...);
+
+void caret_draw(char *data, size_t indent, size_t attached);
+void data_draw(char *data, size_t indent);
+#endif //SAYETH_SAYETH_H