aboutsummaryrefslogtreecommitdiff
path: root/a8cat.c
diff options
context:
space:
mode:
Diffstat (limited to 'a8cat.c')
-rw-r--r--a8cat.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/a8cat.c b/a8cat.c
new file mode 100644
index 0000000..92eae9f
--- /dev/null
+++ b/a8cat.c
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <locale.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "atascii.h"
+#include "wtable.h"
+
+int reverse = 0, verbose = 0;
+
+atascii_ctx actx;
+
+const char *self;
+
+void set_self(const char *argv0) {
+ char *p;
+
+ self = argv0;
+ p = strrchr(self, '/');
+ if(p) self = p + 1;
+}
+
+void die(const char *msg) {
+ fprintf(stderr, "%s: %s\n", self, msg);
+ exit(1);
+}
+
+void print_help(void) {
+ printf("Usage: %s [-i] [-u] [file ...]\n", self);
+}
+
+FILE *open_input(const char *file) {
+ FILE *input;
+
+ if(file[0] == '-' && file[1] == 0) {
+ if(verbose)
+ fprintf(stderr, "%s: reading from standard input.\n", self);
+ if(freopen(NULL, "rb", stdin)) {
+ input = stdin;
+ } else {
+ perror("(standard input)");
+ return NULL;
+ }
+ } else if(!(input = fopen(file, "rb"))) {
+ perror(file);
+ return NULL;
+ }
+
+ if(verbose)
+ fprintf(stderr, "%s: reading from file '%s'.\n", self, file);
+
+ return input;
+}
+
+int handle_escape_seq(int inv, FILE *input, const char *file, int line) {
+ int count, c;
+ char buf[5] = { 0x1b, 0, 0, 0, 0 };
+
+ for(count = 1; count < 4; count++) {
+ c = fgetwc(input);
+ if(c == WEOF) break;
+ buf[count] = c; /* FIXME: might be a wide char! */
+ }
+
+ if(strcmp(atascii_inverse_on, buf) == 0) {
+ return 0x80;
+ } else if(strcmp(atascii_inverse_off, buf) == 0) {
+ return 0;
+ } else {
+ fprintf(stderr, "%s: warning: %s:%d: unrecognized ANSI escape sequence.\n", self, file, line);
+ fputs(buf, stdout);
+ return inv;
+ }
+}
+
+int a8revcat(const char *file) {
+ FILE *input;
+ int c, d, inv = 0, line = 1;
+
+ if( !(input = open_input(file)) )
+ return 1;
+
+ while( (c = fgetwc(input)) != WEOF ) {
+ if(c == 0x1b) {
+ inv = handle_escape_seq(inv, input, file, line);
+ } else if(c == '\r') {
+ continue; /* swallow carriage returns */
+ } else if(c == '\n') {
+ putchar(0x9b);
+ line++;
+ } else if(c == '\t') {
+ putchar(0x7f);
+ } else if(c == '\b' || c == 0x7f) {
+ putchar(0x7e);
+ } else if(c == '\a') {
+ putchar(0xfd);
+ } else if(c < 0x80) {
+ putchar(c | inv);
+ } else {
+ d = wchar2atascii(c, actx.flags & ATA_FLAG_ICS);
+ if(d == -1) {
+ fprintf(stderr, "%s: warning: %s:%d: unrecognized Unicode character %04x.\n", self, file, line, c);
+ } else {
+ putchar(d | inv);
+ }
+ }
+ }
+
+ if(verbose)
+ fprintf(stderr, "%s: %s: converted %d lines, closing file.\n", self, file, line - 1);
+
+ fclose(input);
+ return 0;
+}
+
+int a8cat(const char *file) {
+ FILE *input;
+ int c;
+ char converted[20];
+
+ if( !(input = open_input(file)) )
+ return 1;
+
+ while( (c = fgetc(input)) != EOF ) {
+ fputs(atascii_a2utf(&actx, c, converted), stdout);
+ }
+
+ /* gotta turn off inverse, so if there's another file after this one,
+ it doesn't start out being printed in inverse. */
+ fputs(atascii_a2utf(&actx, ATA_CHR_FINISH, converted), stdout);
+
+ if(verbose)
+ fprintf(stderr, "%s: %s: converted %d lines, closing file.\n", self, file, actx.lines - 1);
+
+ fclose(input);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int opt, result = 0;
+ int mode = ATA_MODE_UTF8, flags = 0;
+
+ set_self(argv[0]);
+
+ if(argc > 1 && strcmp(argv[1], "--help") == 0) {
+ print_help();
+ exit(0);
+ }
+
+ if(argc > 1 && strcmp(argv[1], "--version") == 0) {
+ printf("%s %s\n", self, VERSION);
+ exit(0);
+ }
+
+ while( (opt = getopt(argc, argv, "ihurtmsv")) != -1) {
+ switch(opt) {
+ case 'i': flags |= ATA_FLAG_ICS; break;
+ case 'h': print_help(); exit(0); break;
+ case 'u': flags |= ATA_FLAG_UNDERLINE; break;
+ case 'r': reverse = 1; break;
+ case 't': flags |= ATA_FLAG_TEXTMODE; break;
+ case 'm': mode = ATA_MODE_MAGAZINE; break;
+ case 's': flags |= ATA_FLAG_STRIP_INVERSE; break;
+ case 'v': verbose = 1; break;
+ default: print_help(); exit(1); break;
+ }
+ }
+
+ atascii_context_init(&actx, mode, flags);
+
+ if(reverse) {
+ if(isatty(fileno(stdout)))
+ die("Refusing to write ATASCII to a terminal.");
+
+ /*
+ if(underline || textmode || stripinv || magazine) {
+ die("-t, -u, -m, -s options don't make sense with -r.\n");
+ }
+ */
+ /* the language_country part of the locale doesn't matter,
+ since we aren't doing localization. the encoding *has*
+ to be UTF-8. */
+ setlocale(LC_CTYPE, "en_US.UTF-8");
+ }
+
+ /*
+ if(magazine) {
+ if(ics || stripinv || underline) {
+ die("-i, -s, -u options don't make sense with -m.\n");
+ }
+ }
+ */
+
+ if(optind >= argc) {
+ result = (reverse ? a8revcat("-") : a8cat("-"));
+ } else {
+ while(optind < argc) {
+ result += (reverse ? a8revcat(argv[optind]) : a8cat(argv[optind]));
+ optind++;
+ }
+ }
+
+ exit(result);
+}