File indexing completed on 2025-01-12 06:47:24
0001 /*************************************************************************** 0002 cansiparser.cpp - ANSI parser 0003 This file is a part of KMuddy distribution. 0004 ------------------- 0005 begin : Pa Jun 21 2002 0006 copyright : (C) 2002-2007 by Tomas Mecir 0007 email : kmuddy@kmuddy.com 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 ***************************************************************************/ 0018 0019 #define CANSIPARSER_CPP 0020 0021 #include "cansiparser.h" 0022 0023 #include <ctype.h> 0024 0025 #include "coutput.h" 0026 #include "cactionmanager.h" 0027 #include "cglobalsettings.h" 0028 //needed for attribute #define-s 0029 #include "ctextchunk.h" 0030 0031 cANSIParser::cANSIParser (int sess) : cActionBase ("ansiparser", sess) 0032 { 0033 useansi = true; 0034 0035 //default color scheme 0036 mycolor[CL_BLACK] = Qt::black; 0037 mycolor[CL_RED] = Qt::darkRed; 0038 mycolor[CL_GREEN] = Qt::darkGreen; 0039 mycolor[CL_YELLOW] = Qt::darkYellow; 0040 mycolor[CL_BLUE] = Qt::darkBlue; 0041 mycolor[CL_MAGENTA] = Qt::darkMagenta; 0042 mycolor[CL_CYAN] = Qt::darkCyan; 0043 mycolor[CL_WHITE] = Qt::lightGray; 0044 0045 mycolor[CL_BRIGHT | CL_BLACK] = Qt::darkGray; 0046 mycolor[CL_BRIGHT | CL_RED] = Qt::red; 0047 mycolor[CL_BRIGHT | CL_GREEN] = Qt::green; 0048 mycolor[CL_BRIGHT | CL_YELLOW] = Qt::yellow; 0049 mycolor[CL_BRIGHT | CL_BLUE] = Qt::blue; 0050 mycolor[CL_BRIGHT | CL_MAGENTA] = Qt::magenta; 0051 mycolor[CL_BRIGHT | CL_CYAN] = Qt::cyan; 0052 mycolor[CL_BRIGHT | CL_WHITE] = Qt::white; 0053 0054 defcolor = Qt::lightGray; 0055 defbkcolor = Qt::black; 0056 curcolor = defcolor; 0057 curbkcolor = defbkcolor; 0058 0059 flush (); 0060 0061 addEventHandler ("connected", 100, PT_NOTHING); 0062 addGlobalEventHandler ("global-settings-changed", 50, PT_NOTHING); 0063 } 0064 0065 cANSIParser::~cANSIParser() 0066 { 0067 removeEventHandler ("connected"); 0068 removeGlobalEventHandler ("global-settings-changed"); 0069 } 0070 0071 void cANSIParser::eventNothingHandler (QString event, int) 0072 { 0073 if (event == "connected") 0074 flush (); 0075 if (event == "global-settings-changed") { 0076 cGlobalSettings *gs = cGlobalSettings::self(); 0077 for (int i = 0; i < 16; i++) 0078 setColor (gs->getColor("color-" + QString::number (i)), i); 0079 setDefaultTextColor (color (gs->getInt ("fg-color"))); 0080 setDefaultBkColor (color (gs->getInt ("bg-color"))); 0081 } 0082 } 0083 0084 QColor cANSIParser::color (int index) 0085 { 0086 if ((index >= 0) && (index <= 15)) 0087 return mycolor[index]; 0088 else 0089 return Qt::white; //returns white for invalid parameter values 0090 } 0091 0092 void cANSIParser::setColor (QColor color, int index) 0093 { 0094 if ((index >= 0) && (index <= 15)) 0095 mycolor[index] = color; 0096 } 0097 0098 void cANSIParser::parseText (const QString &data) 0099 { 0100 //buffer may contain unfinished ANSI sequences, so we add new input to it... 0101 buffer += data; 0102 //this will contain ansi commands 0103 QString ansicmd = ""; 0104 //this will contain plain text 0105 QString text = ""; 0106 bool inANSI = false; 0107 int len = buffer.length (); 0108 int processed = -1; //variable processed has the same role as one in cTelnet 0109 for (int i = 0; i < len; i++) 0110 { 0111 if (inANSI) 0112 { 0113 char ch = buffer[i].toLatin1(); 0114 ansicmd += ch; 0115 //ANSI commands end with a letter... 0116 if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) 0117 { 0118 inANSI = false; 0119 processed = i; 0120 if (ch == 'm') 0121 //ANSI command that changed color; other commands are 0122 //not interesting (for us at least ;-))... 0123 { 0124 //the text that preceeded this command should be displayed in old 0125 //colors - make it happen! 0126 emit plainText (text); 0127 text = ""; //old text is no longer needed 0128 0129 //the ANSI command is now in ansicmd... 0130 //we parse it, getting all integers and signaling them (each 0131 //integer in this cmd is a code for ANSI color) 0132 int color = 0; 0133 int innumber = false; 0134 int alen = ansicmd.length (); 0135 int codeCount = 0; 0136 0137 for (int j = 0; j < alen; j++) 0138 { 0139 char nn = ansicmd[j].toLatin1(); 0140 if (isdigit (nn)) //a digit is here 0141 { 0142 if (!innumber) 0143 { 0144 innumber = true; 0145 color = 0; 0146 } 0147 color = color * 10 + (nn - 48); //ASCII code for '0' is 48, ... 0148 } 0149 else //something else is here 0150 { 0151 if (innumber) 0152 { 0153 //only emit the signal if we use ANSI colors 0154 if (useansi) 0155 changeColor (color); 0156 color = 0; 0157 codeCount++; 0158 innumber = false; 0159 } 0160 } 0161 } 0162 if (codeCount == 0) 0163 // ESC[m should be treated as ESC[0m 0164 if (useansi) 0165 changeColor (0); 0166 0167 //the text ends in a 'm', so that we don't have to worry about numbers 0168 //ending at the end of the string... 0169 } 0170 ansicmd = ""; 0171 } 0172 } 0173 else 0174 { 0175 if (buffer[i].toLatin1() == 27) //new ANSI command begins... 0176 { 0177 inANSI = true; 0178 //start new ANSI command 0179 ansicmd = buffer[i]; 0180 } 0181 else 0182 { 0183 text += buffer[i]; //this is normal text, no ANSI... 0184 processed = i; 0185 } 0186 } 0187 } 0188 emit plainText (text); 0189 text = ""; //old text is no longer needed 0190 buffer.remove (0, processed + 1); //remove processed data from the buffer 0191 } 0192 0193 void cANSIParser::flush () 0194 { 0195 buffer = ""; 0196 0197 brightactive = false; 0198 blinkactive = false; 0199 italics = false; 0200 underline = false; 0201 strikeout = false; 0202 negactive = false; 0203 invisible = false; 0204 0205 curcolor = defcolor; 0206 curbkcolor = defbkcolor; 0207 emit fgColor (curcolor); 0208 emit bgColor (curbkcolor); 0209 } 0210 0211 QColor cANSIParser::defaultTextColor () 0212 { 0213 return defcolor; 0214 } 0215 0216 void cANSIParser::setDefaultTextColor (QColor color) 0217 { 0218 if (curcolor == defcolor) 0219 { 0220 curcolor = color; 0221 emit fgColor (curcolor); 0222 } 0223 defcolor = color; 0224 } 0225 0226 QColor cANSIParser::defaultBkColor () 0227 { 0228 return defbkcolor; 0229 } 0230 0231 void cANSIParser::setDefaultBkColor (QColor color) 0232 { 0233 if (curbkcolor == defbkcolor) 0234 { 0235 curbkcolor = color; 0236 emit bgColor (curbkcolor); 0237 } 0238 defbkcolor = color; 0239 cOutput *output = dynamic_cast<cOutput *>(object ("output")); 0240 output->setDefaultBkColor (color); 0241 } 0242 0243 void cANSIParser::activateBright () 0244 { 0245 for (int i = 0; i < 8; i++) 0246 if (curcolor == mycolor[i]) 0247 { 0248 curcolor = mycolor[i + 8]; 0249 break; 0250 } 0251 } 0252 0253 void cANSIParser::deactivateBright () 0254 { 0255 for (int i = 8; i < 16; i++) 0256 if (curcolor == mycolor[i]) 0257 { 0258 curcolor = mycolor[i - 8]; 0259 break; 0260 } 0261 } 0262 0263 void cANSIParser::changeColor (int color) 0264 { 0265 //text color 0266 if ((color >= 30) && (color <= 37)) 0267 { 0268 int c = color - 30; 0269 curcolor = mycolor[c]; 0270 if (brightactive) 0271 activateBright (); 0272 emit fgColor (curcolor); 0273 } 0274 else 0275 //text background 0276 if ((color >= 40) && (color <= 47)) 0277 { 0278 curbkcolor = mycolor[color - 40]; 0279 emit bgColor (curbkcolor); 0280 } 0281 else 0282 { 0283 //color code definitions from Ecma-048, page 61 0284 switch (color) { 0285 case 0: //default color 0286 curcolor = defcolor; 0287 curbkcolor = defbkcolor; 0288 blinkactive = false; 0289 brightactive = false; 0290 italics = false; 0291 underline = false; 0292 strikeout = false; 0293 invisible = false; 0294 negactive = false; 0295 emit fgColor (curcolor); 0296 emit bgColor (curbkcolor); 0297 break; 0298 case 1: //BRIGHT 0299 brightactive = true; 0300 activateBright (); 0301 emit fgColor (curcolor); 0302 break; 0303 case 2: //FAINT (DECREASED INTENSITY) 0304 //this is handled as BOLD OFF, I think it's sufficient 0305 brightactive = false; 0306 deactivateBright (); 0307 emit fgColor (curcolor); 0308 break; 0309 case 3: //ITALICS 0310 italics = true; 0311 break; 0312 case 4: //UNDERLINE 0313 underline = true; 0314 break; 0315 case 5: //BLINK 0316 blinkactive = true; 0317 break; 0318 case 6: //RAPID BLINK 0319 //will blink, but NOT rapidly - rapid blinking is pure evil 0320 //both 5 and 6 are cancelled by 25, so we don't have to manage two 0321 //separate flags for this 0322 blinkactive = true; 0323 break; 0324 case 7: //NEGATIVE IMAGE 0325 negactive = true; 0326 break; 0327 case 8: //INVISIBLE 0328 invisible = true; 0329 break; 0330 case 9: //STRIKE OUT 0331 strikeout = true; 0332 break; 0333 //10-19 are font changes. These are not supported. 0334 case 20: //FRAKTUR (GOTHIC) 0335 //gothic is treated as italics 0336 //both italics and gothic are turned off with 23 so I don't need to 0337 //maintain two separate flags 0338 italics = true; 0339 break; 0340 case 21: //DOUBLE UNDERLINE 0341 //this is handled as single underline 0342 //one flag is enough, as both options are disabled with 24 0343 underline = true; 0344 break; 0345 case 22: //BOLD OFF 0346 brightactive = false; 0347 deactivateBright (); 0348 emit fgColor (curcolor); 0349 break; 0350 case 23: //ITALICS OFF 0351 italics = false; 0352 break; 0353 case 24: //UNDERLINE OFF 0354 underline = false; 0355 break; 0356 case 25: //BLINK OFF 0357 blinkactive = false; 0358 break; 0359 //26 is proportional spacing - NOT SUPPORTED 0360 case 27: //POSITIVE IMAGE 0361 negactive = false; 0362 break; 0363 case 28: //VISIBLE 0364 invisible = false; 0365 break; 0366 case 29: //NOT STRIKED OUT 0367 strikeout = false; 0368 break; 0369 //30-37 are colors, see above 0370 //38 is some special color, not supported 0371 case 39: //default color, keep background 0372 curcolor = defcolor; 0373 if (brightactive) activateBright (); 0374 emit fgColor (curcolor); 0375 break; 0376 //40-47 are colors, see above 0377 //48 is some special color, not supported 0378 case 49: //default background, keep text color 0379 curbkcolor = defbkcolor; 0380 emit bgColor (curbkcolor); 0381 break; 0382 //50 means proportional spacing off - not supported 0383 //codes >50 are not supported (these include special effects like 0384 // framed, encircled, overlined and so... 0385 }; 0386 0387 if ((color <= 29) && (color != 1) && (color != 2) && (color != 22)) 0388 { 0389 //attributes may have changed - inform others... 0390 int a = 0; 0391 if (italics) 0392 a += ATTRIB_ITALIC; 0393 if (underline) 0394 a += ATTRIB_UNDERLINE; 0395 if (strikeout) 0396 a += ATTRIB_STRIKEOUT; 0397 if (blinkactive) 0398 a += ATTRIB_BLINK; 0399 if (negactive) 0400 a += ATTRIB_NEGATIVE; 0401 if (invisible) 0402 a += ATTRIB_INVISIBLE; 0403 emit attrib (a); 0404 } 0405 } 0406 } 0407 0408 #include "moc_cansiparser.cpp"