-
Rob Swindell authored
uncrustify nl_split_if_one_liner setting
Rob Swindell authoreduncrustify nl_split_if_one_liner setting
ans2asc.c 9.09 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 "genwrap.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, " -esc use C-style string literal escaping of control and CP437 chars\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;
bool encode = false;
int cols = 0;
int column = 0;
int delay = 0;
int clear = 0;
int pause = 0;
int space = 0;
int newline = 0;
char* ctrl_a = "\1";
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 (strcmp(argv[i], "-esc") == 0) {
encode = true;
ctrl_a = "\\x01";
}
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, "%sN%sL", ctrl_a, ctrl_a);
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 */
fprintf(out, "%s'", ctrl_a);
column = 0;
break;
case 'J':
if (n[0] == 2) /* clear screen */
fprintf(out, "%sL", ctrl_a);
else if (n[0] == 0) /* clear to EOS */
fprintf(out, "%sJ", ctrl_a);
column = 0;
break;
case 'K':
fprintf(out, "%s>", ctrl_a); /* clear to eol */
column = cols ? (cols - 1) : 79;
break;
case 'm':
for (i = 0; i < ni; i++) {
fprintf(out, "%s", ctrl_a); /* 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, "%s]", ctrl_a); /* linefeed */
n[0]--;
}
break;
case 'C': /* cursor right */
if (space)
fprintf(out, "%*s", n[0], " ");
else {
if (encode)
fprintf(out, "%s\\x%02X", ctrl_a, 0x7f + n[0]);
else
fprintf(out, "%s%c", ctrl_a, 0x7f + n[0]);
}
column += n[0];
break;
case 'D': /* cursor left */
column -= n[0];
if (n[0] >= column)
fprintf(out, "%s[", ctrl_a);
else
while (n[0]) {
fprintf(out, "%s<", ctrl_a);
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;
if (encode) {
if (ch < ' ' || ch >= 0x7f) {
char* p = c_escape_char(ch);
if (p == NULL)
fprintf(out, "\\x%02X", ch);
else
fprintf(out, "%s", p);
}
else
fputc(ch, out);
} else {
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, "%s,", ctrl_a);
}
if (column < 0)
column = 0;
}
while (newline--)
fprintf(out, "\r\n");
if (pause)
fprintf(out, "%sp", ctrl_a);
return 0;
}