clog-1.1.0/0000755000175000017500000000000012215630202011710 5ustar mogaalmogaalclog-1.1.0/AUTHORS0000644000175000017500000000060512215630160012764 0ustar mogaalmogaalThe development of clog was made possible by the significant contributions of the following people: Paul Beckingham (Principal Author) Federico Hernandez (Package Maintainer & Contributing Author) The following submitted code, packages or analysis, and deserve special thanks: ... Thanks to the following, who submitted detailed bug reports and excellent suggestions: ... clog-1.1.0/LICENSE0000644000175000017500000000217312215630160012723 0ustar mogaalmogaalclog - colorized log tail Copyright 2010-2013, Göteborg Bit Factory. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http://www.opensource.org/licenses/mit-license.php clog-1.1.0/COPYING0000644000175000017500000000217312215630160012751 0ustar mogaalmogaalclog - colorized log tail Copyright 2010-2013, Göteborg Bit Factory. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http://www.opensource.org/licenses/mit-license.php clog-1.1.0/doc/0000755000175000017500000000000012215630160012460 5ustar mogaalmogaalclog-1.1.0/doc/demo/0000755000175000017500000000000012215630160013404 5ustar mogaalmogaalclog-1.1.0/doc/demo/intro.txt0000644000175000017500000000046212215630160015302 0ustar mogaalmogaalIntroducing clog. Clog is a colorized log viewer. It can spot text on a line in a log file and apply color to it, a little like this: $ tail -f access.log | sed -e 's/ error / error<\/red> /g' This would spot the text ' error ' in access.log and mark up the matched text. This is what clog does. clog-1.1.0/doc/demo/hamlet0000644000175000017500000000161512215630160014604 0ustar mogaalmogaalFRANCISCO at his post. Enter to him BERNARDO BERNARDO Whos there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king. FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO Tis now struck twelve, get thee to bed, Francisco. FRANCISCO For this relief much thanks: tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho. Whos there? HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. clog-1.1.0/doc/demo/1.txt0000644000175000017500000000157112215630160014311 0ustar mogaalmogaalClog has some basic features, for example, it can prepend timestamps to text: $ head -5 hamlet | clog --date 2013-04-11 FRANCISCO at his post. Enter to him BERNARDO 2013-04-11 BERNARDO Whos there? 2013-04-11 FRANCISCO Nay, answer me: stand, and unfold yourself. 2013-04-11 BERNARDO Long live the king. 2013-04-11 FRANCISCO Bernardo? $ head -5 hamlet | clog --time 21:20:17 FRANCISCO at his post. Enter to him BERNARDO 21:20:17 BERNARDO Whos there? 21:20:17 FRANCISCO Nay, answer me: stand, and unfold yourself. 21:20:17 BERNARDO Long live the king. 21:20:17 FRANCISCO Bernardo? $ head -5 hamlet | clog --date --time 2013-04-11 21:20:22 FRANCISCO at his post. Enter to him BERNARDO 2013-04-11 21:20:22 BERNARDO Whos there? 2013-04-11 21:20:22 FRANCISCO Nay, answer me: stand, and unfold yourself. 2013-04-11 21:20:22 BERNARDO Long live the king. 2013-04-11 21:20:22 FRANCISCO Bernardo? clog-1.1.0/doc/demo/0.txt0000644000175000017500000000223512215630160014306 0ustar mogaalmogaalWe start with a fragment of text, from the opening scene of Hamlet. This is just an example, but will illustrate how clog can be applied to log files. $ cat hamlet FRANCISCO at his post. Enter to him BERNARDO BERNARDO Whos there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king. FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO Tis now struck twelve, get thee to bed, Francisco. FRANCISCO For this relief much thanks: tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho. Whos there? HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. By default, clog is a pass-through filter that does nothing: $ clog < hamlet > foo $ diff hamlet foo $ clog-1.1.0/doc/demo/5.txt0000644000175000017500000000250612215630160014314 0ustar mogaalmogaalSo far, the rules have all involved text string matches. Clog also supports regular expressions, with a slightly different syntax: $ rm ~/.clogrc $ echo 'default rule /[Ww]ho/ --> red match' >> ~/.clogrc $ echo 'default rule /n...t/ --> blue match' >> ~/.clogrc This rules color 'Who' or 'who' red, and the word 'night' (or anything matching 'n...t') blue. $ clog < hamlet FRANCISCO at his post. Enter to him BERNARDO BERNARDO Whos there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king. FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO Tis now struck twelve, get thee to bed, Francisco. FRANCISCO For this relief much thanks: tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho. Whos there? HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. clog-1.1.0/doc/demo/2.txt0000644000175000017500000000227512215630160014314 0ustar mogaalmogaalNow we add a rule, to colorize some text: $ echo 'default rule "HORATIO" --> red match' > ~/.clogrc This rule says that if the text "HORATIO" is found, then the matching text is colored red. The 'default' keyword is a rule section, which allows multiple rule sets. $ clog < hamlet FRANCISCO at his post. Enter to him BERNARDO BERNARDO Whos there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king. FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO Tis now struck twelve, get thee to bed, Francisco. FRANCISCO For this relief much thanks: tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho. Whos there? HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. clog-1.1.0/doc/demo/3.txt0000644000175000017500000000223312215630160014307 0ustar mogaalmogaalAnother rule: $ echo 'default rule "MARCELLUS" --> black on blue line' >> ~/.clogrc This rule says that if the text "MARCELLUS" is found, then the matching line is colored with a blue background. $ clog < hamlet FRANCISCO at his post. Enter to him BERNARDO BERNARDO Whos there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king. FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO Tis now struck twelve, get thee to bed, Francisco. FRANCISCO For this relief much thanks: tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho. Whos there? HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. clog-1.1.0/doc/demo/6.txt0000644000175000017500000000217612215630160014320 0ustar mogaalmogaalThe section name can be used to maintain several rule sets. Here is a new example using two rule sets: $ echo '# Shakespeare characters' >> ~/.clogrc $ echo 'Shakespeare rule "FRANCISCO" --> red match' >> ~/.clogrc $ echo 'Shakespeare rule "BERNARDO" --> blue match' >> ~/.clogrc $ echo 'Shakespeare rule "MARCELLUS" --> green match' >> ~/.clogrc $ echo 'Shakespeare rule "HORATIO" --> white match' >> ~/.clogrc $ $ echo '# Syslog severities' >> ~/.clogrc $ echo 'syslog rule /warn|debug/ --> yellow line' >> ~/.clogrc $ echo 'syslog rule /error|severe/ --> red line' >> ~/.clogrc $ echo 'syslog rule "critical" --> bold red line' >> ~/.clogrc $ echo 'syslog rule "ignore" --> suppress' >> ~/.clogrc Now we can invoke the default set from before, by not specifying a rule set: $ clog < hamlet ... Or we can select the Shakespeare set, by providing the rule set name as an argument: $ clog Shakespeare < hamlet ... We can specify multiple rule set names if we wish, but these do not include the default set: $ clog Shakespeare syslog < hamlet ... clog-1.1.0/doc/demo/4.txt0000644000175000017500000000124712215630160014314 0ustar mogaalmogaalThis rule will suppress the line, instead of coloring it: $ echo 'default rule "FRANCISCO" --> suppress' >> ~/.clogrc $ $ clog < hamlet BERNARDO Whos there? BERNARDO Long live the king. BERNARDO He. BERNARDO Tis now struck twelve, get thee to bed, Francisco. BERNARDO Have you had quiet guard? BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. MARCELLUS O, farewell, honest soldier: Who hath relieved you? MARCELLUS Holla. Bernardo. BERNARDO Say, What, is Horatio there? HORATIO A piece of him. clog-1.1.0/doc/CMakeLists.txt0000644000175000017500000000057012215630160015222 0ustar mogaalmogaalcmake_minimum_required (VERSION 2.8) message ("-- Configuring man pages") set (man_FILES clog.1) foreach (man_FILE ${man_FILES}) configure_file ( man/${man_FILE}.in man/${man_FILE}) endforeach (man_FILE) install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/man/ DESTINATION share/man/man1 FILES_MATCHING PATTERN "*.1") clog-1.1.0/doc/man/0000755000175000017500000000000012215630160013233 5ustar mogaalmogaalclog-1.1.0/doc/man/.gitignore0000644000175000017500000000000712215630160015220 0ustar mogaalmogaalclog.1 clog-1.1.0/doc/man/clog.1.in0000644000175000017500000000654112215630160014654 0ustar mogaalmogaal.TH clog 1 2013-09-10 "${PACKAGE_STRING}" "User Manuals" .SH NAME clog \- colorized log tail .SH SYNOPSIS .B clog [-h|--help] [-v|--version] [-d|--date] [-t|--time] [-f|--file ] [
... ] .SH DESCRIPTION Clog is a filter command, which means it copies its input to its output. But if lines in the input match certain patterns, actions are taken. These are called rules. The rules are defined in ~/.clogrc as regular expressions, and the actions are specified, to colorize either the line or matching pattern, or perhaps to suppress the line. If --date is specified, the current date, in the form YYYY-MM-DD is prepended to all lines. If --time is specified, the current time, in the form HH:MM:SS is prepended to all lines. If --file is specified, an alternate configuration rc file may be specified. Default is to ~/.clogrc One or more section arguments may be specified. If none are provided, 'default' is assumed. A section corresponds to a rule set defined in ~/.clogrc. and allows the use of one .clogrc file to serve multiple different uses of clog. If more than one section is specified, the rules sets are combined, in the sequence found. .SH CONFIGURATION FILE AND OVERRIDE OPTIONS Clog reads its configuration from a file in the user's home directory: ~/.clogrc. The format of the rules is: .RS
rule // --> .br
rule "" --> .RE If the pattern is surrounded by / characters, it is interpreted as a regular expression. If the pattern is surrounded by " characters, it is interpreted as a string fragment. The section is simply a way to allow multiple rules sets, so that one .clogrc file can serve multiple uses. The pattern may be any supported Standard C Library regular expression. Action must be one of 'line', 'match', 'suppress' or 'blank'. Note that there is a default section, called 'default'. Putting rules in the default section means that no section need be specified on the command line. Any color can be used, in both the 16- and 256-color space. Some examples are: .RS bold .br underline .br bold blue .br underline on green .br black on white .br bold red on bright white .br rgb200 on grey4 .RE Instead of coloring the whole line, specifying 'match' instead will only color the parts of the line that match. .SH EXAMPLE Rulesets Here is an example ~/.clogrc file. .RS # Standard syslog entries. .br default rule /warn|debug/ --> yellow line .br default rule /error|severe/ --> red line .br default rule /critical/ --> bold red line .br default rule /critical/ --> blank .br default rule /ignore/ --> suppress .br .br # Apache access.log status codes .br apache rule / 2[0-9][0-9] / --> green match .br apache rule / 3[0-9][0-9] / --> yellow match .br apache rule / 4[0-9][0-9] / --> red match .br apache rule / 5[0-9][0-9] / --> bold red match .RE .SH "CREDITS & COPYRIGHTS" Copyright (C) 2006 \- 2013 P. Beckingham, F. Hernandez. .br Copyright (C) 2006 \- 2013 Goteborg Bit Factory. Clog is distributed under the MIT license. See http://www.opensource.org/licenses/mit-license.php for more information. .SH SEE ALSO For more information, see: .TP The official site at .TP You can contact the project by writing an email to .SH REPORTING BUGS .TP Bugs in clog may be reported to clog-1.1.0/README0000644000175000017500000000346012215630160012576 0ustar mogaalmogaalWhat is clog? ------------- Ever done something like this: $ tail -f /var/log/something.log and left that running in a terminal, while you debug or run some program? Were you able to spot important information as it scrolled by? It's not easy. Clog is a filter, that you run like this: $ tail -f /var/log/something.log | clog something The 'something' argument to clog is a section, which refers to a section in ~/.clogrc with a distinct set of rules. Those rules list patterns to look for, and actions to take when the pattern is matched by a line. A typical example might be that you want to highlight any line that contains the pattern 'severe'. This entry in ~/clogrc achieves this: something rule /severe/ --> bold line This rule is in the 'something' section, the pattern is 'severe', and the action taken is to embolden the whole line. Pattern 'severe' should probably be more restrictive, because it will also match words like 'persevered', but that is optional. Any color can be used, in both the 16- and 256-color space. Some examples are: bold underline bold blue underline on green black on white bold red on bright white rgb200 on grey4 Instead of coloring the whole line, specifying 'match' instead will only color the parts of the line that match. The format of the rules is:
rule // --> The section is simply a way to allow multiple rules sets, so that one .clogrc file can serve multiple uses. The pattern is any supported Standard C Library regular expression. Action must be one of 'line', 'match', 'suppress' or 'blank'. Note that there is a default section, called 'default'. Putting rules in the default section means that no section need be specified on the command line. Multiple sections may be specified, and the rules are combined. --- clog-1.1.0/test/0000755000175000017500000000000012215630217012675 5ustar mogaalmogaalclog-1.1.0/test/regex.match.t0000755000175000017500000000356312215630160015276 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "default rule /foo/ --> red match\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern matches work. my $output = qx{printf "a foo\na bar\n" | ../src/clog -f rc}; like ($output, qr/^a \033\[31mfoo\033\[0m$/ms, 'foo is red'); like ($output, qr/^a bar$/ms, 'bar is unchanged'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/test.cpp0000644000175000017500000002435112215630160014362 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// UnitTest::UnitTest () : mPlanned (0) , mCounter (0) , mPassed (0) , mFailed (0) , mSkipped (0) { } /////////////////////////////////////////////////////////////////////////////// UnitTest::UnitTest (int planned) : mPlanned (planned) , mCounter (0) , mPassed (0) , mFailed (0) , mSkipped (0) { std::cout << "1.." << mPlanned << "\n"; } /////////////////////////////////////////////////////////////////////////////// UnitTest::~UnitTest () { float percentPassed = 0.0; if (mPlanned > 0) percentPassed = (100.0 * mPassed) / std::max (mPlanned, mPassed + mFailed + mSkipped); if (mCounter < mPlanned) { std::cout << "# Only " << mCounter << " tests, out of a planned " << mPlanned << " were run.\n"; mSkipped += mPlanned - mCounter; } else if (mCounter > mPlanned) std::cout << "# " << mCounter << " tests were run, but only " << mPlanned << " were planned.\n"; std::cout << "# " << mPassed << " passed, " << mFailed << " failed, " << mSkipped << " skipped. " << std::setprecision (3) << percentPassed << "% passed.\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::plan (int planned) { mPlanned = planned; mCounter = 0; mPassed = 0; mFailed = 0; mSkipped = 0; std::cout << "1.." << mPlanned << "\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::planMore (int extra) { mPlanned += extra; std::cout << "1.." << mPlanned << "\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::ok (bool expression, const std::string& name) { ++mCounter; if (expression) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::notok (bool expression, const std::string& name) { ++mCounter; if (!expression) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (bool actual, bool expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (size_t actual, size_t expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (int actual, int expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (double actual, double expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (double actual, double expected, double tolerance, const std::string& name) { ++mCounter; if (fabs (actual - expected) <= tolerance) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is (unsigned char actual, unsigned char expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: " << expected << "\n# got: " << actual << "\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is ( const std::string& actual, const std::string& expected, const std::string& name) { ++mCounter; if (actual == expected) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: '" << expected << "'" << "\n# got: '" << actual << "'\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::is ( const char* actual, const char* expected, const std::string& name) { ++mCounter; if (! strcmp (actual, expected)) { ++mPassed; std::cout << "ok " << mCounter << " - " << name << "\n"; } else { ++mFailed; std::cout << "not ok " << mCounter << " - " << name << "\n# expected: '" << expected << "'" << "\n# got: '" << actual << "'\n"; } } /////////////////////////////////////////////////////////////////////////////// void UnitTest::diag (const std::string& text) { std::string::size_type start = text.find_first_not_of (" \t\n\r\f"); std::string::size_type end = text.find_last_not_of (" \t\n\r\f"); std::cout << "# " << text.substr (start, end - start + 1) << "\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::pass (const std::string& text) { ++mCounter; ++mPassed; std::cout << "ok " << mCounter << " " << text << "\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::fail (const std::string& text) { ++mCounter; ++mFailed; std::cout << "not ok " << mCounter << " " << text << "\n"; } /////////////////////////////////////////////////////////////////////////////// void UnitTest::skip (const std::string& text) { ++mCounter; ++mSkipped; std::cout << "skip " << mCounter << " " << text << "\n"; } /////////////////////////////////////////////////////////////////////////////// clog-1.1.0/test/decorate.both.t0000755000175000017500000000361312215630160015606 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "# empty\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "foo\nbar\n" | ../src/clog -f rc --date --time}; like ($output, qr/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} foo$/ms, 'foo decorated'); like ($output, qr/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} bar$/ms, 'bar decorated'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/decorate.time.t0000755000175000017500000000354012215630160015607 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "# empty\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "foo\nbar\n" | ../src/clog -f rc --time}; like ($output, qr/^\d{2}:\d{2}:\d{2} foo$/ms, 'foo decorated'); like ($output, qr/^\d{2}:\d{2}:\d{2} bar$/ms, 'bar decorated'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/regex.line.t0000755000175000017500000000356712215630160015135 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "default rule /foo/ --> red line\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "a foo\na bar\n" | ../src/clog -f rc}; like ($output, qr/^\033\[31ma foo\033\[0m$/ms, 'foo is red'); like ($output, qr/^a bar$/ms, 'bar is unchanged'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/run_all0000755000175000017500000000211712215630160014255 0ustar mogaalmogaal#! /bin/sh if [ x"$1" = x"--verbose" ]; then for i in ./*.t do echo '#' $i $i > test.log 2>&1 while read LINE do echo $LINE done < test.log rm test.log done else date > all.log # Perl is used here to get the time in seconds # because 'date +%s' isn't supported on Solaris. STARTEPOCH=`perl -e 'print time'` VRAMSTEG=`which vramsteg` BAR=0 if [ -x "$VRAMSTEG" ]; then BAR=1 COUNT=0 TOTAL=`ls ./*.t | wc -l` START=`$VRAMSTEG --now` fi for i in ./*.t do echo '#' $i >>all.log if [ $BAR -eq 1 ]; then $VRAMSTEG --label 'All tests' --min 0 --max $TOTAL --current $COUNT --percentage --start $START --estimate COUNT=`expr $COUNT + 1` fi $i >> all.log 2>&1 done if [ $BAR -eq 1 ]; then $VRAMSTEG --remove fi date >> all.log ENDEPOCH=`perl -e 'print time'` RUNTIME=`expr $ENDEPOCH - $STARTEPOCH` printf "Pass: %5d\n" `grep -c '^ok' all.log` printf "Fail: %5d\n" `grep -c '^not' all.log` printf "Skipped: %5d\n" `grep -c '^skip' all.log` printf "Runtime: %5d seconds\n" $RUNTIME fi clog-1.1.0/test/version.t0000755000175000017500000000314412215630160014551 0ustar mogaalmogaal#! /usr/bin/env perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 1; my $year = (localtime (time))[5] + 1900; my $output = qx{../src/clog --version 2>&1}; like ($output, qr/Copyright \(C\) \d{4}-$year/, 'Copyright is current'); exit 0; clog-1.1.0/test/color.t.cpp0000644000175000017500000002253412215630160014764 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { UnitTest t (1036); // Names matched to values. t.is ((int) Color (""), (int) Color (Color::nocolor), "'' == Color::nocolor"); t.is ((int) Color ("black"), (int) Color (Color::black), "'black' == Color::black"); t.is ((int) Color ("red"), (int) Color (Color::red), "'red' == Color::red"); t.is ((int) Color ("green"), (int) Color (Color::green), "'green' == Color::green"); t.is ((int) Color ("yellow"), (int) Color (Color::yellow), "'yellow' == Color::yellow"); t.is ((int) Color ("blue"), (int) Color (Color::blue), "'blue' == Color::blue"); t.is ((int) Color ("magenta"), (int) Color (Color::magenta), "'magenta' == Color::magenta"); t.is ((int) Color ("cyan"), (int) Color (Color::cyan), "'cyan' == Color::cyan"); t.is ((int) Color ("white"), (int) Color (Color::white), "'white' == Color::white"); // Auto upgrades. Color c ("red on color0"); t.is ((std::string) c, "color1 on color0", "upgrade red on color0 -> color1 on color0"); c = Color ("color1 on black"); t.is ((std::string) c, "color1 on color0", "upgrade color1 on black -> color1 on color0"); c = Color ("bold red on color0"); t.is ((std::string) c, "color9 on color0", "upgrade bold red on color0 -> color9 on color0"); c = Color ("color1 on bright black"); t.is ((std::string) c, "color1 on color8", "upgrade color1 on bright black -> color1 on color8"); // Simple blending. c = Color ("red"); c.blend (Color ("on white")); t.is ((std::string) c, "red on white", "red + on white -> red on white"); c = Color ("bold underline red"); c.blend (Color ("on bright white")); t.is ((std::string) c, "bold underline red on bright white", "bold underline red + on bright white -> bold underline red on bright white"); // Blending with conflicts. c = Color ("red on white"); c.blend (Color ("on blue")); t.is ((std::string) c, "red on blue", "red on white + on blue -> red on blue"); c = Color ("red on white"); c.blend (Color ("blue on magenta")); t.is ((std::string) c, "blue on magenta", "red on white + blue on magenta -> blue on magenta"); // Blending with upgrades. c = Color ("color1 on color0"); c.blend (Color ("blue")); t.is ((std::string) c, "color4 on color0", "color1 on color0 + blue -> color4 on color0"); // Now the dumb show of every color and its code. t.is (Color::colorize ("foo", "red"), std::string ("\033[31mfoo\033[0m"), "red -> ^[[31m"); t.is (Color::colorize ("foo", "bold red"), std::string ("\033[1;31mfoo\033[0m"), "bold red -> ^[[1;31m"); t.is (Color::colorize ("foo", "underline red"), std::string ("\033[4;31mfoo\033[0m"), "underline red -> ^[[4;31m"); t.is (Color::colorize ("foo", "underline bold red"), std::string ("\033[1;4;31mfoo\033[0m"), "underline bold red -> ^[[1;4;31m"); // 16-color foregrounds. t.is (Color::colorize ("foo", ""), std::string ("foo"), "'' -> ''"); t.is (Color::colorize ("foo", "black"), std::string ("\033[30mfoo\033[0m"), "black -> ^[[30m"); t.is (Color::colorize ("foo", "red"), std::string ("\033[31mfoo\033[0m"), "red -> ^[[31m"); t.is (Color::colorize ("foo", "green"), std::string ("\033[32mfoo\033[0m"), "green -> ^[[32m"); t.is (Color::colorize ("foo", "yellow"), std::string ("\033[33mfoo\033[0m"), "yellow -> ^[[33m"); t.is (Color::colorize ("foo", "blue"), std::string ("\033[34mfoo\033[0m"), "blue -> ^[[34m"); t.is (Color::colorize ("foo", "magenta"), std::string ("\033[35mfoo\033[0m"), "magenta -> ^[[35m"); t.is (Color::colorize ("foo", "cyan"), std::string ("\033[36mfoo\033[0m"), "cyan -> ^[[36m"); t.is (Color::colorize ("foo", "white"), std::string ("\033[37mfoo\033[0m"), "white -> ^[[37m"); // 16-color backgrounds. t.is (Color::colorize ("foo", "on bright black"), std::string ("\033[100mfoo\033[0m"), "on bright black -> ^[[100m"); t.is (Color::colorize ("foo", "on black"), std::string ("\033[40mfoo\033[0m"), "on black -> ^[[40m"); t.is (Color::colorize ("foo", "on red"), std::string ("\033[41mfoo\033[0m"), "on red -> ^[[41m"); t.is (Color::colorize ("foo", "on green"), std::string ("\033[42mfoo\033[0m"), "on green -> ^[[42m"); t.is (Color::colorize ("foo", "on yellow"), std::string ("\033[43mfoo\033[0m"), "on yellow -> ^[[43m"); t.is (Color::colorize ("foo", "on blue"), std::string ("\033[44mfoo\033[0m"), "on blue -> ^[[44m"); t.is (Color::colorize ("foo", "on magenta"), std::string ("\033[45mfoo\033[0m"), "on magenta -> ^[[45m"); t.is (Color::colorize ("foo", "on cyan"), std::string ("\033[46mfoo\033[0m"), "on cyan -> ^[[46m"); t.is (Color::colorize ("foo", "on white"), std::string ("\033[47mfoo\033[0m"), "on white -> ^[[47m"); // 256-color, basic colors. char color [24]; char codes [64]; char description [64]; for (int i = 0; i < 256; ++i) { sprintf (color, "color%d", i); sprintf (codes, "\033[38;5;%dmfoo\033[0m", i); sprintf (description, "color%d -> ^[[38;5;%dm", i, i); t.is (Color::colorize ("foo", color), std::string (codes), description); } for (int i = 0; i < 256; ++i) { sprintf (color, "on color%d", i); sprintf (codes, "\033[48;5;%dmfoo\033[0m", i); sprintf (description, "on color%d -> ^[[48;5;%dm", i, i); t.is (Color::colorize ("foo", color), std::string (codes), description); } // RGB Color Cube. for (int r = 0; r < 6; ++r) for (int g = 0; g < 6; ++g) for (int b = 0; b < 6; ++b) { int code = 16 + (r*36 + g*6 + b); sprintf (color, "rgb%d%d%d", r, g, b); sprintf (codes, "\033[38;5;%dmfoo\033[0m", code); sprintf (description, "rgb%d%d%d -> ^[[38;5;%dm", r, g, b, code); t.is (Color::colorize ("foo", color), std::string (codes), description); } for (int r = 0; r < 6; ++r) for (int g = 0; g < 6; ++g) for (int b = 0; b < 6; ++b) { int code = 16 + (r*36 + g*6 + b); sprintf (color, "on rgb%d%d%d", r, g, b); sprintf (codes, "\033[48;5;%dmfoo\033[0m", code); sprintf (description, "on rgb%d%d%d -> ^[[48;5;%dm", r, g, b, code); t.is (Color::colorize ("foo", color), std::string (codes), description); } // 256-color, grays. // grey == gray. t.is (Color::colorize ("foo", "grey0"), std::string ("\033[38;5;232mfoo\033[0m"), "grey0 -> ^[[38;5;232m"); for (int i = 0; i < 24; ++i) { sprintf (color, "gray%d", i); sprintf (codes, "\033[38;5;%dmfoo\033[0m", i + 232); sprintf (description, "gray%d -> ^[[38;5;%dm", i + 232, i + 232); t.is (Color::colorize ("foo", color), std::string (codes), description); } for (int i = 0; i < 24; ++i) { sprintf (color, "on gray%d", i); sprintf (codes, "\033[48;5;%dmfoo\033[0m", i + 232); sprintf (description, "on gray%d -> ^[[48;5;%dm", i + 232, i + 232); t.is (Color::colorize ("foo", color), std::string (codes), description); } // std::string Color::strip (const std::string&); t.is (Color::strip (""), "", "Color::strip '' -> ''"); t.is (Color::strip ("foo"), "foo", "Color::strip 'foo' -> 'foo'"); t.is (Color::strip ("f\033[1mo\033[0mo"), "foo", "Color::strip 'foo' -> 'foo'"); return 0; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/test/problems0000755000175000017500000000056712215630160014453 0ustar mogaalmogaal#!/usr/bin/env perl use strict; use warnings; if (open my $fh, '<', 'all.log') { my $test_file; my %errors; while (my $line = <$fh>) { $test_file = $1 if $line =~ /^# (\S+\.t)$/; $errors{$test_file}++ if $line =~ /^not /; } close $fh; printf "%-24s %4d\n", $_, $errors{$_} for sort {$errors{$b} <=> $errors{$a}} keys %errors; } exit 0; clog-1.1.0/test/decorate.date.t0000755000175000017500000000354012215630160015566 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "# empty\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "foo\nbar\n" | ../src/clog -f rc --date}; like ($output, qr/^\d{4}-\d{2}-\d{2} foo$/ms, 'foo decorated'); like ($output, qr/^\d{4}-\d{2}-\d{2} bar$/ms, 'bar decorated'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/CMakeLists.txt0000644000175000017500000000153712215630160015440 0ustar mogaalmogaalcmake_minimum_required (VERSION 2.8) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/test ${CLOG_INCLUDE_DIRS}) set (test_SRCS color.t nibbler.t) add_custom_target (test ./run_all --verbose DEPENDS ${test_SRCS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test) add_custom_target (build_tests DEPENDS ${test_SRCS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test) foreach (src_FILE ${test_SRCS}) add_executable (${src_FILE} "${src_FILE}.cpp" ../src/Nibbler.cpp ../src/RX.cpp ../src/Color.cpp ../src/text.cpp test.cpp) endforeach (src_FILE) clog-1.1.0/test/suppress.t0000755000175000017500000000354612215630160014756 0ustar mogaalmogaal#! /usr/bin/env perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "default rule \"foo\" --> suppress\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "a foo\na bar\n" | ../src/clog -f rc}; unlike ($output, qr/^a foo$/ms, 'foo is suppressed'); like ($output, qr/^a bar$/ms, 'bar is unchanged'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/test.h0000644000175000017500000000457612215630160014036 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_UNITTEST #define INCLUDED_UNITTEST #include class UnitTest { public: UnitTest (); UnitTest (int); ~UnitTest (); void plan (int); void planMore (int); void ok (bool, const std::string&); void notok (bool, const std::string&); void is (bool, bool, const std::string&); void is (size_t, size_t, const std::string&); void is (int, int, const std::string&); void is (double, double, const std::string&); void is (double, double, double, const std::string&); void is (unsigned char, unsigned char, const std::string&); void is (const std::string&, const std::string&, const std::string&); void is (const char*, const char*, const std::string&); void diag (const std::string&); void pass (const std::string&); void fail (const std::string&); void skip (const std::string&); private: int mPlanned; int mCounter; int mPassed; int mFailed; int mSkipped; }; #endif //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/test/string.match.t0000755000175000017500000000356512215630160015474 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "default rule \"foo\" --> red match\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern matches work. my $output = qx{printf "a foo\na bar\n" | ../src/clog -f rc}; like ($output, qr/^a \033\[31mfoo\033\[0m$/ms, 'foo is red'); like ($output, qr/^a bar$/ms, 'bar is unchanged'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/string.line.t0000755000175000017500000000357112215630160015324 0ustar mogaalmogaal#! /usr/bin/perl ################################################################################ ## clog - colorized log tail ## ## Copyright 2010-2013, Paul Beckingham, Federico Hernandez. ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ## SOFTWARE. ## ## http://www.opensource.org/licenses/mit-license.php ## ################################################################################ use strict; use warnings; use Test::More tests => 4; # Create the rc file. if (open my $fh, '>', 'rc') { print $fh "default rule \"foo\" --> red line\n"; close $fh; ok (-r 'rc', 'Created rc'); } # Test that string pattern line matches work. my $output = qx{printf "a foo\na bar\n" | ../src/clog -f rc}; like ($output, qr/^\033\[31ma foo\033\[0m$/ms, 'foo is red'); like ($output, qr/^a bar$/ms, 'bar is unchanged'); # Cleanup. unlink qw(rc); ok (! -r 'rc', 'Cleanup'); exit 0; clog-1.1.0/test/nibbler.t.cpp0000644000175000017500000011620012215630160015255 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #ifdef NIBBLER_FEATURE_DATE #include #endif #include //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { #ifdef NIBBLER_FEATURE_DATE #ifdef NIBBLER_FEATURE_REGEX UnitTest t (402); #else UnitTest t (378); #endif #else #ifdef NIBBLER_FEATURE_REGEX UnitTest t (338); #else UnitTest t (314); #endif #endif try { Nibbler n; std::string s; int i; double d; time_t ti; #ifdef NIBBLER_FEATURE_DATE Date dt; #endif std::vector options; // Make sure the nibbler behaves itself with trivial input. t.diag ("Test all nibbler calls given empty input"); n = Nibbler (""); t.notok (n.getUntil (' ', s), "trivial: getUntil"); t.notok (n.getUntil ("hi", s), "trivial: getUntil"); t.notok (n.getUntilOneOf ("ab", s), "trivial: getUntilOneOf"); t.notok (n.skipN (123), "trivial: skipN"); t.notok (n.skip ('x'), "trivial: skip"); t.notok (n.skipAll ('x'), "trivial: skipAll"); t.notok (n.skipAllOneOf ("abc"), "trivial: skipAllOneOf"); t.notok (n.getQuoted ('"', s), "trivial: getQuoted"); t.notok (n.getDigit (i), "trivial: getDigit"); t.notok (n.getInt (i), "trivial: getInt"); // 10 t.notok (n.getHex (i), "trivial: getHex"); t.notok (n.getUnsignedInt (i), "trivial: getUnsignedInt"); t.notok (n.getUntilEOL (s), "trivial: getUntilEOL"); t.notok (n.getUntilEOS (s), "trivial: getUntilEOS"); t.notok (n.getDateISO (ti), "trivial: getDateISO"); #ifdef NIBBLER_FEATURE_DATE t.notok (n.getDate ("YYYYMMDD", ti), "trivial: getDate"); #endif t.notok (n.getOneOf (options, s), "trivial: getOneOf"); t.ok (n.depleted (), "trivial: depleted"); // bool getUntil (char, std::string&); t.diag ("Nibbler::getUntil"); n = Nibbler ("one two"); t.ok (n.getUntil (' ', s), " 'one two' : getUntil (' ') -> true"); t.is (s, "one", " 'one two' : getUntil (' ') -> 'one'"); // 20 t.ok (n.getUntil (' ', s), " ' two' : getUntil (' ') -> true"); t.is (s, "", " ' two' : getUntil (' ') -> ''"); t.ok (n.skip (' '), " ' two' : skip (' ') -> true"); t.ok (n.getUntil (' ', s), " 'two' : getUntil (' ') -> 'two'"); t.notok (n.getUntil (' ', s), " '' : getUntil (' ') -> false"); t.ok (n.depleted (), " '' : depleted () -> true"); #ifdef NIBBLER_FEATURE_REGEX // bool getUntilRx (const std::string&, std::string&); t.diag ("Nibbler::getUntilRx"); n = Nibbler ("one two"); t.ok (n.getUntilRx ("th", s), " 'one two' : getUntilRx ('th') -> true"); t.is (s, "one two", " 'one two' : getUntilRx ('th') -> 'one two'"); n = Nibbler ("one two"); t.ok (n.getUntilRx ("e", s), " 'one two' : getUntilRx ('e') -> true"); t.is (s, "on", " 'one two' : getUntilRx ('e') -> 'on'"); // 30 t.ok (n.getUntilRx ("tw", s), " 'e two' : getUntilRx ('tw') -> true"); t.is (s, "e ", " 'e two' : getUntilRx ('tw') -> 'e '"); t.ok (n.getUntilRx ("$", s), " 'two' : getUntilRx ('$') -> true"); t.is (s, "two", " 'two' : getUntilRx ('$') -> 'two'"); t.ok (n.depleted (), " '' : depleted () -> true"); #endif // bool getUntilOneOf (const std::string&, std::string&); t.diag ("Nibbler::getUntilOneOf"); n = Nibbler ("ab.cd"); t.ok (n.getUntilOneOf (".:", s), " 'ab.cd' : getUntilOneOf ('.:') -> true"); t.is (s, "ab", " 'ab.cd' : getUntilOneOf ('.:') -> 'ab'"); t.ok (n.skipN (), " '.cd' : skipN () -> true"); t.ok (n.getUntilOneOf (".:", s), " 'cd' : getUntilOneOf ('.:') -> true"); t.notok (n.getUntilOneOf (".:", s), " '' : getUntilOneOf ('.:') -> false"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getUntil (const std::string&, std::string&); t.diag ("Nibbler::getUntil"); n = Nibbler ("ab\r\ncd"); t.ok (n.getUntil ("\r\n", s), "'ab\\r\\ncd' : getUntil ('\\r\\n') -> true"); t.ok (n.skipN (2), " '\\r\\ncd' : skipN (2) -> true"); t.ok (n.getUntil ("\r\n", s), " 'cd' : getUntil ('\\r\\n') -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getUntilWS (std::string&); t.diag ("Nibbler::getUntilWS"); n = Nibbler ("ab \t\ncd"); t.ok (n.getUntilWS (s), " 'ab \\t\\ncd' : getUntilWS () -> true"); t.is (s, "ab", " 'ab \\t\\ncd' : getUntilWS () -> 'ab'"); t.ok (n.getUntilWS (s), " ' \\t\\ncd' : getUntilWS () -> true"); t.is (s, "", " ' \\t\\ncd' : getUntilWS () -> ''"); t.ok (n.skipWS (), " 'cd' : skipWS () -> true"); t.ok (n.getUntilWS (s), " '' : getUntilWS () -> true"); t.is (s, "cd", " 'cd' : getUntilWS () -> 'cd'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool skipN (const int quantity = 1); t.diag ("Nibbler::skipN"); n = Nibbler ("abcde"); t.ok (n.skipN (), " 'abcde' : skipN () -> true"); t.ok (n.skipN (2), " 'bcde' : skipN (2 -> true"); t.notok (n.skipN (3), " 'de' : skipN (3 -> false"); t.notok (n.depleted (), " 'de' : depleted () -> true"); // bool skip (char); t.diag ("Nibbler::skip"); n = Nibbler (" a"); t.ok (n.skip (' '), " ' a' : skip (' ') -> true"); t.ok (n.skip (' '), " ' a' : skip (' ') -> true"); t.notok (n.skip (' '), " 'a' : skip (' ') -> false"); t.notok (n.depleted (), " 'a' : depleted () -> false"); t.ok (n.skip ('a'), " 'a' : skip ('a') -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool skipAll (char); t.diag ("Nibbler::skipAll"); n = Nibbler ("aaaabb"); t.ok (n.skipAll ('a'), " 'aaaabb' : skipAll ('a') -> true"); t.notok (n.skipAll ('a'), " 'bb' : skipAll ('a') -> false"); t.ok (n.skipAll ('b'), " 'bb' : skipAll ('b') -> true"); t.notok (n.skipAll ('b'), " '' : skipAll ('b') -> false"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool skipAllOneOf (const std::string&); t.diag ("Nibbler::skipAllOneOf"); n = Nibbler ("abababcc"); t.ok (n.skipAllOneOf ("ab"), "'abababcc' : skipAllOneOf ('ab') -> true"); t.notok (n.skipAllOneOf ("ab"), " 'cc' : skipAllOneOf ('ab') -> false"); t.ok (n.skipAllOneOf ("c"), " 'cc' : skipAllOneOf ('ab') -> false"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool skipWS (); t.diag ("Nibbler::skipWS"); n = Nibbler (" \tfoo"); t.ok (n.skipWS (), " ' \\tfoo' : skipWS () -> true"); t.notok (n.skipWS (), " 'foo' : skipWS () -> false"); t.ok (n.getUntilEOS (s), " 'foo' : getUntilEOS () -> true"); t.is (s, "foo", " 'foo' : getUntilEOS () -> 'foo'"); t.ok (n.depleted (), " '' : depleted () -> true"); #ifdef NIBBLER_FEATURE_REGEX // bool skipRx (const std::string&); t.diag ("Nibbler::skipRx"); n = Nibbler ("one two"); t.ok (n.skipRx ("o."), " 'one two' : skipRx ('o.') -> true"); t.notok (n.skipRx ("A+"), " 'e two' : skipRx ('A+') -> false"); t.ok (n.skipRx ("e+"), " 'e two' : skipRx ('e+') -> true"); t.ok (n.skipRx ("...."), " ' two' : skipRx ('....') -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); #endif // bool getQuoted (char, std::string&); t.diag ("Nibbler::getQuoted"); n = Nibbler ("''"); t.ok (n.getQuoted ('\'', s), " '''' : getQuoted (''') -> true"); t.is (s, "", " '''' : getQuoted (''') -> ''"); n = Nibbler ("'\"'"); t.ok (n.getQuoted ('\'', s), " ''\"'' : getQuoted (''') -> true"); t.is (s, "\"", " ''\"'' : getQuoted (''') -> '\"'"); n = Nibbler ("'x'"); t.ok (n.getQuoted ('\'', s), " ''x'' : getQuoted (''') -> true"); t.is (s, "x", " ''x'' : getQuoted (''') -> ''"); n = Nibbler ("'x"); t.notok (n.getQuoted ('\'', s), " ''x' : getQuoted (''') -> false"); n = Nibbler ("x"); t.notok (n.getQuoted ('\'', s), " 'x' : getQuoted (''') -> false"); // 90 n = Nibbler ("\"one\\\"two\""); t.notok (n.getQuoted ('\'', s), "\"one\\\"two\" : getQuoted (''') -> false"); n = Nibbler ("\"one\\\"two\""); t.ok (n.getQuoted ('"', s, false), "\"one\\\"two\" : getQuoted ('\"', false, false) -> true"); t.is (s, "one\\\"two", "getQuoted ('\"', false) -> one\\\"two"); n = Nibbler ("\"one\\\"two\""); t.ok (n.getQuoted ('"', s, true), "\"one\\\"two\" : getQuoted ('\"', false, true) -> true"); t.is (s, "\"one\\\"two\"", "getQuoted ('\"', true) -> \"one\\\"two\""); n = Nibbler ("\"one\\\"two\""); t.ok (n.getQuoted ('"', s, false), "\"one\\\"two\" : getQuoted ('\"', true, false) -> true"); t.is (s, "one\\\"two", "getQuoted ('\"', false) -> one\\\"two"); n = Nibbler ("\"one\\\"two\""); t.ok (n.getQuoted ('"', s, true), "\"one\\\"two\" : getQuoted ('\"', s, true) -> true"); t.is (s, "\"one\\\"two\"", "getQuoted ('\"', s, true) -> \"one\\\"two\""); n = Nibbler ("\"one\\\\\""); t.ok (n.getQuoted ('\"', s, true), "\"one\\\" : getQuoted ('\"', s, true) -> true"); t.is (s, "\"one\\\\\"", "getQuoted ('\"', s, true) -> \"one\\\\\""); n = Nibbler ("\"one\\\\\""); t.ok (n.getQuoted ('\"', s, false), "one\\ : getQuoted ('\"', s, false) -> true"); t.is (s, "one\\\\", "getQuoted ('\"', s, false) -> \"one\\\\\""); // bool getDigit (int&); t.diag ("Nibbler::getDigit"); n = Nibbler ("12x"); t.ok (n.getDigit (i), " '12x' : getDigit () -> true"); t.is (i, 1, " '12x' : getDigit () -> 1"); t.ok (n.getDigit (i), " '2x' : getDigit () -> true"); t.is (i, 2, " '2x' : getDigit () -> 2"); t.notok (n.getDigit (i), " 'x' : getDigit () -> false"); // bool getDigit6 (int&); t.diag ("Nibbler::getDigit6"); n = Nibbler ("654321"); t.ok (n.getDigit6 (i), " 654321 : getDigit6 () -> true"); t.is (i, 654321, " 654321 : getDigit6 () -> 654321"); // bool getDigit4 (int&); t.diag ("Nibbler::getDigit4"); n = Nibbler ("4321"); t.ok (n.getDigit4 (i), " 4321 : getDigit4 () -> true"); t.is (i, 4321, " 4321 : getDigit4 () -> 4321"); // bool getDigit2 (int&); t.diag ("Nibbler::getDigit2"); n = Nibbler ("21"); t.ok (n.getDigit2 (i), " 21 : getDigit2 () -> true"); t.is (i, 21, " 21 : getDigit2 () -> 21"); // bool getInt (int&); t.diag ("Nibbler::getInt"); n = Nibbler ("123 -4"); t.ok (n.getInt (i), " '123 -4' : getInt () -> true"); t.is (i, 123, " '123 -4' : getInt () -> '123'"); t.ok (n.skip (' '), " ' -4' : skip (' ') -> true"); t.ok (n.getInt (i), " '-4' : getInt () -> true"); t.is (i, -4, " '-4' : getInt () -> '-4'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getHex (int&); t.diag ("Nibbler::getHex"); n = Nibbler ("123 7b"); t.ok (n.getHex (i), " '123 7b' : getHex () -> true"); t.is (i, 291, " '123 7b' : getHex () -> '291'"); t.ok (n.skip (' '), " ' 7b' : skip (' ') -> true"); t.ok (n.getHex (i), " '7b' : getHex () -> true"); t.is (i, 123, " '7b' : getHex () -> '123'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getUnsignedInt (int&i); t.diag ("Nibbler::getUnsignedInt"); n = Nibbler ("123 4"); t.ok (n.getUnsignedInt (i), " '123 4' : getUnsignedInt () -> true"); t.is (i, 123, " '123 4' : getUnsignedInt () -> '123'"); t.ok (n.skip (' '), " ' 4' : skip (' ') -> true"); t.ok (n.getUnsignedInt (i), " '4' : getUnsignedInt () -> true"); t.is (i, 4, " '4' : getUnsignedInt () -> '4'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getNumber (double&); t.diag ("Nibbler::getNumber"); n = Nibbler ("-1.234 2.3e4"); t.ok (n.getNumber (d), "'-1.234 2.3e4' : getNumber () -> true"); t.is (d, -1.234, 0.000001, "'-1.234 2.3e4' : getNumber () -> '-1.234'"); t.ok (n.skip (' '), " ' 2.3e4' : skip (' ') -> true"); t.ok (n.getNumber (d), " '2.3e4' : getNumber () -> true"); t.is (d, 2.3e4, " '2.3e4' : getNumber () -> '2.3e4'"); t.ok (n.depleted (), " '' : depleted () -> true"); n = Nibbler ("2.0"); t.ok (n.getNumber (d), "'2.0' : getNumber () -> true"); t.is (d, 2.0, 0.000001, "'2.0' : getNumber () -> '2.0'"); t.ok (n.depleted (), " '' : depleted () -> true"); n = Nibbler ("-864000.00000"); t.ok (n.getNumber (d), "'-864000.00000' : getNumber () -> true"); t.is (d, -864000.0, "'-864000.00000' : getNumber () -> -864000.0"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getLiteral (const std::string&); t.diag ("Nibbler::getLiteral"); n = Nibbler ("foobar"); t.ok (n.getLiteral ("foo"), " 'foobar' : getLiteral ('foo') -> true"); t.notok (n.getLiteral ("foo"), " 'bar' : getLiteral ('foo') -> false"); t.ok (n.getLiteral ("bar"), " 'bar' : getLiteral ('bar') -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); #ifdef NIBBLER_FEATURE_REGEX // bool getRx (const std::string&, std::string&); t.diag ("Nibbler::getRx"); n = Nibbler ("one two three"); t.ok (n.getRx ("^(o..)", s), "'one two three' : getRx ('^(o..)') -> true"); t.is (s, "one", "'one two three' : getRx ('^(o..)') -> 'one'"); t.ok (n.skip (' '), " ' two three' : skip (' ') -> true"); t.ok (n.getRx ("t..", s), " 'two three' : getRx ('t..') -> true"); t.is (s, "two", " 'two three' : getRx ('t..') -> 'two'"); t.notok (n.getRx ("th...", s), " ' three' : getRx ('th...') -> false"); t.ok (n.skip (' '), " ' three' : skip (' ') -> true"); t.ok (n.getRx ("th...", s), " 'three' : getRx ('th...') -> true"); t.is (s, "three", " 'three' : getRx ('th...') -> 'three'"); t.ok (n.depleted (), " '' : depleted () -> true"); #endif // bool getUUID (std::string&); t.diag ("Nibbler::getUUID"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5"); t.ok (n.getUUID (s), "uuid 1 found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5", "uuid 1 -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("00000000-0000-0000-0000-000000000000,a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5"); t.ok (n.getUUID (s), "uuid 1 found"); t.is (s, "00000000-0000-0000-0000-000000000000", "uuid 1 -> correct"); t.ok (n.skip (','), "comma -> skipped"); t.ok (n.getUUID (s), "uuid 2 -> found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5", "uuid 2 -> correct"); t.ok (n.depleted (), "depleted"); // bool getPartialUUID (std::string&); t.diag ("Nibbler::getPartialUUID"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5"); t.ok (n.getPartialUUID (s), "partial uuid [36] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5", "partial uuid [36] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d"); t.ok (n.getPartialUUID (s), "partial uuid [35] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d", "partial uuid [35] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4"); t.ok (n.getPartialUUID (s), "partial uuid [34] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4", "partial uuid [34] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c"); t.ok (n.getPartialUUID (s), "partial uuid [33] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c", "partial uuid [33] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3"); t.ok (n.getPartialUUID (s), "partial uuid [32] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3", "partial uuid [32] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b"); t.ok (n.getPartialUUID (s), "partial uuid [31] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b", "partial uuid [31] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2"); t.ok (n.getPartialUUID (s), "partial uuid [30] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2", "partial uuid [30] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a"); t.ok (n.getPartialUUID (s), "partial uuid [29] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a", "partial uuid [29] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1"); t.ok (n.getPartialUUID (s), "partial uuid [28] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1", "partial uuid [28] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F"); t.ok (n.getPartialUUID (s), "partial uuid [27] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F", "partial uuid [27] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0"); t.ok (n.getPartialUUID (s), "partial uuid [26] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0", "partial uuid [26] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E"); t.ok (n.getPartialUUID (s), "partial uuid [25] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E", "partial uuid [25] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-"); t.ok (n.getPartialUUID (s), "partial uuid [24] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-", "partial uuid [24] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9"); t.ok (n.getPartialUUID (s), "partial uuid [23] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9", "partial uuid [23] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D"); t.ok (n.getPartialUUID (s), "partial uuid [22] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8D", "partial uuid [22] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8"); t.ok (n.getPartialUUID (s), "partial uuid [21] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C8", "partial uuid [21] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-C"); t.ok (n.getPartialUUID (s), "partial uuid [20] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-C", "partial uuid [20] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7-"); t.ok (n.getPartialUUID (s), "partial uuid [19] found"); t.is (s, "a0b1c2d3-e4f5-A6B7-", "partial uuid [19] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B7"); t.ok (n.getPartialUUID (s), "partial uuid [18] found"); t.is (s, "a0b1c2d3-e4f5-A6B7", "partial uuid [18] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6B"); t.ok (n.getPartialUUID (s), "partial uuid [17] found"); t.is (s, "a0b1c2d3-e4f5-A6B", "partial uuid [17] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A6"); t.ok (n.getPartialUUID (s), "partial uuid [16] found"); t.is (s, "a0b1c2d3-e4f5-A6", "partial uuid [16] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-A"); t.ok (n.getPartialUUID (s), "partial uuid [15] found"); t.is (s, "a0b1c2d3-e4f5-A", "partial uuid [15] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5-"); t.ok (n.getPartialUUID (s), "partial uuid [14] found"); t.is (s, "a0b1c2d3-e4f5-", "partial uuid [14] -> correct"); t.ok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f5"); t.notok (n.getPartialUUID (s), "partial uuid [13] not found"); t.notok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4f"); t.notok (n.getPartialUUID (s), "partial uuid [12] not found"); t.notok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e4"); t.notok (n.getPartialUUID (s), "partial uuid [11] not found"); t.notok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-e"); t.notok (n.getPartialUUID (s), "partial uuid [10] not found"); t.notok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3-"); t.notok (n.getPartialUUID (s), "partial uuid [9] not found"); t.notok (n.depleted (), "depleted"); n = Nibbler ("a0b1c2d3"); t.notok (n.getPartialUUID (s), "partial uuid [8] not found"); t.notok (n.depleted (), "not depleted"); // bool getDateISO (time_t&); t.diag ("Nibbler::getDateISO"); n = Nibbler ("19980119T070000Z"); t.ok (n.getDateISO (ti), "'19980119T070000Z': getDateISO () -> true"); t.is (ti, 885193200, "'19980119T070000Z': getDateISO () -> 885193200"); t.ok (n.depleted (), "depleted"); n = Nibbler ("20090213T233130Z"); t.ok (n.getDateISO (ti), "'20090213T233130Z': getDateISO () -> true"); t.is (ti, 1234567890, "'20090213T233130Z': getDateISO () -> 1234567890"); t.ok (n.depleted (), "depleted"); #ifdef NIBBLER_FEATURE_DATE // bool getDate (time_t&, const std::string&); t.diag ("Nibbler::getDate"); n = Nibbler ("1/1/2008"); t.ok (n.getDate ("m/d/Y", ti), "m/d/Y ok"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2008, "ctor (std::string) -> y"); n = Nibbler ("20080101"); t.ok (n.getDate ("YMD", ti), "YMD ok"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2008, "ctor (std::string) -> y"); n = Nibbler ("12/31/2007"); t.ok (n.getDate ("m/d/Y", ti), "m/d/Y ok"); dt = Date (ti); t.is (dt.month (), 12, "ctor (std::string) -> m"); t.is (dt.day (), 31, "ctor (std::string) -> d"); t.is (dt.year (), 2007, "ctor (std::string) -> y"); n = Nibbler ("20071231"); t.ok (n.getDate ("YMD", ti), "YMD ok"); dt = Date (ti); t.is (dt.month (), 12, "ctor (std::string) -> m"); t.is (dt.day (), 31, "ctor (std::string) -> d"); t.is (dt.year (), 2007, "ctor (std::string) -> y"); n = Nibbler ("Tue 01 Jan 2008 (01)"); t.ok (n.getDate ("a D b Y (V)", ti), "a D b Y (V)"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2008, "ctor (std::string) -> y"); n = Nibbler ("Tuesday, January 1, 2008"); t.ok (n.getDate ("A, B d, Y", ti), "A, B d, Y ok"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2008, "ctor (std::string) -> y"); n = Nibbler ("w01 Tue 2008-01-01"); t.ok (n.getDate ("wV a Y-M-D", ti), "wV a Y-M-D ok"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2008, "ctor (std::string) -> y"); n = Nibbler ("6/7/2010 1:23:45"); t.ok (n.getDate ("m/d/Y h:N:S", ti), "m/d/Y h:N:S ok"); dt = Date (ti); t.is (dt.month (), 6, "ctor (std::string) -> m"); t.is (dt.day (), 7, "ctor (std::string) -> d"); t.is (dt.year (), 2010, "ctor (std::string) -> Y"); t.is (dt.hour (), 1, "ctor (std::string) -> h"); t.is (dt.minute (), 23, "ctor (std::string) -> N"); t.is (dt.second (), 45, "ctor (std::string) -> S"); n = Nibbler ("6/7/2010 01:23:45"); t.ok (n.getDate ("m/d/Y H:N:S", ti), "m/d/Y H:N:S ok"); dt = Date (ti); t.is (dt.month (), 6, "ctor (std::string) -> m"); t.is (dt.day (), 7, "ctor (std::string) -> d"); t.is (dt.year (), 2010, "ctor (std::string) -> Y"); t.is (dt.hour (), 1, "ctor (std::string) -> h"); t.is (dt.minute (), 23, "ctor (std::string) -> N"); t.is (dt.second (), 45, "ctor (std::string) -> S"); n = Nibbler ("6/7/2010 12:34:56"); t.ok (n.getDate ("m/d/Y H:N:S", ti), "m/d/Y H:N:S ok"); dt = Date (ti); t.is (dt.month (), 6, "ctor (std::string) -> m"); t.is (dt.day (), 7, "ctor (std::string) -> d"); t.is (dt.year (), 2010, "ctor (std::string) -> Y"); t.is (dt.hour (), 12, "ctor (std::string) -> h"); t.is (dt.minute (), 34, "ctor (std::string) -> N"); t.is (dt.second (), 56, "ctor (std::string) -> S"); n = Nibbler ("2010"); t.ok (n.getDate ("Y", ti), "Y ok"); dt = Date (ti); t.is (dt.month (), 1, "ctor (std::string) -> m"); t.is (dt.day (), 1, "ctor (std::string) -> d"); t.is (dt.year (), 2010, "ctor (std::string) -> Y"); t.is (dt.hour (), 0, "ctor (std::string) -> h"); t.is (dt.minute (), 0, "ctor (std::string) -> N"); t.is (dt.second (), 0, "ctor (std::string) -> S"); n = Nibbler ("17:18:19"); t.ok (n.getDate ("H:N:S", ti), "H:N:S ok"); dt = Date (ti); Date now = Date (); t.is (dt.month (), now.month(), "ctor (std::string) -> m"); t.is (dt.day (), now.day(), "ctor (std::string) -> d"); t.is (dt.year (), now.year(), "ctor (std::string) -> Y"); t.is (dt.hour (), 17, "ctor (std::string) -> h"); t.is (dt.minute (), 18, "ctor (std::string) -> N"); t.is (dt.second (), 19, "ctor (std::string) -> S"); #endif // bool getOneOf (const std::vector &, std::string&); t.diag ("Nibbler::getOneOf"); options.push_back ("one"); options.push_back ("two"); options.push_back ("three"); n = Nibbler ("onetwothreefour"); t.ok (n.getOneOf (options, s), "'onetwothreefour': getOneOf () -> true"); t.is (s, "one", "'onetwothreefour': getOneOf () -> one"); t.ok (n.getOneOf (options, s), " 'twothreefour': getOneOf () -> true"); t.is (s, "two", " 'twothreefour': getOneOf () -> two"); t.ok (n.getOneOf (options, s), " 'threefour': getOneOf () -> true"); t.is (s, "three", " 'threefour': getOneOf () -> three"); t.notok (n.getOneOf (options, s), " 'four': getOneOf () -> false"); // bool getName (std::string&); t.diag ("Nibbler::getName"); n = Nibbler ("a1 one one.two 9"); t.ok (n.getName (s), "'a1 one one.two 9' getName -> ok"); t.is (s, "a1", " ' one one.two 9' getName -> 'a1'"); t.ok (n.skipWS (), " 'one one.two 9' skipWS -> ok"); t.ok (n.getName (s), " 'one one.two 9' getName -> ok"); t.is (s, "one", " ' one.two 9' getName -> 'one'"); t.ok (n.skipWS (), " 'one.two 9' skipWS -> ok"); t.ok (n.getName (s), " 'one.two 9' getName -> ok"); t.is (s, "one", " '.two 9' getName -> 'one'"); t.ok (n.skip ('.'), " 'two 9' skip . -> ok"); t.ok (n.getName (s), " 'two 9' getName -> ok"); t.is (s, "two", " ' 9' getName -> 'two'"); t.ok (n.skipWS (), " '9' skipWS -> ok"); t.notok (n.getName (s), " '9' getName -> not ok"); t.ok (n.skip ('9'), " '' skip 9 -> ok"); t.ok (n.depleted (), "depleted"); n = Nibbler ("entrée"); t.ok (n.getName (s), "'entrée' -> ok"); t.is (s, "entrée", "'entrée' -> 'entrée'"); // bool getWord (std::string&); t.diag ("Nibbler::getWord"); n = Nibbler ("one two th3ee"); t.ok (n.getWord (s), "'one' getWord -> ok"); t.is (s, "one", "'one' getWord -> 'one'"); t.ok (n.skipWS (), "skipWS"); t.ok (n.getWord (s), "'two' getWord -> ok"); t.is (s, "two", "'two' getWord -> 'two'"); t.ok (n.skipWS (), "skipWS"); t.ok (n.getWord (s), "'th' getWord -> ok"); t.is (s, "th", "'th' getWord -> 'th'"); t.ok (n.skip ('3'), "skip(3)"); t.ok (n.getWord (s), "'ee' getWord -> ok"); t.is (s, "ee", "'ee' getWord -> 'ee'"); t.ok (n.depleted (), "depleted"); t.diag ("Nibbler::getWord"); n = Nibbler ("one TWO,three,f "); t.ok (n.getWord (s), "'one TWO,three,f ' getWord -> ok"); t.is (s, "one", " ' TWO,three,f ' getWord -> one"); t.ok (n.skipWS (), " 'TWO,three,f ' skipWS -> ok"); t.ok (n.getWord (s), " 'TWO,three,f ' getWord -> ok"); t.is (s, "TWO", " ',three,f ' getWord -> TWO"); t.ok (n.skip (','), " 'three,f ' skip , -> ok"); t.ok (n.getWord (s), " 'three,f ' getWord -> ok"); t.is (s, "three", " ',f ' getWord -> three"); t.ok (n.skip (','), " 'f ' skip , -> ok"); t.ok (n.getWord (s), " 'f ' getWord -> ok"); t.is (s, "f", " ' ' getWord -> f"); t.ok (n.skipWS (), " '' skip , -> ok"); t.ok (n.depleted (), " '' depleted -> true"); // bool getN (int, std::string&); t.diag ("Nibbler::getN"); n = Nibbler ("111223"); t.ok (n.getN (3, s), " '111223' : getN (3) -> true"); t.is (s, "111", " '111223' : getN (3) -> '111'"); t.ok (n.getN (2, s), " '223' : getN (2) -> true"); t.is (s, "22", " '223' : getN (2) -> '22'"); t.ok (n.getN (1, s), " '3' : getN (1) -> true"); t.is (s, "3", " '3' : getN (1) -> '1'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getUntilEOL (std::string&); t.diag ("Nibbler::getUntilEOL"); n = Nibbler ("one\ntwo"); t.ok (n.getUntilEOL (s), "'one\\ntwo' : getUntilEOL () -> true"); t.is (s, "one", "'one\\ntwo' : getUntilEOL () -> 'one'"); t.ok (n.skip ('\n'), " '\\ntwo' : skip ('\\n') -> true"); t.ok (n.getUntilEOL (s), " 'two' : getUntilEOL () -> true"); t.is (s, "two", " 'two' : getUntilEOL () -> 'two'"); t.ok (n.depleted (), " '' : depleted () -> true"); // bool getUntilEOS (std::string&); t.diag ("Nibbler::getUntilEOS"); n = Nibbler ("one two"); t.ok (n.getUntilEOS (s), " 'one two' : getUntilEOS () -> 'one two'"); t.ok (n.depleted (), " '' : depleted () -> true"); // char next (); t.diag ("Nibbler::next"); n = Nibbler ("hello"); t.is (n.next (), 'h', " 'hello' : next () -> 'h'"); t.is (n.next (), 'h', " 'hello' : next () -> 'h'"); t.ok (n.skipN (4), " 'hello' : skipN (4) -> true"); t.is (n.next (), 'o', " 'o' : next () -> 'o'"); t.ok (n.skipN (1), " 'o' : skipN () -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); // std::string next (const int quantity); t.diag ("Nibbler::next"); n = Nibbler ("hello"); t.is (n.next (1), "h", " 'hello' : next (1) -> 'h'"); t.is (n.next (1), "h", " 'hello' : next (1) -> 'h'"); t.is (n.next (2), "he", " 'hello' : next (2) -> 'he'"); t.is (n.next (3), "hel", " 'hello' : next (3) -> 'hel'"); t.is (n.next (4), "hell", " 'hello' : next (4) -> 'hell'"); t.is (n.next (5), "hello", " 'hello' : next (5) -> 'hello'"); t.is (n.next (6), "", " 'hello' : next (6) -> ''"); // bool depleted (); t.diag ("Nibbler::depleted"); n = Nibbler (" "); t.notok (n.depleted (), " ' ' : depleted () -> false"); t.ok (n.skipN (), " '' : skip () -> true"); t.ok (n.depleted (), " '' : depleted () -> true"); // void save (); // void restore (); n = Nibbler ("abcde"); t.ok (n.skipN (), " 'abcde' : skip () -> true"); n.save (); t.ok (n.skipN (), " 'bcde' : skip () -> true"); t.ok (n.skipN (), " 'cde' : skip () -> true"); t.ok (n.skipN (), " 'de' : skip () -> true"); n.restore (); t.is (n.next (1), "b", " 'bcde' : skip () -> 'b'"); } catch (const std::string& e) {t.diag (e);} return 0; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/NEWS0000644000175000017500000000110412215630160012406 0ustar mogaalmogaal New Features in clog 1.1.0 - Regular expression or plain text matching. - Colorization of line or pattern. - Suppression. - Date- and time-stamp insertion. - Highlighting by putting a blank line before and after a pattern. Please refer to the ChangeLog file for full details. --- Clog has been built and tested on the following configurations: * Ubuntu 10.04 * OS X 10.8 Mountain Lion * OS X 10.7 Lion --- While clog has undergone testing, bugs are sure to remain. If you encounter a bug, please send a message to: support@tasktools.org Thank you. clog-1.1.0/src/0000755000175000017500000000000012215630207012504 5ustar mogaalmogaalclog-1.1.0/src/text.h0000644000175000017500000000600212215630160013635 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_TEXT #define INCLUDED_TEXT #include #include // text.cpp, Non-UTF-8 aware. std::string trimLeft (const std::string& in, const std::string& t = " "); std::string trimRight (const std::string& in, const std::string& t = " "); std::string trim (const std::string& in, const std::string& t = " "); void split (std::vector&, const std::string&, const char); void split (std::vector&, const std::string&, const std::string&); void join (std::string&, const std::string&, const std::vector&); void join (std::string&, const std::string&, const std::vector&); std::string lowerCase (const std::string&); std::string upperCase (const std::string&); const std::string format (char); const std::string format (int); const std::string formatHex (int); const std::string format (float, int, int); const std::string format (double, int, int); const std::string format (double); const std::string format (const std::string&, const std::string&); const std::string format (const std::string&, int); const std::string format (const std::string&, const std::string&, const std::string&); const std::string format (const std::string&, const std::string&, int); const std::string format (const std::string&, const std::string&, double); const std::string format (const std::string&, int, const std::string&); const std::string format (const std::string&, int, int); const std::string format (const std::string&, int, double); const std::string format (const std::string&, const std::string&, const std::string&, const std::string&); #endif //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/clog.cpp0000644000175000017500000001624312215630160014140 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // - Read rc file // - Strip comments // - Parse rules // // Note that it is an error to not have an rc file. bool loadRules (const std::string& file, std::vector & rules) { std::ifstream rc (file.c_str ()); if (rc.good ()) { std::string::size_type comment; std::string line; while (getline (rc, line)) // Strips \n { // Remove comments. if ((comment = line.find ('#')) != std::string::npos) line = line.substr (0, comment); // Process each non-trivial line as a rule. if (line.length () > 1) { try { rules.push_back (Rule (line)); } catch (int) { // Deliberately ignored - error handling. } } } rc.close (); return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // Applies all the rules in all the sections specified. // Note that processing does not stop after the first rule match - it keeps // going. void applyRules ( std::vector & rules, std::vector & sections, std::string& line) { std::vector ::const_iterator section; for (section = sections.begin (); section != sections.end (); ++section) { std::vector ::iterator rule; for (rule = rules.begin (); rule != rules.end (); ++rule) { // Modify line accordingly. rule->apply (*section, line); } } } //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { int status = 0; try { // Locate $HOME. struct passwd* pw = getpwuid (getuid ()); if (!pw) throw std::string ("Could not read home directory from the passwd file."); // Assume ~/.clogrc std::string rcFile = pw->pw_dir; rcFile += "/.clogrc"; // Process arguments. std::vector sections; bool prepend_date = false; bool prepend_time = false; for (int i = 1; i < argc; ++i) { if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { std::cout << "\n" << "Usage: clog [-h|--help] [-v|--version] [-d|--date] [-t|--time] " << " [-f|--file ] [
... ]\n" << "\n"; return status; } else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version")) { std::cout << "\n" << PACKAGE_STRING << " built for " #if defined (DARWIN) << "darwin" #elif defined (SOLARIS) << "solaris" #elif defined (CYGWIN) << "cygwin" #elif defined (OPENBSD) << "openbsd" #elif defined (HAIKU) << "haiku" #elif defined (FREEBSD) << "freebsd" #elif defined (LINUX) << "linux" #else << "unknown" #endif << "\n" << "Copyright (C) 2010-2013 Göteborg Bit Factory\n" << "\n" << "Clog may be copied only under the terms of the MIT " "license, which may be found in the source kit.\n" << "\n" << "Documentation for clog can be found using 'man clog' " "or at http://tasktools.org/projects/clog.html\n" << "\n"; return status; } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--date")) { prepend_date = true; } else if (!strcmp (argv[i], "-t") || !strcmp (argv[i], "--time")) { prepend_time = true; } else if (argc > i + 1 && (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--file"))) { rcFile = argv[++i]; } else { sections.push_back (argv[i]); } } // Use a default section if one was not specified. if (sections.size () == 0) sections.push_back ("default"); // Read rc file. std::vector rules; if (loadRules (rcFile, rules)) { // Main loop: read line, apply rules, write line. std::string line; while (getline (std::cin, line)) // Strips \n { applyRules (rules, sections, line); if (line.length ()) { if (prepend_date || prepend_time) { time_t current; time (¤t); struct tm* t = localtime (¤t); if (prepend_date) std::cout << t->tm_year + 1900 << '-' << std::setw (2) << std::setfill ('0') << t->tm_mon + 1 << '-' << std::setw (2) << std::setfill ('0') << t->tm_mday << ' '; if (prepend_time) std::cout << std::setw (2) << std::setfill ('0') << t->tm_hour << ':' << std::setw (2) << std::setfill ('0') << t->tm_min << ':' << std::setw (2) << std::setfill ('0') << t->tm_sec << ' '; } std::cout << line << std::endl; } } } else { std::cout << "Cannot open " << rcFile << "\n" << "See 'man clog' for details, and a sample file.\n"; status = -1; } } catch (std::string& error) { std::cout << error << "\n"; return -1; } catch (...) { std::cout << "Unknown error\n"; return -2; } return status; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/Rule.cpp0000644000175000017500000001613112215630160014117 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include //////////////////////////////////////////////////////////////////////////////// //
rule // --> // taskd rule /code:"2.."/ --> green line Rule::Rule (const std::string& line) { fragment = ""; Nibbler n (line); n.skipWS (); std::string pattern; if (n.getUntilWS (section) && n.skipWS () && n.getLiteral ("rule") && n.skipWS ()) { //
rule // if (n.getQuoted ('/', pattern) && n.skipWS () && n.getLiteral ("-->")) { n.skipWS (); std::string rest; n.getRemainder (rest); std::string color_name; std::vector words; split (words, rest, ' '); std::vector ::iterator i; for (i = words.begin (); i != words.end (); ++i) { if (i->length ()) { if (*i == "line") context = *i; else if (*i == "match") context = *i; else if (*i == "suppress") context = *i; else if (*i == "blank") context = *i; else { if (color_name.length ()) color_name += " "; color_name += *i; } } } color = Color (color_name); // Now for "match" context patterns, add an enclosing ( ... ) is not // already present. if (context == "match") if (pattern.find ('(') == std::string::npos) pattern = "(" + pattern + ")"; rx = RX (pattern, true); return; } //
rule "" else if (n.getQuoted ('"', pattern) && n.skipWS () && n.getLiteral ("-->")) { n.skipWS (); std::string rest; n.getRemainder (rest); std::string color_name; std::vector words; split (words, rest, ' '); std::vector ::iterator i; for (i = words.begin (); i != words.end (); ++i) { if (i->length ()) { if (*i == "line") context = *i; else if (*i == "match") context = *i; else if (*i == "suppress") context = *i; else if (*i == "blank") context = *i; // TODO Support context "datetime", "time" else { if (color_name.length ()) color_name += " "; color_name += *i; } } } color = Color (color_name); fragment = pattern; return; } } // Indicates that 'line' was not a rule def, but a blank line or similar. throw int (1); } //////////////////////////////////////////////////////////////////////////////// Rule::Rule (const Rule& other) { if (this != &other) { section = other.section; color = other.color; context = other.context; rx = other.rx; fragment = other.fragment; } } //////////////////////////////////////////////////////////////////////////////// Rule::~Rule () { } //////////////////////////////////////////////////////////////////////////////// Rule& Rule::operator= (const Rule& other) { if (this != &other) { section = other.section; color = other.color; context = other.context; rx = other.rx; fragment = other.fragment; } return *this; } //////////////////////////////////////////////////////////////////////////////// // There are two kinds of matching: // - regex (when fragment is "") // - substring (when fragment is not "") // // There are several corresponding actions: // - suppress Eats the line // - line Colorizes the line // - match Colorizes the matching part // - blank Adds a blank line before and after // bool Rule::apply (const std::string& section, std::string& line) { if (section == this->section) { if (context == "suppress") { if (fragment != "") { if (line.find (fragment) != std::string::npos) { line = ""; return true; } } else { if (rx.match (line)) { line = ""; return true; } } } else if (context == "line") { if (fragment != "") { if (line.find (fragment) != std::string::npos) { line = color.colorize (line); return true; } } else { if (rx.match (line)) { line = color.colorize (line); return true; } } } else if (context == "match") { if (fragment != "") { std::string::size_type pos = line.find (fragment); if (pos != std::string::npos) { line = line.substr (0, pos) + color.colorize (line.substr (pos, fragment.length ())) + line.substr (pos + fragment.length ()); return true; } } else { std::vector start; std::vector end; if (rx.match (start, end, line)) { line = line.substr (0, start[0]) + color.colorize (line.substr (start[0], end[0] - start[0])) + line.substr (end[0]); return true; } } } else if (context == "blank") { if (fragment != "") { if (line.find (fragment) != std::string::npos) { line = "\n" + line + "\n"; return true; } } else { if (rx.match (line)) { line = "\n" + line + "\n"; return true; } } } } return false; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/Nibbler.h0000644000175000017500000000762012215630160014235 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_NIBBLER #define INCLUDED_NIBBLER #include #define NIBBLER_FEATURE_DATE #undef NIBBLER_FEATURE_DATE #define NIBBLER_FEATURE_REGEX //#undef NIBBLER_FEATURE_REGEX #include #include class Nibbler { public: Nibbler (); // Default constructor Nibbler (const std::string&); // Constructor Nibbler (const Nibbler&); // Copy constructor Nibbler& operator= (const Nibbler&); // Assignment operator ~Nibbler (); // Destructor bool getUntil (char, std::string&); bool getUntil (const std::string&, std::string&); #ifdef NIBBLER_FEATURE_REGEX bool getUntilRx (const std::string&, std::string&); #endif bool getUntilOneOf (const std::string&, std::string&); bool getUntilWS (std::string&); bool getUntilEOL (std::string&); bool getUntilEOS (std::string&); /* bool getAllOneOf (const std::string&, std::string&); */ bool getN (const int, std::string&); bool getQuoted (char, std::string&, bool quote = false); bool getDigit (int&); bool getDigit6 (int&); bool getDigit4 (int&); bool getDigit2 (int&); bool getInt (int&); bool getHex (int&); bool getUnsignedInt (int&); bool getNumber (std::string&); bool getNumber (double&); bool getUnsignedNumber (double&); bool getLiteral (const std::string&); #ifdef NIBBLER_FEATURE_REGEX bool getRx (const std::string&, std::string&); #endif bool getUUID (std::string&); bool getPartialUUID (std::string&); bool getDateISO (time_t&); bool parseDigits(std::string::size_type&, int&, unsigned int, bool strict = true); #ifdef NIBBLER_FEATURE_DATE bool getDate (const std::string&, time_t&); #endif bool getOneOf (const std::vector &, std::string&); bool getName (std::string&); bool getWord (std::string&); bool skipN (const int quantity = 1); bool skip (char); bool skipAll (char); bool skipAllOneOf (const std::string&); bool skipWS (); #ifdef NIBBLER_FEATURE_REGEX bool skipRx (const std::string&); #endif void getRemainder (std::string&); char next (); std::string next (const int quantity); std::string::size_type cursor (); std::string::size_type save (); std::string::size_type restore (); const std::string& str () const; bool depleted (); static bool isPunctuation (char); std::string dump (); private: std::string _input; std::string::size_type _length; std::string::size_type _cursor; std::string::size_type _saved; }; #endif //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/RX.h0000644000175000017500000000366412215630160013215 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_RX #define INCLUDED_RX #include #include #include class RX { public: RX (); RX (const std::string&, bool caseSensitive = true); RX (const RX&); RX& operator= (const RX&); bool operator== (const RX&) const; ~RX (); bool match (const std::string&); bool match (std::vector&, const std::string&); bool match (std::vector &, std::vector &, const std::string&); private: void compile (); private: bool _compiled; std::string _pattern; bool _case_sensitive; regex_t _regex; }; #endif clog-1.1.0/src/RX.cpp0000644000175000017500000001147312215630160013545 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include //#define _POSIX_C_SOURCE 1 // Forgot why this is here. Moving on... //////////////////////////////////////////////////////////////////////////////// RX::RX () : _compiled (false) , _pattern ("") , _case_sensitive (true) { } //////////////////////////////////////////////////////////////////////////////// RX::RX ( const std::string& pattern, bool case_sensitive /* = true */) : _compiled (false) , _pattern (pattern) , _case_sensitive (case_sensitive) { compile (); } //////////////////////////////////////////////////////////////////////////////// RX::RX (const RX& other) : _compiled (false) , _pattern (other._pattern) , _case_sensitive (other._case_sensitive) { } //////////////////////////////////////////////////////////////////////////////// RX& RX::operator= (const RX& other) { if (this != &other) { _compiled = false; _pattern = other._pattern; _case_sensitive = other._case_sensitive; } return *this; } //////////////////////////////////////////////////////////////////////////////// bool RX::operator== (const RX& other) const { return _pattern == other._pattern && _case_sensitive == other._case_sensitive; } //////////////////////////////////////////////////////////////////////////////// RX::~RX () { if (_compiled) regfree (&_regex); } //////////////////////////////////////////////////////////////////////////////// void RX::compile () { if (!_compiled) { memset (&_regex, 0, sizeof (regex_t)); int result; if ((result = regcomp (&_regex, _pattern.c_str (), REG_EXTENDED | REG_NEWLINE | (_case_sensitive ? 0 : REG_ICASE))) != 0) { char message[256]; regerror (result, &_regex, message, 256); throw std::string (message); } _compiled = true; } } //////////////////////////////////////////////////////////////////////////////// bool RX::match (const std::string& in) { if (!_compiled) compile (); return regexec (&_regex, in.c_str (), 0, NULL, 0) == 0 ? true : false; } //////////////////////////////////////////////////////////////////////////////// bool RX::match ( std::vector& matches, const std::string& in) { if (!_compiled) compile (); regmatch_t rm[2]; int offset = 0; int length = in.length (); while (regexec (&_regex, in.c_str () + offset, 2, &rm[0], 0) == 0 && offset < length) { matches.push_back (in.substr (rm[0].rm_so + offset, rm[0].rm_eo - rm[0].rm_so)); offset += rm[0].rm_eo; // Protection against zero-width patterns causing infinite loops. if (rm[0].rm_so == rm[0].rm_eo) ++offset; } return matches.size () ? true : false; } //////////////////////////////////////////////////////////////////////////////// bool RX::match ( std::vector & start, std::vector & end, const std::string& in) { if (!_compiled) compile (); regmatch_t rm[2]; int offset = 0; int length = in.length (); while (regexec (&_regex, in.c_str () + offset, 2, &rm[0], 0) == 0 && offset < length) { start.push_back (rm[0].rm_so + offset); end.push_back (rm[0].rm_eo + offset); offset += rm[0].rm_eo; // Protection against zero-width patterns causing infinite loops. if (rm[0].rm_so == rm[0].rm_eo) ++offset; } return start.size () ? true : false; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/text.cpp0000644000175000017500000002172312215630160014177 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// void split ( std::vector& results, const std::string& input, const char delimiter) { results.clear (); std::string::size_type start = 0; std::string::size_type i; while ((i = input.find (delimiter, start)) != std::string::npos) { results.push_back (input.substr (start, i - start)); start = i + 1; } if (input.length ()) results.push_back (input.substr (start)); } //////////////////////////////////////////////////////////////////////////////// void split ( std::vector& results, const std::string& input, const std::string& delimiter) { results.clear (); std::string::size_type length = delimiter.length (); std::string::size_type start = 0; std::string::size_type i; while ((i = input.find (delimiter, start)) != std::string::npos) { results.push_back (input.substr (start, i - start)); start = i + length; } if (input.length ()) results.push_back (input.substr (start)); } //////////////////////////////////////////////////////////////////////////////// void join ( std::string& result, const std::string& separator, const std::vector& items) { std::stringstream s; unsigned int size = items.size (); for (unsigned int i = 0; i < size; ++i) { s << items[i]; if (i < size - 1) s << separator; } result = s.str (); } //////////////////////////////////////////////////////////////////////////////// void join ( std::string& result, const std::string& separator, const std::vector& items) { std::stringstream s; unsigned int size = items.size (); for (unsigned int i = 0; i < size; ++i) { s << items[i]; if (i < size - 1) s << separator; } result = s.str (); } //////////////////////////////////////////////////////////////////////////////// std::string trimLeft (const std::string& in, const std::string& t /*= " "*/) { std::string out = in; return out.erase (0, in.find_first_not_of (t)); } //////////////////////////////////////////////////////////////////////////////// std::string trimRight (const std::string& in, const std::string& t /*= " "*/) { std::string out = in; return out.erase (out.find_last_not_of (t) + 1); } //////////////////////////////////////////////////////////////////////////////// std::string trim (const std::string& in, const std::string& t /*= " "*/) { std::string out = in; return trimLeft (trimRight (out, t), t); } //////////////////////////////////////////////////////////////////////////////// std::string lowerCase (const std::string& input) { std::string output = input; std::transform (output.begin (), output.end (), output.begin (), tolower); return output; } //////////////////////////////////////////////////////////////////////////////// std::string upperCase (const std::string& input) { std::string output = input; std::transform (output.begin (), output.end (), output.begin (), toupper); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format (char value) { std::stringstream s; s << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// const std::string format (int value) { std::stringstream s; s << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// const std::string formatHex (int value) { std::stringstream s; s.setf (std::ios::hex, std::ios::basefield); s << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// const std::string format (float value, int width, int precision) { std::stringstream s; s.width (width); s.precision (precision); s << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// const std::string format (double value, int width, int precision) { std::stringstream s; s.width (width); s.precision (precision); s << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// const std::string format (double value) { std::stringstream s; s << std::fixed << value; return s.str (); } //////////////////////////////////////////////////////////////////////////////// static void replace_positional ( std::string& fmt, const std::string& from, const std::string& to) { std::string::size_type pos = 0; while ((pos = fmt.find (from, pos)) != std::string::npos) { fmt.replace (pos, from.length (), to); pos += to.length (); } } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, const std::string& arg1) { std::string output = fmt; replace_positional (output, "{1}", arg1); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, int arg1) { std::string output = fmt; replace_positional (output, "{1}", format (arg1)); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, const std::string& arg1, const std::string& arg2) { std::string output = fmt; replace_positional (output, "{1}", arg1); replace_positional (output, "{2}", arg2); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, const std::string& arg1, int arg2) { std::string output = fmt; replace_positional (output, "{1}", arg1); replace_positional (output, "{2}", format (arg2)); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, const std::string& arg1, double arg2) { std::string output = fmt; replace_positional (output, "{1}", arg1); replace_positional (output, "{2}", trim (format (arg2, 6, 3))); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, int arg1, const std::string& arg2) { std::string output = fmt; replace_positional (output, "{1}", format (arg1)); replace_positional (output, "{2}", arg2); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, int arg1, int arg2) { std::string output = fmt; replace_positional (output, "{1}", format (arg1)); replace_positional (output, "{2}", format (arg2)); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, int arg1, double arg2) { std::string output = fmt; replace_positional (output, "{1}", format (arg1)); replace_positional (output, "{2}", trim (format (arg2, 6, 3))); return output; } //////////////////////////////////////////////////////////////////////////////// const std::string format ( const std::string& fmt, const std::string& arg1, const std::string& arg2, const std::string& arg3) { std::string output = fmt; replace_positional (output, "{1}", arg1); replace_positional (output, "{2}", arg2); replace_positional (output, "{3}", arg3); return output; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/Color.h0000644000175000017500000000633412215630160013737 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_COLOR #define INCLUDED_COLOR #include #define FEATURE_COLOR 1 //////////////////////////////////////////////////////////////////////////////// #define _COLOR_INVERSE 0x00400000 // Inverse attribute. #define _COLOR_256 0x00200000 // 256-color mode. #define _COLOR_HASBG 0x00100000 // Has background color (all values taken). #define _COLOR_HASFG 0x00080000 // Has foreground color (all values taken). #define _COLOR_UNDERLINE 0x00040000 // General underline attribute. #define _COLOR_BOLD 0x00020000 // 16-color bold attribute. #define _COLOR_BRIGHT 0x00010000 // 16-color bright background attribute. #define _COLOR_BG 0x0000FF00 // 8-bit background color index. #define _COLOR_FG 0x000000FF // 8-bit foreground color index. class Color { public: enum color_id {nocolor = 0, black, red, green, yellow, blue, magenta, cyan, white}; Color (); Color (const Color&); Color (unsigned int); // 256 | INVERSE | UNDERLINE | BOLD | BRIGHT | (BG << 8) | FG Color (const std::string&); // "red on bright black" Color (color_id); // fg. Color (color_id, color_id); // fg, bg. Color (color_id, color_id, bool, bool, bool); // fg, bg, underline, bold, bright ~Color (); Color& operator= (const Color&); operator std::string () const; operator int () const; void upgrade (); void blend (const Color&); std::string colorize (const std::string&); static std::string colorize (const std::string&, const std::string&); static std::string strip (const std::string&); bool nontrivial () const; private: int find (const std::string&); std::string fg () const; std::string bg () const; private: unsigned int _value; }; #endif //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/CMakeLists.txt0000644000175000017500000000101412215630160015236 0ustar mogaalmogaalcmake_minimum_required(VERSION 2.8) include_directories (${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR} ${CLOG_INCLUDE_DIRS}) add_executable(clog clog.cpp Nibbler.cpp Nibbler.h RX.cpp RX.h Rule.cpp Rule.h Color.cpp Color.h text.cpp text.h) install (TARGETS clog DESTINATION bin) #set (CMAKE_BUILD_TYPE debug) #set (CMAKE_C_FLAGS_DEBUG "-ggdb3") #set (CMAKE_C_FLAGS_RELEASE "-O3") clog-1.1.0/src/Nibbler.cpp0000644000175000017500000007114212215630160014570 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #ifdef NIBBLER_FEATURE_DATE #include #endif #ifdef NIBBLER_FEATURE_REGEX #include #endif #include static const char* _uuid_pattern = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; static const unsigned int _uuid_min_length = 14; //////////////////////////////////////////////////////////////////////////////// Nibbler::Nibbler () : _input ("") , _length (0) , _cursor (0) , _saved (0) { } //////////////////////////////////////////////////////////////////////////////// Nibbler::Nibbler (const std::string& input) : _input (input) , _length (input.length ()) , _cursor (0) { } //////////////////////////////////////////////////////////////////////////////// Nibbler::Nibbler (const Nibbler& other) : _input (other._input) , _length (other._length) , _cursor (other._cursor) { } //////////////////////////////////////////////////////////////////////////////// Nibbler& Nibbler::operator= (const Nibbler& other) { if (this != &other) { _input = other._input; _length = other._length; _cursor = other._cursor; } return *this; } //////////////////////////////////////////////////////////////////////////////// Nibbler::~Nibbler () { } //////////////////////////////////////////////////////////////////////////////// // Extract up until the next c (but not including) or EOS. bool Nibbler::getUntil (char c, std::string& result) { if (_cursor < _length) { std::string::size_type i = _input.find (c, _cursor); if (i != std::string::npos) { result = _input.substr (_cursor, i - _cursor); _cursor = i; } else { result = _input.substr (_cursor); _cursor = _length; } return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUntil (const std::string& terminator, std::string& result) { if (_cursor < _length) { std::string::size_type i = _input.find (terminator, _cursor); if (i != std::string::npos) { result = _input.substr (_cursor, i - _cursor); _cursor = i; } else { result = _input.substr (_cursor); _cursor = _length; } return true; } return false; } //////////////////////////////////////////////////////////////////////////////// #ifdef NIBBLER_FEATURE_REGEX bool Nibbler::getUntilRx (const std::string& regex, std::string& result) { if (_cursor < _length) { RX r (regex, true); std::vector start; std::vector end; if (r.match (start, end, _input.substr (_cursor))) { result = _input.substr (_cursor, start[0]); _cursor += start[0]; } else { result = _input.substr (_cursor); _cursor = _length; } return true; } return false; } #endif //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result) { if (_cursor < _length) { std::string::size_type i = _input.find_first_of (chars, _cursor); if (i != std::string::npos) { result = _input.substr (_cursor, i - _cursor); _cursor = i; } else { result = _input.substr (_cursor); _cursor = _length; } return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUntilWS (std::string& result) { return this->getUntilOneOf (" \t\r\n\f", result); } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUntilEOL (std::string& result) { return getUntil ('\n', result); } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUntilEOS (std::string& result) { if (_cursor < _length) { result = _input.substr (_cursor); _cursor = _length; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getN (const int quantity, std::string& result) { if (_cursor + quantity <= _length) { result = _input.substr (_cursor, quantity); _cursor += quantity; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getQuoted ( char c, std::string& result, bool quote /* = false */) { bool inquote = false; bool inescape = false; char previous = 0; char current = 0; result = ""; if (_cursor >= _length || _input[_cursor] != c) { return false; } for (std::string::size_type i = _cursor; i < _length; ++i) { current = _input[i]; if (current == '\\' && !inescape) { inescape = true; previous = current; continue; } if (current == c && !inescape) { if (quote) result += current; if (!inquote) { inquote = true; } else { _cursor = i + 1; return true; } } else { if (previous) { result += previous; previous = 0; } result += current; inescape = false; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getDigit (int& result) { if (_cursor < _length && isdigit (_input[_cursor])) { result = _input[_cursor++] - '0'; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getDigit6 (int& result) { std::string::size_type i = _cursor; if (i < _length && _length - i >= 6) { if (isdigit (_input[i + 0]) && isdigit (_input[i + 1]) && isdigit (_input[i + 2]) && isdigit (_input[i + 3]) && isdigit (_input[i + 4]) && isdigit (_input[i + 5])) { result = strtoimax (_input.substr (_cursor, 6).c_str (), NULL, 10); _cursor += 6; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getDigit4 (int& result) { std::string::size_type i = _cursor; if (i < _length && _length - i >= 4) { if (isdigit (_input[i + 0]) && isdigit (_input[i + 1]) && isdigit (_input[i + 2]) && isdigit (_input[i + 3])) { result = strtoimax (_input.substr (_cursor, 4).c_str (), NULL, 10); _cursor += 4; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getDigit2 (int& result) { std::string::size_type i = _cursor; if (i < _length && _length - i >= 2) { if (isdigit (_input[i + 0]) && isdigit (_input[i + 1])) { result = strtoimax (_input.substr (_cursor, 2).c_str (), NULL, 10); _cursor += 2; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getInt (int& result) { std::string::size_type i = _cursor; if (i < _length) { if (_input[i] == '-') ++i; else if (_input[i] == '+') ++i; } // TODO Potential for use of find_first_not_of while (i < _length && isdigit (_input[i])) ++i; if (i > _cursor) { result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 10); _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getHex (int& result) { std::string::size_type i = _cursor; if (i < _length) { if (_input[i] == '-') ++i; else if (_input[i] == '+') ++i; } // TODO Potential for use of find_first_not_of while (i < _length && isxdigit (_input[i])) ++i; if (i > _cursor) { result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 16); _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUnsignedInt (int& result) { std::string::size_type i = _cursor; // TODO Potential for use of find_first_not_of while (i < _length && isdigit (_input[i])) ++i; if (i > _cursor) { result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 10); _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // number: // int frac? exp? // // int: // (-|+)? digit+ // // frac: // . digit+ // // exp: // e digit+ // // e: // e|E (+|-)? // bool Nibbler::getNumber (std::string& result) { std::string::size_type i = _cursor; // [+-]? if (i < _length && (_input[i] == '-' || _input[i] == '+')) ++i; // digit+ if (i < _length && isdigit (_input[i])) { ++i; while (i < _length && isdigit (_input[i])) ++i; // ( . digit+ )? if (i < _length && _input[i] == '.') { ++i; while (i < _length && isdigit (_input[i])) ++i; } // ( [eE] [+-]? digit+ )? if (i < _length && (_input[i] == 'e' || _input[i] == 'E')) { ++i; if (i < _length && (_input[i] == '+' || _input[i] == '-')) ++i; if (i < _length && isdigit (_input[i])) { ++i; while (i < _length && isdigit (_input[i])) ++i; result = _input.substr (_cursor, i - _cursor); _cursor = i; return true; } return false; } result = _input.substr (_cursor, i - _cursor); _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getNumber (double &result) { bool isnumber; std::string s; isnumber = getNumber (s); if (isnumber) { result = strtof (s.c_str (), NULL); } return isnumber; } //////////////////////////////////////////////////////////////////////////////// // number: // int frac? exp? // // int: // digit+ // // frac: // . digit+ // // exp: // e digit+ // // e: // e|E (+|-)? // bool Nibbler::getUnsignedNumber (double& result) { std::string::size_type i = _cursor; // digit+ if (i < _length && isdigit (_input[i])) { ++i; while (i < _length && isdigit (_input[i])) ++i; // ( . digit+ )? if (i < _length && _input[i] == '.') { ++i; while (i < _length && isdigit (_input[i])) ++i; } // ( [eE] [+-]? digit+ )? if (i < _length && (_input[i] == 'e' || _input[i] == 'E')) { ++i; if (i < _length && (_input[i] == '+' || _input[i] == '-')) ++i; if (i < _length && isdigit (_input[i])) { ++i; while (i < _length && isdigit (_input[i])) ++i; result = strtof (_input.substr (_cursor, i - _cursor).c_str (), NULL); _cursor = i; return true; } return false; } result = strtof (_input.substr (_cursor, i - _cursor).c_str (), NULL); _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getLiteral (const std::string& literal) { if (_cursor < _length && _input.find (literal, _cursor) == _cursor) { _cursor += literal.length (); return true; } return false; } //////////////////////////////////////////////////////////////////////////////// #ifdef NIBBLER_FEATURE_REGEX bool Nibbler::getRx (const std::string& regex, std::string& result) { if (_cursor < _length) { // Regex may be anchored to the beginning and include capturing parentheses, // otherwise they are added. std::string modified_regex; if (regex.substr (0, 2) != "^(") modified_regex = "^(" + regex + ")"; else modified_regex = regex; RX r (modified_regex, true); std::vector results; if (r.match (results, _input.substr (_cursor))) { result = results[0]; _cursor += result.length (); return true; } } return false; } #endif //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getUUID (std::string& result) { std::string::size_type i = _cursor; if (i < _length && _length - i >= 36) { // 88888888-4444-4444-4444-cccccccccccc if (isxdigit (_input[i + 0]) && isxdigit (_input[i + 1]) && isxdigit (_input[i + 2]) && isxdigit (_input[i + 3]) && isxdigit (_input[i + 4]) && isxdigit (_input[i + 5]) && isxdigit (_input[i + 6]) && isxdigit (_input[i + 7]) && _input[i + 8] == '-' && isxdigit (_input[i + 9]) && isxdigit (_input[i + 10]) && isxdigit (_input[i + 11]) && isxdigit (_input[i + 12]) && _input[i + 13] == '-' && isxdigit (_input[i + 14]) && isxdigit (_input[i + 15]) && isxdigit (_input[i + 16]) && isxdigit (_input[i + 17]) && _input[i + 18] == '-' && isxdigit (_input[i + 19]) && isxdigit (_input[i + 20]) && isxdigit (_input[i + 21]) && isxdigit (_input[i + 22]) && _input[i + 23] == '-' && isxdigit (_input[i + 24]) && isxdigit (_input[i + 25]) && isxdigit (_input[i + 26]) && isxdigit (_input[i + 27]) && isxdigit (_input[i + 28]) && isxdigit (_input[i + 29]) && isxdigit (_input[i + 30]) && isxdigit (_input[i + 31]) && isxdigit (_input[i + 32]) && isxdigit (_input[i + 33]) && isxdigit (_input[i + 34]) && isxdigit (_input[i + 35])) { result = _input.substr (_cursor, 36); _cursor = i + 36; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::getPartialUUID (std::string& result) { std::string::size_type i; for (i = 0; i < 36 && i < (_length - _cursor); i++) { if (_uuid_pattern[i] == 'x' && !isxdigit (_input[_cursor + i])) break; else if (_uuid_pattern[i] == '-' && _input[_cursor + i] != '-') break; } // If the partial match found is long enough, consider it a match. if (i >= _uuid_min_length) { // Fail if there is another hex digit. if (_cursor + i < _length && isxdigit (_input[_cursor + i])) return false; result = _input.substr (_cursor, i); _cursor += i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // 19980119T070000Z = YYYYMMDDThhmmssZ bool Nibbler::getDateISO (time_t& t) { std::string::size_type i = _cursor; if (i < _length && _length - i >= 16) { if (isdigit (_input[i + 0]) && isdigit (_input[i + 1]) && isdigit (_input[i + 2]) && isdigit (_input[i + 3]) && isdigit (_input[i + 4]) && isdigit (_input[i + 5]) && isdigit (_input[i + 6]) && isdigit (_input[i + 7]) && _input[i + 8] == 'T' && isdigit (_input[i + 9]) && isdigit (_input[i + 10]) && isdigit (_input[i + 11]) && isdigit (_input[i + 12]) && isdigit (_input[i + 13]) && isdigit (_input[i + 14]) && _input[i + 15] == 'Z') { _cursor += 16; int year = (_input[i + 0] - '0') * 1000 + (_input[i + 1] - '0') * 100 + (_input[i + 2] - '0') * 10 + (_input[i + 3] - '0'); int month = (_input[i + 4] - '0') * 10 + (_input[i + 5] - '0'); int day = (_input[i + 6] - '0') * 10 + (_input[i + 7] - '0'); int hour = (_input[i + 9] - '0') * 10 + (_input[i + 10] - '0'); int minute = (_input[i + 11] - '0') * 10 + (_input[i + 12] - '0'); int second = (_input[i + 13] - '0') * 10 + (_input[i + 14] - '0'); // Convert to epoch. struct tm tms = {0}; tms.tm_isdst = -1; // Requests that mktime determine summer time effect. tms.tm_mon = month - 1; tms.tm_mday = day; tms.tm_year = year - 1900; tms.tm_hour = hour; tms.tm_min = minute; tms.tm_sec = second; #ifdef HAVE_TM_GMTOFF tms.tm_gmtoff = 0; #endif t = timegm (&tms); return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// // Parse the longest integer using the next 'limit' characters of 'result' // following position 'i' (when strict is true, the number of digits must be // equal to limit). bool Nibbler::parseDigits(std::string::size_type& i, int& result, unsigned int limit, bool strict /* = true */) { // If the result has already been set if (result != -1) return false; for (unsigned int f = limit; f > 0; --f) { // Check that the nibbler has enough unparsed characters if (i + f <= _length) { // Check that 'f' of them are digits unsigned int g; for (g = 0; g < f; g++) if (! isdigit (_input[i + g])) break; // Parse the integer when it is the case if (g == f) { if (f == 1) result = _input[i] - '0'; else result = atoi (_input.substr (i, f).c_str ()); // Update the global cursor before returning i += f; return true; } } // Do not try smaller limits if the option is strict on the size if (strict) break; } return false; } //////////////////////////////////////////////////////////////////////////////// #ifdef NIBBLER_FEATURE_DATE bool Nibbler::getDate (const std::string& format, time_t& t) { std::string::size_type i = _cursor; int month = -1; // So we can check later. int day = -1; int year = -1; int hour = -1; int minute = -1; int second = -1; // For parsing, unused. int wday = -1; int week = -1; for (unsigned int f = 0; f < format.length (); ++f) { switch (format[f]) { case 'm': case 'M': if (! parseDigits(i, month, 2, format[f] == 'M')) return false; break; case 'd': case 'D': if (! parseDigits(i, day, 2, format[f] == 'D')) return false; break; case 'y': case 'Y': if (! parseDigits(i, year, format[f] == 'y' ? 2 : 4)) return false; if (format[f] == 'y') year += 2000; break; case 'h': case 'H': if (! parseDigits(i, hour, 2, format[f] == 'H')) return false; break; case 'n': case 'N': if (! parseDigits(i, minute, 2, format[f] == 'N')) return false; break; case 's': case 'S': if (! parseDigits(i, second, 2, format[f] == 'S')) return false; break; // Merely parse, not extract. case 'v': case 'V': if (! parseDigits(i, week, 2, format[f] == 'V')) return false; break; // Merely parse, not extract. case 'a': case 'A': if (i + 3 <= _length && ! isdigit (_input[i + 0]) && ! isdigit (_input[i + 1]) && ! isdigit (_input[i + 2])) { wday = Date::dayOfWeek (_input.substr (i, 3).c_str ()); i += (format[f] == 'a') ? 3 : Date::dayName (wday).size (); } else return false; break; case 'b': case 'B': if (i + 3 <= _length && ! isdigit (_input[i + 0]) && ! isdigit (_input[i + 1]) && ! isdigit (_input[i + 2])) { if (month != -1) return false; month = Date::monthOfYear (_input.substr (i, 3).c_str()); i += (format[f] == 'b') ? 3 : Date::monthName (month).size (); } else return false; break; default: if (i + 1 <= _length && _input[i] == format[f]) ++i; else return false; break; } } // By default, the most global date variables that are undefined are put to // the current date (for instance, the year to the current year for formats // that lack Y/y). If even 'second' is undefined, then the date is parsed as // now. if (year == -1) { Date now = Date (); year = now.year (); if (month == -1) { month = now.month (); if (day == -1) { day = now.day (); if (hour == -1) { hour = now.hour (); if (minute == -1) { minute = now.minute (); if (second == -1) second = now.second (); } } } } } // Put all remaining undefined date variables to their default values (0 or // 1). month = (month == -1) ? 1 : month; day = (day == -1) ? 1 : day; hour = (hour == -1) ? 0 : hour; minute = (minute == -1) ? 0 : minute; second = (second == -1) ? 0 : second; // Check that values are correct if (! Date::valid (month, day, year, hour, minute, second)) return false; // Convert to epoch. struct tm tms = {0}; tms.tm_isdst = -1; // Requests that mktime determine summer time effect. tms.tm_mon = month - 1; tms.tm_mday = day; tms.tm_year = year - 1900; tms.tm_hour = hour; tms.tm_min = minute; tms.tm_sec = second; t = mktime (&tms); _cursor = i; return true; } #endif //////////////////////////////////////////////////////////////////////////////// // Assumes that the options are sorted by decreasing length, so that if the // options contain 'fourteen' and 'four', the stream is first matched against // the longer entry. bool Nibbler::getOneOf ( const std::vector & options, std::string& found) { std::vector ::const_iterator option; for (option = options.begin (); option != options.end (); ++option) { if (getLiteral (*option)) { found = *option; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// // A name is a string of alpha-numeric characters. bool Nibbler::getName (std::string& result) { std::string::size_type i = _cursor; if (i < _length) { if (! isdigit (_input[i]) && ! ispunct (_input[i]) && ! isspace (_input[i])) { ++i; while (i < _length && ! ispunct (_input[i]) && ! isspace (_input[i])) { ++i; } } if (i > _cursor) { result = _input.substr (_cursor, i - _cursor); _cursor = i; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// // A word is a contiguous string of non-space, non-digit, non-punct characters. bool Nibbler::getWord (std::string& result) { std::string::size_type i = _cursor; if (i < _length) { while (!isdigit (_input[i]) && !isPunctuation (_input[i]) && !isspace (_input[i])) { ++i; } if (i > _cursor) { result = _input.substr (_cursor, i - _cursor); _cursor = i; return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::skipN (const int quantity /* = 1 */) { if (_cursor < _length && _cursor <= _length - quantity) { _cursor += quantity; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::skip (char c) { if (_cursor < _length && _input[_cursor] == c) { ++_cursor; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::skipAll (char c) { if (_cursor < _length) { std::string::size_type i = _input.find_first_not_of (c, _cursor); if (i == _cursor) return false; if (i == std::string::npos) _cursor = _length; // Yes, off the end. else _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::skipWS () { return this->skipAllOneOf (" \t\n\r\f"); } //////////////////////////////////////////////////////////////////////////////// #ifdef NIBBLER_FEATURE_REGEX bool Nibbler::skipRx (const std::string& regex) { if (_cursor < _length) { // Regex may be anchored to the beginning and include capturing parentheses, // otherwise they are added. std::string modified_regex; if (regex.substr (0, 2) != "^(") modified_regex = "^(" + regex + ")"; else modified_regex = regex; RX r (modified_regex, true); std::vector results; if (r.match (results, _input.substr (_cursor))) { _cursor += results[0].length (); return true; } } return false; } #endif //////////////////////////////////////////////////////////////////////////////// void Nibbler::getRemainder (std::string& result) { if (_cursor < _length) result = _input.substr (_cursor); } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::skipAllOneOf (const std::string& chars) { if (_cursor < _length) { std::string::size_type i = _input.find_first_not_of (chars, _cursor); if (i == _cursor) return false; if (i == std::string::npos) _cursor = _length; // Yes, off the end. else _cursor = i; return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // Peeks ahead - does not move cursor. char Nibbler::next () { if (_cursor < _length) return _input[_cursor]; return '\0'; } //////////////////////////////////////////////////////////////////////////////// std::string::size_type Nibbler::cursor () { return _cursor; } //////////////////////////////////////////////////////////////////////////////// // Peeks ahead - does not move cursor. std::string Nibbler::next (const int quantity) { if ( _cursor < _length && (unsigned) quantity <= _length && _cursor <= _length - quantity) return _input.substr (_cursor, quantity); return ""; } //////////////////////////////////////////////////////////////////////////////// std::string::size_type Nibbler::save () { return _saved = _cursor; } //////////////////////////////////////////////////////////////////////////////// std::string::size_type Nibbler::restore () { return _cursor = _saved; } //////////////////////////////////////////////////////////////////////////////// const std::string& Nibbler::str () const { return _input; } //////////////////////////////////////////////////////////////////////////////// bool Nibbler::depleted () { if (_cursor >= _length) return true; return false; } //////////////////////////////////////////////////////////////////////////////// // Override of ispunct, that considers #, $ and @ not to be punctuation. // // ispunct: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ // Punctuation: ! " % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ ` { | } ~ // delta: # $ @ // bool Nibbler::isPunctuation (char c) { if (c == '@' || c == '#' || c == '$') return false; return ispunct (c); } //////////////////////////////////////////////////////////////////////////////// std::string Nibbler::dump () { return std::string ("Nibbler ‹") + _input.substr (_cursor) + "›"; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/Color.cpp0000644000175000017500000004003112215630160014262 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "Color.h" #include "text.h" //////////////////////////////////////////////////////////////////////////////// static struct { Color::color_id id; std::string english_name; int index; // offset red=3 (therefore fg=33, bg=43) } allColors[] = { // Color.h enum English Index { Color::nocolor, "none", 0}, { Color::black, "black", 1}, // fg 29+0 bg 39+0 { Color::red, "red", 2}, { Color::green, "green", 3}, { Color::yellow, "yellow", 4}, { Color::blue, "blue", 5}, { Color::magenta, "magenta", 6}, { Color::cyan, "cyan", 7}, { Color::white, "white", 8}, }; #define NUM_COLORS (sizeof (allColors) / sizeof (allColors[0])) //////////////////////////////////////////////////////////////////////////////// Color::Color () : _value (0) { } //////////////////////////////////////////////////////////////////////////////// Color::Color (const Color& other) { _value = other._value; } //////////////////////////////////////////////////////////////////////////////// Color::Color (unsigned int c) : _value (0) { #ifdef FEATURE_COLOR if (!(c & _COLOR_HASFG)) _value &= ~_COLOR_FG; if (!(c & _COLOR_HASBG)) _value &= ~_COLOR_BG; _value = c & (_COLOR_256 | _COLOR_HASBG | _COLOR_HASFG |_COLOR_UNDERLINE | _COLOR_INVERSE | _COLOR_BOLD | _COLOR_BRIGHT | _COLOR_BG | _COLOR_FG); #endif } //////////////////////////////////////////////////////////////////////////////// // Supports the following constructs: // [bright] [color] [on color] [bright] [underline] // // Where [color] is one of: // black // red // ... // grayN 0 <= N <= 23 fg 38;5;232 + N bg 48;5;232 + N // greyN 0 <= N <= 23 fg 38;5;232 + N bg 48;5;232 + N // colorN 0 <= N <= 255 fg 38;5;N bg 48;5;N // rgbRGB 0 <= R,G,B <= 5 fg 38;5;16 + R*36 + G*6 + B bg 48;5;16 + R*36 + G*6 + B Color::Color (const std::string& spec) : _value (0) { #ifdef FEATURE_COLOR // By converting underscores to spaces, we inherently support the old "on_red" // style of specifying background colors. We consider underscores to be // deprecated. std::string modifiable_spec = spec; std::replace (modifiable_spec.begin (), modifiable_spec.end (), '_', ' '); // Split spec into words. std::vector words; split (words, modifiable_spec, ' '); // Construct the color as two separate colors, then blend them later. This // make it possible to declare a color such as "color1 on black", and have // the upgrade work properly. unsigned int fg_value = 0; unsigned int bg_value = 0; bool bg = false; int index; std::string word; std::vector ::iterator it; for (it = words.begin (); it != words.end (); ++it) { word = lowerCase (trim (*it)); if (word == "bold") fg_value |= _COLOR_BOLD; else if (word == "bright") bg_value |= _COLOR_BRIGHT; else if (word == "underline") fg_value |= _COLOR_UNDERLINE; else if (word == "inverse") fg_value |= _COLOR_INVERSE; else if (word == "on") bg = true; // X where X is one of black, red, blue ... else if ((index = find (word)) != -1) { if (index) { if (bg) { bg_value |= _COLOR_HASBG; bg_value |= index << 8; } else { fg_value |= _COLOR_HASFG; fg_value |= index; } } } // greyN/grayN, where 0 <= N <= 23. else if (word.substr (0, 4) == "grey" || word.substr (0, 4) == "gray") { index = atoi (word.substr (4).c_str ()); if (index < 0 || index > 23) throw format ("ERROR: The color '{1}' is not recognized.", *it); if (bg) { bg_value |= _COLOR_HASBG; bg_value |= (index + 232) << 8; bg_value |= _COLOR_256; } else { fg_value |= _COLOR_HASFG; fg_value |= index + 232; fg_value |= _COLOR_256; } } // rgbRGB, where 0 <= R,G,B <= 5. else if (word.substr (0, 3) == "rgb") { index = atoi (word.substr (3).c_str ()); if (word.length () != 6 || index < 0 || index > 555) throw format ("ERROR: The color '{1}' is not recognized.", *it); int r = atoi (word.substr (3, 1).c_str ()); int g = atoi (word.substr (4, 1).c_str ()); int b = atoi (word.substr (5, 1).c_str ()); if (r < 0 || r > 5 || g < 0 || g > 5 || b < 0 || b > 5) throw format ("ERROR: The color '{1}' is not recognized.", *it); index = 16 + r*36 + g*6 + b; if (bg) { bg_value |= _COLOR_HASBG; bg_value |= index << 8; bg_value |= _COLOR_256; } else { fg_value |= _COLOR_HASFG; fg_value |= index; fg_value |= _COLOR_256; } } // colorN, where 0 <= N <= 255. else if (word.substr (0, 5) == "color") { index = atoi (word.substr (5).c_str ()); if (index < 0 || index > 255) throw format ("ERROR: The color '{1}' is not recognized.", *it); upgrade (); if (bg) { bg_value |= _COLOR_HASBG; bg_value |= index << 8; bg_value |= _COLOR_256; } else { fg_value |= _COLOR_HASFG; fg_value |= index; fg_value |= _COLOR_256; } } else if (word != "") throw format ("ERROR: The color '{1}' is not recognized.", *it); } // Now combine the fg and bg into a single color. _value = fg_value; blend (Color (bg_value)); #endif } //////////////////////////////////////////////////////////////////////////////// Color::Color (color_id fg) : _value (0) { #ifdef FEATURE_COLOR if (fg != Color::nocolor) { _value |= _COLOR_HASFG; _value |= fg; } #endif } //////////////////////////////////////////////////////////////////////////////// Color::Color (color_id fg, color_id bg) : _value (0) { #ifdef FEATURE_COLOR if (bg != Color::nocolor) { _value |= _COLOR_HASBG; _value |= (bg << 8); } if (fg != Color::nocolor) { _value |= _COLOR_HASFG; _value |= fg; } #endif } //////////////////////////////////////////////////////////////////////////////// Color::Color (color_id fg, color_id bg, bool underline, bool bold, bool bright) : _value (0) { #ifdef FEATURE_COLOR _value |= ((underline ? 1 : 0) << 18) | ((bold ? 1 : 0) << 17) | ((bright ? 1 : 0) << 16); if (bg != Color::nocolor) { _value |= _COLOR_HASBG; _value |= (bg << 8); } if (fg != Color::nocolor) { _value |= _COLOR_HASFG; _value |= fg; } #endif } //////////////////////////////////////////////////////////////////////////////// Color::~Color () { } //////////////////////////////////////////////////////////////////////////////// Color& Color::operator= (const Color& other) { if (this != &other) _value = other._value; return *this; } //////////////////////////////////////////////////////////////////////////////// Color::operator std::string () const { std::string description; #ifdef FEATURE_COLOR if (_value & _COLOR_BOLD) description += "bold"; if (_value & _COLOR_UNDERLINE) description += std::string (description.length () ? " " : "") + "underline"; if (_value & _COLOR_INVERSE) description += std::string (description.length () ? " " : "") + "inverse"; if (_value & _COLOR_HASFG) description += std::string (description.length () ? " " : "") + fg (); if (_value & _COLOR_HASBG) { description += std::string (description.length () ? " " : "") + "on"; if (_value & _COLOR_BRIGHT) description += std::string (description.length () ? " " : "") + "bright"; description += " " + bg (); } #endif return description; } //////////////////////////////////////////////////////////////////////////////// Color::operator int () const { return (int) _value; } //////////////////////////////////////////////////////////////////////////////// // If 'other' has styles that are compatible, merge them into this. Colors in // other take precedence. void Color::blend (const Color& other) { #ifdef FEATURE_COLOR if (!other.nontrivial ()) return; Color c (other); _value |= (c._value & _COLOR_UNDERLINE); // Always inherit underline. _value |= (c._value & _COLOR_INVERSE); // Always inherit inverse. // 16 <-- 16. if (!(_value & _COLOR_256) && !(c._value & _COLOR_256)) { _value |= (c._value & _COLOR_BOLD); // Inherit bold. _value |= (c._value & _COLOR_BRIGHT); // Inherit bright. if (c._value & _COLOR_HASFG) { _value |= _COLOR_HASFG; // There is now a color. _value &= ~_COLOR_FG; // Remove previous color. _value |= (c._value & _COLOR_FG); // Apply other color. } if (c._value & _COLOR_HASBG) { _value |= _COLOR_HASBG; // There is now a color. _value &= ~_COLOR_BG; // Remove previous color. _value |= (c._value & _COLOR_BG); // Apply other color. } return; } else { // Upgrade either color, if necessary. if (!(_value & _COLOR_256)) upgrade (); if (!(c._value & _COLOR_256)) c.upgrade (); // 256 <-- 256. if (c._value & _COLOR_HASFG) { _value |= _COLOR_HASFG; // There is now a color. _value &= ~_COLOR_FG; // Remove previous color. _value |= (c._value & _COLOR_FG); // Apply other color. } if (c._value & _COLOR_HASBG) { _value |= _COLOR_HASBG; // There is now a color. _value &= ~_COLOR_BG; // Remove previous color. _value |= (c._value & _COLOR_BG); // Apply other color. } } #endif } //////////////////////////////////////////////////////////////////////////////// void Color::upgrade () { #ifdef FEATURE_COLOR if (!(_value & _COLOR_256)) { if (_value & _COLOR_HASFG) { bool bold = _value & _COLOR_BOLD; unsigned int fg = _value & _COLOR_FG; _value &= ~_COLOR_FG; _value &= ~_COLOR_BOLD; _value |= (bold ? fg + 7 : fg - 1); } if (_value & _COLOR_HASBG) { bool bright = _value & _COLOR_BRIGHT; unsigned int bg = (_value & _COLOR_BG) >> 8; _value &= ~_COLOR_BG; _value &= ~_COLOR_BRIGHT; _value |= (bright ? bg + 7 : bg - 1) << 8; } _value |= _COLOR_256; } #endif } //////////////////////////////////////////////////////////////////////////////// // Sample color codes: // red \033[31m // bold red \033[91m // underline red \033[4;31m // bold underline red \033[1;4;31m // // on red \033[41m // on bright red \033[101m // // 256 fg \033[38;5;Nm // 256 bg \033[48;5;Nm std::string Color::colorize (const std::string& input) { #ifdef FEATURE_COLOR if (!nontrivial ()) return input; int count = 0; std::stringstream result; // 256 color if (_value & _COLOR_256) { bool needTerminator = false; if (_value & _COLOR_UNDERLINE) { result << "\033[4m"; needTerminator = true; } if (_value & _COLOR_INVERSE) { result << "\033[7m"; needTerminator = true; } if (_value & _COLOR_HASFG) { result << "\033[38;5;" << (_value & _COLOR_FG) << "m"; needTerminator = true; } if (_value & _COLOR_HASBG) { result << "\033[48;5;" << ((_value & _COLOR_BG) >> 8) << "m"; needTerminator = true; } result << input; if (needTerminator) result << "\033[0m"; return result.str (); } // 16 color else { result << "\033["; if (_value & _COLOR_BOLD) { if (count++) result << ";"; result << "1"; } if (_value & _COLOR_UNDERLINE) { if (count++) result << ";"; result << "4"; } if (_value & _COLOR_INVERSE) { if (count++) result << ";"; result << "7"; } if (_value & _COLOR_HASFG) { if (count++) result << ";"; result << (29 + (_value & _COLOR_FG)); } if (_value & _COLOR_HASBG) { if (count++) result << ";"; result << ((_value & _COLOR_BRIGHT ? 99 : 39) + ((_value & _COLOR_BG) >> 8)); } result << "m" << input << "\033[0m"; return result.str (); } #endif return input; } //////////////////////////////////////////////////////////////////////////////// // Remove color codes from a string. std::string Color::strip (const std::string& input) { #ifdef FEATURE_COLOR int length = input.length (); bool inside = false; std::string output; for (int i = 0; i < length; ++i) { if (inside) { if (input[i] == 'm') inside = false; } else { if (input[i] == 033) inside = true; else output += input[i]; } } return output; #else return input; #endif } //////////////////////////////////////////////////////////////////////////////// std::string Color::colorize (const std::string& input, const std::string& spec) { #ifdef FEATURE_COLOR Color c (spec); return c.colorize (input); #else return input; #endif } //////////////////////////////////////////////////////////////////////////////// bool Color::nontrivial () const { return _value != 0 ? true : false; } //////////////////////////////////////////////////////////////////////////////// int Color::find (const std::string& input) { for (unsigned int i = 0; i < NUM_COLORS; ++i) if (allColors[i].english_name == input) return (int) i; return -1; } //////////////////////////////////////////////////////////////////////////////// std::string Color::fg () const { #ifdef FEATURE_COLOR int index = _value & _COLOR_FG; if (_value & _COLOR_256) { if (_value & _COLOR_HASFG) { std::stringstream s; s << "color" << (_value & _COLOR_FG); return s.str (); } } else { for (unsigned int i = 0; i < NUM_COLORS; ++i) if (allColors[i].index == index) return allColors[i].english_name; } #endif return ""; } //////////////////////////////////////////////////////////////////////////////// std::string Color::bg () const { #ifdef FEATURE_COLOR int index = (_value & _COLOR_BG) >> 8; if (_value & _COLOR_256) { if (_value & _COLOR_HASBG) { std::stringstream s; s << "color" << ((_value & _COLOR_BG) >> 8); return s.str (); } } else { for (unsigned int i = 0; i < NUM_COLORS; ++i) if (allColors[i].index == index) return allColors[i].english_name; } #endif return ""; } //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/src/Rule.h0000644000175000017500000000353312215630160013566 0ustar mogaalmogaal//////////////////////////////////////////////////////////////////////////////// // clog - colorized log tail // // Copyright 2010-2013, Paul Beckingham, Federico Hernandez. // All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #ifndef INCLUDED_RULE #define INCLUDED_RULE #include #include #include class Rule { public: Rule (const std::string&); Rule (const Rule&); virtual ~Rule (); Rule& operator= (const Rule&); bool apply (const std::string&, std::string&); public: std::string section; Color color; std::string context; RX rx; std::string fragment; }; #endif //////////////////////////////////////////////////////////////////////////////// clog-1.1.0/CMakeLists.txt0000644000175000017500000000427512215630160014463 0ustar mogaalmogaalcmake_minimum_required (VERSION 2.8) set (HAVE_CMAKE true) project (clog) set (PROJECT_VERSION "1.1.0") SET (CLOG_MAN3DIR share/man/man3 CACHE STRING "Installation directory for man pages, section 3") SET (CLOG_DOCDIR share/doc/clog CACHE STRING "Installation directory for doc files") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set (LINUX true) elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set (DARWIN true) elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set (FREEBSD true) elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") set (SOLARIS true) else (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set (UNKNOWN true) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") message ("-- Looking for SHA1 references") if (EXISTS ${CMAKE_SOURCE_DIR}/.git/index) set (HAVE_COMMIT true) execute_process (COMMAND git log -1 --pretty=format:%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE COMMIT) configure_file ( ${CMAKE_SOURCE_DIR}/commit.h.in ${CMAKE_SOURCE_DIR}/commit.h) message ("-- Found SHA1 reference: ${COMMIT}") endif (EXISTS ${CMAKE_SOURCE_DIR}/.git/index) set (PACKAGE "${PROJECT_NAME}") set (VERSION "${PROJECT_VERSION}") set (PACKAGE_BUGREPORT "support@yootabory.com") set (PACKAGE_NAME "${PACKAGE}") set (PACKAGE_TARNAME "${PACKAGE}") set (PACKAGE_VERSION "${VERSION}") set (PACKAGE_STRING "${PACKAGE} ${VERSION}") message ("-- Configuring cmake.h") configure_file ( ${CMAKE_SOURCE_DIR}/cmake.h.in ${CMAKE_SOURCE_DIR}/cmake.h) add_subdirectory (src) add_subdirectory (doc) if (EXISTS test) add_subdirectory (test EXCLUDE_FROM_ALL) endif (EXISTS test) set (doc_FILES NEWS ChangeLog README INSTALL AUTHORS COPYING) foreach (doc_FILE ${doc_FILES}) install (FILES ${doc_FILE} DESTINATION ${CLOG_DOCDIR}) endforeach (doc_FILE) # --- set (CPACK_SOURCE_GENERATOR "TGZ") set (CPACK_SOURCE_PACKAGE_FILE_NAME ${PACKAGE_NAME}-${PACKAGE_VERSION}) set (CPACK_SOURCE_IGNORE_FILES "CMakeCache" "CMakeFiles" "CPackConfig" "CPackSourceConfig" "_CPack_Packages" "cmake_install" "install_manifest" "Makefile$" "test" "/\\.gitignore" "/\\.git/" "swp$") include (CPack) clog-1.1.0/ChangeLog0000644000175000017500000000122312215630160013463 0ustar mogaalmogaal------ current release --------------------------- 1.1.0 (2013-09-10) 3feae394c0407954e7eb345ffdcc29ae09e23ba6 + Supports action 'blank' that adds a preceding and following blank line to a match. ------ old releases ------------------------------ 1.0.0 (2012-08-05) + Supports regular expressions and text strings. + Supports multiple rulesets in different sections of ~/.clogrc. + Supports adding date- or time-stamps to each line. + Supports colorizing lines or patterns. + Supports suppression of lines. + Has clog.1 man page. + Uses cmake build system. Project started September 22, 2010. ------ start ----------------------------------- clog-1.1.0/commit.h.in0000644000175000017500000000015112215630160013756 0ustar mogaalmogaal/* commit.h.in. Creates commit.h during a cmake run */ /* git information */ #define COMMIT "${COMMIT}" clog-1.1.0/INSTALL0000644000175000017500000000433112215630160012745 0ustar mogaalmogaalInstallation Instructions ------------------------- Please follow the instructions below to build clog with cmake. Pre-requisites -------------- You will need the 'cmake' build system installed in order to build clog from source. More information on cmake can be obtained at http://cmake.org Basic Installation ------------------ Briefly, these shell commands will unpack, build and install clog: $ tar xzf clog-X.Y.Z.tar.gz [1] $ cd clog-X.Y.Z [2] $ cmake . [3] $ make [4] $ make test [5] $ sudo make install [6] $ cd .. ; rm -r clog-X.Y.Z [7] These commands are explained below: 1. Unpacks the source tarball. This creates the directory clog-X.Y.Z, containing all the code. 2. Change directory to the root of the distribution. 3. Invokes cmake to scan for dependencies and machine-specific details, then generate the makefiles. This may take a minute. 4. Builds clog. This may take a minute. 5. Optional step that runs the unit tests. On completion, will report the number of passing and failing tests. There should be zero failing tests. If you see failing tests, please report this. 6. Installs the program, documentation and other data files. 7. Removes the temporary directory. Uninstallation -------------- To uninstall clog, you need the Makefiles, so if you deleted them in step 7 above, they must first be regenerated by following steps [1], [2] and [3]. Then simply run: $ sudo make uninstall TODO TODO TODO -- cmake doesn't include uninstall Clog Build Notes ---------------- Clog has dependencies that are detected by cmake in almost all cases, but there are situations and operating systems that mean you will need to offer a little help. If clog will not build on your system, first take a look at the Operating System notes below. If this doesn't help, then go to the Troubleshooting section, which includes instructions on how to contact us for help. Operating System Notes ---------------------- ... Troubleshooting --------------- ... --- clog-1.1.0/cmake.h.in0000644000175000017500000000113412215630160013550 0ustar mogaalmogaal/* cmake.h.in. Creates cmake.h during a build */ /* Package information */ #define PACKAGE "${PACKAGE}" #define VERSION "${VERSION}" #define PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" #define PACKAGE_NAME "${PACKAGE_NAME}" #define PACKAGE_TARNAME "${PACKAGE_TARNAME}" #define PACKAGE_VERSION "${PACKAGE_VERSION}" #define PACKAGE_STRING "${PACKAGE_STRING}" /* git information */ #cmakedefine HAVE_COMMIT /* Compiling platform */ #cmakedefine LINUX #cmakedefine DARWIN #cmakedefine CYGWIN #cmakedefine FREEBSD #cmakedefine OPENBSD #cmakedefine HAIKU #cmakedefine SOLARIS #cmakedefine UNKNOWN