#include #include #include #include #include #include #include #include "atables.h" #include "wtable.h" const char **table = ata2utf; const char *inverse_on = "\x1b[7m"; const char *inverse_off = "\x1b[0m"; int underline = 0, reverse = 0, textmode = 0, ics = 0; void print_help(void) { printf("Usage: a8cat [-i] [-u] [file ...]\n"); } FILE *open_input(const char *file) { FILE *input; if(file[0] == '-' && file[1] == 0) { if(freopen(NULL, "rb", stdin)) { input = stdin; } else { perror("(standard input)"); return NULL; } } else if(!(input = fopen(file, "rb"))) { perror(file); return NULL; } return input; } int handle_escape_seq(int inv, FILE *input) { 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(inverse_on, buf) == 0) { return 0x80; } else if(strcmp(inverse_off, buf) == 0) { return 0; } else { fputs(buf, stdout); return inv; } } int a8revcat(const char *file) { FILE *input; int c, d, inv = 0; if( !(input = open_input(file)) ) return 1; setlocale(LC_CTYPE, "en_US.UTF-8"); while( (c = fgetwc(input)) != WEOF ) { if(c == 0x1b) { inv = handle_escape_seq(inv, input); } else if(c == '\n') { putchar(0x9b); } else if(c < 0x80) { putchar(c | inv); } else { d = wchar2atascii(c, ics); if(d == -1) { fprintf(stderr, "warning: unrecognized Unicode character %04x\n", c); } else { putchar(d | inv); } } } return 0; } /* XXX: hard-coded ANSI/vt100 escape sequences. would be better but more complex to use terminfo to support any ol' terminal... */ void inverse(int onoff) { fputs((onoff ? inverse_on : inverse_off ), stdout); } int a8cat(const char *file) { FILE *input; int c, inv = 0; if( !(input = open_input(file)) ) return 1; while( (c = fgetc(input)) != EOF ) { if(c == 0x9b) { putchar('\n'); continue; } if(textmode) { switch(c) { case 0x09: /* Atari TAB is same as ASCII */ putchar('\t'); continue; case 0xfd: /* bell */ putchar('\a'); continue; case 0x7e: /* backspace */ putchar('\b'); continue; default: break; } } if(!underline) { /* strings of inverse chars only get one "inverse on" ANSI sequence, and one "inverse off" afterwards. */ if(c & 0x80) { if(!inv) { inv = 1; inverse(1); } } else { if(inv) { inv = 0; inverse(0); } } } fputs(table[c & 0x7f], stdout); if(underline && (c & 0x80)) { putchar('\b'); putchar('_'); } } /* gotta turn off inverse, so if there's another file after this one, it doesn't start out being printed in inverse. */ if(inv && !underline) inverse(0); fclose(input); return 0; } int main(int argc, char **argv) { int opt, result = 0; while( (opt = getopt(argc, argv, "ihurt")) != -1) { switch(opt) { case 'i': table = ics2utf; ics = 1; break; case 'h': print_help(); exit(0); break; case 'u': underline = 1; break; case 'r': reverse = 1; break; case 't': textmode = 1; break; default: print_help(); exit(1); break; } } if(reverse) { if(underline || textmode) { fprintf(stderr, "-t and -u options don't make sense with -r.\n"); exit(1); } } if(optind >= argc) { result = (reverse ? a8revcat("-") : a8cat("-")); } else { while(optind < argc) { result += (reverse ? a8revcat(argv[optind]) : a8cat(argv[optind])); optind++; } } exit(result); }