aboutsummaryrefslogtreecommitdiff
path: root/atascii.c
diff options
context:
space:
mode:
Diffstat (limited to 'atascii.c')
-rw-r--r--atascii.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/atascii.c b/atascii.c
new file mode 100644
index 0000000..d4e4a91
--- /dev/null
+++ b/atascii.c
@@ -0,0 +1,157 @@
+#include "atascii.h"
+
+const char *atascii_inverse_on = "\x1b[7m";
+const char *atascii_inverse_off = "\x1b[27m";
+
+/* only called in magazine mode. cursor control characters
+ like a bell in the middle of a non-inverse string
+ should not cause it to print {inv}{bell}{norm}. The {bell}
+ is "inherently" inverse (since its high bit is set) but doesn't
+ need to be printed that way. */
+static int affects_inv(int c) {
+ switch(c) {
+ case 0x1b: /* esc */
+ case 0x1c: /* up */
+ case 0x1d: /* down */
+ case 0x1e: /* left */
+ case 0x1f: /* right */
+ case 0x9b: /* EOL */
+ case 0x9c: /* del line */
+ case 0x9d: /* ins line */
+ case 0x9e: /* clear tab */
+ case 0x9f: /* set tab */
+ case 0x7d: /* cls */
+ case 0x7e: /* BS */
+ case 0x7f: /* tab */
+ case 0xfd: /* bell */
+ case 0xfe: /* del chr */
+ case 0xff: /* ins chr */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int atascii_context_init(atascii_ctx *ctx, int mode, int flags) {
+ memset(ctx, 0, sizeof(atascii_ctx));
+
+ switch(mode) {
+ case ATA_MODE_UTF8:
+ if(flags & ATA_FLAG_ICS)
+ ctx->table = ics2utf;
+ else
+ ctx->table = ata2utf;
+ break;
+ case ATA_MODE_MAGAZINE:
+ ctx->flags &= ~ATA_FLAG_UNDERLINE;
+ ctx->table = ata2mag;
+ break;
+ default:
+ return 0;
+ }
+
+ ctx->mode = mode;
+ ctx->flags = flags;
+
+ return 1;
+}
+
+char *atascii_a2utf(atascii_ctx *ctx, int src, char *dest) {
+ dest[0] = 0;
+
+ if(src == ATA_CHR_FINISH) {
+ if(ctx->inv)
+ strcpy(dest, ctx->mode == ATA_MODE_MAGAZINE ? "{norm}": atascii_inverse_off);
+ return dest;
+ }
+
+ if(src == 0x9b) {
+ strcpy(dest, "\n");
+ ctx->lines++;
+ return dest;
+ }
+
+ if(ctx->flags & ATA_FLAG_TEXTMODE) {
+ switch(src) {
+ case 0x7f: /* tab */
+ strcpy(dest, "\t");
+ return dest;
+ case 0xfd: /* bell */
+ strcpy(dest, "\a");
+ return dest;
+ case 0x7e: /* backspace */
+ strcpy(dest, "\b");
+ return dest;
+ default: break;
+ }
+ }
+
+ if(ctx->flags & ATA_FLAG_STRIP_INVERSE) src &= 0x7f;
+
+ if(!(ctx->flags & ATA_FLAG_UNDERLINE)) {
+ /* strings of inverse chars only get one "inverse on" ANSI
+ sequence, and one "inverse off" afterwards. */
+ if(src & 0x80) {
+ if(!ctx->inv) {
+ if(ctx->mode == ATA_MODE_MAGAZINE) {
+ if(affects_inv(src)) {
+ strcpy(dest, "{inv}");
+ ctx->inv = 1;
+ }
+ } else {
+ strcpy(dest, atascii_inverse_on);
+ ctx->inv = 1;
+ }
+ }
+ } else {
+ if(ctx->inv) {
+ if(ctx->mode == ATA_MODE_MAGAZINE) {
+ if(affects_inv(src)) {
+ strcpy(dest, "{norm}");
+ ctx->inv = 0;
+ }
+ } else {
+ strcpy(dest, atascii_inverse_off);
+ ctx->inv = 0;
+ }
+ }
+ }
+ }
+
+ if(ctx->mode == ATA_MODE_MAGAZINE) {
+ /* special cases: control codes with bit 7 set can't go
+ in the table since it's only got 128 entries. */
+ switch(src) {
+ case 0x9c:
+ strcat(dest, "{del-line}"); return dest;
+ case 0x9d:
+ strcat(dest, "{ins-line}"); return dest;
+ case 0x9e:
+ strcat(dest, "{clr-tab}"); return dest;
+ case 0x9f:
+ strcat(dest, "{set-tab}"); return dest;
+ case 0xfd:
+ strcat(dest, "{bell}"); return dest;
+ case 0xfe:
+ strcat(dest, "{del-char}"); return dest;
+ case 0xff:
+ strcat(dest, "{ins-char}"); return dest;
+ default: break;
+ }
+ }
+
+ strcat(dest, ctx->table[src & 0x7f]);
+
+ if((ctx->flags & ATA_FLAG_UNDERLINE) && (src & 0x80)) {
+ strcat(dest, "\b_");
+ }
+
+ return dest;
+}
+
+const char *atascii_finish(atascii_ctx *ctx) {
+ if(ctx->inv)
+ return ATA_MODE_MAGAZINE ? "{norm}": atascii_inverse_off;
+ else
+ return "";
+};