NetBSD Problem Report #48092 From www@NetBSD.org Sun Jul 28 13:39:50 2013 Return-Path: Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "mail.NetBSD.org", Issuer "Postmaster NetBSD.org" (verified OK)) by mollari.NetBSD.org (Postfix) with ESMTPS id CF007705DA for ; Sun, 28 Jul 2013 13:39:50 +0000 (UTC) Message-Id: <20130728133948.90B4D70D0A@mollari.NetBSD.org> Date: Sun, 28 Jul 2013 13:39:48 +0000 (UTC) From: nathanialsloss@yahoo.com.au Reply-To: nathanialsloss@yahoo.com.au To: gnats-bugs@NetBSD.org Subject: ansi2text a utility for formatting text with ANSI sequences for display with less. X-Send-Pr-Version: www-1.0 *>Number:* 48092 *>Category:* bin *>Synopsis:* ansi2text a utility for formatting text with ANSI sequences for display with less. *>Confidential:* no *>Severity:* non-critical *>Priority:* medium *>Responsible:* bin-bug-people *>State:* open *>Class:* change-request *>Submitter-Id:* net *>Arrival-Date:* Sun Jul 28 13:40:00 +0000 2013 *>Originator:* Nat Sloss *>Release:* NetBSD 5.0.1 *>Organization:* *>Environment:* NetBSD beast 5.0.1 NetBSD 5.0.1 (LOCKDEBUG) #4: Wed Jul 17 22:24:41 EST 2013 build@beast:/home/build/NetBSD-5.0.1_source_tree/usr/src/sys/arch/i386/compile/obj/LOCKDEBUG i386 *>Description:* Consider the following: tip myconnection | tee myconnection.log Assume that my connection sends ANSI cursor and colour sequences. Try to display myconnection.log with less or open with a text editor less myconnection.log You will find the display illegible ansi2text is my attempt at rectifying this. *>How-To-Repeat:* Refer to Description. *>Fix:* To use: cat myconnection.log | ansi2text | less ansi2text.c /*- * Copyright (c) 2012, 2013 Nathanial Sloss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include int lines = 25; int cols = 80; char *screen; char *bgcolor; char *fgcolor; char *attributes; int screensize; char ansibuffer[256]; char *leftover; int curpos, newpos, cury, newy, curx, newx; int ansiattr, ansiattr_old; int bg_color, fg_color, oldbg, oldfg; int ansipos; char ansicode; int ansinum; bool csistart; bool colorflag; void writebuffer(void *buf, int count) { int fdout = fileno(stdout); write(fdout, buf, count); return; } void writescreen(void) { int newbg, newfg, newattr, m, n, o, p; int colorcode_len; char colorcode[20]; char nl = 0x0a; char buf[2048]; int buffercount = 0; int buffersize = 2048; for (m = 0; m < screensize; m += cols) { for (n = 0; n < cols; n++) { o = n + m; if (colorflag && (attributes[o] != ansiattr_old)) { snprintf(colorcode, sizeof(colorcode), "\033[m"); colorcode_len = strlen(colorcode); for (p = 0; p < colorcode_len; p++) { if (buffercount >= buffersize) { writebuffer(buf, buffercount); buffercount = 0; } buf[buffercount] = colorcode[p]; buffercount++; } } if (colorflag && (bgcolor[o] != oldbg || fgcolor[o] != oldfg || attributes[o] != ansiattr_old || n == 0)) { if (attributes[o] == -1) newattr = 0; else newattr = attributes[o]; if (bgcolor[o] == -1) newbg = 49; else newbg = bgcolor[o]; if (fgcolor[o] == -1) newfg = 39; else newfg = fgcolor[o]; snprintf(colorcode, sizeof(colorcode), "\033[%d;%d;%dm", newfg, newbg, newattr); ansiattr_old = attributes[o]; oldbg = bgcolor[o]; oldfg = fgcolor[o]; colorcode_len = strlen(colorcode); for (p = 0; p < colorcode_len; p++) { if (buffercount >= buffersize) { writebuffer(buf, buffercount); buffercount = 0; } buf[buffercount] = colorcode[p]; buffercount++; } } if (buffercount >= buffersize) { writebuffer(buf, buffercount); buffercount = 0; } buf[buffercount] = screen[o]; buffercount++; } if (buffercount >= buffersize) { writebuffer(buf, buffercount); buffercount = 0; } buf[buffercount] = nl; buffercount++; } writebuffer(buf, buffercount); return; } void parseansi(void) { unsigned int j, k, l; /* Strip first two characters esc[ */ for (j = 0; j < sizeof(ansibuffer); j++) { if (j + 2 >= (sizeof(ansibuffer))) k = 0; else k = ansibuffer[j + 2]; ansibuffer[j] = k; } ansinum = strtoimax(ansibuffer, &leftover, 10); strcpy(ansibuffer, leftover); if (ansicode == 'J') { writescreen(); ansiattr = 0; bg_color = 49; fg_color = 39; if (ansinum == 2) l = 0; else l = (cury * cols) + curx - 1; for (j = l; j < (unsigned int)screensize; j++) { screen[j] = ' '; attributes[j] = ansiattr; bgcolor[j] = bg_color; fgcolor[j] = fg_color; } } if (ansicode == 'A') { writescreen(); if (ansinum == 0) cury--; else if (ansinum > 0) cury -= ansinum; if (cury < 1) cury = 1; } if (ansicode == 'B') { if (ansinum == 0) cury++; else if (ansinum > 0) cury += ansinum; if (cury > lines) { writescreen(); cury = lines; } } if (ansicode == 'C') { if (ansinum == 0) curx++; else if (ansinum > 0) curx += ansinum; if (curx > cols) { writescreen(); curx = cols; } } if (ansicode == 'D') { writescreen(); if (ansinum == 0) curx--; else if (ansinum > 0) curx -= ansinum; if (curx < 1) curx = 1; } if (ansicode == 'E') { if (ansinum == 0) cury++; if (ansinum > 0) cury += ansinum; curx = 1; if (cury > lines) { writescreen(); cury = lines; } } if (ansicode == 'F') { writescreen(); if (ansinum == 0) cury--; if (ansinum > 0) cury -= ansinum; curx = 1; if (cury < 1) cury = 1; } if (ansicode == 'G') { if (ansinum < curx) writescreen(); if (ansinum > 0) curx = ansinum; if (curx > cols) { writescreen(); curx = cols; } } if (ansicode == 'H' || ansicode == 'f') { if (ansinum < 1) newy = 1; else newy = ansinum; if (ansibuffer[0] == ';') { for (j = 0; j < sizeof(ansibuffer); j++) { if (j + 1 >= (sizeof(ansibuffer))) k = 0; else k = ansibuffer[j + 1]; ansibuffer[j] = k; } newx = strtoimax(ansibuffer, &leftover, 10); if (newx < 1) newx = 1; } if (newx > cols) newx = cols; if (newy > lines) newy = lines; if ((newy < cury)) writescreen(); curx = newx; cury = newy; } if (ansicode == 'm') { if (ansinum >= 0 && ansinum < 30) ansiattr = ansinum; else if (ansinum >= 30 && ansinum <= 39) fg_color = ansinum; else if (ansinum >= 40 && ansinum < 49) bg_color = ansinum; while (ansibuffer[0] == ';') { for (j = 0; j < sizeof(ansibuffer); j++) { if (j + 1 >= (sizeof(ansibuffer))) k = 0; else k = ansibuffer[j + 1]; ansibuffer[j] = k; } ansinum = strtoimax(ansibuffer, &leftover, 10); strcpy(ansibuffer, leftover); if (ansinum >= 0 && ansinum < 30) ansiattr = ansinum; else if (ansinum >= 30 && ansinum <= 39) fg_color = ansinum; else if (ansinum >= 40 && ansinum < 49) bg_color = ansinum; } } return; } int main(int argc, char **argv) { int ch, nr, readpos; int fdin = fileno(stdin); char buffer[2048]; cols = 80; lines = 25; curpos = newpos = 0; cury = newy = 1; curx = newx = 1; bg_color = fg_color = oldbg = oldfg = -1; ansiattr = ansiattr_old = -1; colorflag = false; /* Defaults to b&w */ while ((ch = getopt(argc, argv, "cl:w:")) != -1) switch (ch) { case 'c': colorflag = true; break; case 'l': lines = atoi(optarg); /* lines per screen */ break; case 'w': cols = atoi(optarg); /* coloumns per screen */ break; default: case '?': (void)fprintf(stderr, "usage: ansi2text [-c -w [width] -l [lines]] [file]\n"); exit(EXIT_FAILURE); /* NOTREACHED */ } argv += optind; if (*argv) { if ((fdin = open(*argv, O_RDONLY)) < 0) err("Error opening file: %s", *argv); } screensize = cols * lines; if (screensize < 1) { fprintf(stderr, "Screensize must be at least 1 x 1.\n"); return EXIT_FAILURE; } /* Allocate virtual screen */ screen = malloc(screensize); attributes = malloc(screensize); bgcolor = malloc(screensize); fgcolor = malloc(screensize); /* Initialise virtual screen with spaces */ memset(screen, ' ', screensize); memset(bgcolor, -1, screensize); memset(fgcolor, -1, screensize); memset(attributes, -1, screensize); while ((nr = read(fdin, &buffer, sizeof(buffer))) != -1 && nr != 0) { for(readpos = 0; readpos < nr; readpos++) { if (buffer[readpos] == 0x1b) { csistart = true; memset(ansibuffer, 0, sizeof(ansibuffer)); ansipos = 0; ansinum = 0; ansicode = 0; } if (csistart) { ansibuffer[ansipos] = buffer[readpos]; if (ansibuffer[ansipos] >= '0' && ansipos > 1 && ansibuffer[1] != '[') csistart = false; if (ansibuffer[ansipos] >= 'A' && ansipos > 1 && ansibuffer[1] == '[') { ansicode = ansibuffer[ansipos]; } else ansicode = 0; if (ansicode) { parseansi(); csistart = false; ansicode = 0; } ansipos++; } else { if (buffer[readpos] == 0x0a) { cury++; curx = 1; } if (buffer[readpos] == 0x0d) curx = 1; if (buffer[readpos] == 0x08) { curx--; if (curx < 1) curx = 1; } if (curx > cols) { cury++; curx = 1; } if (cury > lines) { writescreen(); cury = 1; } curpos = ((cury - 1) * cols) + curx - 1; if (curpos == screensize) { cury = curx = 1; curpos = 0; } if (buffer[readpos] >= ' ') { if ((fg_color != 39 || bg_color != 49) && ansiattr == 0) ansiattr = 22; attributes[curpos] = ansiattr; bgcolor[curpos] = bg_color; fgcolor[curpos] = fg_color; screen[curpos] = buffer[readpos]; curx++; } } } } writescreen(); close(fdin); /* free virtual screen */ free(fgcolor); free(bgcolor); free(attributes); free(screen); return EXIT_SUCCESS; } ansi2text.1 .\" $NetBSD: colorbars.6,v 1.3 2012/06/09 23:15:13 njoly Exp $ .\" .\" Copyright (c) 2012, 2013 Nathanial Sloss .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd July 28, 2013 .Dt ANSI2TEXT 1 .Os .Sh NAME .Nm ansi2text .Nd formats ANSI text files or standard input for display .Sh SYNOPSIS .Nm .Op Fl c .Op Fl w Ar width .Op Fl l Ar length .Op Ar file .Sh DESCRIPTION The .Nm command formats ANSI text for display .Bl -tag -width Ds .It Fl c Display formatted text in color suitable for display with less -R .It Fl w Ar width Display formatted text in with a maximum .Ar width in coloumns. Defaults to 80 coloumns. .It Fl l Ar length Display formatted text in with a maximum .Ar length (height) in rows. Defaults to 25 rows. .It Ar file File to display, if not specified standard input is used. .Sh SEE ALSO .Xr less 1 .Sh HISTORY .Nm appeared in .Nx 7.0 . .Sh AUTHORS Nathanial Sloss I hope this is useful. Regards, Nat ------------------------------------------------------------------------ NetBSD Home NetBSD PR Database Search ------------------------------------------------------------------------ (Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $ $NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $ Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.