-
Rob Swindell authoredRob Swindell authored
ans2asc.c 7.94 KiB
/* Convert ANSI messages to Synchronet Ctrl-A code format */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strcmp */
#include "sauce.h"
#include "git_branch.h"
#include "git_hash.h"
#ifndef CTRL_Z
#define CTRL_Z 0x1a
#endif
static void print_usage(const char* prog)
{
fprintf(stderr,"\nSynchronet ANSI-Terminal-Sequence to Ctrl-A-Code Conversion Utility %s/%s\n"
,GIT_BRANCH
,GIT_HASH
);
fprintf(stderr,"\nusage: %s infile.ans [outfile.asc | outfile.msg] [[option] [...]]\n",prog);
fprintf(stderr,"\noptions:\n\n");
fprintf(stderr," -ice treat blink as bright-background (iCE colors)\n");
fprintf(stderr," -<columns> insert conditional-newlines to force wrap (e.g. -80)\n");
fprintf(stderr," -normal use 'save/normal/restore' attributes for conditional new-lines\n");
fprintf(stderr," -newline append a newline (CRLF) sequence to output file\n");
fprintf(stderr," -clear insert a clear screen code at beginning of output file\n");
fprintf(stderr," -pause append a pause (hit a key) code to end of output file\n");
fprintf(stderr," -space use space characters for cursor-right movement/alignment\n");
fprintf(stderr," -delay <int> insert a 1/10th second delay code at output byte interval\n");
fprintf(stderr," (lower interval values result in more delays, slower display)\n");
}
int main(int argc, char **argv)
{
unsigned char esc,n[25];
int i,ch,ni;
FILE *in=stdin;
FILE *out=stdout;
bool ice=false;
bool normal=false;
int cols=0;
int column=0;
int delay=0;
int clear=0;
int pause=0;
int space=0;
int newline=0;
if(argc<2) {
print_usage(argv[0]);
return(0);
}
for(i=1; i<argc; i++) {
if(argv[i][0]=='-') {
if(strcmp(argv[i], "-delay") == 0) {
if(i+1 == argc) {
print_usage(argv[0]);
return -1;
}
if((delay=atoi(argv[++i])) < 1) {
print_usage(argv[0]);
return -1;
}
}
else if(strcmp(argv[i], "-ice") == 0)
ice = true;
else if(strcmp(argv[i], "-clear") == 0)
clear = 1;
else if(strcmp(argv[i], "-pause") == 0)
pause = 1;
else if(strcmp(argv[i], "-space") == 0)
space = 1;
else if(strcmp(argv[i], "-normal") == 0)
normal = true;
else if(strcmp(argv[i], "-newline") == 0)
newline++;
else if(IS_DIGIT(argv[i][1]))
cols = atoi(argv[i] + 1);
else {
print_usage(argv[0]);
return 0;
}
} else if(in==stdin) {
if((in=fopen(argv[i],"rb"))==NULL) {
perror(argv[i]);
return(1);
}
} else if(out==stdout) {
if((out=fopen(argv[i],"wb"))==NULL) {
perror(argv[i]);
return(1);
}
}
}
if(in != stdin && cols < 1) {
struct sauce_charinfo info;
if(sauce_fread_charinfo(in, /* type: */NULL, &info)) {
cols = info.width;
ice = info.ice_color;
}
}
const char* cond_newline = normal ? "\1+\1N\1/\1-" : "\1/";
if(clear)
fprintf(out,"\1N\1L");
esc=0;
while((ch=fgetc(in))!=EOF && ch != CTRL_Z) {
if(ch=='[' && esc) { /* ANSI escape sequence */
if(cols && column >= cols) {
fprintf(out, "%s", cond_newline); // Conditional-newline
column = 0;
}
ni=0; /* zero number index */
memset(n,1,sizeof(n));
while((ch=fgetc(in))!=EOF) {
if(IS_DIGIT(ch)) { /* 1 digit */
n[ni]=ch&0xf;
ch=fgetc(in);
if(ch==EOF)
break;
if(IS_DIGIT(ch)) { /* 2 digits */
n[ni]*=10;
n[ni]+=ch&0xf;
ch=fgetc(in);
if(ch==EOF)
break;
if(IS_DIGIT(ch)) { /* 3 digits */
n[ni]*=10;
n[ni]+=ch&0xf;
ch=fgetc(in);
}
}
ni++;
}
if(ch==';')
continue;
switch(ch) {
case '=':
case '?':
ch=fgetc(in); /* First digit */
if(IS_DIGIT(ch)) ch=fgetc(in); /* l or h ? */
if(IS_DIGIT(ch)) ch=fgetc(in);
if(IS_DIGIT(ch)) fgetc(in);
break;
case 'f':
case 'H':
if(n[0]<=1 && n[1]<=1) /* home cursor */
fputs("\1'", out);
column = 0;
break;
case 'J':
if(n[0]==2) /* clear screen */
fputs("\1L",out); /* ctrl-aL */
else if(n[0]==0) /* clear to EOS */
fputs("\1J",out); /* ctrl-aJ */
column = 0;
break;
case 'K':
fputs("\1>",out); /* clear to eol */
column = cols ? (cols - 1) : 79;
break;
case 'm':
for(i=0;i<ni;i++) {
fputc(1,out); /* ctrl-ax */
switch(n[i]) {
case 0:
case 2: /* no attribute */
fputc('N',out);
break;
case 1: /* high intensity */
fputc('H',out);
break;
case 3:
case 4:
case 5: /* blink */
case 6:
case 7:
fputc(ice ? 'E': 'I',out);
break;
case 30:
fputc('K',out);
break;
case 31:
fputc('R',out);
break;
case 32:
fputc('G',out);
break;
case 33:
fputc('Y',out);
break;
case 34:
fputc('B',out);
break;
case 35:
fputc('M',out);
break;
case 36:
fputc('C',out);
break;
case 37:
fputc('W',out);
break;
case 40:
fputc('0',out);
break;
case 41:
fputc('1',out);
break;
case 42:
fputc('2',out);
break;
case 43:
fputc('3',out);
break;
case 44:
fputc('4',out);
break;
case 45:
fputc('5',out);
break;
case 46:
fputc('6',out);
break;
case 47:
fputc('7',out);
break;
default:
fprintf(stderr,"Unsupported ANSI color code: %u\n", (unsigned int)n[i]);
break;
}
}
break;
case 'B': /* cursor down */
while(n[0]) {
fprintf(out,"\1]"); /* linefeed */
n[0]--;
}
break;
case 'C': /* cursor right */
if(space)
fprintf(out, "%*s", n[0], " ");
else
fprintf(out,"\1%c",0x7f+n[0]);
column += n[0];
break;
case 'D': /* cursor left */
column -= n[0];
if(n[0] >= column)
fprintf(out,"\1[");
else
while(n[0]) {
fprintf(out,"\1<");
n[0]--;
}
break;
default:
fprintf(stderr,"Unsupported ANSI code '%c' (0x%02X)\r\n",ch,ch);
break;
}
break;
} /* end of while */
esc=0;
continue;
} /* end of ANSI expansion */
if(ch=='\x1b')
esc=1;
else {
esc=0;
switch(ch) {
case '\r':
case '\n':
fputc(ch,out);
column = 0;
break;
default:
if(cols && column >= cols) {
fprintf(out, "%s", cond_newline); // Conditional-newline
column = 0;
}
fputc(ch,out);
column++;
break;
}
if(delay && (ftell(out)%delay)==0)
fprintf(out,"\1,");
}
if(column < 0)
column = 0;
}
while(newline--)
fprintf(out,"\r\n");
if(pause)
fprintf(out,"\1p");
return(0);
}