├── .gitignore ├── BUGS ├── Changelog ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── TODO ├── acoc.conf ├── acoc.gemspec ├── bin └── acoc └── lib ├── acoc.rb └── acoc ├── config.rb ├── painter.rb ├── parser.rb ├── program.rb ├── rule.rb └── version.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /BUGS: -------------------------------------------------------------------------------- 1 | # $Id: BUGS,v 1.6 2004/11/01 00:02:49 ianmacd Exp $ 2 | 3 | Known issues with acoc 4 | ---------------------- 5 | 6 | - Interactive programs do not work well with acoc. 7 | 8 | This includes things like 'make config' when building a kernel on Linux, 9 | Ruby's interactive interpreter (irb) and others. This is due to the fact 10 | that acoc's output is line-buffered. 11 | 12 | - TkDiff displays error messages when calling diff via acoc. 13 | 14 | - curses based programs don't always work correctly, such as mtr. 15 | 16 | - Programs that expect to output to a tty may act oddly when called by acoc in 17 | its default mode, since their output is first passed through a pipe to acoc 18 | and only then sent to stdout. 19 | 20 | ls, for example, formats its basic output as a single column if it detects 21 | that it is not outputting to a tty, so the output of 'ls' will be the same 22 | as for 'ls -1' when called via acoc in its default mode. 23 | 24 | The /p program flag was added to acoc 0.3.0 to circumvent this problem. 25 | 26 | - A similar problem used to occur when acoc was invoked via a symlink and 27 | acoc's stdout was not a tty. 28 | 29 | Consider the following line of code from /etc/bashrc on a Red Hat Linux 30 | system: 31 | 32 | if [ "`id -gn`" = "`id -un`" -a `id -u` -gt 99 ]; then 33 | 34 | If id(1) is symlinked to acoc and acoc adds ANSI colour codes to id's 35 | output, the backticks in the above three invocations of id will capture the 36 | colour codes along with the normal output, causing the comparison to fail 37 | with an error. 38 | 39 | For this reason, the default behaviour of acoc as of version 0.2.5 is to 40 | leave command output unaltered if stdout is not a tty. This can be 41 | overridden by specifying the /t flag on a 'program_spec'. 42 | 43 | 44 | If you encounter one of the above problems while invoking a program via a 45 | symlink to acoc and need to avoid running the program through acoc on this 46 | particular occasion, call the program using its full path to ensure that acoc 47 | is bypassed, e.g. 48 | 49 | $ /usr/bin/make config 50 | 51 | instead of: 52 | 53 | $ make config 54 | 55 | If the program is called indirectly, such as diff being called by TkDiff, 56 | circumvent the calling of diff via acoc by passing your program an explicit 57 | path that omits /usr/acoc/bin, e.g. 58 | 59 | $ PATH=/usr/bin:/usr/local/bin:/usr/X11R6/bin tkdiff file1 file2 60 | 61 | Then, the /usr/acoc/bin/diff symlink will not be found when TkDiff invokes 62 | diff. 63 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | 2 | RCS file: /var/cvs/acoc/acoc,v 3 | Working file: acoc 4 | head: 1.67 5 | branch: 6 | locks: strict 7 | access list: 8 | symbolic names: 9 | v0-7-1: 1.67 10 | v0-7-0: 1.65 11 | v0-6-0: 1.62 12 | v0-5-2: 1.58 13 | v0-5-1: 1.57 14 | v0-5-0: 1.56 15 | v0-4-7: 1.53 16 | v0-4-6: 1.52 17 | v0-4-5: 1.51 18 | v0-4-4: 1.47 19 | v0-4-3: 1.46 20 | v0-4-2: 1.44 21 | v0-4-1: 1.38 22 | v0-4-0: 1.37 23 | v0-3-0: 1.33 24 | v0-2-6: 1.25 25 | v0-2-5: 1.22 26 | v0-2-1: 1.20 27 | v0-2-0: 1.19 28 | default: 1.1.1.1 29 | rc: 1.1.1 30 | keyword substitution: kv 31 | total revisions: 68; selected revisions: 68 32 | description: 33 | ---------------------------- 34 | revision 1.67 35 | date: 2005/02/27 01:02:24; author: ianmacd; state: Exp; lines: +5 -5 36 | 37 | Bump version to 0.7.1 and copyright message to include 2005. 38 | ---------------------------- 39 | revision 1.66 40 | date: 2005/02/27 01:01:17; author: ianmacd; state: Exp; lines: +5 -2 41 | 42 | Catch SIGPIPE during exit. 43 | ---------------------------- 44 | revision 1.65 45 | date: 2004/10/31 23:57:33; author: ianmacd; state: Exp; lines: +3 -3 46 | 47 | - bump version to 0.7.0 48 | ---------------------------- 49 | revision 1.64 50 | date: 2004/10/28 09:19:08; author: ianmacd; state: Exp; lines: +3 -3 51 | 52 | - Make it possible to use regular expressions in program specs, 53 | e.g. [ps -.*(e.*f|f.*e)]. Additionally, @spec@ can be used to delimit specs, 54 | instead of [spec]. 55 | ---------------------------- 56 | revision 1.63 57 | date: 2004/10/28 06:34:48; author: ianmacd; state: Exp; lines: +4 -3 58 | 59 | - When removing acoc's path from PATH, remove it multiple times if necessary, 60 | to avoid reinvoking acoc. 61 | ---------------------------- 62 | revision 1.62 63 | date: 2004/10/23 08:49:08; author: ianmacd; state: Exp; lines: +3 -3 64 | 65 | - update to 0.6.0 66 | ---------------------------- 67 | revision 1.61 68 | date: 2004/10/21 09:17:46; author: ianmacd; state: Exp; lines: +7 -3 69 | 70 | - rework assembly of config file list array 71 | ---------------------------- 72 | revision 1.60 73 | date: 2004/10/20 08:59:39; author: ianmacd; state: Exp; lines: +4 -1 74 | 75 | - document $ACOCRC 76 | ---------------------------- 77 | revision 1.59 78 | date: 2004/10/20 08:47:49; author: ianmacd; state: Exp; lines: +3 -3 79 | 80 | - allow a user-definable config file to be given in $ACOCRC 81 | ---------------------------- 82 | revision 1.58 83 | date: 2004/04/05 07:37:51; author: ianmacd; state: Exp; lines: +8 -8 84 | 85 | - bump version to 0.5.2 86 | - command line args expanded by globbing presented problems if the expansion 87 | then contained single quotes (ls on mp3 files would often show this) 88 | - expand ARGV array when passing it to colour method 89 | - remove a superfluous debugging statement 90 | ---------------------------- 91 | revision 1.57 92 | date: 2004/02/05 03:36:20; author: ianmacd; state: Exp; lines: +6 -4 93 | 94 | - properly catch Errno::ECHILD 95 | - update to version 0.5.1 96 | ---------------------------- 97 | revision 1.56 98 | date: 2004/01/12 11:02:32; author: ianmacd; state: Exp; lines: +8 -5 99 | 100 | - sometimes need to catch Errno::ECHILD in waitpid2 101 | ---------------------------- 102 | revision 1.55 103 | date: 2004/01/12 10:57:38; author: ianmacd; state: Exp; lines: +2 -3 104 | 105 | - move a line of comment 106 | ---------------------------- 107 | revision 1.54 108 | date: 2004/01/12 10:31:04; author: ianmacd; state: Exp; lines: +19 -9 109 | 110 | - trap SIGCHLD and make sure non-zero exit status of child process is 111 | passed back to parent, so that we don't accidentally mask failures 112 | - update version to 0.5.0 113 | ---------------------------- 114 | revision 1.53 115 | date: 2003/12/10 10:53:39; author: ianmacd; state: Exp; lines: +5 -5 116 | 117 | - fix bug that caused /r to work only for the first spec that included it 118 | ---------------------------- 119 | revision 1.52 120 | date: 2003/09/12 16:16:15; author: ianmacd; state: Exp; lines: +10 -12 121 | 122 | - programs run in pseudo-tty should not run in their own session 123 | ---------------------------- 124 | revision 1.51 125 | date: 2003/07/31 04:41:35; author: ianmacd; state: Exp; lines: +2 -2 126 | 127 | - update version in documentation 128 | ---------------------------- 129 | revision 1.50 130 | date: 2003/07/31 04:39:56; author: ianmacd; state: Exp; lines: +2 -2 131 | 132 | - update version to 0.4.5 133 | ---------------------------- 134 | revision 1.49 135 | date: 2003/07/31 04:38:40; author: ianmacd; state: Exp; lines: +2 -2 136 | 137 | - handle signals properly 138 | ---------------------------- 139 | revision 1.48 140 | date: 2003/07/24 21:15:03; author: ianmacd; state: Exp; lines: +2 -2 141 | 142 | - why am I trying to trap SIGSTOP? 143 | ---------------------------- 144 | revision 1.47 145 | date: 2003/07/18 09:55:12; author: ianmacd; state: Exp; lines: +10 -5 146 | 147 | - Ruby 1.6.x can't take rescue as a statement modifier 148 | ---------------------------- 149 | revision 1.46 150 | date: 2003/07/18 08:44:09; author: ianmacd; state: Exp; lines: +3 -3 151 | 152 | - increase version to 0.4.3 153 | ---------------------------- 154 | revision 1.45 155 | date: 2003/07/18 08:35:16; author: ianmacd; state: Exp; lines: +23 -9 156 | 157 | - go back to using Masahiro Tomita's Ruby/TPty library, after problems 158 | with standard PTY library 159 | ---------------------------- 160 | revision 1.44 161 | date: 2003/07/17 05:47:28; author: ianmacd; state: Exp; lines: +4 -4 162 | 163 | - update to version 0.4.2 164 | ---------------------------- 165 | revision 1.43 166 | date: 2003/07/15 09:44:53; author: ianmacd; state: Exp; lines: +51 -41 167 | 168 | - modularise the colouring code by putting it into its own method, colour_line 169 | ---------------------------- 170 | revision 1.42 171 | date: 2003/07/15 09:29:49; author: ianmacd; state: Exp; lines: +7 -21 172 | 173 | - use standard PTY module, rather than Ruby/TPty 174 | ---------------------------- 175 | revision 1.41 176 | date: 2003/07/15 08:58:09; author: ianmacd; state: Exp; lines: +4 -3 177 | 178 | - add RD paragraph on use of $ACOC 179 | ---------------------------- 180 | revision 1.40 181 | date: 2003/07/15 08:44:59; author: ianmacd; state: Exp; lines: +3 -3 182 | 183 | - no colouring if $ACOC == 'none' 184 | ---------------------------- 185 | revision 1.39 186 | date: 2003/07/14 03:27:42; author: ianmacd; state: Exp; lines: +3 -6 187 | 188 | - minor simplification 189 | ---------------------------- 190 | revision 1.38 191 | date: 2003/07/08 06:57:48; author: ianmacd; state: Exp; lines: +7 -7 192 | 193 | - fix bug whereby arguments containing white space were expanded to 194 | multiple arguments 195 | ---------------------------- 196 | revision 1.37 197 | date: 2003/07/06 22:42:23; author: ianmacd; state: Exp; lines: +5 -5 198 | 199 | - update to 0.4.0 200 | ---------------------------- 201 | revision 1.36 202 | date: 2003/07/03 06:41:08; author: ianmacd; state: Exp; lines: +12 -3 203 | 204 | - when trying to match the program specs against the command line, try to 205 | match the longest (i.e. most specific) spec first, so that if there's a 206 | config for, for example, 'ps ax', it will match before the one for 'ps a' 207 | ---------------------------- 208 | revision 1.35 209 | date: 2003/07/01 08:20:32; author: ianmacd; state: Exp; lines: +16 -12 210 | 211 | - move more stuff into 'colour' method 212 | ---------------------------- 213 | revision 1.34 214 | date: 2003/07/01 07:48:57; author: ianmacd; state: Exp; lines: +19 -15 215 | 216 | - implement argument-specific colouring, so that colouring depends on how 217 | the command was invoked 218 | ---------------------------- 219 | revision 1.33 220 | date: 2003/06/30 02:17:37; author: ianmacd; state: Exp; lines: +3 -3 221 | 222 | - update version to 0.3.0 223 | ---------------------------- 224 | revision 1.32 225 | date: 2003/06/30 01:53:27; author: ianmacd; state: Exp; lines: +6 -6 226 | 227 | - avoid unnecessary use of * operator with ARGV 228 | ---------------------------- 229 | revision 1.31 230 | date: 2003/06/29 00:49:08; author: ianmacd; state: Exp; lines: +2 -2 231 | 232 | - call our own run method, not exec when running target program in fork 233 | for pty 234 | ---------------------------- 235 | revision 1.30 236 | date: 2003/06/29 00:29:51; author: ianmacd; state: Exp; lines: +96 -64 237 | 238 | - 'require' optional Ruby/TPty for pseudo-terminal usage 239 | - move colouring code into its own method, colour 240 | - new program flag /p allocates a pseudo-terminal through which to run the 241 | target program 242 | ---------------------------- 243 | revision 1.29 244 | date: 2003/06/27 16:11:21; author: ianmacd; state: Exp; lines: +10 -7 245 | 246 | - subsequent program specs for a given program were replacing all previous 247 | ones 248 | ---------------------------- 249 | revision 1.28 250 | date: 2003/06/27 07:50:18; author: ianmacd; state: Exp; lines: +6 -8 251 | 252 | - a method contains an implicit begin/end block 253 | ---------------------------- 254 | revision 1.27 255 | date: 2003/06/27 07:19:27; author: ianmacd; state: Exp; lines: +70 -55 256 | 257 | - program specs are now Program objects, rather than arrays of hashes. 258 | The colour specs that used to form the values of the hash and were, 259 | themselves, a hash of arrays, are now Rule objects. 260 | 261 | This allows us to eliminate the @flags hash completely and simplify 262 | other parts of the code. 263 | ---------------------------- 264 | revision 1.26 265 | date: 2003/06/26 07:46:25; author: ianmacd; state: Exp; lines: +6 -4 266 | 267 | - merely exec() the program if there *is* a configuration stanza, but it 268 | contains *no* rules 269 | ---------------------------- 270 | revision 1.25 271 | date: 2003/06/26 04:19:46; author: ianmacd; state: Exp; lines: +10 -3 272 | 273 | - bump version to 0.2.6 274 | - space out some of the code blocks a little 275 | ---------------------------- 276 | revision 1.24 277 | date: 2003/06/26 04:17:34; author: ianmacd; state: Exp; lines: +2 -2 278 | 279 | - parse /usr/local/etc/acoc.conf after /etc/acoc.conf 280 | ---------------------------- 281 | revision 1.23 282 | date: 2003/06/26 04:16:56; author: ianmacd; state: Exp; lines: +7 -1 283 | 284 | - add new operational flag, /r, which removes all previous matching rules 285 | for the given program 286 | ---------------------------- 287 | revision 1.22 288 | date: 2003/06/21 10:27:01; author: ianmacd; state: Exp; lines: +22 -14 289 | 290 | - by default, output is not coloured if stdout is not a tty 291 | - add new program flag /t for allowing output to be coloured even when stdout 292 | is not a tty 293 | ---------------------------- 294 | revision 1.21 295 | date: 2003/06/20 23:22:28; author: ianmacd; state: Exp; lines: +3 -3 296 | 297 | - exec command without colouring if STDOUT is not a tty. There's no point 298 | having colour output that you'll never see and scripts that capture 299 | command output don't like it either. 300 | ---------------------------- 301 | revision 1.20 302 | date: 2003/06/20 08:53:55; author: ianmacd; state: Exp; lines: +3 -3 303 | 304 | - update version to 0.2.1 305 | ---------------------------- 306 | revision 1.19 307 | date: 2003/06/11 07:31:42; author: ianmacd; state: Exp; lines: +3 -3 308 | 309 | - change version to 0.2.0 310 | ---------------------------- 311 | revision 1.18 312 | date: 2003/06/10 01:38:35; author: ianmacd; state: Exp; lines: +10 -3 313 | 314 | - catch a SIGPIPE while printing 315 | - error message if we're called on a non-existent program should go to 316 | stderr, not stdout 317 | ---------------------------- 318 | revision 1.17 319 | date: 2003/06/09 10:22:03; author: ianmacd; state: Exp; lines: +1 -2 320 | 321 | - remove bug about program flags needing to appear on final stanza 322 | ---------------------------- 323 | revision 1.16 324 | date: 2003/06/09 10:07:10; author: ianmacd; state: Exp; lines: +3 -2 325 | 326 | - make program flags cumulative with each stanza 327 | ---------------------------- 328 | revision 1.15 329 | date: 2003/06/08 06:39:16; author: ianmacd; state: Exp; lines: +3 -2 330 | 331 | - check for a config file at /usr/local/etc/acoc.conf, too 332 | ---------------------------- 333 | revision 1.14 334 | date: 2003/06/08 06:23:47; author: ianmacd; state: Exp; lines: +14 -6 335 | 336 | - update RD documentation 337 | ---------------------------- 338 | revision 1.13 339 | date: 2003/06/08 02:03:33; author: ianmacd; state: Exp; lines: +3 -2 340 | 341 | - minor documentation fix 342 | ---------------------------- 343 | revision 1.12 344 | date: 2003/06/08 01:52:52; author: ianmacd; state: Exp; lines: +12 -6 345 | 346 | - improve documentation 347 | ---------------------------- 348 | revision 1.11 349 | date: 2003/06/08 00:49:10; author: ianmacd; state: Exp; lines: +2 -2 350 | 351 | - RD documentation didn't parse 352 | ---------------------------- 353 | revision 1.10 354 | date: 2003/06/08 00:32:19; author: ianmacd; state: Exp; lines: +72 -6 355 | 356 | - include version and usage methods 357 | - catch ENOENT when trying to call a non-existant command 358 | - add some RD documentation 359 | - rename to acoc 360 | ---------------------------- 361 | revision 1.9 362 | date: 2003/06/06 06:45:16; author: ianmacd; state: Exp; lines: +2 -2 363 | 364 | - fix bug whereby data in config stanzas for a command would be overwritten 365 | as soon as a later stanza was parsed 366 | ---------------------------- 367 | revision 1.8 368 | date: 2003/06/06 06:29:11; author: ianmacd; state: Exp; lines: +3 -3 369 | 370 | - state config file name when parsing fails 371 | ---------------------------- 372 | revision 1.7 373 | date: 2003/06/06 03:56:01; author: ianmacd; state: Exp; lines: +3 -3 374 | 375 | - change all references to rc into references to rcf. rc conflicts with 376 | Red Hat's Red Carpet service. 377 | - .spec file now Obsoletes rc 378 | ---------------------------- 379 | revision 1.6 380 | date: 2003/06/05 16:58:51; author: ianmacd; state: Exp; lines: +4 -4 381 | 382 | - fix some white space 383 | ---------------------------- 384 | revision 1.5 385 | date: 2003/06/05 06:03:13; author: ianmacd; state: Exp; lines: +18 -7 386 | 387 | - allow for multiple colour attributes, such as 'bold + red', etc. 388 | ---------------------------- 389 | revision 1.4 390 | date: 2003/06/04 05:21:52; author: ianmacd; state: Exp; lines: +3 -3 391 | 392 | - Ruby 1.6 doesn't have String#to_sym or the Signal class, so work around 393 | this 394 | ---------------------------- 395 | revision 1.3 396 | date: 2003/06/03 23:29:55; author: ianmacd; state: Exp; lines: +9 -4 397 | 398 | - add symlink handling code 399 | ---------------------------- 400 | revision 1.2 401 | date: 2003/06/03 05:42:14; author: ianmacd; state: Exp; lines: +5 -1 402 | 403 | - check if the command used to invoke the program is a symlink. If it is, 404 | remove its directory from the $PATH and then add the program's name to 405 | the start of ARGV. 406 | 407 | This allows us to use both: 408 | 409 | $ rc command arg1 arg2 ... 410 | 411 | and 412 | 413 | $ command arg1 arg2 ... 414 | 415 | to invoke the program either directly or indirectly 416 | ---------------------------- 417 | revision 1.1 418 | date: 2003/06/02 10:04:14; author: ianmacd; state: Exp; 419 | branches: 1.1.1; 420 | Initial revision 421 | ---------------------------- 422 | revision 1.1.1.1 423 | date: 2003/06/02 10:04:14; author: ianmacd; state: Exp; lines: +0 -0 424 | 425 | - initial check-in 426 | ============================================================================= 427 | 428 | RCS file: /var/cvs/acoc/acoc.conf,v 429 | Working file: acoc.conf 430 | head: 1.34 431 | branch: 432 | locks: strict 433 | access list: 434 | symbolic names: 435 | v0-7-1: 1.34 436 | v0-7-0: 1.34 437 | v0-6-0: 1.31 438 | v0-5-2: 1.29 439 | v0-5-1: 1.29 440 | v0-5-0: 1.29 441 | v0-4-7: 1.29 442 | v0-4-6: 1.28 443 | v0-4-5: 1.26 444 | v0-4-4: 1.26 445 | v0-4-3: 1.26 446 | v0-4-2: 1.26 447 | v0-4-1: 1.24 448 | v0-4-0: 1.24 449 | v0-3-0: 1.20 450 | v0-2-6: 1.19 451 | v0-2-5: 1.18 452 | v0-2-1: 1.17 453 | v0-2-0: 1.16 454 | default: 1.1.1.1 455 | rc: 1.1.1 456 | keyword substitution: kv 457 | total revisions: 35; selected revisions: 35 458 | description: 459 | ---------------------------- 460 | revision 1.34 461 | date: 2004/10/29 07:41:32; author: ianmacd; state: Exp; lines: +6 -6 462 | 463 | - fix colouring for top(1), so that it works with the versions from procps 464 | 2.x and 3.x 465 | ---------------------------- 466 | revision 1.33 467 | date: 2004/10/29 06:56:21; author: ianmacd; state: Exp; lines: +4 -5 468 | 469 | - convert to using regexes in program specs, for better matching 470 | ---------------------------- 471 | revision 1.32 472 | date: 2004/10/23 19:00:38; author: ianmacd; state: Exp; lines: +3 -2 473 | 474 | - allow ls to colour when -h is given 475 | ---------------------------- 476 | revision 1.31 477 | date: 2004/10/21 07:46:53; author: ianmacd; state: Exp; lines: +49 -5 478 | 479 | - apt-cache, apt-get, nmap, netstat, lsmod and whereis colouring adapted 480 | from patterns sent in by Kototama 481 | ---------------------------- 482 | revision 1.30 483 | date: 2004/10/20 09:10:06; author: ianmacd; state: Exp; lines: +10 -1 484 | 485 | - add config for Ruby, supplied by Gavin Sinclair 486 | ---------------------------- 487 | revision 1.29 488 | date: 2003/10/08 03:50:15; author: ianmacd; state: Exp; lines: +3 -3 489 | 490 | - ifconfig fixes 491 | ---------------------------- 492 | revision 1.28 493 | date: 2003/09/12 16:09:29; author: ianmacd; state: Exp; lines: +2 -2 494 | 495 | - ping behaves differently because of isatty(3), so use a pseudo-TTY 496 | ---------------------------- 497 | revision 1.27 498 | date: 2003/08/14 18:10:47; author: ianmacd; state: Exp; lines: +3 -3 499 | 500 | - minor ping and traceroute fix 501 | ---------------------------- 502 | revision 1.26 503 | date: 2003/07/17 05:42:14; author: ianmacd; state: Exp; lines: +4 -4 504 | 505 | - fix traceroute colouring for TTLs under 10ms 506 | - colour traceroute errors 507 | ---------------------------- 508 | revision 1.25 509 | date: 2003/07/16 08:32:07; author: ianmacd; state: Exp; lines: +2 -2 510 | 511 | - diff output should not be coloured when not going to stdout 512 | ---------------------------- 513 | revision 1.24 514 | date: 2003/07/06 23:00:39; author: ianmacd; state: Exp; lines: +2 -2 515 | 516 | - 'ps a' will match more than 'ps ax' 517 | ---------------------------- 518 | revision 1.23 519 | date: 2003/07/03 06:43:24; author: ianmacd; state: Exp; lines: +4 -4 520 | 521 | - don't show command lines in bold 522 | ---------------------------- 523 | revision 1.22 524 | date: 2003/07/01 08:54:00; author: ianmacd; state: Exp; lines: +14 -6 525 | 526 | - make rpm rules specific to package building 527 | - add rpm rules for querying packages 528 | ---------------------------- 529 | revision 1.21 530 | date: 2003/07/01 07:54:42; author: ianmacd; state: Exp; lines: +11 -3 531 | 532 | - apply diff rules to 'cvs diff' and 'p4 diff', too 533 | - add rules for 'ps ax' and 'ps -ef' 534 | ---------------------------- 535 | revision 1.20 536 | date: 2003/06/28 08:20:10; author: ianmacd; state: Exp; lines: +5 -4 537 | 538 | - ls needs a pseudo-terminal 539 | - fix diff rule 540 | ---------------------------- 541 | revision 1.19 542 | date: 2003/06/26 05:02:46; author: ianmacd; state: Exp; lines: +4 -4 543 | 544 | - correct and improve rules for ls 545 | ---------------------------- 546 | revision 1.18 547 | date: 2003/06/21 10:02:40; author: ianmacd; state: Exp; lines: +7 -7 548 | 549 | - add /t flag for programs that are unlikely to be used in scripts 550 | ---------------------------- 551 | revision 1.17 552 | date: 2003/06/20 08:55:51; author: ianmacd; state: Exp; lines: +41 -4 553 | 554 | - diff section now also applies to rcsdiff 555 | - make section now also applies to gmake 556 | - new config sections for tcpdump, ldd, nm, strace, ltrace, id and ls 557 | ---------------------------- 558 | revision 1.16 559 | date: 2003/06/11 01:16:37; author: ianmacd; state: Exp; lines: +2 -2 560 | 561 | - minimal support for context diffs, too 562 | ---------------------------- 563 | revision 1.15 564 | date: 2003/06/11 01:10:49; author: ianmacd; state: Exp; lines: +15 -9 565 | 566 | - diff rules now handle standard format as well as unified format 567 | - break out rpmbuild rules into gcc and make rules 568 | ---------------------------- 569 | revision 1.14 570 | date: 2003/06/08 02:16:07; author: ianmacd; state: Exp; lines: +2 -2 571 | 572 | - top show's command lines of processes run by root in red, not the word 573 | 'root' 574 | ---------------------------- 575 | revision 1.13 576 | date: 2003/06/08 00:47:19; author: ianmacd; state: Exp; lines: +3 -3 577 | 578 | - rename all references to rcf to acoc 579 | ---------------------------- 580 | revision 1.12 581 | date: 2003/06/06 07:13:57; author: ianmacd; state: Exp; lines: +7 -7 582 | 583 | - fix ifconfig 584 | ---------------------------- 585 | revision 1.11 586 | date: 2003/06/06 07:04:56; author: ianmacd; state: Exp; lines: +20 -5 587 | 588 | - add route and ifconfig rules 589 | - remove the vmstat header colouring - it didn't work 590 | - simplify the df stuff 591 | ---------------------------- 592 | revision 1.10 593 | date: 2003/06/06 06:20:52; author: ianmacd; state: Exp; lines: +5 -1 594 | 595 | - rules for df 596 | ---------------------------- 597 | revision 1.9 598 | date: 2003/06/06 03:56:01; author: ianmacd; state: Exp; lines: +2 -2 599 | 600 | - change all references to rc into references to rcf. rc conflicts with 601 | Red Hat's Red Carpet service. 602 | - .spec file now Obsoletes rc 603 | ---------------------------- 604 | revision 1.8 605 | date: 2003/06/05 16:59:19; author: ianmacd; state: Exp; lines: +36 -1 606 | 607 | - top and vmstat rules 608 | ---------------------------- 609 | revision 1.7 610 | date: 2003/06/05 06:00:02; author: ianmacd; state: Exp; lines: +6 -1 611 | 612 | - extra config line for rpmbuild 613 | ---------------------------- 614 | revision 1.6 615 | date: 2003/06/04 03:35:53; author: ianmacd; state: Exp; lines: +5 -3 616 | 617 | - ping fixes and improvements 618 | ---------------------------- 619 | revision 1.5 620 | date: 2003/06/04 00:37:58; author: ianmacd; state: Exp; lines: +5 -1 621 | 622 | - add place-holder [default] section 623 | ---------------------------- 624 | revision 1.4 625 | date: 2003/06/03 23:06:40; author: ianmacd; state: Exp; lines: +10 -2 626 | 627 | - numerous additions and fixes 628 | ---------------------------- 629 | revision 1.3 630 | date: 2003/06/03 05:47:58; author: ianmacd; state: Exp; lines: +2 -2 631 | 632 | - add /a flag to traceroute to ensure all 3 packets per line are matched 633 | ---------------------------- 634 | revision 1.2 635 | date: 2003/06/02 10:22:43; author: ianmacd; state: Exp; lines: +1 -0 636 | 637 | - added Id tag 638 | ---------------------------- 639 | revision 1.1 640 | date: 2003/06/02 09:47:32; author: ianmacd; state: Exp; 641 | branches: 1.1.1; 642 | Initial revision 643 | ---------------------------- 644 | revision 1.1.1.1 645 | date: 2003/06/02 09:47:32; author: ianmacd; state: Exp; lines: +0 -0 646 | 647 | - initial check-in 648 | ============================================================================= 649 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in acoc.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # acoc - arbitrary command output colourer 2 | 3 | `acoc` is a regular expression based colour formatter for programs 4 | that display output on the command-line. 5 | 6 | It works as a wrapper around the target program, executing it 7 | and capturing the stdout stream. Optionally, stderr can 8 | be redirected to stdout, so that it, too, can be manipulated. 9 | 10 | `acoc` then applies matching rules to patterns in the output 11 | and applies colour sets to those matches. 12 | 13 | ## Usage 14 | 15 | Just call the command you want to color after `acoc`. 16 | Arguments are passed normally: 17 | 18 | acoc command [arg1 .. argN] 19 | 20 | For example, to color the output of the `ping` command, do: 21 | 22 | acoc ping http://host.com -c 3 23 | 24 | `acoc` supports the following command-line options: 25 | 26 | | Option | Description | 27 | | ------------------- | ----------- | 28 | |`-h` or `--help` | Display usage information. | 29 | | `-v` or `--version` | Display version information. | 30 | 31 | ## Installation 32 | 33 | `acoc` depends on the [Term::ANSIColor][term] module. Installing it as a RubyGem 34 | should solve all dependencies, though: 35 | 36 | $ gem install acoc 37 | 38 | `acoc` can also make use of [Masahiro Tomita's Ruby/TPty][tpty] library to 39 | allocate pseudo-terminals in order to fool those programs that behave 40 | differently if their *stdout* stream is not connected to a tty. `ls` is one 41 | such program. 42 | 43 | Whilst `Ruby/TPty` is not mandatory (`acoc` will ignore its absence), 44 | it's installation is recommended in order to improve the 45 | transparency of `acoc`'s operation. 46 | 47 | ## Configuration 48 | 49 | Out-of-the-box, `acoc` provides coloring for the following commands: 50 | 51 | * diff 52 | * ping 53 | * traceroute 54 | * make, configure 55 | * rpm, rmpbuild 56 | * w, top, df 57 | * vmstat 58 | * nmap, netstat 59 | * ifconfig, route, tcpdump 60 | * gcc, ldd, nm 61 | * strace, ltrace 62 | * id, ps 63 | * apt-cache search, apt-cache show 64 | * apt-get install, apt-get remove 65 | * lsmod, whereis 66 | 67 | You can customize it to color the output of any command you want. 68 | To do so, follow the steps: 69 | 70 | 1. Open one of the configuration files (see below); 71 | 2. Add a _section_ to the program you want; 72 | 3. Add a _regular expression_, marking important parts, followed by _their 73 | colors_; 74 | 75 | For example, the command `mount` outputs the following: 76 | 77 | $ mount 78 | proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) 79 | sys on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) 80 | ... 81 | /dev/sda2 on /home type ext4 (rw,relatime,data=ordered) 82 | 83 | Note that it has a well-defined structure - it's quite like this: 84 | 85 | "A" on "B" type "C" ("D") 86 | 87 | So to make _the first block cyan_, _the second block blue_ and the _third block 88 | red_, add the following to the configuration file: 89 | 90 | # My custom colors for "mount" 91 | [mount] 92 | /^(.*) on (.*) .*$/ cyan,blue+bold 93 | /type (.*)/ red 94 | 95 | Note that you can put as many regular expressions as you want 96 | inside the command section. Last ones have higher precedence. 97 | 98 | So, here's the rules: 99 | 100 | * **Command**: must be between `[]`s; 101 | * **Regular Expression*: must be between `//`s; 102 | * **Colors**: must be in a whole block (cannot have spaces); 103 | 104 | ### Files 105 | 106 | By reading the regular expressions on the configuration file, 107 | `acoc` decides how to color the output. 108 | 109 | Here's the order of reading (with the last one taking precedence over the 110 | first): 111 | 112 | 1. `/usr/local/etc/acoc.conf` 113 | 2. `/etc/acoc.conf` 114 | 3. `~/.acoc.conf` 115 | 116 | **NOTE:** When you run `acoc` for the first time, it places an 117 | example file on your home directory. Instructions on how to 118 | customize and add your commands are included there. 119 | 120 | ### Environment Variables 121 | 122 | `acoc` also responds to environment variables. You'd normally 123 | use them like this: 124 | 125 | $ export VAR="value" 126 | $ acoc 127 | 128 | If `ACOC` is set to `none`, no colouring will be performed. 129 | 130 | If `ACOCRC` is set, specifies the location of an additional 131 | configuration file. 132 | 133 | ## Screenshots 134 | 135 | **traceroute (green = fast, red = slow)** 136 | 137 | ![traceroute](http://caliban.org/images/traceroute.png) 138 | 139 | **w (neat colors)** 140 | 141 | ![w](http://caliban.org/images/w.png) 142 | 143 | **top (with root's processes shown in red)** 144 | 145 | ![top](http://caliban.org/images/top.png) 146 | 147 | ## Contributing 148 | 149 | `acoc` is only as good as the configuration file that it uses. Please share your 150 | pattern-matching rules, it could be very helpful for everyone! 151 | 152 | To share (and see other community-created patterns), go to 153 | [the acoc wiki][wiki]. 154 | 155 | If you feel that your command is important, [open an issue on GitHub][issues] or 156 | [mail me](mailto:eu@alexdantas.net) and it could get included on a subsequent 157 | release! 158 | 159 | ## Bugs 160 | 161 | * Nested regular expressions do not work well. 162 | Inner subexpressions need to use clustering (?:), 163 | not capturing (). 164 | In other words, they can be used for matching, 165 | but not for colouring. 166 | 167 | ## Author 168 | 169 | * `acoc` was originally written by Ian Macdonald 170 | ([Homepage][ian-home]); 171 | * It is currently being maintained by Alexandre Dantas 172 | ([Homepage][kure-home]); 173 | 174 | ## License 175 | 176 | Copyright (C) 2003-2004 Ian Macdonald 177 | 178 | This program is free software; you can redistribute it and/or modify 179 | it under the terms of the GNU General Public License as published by 180 | the Free Software Foundation; either version 2, or (at your option) 181 | any later version. 182 | 183 | This program is distributed in the hope that it will be useful, 184 | but WITHOUT ANY WARRANTY; without even the implied warranty of 185 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 186 | GNU General Public License for more details. 187 | 188 | You should have received a copy of the GNU General Public License 189 | along with this program; if not, write to the Free Software Foundation, 190 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 191 | 192 | [ian-home]: http://www.caliban.org/ruby/ 193 | [kure-home]: http://www.alexdantas.net/ 194 | [term]: http://raa.ruby-lang.org/list.rhtml?name=ansicolor 195 | [tpty]: http://www.tmtm.org/ruby/tpty/ 196 | [github]: https://github.com/alexdantas/acoc 197 | [issues]: https://github.com/alexdantas/acoc/issues 198 | [wiki]: https://github.com/alexdantas/acoc/wiki 199 | 200 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | $Id: TODO,v 1.12 2005/02/27 01:05:20 ianmacd Exp $ 2 | 3 | - add many more sample rules to acoc.conf 4 | 5 | - fix pseudo-tty handling to be bidirectional 6 | 7 | 8 | Maybes 9 | ------ 10 | 11 | - new config file format with more flexible syntax 12 | -------------------------------------------------------------------------------- /acoc.conf: -------------------------------------------------------------------------------- 1 | # sample configuration file for acoc 2 | # 3 | # $Id: acoc.conf,v 1.35 2005/02/27 02:08:43 ianmacd Exp $ 4 | 5 | # tabstop should be 8 in this file 6 | # 7 | #[default] 8 | # 9 | # default rules go here 10 | 11 | # all kinds of diffs 12 | [diff,rcsdiff/t,cvs diff/t,p4 diff/t] 13 | /^([+>*].*)/ green 14 | /^([-<].*)/ red 15 | /^(@@.*|diff.*|[\d,acd]+)/ blue 16 | 17 | [ping/ap] 18 | # hostname and IP address 19 | /from (\S+) \(((?:\d?\d?\d\.){3}\d?\d?\d)/ bold 20 | # < 100 ms RTT 21 | /(\d\d?\.\d+ ms)/ green 22 | # > 100 ms RTT 23 | /[^.](1\d\d ms)/ yellow 24 | # > 200 ms RTT 25 | /[^.]([2-9]\d\d\d? ms)/ red 26 | # end report 27 | /(\d+) packets transmitted, (\d+) received, (\d+%) packet loss, time (\d+ms)/ bold 28 | @rtt min/avg/max/mdev = (\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+ ms)@ bold 29 | 30 | [tracepath,traceroute/a] 31 | # < 100 ms RTT 32 | /[^\d]\d\d?\.\d* ?ms/g green 33 | # > 100 ms RTT 34 | /1\d\d\.\d* ?ms/g yellow 35 | # > 200 ms RTT 36 | /[2-9]\d\d\d?\.\d* ?ms/g red 37 | # no response or TTL < 1 38 | /(\*|![HNPSFXVC]?|no reply)/g red 39 | 40 | # compilation and package building 41 | [make,gmake,rpmbuild -b,rpmbuild --rebuild,rpm -b,rpm --rebuild] 42 | /^(make.*)$/ yellow 43 | 44 | [configure,rpmbuild -b,rpmbuild --rebuild,rpm -b,rpm --rebuild] 45 | /^(checking .+\.\.\.) (yes)$/ yellow,green 46 | /^(checking .+\.\.\.) (no)$/ yellow,red 47 | /^(checking .+\.\.\.) ?(?!yes|no)(.+)$/ yellow,magenta 48 | 49 | [make,gmake,cc,gcc,rpmbuild -b,rpmbuild --rebuild,rpm -b,rpm --rebuild] 50 | /(\S+\.c)\b/ cyan 51 | /-o\s+(\S+(?:\.o)?)\b/ green 52 | /\s(-l\S+)\b/g magenta 53 | /^([^:]+): (In function `)(.+)(':)/ green,yellow,cyan,yellow 54 | /^([^:]+):(\d+): (warning: [^`]+`)([^']+)(.+)$/ green,bold,yellow,cyan,yellow 55 | /^([^:]+):(\d+): (warning: [^`]+)$/ green,bold,yellow 56 | 57 | # package building 58 | [rpmbuild -b/ae,rpmbuild --rebuild/ae,rpm -b/ae,rpm --rebuild/ae] 59 | /^(\+.*)$/ bold 60 | /^(Executing)([^:]+): (.+)$/ yellow,cyan,green 61 | /^(Patch #\d+) \((.+)\):$/ yellow,green 62 | /^(Wrote: )(.+)/ yellow,green 63 | 64 | # package querying 65 | [rpm -.*(q.*i|i.*q)/a,rpm -.*(q.*p.*i|q.*i.*p|p.*i.*q|p.*q.*i|i.*p.*q|i.*q.*p)/a] 66 | /^(Name|Version|Release|Install Date|Group|Size)\s*: (.+)\s\s/ yellow,green 67 | /(^Signature|^Packager|^URL|^Summary|Relocations|Vendor|Build (?:Date|Host)|Source RPM|License)\s*: (.+)$/ yellow,green 68 | 69 | [w/a] 70 | /^(\S+)\s+(\S+)\s+(\S+)\s+(.{7})\s+\S+\s+(\S+)\s+(\S+)\s+(.+)$/ bold,blue,bold,yellow,green,green,magenta 71 | /(\d+days)/ red 72 | 73 | #[irb] 74 | # irb doesn't function correctly 75 | #/^irb\(([^)]+)\):(\d+):(\d+)(.)/ bold,yellow,cyan,green 76 | 77 | # Highlight Ruby source files, etc., when there's an exception. 78 | #[ruby/er] 79 | # message and error class 80 | #/:\d+:in `.*?': (.*) \((\w+)\)\s*$/ bold,red+bold 81 | # file name and line number 82 | #/^(?:\s+from)?(.*?):(\d+)/ green+bold,yellow+bold 83 | # method name 84 | #/:in `(.*?)'/ cyan+bold 85 | 86 | [vmstat] 87 | # load 88 | /^\s+([5-9]\d*).*/ yellow 89 | /^\s+([1-9]\d+).*/ red 90 | # free RAM 91 | /^\s+\S+\s+\S+\s+\S+\s+(\d\d)\s+.*/ red 92 | 93 | [top/a] 94 | # load average < 0.70 95 | /0\.[0-6]\d(?!\s+\w)/g green+bold 96 | # load average 0.99 < load < 0.70 97 | /0\.[7-9]\d(?!\s+\w)/g yellow+bold 98 | # load average > 1.00 99 | /[^0]\.\d\d(?!\s+\w)/g red+bold 100 | # process information 101 | /^(\d+) processes\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d)/ cyan+bold 102 | # header percentages, except for idle 103 | /\d+\.\d+% (?!idle)/g cyan+bold 104 | # idle percentage 0 - 19% 105 | /((?:1\d|[^\d]\d)\.\d%) idle/ red+bold 106 | # idle percentage 20 - 49% 107 | /([2-4]\d\.\d%) idle/ yellow+bold 108 | # idle percentage 50 - 100% 109 | /(1?[5-9]\d\.\d%) idle/ green+bold 110 | # memory 111 | /\d+k/g cyan+bold 112 | # root processes 113 | /root\s+(?:\S+\s+){9}(?:\d\s+)?(.+)$/ red 114 | # stat names (doesn't quite work) 115 | /\b(up|load average|processes|sleeping|running|zombie|stopped|user|system|nice|iowait|av|used|free|shrd|buff|(?:in)?active|cached)\b/g magenta+bold 116 | # zombies and processes in uninterruptible sleep 117 | /\b([ZD])\b/ red 118 | 119 | [df] 120 | # header line 121 | /([A-Z][a-z]+(?:%| on)?)/g white+bold 122 | # filesystem 123 | /^(?!Filesystem)(.*?)\s/ blue 124 | # 91 - 95% full 125 | /.*(9[1-5]%)\s+(.+)$/ yellow,bold 126 | # 96 - 100% full 127 | /.*(9[6-9]%|100%)\s+(.+)$/ red,bold 128 | # mount points 129 | /\s(\/.*?)$/ green 130 | 131 | [ifconfig,route] 132 | # IP addresses 133 | /(?:\d?\d?\d\.){3}\d?\d?\d/g cyan 134 | 135 | [route/a] 136 | # interface 137 | /([a-z]+\d+|lo)$/ magenta 138 | 139 | [ifconfig/ae] 140 | /^(\S+).*((?:[\dA-F][\dA-F]:){5}[\dA-F][\dA-F])/ magenta 141 | /[RT]X packets:(\d+).*(?:frame|carrier):(\d+)/ green 142 | /errors:([^0]+)\s+dropped:([^0]+)\s+overruns:([^0]+)/ red 143 | /collisions:([^0][\d\s]*)/ red 144 | /RX bytes:(\d+)\s+\(([^)]+)\)\s+TX bytes:(\d+)\s+\(([^)]+)\)/ green 145 | 146 | [tcpdump/t] 147 | # ARP 148 | /^(\d\d:\d\d:\d\d\.\d+)\s+(arp\s+\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/ green,bold,cyan,bold,cyan 149 | # everything else 150 | /^(\d\d:\d\d:\d\d\.\d+)\s+(\S+)\.(\S+)\s+>\s+(\S+)\.(\S+):(.+)$/ green,cyan,yellow,cyan,yellow,bold 151 | 152 | [ldd/t] 153 | /(\S+) => (\S+) (\S+)/ yellow,bold,magenta 154 | 155 | [nm/t] 156 | /^(\S+) ([[:lower:]]) (\S+)/ yellow,green+bold,magenta 157 | /^(\S+) ([[:upper:]]) (\S+)/ yellow,cyan+bold,magenta 158 | # undefined symbols 159 | /([Uu] \w+?@@\S+)/ red 160 | 161 | [strace/aet] 162 | # calls to open 163 | /^(open)\("([^"]+)", (\S+)/ yellow,green,cyan 164 | # return value 165 | /= (.+)/ bold 166 | 167 | [ltrace/et] 168 | # syscalls 169 | /^([^(]+)\(/ green 170 | 171 | [id] 172 | /\d+/g bold 173 | 174 | # ls needs a pseudo-terminal 175 | [ls/ap] 176 | # setuid 177 | /^-[r-][w-]([Ss])/ bold 178 | # setgid 179 | /^-[rwx-]{5}([Ss])/ bold 180 | # sticky bit 181 | /^d[rwx-]{8}(t)/ bold 182 | /^(?:\S+)\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+(?:\.?\d?[KM]?))\s+(\S+\s+\S+\s+\S+)/ green,cyan,yellow,magenta,blue 183 | 184 | [ps .*a] 185 | /^\s*(\d+)\s+(\S+)\s+([^DZ\s]+)\s+(\S+)/ magenta,yellow,green,cyan 186 | # zombies and uninterruptible sleep 187 | /^\s*(\d+)\s+(\S+)\s+([DZ]+)\s+(\S+)/ magenta,yellow,red,cyan 188 | 189 | [ps -.*(e.*f|f.*e)] 190 | /^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)/ green,magenta,magenta,blue,cyan,yellow,cyan 191 | 192 | # Apt package utilities 193 | [apt-cache search] 194 | /^(.*?) - .*/ green 195 | 196 | [apt-cache show] 197 | /^Package: (.*)/ green 198 | /^Priority: (required)/ red 199 | /^Priority: (standard)/ green 200 | /^Priority: (optional)/ yellow 201 | /^Description: (.*)/ yellow 202 | /^Version: (.*)/ blue 203 | /^Size: (.*)/ magenta 204 | /^Conflicts: (.*)/ red 205 | 206 | [apt-get install] 207 | /^ +(.*)/ green 208 | /^.*\[(.*)\]$/ magenta 209 | 210 | [apt-get remove] 211 | /^ +(.*)/ red 212 | /^.*\[(.*)\]$/ magenta 213 | 214 | # some network utilities 215 | [nmap] 216 | /^.*\((.*)\).*/ green 217 | /^(\d+)/(\w+)\s+(open)\s+(\S+)/ magenta,bold,green,cyan 218 | /^(\d+)/(\w+)\s+(filtered)\s+(\S+)/ magenta,bold,yellow,cyan 219 | /^(\d+)/(\w+)\s+(closed)\s+(\S+)/ magenta,red,cyan 220 | 221 | [netstat] 222 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(ESTABLISHED)/ bold,cyan,green,bold 223 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(TIME_WAIT)/ bold,cyan,green,yellow 224 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(SYN_(?:SENT|RECV))/ bold,cyan,green,magenta 225 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(CLOSE(?:_WAIT|ING))/ bold,cyan,green,red 226 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(LAST_ACK|FIN_WAIT[12])/ bold,cyan,green,red 227 | /^(\w+)\s+\d+\s+\d+\s+(\S+)\s+(.+)\s+(CLOSED)/ bold,cyan,green,blue 228 | 229 | # some utilities 230 | [lsmod] 231 | /^(\w+)\s+(\d+)\s+(\d+)/ green,magenta,bold 232 | 233 | [whereis] 234 | /^(.+): (.+)/ yellow,bold 235 | -------------------------------------------------------------------------------- /acoc.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'acoc/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "acoc" 8 | spec.version = ACOC::VERSION 9 | spec.authors = ["Ian Macdonald", "Alexandre Dantas"] 10 | spec.email = ["eu@alexdantas.net"] 11 | spec.description = < 1.3" 34 | spec.add_development_dependency "rake" 35 | end 36 | -------------------------------------------------------------------------------- /bin/acoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # __ __ ___ __ 3 | # / /\ / /` / / \ / /` 4 | # /_/--\ \_\_, \_\_/ \_\_, 5 | # 6 | # acoc - Arbitrary Command Output Colorer 7 | # $Id: acoc,v 1.67 2005/02/27 01:02:24 ianmacd Exp $ 8 | # 9 | # Version : 0.7.1 10 | # Author : Ian Macdonald 11 | # 12 | # Copyright (C) 2003-2005 Ian Macdonald 13 | # 14 | # This program is free software; you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation; either version 2, or (at your option) 17 | # any later version. 18 | # 19 | # This program is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with this program; if not, write to the Free Software Foundation, 26 | # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | require 'acoc' 29 | 30 | 31 | # Prints a human-readable help text 32 | # (and how to use acoc). 33 | # 34 | def show_usage 35 | $stderr.puts < [args] 39 | acoc [-h | --help | -v | --version] 40 | 41 | acoc: Arbitrary Command Output Colourer 42 | 43 | Copyright 2003-2005 Ian Macdonald 44 | Copyright 2013-2014 Alexandre Dantas 45 | 46 | acoc is free software; see the source for copying conditions. 47 | There is NO warranty; not even for MERCHANTABILITY or FITNESS 48 | FOR A PARTICULAR PURPOSE, to the extent permitted by law. 49 | 50 | Homepage: http://alexdantas.net/projects/acoc/ 51 | EOF 52 | end 53 | 54 | # Script-friendly version checker: 55 | # useful to check compatibility and stuff. 56 | # 57 | def show_version 58 | puts "#{ACOC::VERSION}" 59 | end 60 | 61 | begin 62 | # Showing usage and quitting 63 | if ARGV.empty? || %w[-h --help].include?(ARGV[0]) 64 | show_usage 65 | exit 0 66 | end 67 | 68 | # Showing version and quitting 69 | if %w[-v --version].include?(ARGV[0]) 70 | show_version 71 | exit 0 72 | end 73 | 74 | ACOC.initialise 75 | 76 | if File.lstat($0).symlink? # we're being invoked via a symlink 77 | # Remove symlink's directory from PATH, 78 | # multiple times if necessary 79 | # Otherwise, acoc will reinvoke itself. 80 | ENV['PATH'] = ENV['PATH'].gsub(/#{File.dirname($0)}:?/, '') 81 | 82 | # prefix command line with symlink's name 83 | ARGV.unshift 'acoc' # ARGV can now be either exec'ed or popen'ed 84 | end 85 | 86 | # sort the keys to ensure we find the longest (i.e. most specific) 87 | # match for the command line, e.g. a config section for [ps ax] 88 | # will match before one for [ps a] 89 | prog = nil 90 | ACOC::cmd.keys.sort { |a,b| b.length <=> a.length }.each do |key| 91 | if ARGV.join(' ').match(/^#{key}/) 92 | prog = key 93 | break 94 | end 95 | end 96 | 97 | # if there's no config section for this command and no 'default' 98 | # section, simply execute it normally. 99 | # Do same if $ACOC set to 'none'. 100 | if ENV['ACOC'] == 'none' || ! (prog || ACOC::cmd.include?('default')) 101 | ACOC.execute_program(ARGV) 102 | end 103 | 104 | # use default section if no program-specific section available 105 | prog ||= 'default' 106 | 107 | # if there's a config section for the command, but no rules to 108 | # accompany it, simply execute it normally. 109 | # Likewise if STDOUT is not a tty and the 't' flag is 110 | # not specified. 111 | if ACOC::cmd[prog].specs.empty? || ! ($stdout.tty? || ACOC::cmd[prog].flags.include?('t')) 112 | ACOC.execute_program(ARGV) 113 | end 114 | 115 | # colour program output 116 | status = ACOC.paint_output(prog, *ARGV) 117 | 118 | exit status 119 | 120 | end 121 | 122 | -------------------------------------------------------------------------------- /lib/acoc.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'English' 3 | require 'fileutils' 4 | require 'logger' 5 | require 'shellwords' 6 | 7 | require 'acoc/version' 8 | require 'acoc/program' 9 | require 'acoc/config' 10 | require 'acoc/rule' 11 | require 'acoc/parser' 12 | require 'acoc/painter' 13 | 14 | begin 15 | require 'tpty' 16 | $has_tpty = true 17 | rescue LoadError 18 | require 'pty' 19 | $has_tpty = false 20 | end 21 | 22 | module ACOC 23 | module_function 24 | 25 | # Signal name from number. 26 | def signame(signo) 27 | # Do not use signame: 28 | # - ruby 1.8 does not have it 29 | # - it will not work with an unknown signal number (e.g. 42) 30 | Signal.list.invert[signo] || '???' 31 | end 32 | 33 | # Get pseudo terminal. 34 | def getpty 35 | if $has_tpty 36 | pty = TPty.new() 37 | [pty.master, pty.slave] 38 | else 39 | # Ruby >=1.9 has PTY.open. 40 | unless PTY.respond_to?(:open) 41 | $stderr.puts "acoc: warning: no pseudo terminal support available (for Ruby 1.8, install tpty)" 42 | IO.pipe() 43 | else 44 | PTY.open() 45 | end 46 | end 47 | end 48 | 49 | # All options from the configuration file, in a Hash 50 | def cmd 51 | @@cmd ||= Config.new 52 | end 53 | 54 | # External interface to log things. 55 | # 56 | # @note The _actual_ way to use it is passing a message block 57 | # (like this): 58 | # ACOC.logger.debug do "message" end 59 | # That's because the string concatenations are only 60 | # processed if the debug mode is active. 61 | # 62 | def logger 63 | if not defined? @@logger 64 | @@logger = Logger.new(STDERR) 65 | 66 | # Default level is WARN and above. 67 | # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN 68 | @@logger.level = Logger::WARN 69 | @@logger.level = Logger::DEBUG if $DEBUG 70 | 71 | @@logger.formatter = Kernel.proc do |severity, datetime, progname, msg| 72 | "#{datetime} #{severity}: #{msg}\n" 73 | end 74 | end 75 | @@logger 76 | end 77 | 78 | # Set things up, making sure to parse the configuration 79 | # files. 80 | # 81 | def initialise 82 | 83 | # The default configuration files, in order of reading 84 | # Note that the last file will override the preferences 85 | # of the first. 86 | config_files = [] 87 | config_files << File.expand_path(File.dirname(__FILE__) + '/../acoc.conf') 88 | config_files += %w(/etc/acoc.conf /usr/local/etc/acoc.conf) 89 | config_files << ENV['HOME'] + "/.acoc.conf" 90 | config_files << ENV['ACOCRC'] if ENV['ACOCRC'] 91 | 92 | # No configuration files parsed? 93 | # It returns the number of files read. 94 | if (Parser.parse_config(*config_files) == 0) 95 | $stderr.puts "No readable config files found." 96 | exit 1 97 | end 98 | end 99 | 100 | def trap_signal(signals) 101 | signals.each { |signal| trap(signal) {} } 102 | end 103 | 104 | # Runs a program. 105 | # 106 | # @param args The full command (with arguments) to be executed on the terminal. 107 | # 108 | # @warning It WILL replace ACOC; in other words, ACOC's execution 109 | # will be interrupted and the command will run and 110 | # finish as if it ran itself on the first place. 111 | # 112 | # @note If you want to run this command along with ACOC, you should 113 | # `fork()` or something. 114 | # 115 | def execute_program(args) 116 | 117 | Kernel.exec(*args) 118 | 119 | rescue Errno::ENOENT => reason 120 | 121 | # Can't find the program we're supposed to run 122 | $stderr.puts "acoc: #{args[0]}: command not found" 123 | 124 | exit Errno::ENOENT::Errno 125 | end 126 | 127 | # Process program output, one line at a time. 128 | # 129 | # @param section acoc section on the config file, specifying colors 130 | # @param cmd_line The full command to be executed, with arguments. 131 | # 132 | def paint_output(section, *cmd_line) 133 | 134 | # We're creating a Proc - meaning we are saving 135 | # the following block to be executed only when 136 | # we want it to. 137 | # 138 | # When called, this block will run the program 139 | # and paint it's output. 140 | # 141 | # That `io` is the input-output of the program 142 | # being executed. 143 | # 144 | block = Kernel.proc do |io| 145 | while true 146 | 147 | line = begin 148 | io.gets 149 | rescue Errno::EIO # GNU/Linux raises EIO on EOF when using PTY. 150 | nil 151 | end 152 | break unless line 153 | 154 | colored_line = Painter.color_line(section, line) 155 | 156 | begin 157 | print colored_line 158 | 159 | rescue Errno::EPIPE => reason # catch broken pipes 160 | $stderr.puts reason 161 | exit Errno::EPIPE::Errno 162 | end 163 | end 164 | end 165 | 166 | # Make sure we don't buffer 167 | # output when stdout is connected to a pipe 168 | STDOUT.sync = true 169 | 170 | # Install signal handler 171 | trap_signal(%w(HUP INT QUIT)) 172 | 173 | if @@cmd[section].flags.include?('p') 174 | pipe = getpty() 175 | else 176 | pipe = IO.pipe() 177 | end 178 | 179 | child = fork do 180 | if @@cmd[section].flags.include? 'p' 181 | lines, cols = `stty size 2>/dev/null`.split() 182 | if 0 == $? 183 | ENV['LINES'] = lines 184 | ENV['COLUMNS'] = cols 185 | end 186 | end 187 | STDOUT.reopen(pipe[1]) 188 | STDERR.reopen(pipe[1]) if @@cmd[section].flags.include? 'e' 189 | pipe[0].close() 190 | pipe[1].close() 191 | execute_program(cmd_line) 192 | end 193 | 194 | pipe[1].close() 195 | 196 | # This will run the `Proc` defined at the 197 | # beginning of this function, running 198 | # the program and painting it's output. 199 | block.call(pipe[0]) 200 | 201 | # reap the child and collect its exit status 202 | # WNOHANG is needed to prevent hang when pty is used 203 | begin 204 | Process.waitpid(child) 205 | rescue Errno::ECHILD # Errno::ECHILD can occur in waitpid 206 | end 207 | 208 | # make sure terminal is never left in a coloured state 209 | begin 210 | print reset 211 | rescue Errno::EPIPE # Errno::EPIPE can occur when we're being piped 212 | end 213 | 214 | if $?.signaled? 215 | case signame($?.termsig) 216 | when 'ABRT' ; reason = "abort" 217 | when 'ALRM' ; reason = "alarm" 218 | when 'BUS' ; reason = "bus error" 219 | when 'FPE' ; reason = "floating point exception" 220 | when 'HUP' ; reason = "hangup" 221 | when 'ILL' ; reason = "illegal hardware instruction" 222 | when 'INT' ; reason = "interrupt" 223 | when 'KILL' ; reason = "killed" 224 | when 'QUIT' ; reason = "quit" 225 | when 'SEGV' ; reason = "segmentation fault" 226 | when 'TERM' ; reason = "terminated" 227 | when 'TRAP' ; reason = "trace trap" 228 | else ; reason = "signal #{$?.termsig} (#{signame($?.termsig)})" 229 | end 230 | reason << ' (cored dumped)' if $?.coredump? 231 | STDERR.puts "acoc: #{reason}: #{Shellwords.join(cmd_line)}" 232 | status = 128 + $?.termsig 233 | else 234 | status = $? >> 8 235 | end 236 | 237 | return status 238 | 239 | end 240 | 241 | end 242 | 243 | -------------------------------------------------------------------------------- /lib/acoc/config.rb: -------------------------------------------------------------------------------- 1 | 2 | module ACOC 3 | # Wrapper for all possible color settings. 4 | class Config < Hash; end 5 | end 6 | 7 | -------------------------------------------------------------------------------- /lib/acoc/painter.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'term/ansicolor' 3 | include Term::ANSIColor 4 | 5 | module ACOC 6 | 7 | # Responsible for adding colors to the output 8 | module Painter 9 | module_function 10 | 11 | # Tells if #color is supported. 12 | # 13 | # @param color Color String. 14 | # 15 | def valid_color? color 16 | Term::ANSIColor::attributes.collect { |a| a.to_s }.include? color 17 | end 18 | 19 | # match and color an individual line 20 | # 21 | def color_line(prog, line) 22 | matched = false 23 | 24 | # act on only the first match unless the /a flag was given 25 | return if matched && ! ACOC.cmd[prog].flags.include?('a') 26 | 27 | # get a pattern and attribute set pairing for this command 28 | ACOC.cmd[prog].specs.each do |spec| 29 | 30 | if r = spec.regex.match(line) # line matches this regex 31 | matched = true 32 | if spec.flags.include? 'g' # global flag 33 | matches = 0 34 | 35 | # perform global substitution 36 | line.gsub!(spec.regex) do |match| 37 | index = [matches, spec.colors.size - 1].min 38 | spec.colors[index].split(/[+\s]+/).each do |color| 39 | match = match.send(color) 40 | end 41 | matches += 1 42 | match 43 | end 44 | 45 | else # color each match separately 46 | # work from right to left, bracketing each match 47 | (r.size - 1).downto(1) do |i| 48 | start = r.begin(i) 49 | length = r.end(i) - start 50 | index = [i - 1, spec.colors.size - 1].min 51 | ansi_offset = 0 52 | spec.colors[index].split(/[+\s]+/).each do |color| 53 | line[start + ansi_offset, length] = 54 | line[start + ansi_offset, length].send(color) 55 | # when applying multiple colors, we apply them one at a 56 | # time, so we need to compensate for the start of the string 57 | # moving to the right as the color codes are applied 58 | ansi_offset += send(color).length 59 | end 60 | end 61 | end 62 | end 63 | end 64 | 65 | line 66 | end 67 | 68 | end 69 | end 70 | 71 | -------------------------------------------------------------------------------- /lib/acoc/parser.rb: -------------------------------------------------------------------------------- 1 | 2 | module ACOC 3 | 4 | # Parses configuration files and builds configurations 5 | # on the main ACOC module. 6 | # 7 | module Parser 8 | module_function 9 | 10 | # Parses data inside configuration files. 11 | # 12 | # @param files An array of filenames to parse. 13 | # @return The amount of files parsed 14 | # 15 | def parse_config(*files) 16 | parsed_count = 0 17 | 18 | files.each do |file| 19 | ACOC.logger.debug do "Attempting to read config file: '#{file}'" end 20 | 21 | next unless file && FileTest::file?(file) && FileTest::readable?(file) 22 | 23 | begin 24 | File.open(file) do |f| 25 | while line = f.gets do 26 | parse_line line 27 | end 28 | end 29 | 30 | rescue Errno::ENOENT 31 | $stderr.puts "acoc: Failed to open config file '#{$ERROR_INFO}'" 32 | exit 1 33 | 34 | rescue 35 | $stderr.puts "acoc: Error on config file '#{file}' at line #{$NR}: #{$ERROR_INFO}" 36 | exit 2 37 | end 38 | parsed_count += 1 39 | 40 | ACOC.logger.debug do "Action data: #{ACOC.cmd.inspect}" end 41 | end 42 | 43 | parsed_count 44 | end 45 | 46 | def parse_line(line) 47 | 48 | # Skipping blank lines and comments 49 | return if line =~ /^(#|$)/ 50 | 51 | # Are we're at the start of program section? 52 | # 53 | # [program] 54 | # 55 | section = /^[@\[]([^\]]+)[@\]]$/.match(line) 56 | if section 57 | 58 | # Get program invocations and flags 59 | # 60 | # [invocation1/flags1,invocation2/flags2,...] 61 | # 62 | @@progs = section[1].split(/\s*,\s*/) 63 | 64 | @@progs.each do |prog| 65 | 66 | invocation, flags = prog.split(%r(/)) 67 | 68 | # The 'r' flag removes any previous matching entries 69 | # for the current command. 70 | if ! flags.nil? && flags.include?('r') 71 | 72 | program = invocation.sub(/\s.*$/, '') 73 | 74 | ACOC.cmd.each_key do |key| 75 | ACOC.cmd.delete(key) if key =~ /^#{program}\b/ 76 | end 77 | 78 | flags.delete 'r' 79 | end 80 | 81 | # Create entry for this program 82 | if ACOC.cmd.has_key?(invocation) 83 | ACOC.cmd[invocation].flags += flags unless flags.nil? 84 | else 85 | ACOC.cmd[invocation] = Program.new(flags) 86 | end 87 | prog.sub!(%r(/\w+), '') 88 | end 89 | return 90 | end 91 | 92 | # If not then it's a rule line 93 | # 94 | # /regexp/ color1,color2,... 95 | # 96 | begin 97 | regex, flags, colors = /^(.)([^\1]*)\1(g?)\s+(.*)/.match(line)[2..4] 98 | rescue 99 | $stderr.puts "acoc: Ignoring bad config line #{$NR}: '#{line}'" 100 | end 101 | 102 | colors = colors.split(/\s*,\s*/) 103 | colors.join(' ').split(/[+\s]+/).each do |color| 104 | 105 | # Let's quit if the user provided an invalid color 106 | if not Painter.valid_color? color 107 | raise "'#{color}' is not a supported color" 108 | end 109 | 110 | @@progs.each do |prog| 111 | ACOC.cmd[prog].specs << Rule.new(Regexp.new(regex), flags, colors) 112 | end 113 | end 114 | end 115 | 116 | end 117 | end 118 | 119 | -------------------------------------------------------------------------------- /lib/acoc/program.rb: -------------------------------------------------------------------------------- 1 | 2 | module ACOC 3 | 4 | # Single program, that can have multiple color Rules. 5 | class Program 6 | attr_accessor :flags, :specs 7 | 8 | def initialize(flags) 9 | @flags = flags || "" 10 | @specs = Array.new 11 | end 12 | end 13 | end 14 | 15 | -------------------------------------------------------------------------------- /lib/acoc/rule.rb: -------------------------------------------------------------------------------- 1 | 2 | module ACOC 3 | 4 | # Single color rule for a program. 5 | class Rule 6 | attr_reader :regex, :flags, :colors 7 | 8 | def initialize(regex, flags, colors) 9 | @regex = regex 10 | @flags = flags 11 | @colors = colors 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /lib/acoc/version.rb: -------------------------------------------------------------------------------- 1 | 2 | module ACOC 3 | VERSION = '0.7.1' 4 | end 5 | 6 | --------------------------------------------------------------------------------