From f8010dc6f95b967ffc6b653b33300e4b4d850c14 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 31 Jul 2017 17:26:18 -0700 Subject: txr-011 2009-09-25 --- ChangeLog | 228 +++++ LICENSE | 22 + Makefile | 75 ++ extract.h | 37 + extract.l | 678 +++++++++++++ extract.y | 1620 +++++++++++++++++++++++++++++++ gc.c | 368 +++++++ gc.h | 36 + lib.c | 1609 +++++++++++++++++++++++++++++++ lib.h | 331 +++++++ regex.c | 631 ++++++++++++ regex.h | 107 +++ tests/001/data | 87 ++ tests/001/query-1.expected | 688 ++++++++++++++ tests/001/query-1.txr | 7 + tests/001/query-2.expected | 696 ++++++++++++++ tests/001/query-2.txr | 7 + tests/001/query-3.expected | 87 ++ tests/001/query-3.txr | 21 + tests/002/etc/passwd | 32 + tests/002/proc/1/status | 31 + tests/002/proc/1/task/1/stat | 1 + tests/002/proc/103/status | 20 + tests/002/proc/103/task/103/stat | 1 + tests/002/proc/1068/status | 31 + tests/002/proc/1068/task/1068/stat | 1 + tests/002/proc/1235/status | 20 + tests/002/proc/1235/task/1235/stat | 1 + tests/002/proc/1236/status | 20 + tests/002/proc/1236/task/1236/stat | 1 + tests/002/proc/15812/status | 31 + tests/002/proc/15812/task/15812/stat | 1 + tests/002/proc/16/status | 20 + tests/002/proc/16/task/16/stat | 1 + tests/002/proc/1620/status | 31 + tests/002/proc/1620/task/1620/stat | 1 + tests/002/proc/1624/status | 31 + tests/002/proc/1624/task/1624/stat | 1 + tests/002/proc/16248/status | 31 + tests/002/proc/16248/task/16248/stat | 1 + tests/002/proc/16249/status | 31 + tests/002/proc/16249/task/16249/stat | 1 + tests/002/proc/1645/status | 31 + tests/002/proc/1645/task/1645/stat | 1 + tests/002/proc/1665/status | 31 + tests/002/proc/1665/task/1665/stat | 1 + tests/002/proc/1698/status | 31 + tests/002/proc/1698/task/1698/stat | 1 + tests/002/proc/17/status | 20 + tests/002/proc/17/task/17/stat | 1 + tests/002/proc/175/status | 20 + tests/002/proc/175/task/175/stat | 1 + tests/002/proc/1766/status | 31 + tests/002/proc/1766/task/1766/stat | 1 + tests/002/proc/1790/status | 20 + tests/002/proc/1790/task/1790/stat | 1 + tests/002/proc/1791/status | 20 + tests/002/proc/1791/task/1791/stat | 1 + tests/002/proc/1821/status | 31 + tests/002/proc/1821/task/1821/stat | 1 + tests/002/proc/1821/task/1822/stat | 1 + tests/002/proc/1821/task/1826/stat | 1 + tests/002/proc/1839/status | 31 + tests/002/proc/1839/task/1839/stat | 1 + tests/002/proc/1851/status | 31 + tests/002/proc/1851/task/1851/stat | 1 + tests/002/proc/186/status | 20 + tests/002/proc/186/task/186/stat | 1 + tests/002/proc/1887/status | 31 + tests/002/proc/1887/task/1887/stat | 1 + tests/002/proc/1902/status | 31 + tests/002/proc/1902/task/1902/stat | 1 + tests/002/proc/1921/status | 31 + tests/002/proc/1921/task/1921/stat | 1 + tests/002/proc/1925/status | 20 + tests/002/proc/1925/task/1925/stat | 1 + tests/002/proc/1926/status | 20 + tests/002/proc/1926/task/1926/stat | 1 + tests/002/proc/1927/status | 20 + tests/002/proc/1927/task/1927/stat | 1 + tests/002/proc/1928/status | 20 + tests/002/proc/1928/task/1928/stat | 1 + tests/002/proc/1929/status | 20 + tests/002/proc/1929/task/1929/stat | 1 + tests/002/proc/1930/status | 20 + tests/002/proc/1930/task/1930/stat | 1 + tests/002/proc/1931/status | 20 + tests/002/proc/1931/task/1931/stat | 1 + tests/002/proc/1932/status | 20 + tests/002/proc/1932/task/1932/stat | 1 + tests/002/proc/1936/status | 31 + tests/002/proc/1936/task/1936/stat | 1 + tests/002/proc/1963/status | 31 + tests/002/proc/1963/task/1963/stat | 1 + tests/002/proc/1989/status | 31 + tests/002/proc/1989/task/1989/stat | 1 + tests/002/proc/2/status | 20 + tests/002/proc/2/task/2/stat | 1 + tests/002/proc/2008/status | 31 + tests/002/proc/2008/task/2008/stat | 1 + tests/002/proc/2027/status | 31 + tests/002/proc/2027/task/2027/stat | 1 + tests/002/proc/2027/task/2032/stat | 1 + tests/002/proc/2041/status | 31 + tests/002/proc/2041/task/2041/stat | 1 + tests/002/proc/2052/status | 31 + tests/002/proc/2052/task/2052/stat | 1 + tests/002/proc/2062/status | 31 + tests/002/proc/2062/task/2062/stat | 1 + tests/002/proc/2124/status | 31 + tests/002/proc/2124/task/2124/stat | 1 + tests/002/proc/2184/status | 31 + tests/002/proc/2184/task/2184/stat | 1 + tests/002/proc/2354/status | 31 + tests/002/proc/2354/task/2354/stat | 1 + tests/002/proc/2551/status | 31 + tests/002/proc/2551/task/2551/stat | 1 + tests/002/proc/2579/status | 31 + tests/002/proc/2579/task/2579/stat | 1 + tests/002/proc/2625/status | 31 + tests/002/proc/2625/task/2625/stat | 1 + tests/002/proc/2626/status | 31 + tests/002/proc/2626/task/2626/stat | 1 + tests/002/proc/2626/task/2627/stat | 1 + tests/002/proc/2631/status | 31 + tests/002/proc/2631/task/2631/stat | 1 + tests/002/proc/2634/status | 31 + tests/002/proc/2634/task/2634/stat | 1 + tests/002/proc/2636/status | 31 + tests/002/proc/2636/task/2636/stat | 1 + tests/002/proc/2638/status | 31 + tests/002/proc/2638/task/2638/stat | 1 + tests/002/proc/2644/status | 31 + tests/002/proc/2644/task/2644/stat | 1 + tests/002/proc/2661/status | 31 + tests/002/proc/2661/task/2661/stat | 1 + tests/002/proc/2685/status | 31 + tests/002/proc/2685/task/2685/stat | 1 + tests/002/proc/2689/status | 31 + tests/002/proc/2689/task/2689/stat | 1 + tests/002/proc/2691/status | 31 + tests/002/proc/2691/task/2691/stat | 1 + tests/002/proc/2691/task/2696/stat | 1 + tests/002/proc/2691/task/2708/stat | 1 + tests/002/proc/2691/task/2709/stat | 1 + tests/002/proc/2691/task/2710/stat | 1 + tests/002/proc/2691/task/2711/stat | 1 + tests/002/proc/2691/task/2712/stat | 1 + tests/002/proc/2691/task/2713/stat | 1 + tests/002/proc/2691/task/2714/stat | 1 + tests/002/proc/2691/task/2715/stat | 1 + tests/002/proc/2693/status | 31 + tests/002/proc/2693/task/2693/stat | 1 + tests/002/proc/2695/status | 31 + tests/002/proc/2695/task/2695/stat | 1 + tests/002/proc/2698/status | 31 + tests/002/proc/2698/task/2698/stat | 1 + tests/002/proc/2698/task/2699/stat | 1 + tests/002/proc/2701/status | 31 + tests/002/proc/2701/task/2701/stat | 1 + tests/002/proc/2707/status | 31 + tests/002/proc/2707/task/2707/stat | 1 + tests/002/proc/27121/status | 20 + tests/002/proc/27121/task/27121/stat | 1 + tests/002/proc/2717/status | 31 + tests/002/proc/2717/task/2717/stat | 1 + tests/002/proc/2718/status | 31 + tests/002/proc/2718/task/2718/stat | 1 + tests/002/proc/2720/status | 31 + tests/002/proc/2720/task/2720/stat | 1 + tests/002/proc/2722/status | 31 + tests/002/proc/2722/task/2722/stat | 1 + tests/002/proc/27243/status | 20 + tests/002/proc/27243/task/27243/stat | 1 + tests/002/proc/2726/status | 31 + tests/002/proc/2726/task/2726/stat | 1 + tests/002/proc/2728/status | 31 + tests/002/proc/2728/task/2728/stat | 1 + tests/002/proc/27682/status | 31 + tests/002/proc/27682/task/27682/stat | 1 + tests/002/proc/27684/status | 31 + tests/002/proc/27684/task/27684/stat | 1 + tests/002/proc/27685/status | 31 + tests/002/proc/27685/task/27685/stat | 1 + tests/002/proc/28/status | 20 + tests/002/proc/28/task/28/stat | 1 + tests/002/proc/29/status | 20 + tests/002/proc/29/task/29/stat | 1 + tests/002/proc/29840/status | 31 + tests/002/proc/29840/task/29840/stat | 1 + tests/002/proc/3/status | 20 + tests/002/proc/3/task/3/stat | 1 + tests/002/proc/30737/status | 31 + tests/002/proc/30737/task/30737/stat | 1 + tests/002/proc/31905/status | 31 + tests/002/proc/31905/task/31905/stat | 1 + tests/002/proc/31907/status | 31 + tests/002/proc/31907/task/31907/stat | 1 + tests/002/proc/31908/status | 31 + tests/002/proc/31908/task/31908/stat | 1 + tests/002/proc/32672/status | 31 + tests/002/proc/32672/task/32672/stat | 1 + tests/002/proc/32674/status | 31 + tests/002/proc/32674/task/32674/stat | 1 + tests/002/proc/32675/status | 31 + tests/002/proc/32675/task/32675/stat | 1 + tests/002/proc/4/status | 20 + tests/002/proc/4/task/4/stat | 1 + tests/002/proc/5/status | 20 + tests/002/proc/5/task/5/stat | 1 + tests/002/proc/870/status | 31 + tests/002/proc/870/task/870/stat | 1 + tests/002/query-1.expected | 90 ++ tests/002/query-1.txr | 38 + txr.1 | 1741 ++++++++++++++++++++++++++++++++++ unwind.c | 88 ++ unwind.h | 66 ++ 217 files changed, 11977 insertions(+) create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 extract.h create mode 100644 extract.l create mode 100644 extract.y create mode 100644 gc.c create mode 100644 gc.h create mode 100644 lib.c create mode 100644 lib.h create mode 100644 regex.c create mode 100644 regex.h create mode 100644 tests/001/data create mode 100644 tests/001/query-1.expected create mode 100644 tests/001/query-1.txr create mode 100644 tests/001/query-2.expected create mode 100644 tests/001/query-2.txr create mode 100644 tests/001/query-3.expected create mode 100644 tests/001/query-3.txr create mode 100644 tests/002/etc/passwd create mode 100644 tests/002/proc/1/status create mode 100644 tests/002/proc/1/task/1/stat create mode 100644 tests/002/proc/103/status create mode 100644 tests/002/proc/103/task/103/stat create mode 100644 tests/002/proc/1068/status create mode 100644 tests/002/proc/1068/task/1068/stat create mode 100644 tests/002/proc/1235/status create mode 100644 tests/002/proc/1235/task/1235/stat create mode 100644 tests/002/proc/1236/status create mode 100644 tests/002/proc/1236/task/1236/stat create mode 100644 tests/002/proc/15812/status create mode 100644 tests/002/proc/15812/task/15812/stat create mode 100644 tests/002/proc/16/status create mode 100644 tests/002/proc/16/task/16/stat create mode 100644 tests/002/proc/1620/status create mode 100644 tests/002/proc/1620/task/1620/stat create mode 100644 tests/002/proc/1624/status create mode 100644 tests/002/proc/1624/task/1624/stat create mode 100644 tests/002/proc/16248/status create mode 100644 tests/002/proc/16248/task/16248/stat create mode 100644 tests/002/proc/16249/status create mode 100644 tests/002/proc/16249/task/16249/stat create mode 100644 tests/002/proc/1645/status create mode 100644 tests/002/proc/1645/task/1645/stat create mode 100644 tests/002/proc/1665/status create mode 100644 tests/002/proc/1665/task/1665/stat create mode 100644 tests/002/proc/1698/status create mode 100644 tests/002/proc/1698/task/1698/stat create mode 100644 tests/002/proc/17/status create mode 100644 tests/002/proc/17/task/17/stat create mode 100644 tests/002/proc/175/status create mode 100644 tests/002/proc/175/task/175/stat create mode 100644 tests/002/proc/1766/status create mode 100644 tests/002/proc/1766/task/1766/stat create mode 100644 tests/002/proc/1790/status create mode 100644 tests/002/proc/1790/task/1790/stat create mode 100644 tests/002/proc/1791/status create mode 100644 tests/002/proc/1791/task/1791/stat create mode 100644 tests/002/proc/1821/status create mode 100644 tests/002/proc/1821/task/1821/stat create mode 100644 tests/002/proc/1821/task/1822/stat create mode 100644 tests/002/proc/1821/task/1826/stat create mode 100644 tests/002/proc/1839/status create mode 100644 tests/002/proc/1839/task/1839/stat create mode 100644 tests/002/proc/1851/status create mode 100644 tests/002/proc/1851/task/1851/stat create mode 100644 tests/002/proc/186/status create mode 100644 tests/002/proc/186/task/186/stat create mode 100644 tests/002/proc/1887/status create mode 100644 tests/002/proc/1887/task/1887/stat create mode 100644 tests/002/proc/1902/status create mode 100644 tests/002/proc/1902/task/1902/stat create mode 100644 tests/002/proc/1921/status create mode 100644 tests/002/proc/1921/task/1921/stat create mode 100644 tests/002/proc/1925/status create mode 100644 tests/002/proc/1925/task/1925/stat create mode 100644 tests/002/proc/1926/status create mode 100644 tests/002/proc/1926/task/1926/stat create mode 100644 tests/002/proc/1927/status create mode 100644 tests/002/proc/1927/task/1927/stat create mode 100644 tests/002/proc/1928/status create mode 100644 tests/002/proc/1928/task/1928/stat create mode 100644 tests/002/proc/1929/status create mode 100644 tests/002/proc/1929/task/1929/stat create mode 100644 tests/002/proc/1930/status create mode 100644 tests/002/proc/1930/task/1930/stat create mode 100644 tests/002/proc/1931/status create mode 100644 tests/002/proc/1931/task/1931/stat create mode 100644 tests/002/proc/1932/status create mode 100644 tests/002/proc/1932/task/1932/stat create mode 100644 tests/002/proc/1936/status create mode 100644 tests/002/proc/1936/task/1936/stat create mode 100644 tests/002/proc/1963/status create mode 100644 tests/002/proc/1963/task/1963/stat create mode 100644 tests/002/proc/1989/status create mode 100644 tests/002/proc/1989/task/1989/stat create mode 100644 tests/002/proc/2/status create mode 100644 tests/002/proc/2/task/2/stat create mode 100644 tests/002/proc/2008/status create mode 100644 tests/002/proc/2008/task/2008/stat create mode 100644 tests/002/proc/2027/status create mode 100644 tests/002/proc/2027/task/2027/stat create mode 100644 tests/002/proc/2027/task/2032/stat create mode 100644 tests/002/proc/2041/status create mode 100644 tests/002/proc/2041/task/2041/stat create mode 100644 tests/002/proc/2052/status create mode 100644 tests/002/proc/2052/task/2052/stat create mode 100644 tests/002/proc/2062/status create mode 100644 tests/002/proc/2062/task/2062/stat create mode 100644 tests/002/proc/2124/status create mode 100644 tests/002/proc/2124/task/2124/stat create mode 100644 tests/002/proc/2184/status create mode 100644 tests/002/proc/2184/task/2184/stat create mode 100644 tests/002/proc/2354/status create mode 100644 tests/002/proc/2354/task/2354/stat create mode 100644 tests/002/proc/2551/status create mode 100644 tests/002/proc/2551/task/2551/stat create mode 100644 tests/002/proc/2579/status create mode 100644 tests/002/proc/2579/task/2579/stat create mode 100644 tests/002/proc/2625/status create mode 100644 tests/002/proc/2625/task/2625/stat create mode 100644 tests/002/proc/2626/status create mode 100644 tests/002/proc/2626/task/2626/stat create mode 100644 tests/002/proc/2626/task/2627/stat create mode 100644 tests/002/proc/2631/status create mode 100644 tests/002/proc/2631/task/2631/stat create mode 100644 tests/002/proc/2634/status create mode 100644 tests/002/proc/2634/task/2634/stat create mode 100644 tests/002/proc/2636/status create mode 100644 tests/002/proc/2636/task/2636/stat create mode 100644 tests/002/proc/2638/status create mode 100644 tests/002/proc/2638/task/2638/stat create mode 100644 tests/002/proc/2644/status create mode 100644 tests/002/proc/2644/task/2644/stat create mode 100644 tests/002/proc/2661/status create mode 100644 tests/002/proc/2661/task/2661/stat create mode 100644 tests/002/proc/2685/status create mode 100644 tests/002/proc/2685/task/2685/stat create mode 100644 tests/002/proc/2689/status create mode 100644 tests/002/proc/2689/task/2689/stat create mode 100644 tests/002/proc/2691/status create mode 100644 tests/002/proc/2691/task/2691/stat create mode 100644 tests/002/proc/2691/task/2696/stat create mode 100644 tests/002/proc/2691/task/2708/stat create mode 100644 tests/002/proc/2691/task/2709/stat create mode 100644 tests/002/proc/2691/task/2710/stat create mode 100644 tests/002/proc/2691/task/2711/stat create mode 100644 tests/002/proc/2691/task/2712/stat create mode 100644 tests/002/proc/2691/task/2713/stat create mode 100644 tests/002/proc/2691/task/2714/stat create mode 100644 tests/002/proc/2691/task/2715/stat create mode 100644 tests/002/proc/2693/status create mode 100644 tests/002/proc/2693/task/2693/stat create mode 100644 tests/002/proc/2695/status create mode 100644 tests/002/proc/2695/task/2695/stat create mode 100644 tests/002/proc/2698/status create mode 100644 tests/002/proc/2698/task/2698/stat create mode 100644 tests/002/proc/2698/task/2699/stat create mode 100644 tests/002/proc/2701/status create mode 100644 tests/002/proc/2701/task/2701/stat create mode 100644 tests/002/proc/2707/status create mode 100644 tests/002/proc/2707/task/2707/stat create mode 100644 tests/002/proc/27121/status create mode 100644 tests/002/proc/27121/task/27121/stat create mode 100644 tests/002/proc/2717/status create mode 100644 tests/002/proc/2717/task/2717/stat create mode 100644 tests/002/proc/2718/status create mode 100644 tests/002/proc/2718/task/2718/stat create mode 100644 tests/002/proc/2720/status create mode 100644 tests/002/proc/2720/task/2720/stat create mode 100644 tests/002/proc/2722/status create mode 100644 tests/002/proc/2722/task/2722/stat create mode 100644 tests/002/proc/27243/status create mode 100644 tests/002/proc/27243/task/27243/stat create mode 100644 tests/002/proc/2726/status create mode 100644 tests/002/proc/2726/task/2726/stat create mode 100644 tests/002/proc/2728/status create mode 100644 tests/002/proc/2728/task/2728/stat create mode 100644 tests/002/proc/27682/status create mode 100644 tests/002/proc/27682/task/27682/stat create mode 100644 tests/002/proc/27684/status create mode 100644 tests/002/proc/27684/task/27684/stat create mode 100644 tests/002/proc/27685/status create mode 100644 tests/002/proc/27685/task/27685/stat create mode 100644 tests/002/proc/28/status create mode 100644 tests/002/proc/28/task/28/stat create mode 100644 tests/002/proc/29/status create mode 100644 tests/002/proc/29/task/29/stat create mode 100644 tests/002/proc/29840/status create mode 100644 tests/002/proc/29840/task/29840/stat create mode 100644 tests/002/proc/3/status create mode 100644 tests/002/proc/3/task/3/stat create mode 100644 tests/002/proc/30737/status create mode 100644 tests/002/proc/30737/task/30737/stat create mode 100644 tests/002/proc/31905/status create mode 100644 tests/002/proc/31905/task/31905/stat create mode 100644 tests/002/proc/31907/status create mode 100644 tests/002/proc/31907/task/31907/stat create mode 100644 tests/002/proc/31908/status create mode 100644 tests/002/proc/31908/task/31908/stat create mode 100644 tests/002/proc/32672/status create mode 100644 tests/002/proc/32672/task/32672/stat create mode 100644 tests/002/proc/32674/status create mode 100644 tests/002/proc/32674/task/32674/stat create mode 100644 tests/002/proc/32675/status create mode 100644 tests/002/proc/32675/task/32675/stat create mode 100644 tests/002/proc/4/status create mode 100644 tests/002/proc/4/task/4/stat create mode 100644 tests/002/proc/5/status create mode 100644 tests/002/proc/5/task/5/stat create mode 100644 tests/002/proc/870/status create mode 100644 tests/002/proc/870/task/870/stat create mode 100644 tests/002/query-1.expected create mode 100644 tests/002/query-1.txr create mode 100644 txr.1 create mode 100644 unwind.c create mode 100644 unwind.h diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..b5279410 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,228 @@ +2009-09-25 Kaz Kylheku + + Version 011 + + New @(maybe) clause optionally matches (does not fail if none of + its clauses match anything). + + New blocks feature: allows a query or subquery to be + abruptly terminated by invoking an exit to a named or anonymous + block. @(collect) and @(skip) have implicit anonymous blocks now. + + The @(skip) directive takes a numeric argument now, which limits + how many lines are searched. + + * Makefile, extract.l, extract.y, extract.h, gc.c, gc.h, lib.c, lib.h, + regex.c, regex.h, txr.1, unwind.c, unwind.h: Copyright notice and + license text updated or added, and version bumped up to 011. + * tests/001/query-1.txr, tests/001/query-2.txr, tests/001/query-3.txr, + tests/002/query-1.txr: Assigned to public domain. + +2009-09-25 Kaz Kylheku + + New features: + - named blocks; + - maybe clause; + - optional iteration bound on skip. + + * extract.y: includes added: "unwind.h", . + (MAYBE, OR): New grammar tokens. + (maybe_clause): New nonterminal grammar symbol. + (expr): A NUMBER can be an expression now, so that @(skip 42) + is valid syntax. + (match_files): Support for numeric argument in skip directive + to bound the search to a maximum number of lines. + Anonymous block established around skip. + New directives implemented: maybe, block, accept and fail. + Anonymous block established around collect. + * txr.1: Documentation updated with new features. + * Makefile: new object file unwind.o, and associated rules. + * extract.l (yybadtoken): New cases for MAYBE and OR. + (grammar): Likewise. + * lib.c (block, fail, accept): New symbol variables. + (obj_init): New symbols interned. + * lib.h (block, fail, accept): Declared. + (if2, if3): Macros fixed so test expression is not compared to nil, + but implicitly tested as boolean. + * unwind.c, unwind.h: New source files. + +2009-09-24 Kaz Kylheku + + Stability fixes. + + * extract.y (match_files): Fixed invalid string("-") to + string(chk_strdup("-")) which caused a freeing of + a non-malloced string at gc finalization time. + * regex.c (nfa_state_shallow_free): New function: does not + free satellite objects, just the structure itself. + (nfa_combine): Use nfa_state_shallow_free instead of nfa_state_free, + because the merged state inherits ownership of objects from the state + being spliced out. + (nfa_state_set): Fix lack of initialization of s.visited member of the + state structure. + +2009-09-24 Kaz Kylheku + + Version 010 + + A file specs can start with $, which means read a directory. + + Data sources are not into memory at once, but on demand, + which can reduce memory for many queries. + + Regular expressions are now compiled once, when the + query is parsed. + + Character escapes are now supported in regular expressions, + and as a special syntax. + + * extract.l (version): Bumped to 010. + (grammar): 8 and 9 are not octal digits; handle all regex + backslash escaping in lexical grammar. + * extract.y (grammar): Get rid of backslash handling from + regex grammar. Lexer returns a REGCHAR for every escaped + item. In situations where an operator character is implicily + literal, like * in a character class, we use the grammar + to include that alongside REGCHAR. Bugfixes: the character ], when not + closing a class, is not a syntax error but stands for itself; + the character - stands for itself outside of character class; + the | character is literal in a character class. + * txr.1: Updated version. Documented character escapes. + +2009-09-24 Kaz Kylheku + + Lazy stream list improvement: no extra NIL element caused + by end-of-file. Requires push-back support in streams. + To avoid introducing a new structure member into streams, + we extend the semantics of the label member, and rename + it to label_pushback. + + * lib.c (stdio_line_stream, pipe_line_stream, + dirent_stream): Follow rename of struct stream member; + assert that label is an atom. + (stream_get): Check pushback stack first and get item from there. + (stream_pushback): New function. + (lazy_stream_func): Pull one more item from the stream and + use /that/ to decide whether to continue the lazy stream. + The extra item is pushed back, if valid. + (lazy_stream_cons): Simplified: no hack involving regular cons. Starts + the induction by peeking into the stream. If something is there, it is + pushed back, and a lazy cons is constructed which will fetch it. + (obj_print): Made aware of the pushback, which must be skipped + to get to the terminating label. + * lib.h (struct stream): Member renamed from label to label_pushback. + (stream_pushback): New function declaration. + +2009-09-23 Kaz Kylheku + + Escape syntax in regexes, and text. The + standard seven character escapes are supported, + namely \a, \b, \t, \n, \v, \f, and \r, + as well as hex and octal escapes, plus + the code \e for ASCII ESC. + + * extract.l (char_esc, num_esc): New functions. + (grammar): New lex cases. + * lib.c (obj_print): Support all character escapes in printing. + Bugfix: backslash printed as two backslashes, not one. + +2009-09-23 Kaz Kylheku + + * tests/002/query-1.txr: Modified to use $ to scan thread + subdirectories. + * tests/002/query-1.expected: Updated. + +2009-09-23 Kaz Kylheku + + New COBJ type for wrapping arbitrary C objects into the + Lisp-like framework. Compiled regexes are objects now. + Regexes in a query are now compiled just once. + + * extract.y (grammar): Regexes compiled while parsing. + (match_line): Modify with respect to the abstract syntax + tree change, and the interface changes in the match_regex, + and search_regex functions. + * gc.c (mark_obj, finalize): Handle marking and finalization + of COBJ objects. + * lib.c (typeof, equal, obj_print): Handle COBJ. + (cobj, cobj_print_op): New functions. + * lib.h (type_t): New enum element, COBJ. + (struct cobj, struct subj_ops): New types. + (union obj): New member, co. + (cobj, cobj_print_op): New functions declared. + * regex.c (regex_equal, regex_destroy, regex_compile, regex_nfa): New + functions. + (regex_obj_ops): New static struct. + (search_regex, match_regex): Interface change. Regex arguments + are now compiled regexes. Functions won't handle raw regexes. + * regex.h (regex_compile, regex_nfa): New functions declared. + +2009-09-23 Kaz Kylheku + + New feature: file specs that start with $ read directories. + Reading from an ``ls'' pipe is too slow. + + Streams and lazy conses implemented. Lazy conses allow us to treat a + file or other kind of stream exactly as if it were a list. + We can use car and cdr, etc. But only the parts of the list + that we actually touch are instantiated on-the-fly by + reading from the underlying stream. + + * extract.l: inclusion of added. + * extract.l: inclusion of added. + * extract.y (fpip_closedir): new enumeration in struct fpip, + and fpip_noclose removed. + (complex_open): Check for leading $, use opendir. + (complex_open_failed): New function. + (complex_close): Handle fpip_closedir case. Not closing + stdin and stdout is handled by explicit comparison now. + (complex_snarf): New function, constructs stream of + a suitable type, over object returned from complex_close, + wraps it in a lazy list. + (match_files): Use complex_snarf instead of snarf to get a lazy list. + * gc.c: Handle LCONS and STREAM cases. + * lib.c (stream_t, lcons_t): New variables holding symbols. + (typeof, equal, obj_print): Handle LCONS and STREAM. + (car, cdr, car_l, cdr_l, consp, atom, listp): Rewritten to handle + LCONS. + (chk_strdup, stdio_line_read, stdio_line_write, stdio_close + stdio_line_stream, pipe_close, pipe_line_stream, + dirent_read, dirent_close, dirent_stream, + stream_get, stream_put, stream_close, + make_lazycons, lazy_stream_func, lazy_stream_cons): New functions. + (stdio_line_stream_ops, pipe_line_stream_ops, + dirent_stream_ops): New static structs. + (obj_init): Intern new symbols lstream, lcons, and dir. + * lib.h (type_t): New enum members STREAM and LCONS. + (struct stream, struct stream_ops, struct lazy_cons): New types. + (union obj): New members sm and lc. + (chk_strdup, stdio_line_stream, pipe_line_stream, + dirent_stream, stream_get, stream_put, stream_close, + lazy_stream_cons): New function declarations. + * regex.c: inclusion of added + +2009-09-23 Kaz Kylheku + + Version 009 + + User-friendly error messages from parser. + Fixed -q option. + + * extract.l (version): Bumped to 009. + * txr.1: Updated version. + +2009-09-22 Kaz Kylheku + + * Makefile (LIBLEX): New variable. + Refer to lex library as -lfl, using variable + that can be overridden. + +2009-09-22 Kaz Kylheku + + * extract.h (yybadtoken): New function declaration. + * extract.l (yybadtoken): New function. + (main): Fixed -q option. + * extract.y (grammar): Lots of new error productions, some + phrase rules refactored, resulting in much more user-friendly + error diagnosis. + * txr.1: -q option semantics clarified. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ae4276e0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (C) 2009, Kaz Kylheku . +All rights reserved. + +BSD License: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2b0973b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +# Copyright 2009 +# Kaz Kylheku +# Vancouver, Canada +# All rights reserved. +# +# BSD License: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. The name of the author may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# Test data in the tests/ directory is in the public domain, +# unless it contains notices to the contrary. +OPT_FLAGS := -O2 +LANG_FLAGS := -ansi -D_GNU_SOURCE +DIAG_FLAGS := -Wall +DBG_FLAGS := -g +LEXLIB := fl + +CFLAGS := $(LANG_FLAGS) $(DIAG_FLAGS) $(OPT_FLAGS) $(DBG_FLAGS) + +txr: lex.yy.o y.tab.o lib.o regex.o gc.o unwind.o + $(CC) $(CFLAGS) -o $@ $^ -l$(LEXLIB) + +lex.yy.o y.tab.o: y.tab.h extract.h lib.h gc.h + +y.tab.o: regex.h + +lib.o: lib.h gc.h + +regex.o: regex.h lib.h gc.h + +gc.o: gc.h lib.h gc.h + +unwind.o: unwind.h lib.h + +lex.yy.c: extract.l + $(LEX) $< + +y.tab.c y.tab.h: extract.y + if $(YACC) -v -d $< ; then true ; else rm $@ ; false ; fi + +clean: + rm -f txr lex.yy.o y.tab.o lib.o regex.o gc.o unwind.o \ + y.tab.c lex.yy.c y.tab.h y.output $(TESTS:.ok=.out) + +TESTS := $(patsubst %.txr,%.ok,$(shell find tests -name '*.txr' | sort)) + +tests: txr $(TESTS) + @echo "** tests passed!" + +tests/001/%: TXR_ARGS := tests/001/data +tests/002/%: TXR_OPTS := -DTESTDIR=tests/002 + +%.ok: %.txr + ./txr $(TXR_OPTS) $^ $(TXR_ARGS) > $(@:.ok=.out) + diff $(@:.ok=.expected) $(@:.ok=.out) + +%.expected: %.txr + ./txr $(TXR_OPTS) $^ $(TXR_ARGS) > $@ + diff --git a/extract.h b/extract.h new file mode 100644 index 00000000..cff5d432 --- /dev/null +++ b/extract.h @@ -0,0 +1,37 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +long lineno; +extern int opt_loglevel; +extern int opt_nobindings; +extern int opt_arraydims; +int yyparse(void); +obj_t *get_spec(void); +int extract(obj_t *spec, obj_t *filenames, obj_t *bindings); +void yyerrorf(int level, const char *s, ...); +void yyerrorlf(int level, long spec_lineno, const char *s, ...); +void yybadtoken(int tok, const char *context); diff --git a/extract.l b/extract.l new file mode 100644 index 00000000..4c15476d --- /dev/null +++ b/extract.l @@ -0,0 +1,678 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +%{ + +#include +#include +#include +#include +#include +#include +#include +#include "y.tab.h" +#include "lib.h" +#include "gc.h" +#include "extract.h" + +#define YY_NO_UNPUT + +const char *version = "011"; +const char *progname = "txr"; +const char *spec_file = "stdin"; +long lineno = 1; +int opt_loglevel = 1; /* 0 - quiet; 1 - normal; 2 - verbose */ +int opt_nobindings = 0; +int opt_arraydims = 1; + +static int nesting; +static int closechar; +static int errors; + +/* + * Can implement an emergency allocator here from a fixed storage + * pool, which sets an OOM flag. Program can check flag + * and gracefully terminate instead of aborting like this. + */ +void *oom_realloc_handler(void *old, size_t size) +{ + fprintf(stderr, "%s: out of memory\n", progname); + puts("false"); + abort(); +} + +void yyerror(const char *s) +{ + yyerrorlf(1, lineno, "%s", s); + errors++; +} + +void yyerrorf(int level, const char *s, ...) +{ + if (opt_loglevel >= level) { + va_list vl; + va_start (vl, s); + fprintf(stderr, "%s: (%s:%ld): ", progname, spec_file, lineno); + vfprintf(stderr, s, vl); + putc('\n', stderr); + va_end (vl); + } + + if (level < 2) + errors++; +} + +void yyerrorlf(int level, long spec_lineno, const char *s, ...) +{ + if (opt_loglevel >= level) { + va_list vl; + va_start (vl, s); + fprintf(stderr, "%s: (%s:%ld): ", progname, spec_file, spec_lineno); + vfprintf(stderr, s, vl); + putc('\n', stderr); + va_end (vl); + } + + if (level < 2) + errors++; +} + +void yybadtoken(int tok, const char *context) +{ + const char *problem = 0; + + switch (tok) { + case TEXT: problem = "text"; break; + case IDENT: problem = "identifier"; break; + case ALL: problem = "\"all\""; break; + case SOME: problem = "\"some\""; break; + case NONE: problem = "\"none\""; break; + case MAYBE: problem = "\"maybe\""; break; + case AND: problem = "\"and\""; break; + case OR: problem = "\"or\""; break; + case END: problem = "\"end\""; break; + case COLLECT: problem = "\"collect\""; break; + case UNTIL: problem = "\"until\""; break; + case COLL: problem = "\"coll\""; break; + case OUTPUT: problem = "\"output\""; break; + case REPEAT: problem = "\"repeat\""; break; + case REP: problem = "\"rep\""; break; + case SINGLE: problem = "\"single\""; break; + case FIRST: problem = "\"first\""; break; + case LAST: problem = "\"last\""; break; + case EMPTY: problem = "\"empty\""; break; + case NUMBER: problem = "\"number\""; break; + case REGCHAR: problem = "regular expression character"; break; + } + + if (problem != 0) + if (context) + yyerrorlf(1, lineno, "misplaced %s in %s", problem, context); + else + yyerrorlf(1, lineno, "unexpected %s", problem); + else + if (context) + yyerrorlf(1, lineno, "unterminated %s", context); + else + yyerrorlf(1, lineno, "unexpected end of input"); +} + +static int char_esc(int letter) +{ + switch (letter) { + case 'a': return '\a'; + case 'b': return '\b'; + case 't': return '\t'; + case 'n': return '\n'; + case 'v': return '\v'; + case 'f': return '\f'; + case 'r': return '\r'; + case 'e': return 27; + } + + abort(); +} + +static int num_esc(char *num) +{ + if (num[0] == 'x') { + if (strlen(num) > 3) + yyerror("too many digits in hex character escape"); + return strtol(num + 1, 0, 16); + } else { + if (strlen(num) > 3) + yyerror("too many digits in octal character escape"); + return strtol(num, 0, 8); + } +} + +%} + +TOK [a-zA-Z_][a-zA-Z0-9_]*|[+-]?[0-9]+ +WS [\t ]* +%x SPECIAL REGEX REGCLASS + +%% + +{TOK} { + long val; + char *errp; + + errno = 0; + + val = strtol(yytext, &errp, 10); + + if (nesting == 0) + BEGIN(INITIAL); + + if (*errp != 0) { + /* not a number */ + yylval.lexeme = strdup(yytext); + return IDENT; + } + + if ((val == LONG_MAX || val == LONG_MIN) && errno == ERANGE) + yyerror("numeric overflow in token"); + + yylval.num = val; + return NUMBER; + } + + +\({WS}all{WS}\) { + BEGIN(INITIAL); + return ALL; + } + +\({WS}some{WS}\) { + BEGIN(INITIAL); + return SOME; + } + +\({WS}none{WS}\) { + BEGIN(INITIAL); + return NONE; + } + +\({WS}maybe{WS}\) { + BEGIN(INITIAL); + return MAYBE; + } + +\({WS}and{WS}\) { + BEGIN(INITIAL); + return AND; + } + +\({WS}or{WS}\) { + BEGIN(INITIAL); + return OR; + } + +\({WS}end{WS}\) { + BEGIN(INITIAL); + return END; + } + +\({WS}collect{WS}\) { + BEGIN(INITIAL); + return COLLECT; + } + +\({WS}coll{WS}\) { + BEGIN(INITIAL); + return COLL; + } + +\({WS}until{WS}\) { + BEGIN(INITIAL); + return UNTIL; + } + +\({WS}output{WS}\) { + BEGIN(INITIAL); + return OUTPUT; + } + +\({WS}repeat{WS}\) { + BEGIN(INITIAL); + return REPEAT; + } + + +\({WS}rep{WS}\) { + BEGIN(INITIAL); + return REP; + } + +\({WS}single{WS}\) { + BEGIN(INITIAL); + return SINGLE; + } + +\({WS}first{WS}\) { + BEGIN(INITIAL); + return FIRST; + } + +\({WS}last{WS}\) { + BEGIN(INITIAL); + return LAST; + } + +\({WS}empty{WS}\) { + BEGIN(INITIAL); + return EMPTY; + } + +\{|\( { + nesting++; + if (yytext[0] == '{') + closechar = '}'; + else + closechar = ')'; + return yytext[0]; + } + +\}|\) { + if (yytext[0] != closechar) { + yyerror("paren mismatch"); + BEGIN(INITIAL); + } else { + if (--nesting == 0) + BEGIN(INITIAL); + return yytext[0]; + } + } + +[\t ]+ { + /* Eat whitespace in directive */ + } + +@ { + if (nesting == 0) { + BEGIN(INITIAL); + yylval.lexeme = strdup("@"); + return TEXT; + } else { + yyerrorf(0, "bad character in directive: %c", yytext[0]); + } + } + +\n { + lineno++; + yyerror("newline in directive"); + } + +[/] { + BEGIN(REGEX); + return '/'; + } + +\. { + yylval.chr = '.'; + return '.'; + } + +[\\][abtnvfre] { + char lexeme[2]; + lexeme[0] = char_esc(yytext[1]); + lexeme[1] = 0; + yylval.lexeme = strdup(lexeme); + BEGIN(INITIAL); + return TEXT; + } + +[\\](x[0-9a-fA-F]+|[0-7]+) { + char lexeme[2]; + lexeme[0] = num_esc(yytext + 1); + lexeme[1] = 0; + yylval.lexeme = strdup(lexeme); + BEGIN(INITIAL); + return TEXT; + } + +. { + yyerrorf(0, "bad character in directive: '%c'", yytext[0]); + } + +[/] { + if (nesting == 0) + BEGIN(INITIAL); + else + BEGIN(SPECIAL); + yylval.chr = '/'; + return '/'; + } + + +[\\][abtnvfre] { + yylval.chr = char_esc(yytext[1]); + return REGCHAR; + } + +[\\](x[0-9a-fA-F]+|[0-9]+) { + yylval.chr = num_esc(yytext + 1); + return REGCHAR; + } + +\n { + lineno++; + yyerror("newline in regex"); + } + +[.*?+^] { + yylval.chr = yytext[0]; + return yytext[0]; + } + + +[\[\]\-] { + yylval.chr = yytext[0]; + return yytext[0]; + } + +[()|] { + yylval.chr = yytext[0]; + return yytext[0]; + } + +[\\]. { + yylval.chr = yytext[1]; + return REGCHAR; + } + +. { + yylval.chr = yytext[0]; + return REGCHAR; + } + +[^@\n]+ { + yylval.lexeme = strdup(yytext); + return TEXT; + } + +\n { + lineno++; + return '\n'; + } + +@{WS}\* { + BEGIN(SPECIAL); + return '*'; + } + +@ { + BEGIN(SPECIAL); + } + +^@#.*\n { + /* eat whole line comment */ + lineno++; + } + +@#.* { + /* comment to end of line */ + } + +%% + +void help(void) +{ + const char *text = +"\n" +"txr version %s\n" +"\n" +"copyright 2009, Kaz Kylheku \n" +"\n" +"usage:\n" +"\n" +" %s [ options ] query-file { data-file }*\n" +"\n" +"The query-file or data-file arguments may be specified as -, in which case\n" +"standard input is used. If these arguments end with a | character, then\n" +"they are treated as command pipes. Leading arguments which begin with a -\n" +"followed by one or more characters, and which are not arguments to options\n" +"are interpreted as options. The -- option indicates the end of the options.\n" +"\n" +"If no data-file arguments sare supplied, then the query itself must open a\n" +"a data source prior to attempting to make any pattern match, or it will\n" +"simply fail due to a match which has run out of data.\n" +"\n" +"options:\n" +"\n" +"-Dvar=value Pre-define variable var, with the given value.\n" +" A list value can be specified using commas.\n" +"-Dvar Predefine variable var, with empty string value.\n" +"-q Quiet: don't report errors during query matching.\n" +"-v Verbose: extra logging from matcher.\n" +"-b Don't dump list of bindings.\n" +"-a num Generate array variables up to num-dimensions.\n" +" Default is 1. Additional dimensions are fudged\n" +" by generating numeric suffixes\n" +"--help You already know!\n" +"--version Display program version\n" +"\n" +"Options that take no argument can be combined. The -q and -v options\n" +"are mutually exclusive; the right-most one dominates.\n" +"\n" + ; + fprintf(stdout, text, version, progname); +} + +void hint(void) +{ + fprintf(stderr, "%s: incorrect arguments: try --help\n", progname); +} + +int main(int argc, char **argv) +{ + obj_t *stack_top = nil; + obj_t *spec = nil; + obj_t *bindings = nil; + int match_loglevel = opt_loglevel; + progname = argv[0] ? argv[0] : progname; + + gc_stack_top = &stack_top; + + if (argc <= 1) { + hint(); + return EXIT_FAILURE; + } + + argc--, argv++; + + while (argc > 0 && (*argv)[0] == '-') { + if (!strcmp(*argv, "--")) { + argv++, argc--; + break; + } + + if (!strcmp(*argv, "-")) + break; + + if (!strncmp(*argv, "-D", 2)) { + char *var = *argv + 2; + char *equals = strchr(var, '='); + char *has_comma = (equals != 0) ? strchr(equals, ',') : 0; + + if (has_comma) { + char *val = equals + 1; + obj_t *list = nil; + + *equals = 0; + + for (;;) { + size_t piece = strcspn(val, ","); + char comma_p = val[piece]; + + val[piece] = 0; + + list = cons(string(strdup(val)), list); + + if (!comma_p) + break; + + val += piece + 1; + } + + list = nreverse(list); + bindings = cons(cons(intern(string(strdup(var))), list), bindings); + } else if (equals) { + char *val = equals + 1; + *equals = 0; + bindings = cons(cons(intern(string(strdup(var))), + string(strdup(val))), bindings); + } else { + bindings = cons(cons(intern(string(strdup(var))), + null_string), bindings); + } + + argc--, argv++; + continue; + } + + if (!strcmp(*argv, "--version")) { + printf("%s: version %s\n", progname, version); + return 0; + } + + if (!strcmp(*argv, "--help")) { + help(); + return 0; + } + + if (!strcmp(*argv, "-a")) { + long val; + char *errp; + char opt = (*argv)[1]; + + if (argc == 1) { + fprintf(stderr, "%s: option %c needs argument\n", progname, opt); + + return EXIT_FAILURE; + } + + argv++, argc--; + + switch (opt) { + case 'a': + val = strtol(*argv, &errp, 10); + if (*errp != 0) { + fprintf(stderr, "%s: option %c needs numeric argument, not %s\n", + progname, opt, *argv); + return EXIT_FAILURE; + } + + opt_arraydims = val; + break; + } + + argv++, argc--; + continue; + } + + if (!strcmp(*argv, "--gc-debug")) { + opt_gc_debug = 1; + argv++, argc--; + continue; + } + + { + char *popt; + for (popt = (*argv)+1; *popt != 0; popt++) { + switch (*popt) { + case 'v': + match_loglevel = 2; + break; + case 'q': + match_loglevel = 0; + break; + case 'b': + opt_nobindings = 1; + break; + default: + fprintf(stderr, "%s: unrecognized option: %c\n", progname, *popt); + return EXIT_FAILURE; + } + } + + argc--, argv++; + } + } + + if (argc < 1) { + hint(); + return EXIT_FAILURE; + } + + if (strcmp(*argv, "-") != 0) { + yyin = fopen(*argv, "r"); + if (yyin == 0) { + fprintf(stderr, "%s: unable to open %s\n", progname, *argv); + return EXIT_FAILURE; + } + spec_file = *argv; + } + + argc--, argv++; + + { + int gc; + init(progname, oom_realloc_handler); + + gc = gc_state(0); + yyparse(); + gc_state(gc); + + if (errors) + return EXIT_FAILURE; + spec = get_spec(); + + + opt_loglevel = match_loglevel; + + if (opt_loglevel >= 2) { + fputs("spec:\n", stderr); + dump(spec, stderr); + + fputs("bindings:\n", stderr); + dump(bindings, stderr); + } + + { + int retval; + list_collect_decl(filenames, iter); + + while (*argv) + list_collect(iter, string(*argv++)); + + retval = extract(spec, filenames, bindings); + + return errors ? EXIT_FAILURE : retval; + } + } +} diff --git a/extract.y b/extract.y new file mode 100644 index 00000000..594b341e --- /dev/null +++ b/extract.y @@ -0,0 +1,1620 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +%{ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lib.h" +#include "gc.h" +#include "unwind.h" +#include "regex.h" +#include "extract.h" + +int yylex(void); +void yyerror(const char *); + +obj_t *repeat_rep_helper(obj_t *sym, obj_t *main, obj_t *parts); + +static obj_t *parsed_spec; +static int output_produced; + +%} + +%union { + char *lexeme; + union obj *obj; + char chr; + long num; +} + +%token TEXT IDENT ALL SOME NONE MAYBE AND OR END COLLECT UNTIL COLL +%token OUTPUT REPEAT REP SINGLE FIRST LAST EMPTY +%token NUMBER +%token REGCHAR + +%type spec clauses clause all_clause some_clause none_clause maybe_clause +%type collect_clause clause_parts additional_parts output_clause +%type line elems_opt elems elem var var_op list exprs expr +%type out_clauses out_clauses_opt out_clause +%type repeat_clause repeat_parts_opt o_line +%type o_elems_opt o_elems_opt2 o_elems o_elem rep_elem rep_parts_opt +%type regex regexpr regbranch +%type regterm regclass regclassterm regrange +%type regchar + +%nonassoc ALL SOME NONE MAYBE AND OR END COLLECT UNTIL COLL +%nonassoc OUTPUT REPEAT REP FIRST LAST EMPTY +%nonassoc '{' '}' '[' ']' '(' ')' +%right IDENT TEXT NUMBER +%left '|' '/' +%right '*' '?' '+' +%right '^' '.' '\\' REGCHAR + +%% + +spec : clauses { parsed_spec = $1; } + | { parsed_spec = nil; } + | error { parsed_spec = nil; + yybadtoken(yychar, 0); } + ; + +clauses : clause { $$ = cons($1, nil); } + | clause clauses { $$ = cons($1, $2); } + ; + +clause : all_clause { $$ = list(num(lineno - 1), $1, nao); } + | some_clause { $$ = list(num(lineno - 1), $1, nao); } + | none_clause { $$ = list(num(lineno - 1), $1, nao); } + | maybe_clause { $$ = list(num(lineno - 1), $1, nao); } + | collect_clause { $$ = list(num(lineno - 1), $1, nao); } + | output_clause { $$ = list(num(lineno - 1), $1, nao); } + | line { $$ = $1; } + | repeat_clause { $$ = nil; + yyerror("repeat outside of output"); } + ; + +all_clause : ALL newl clause_parts { $$ = cons(all, $3); } + | ALL newl error { $$ = nil; + yybadtoken(yychar, + "all clause"); } + | ALL newl END { $$ = nil; + yyerror("empty all clause"); } + + ; + +some_clause : SOME newl clause_parts { $$ = cons(some, $3); } + | SOME newl error { $$ = nil; + yybadtoken(yychar, + "some clause"); } + | SOME newl END { $$ = nil; + yyerror("empty some clause"); } + ; + +none_clause : NONE newl clause_parts { $$ = cons(none, $3); } + | NONE newl error { $$ = nil; + yybadtoken(yychar, + "none clause"); } + | NONE newl END { $$ = nil; + yyerror("empty none clause"); } + ; + +maybe_clause : MAYBE newl clause_parts { $$ = cons(maybe, $3); } + | MAYBE newl error { $$ = nil; + yybadtoken(yychar, + "maybe clause"); } + | MAYBE newl END { $$ = nil; + yyerror("empty maybe clause"); } + ; + +collect_clause : COLLECT newl clauses END newl { $$ = list(collect, $3, nao); } + | COLLECT newl clauses + UNTIL newl clauses END newl { $$ = list(collect, $3, + $6, nao); } + | COLLECT newl error { $$ = nil; + if (yychar == UNTIL || yychar == END) + yyerror("empty collect"); + else + yybadtoken(yychar, + "collect clause"); } + ; + +clause_parts : clauses additional_parts { $$ = cons($1, $2); } + ; + +additional_parts : END newl { $$ = nil; } + | AND newl clauses additional_parts { $$ = cons($3, $4); } + | OR newl clauses additional_parts { $$ = cons($3, $4); } + ; + +line : elems_opt '\n' { $$ = $1; } + ; + +elems_opt : elems { $$ = cons(num(lineno - 1), $1); } + | { $$ = nil; } + ; + +elems : elem { $$ = cons($1, nil); } + | elem elems { $$ = cons($1, $2); } + | rep_elem { $$ = nil; + yyerror("rep outside of output"); } + ; + +elem : TEXT { $$ = string($1); } + | var { $$ = $1; } + | list { $$ = $1; } + | regex { $$ = cons(regex_compile($1), $1); } + | COLL elems END { $$ = list(coll, $2, nao); } + | COLL elems + UNTIL elems END { $$ = list(coll, $2, $4, nao); } + | COLL error { $$ = nil; + yybadtoken(yychar, "coll clause"); } + ; + +output_clause : OUTPUT o_elems '\n' + out_clauses + END newl { $$ = list(output, $4, $2, nao); } + | OUTPUT newl + out_clauses + END newl { $$ = list(output, $3, nao); } + | OUTPUT o_elems '\n' + error { $$ = nil; + yybadtoken(yychar, "output clause"); } + | OUTPUT newl + error { $$ = nil; + yybadtoken(yychar, "output clause"); } + ; + +out_clauses : out_clause { $$ = cons($1, nil); } + | out_clause out_clauses { $$ = cons($1, $2); } + ; + +out_clause : repeat_clause { $$ = list(num(lineno - 1), $1, nao); } + | o_line { $$ = $1; } + | all_clause { $$ = nil; + yyerror("match clause in output"); } + | some_clause { $$ = nil; + yyerror("match clause in output"); } + | none_clause { $$ = nil; + yyerror("match clause in output"); } + | maybe_clause { $$ = nil; + yyerror("match clause in output"); } + | collect_clause { $$ = nil; + yyerror("match clause in output"); } + | output_clause { $$ = nil; + yyerror("match clause in output"); } + ; + +repeat_clause : REPEAT newl + out_clauses + repeat_parts_opt + END newl { $$ = repeat_rep_helper(repeat, $3, $4); } + | REPEAT newl + error { $$ = nil; + yybadtoken(yychar, "repeat clause"); } + ; + +repeat_parts_opt : SINGLE newl + out_clauses_opt + repeat_parts_opt { $$ = cons(cons(single, $3), $4); } + | FIRST newl + out_clauses_opt + repeat_parts_opt { $$ = cons(cons(frst, $3), $4); } + | LAST newl + out_clauses_opt + repeat_parts_opt { $$ = cons(cons(lst, $3), $4); } + | EMPTY newl + out_clauses_opt + repeat_parts_opt { $$ = cons(cons(empty, $3), $4); } + | /* empty */ { $$ = nil; } + ; + + +out_clauses_opt : out_clauses { $$ = $1; } + | /* empty */ { $$ = null_list; } + +o_line : o_elems_opt '\n' { $$ = $1; } + ; + +o_elems_opt : o_elems { $$ = cons(num(lineno - 1), $1); } + | { $$ = nil; } + ; + +o_elems_opt2 : o_elems { $$ = $1; } + | { $$ = null_list; } + ; + +o_elems : o_elem { $$ = cons($1, nil); } + | o_elem o_elems { $$ = cons($1, $2); } + ; + +o_elem : TEXT { $$ = string($1); } + | var { $$ = $1; } + | rep_elem { $$ = $1; } + ; + +rep_elem : REP o_elems + rep_parts_opt END { $$ = repeat_rep_helper(rep, $2, $3); } + | REP error { $$ = nil; yybadtoken(yychar, "rep clause"); } + ; + +rep_parts_opt : SINGLE o_elems_opt2 + rep_parts_opt { $$ = cons(cons(single, $2), $3); } + | FIRST o_elems_opt2 + rep_parts_opt { $$ = cons(cons(frst, $2), $3); } + | LAST o_elems_opt2 + rep_parts_opt { $$ = cons(cons(lst, $2), $3); } + | EMPTY o_elems_opt2 + rep_parts_opt { $$ = cons(cons(empty, $2), $3); } + | /* empty */ { $$ = nil; } + ; + + +/* This sucks, but factoring '*' into a nonterminal + * that generates an empty phrase causes reduce/reduce conflicts. + */ +var : IDENT { $$ = list(var, intern(string($1)), nao); } + | IDENT elem { $$ = list(var, intern(string($1)), $2, nao); } + | '{' IDENT '}' { $$ = list(var, intern(string($2)), nao); } + | '{' IDENT '}' elem { $$ = list(var, intern(string($2)), $4, nao); } + | '{' IDENT regex '}' { $$ = list(var, intern(string($2)), + nil, cons(regex_compile($3), $3), + nao); } + | '{' IDENT NUMBER '}' { $$ = list(var, intern(string($2)), + nil, num($3), nao); } + | var_op IDENT { $$ = list(var, intern(string($2)), + nil, $1, nao); } + | var_op IDENT elem { $$ = list(var, intern(string($2)), + $3, $1, nao); } + | var_op '{' IDENT '}' { $$ = list(var, intern(string($3)), + nil, $1, nao); } + | var_op '{' IDENT '}' elem { $$ = list(var, intern(string($3)), + $5, $1, nao); } + | IDENT error { $$ = nil; + yybadtoken(yychar, "variable spec"); } + | var_op error { $$ = nil; + yybadtoken(yychar, "variable spec"); } + ; + +var_op : '*' { $$ = t; } + ; + +list : '(' exprs ')' { $$ = $2; } + | '(' ')' { $$ = nil; } + | '(' error { $$ = nil; + yybadtoken(yychar, "list expression"); } + ; + +exprs : expr { $$ = cons($1, nil); } + | expr exprs { $$ = cons($1, $2); } + | expr '.' expr { $$ = cons($1, $3); } + ; + +expr : IDENT { $$ = intern(string($1)); } + | NUMBER { $$ = num($1); } + | list { $$ = $1; } + | regex { $$ = cons(regex_compile($1), $1); } + ; + +regex : '/' regexpr '/' { $$ = $2; } + | '/' '/' { $$ = nil; } + | '/' error { $$ = nil; + yybadtoken(yychar, "regex"); } + ; + +regexpr : regbranch { $$ = $1; } + | regbranch '|' regbranch { $$ = list(list(or, $1, + $3, nao), nao); } + ; + +regbranch : regterm { $$ = cons($1, nil); } + | regterm regbranch { $$ = cons($1, $2); } + ; + +regterm : '[' regclass ']' { $$ = cons(set, $2); } + | '[' '^' regclass ']' { $$ = cons(cset, $3); } + | '.' { $$ = wild; } + | '^' { $$ = chr('^'); } + | ']' { $$ = chr(']'); } + | '-' { $$ = chr('-'); } + | regterm '*' { $$ = list(zeroplus, $1, nao); } + | regterm '+' { $$ = list(oneplus, $1, nao); } + | regterm '?' { $$ = list(optional, $1, nao); } + | REGCHAR { $$ = chr($1); } + | '(' regexpr ')' { $$ = cons(compound, $2); } + | '(' error { $$ = nil; + yybadtoken(yychar, "regex subexpression"); } + | '[' error { $$ = nil; + yybadtoken(yychar, "regex character class"); } + ; + +regclass : regclassterm { $$ = cons($1, nil); } + | regclassterm regclass { $$ = cons($1, $2); } + ; + +regclassterm : regrange { $$ = $1; } + | regchar { $$ = chr($1); } + ; + +regrange : regchar '-' regchar { $$ = cons(chr($1), chr($3)); } + +regchar : '?' { $$ = '?'; } + | '.' { $$ = '.'; } + | '*' { $$ = '*'; } + | '+' { $$ = '+'; } + | '(' { $$ = '('; } + | ')' { $$ = ')'; } + | '^' { $$ = '^'; } + | '|' { $$ = '|'; } + | REGCHAR { $$ = $1; } + ; + +newl : '\n' + | error '\n' { yyerror("newline expected after directive"); + yyerrok; } + ; + +%% + +obj_t *repeat_rep_helper(obj_t *sym, obj_t *main, obj_t *parts) +{ + obj_t *single_parts = nil; + obj_t *first_parts = nil; + obj_t *last_parts = nil; + obj_t *empty_parts = nil; + obj_t *iter; + + for (iter = parts; iter != nil; iter = cdr(iter)) { + obj_t *part = car(iter); + obj_t *sym = car(part); + obj_t *clauses = cdr(part); + + if (sym == single) + single_parts = nappend2(single_parts, clauses); + else if (sym == frst) + first_parts = nappend2(first_parts, clauses); + else if (sym == lst) + last_parts = nappend2(last_parts, clauses); + else if (sym == empty) + empty_parts = nappend2(empty_parts, clauses); + else + abort(); + } + + return list(sym, main, single_parts, first_parts, + last_parts, empty_parts, nao); +} + +obj_t *get_spec(void) +{ + return parsed_spec; +} + +void dump_shell_string(const char *str) +{ + int ch; + + putchar('"'); + while ((ch = *str++) != 0) { + switch (ch) { + case '"': case '`': case '$': case '\\': case '\n': + putchar('\\'); + /* fallthrough */ + default: + putchar(ch); + } + } + putchar('"'); +} + +void dump_var(const char *name, char *pfx1, size_t len1, + char *pfx2, size_t len2, obj_t *value, int level) +{ + if (len1 >= 112 || len2 >= 112) + abort(); + + if (stringp(value)) { + fputs(name, stdout); + fputs(pfx1, stdout); + fputs(pfx2, stdout); + putchar('='); + dump_shell_string(c_str(value)); + putchar('\n'); + } else { + obj_t *iter; + int i; + size_t add1 = 0, add2 = 0; + + for (i = 0, iter = value; iter; iter = cdr(iter), i++) { + if (level < opt_arraydims) { + add2 = sprintf(pfx2 + len2, "[%d]", i); + add1 = 0; + } else { + add1 = sprintf(pfx1 + len1, "_%d", i); + add2 = 0; + } + + dump_var(name, pfx1, len1 + add1, pfx2, len2 + add2, car(iter), level + 1); + } + } +} + +void dump_bindings(obj_t *bindings) +{ + if (opt_loglevel >= 2) { + fputs("raw_bindings:\n", stderr); + dump(bindings, stderr); + } + + while (bindings) { + char pfx1[128], pfx2[128]; + obj_t *var = car(car(bindings)); + obj_t *value = cdr(car(bindings)); + const char *name = c_str(symbol_name(var)); + *pfx1 = 0; *pfx2 = 0; + dump_var(name, pfx1, 0, pfx2, 0, value, 0); + bindings = cdr(bindings); + } +} + +obj_t *depth(obj_t *obj) +{ + obj_t *dep = zero; + + if (obj == nil) + return one; + + if (atom(obj)) + return zero; + + while (obj) { + dep = max2(dep, depth(first(obj))); + obj = rest(obj); + } + + return plus(dep, one); +} + +obj_t *merge(obj_t *left, obj_t *right) +{ + obj_t *left_depth = depth(left); + obj_t *right_depth = depth(right); + + while (lt(left_depth, right_depth) || zerop(left_depth)) { + left = cons(left, nil); + left_depth = plus(left_depth, one); + } + + while (lt(right_depth, left_depth) || zerop(right_depth)) { + right = cons(right, nil); + right_depth = plus(right_depth, one); + } + + return append2(left, right); +} + +obj_t *dest_bind(obj_t *bindings, obj_t *pattern, obj_t *value) +{ + if (nullp(pattern)) + return bindings; + + if (symbolp(pattern)) { + obj_t *existing = assoc(bindings, pattern); + if (existing) { + if (tree_find(value, cdr(existing))) + return bindings; + if (tree_find(cdr(existing), value)) + return bindings; + yyerrorf(2, "bind variable mismatch: %s", c_str(symbol_name(pattern))); + return t; + } + return cons(cons(pattern, value), bindings); + } + + if (consp(pattern)) { + obj_t *piter = pattern, *viter = value; + + while (consp(piter) && consp(viter)) + { + bindings = dest_bind(bindings, car(piter), car(viter)); + if (bindings == t) + return t; + piter = cdr(piter); + viter = cdr(viter); + } while (consp(piter) && consp(viter)); + + if (symbolp(piter)) { + bindings = dest_bind(bindings, piter, viter); + if (bindings == t) + return t; + } + } + + return bindings; +} + +obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline, + obj_t *pos, obj_t *spec_lineno, obj_t *data_lineno, + obj_t *file) +{ +#define LOG_MISMATCH(KIND) \ + yyerrorlf(2, c_num(spec_lineno), \ + "%s mismatch, position %ld (%s:%ld)", (KIND), c_num(pos), \ + c_str(file), c_num(data_lineno)); \ + yyerrorlf(2, c_num(spec_lineno), " %s", c_str(dataline)); \ + if (c_num(pos) < 77) \ + yyerrorlf(2, c_num(spec_lineno), " %*s^", (int) c_num(pos), "") + +#define LOG_MATCH(KIND, EXTENT) \ + yyerrorlf(2, c_num(spec_lineno), \ + "%s matched, position %ld-%ld (%s:%ld)", (KIND), \ + c_num(pos), c_num(EXTENT), c_str(file), \ + c_num(data_lineno)); \ + yyerrorlf(2, c_num(spec_lineno), " %s", c_str(dataline)); \ + if (c_num(EXTENT) < 77) \ + yyerrorlf(2, c_num(spec_lineno), " %*s%-*s^", (int) c_num(pos), \ + "", (int) (c_num(EXTENT) - c_num(pos)), "^") + for (;;) { + obj_t *elem; + + if (specline == nil) + break; + + elem = first(specline); + + switch (elem ? elem->t.type : 0) { + case CONS: /* directive */ + { + obj_t *directive = first(elem); + + if (directive == var) { + obj_t *sym = second(elem); + obj_t *pat = third(elem); + obj_t *modifier = fourth(elem); + obj_t *pair = assoc(bindings, sym); /* var exists already? */ + + if (pair) { + /* If the variable already has a binding, we replace + it with its value, and treat it as a string match. + The spec looks like ((var ) ...) + and it must be transformed into + ( ...) */ + if (pat) { + specline = cons(cdr(pair), cons(pat, rest(specline))); + } else if (nump(modifier)) { + obj_t *past = plus(pos, modifier); + + if (c_num(past) > c_num(length_str(dataline)) || + c_num(past) < c_num(pos)) + { + LOG_MISMATCH("fixed field size"); + return nil; + } + + if (!tree_find(trim_str(sub_str(dataline, pos, past)), + cdr(pair))) + { + LOG_MISMATCH("fixed field contents"); + return nil; + } + + LOG_MATCH("fixed field", past); + pos = past; + specline = cdr(specline); + } else { + specline = cons(cdr(pair), rest(specline)); + } + continue; + } else if (pat == nil) { /* match to end of line or with regex */ + if (consp(modifier)) { + obj_t *past = match_regex(dataline, car(modifier), pos); + if (nullp(past)) { + LOG_MISMATCH("var positive regex"); + return nil; + } + LOG_MATCH("var positive regex", past); + bindings = acons_new(bindings, sym, sub_str(dataline, pos, past)); + pos = past; + } else if (nump(modifier)) { + obj_t *past = plus(pos, modifier); + if (c_num(past) > c_num(length_str(dataline)) || + c_num(past) < c_num(pos)) + { + LOG_MISMATCH("count based var"); + return nil; + } + LOG_MATCH("count based var", past); + bindings = acons_new(bindings, sym, trim_str(sub_str(dataline, pos, past))); + pos = past; + } else { + bindings = acons_new(bindings, sym, sub_str(dataline, pos, nil)); + pos = length_str(dataline); + } + } else if (pat->t.type == STR) { + obj_t *find = search_str(dataline, pat, pos, modifier); + if (!find) { + LOG_MISMATCH("var delimiting string"); + return nil; + } + LOG_MATCH("var delimiting string", find); + bindings = acons_new(bindings, sym, sub_str(dataline, pos, find)); + pos = plus(find, length_str(pat)); + } else if (consp(pat) && typeof(first(pat)) == regex) { + obj_t *find = search_regex(dataline, first(pat), pos, modifier); + obj_t *fpos = car(find); + obj_t *flen = cdr(find); + if (!find) { + LOG_MISMATCH("var delimiting regex"); + return nil; + } + LOG_MATCH("var delimiting regex", fpos); + bindings = acons_new(bindings, sym, sub_str(dataline, pos, fpos)); + pos = plus(fpos, flen); + } else if (consp(pat) && first(pat) == var) { + /* Unbound var followed by var: the following one must be bound. */ + obj_t *second_sym = second(pat); + obj_t *next_pat = third(pat); + obj_t *pair = assoc(bindings, second_sym); /* var exists already? */ + + if (!pair) { + yyerrorlf(1, c_num(spec_lineno), "consecutive unbound variables"); + return nil; + } + + /* Re-generate a new spec with an edited version of + the element we just processed, and repeat. */ + { + obj_t *new_elem = list(var, sym, cdr(pair), modifier, nao); + + if (next_pat) + specline = cons(new_elem, cons(next_pat, rest(specline))); + else + specline = cons(new_elem, rest(specline)); + } + + continue; + } else if (consp(pat) && (consp(first(pat)) || stringp(first(pat)))) { + cons_bind (find, len, search_str(dataline, pat, pos, modifier)); + if (!find) { + LOG_MISMATCH("string"); + return nil; + } + bindings = acons_new(bindings, sym, sub_str(dataline, pos, find)); + pos = plus(find, len); + } else { + yyerrorlf(0, c_num(spec_lineno), "variable followed by invalid element"); + return nil; + } + } else if (typeof(directive) == regex) { + obj_t *past = match_regex(dataline, directive, pos); + if (nullp(past)) { + LOG_MISMATCH("regex"); + return nil; + } + LOG_MATCH("regex", past); + pos = past; + } else if (directive == coll) { + obj_t *coll_specline = second(elem); + obj_t *until_specline = third(elem); + obj_t *bindings_coll = nil; + obj_t *iter; + + for (;;) { + cons_bind (new_bindings, new_pos, + match_line(bindings, coll_specline, dataline, pos, + spec_lineno, data_lineno, file)); + + if (new_pos) { + LOG_MATCH("coll", new_pos); + + for (iter = new_bindings; iter && iter != bindings; + iter = cdr(iter)) + { + obj_t *binding = car(iter); + obj_t *existing = assoc(bindings_coll, car(binding)); + + bindings_coll = acons_new(bindings_coll, car(binding), + cons(cdr(binding), cdr(existing))); + } + } + + if (until_specline) { + cons_bind (until_bindings, until_pos, + match_line(bindings, until_specline, dataline, pos, + spec_lineno, data_lineno, file)); + + (void) until_bindings; + if (until_pos) { + /* The until specline matched. Special behavior: + We throw away its bindings, and run it again. + We run it again by incorporating it into the + surrouding specline, just behind the collect + item, which will be popped off. */ + LOG_MATCH("until", until_pos); + (void) new_bindings; + specline = cons(first(specline), + append2(until_specline, rest(specline))); + break; + } + LOG_MISMATCH("until"); + } + + if (new_pos && !equal(new_pos, pos)) { + pos = new_pos; + assert (c_num(pos) <= c_num(length_str(dataline))); + } else { + pos = plus(pos, one); + } + + if (c_num(pos) >= c_num(length_str(dataline))) + break; + } + + + if (!bindings_coll) + yyerrorlf(2, c_num(spec_lineno), "nothing was collected"); + + for (iter = bindings_coll; iter; iter = cdr(iter)) { + obj_t *pair = car(iter); + obj_t *rev = cons(car(pair), nreverse(cdr(pair))); + bindings = cons(rev, bindings); + } + } else if (consp(directive) || stringp(directive)) { + cons_bind (find, len, search_str_tree(dataline, elem, pos, nil)); + obj_t *newpos; + + if (find == nil || !equal(find, pos)) { + LOG_MISMATCH("string tree"); + return nil; + } + + newpos = plus(find, len); + LOG_MATCH("string tree", newpos); + pos = newpos; + } else { + yyerrorlf(0, c_num(spec_lineno), "unknown directive: %s", + c_str(symbol_name(directive))); + } + } + break; + case STR: + { + obj_t *find = search_str(dataline, elem, pos, nil); + obj_t *newpos; + if (find == nil || !equal(find, pos)) { + LOG_MISMATCH("string"); + return nil; + } + newpos = plus(find, length_str(elem)); + LOG_MATCH("string", newpos); + pos = newpos; + break; + } + default: + yyerrorlf(0, c_num(spec_lineno), "unsupported object in spec"); + } + + specline = cdr(specline); + } + + return cons(bindings, pos); +} + +obj_t *format_field(obj_t *string_or_list, obj_t *spec) +{ + if (!stringp(string_or_list)) + return string_or_list; + + { + obj_t *right = lt(spec, zero); + obj_t *width = if3(lt(spec, zero), neg(spec), spec); + obj_t *diff = minus(width, length_str(string_or_list)); + + if (le(diff, zero)) + return string_or_list; + + if (ge(length_str(string_or_list), width)) + return string_or_list; + + { + obj_t *padding = mkstring(diff, chr(' ')); + + return if3(right, + cat_str(list(padding, string_or_list, nao), nil), + cat_str(list(string_or_list, padding, nao), nil)); + } + } +} + +obj_t *subst_vars(obj_t *spec, obj_t *bindings) +{ + list_collect_decl(out, iter); + + while (spec) { + obj_t *elem = first(spec); + + if (consp(elem) && first(elem) == var) { + obj_t *sym = second(elem); + obj_t *pat = third(elem); + obj_t *modifier = fourth(elem); + obj_t *pair = assoc(bindings, sym); + + if (pair) { + if (pat) + spec = cons(cdr(pair), cons(pat, rest(spec))); + else if (nump(modifier)) + spec = cons(format_field(cdr(pair), modifier), rest(spec)); + else + spec = cons(cdr(pair), rest(spec)); + continue; + } + } + + list_collect(iter, elem); + spec = cdr(spec); + } + + return out; +} + +typedef struct fpip { + FILE *f; + DIR *d; + enum { fpip_fclose, fpip_pclose, fpip_closedir } close; +} fpip_t; + +fpip_t complex_open(obj_t *name, obj_t *output) +{ + fpip_t ret = { 0 }; + + const char *namestr = c_str(name); + long len = c_num(length_str(name)); + + if (len == 0) + return ret; + + if (!strcmp(namestr, "-")) { + ret.close = fpip_fclose; + ret.f = output ? stdout : stdin; + output_produced = output ? 1 : 0; + } else if (namestr[0] == '!') { + ret.close = fpip_pclose; + ret.f = popen(namestr+1, output ? "w" : "r"); + } else if (namestr[0] == '$') { + if (output) + return ret; + ret.close = fpip_closedir; + ret.d = opendir(namestr+1); + } else { + ret.close = fpip_fclose; + ret.f = fopen(namestr, output ? "w" : "r"); + } + + return ret; +} + +int complex_open_failed(fpip_t fp) +{ + return fp.f == 0 && fp.d == 0; +} + +void complex_close(fpip_t fp) +{ + if (fp.f == 0) + return; + switch (fp.close) { + case fpip_fclose: + if (fp.f != stdin && fp.f != stdout) + fclose(fp.f); + return; + case fpip_pclose: + pclose(fp.f); + return; + case fpip_closedir: + closedir(fp.d); + return; + } + + abort(); +} + +obj_t *complex_snarf(fpip_t fp, obj_t *name) +{ + switch (fp.close) { + case fpip_fclose: + return lazy_stream_cons(stdio_line_stream(fp.f, name)); + case fpip_pclose: + return lazy_stream_cons(pipe_line_stream(fp.f, name)); + case fpip_closedir: + return lazy_stream_cons(dirent_stream(fp.d, name)); + } + + abort(); +} + +obj_t *robust_length(obj_t *obj) +{ + if (obj == nil) + return zero; + if (atom(obj)) + return negone; + return length(obj); +} + +obj_t *bind_car(obj_t *bind_cons) +{ + return if3(consp(cdr(bind_cons)), + cons(car(bind_cons), car(cdr(bind_cons))), + bind_cons); +} + +obj_t *bind_cdr(obj_t *bind_cons) +{ + return if3(consp(cdr(bind_cons)), + cons(car(bind_cons), cdr(cdr(bind_cons))), + bind_cons); +} + +obj_t *extract_vars(obj_t *output_spec) +{ + list_collect_decl (vars, tai); + + if (consp(output_spec)) { + if (first(output_spec) == var) { + list_collect (tai, second(output_spec)); + } else { + for (; output_spec; output_spec = cdr(output_spec)) + list_collect_nconc(tai, extract_vars(car(output_spec))); + } + } + + return vars; +} + +obj_t *extract_bindings(obj_t *bindings, obj_t *output_spec) +{ + list_collect_decl (bindings_out, tail); + obj_t *var_list = extract_vars(output_spec); + + for (; bindings; bindings = cdr(bindings)) + if (memq(car(car(bindings)), var_list)) + list_collect(tail, car(bindings)); + + return bindings_out; +} + +void do_output_line(obj_t *bindings, obj_t *specline, + obj_t *spec_lineno, FILE *out) +{ + for (; specline; specline = rest(specline)) { + obj_t *elem = first(specline); + + switch (elem ? elem->t.type : 0) { + case CONS: + { + obj_t *directive = first(elem); + + if (directive == var) { + obj_t *str = cat_str(subst_vars(cons(elem, nil), bindings), nil); + if (str == nil) { + yyerrorlf(1, c_num(spec_lineno), "bad substitution: %s", + c_str(symbol_name(second(elem)))); + continue; + } + fputs(c_str(str), out); + } else if (directive == rep) { + obj_t *main_clauses = second(elem); + obj_t *single_clauses = third(elem); + obj_t *first_clauses = fourth(elem); + obj_t *last_clauses = fifth(elem); + obj_t *empty_clauses = sixth(elem); + obj_t *bind_cp = extract_bindings(bindings, elem); + obj_t *max_depth = reduce_left(func_n2(max2), + bind_cp, zero, + chain(list(func_n1(cdr), + func_n1(robust_length), + nao))); + + if (equal(max_depth, zero) && empty_clauses) { + do_output_line(bindings, empty_clauses, spec_lineno, out); + } else if (equal(max_depth, one) && single_clauses) { + obj_t *bind_a = mapcar(func_n1(bind_car), bind_cp); + do_output_line(bind_a, single_clauses, spec_lineno, out); + } else if (!zerop(max_depth)) { + long i; + + for (i = 0; i < c_num(max_depth); i++) { + obj_t *bind_a = mapcar(func_n1(bind_car), bind_cp); + obj_t *bind_d = mapcar(func_n1(bind_cdr), bind_cp); + + if (i == 0 && first_clauses) { + do_output_line(bind_a, first_clauses, spec_lineno, out); + } else if (i == c_num(max_depth) - 1 && last_clauses) { + do_output_line(bind_a, last_clauses, spec_lineno, out); + } else { + do_output_line(bind_a, main_clauses, spec_lineno, out); + } + + bind_cp = bind_d; + } + } + + } else { + yyerrorlf(0, c_num(spec_lineno), "unknown directive: %s", + c_str(symbol_name(directive))); + } + } + break; + case STR: + fputs(c_str(elem), out); + break; + case 0: + break; + default: + yyerrorlf(0, c_num(spec_lineno), "unsupported object in output spec"); + } + } +} + +void do_output(obj_t *bindings, obj_t *specs, FILE *out) +{ + if (equal(specs, null_list)) + return; + + for (; specs; specs = cdr(specs)) { + cons_bind (spec_lineno, specline, first(specs)); + obj_t *first_elem = first(specline); + + if (consp(first_elem)) { + obj_t *sym = first(first_elem); + + if (sym == repeat) { + obj_t *main_clauses = second(first_elem); + obj_t *single_clauses = third(first_elem); + obj_t *first_clauses = fourth(first_elem); + obj_t *last_clauses = fifth(first_elem); + obj_t *empty_clauses = sixth(first_elem); + obj_t *bind_cp = extract_bindings(bindings, first_elem); + obj_t *max_depth = reduce_left(func_n2(max2), + bind_cp, zero, + chain(list(func_n1(cdr), + func_n1(robust_length), + nao))); + + if (equal(max_depth, zero) && empty_clauses) { + do_output(bind_cp, empty_clauses, out); + } else if (equal(max_depth, one) && single_clauses) { + obj_t *bind_a = mapcar(func_n1(bind_car), bind_cp); + do_output(bind_a, single_clauses, out); + } else if (!zerop(max_depth)) { + long i; + + for (i = 0; i < c_num(max_depth); i++) { + obj_t *bind_a = mapcar(func_n1(bind_car), bind_cp); + obj_t *bind_d = mapcar(func_n1(bind_cdr), bind_cp); + + if (i == 0 && first_clauses) { + do_output(bind_a, first_clauses, out); + } else if (i == c_num(max_depth) - 1 && last_clauses) { + do_output(bind_a, last_clauses, out); + } else { + do_output(bind_a, main_clauses, out); + } + + bind_cp = bind_d; + } + } + continue; + } + } + + do_output_line(bindings, specline, spec_lineno, out); + putc('\n', out); + } +} + +obj_t *match_files(obj_t *spec, obj_t *files, + obj_t *bindings, obj_t *first_file_parsed, + obj_t *data_linenum) +{ + obj_t *data = nil; + long data_lineno = 0; + + if (first_file_parsed) { + data = first_file_parsed; + data_lineno = c_num(data_linenum); + first_file_parsed = nil; + } else if (files) { + obj_t *name = first(files); + fpip_t fp = (errno = 0, complex_open(name, nil)); + + yyerrorf(2, "opening data source %s", c_str(name)); + + if (complex_open_failed(fp)) { + if (errno != 0) + yyerrorf(2, "could not open %s: %s", c_str(name), strerror(errno)); + else + yyerrorf(2, "could not open %s", c_str(name)); + return nil; + } + + if ((data = complex_snarf(fp, name)) != nil) + data_lineno = 1; + } + + for (; spec; spec = rest(spec), data = rest(data), data_lineno++) +repeat_spec_same_data: + { + obj_t *specline = rest(first(spec)); + obj_t *dataline = first(data); + obj_t *spec_linenum = first(first(spec)); + obj_t *first_spec = first(specline); + long spec_lineno = spec_linenum ? c_num(spec_linenum) : 0; + + if (consp(first_spec)) { + obj_t *sym = first(first_spec); + + if (sym == skip) { + obj_t *max = first(rest(first_spec)); + long cmax = nump(max) ? c_num(max) : 0; + long reps = 0; + + if (rest(specline)) + yyerrorlf(1, spec_lineno, "material after skip directive ignored"); + + if ((spec = rest(spec)) == nil) + break; + + { + uw_block_begin(nil, result); + + while (dataline && (!max || reps++ < cmax)) { + cons_bind (new_bindings, success, + match_files(spec, files, bindings, + data, num(data_lineno))); + + if (success) { + yyerrorlf(2, spec_lineno, "skip matched %s:%ld", + c_str(first(files)), data_lineno); + result = cons(new_bindings, cons(data, num(data_lineno))); + break; + } + + yyerrorlf(2, spec_lineno, "skip didn't match %s:%ld", + c_str(first(files)), data_lineno); + data = rest(data); + data_lineno++; + dataline = first(data); + } + + uw_block_end; + + if (result) + return result; + } + + yyerrorlf(2, spec_lineno, "skip failed"); + return nil; + } else if (sym == block) { + obj_t *name = first(rest(first_spec)); + if (rest(specline)) + yyerrorlf(1, spec_lineno, "material after block directive ignored"); + if ((spec = rest(spec)) == nil) + break; + uw_block_begin(name, result); + result = match_files(spec, files, bindings, data, num(data_lineno)); + uw_block_end; + return result; + } else if (sym == fail || sym == accept) { + obj_t *target = first(rest(first_spec)); + + if (rest(specline)) + yyerrorlf(1, spec_lineno, "material after %s ignored", + c_str(symbol_name(sym))); + + uw_block_return(target, + if2(sym == accept, + cons(bindings, + if3(data, cons(data, num(data_lineno)), t)))); + if (target) + yyerrorlf(1, spec_lineno, "%s: no block named %s in scope", + c_str(symbol_name(sym)), c_str(symbol_name(target))); + else + yyerrorlf(1, spec_lineno, "%s: not anonymous block in scope", + c_str(symbol_name(sym))); + + return nil; + } else if (sym == next) { + if (rest(first_spec)) + yyerrorlf(0, spec_lineno, "next takes no args"); + + if ((spec = rest(spec)) == nil) + break; + + if (rest(specline)) { + obj_t *sub = subst_vars(rest(specline), bindings); + obj_t *str = cat_str(sub, nil); + if (str == nil) { + yyerrorlf(2, spec_lineno, "bad substitution in next file spec"); + continue; + } + files = cons(str, files); + } else { + files = rest(files); + } + + /* We recursively process the file list, but the new + data position we return to the caller must be in the + original file we we were called with. Hence, we can't + make a straight tail call here. */ + { + cons_bind (new_bindings, success, + match_files(spec, files, bindings, nil, nil)); + if (success) + return cons(new_bindings, + if3(data, cons(data, num(data_lineno)), t)); + return nil; + } + } else if (sym == some || sym == all || sym == none || sym == maybe) { + obj_t *specs; + obj_t *all_match = t; + obj_t *some_match = nil; + obj_t *max_line = zero; + obj_t *max_data = nil; + + for (specs = rest(first_spec); specs != nil; specs = rest(specs)) + { + obj_t *nested_spec = first(specs); + obj_t *data_linenum = num(data_lineno); + + cons_bind (new_bindings, success, + match_files(nested_spec, files, bindings, + data, data_linenum)); + + if (success) { + bindings = new_bindings; + some_match = t; + + if (success == t) { + max_data = t; + } else if (consp(success) && max_data != t) { + cons_bind (new_data, new_line, success); + if (gt(new_line, max_line)) { + max_line = new_line; + max_data = new_data; + } + } + } else { + all_match = nil; + } + } + + if (sym == all && !all_match) { + yyerrorlf(2, spec_lineno, "all: some clauses didn't match"); + return nil; + } + + if (sym == some && !some_match) { + yyerrorlf(2, spec_lineno, "some: no clauses matched"); + return nil; + } + + if (sym == none && some_match) { + yyerrorlf(2, spec_lineno, "none: some clauses matched"); + return nil; + } + + /* No check for maybe, since it always succeeds. */ + + if (consp(max_data)) { + data_lineno = c_num(max_line); + data = max_data; + } else if (max_data == t) { + data = nil; + } + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == collect) { + obj_t *coll_spec = second(first_spec); + obj_t *until_spec = third(first_spec); + obj_t *bindings_coll = nil; + obj_t *iter; + + uw_block_begin(nil, result); + + result = t; + + while (data) { + cons_bind (new_bindings, success, + match_files(coll_spec, files, bindings, + data, num(data_lineno))); + + if (success) { + yyerrorlf(2, spec_lineno, "collect matched %s:%ld", + c_str(first(files)), data_lineno); + + for (iter = new_bindings; iter && iter != bindings; + iter = cdr(iter)) + { + obj_t *binding = car(iter); + obj_t *existing = assoc(bindings_coll, car(binding)); + + bindings_coll = acons_new(bindings_coll, car(binding), + cons(cdr(binding), cdr(existing))); + } + } + + /* Until clause sees un-collated bindings from collect. */ + if (until_spec) + { + cons_bind (discarded_bindings, success, + match_files(until_spec, files, new_bindings, + data, num(data_lineno))); + + if (success) { + /* The until spec matched. Special behavior: + We throw away its bindings, and run it again. + We run it again by incorporating it into the + surrouding spec, just behind the topmost one. + When we bail out of this loop, the first(spec) + will be popped, exposing the until_spec, + and then the main loop is repeated. */ + (void) discarded_bindings; + spec = cons(first(spec), append2(until_spec, rest(spec))); + break; + } + } + + if (success) { + if (consp(success)) { + yyerrorlf(2, spec_lineno, + "collect advancing from line %ld to %ld", + data_lineno, c_num(cdr(success))); + data = car(success); + data_lineno = c_num(cdr(success)); + } else { + yyerrorlf(2, spec_lineno, "collect consumed entire file"); + data = nil; + break; + } + } else { + data = rest(data); + data_lineno++; + } + } + + uw_block_end; + + if (!result) { + yyerrorlf(2, spec_lineno, "collect explicitly failed"); + return nil; + } + + if (!bindings_coll) + yyerrorlf(2, spec_lineno, "nothing was collected"); + + for (iter = bindings_coll; iter; iter = cdr(iter)) { + obj_t *pair = car(iter); + obj_t *rev = cons(car(pair), nreverse(cdr(pair))); + bindings = cons(rev, bindings); + } + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == flattn) { + obj_t *iter; + + for (iter = rest(first_spec); iter; iter = rest(iter)) { + obj_t *sym = first(iter); + + if (!symbolp(sym)) { + yyerrorlf(1, spec_lineno, "non-symbol in flatten directive"); + continue; + } else { + obj_t *existing = assoc(bindings, sym); + + if (existing) + *cdr_l(existing) = flatten(cdr(existing)); + } + } + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == forget) { + bindings = alist_remove(bindings, rest(first_spec)); + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == mrge) { + obj_t *target = first(rest(first_spec)); + obj_t *args = rest(rest(first_spec)); + obj_t *exists = assoc(bindings, target); + obj_t *merged = nil; + + if (!target || !symbolp(target)) + yyerrorlf(1, spec_lineno, "bad merge directive"); + + if (exists) + yyerrorlf(1, spec_lineno, "merge: symbol %s already bound", + c_str(symbol_name(target))); + + for (; args; args = rest(args)) { + obj_t *other_sym = first(args); + + if (other_sym) { + obj_t *other_lookup = assoc(bindings, other_sym); + + if (!symbolp(other_sym)) + yyerrorlf(1, spec_lineno, "non-symbol in merge directive"); + else if (!other_lookup) + yyerrorlf(1, spec_lineno, "merge: nonexistent symbol %s", + c_str(symbol_name(sym))); + + if (merged) + merged = merge(merged, cdr(other_lookup)); + else + merged = cdr(other_lookup); + } + } + + bindings = acons_new(bindings, target, merged); + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == bind) { + obj_t *args = rest(first_spec); + obj_t *pattern = first(args); + obj_t *var = second(args); + obj_t *lookup = assoc(bindings, var); + + if (!var || !symbolp(var)) + yyerrorlf(1, spec_lineno, "bind: bad variable spec"); + else if (!lookup) + yyerrorlf(1, spec_lineno, "bind: unbound source variable"); + + bindings = dest_bind(bindings, pattern, cdr(lookup)); + + if (bindings == t) + return nil; + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == cat) { + obj_t *iter; + + for (iter = rest(first_spec); iter; iter = rest(iter)) { + obj_t *sym = first(iter); + + if (!symbolp(sym)) { + yyerrorlf(1, spec_lineno, "non-symbol in cat directive"); + continue; + } else { + obj_t *existing = assoc(bindings, sym); + obj_t *sep = nil; + + if (rest(specline)) { + obj_t *sub = subst_vars(rest(specline), bindings); + sep = cat_str(sub, nil); + } + + if (existing) + *cdr_l(existing) = cat_str(flatten(cdr(existing)), sep); + } + } + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } else if (sym == output) { + obj_t *specs = second(first_spec); + obj_t *dest_opt = third(first_spec); + obj_t *dest = dest_opt ? cat_str(subst_vars(dest_opt, bindings), nil) + : string(chk_strdup("-")); + fpip_t fp = (errno = 0, complex_open(dest, t)); + + yyerrorf(2, "opening data sink %s", c_str(dest)); + + if (complex_open_failed(fp)) { + if (errno != 0) + yyerrorf(2, "could not open %s: %s", c_str(dest), strerror(errno)); + else + yyerrorf(2, "could not open %s", c_str(dest)); + } else { + do_output(bindings, specs, fp.f); + complex_close(fp); + } + + if ((spec = rest(spec)) == nil) + break; + + goto repeat_spec_same_data; + } + } + + if (dataline == nil) + return nil; + + { + cons_bind (new_bindings, success, + match_line(bindings, specline, dataline, zero, + spec_linenum, num(data_lineno), first(files))); + + if (nump(success) && c_num(success) < c_num(length_str(dataline))) { + yyerrorf(2, "spec only matches line to position %ld: %s", + c_num(success), c_str(dataline)); + return nil; + } + + if (!success) + return nil; + + bindings = new_bindings; + } + } + + return cons(bindings, if3(data, cons(data, num(data_lineno)), t)); +} + +int extract(obj_t *spec, obj_t *files, obj_t *predefined_bindings) +{ + cons_bind (bindings, success, match_files(spec, files, predefined_bindings, + nil, nil)); + + if (!output_produced) { + if (!opt_nobindings) { + if (bindings) { + bindings = nreverse(bindings); + dump_bindings(bindings); + } + } + + if (!success) + puts("false"); + } + + return success ? 0 : EXIT_FAILURE; +} diff --git a/gc.c b/gc.c new file mode 100644 index 00000000..2b98887b --- /dev/null +++ b/gc.c @@ -0,0 +1,368 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include "lib.h" +#include "gc.h" + +#define PROT_STACK_SIZE 1024 +#define HEAP_SIZE 16384 +#define REACHABLE 0x100 +#define FREE 0x200 + +typedef struct heap { + struct heap *next; + obj_t block[HEAP_SIZE]; +} heap_t; + +int opt_gc_debug; +obj_t **gc_stack_top; + +static obj_t **prot_stack[PROT_STACK_SIZE]; +static obj_t ***prot_stack_limit = prot_stack + PROT_STACK_SIZE; +static obj_t ***top = prot_stack; + +static obj_t *free_list, **free_tail = &free_list; +static heap_t *heap_list; + +int gc_enabled = 1; + +obj_t *prot1(obj_t **loc) +{ + assert (top < prot_stack_limit); + *top++ = loc; + return nil; /* for use in macros */ +} + +void rel1(obj_t **loc) +{ + /* protect and release calls must nest. */ + if (*--top != loc) + abort(); +} + +void protect(obj_t **first, ...) +{ + obj_t **next = first; + va_list vl; + va_start (vl, first); + + while (next) { + prot1(next); + next = va_arg(vl, obj_t **); + } + + va_end (vl); +} + +void release(obj_t **last, ...) +{ + obj_t **next = last; + va_list vl; + va_start (vl, last); + + while (next) { + rel1(next); + next = va_arg(vl, obj_t **); + } + + va_end (vl); +} + +static void more() +{ + heap_t *heap = (heap_t *) chk_malloc(sizeof *heap); + obj_t *block = heap->block, *end = heap->block + HEAP_SIZE; + + while (block < end) { + block->t.next = free_list; + block->t.type = FREE; + free_list = block++; + } + + free_tail = &block[-1].t.next; + + heap->next = heap_list; + heap_list = heap; +} + +obj_t *make_obj(void) +{ + int try; + + if (opt_gc_debug) + gc(); + + for (try = 0; try < 3; try++) { + if (free_list) { + obj_t *ret = free_list; + free_list = free_list->t.next; + return ret; + } + + free_tail = &free_list; + + switch (try) { + case 0: gc(); break; + case 1: more(); break; + } + } + + return 0; +} + +static void finalize(obj_t *obj) +{ + switch (obj->t.type) { + case CONS: + break; + case STR: + if (!opt_gc_debug) { + free(obj->st.str); + obj->st.str = 0; + } + break; + case CHR: + case NUM: + case SYM: + case FUN: + break; + case VEC: + if (!opt_gc_debug) { + free(obj->v.vec-2); + obj->v.vec = 0; + } + break; + case STREAM: + stream_close(obj); + break; + case LCONS: + break; + case COBJ: + obj->co.ops->destroy(obj); + break; + default: + assert (0 && "corrupt type field"); + } +} + +static void mark_obj(obj_t *obj) +{ + type_t t; + + if (obj == nil) + return; + + t = obj->t.type; + + if ((t & REACHABLE) != 0) + return; + + if ((t & FREE) != 0) + abort(); + + obj->t.type |= REACHABLE; + + switch (t) { + case CONS: + mark_obj(obj->c.car); + mark_obj(obj->c.cdr); + break; + case STR: + mark_obj(obj->st.len); + break; + case CHR: + case NUM: + break; + case SYM: + mark_obj(obj->s.name); + mark_obj(obj->s.val); + break; + case FUN: + mark_obj(obj->f.env); + if (obj->f.functype == FINTERP) + mark_obj(obj->f.f.interp_fun); + break; + case VEC: + { + obj_t *alloc_size = obj->v.vec[-2]; + obj_t *fill_ptr = obj->v.vec[-1]; + long i, fp = c_num(fill_ptr); + + mark_obj(alloc_size); + mark_obj(fill_ptr); + + for (i = 0; i < fp; i++) + mark_obj(obj->v.vec[i]); + } + break; + case STREAM: + mark_obj(obj->sm.label_pushback); + break; + case LCONS: + mark_obj(obj->lc.car); + mark_obj(obj->lc.cdr); + mark_obj(obj->lc.func); + break; + case COBJ: + mark_obj(obj->co.cls); + break; + default: + assert (0 && "corrupt type field"); + } +} + +static int in_heap(obj_t *ptr) +{ + heap_t *heap; + + for (heap = heap_list; heap != 0; heap = heap->next) { + if (ptr >= heap->block && ptr < heap->block + HEAP_SIZE) + if (((char *) ptr - (char *) heap->block) % sizeof (obj_t) == 0) + return 1; + } + + return 0; +} + +static void mark_mem_region(obj_t **bottom, obj_t **top) +{ + if (bottom > top) { + obj_t **tmp = top; + top = bottom; + bottom = tmp; + } + + while (bottom < top) { + obj_t *maybe_obj = *bottom; + if (in_heap(maybe_obj)) { + type_t t = maybe_obj->t.type; + if ((t & FREE) == 0) + mark_obj(maybe_obj); + } + bottom++; + } +} + +static void mark(void) +{ + obj_t *gc_stack_bottom; + obj_t ***rootloc; + + /* + * First, scan the officially registered locations. + */ + + for (rootloc = prot_stack; rootloc != top; rootloc++) { + if (*rootloc) /* stack may have nulls */ + mark_obj(**rootloc); + } + + mark_mem_region(&gc_stack_bottom, gc_stack_top); +} + +static void sweep(void) +{ + heap_t *heap; + int dbg = opt_gc_debug; + long freed = 0; + + for (heap = heap_list; heap != 0; heap = heap->next) { + obj_t *block, *end; + for (block = heap->block, end = heap->block + HEAP_SIZE; + block < end; + block++) + { + if (block->t.type & REACHABLE) { + block->t.type &= ~REACHABLE; + continue; + } + + if (block->t.type & FREE) + continue; + + if (0 && dbg) { + fprintf(stderr, "%s: finalizing: ", progname); + obj_print(block, stderr); + putc('\n', stderr); + } + finalize(block); + block->t.type |= FREE; + if (dbg) { + *free_tail = block; + block->t.next = nil; + free_tail = &block->t.next; + } else { + block->t.next = free_list; + free_list = block; + } + freed++; + } + } + + if (dbg) + fprintf(stderr, "%s: gc freed %ld blocks\n", progname, freed); +} + +void gc(void) +{ + if (gc_enabled) { + jmp_buf jmp; + setjmp(jmp); + mark(); + sweep(); + } +} + +int gc_state(int enabled) +{ + int old = gc_enabled; + gc_enabled = enabled; + return old; +} + +/* + * Useful functions for gdb'ing. + */ +void unmark(void) +{ + heap_t *heap; + + for (heap = heap_list; heap != 0; heap = heap->next) { + obj_t *block, *end; + for (block = heap->block, end = heap->block + HEAP_SIZE; + block < end; + block++) + { + block->t.type &= ~(FREE | REACHABLE); + } + } +} diff --git a/gc.h b/gc.h new file mode 100644 index 00000000..aaafbec2 --- /dev/null +++ b/gc.h @@ -0,0 +1,36 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +extern int opt_gc_debug; +extern obj_t **gc_stack_top; + +obj_t *prot1(obj_t **loc); +void rel1(obj_t **loc); +void protect(obj_t **, ...); +void release(obj_t **, ...); +obj_t *make_obj(void); +void gc(void); +int gc_state(int); diff --git a/lib.c b/lib.c new file mode 100644 index 00000000..348b54f3 --- /dev/null +++ b/lib.c @@ -0,0 +1,1609 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lib.h" +#include "gc.h" + +#define max(a, b) ((a) > (b) ? (a) : (b)) + +obj_t *interned_syms; + +obj_t *null, *t, *cons_t, *str_t, *chr_t, *num_t, *sym_t, *fun_t, *vec_t; +obj_t *stream_t, *lcons_t, *var, *regex, *set, *cset, *wild, *oneplus; +obj_t *zeroplus, *optional, *compound, *or; +obj_t *skip, *block, *next, *fail, *accept; +obj_t *all, *some, *none, *maybe, *collect, *until, *coll; +obj_t *output, *single, *frst, *lst, *empty, *repeat, *rep; +obj_t *flattn, *forget, *mrge, *bind, *cat, *dir; + +obj_t *zero, *one, *two, *negone, *maxint, *minint; +obj_t *null_string; +obj_t *nil_string; +obj_t *null_list; + +obj_t *identity_f; +obj_t *equal_f; + +const char *progname; +void *(*oom_realloc)(void *, size_t); + + +obj_t *identity(obj_t *obj) +{ + return obj; +} + +static obj_t *identity_tramp(obj_t *env, obj_t *obj) +{ + (void) env; + return identity(obj); +} + +static obj_t *equal_tramp(obj_t *env, obj_t *, obj_t *); + +obj_t *typeof(obj_t *obj) +{ + if (obj == nil) + return null; + switch (obj->t.type) { + case CONS: return cons_t; + case STR: return str_t; + case CHR: return chr_t; + case NUM: return num_t; + case SYM: return sym_t; + case FUN: return fun_t; + case VEC: return vec_t; + case STREAM: return stream_t; + case LCONS: return lcons_t; + case COBJ: return obj->co.cls; + } + assert (0 && "corrupt type field"); +} + +obj_t *car(obj_t *cons) +{ + if (cons == nil) + return nil; + else switch (cons->t.type) { + case CONS: + return cons->c.car; + case LCONS: + if (cons->lc.func == nil) { + return cons->lc.car; + } else { + if (!funcall1(cons->lc.func, cons)) + return nil; + return cons->lc.car; + } + default: + assert (0 && "corrupt type field"); + } +} + +obj_t *cdr(obj_t *cons) +{ + if (cons == nil) + return nil; + else switch (cons->t.type) { + case CONS: + return cons->c.cdr; + case LCONS: + if (cons->lc.func == nil) { + return cons->lc.cdr; + } else { + if (!funcall1(cons->lc.func, cons)) + return nil; + return cons->lc.cdr; + } + default: + assert (0 && "corrupt type field"); + } +} + +obj_t **car_l(obj_t *cons) +{ + switch (cons->t.type) { + case CONS: + return &cons->c.car; + case LCONS: + funcall1(cons->lc.func, cons); + return &cons->lc.car; + default: + assert (0 && "corrupt type field"); + } +} + +obj_t **cdr_l(obj_t *cons) +{ + switch (cons->t.type) { + case CONS: + return &cons->c.cdr; + case LCONS: + funcall1(cons->lc.func, cons); + return &cons->lc.cdr; + default: + assert (0 && "corrupt type field"); + } +} + +obj_t *first(obj_t *cons) +{ + return car(cons); +} + +obj_t *rest(obj_t *cons) +{ + return cdr(cons); +} + +obj_t *second(obj_t *cons) +{ + return car(cdr(cons)); +} + +obj_t *third(obj_t *cons) +{ + return car(cdr(cdr(cons))); +} + +obj_t *fourth(obj_t *cons) +{ + return car(cdr(cdr(cdr(cons)))); +} + +obj_t *fifth(obj_t *cons) +{ + return car(cdr(cdr(cdr(cdr(cons))))); +} + +obj_t *sixth(obj_t *cons) +{ + return car(cdr(cdr(cdr(cdr(cdr(cons)))))); +} + +obj_t **tail(obj_t *cons) +{ + while (cdr(cons)) + cons = cdr(cons); + return cdr_l(cons); +} + +obj_t *copy_list(obj_t *list) +{ + list_collect_decl (out, tail); + + while (consp(list)) { + list_collect(tail, car(list)); + list = cdr(list); + } + + list_collect_terminate(tail, list); + + return out; +} + +obj_t *nreverse(obj_t *in) +{ + obj_t *rev = nil; + + while (in) { + obj_t *temp = cdr(in); + *cdr_l(in) = rev; + rev = in; + in = temp; + } + + return rev; +} + +obj_t *reverse(obj_t *in) +{ + obj_t *rev = nil; + + while (in) { + rev = cons(car(in), rev); + in = cdr(in); + } + + return rev; +} + +obj_t *append2(obj_t *list1, obj_t *list2) +{ + list_collect_decl (out, tail); + + while (list1) { + list_collect(tail, car(list1)); + list1 = cdr(list1); + } + + list_collect_terminate(tail, list2); + return out; +} + +obj_t *nappend2(obj_t *list1, obj_t *list2) +{ + obj_t *temp, *iter; + + if (list1 == nil) + return list2; + + for (iter = list1; (temp = cdr(iter)) != nil; iter = temp) + ; /* empty */ + + *cdr_l(iter) = list2; + return list1; +} + +obj_t *flatten_helper(obj_t *env, obj_t *item) +{ + return flatten(item); +} + +obj_t *memq(obj_t *obj, obj_t *list) +{ + while (list && car(list) != obj) + list = cdr(list); + return list; +} + +obj_t *tree_find(obj_t *obj, obj_t *tree) +{ + if (equal(obj, tree)) + return t; + else if (consp(tree)) + return some_satisfy(tree, bind2(func_n2(tree_find), obj), nil); + return nil; +} + +obj_t *some_satisfy(obj_t *list, obj_t *pred, obj_t *key) +{ + if (!key) + key = identity_f; + + for (; list; list = cdr(list)) { + if (funcall1(pred, funcall1(key, car(list)))) + return t; + } + + return nil; +} + +obj_t *flatten(obj_t *list) +{ + if (atom(list)) + return cons(list, nil); + + return mappend(func_f1(nil, flatten_helper), list); +} + +long c_num(obj_t *num); + +obj_t *equal(obj_t *left, obj_t *right) +{ + if (left == nil && right == nil) + return t; + + if (left == nil || right == nil) + return nil; + + switch (left->t.type) { + case CONS: + case LCONS: + if ((right->t.type == CONS || left->t.type == LCONS) && + equal(car(left), car(right)) && + equal(cdr(left), cdr(right))) + { + return t; + } + return nil; + case STR: + if (right->t.type == STR && + strcmp(left->st.str, right->st.str) == 0) + return t; + return nil; + case CHR: + if (right->t.type == CHR && + left->ch.ch == right->ch.ch) + return t; + return nil; + case NUM: + if (right->t.type == NUM && + left->n.val == right->n.val) + return t; + return nil; + case SYM: + return right == left ? t : nil; + case FUN: + if (right->t.type == FUN && + left->f.functype == right->f.functype) + { + switch (left->f.functype) { + case FINTERP: return (equal(left->f.f.interp_fun, right->f.f.interp_fun)); + case F0: return (left->f.f.f0 == right->f.f.f0) ? t : nil; + case F1: return (left->f.f.f1 == right->f.f.f1) ? t : nil; + case F2: return (left->f.f.f2 == right->f.f.f2) ? t : nil; + case F3: return (left->f.f.f3 == right->f.f.f3) ? t : nil; + case F4: return (left->f.f.f4 == right->f.f.f4) ? t : nil; + case N0: return (left->f.f.n0 == right->f.f.n0) ? t : nil; + case N1: return (left->f.f.n1 == right->f.f.n1) ? t : nil; + case N2: return (left->f.f.n2 == right->f.f.n2) ? t : nil; + case N3: return (left->f.f.n3 == right->f.f.n3) ? t : nil; + case N4: return (left->f.f.n4 == right->f.f.n4) ? t : nil; + } + return nil; + } + case VEC: + if (right->t.type == VEC) { + long i, fill; + if (!equal(left->v.vec[vec_fill], right->v.vec[vec_fill])) + return nil; + fill = c_num(left->v.vec[vec_fill]); + for (i = 0; i < fill; i++) { + if (!equal(left->v.vec[i], right->v.vec[i])) + return nil; + } + return t; + } + break; + case STREAM: + return nil; /* Different stream objects never equal. */ + case COBJ: + if (right->t.type == COBJ) + return left->co.ops->equal(left, right); + } + + assert (0 && "notreached"); + return nil; +} + +static obj_t *equal_tramp(obj_t *env, obj_t *left, obj_t *right) +{ + (void) env; + return equal(left, right); +} + +void *chk_malloc(size_t size) +{ + void *ptr = malloc(size); + if (size && ptr == 0) + ptr = oom_realloc(0, size); + return ptr; +} + +void *chk_realloc(void *old, size_t size) +{ + void *newptr = realloc(old, size); + if (size != 0 && newptr == 0) + newptr = oom_realloc(old, size); + return newptr; +} + +void *chk_strdup(const char *str) +{ + size_t size = strlen(str) + 1; + char *copy = chk_malloc(size); + memcpy(copy, str, size); + return copy; +} + + +obj_t *cons(obj_t *car, obj_t *cdr) +{ + obj_t *obj = make_obj(); + obj->c.type = CONS; + obj->c.car = car; + obj->c.cdr = cdr; + return obj; +} + +obj_t *list(obj_t *first, ...) +{ + va_list vl; + obj_t *list = nil; + obj_t *array[32], **ptr = array; + + if (first != nao) { + obj_t *next = first; + + va_start (vl, first); + + do { + *ptr++ = next; + if (ptr == array + 32) + abort(); + next = va_arg(vl, obj_t *); + } while (next != nao); + + while (ptr > array) + list = cons(*--ptr, list); + } + + return list; +} + +obj_t *consp(obj_t *obj) +{ + if (!obj) + return nil; + return (obj->t.type == CONS || obj->t.type == LCONS) ? t : nil; +} + +obj_t *nullp(obj_t *obj) +{ + return obj == 0 ? t : nil; +} + +obj_t *atom(obj_t *obj) +{ + return (obj == nil || (obj->t.type != CONS && obj->t.type != LCONS)) + ? t : nil; +} + +obj_t *listp(obj_t *obj) +{ + return (obj == nil || obj->t.type == CONS || obj->t.type == LCONS) + ? t : nil; +} + +obj_t *length(obj_t *list) +{ + long len = 0; + while (consp(list)) { + len++; + list = cdr(list); + } + return num(len); +} + +obj_t *num(long val) +{ + obj_t *obj = make_obj(); + obj->n.type = NUM; + obj->n.val = val; + return obj; +} + +long c_num(obj_t *num) +{ + assert (num && num->t.type == NUM); + return num->n.val; +} + +obj_t *nump(obj_t *num) +{ + return (num && num->n.type == NUM) ? t : nil; +} + +obj_t *plus(obj_t *anum, obj_t *bnum) +{ + long a = c_num(anum); + long b = c_num(bnum); + + assert (a <= 0 || b <= 0 || LONG_MAX - b >= a); + assert (a >= 0 || b >= 0 || LONG_MIN - b >= a); + + return num(a + b); +} + +obj_t *minus(obj_t *anum, obj_t *bnum) +{ + long a = c_num(anum); + long b = c_num(bnum); + + assert (b != LONG_MIN || LONG_MIN == -LONG_MAX); + assert (a <= 0 || -b <= 0 || LONG_MAX + b >= a); + assert (a >= 0 || -b >= 0 || LONG_MIN + b >= a); + + return num(a - b); +} + +obj_t *neg(obj_t *anum) +{ + long n = c_num(anum); + return num(-n); +} + +obj_t *zerop(obj_t *num) +{ + return c_num(num) == 0 ? t : nil; +} + +obj_t *gt(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) > c_num(bnum) ? t : nil; +} + +obj_t *lt(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) < c_num(bnum) ? t : nil; +} + +obj_t *ge(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) >= c_num(bnum) ? t : nil; +} + +obj_t *le(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) <= c_num(bnum) ? t : nil; +} + +obj_t *numeq(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) == c_num(bnum) ? t : nil; +} + +obj_t *max2(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) > c_num(bnum) ? anum : bnum; +} + +obj_t *min2(obj_t *anum, obj_t *bnum) +{ + return c_num(anum) < c_num(bnum) ? anum : bnum; +} + +obj_t *string(char *str) +{ + obj_t *obj = make_obj(); + obj->st.type = STR; + obj->st.str = str; + obj->st.len = nil; + return obj; +} + +obj_t *mkstring(obj_t *len, obj_t *ch) +{ + char *str = chk_malloc(c_num(len) + 1); + memset(str, c_chr(ch), c_num(len)); + str[c_num(len)] = 0; + return string(str); +} + +obj_t *copy_str(obj_t *str) +{ + return string(strdup(c_str(str))); +} + +obj_t *stringp(obj_t *str) +{ + return (str && str->st.type == STR) ? t : nil; +} + +obj_t *length_str(obj_t *str) +{ + assert (str && str->t.type == STR); + if (!str->st.len) + str->st.len = num(strlen(str->st.str)); + return str->st.len; +} + +const char *c_str(obj_t *str) +{ + assert (str && str->t.type == STR); + return str->st.str; +} + +obj_t *search_str(obj_t *haystack, obj_t *needle, obj_t *start_num, + obj_t *from_end) +{ + const char *h = c_str(haystack); + long len = c_num(length_str(haystack)); + long start = c_num(start_num); + + if (start > len) { + return nil; + } else { + const char *n = c_str(needle), *good = 0, *pos, *from = h + start; + + do { + pos = strstr(from, n); + } while (pos && (good = pos) && from_end && *(from = pos + 1)); + return (good == 0) ? nil : num(good - h); + } +} + +obj_t *search_str_tree(obj_t *haystack, obj_t *tree, obj_t *start_num, + obj_t *from_end) +{ + if (stringp(tree)) { + obj_t *result = search_str(haystack, tree, start_num, from_end); + if (result) + return cons(result, length_str(tree)); + } else if (consp(tree)) { + while (tree) { + obj_t *result = search_str_tree(haystack, car(tree), start_num, from_end); + if (result) + return result; + tree = cdr(tree); + } + } + + return nil; +} + +obj_t *sub_str(obj_t *str_in, obj_t *from_num, obj_t *to_num) +{ + const char *str = c_str(str_in); + size_t len = c_num(length_str(str_in)); + long from = c_num(from_num); + long to = to_num ? c_num(to_num) : len; + + if (to < 0) + to = 0; + if (from < 0) + from = 0; + if (from > len) + from = len; + if (to > len) + to = len; + + if (from >= to) { + return null_string; + } else { + size_t size = to - from + 1; + char *sub = chk_malloc(size); + strncpy(sub, str + from, size); + sub[size-1] = 0; + return string(sub); + } +} + +obj_t *cat_str(obj_t *list, obj_t *sep) +{ + long total = 0; + obj_t *iter; + char *str, *ptr; + long len_sep = sep ? c_num(length_str(sep)) : 0; + + for (iter = list; iter != nil; iter = cdr(iter)) { + obj_t *item = car(iter); + if (!item) + continue; + if (!stringp(item)) + return nil; + total += c_num(length_str(item)); + if (len_sep && cdr(iter)) + total += len_sep; + } + + str = chk_malloc(total + 1); + + for (ptr = str, iter = list; iter != nil; iter = cdr(iter)) { + obj_t *item = car(iter); + long len; + if (!item) + continue; + len = c_num(length_str(item)); + memcpy(ptr, c_str(item), len); + ptr += len; + if (len_sep && cdr(iter)) { + memcpy(ptr, c_str(sep), len_sep); + ptr += len_sep; + } + } + *ptr = 0; + + return string(str); +} + +obj_t *trim_str(obj_t *str) +{ + const char *start = c_str(str); + const char *end = start + c_num(length_str(str)); + + while (start[0] && isspace(start[0])) + start++; + + while (end > start && isspace(end[-1])) + end--; + + if (end == start) { + return null_string; + } else { + size_t len = end - start; + char *new = chk_malloc(len + 1); + memcpy(new, start, len); + new[len] = 0; + return string(new); + } +} + +obj_t *chr(int ch) +{ + obj_t *obj = make_obj(); + obj->ch.type = CHR; + obj->ch.ch = ch; + return obj; +} + +int c_chr(obj_t *chr) +{ + assert (chr && chr->t.type == CHR); + return chr->ch.ch; +} + +obj_t *sym_name(obj_t *sym) +{ + assert (sym && sym->t.type == SYM); + return sym->s.name; +} + +obj_t *make_sym(obj_t *name) +{ + obj_t *obj = make_obj(); + obj->s.type = SYM; + obj->s.name = name; + obj->s.val = nil; + return obj; +} + +obj_t *intern(obj_t *str) +{ + obj_t *iter; + + for (iter = interned_syms; iter != nil; iter = cdr(iter)) { + obj_t *sym = car(iter); + if (equal(sym_name(sym), str)) + return sym; + } + + interned_syms = cons(make_sym(str), interned_syms); + return car(interned_syms); +} + +obj_t *symbolp(obj_t *sym) +{ + return (sym == nil || sym->s.type == SYM) ? t : nil; +} + +obj_t *symbol_name(obj_t *sym) +{ + assert (sym == nil || sym->t.type == SYM); + return sym ? sym->s.name : nil_string; +} + +obj_t *func_f0(obj_t *env, obj_t *(*fun)(obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = F0; + obj->f.env = env; + obj->f.f.f0 = fun; + return obj; +} + +obj_t *func_f1(obj_t *env, obj_t *(*fun)(obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = F1; + obj->f.env = env; + obj->f.f.f1 = fun; + return obj; +} + +obj_t *func_f2(obj_t *env, obj_t *(*fun)(obj_t *, obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = F2; + obj->f.env = env; + obj->f.f.f2 = fun; + return obj; +} + +obj_t *func_f3(obj_t *env, obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = F3; + obj->f.env = env; + obj->f.f.f3 = fun; + return obj; +} + +obj_t *func_f4(obj_t *env, obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *, + obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = F4; + obj->f.env = env; + obj->f.f.f4 = fun; + return obj; +} + +obj_t *func_n0(obj_t *(*fun)(void)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = N0; + obj->f.env = nil; + obj->f.f.n0 = fun; + return obj; +} + +obj_t *func_n1(obj_t *(*fun)(obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = N1; + obj->f.env = nil; + obj->f.f.n1 = fun; + return obj; +} + +obj_t *func_n2(obj_t *(*fun)(obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = N2; + obj->f.env = nil; + obj->f.f.n2 = fun; + return obj; +} + +obj_t *func_n3(obj_t *(*fun)(obj_t *, obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = N3; + obj->f.f.n3 = fun; + return obj; +} + +obj_t *func_n4(obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *)) +{ + obj_t *obj = make_obj(); + obj->f.type = FUN; + obj->f.functype = N4; + obj->f.f.n4 = fun; + return obj; +} + + +obj_t *apply(obj_t *fun, obj_t *arglist) +{ + obj_t *arg[4], **p = arg; + + assert (fun && fun->f.type == FUN); + assert (arglist == nil || consp(arglist)); + + *p++ = car(arglist); arglist = cdr(arglist); + *p++ = car(arglist); arglist = cdr(arglist); + *p++ = car(arglist); arglist = cdr(arglist); + *p++ = car(arglist); arglist = cdr(arglist); + + switch (fun->f.functype) { + case F0: + return fun->f.f.f0(fun); + case F1: + return fun->f.f.f1(fun, arg[0]); + case F2: + return fun->f.f.f2(fun, arg[0], arg[1]); + case F3: + return fun->f.f.f3(fun, arg[0], arg[1], arg[2]); + case F4: + return fun->f.f.f4(fun, arg[0], arg[1], arg[2], arg[3]); + case N0: + return fun->f.f.n0(); + case N1: + return fun->f.f.n1(arg[0]); + case N2: + return fun->f.f.n2(arg[0], arg[1]); + case N3: + return fun->f.f.n3(arg[0], arg[1], arg[2]); + case N4: + return fun->f.f.n4(arg[0], arg[1], arg[2], arg[3]); + case FINTERP: + abort(); + } + + assert (0 && "bad functype"); +} + +obj_t *funcall(obj_t *fun) +{ + assert (fun && fun->f.type == FUN); + + switch (fun->f.functype) { + case F0: + return fun->f.f.f0(fun->f.env); + case N0: + return fun->f.f.n0(); + default: + abort(); + } +} + +obj_t *funcall1(obj_t *fun, obj_t *arg) +{ + assert (fun && fun->f.type == FUN); + + switch (fun->f.functype) { + case F1: + return fun->f.f.f1(fun->f.env, arg); + case N1: + return fun->f.f.n1(arg); + default: + abort(); + } +} + +obj_t *funcall2(obj_t *fun, obj_t *arg1, obj_t *arg2) +{ + assert (fun && fun->f.type == FUN); + + switch (fun->f.functype) { + case F2: + return fun->f.f.f2(fun->f.env, arg1, arg2); + case N2: + return fun->f.f.n2(arg1, arg2); + default: + abort(); + } +} + +obj_t *reduce_left(obj_t *fun, obj_t *list, obj_t *init, obj_t *key) +{ + if (!key) + key = identity_f; + + for (; list; list = cdr(list)) + init = funcall2(fun, init, funcall1(key, car(list))); + + return init; +} + +obj_t *do_bind2(obj_t *fcons, obj_t *arg2) +{ + return funcall2(car(fcons), cdr(fcons), arg2); +} + +obj_t *bind2(obj_t *fun2, obj_t *arg) +{ + return func_f1(cons(fun2, arg), do_bind2); +} + +static obj_t *do_chain(obj_t *fun1_list, obj_t *arg) +{ + for (; fun1_list; fun1_list = cdr(fun1_list)) + arg = funcall1(car(fun1_list), arg); + + return arg; +} + +obj_t *chain(obj_t *fun1_list) +{ + return func_f1(fun1_list, do_chain); +} + +obj_t *vector(obj_t *alloc) +{ + long alloc_plus = c_num(alloc) + 2; + obj_t *vec = make_obj(); + obj_t **v = chk_malloc(alloc_plus * sizeof *v); + vec->v.type = VEC; + vec->v.vec = v + 2; + v[0] = alloc; + v[1] = zero; + return vec; +} + +obj_t *vec_get_fill(obj_t *vec) +{ + assert (vec && vec->v.type == VEC); + return vec->v.vec[vec_fill]; +} + +obj_t *vec_set_fill(obj_t *vec, obj_t *fill) +{ + assert (vec && vec->v.type == VEC); + + { + long new_fill = c_num(fill); + long old_fill = c_num(vec->v.vec[vec_fill]); + long old_alloc = c_num(vec->v.vec[vec_alloc]); + long fill_delta = new_fill - old_fill; + long alloc_delta = new_fill - old_alloc; + + if (alloc_delta > 0) { + long new_alloc = max(new_fill, 2*old_alloc); + obj_t **newvec = chk_realloc(vec->v.vec - 2, + (new_alloc + 2)*sizeof *newvec); + vec->v.vec = newvec + 2; + vec->v.vec[vec_alloc] = num(new_alloc); + } + + if (fill_delta > 0) { + long i; + for (i = old_fill; i < new_fill; i++) + vec->v.vec[i] = nil; + } + + vec->v.vec[vec_fill] = fill; + } + + return vec; +} + + +obj_t **vecref_l(obj_t *vec, obj_t *ind) +{ + assert (vec && vec->v.type == VEC); + assert (c_num(ind) < c_num(vec->v.vec[vec_fill])); + return vec->v.vec + c_num(ind); +} + +obj_t *vec_push(obj_t *vec, obj_t *item) +{ + obj_t *fill = vec_get_fill(vec); + vec_set_fill(vec, plus(fill, one)); + *vecref_l(vec, fill) = item; + return fill; +} + + +static obj_t *stdio_line_read(struct stream *sm) +{ + if (sm->handle == 0) { + return nil; + } else { + char *line = snarf_line((FILE *) sm->handle); + + if (!line) + return nil; + + return string(line); + } +} + +static obj_t *stdio_line_write(struct stream *sm, obj_t *obj) +{ + assert (obj->t.type == STR); + if (sm->handle == 0) + return nil; + if (fputs(c_str(obj), (FILE *) sm->handle) == EOF) + return nil; + if (putc('\n', (FILE *) sm->handle) == EOF) + return nil; + return t; +} + +static obj_t *stdio_close(struct stream *sm) +{ + FILE *f = (FILE *) sm->handle; + + if (f != 0 && f != stdin && f != stdout) { + fclose((FILE *) sm->handle); + sm->handle = 0; + return t; + } + return nil; +} + +static struct stream_ops stdio_line_stream_ops = { + stdio_line_read, stdio_line_write, stdio_close +}; + +obj_t *stdio_line_stream(FILE *f, obj_t *label) +{ + obj_t *sm = make_obj(); + sm->sm.type = STREAM; + sm->sm.handle = f; + sm->sm.ops = &stdio_line_stream_ops; + sm->sm.label_pushback = label; + assert (atom(label)); + return sm; +} + +static obj_t *pipe_close(struct stream *sm) +{ + if (sm->handle != 0) { + pclose((FILE *) sm->handle); + sm->handle = 0; + return t; + } + return nil; +} + +static struct stream_ops pipe_line_stream_ops = { + stdio_line_read, stdio_line_write, pipe_close +}; + +obj_t *pipe_line_stream(FILE *f, obj_t *label) +{ + obj_t *sm = make_obj(); + sm->sm.type = STREAM; + sm->sm.handle = f; + sm->sm.ops = &pipe_line_stream_ops; + sm->sm.label_pushback = label; + assert (atom(label)); + return sm; +} + +obj_t *dirent_read(struct stream *sm) +{ + if (sm->handle == 0) { + return nil; + } else { + for (;;) { + struct dirent *e = readdir(sm->handle); + if (!e) + return nil; + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) + continue; + return string(chk_strdup(e->d_name)); + } + } +} + +obj_t *dirent_close(struct stream *sm) +{ + if (sm->handle != 0) { + closedir((DIR *) sm->handle); + sm->handle = 0; + return t; + } + + return nil; +} + +static struct stream_ops dirent_stream_ops = { + dirent_read, 0, dirent_close +}; + +obj_t *dirent_stream(DIR *d, obj_t *label) +{ + obj_t *sm = make_obj(); + sm->sm.type = STREAM; + sm->sm.handle = d; + sm->sm.ops = &dirent_stream_ops; + sm->sm.label_pushback = label; + assert (atom(label)); + return sm; +} + +obj_t *stream_get(obj_t *sm) +{ + assert (sm->sm.type == STREAM); + + if (consp(sm->sm.label_pushback)) { + obj_t *ret = car(sm->sm.label_pushback); + sm->sm.label_pushback = cdr(sm->sm.label_pushback); + return ret; + } + + return sm->sm.ops->read(&sm->sm); +} + +obj_t *stream_pushback(obj_t *sm, obj_t *obj) +{ + assert (sm->sm.type == STREAM); + sm->sm.label_pushback = cons(obj, sm->sm.label_pushback); + return obj; +} + +obj_t *stream_put(obj_t *sm, obj_t *obj) +{ + assert (sm->sm.type == STREAM); + return sm->sm.ops->write(&sm->sm, obj); +} + +obj_t *stream_close(obj_t *sm) +{ + assert (sm->sm.type == STREAM); + return sm->sm.ops->close(&sm->sm); +} + + +static obj_t *make_lazycons(obj_t *func) +{ + obj_t *obj = make_obj(); + obj->lc.type = LCONS; + obj->lc.car = obj->lc.cdr = nil; + obj->lc.func = func; + return obj; +} + +static obj_t *lazy_stream_func(obj_t *stream, obj_t *lcons) +{ + obj_t *next = stream_get(stream); + obj_t *ahead = stream_get(stream); + + lcons->lc.car = next; + lcons->lc.cdr = if2(ahead, make_lazycons(lcons->lc.func)); + lcons->lc.func = nil; + + if (!next || !ahead) + stream_close(stream); + + if (ahead) + stream_pushback(stream, ahead); + + return next; +} + +obj_t *lazy_stream_cons(obj_t *stream) +{ + obj_t *first = stream_get(stream); + + if (!first) { + stream_close(stream); + return nil; + } + + stream_pushback(stream, first); + + return make_lazycons(func_f1(stream, lazy_stream_func)); +} + +obj_t *cobj(void *handle, obj_t *cls_sym, struct cobj_ops *ops) +{ + obj_t *obj = make_obj(); + obj->co.type = COBJ; + obj->co.handle = handle; + obj->co.ops = ops; + obj->co.cls = cls_sym; + return obj; +} + +void cobj_print_op(obj_t *obj, FILE *out) +{ + fprintf(out, "#<"); + obj_print(obj->co.cls, out); + fprintf(out, ": %p>", obj->co.handle); +} + +obj_t *assoc(obj_t *list, obj_t *key) +{ + while (list) { + obj_t *elem = car(list); + if (equal(car(elem), key)) + return elem; + list = cdr(list); + } + + return nil; +} + +obj_t *acons_new(obj_t *list, obj_t *key, obj_t *value) +{ + obj_t *existing = assoc(list, key); + + if (existing) { + *cdr_l(existing) = value; + return list; + } else { + return cons(cons(key, value), list); + } +} + +obj_t *alist_remove(obj_t *list, obj_t *keys) +{ + obj_t **plist = &list; + + while (*plist) { + if (memq(car(car(*plist)), keys)) + *plist = cdr(*plist); + else + plist = cdr_l(*plist); + } + + return list; +} + +obj_t *mapcar(obj_t *fun, obj_t *list) +{ + list_collect_decl (out, iter); + + for (; list; list = cdr(list)) + list_collect (iter, funcall1(fun, car(list))); + + return out; +} + +obj_t *mappend(obj_t *fun, obj_t *list) +{ + list_collect_decl (out, iter); + + for (; list; list = cdr(list)) + list_collect_append (iter, funcall1(fun, car(list))); + + return out; +} + +static void obj_init(void) +{ + int gc_save = gc_state(0); + + /* + * No need to GC-protect the convenience variables which hold the interned + * symbols, because the interned_syms list holds a reference to all the + * symbols. + */ + + protect(&interned_syms, &zero, &one, + &two, &negone, &maxint, &minint, + &null_string, &nil_string, + &null_list, &equal_f, + &identity_f, 0); + + null = intern(string(strdup("null"))); + t = intern(string(strdup("t"))); + cons_t = intern(string(strdup("cons"))); + str_t = intern(string(strdup("str"))); + chr_t = intern(string(strdup("chr"))); + num_t = intern(string(strdup("num"))); + sym_t = intern(string(strdup("sym"))); + fun_t = intern(string(strdup("fun"))); + vec_t = intern(string(strdup("vec"))); + stream_t = intern(string(strdup("stream"))); + lcons_t = intern(string(strdup("lcons"))); + var = intern(string(strdup("var"))); + regex = intern(string(strdup("regex"))); + set = intern(string(strdup("set"))); + cset = intern(string(strdup("cset"))); + wild = intern(string(strdup("wild"))); + oneplus = intern(string(strdup("1+"))); + zeroplus = intern(string(strdup("0+"))); + optional = intern(string(strdup("?"))); + compound = intern(string(strdup("compound"))); + or = intern(string(strdup("or"))); + skip = intern(string(strdup("skip"))); + block = intern(string(strdup("block"))); + next = intern(string(strdup("next"))); + fail = intern(string(strdup("fail"))); + accept = intern(string(strdup("accept"))); + all = intern(string(strdup("all"))); + some = intern(string(strdup("some"))); + none = intern(string(strdup("none"))); + maybe = intern(string(strdup("maybe"))); + collect = intern(string(strdup("collect"))); + until = intern(string(strdup("until"))); + coll = intern(string(strdup("coll"))); + output = intern(string(strdup("output"))); + single = intern(string(strdup("single"))); + frst = intern(string(strdup("first"))); + lst = intern(string(strdup("last"))); + empty = intern(string(strdup("empty"))); + repeat = intern(string(strdup("repeat"))); + rep = intern(string(strdup("rep"))); + flattn = intern(string(strdup("flatten"))); + forget = intern(string(strdup("forget"))); + mrge = intern(string(strdup("merge"))); + bind = intern(string(strdup("bind"))); + cat = intern(string(strdup("cat"))); + dir = intern(string(strdup("dir"))); + + zero = num(0); + one = num(1); + two = num(2); + negone = num(-1); + maxint = num(LONG_MAX); + minint = num(LONG_MIN); + + null_string = string(strdup("")); + nil_string = string(strdup("NIL")); + + null_list = cons(nil, nil); + + equal_f = func_f2(nil, equal_tramp); + identity_f = func_f1(nil, identity_tramp); + + gc_state(gc_save); +} + +void obj_print(obj_t *obj, FILE *out) +{ + if (obj == nil) { + fputs("nil", out); + return; + } + + switch (obj->t.type) { + case CONS: + case LCONS: + { + obj_t *iter; + putc('(', out); + for (iter = obj; consp(iter); iter = cdr(iter)) { + obj_print(car(iter), out); + if (nullp(cdr(iter))) { + putc(')', out); + } else if (consp(cdr(iter))) { + putc(' ', out); + } else { + fputs(" . ", out); + obj_print(cdr(iter), out); + putc(')', out); + } + } + } + break; + case STR: + { + const char *ptr; + putc('"', out); + for (ptr = obj->st.str; *ptr; ptr++) { + switch (*ptr) { + case '\a': fputs("\\a", out); break; + case '\b': fputs("\\b", out); break; + case '\t': fputs("\\t", out); break; + case '\n': fputs("\\n", out); break; + case '\v': fputs("\\v", out); break; + case '\f': fputs("\\f", out); break; + case '\r': fputs("\\r", out); break; + case '"': fputs("\\\"", out); break; + case '\\': fputs("\\\\", out); break; + case 27: fputs("\\e", out); break; + default: + if (iscntrl(*ptr)) + fprintf(out, "\\%03o", (int) *ptr); + else + putc(*ptr, out); + } + } + putc('"', out); + } + break; + case CHR: + { + int ch = obj->ch.ch; + + putc('\'', out); + switch (ch) { + case '\a': fputs("\\a", out); break; + case '\b': fputs("\\b", out); break; + case '\t': fputs("\\t", out); break; + case '\n': fputs("\\n", out); break; + case '\v': fputs("\\v", out); break; + case '\f': fputs("\\f", out); break; + case '\r': fputs("\\r", out); break; + case '"': fputs("\\\"", out); break; + case '\\': fputs("\\\\", out); break; + case 27: fputs("\\e", out); break; + default: + if (iscntrl(ch)) + fprintf(out, "\\%03o", ch); + else + putc(ch, out); + } + putc('\'', out); + } + break; + case NUM: + fprintf(out, "%ld", c_num(obj)); + break; + case SYM: + fputs(c_str(symbol_name(obj)), out); + break; + case FUN: + fprintf(out, "#", (int) obj->f.functype); + break; + case VEC: + { + long i, fill = c_num(obj->v.vec[vec_fill]); + fputs("#(", out); + for (i = 0; i < fill; i++) { + obj_print(obj->v.vec[i], out); + if (i < fill - 1) + putc(' ', out); + } + putc(')', out); + } + break; + case STREAM: + fprintf(out, "#sm.label_pushback; consp(iter); iter = cdr(iter)) + ; + obj_print(iter, out); + } + fprintf(out, ", %p>", (void *) obj->sm.handle); + break; + case COBJ: + obj->co.ops->print(obj, out); + break; + } +} + +void init(const char *pn, void *(*oom)(void *, size_t)) +{ + progname = pn; + obj_init(); +} + +void dump(obj_t *obj, FILE *out) +{ + obj_print(obj, out); + putc('\n', out); +} + +/* + * Handy function for debugging in gdb, + * so we don't have to keep typing: + * (gdb) p dump(something, stdout) + */ +void d(obj_t *obj) +{ + dump(obj, stdout); +} + +char *snarf_line(FILE *in) +{ + const size_t min_size = 512; + size_t size = 0; + size_t fill = 0; + char *buf = 0; + + for (;;) { + int ch = getc(in); + + if (ch == EOF && buf == 0) + break; + + if (fill >= size) { + size_t newsize = size ? size * 2 : min_size; + buf = chk_realloc(buf, newsize); + size = newsize; + } + + if (ch == '\n') { + buf[fill++] = 0; + break; + } + buf[fill++] = ch; + } + + if (buf) + buf = chk_realloc(buf, fill); + + return buf; +} + +obj_t *snarf(FILE *in) +{ + list_collect_decl (list, iter); + char *str; + + while ((str = snarf_line(in)) != 0) + list_collect (iter, string(str)); + + return list; +} diff --git a/lib.h b/lib.h new file mode 100644 index 00000000..026efb97 --- /dev/null +++ b/lib.h @@ -0,0 +1,331 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +typedef enum type { + CONS = 1, STR, CHR, NUM, SYM, FUN, VEC, STREAM, LCONS, COBJ +} type_t; + +typedef enum functype +{ + FINTERP, /* Interpreted function. */ + F0, F1, F2, F3, F4, /* Intrinsic functions with env. */ + N0, N1, N2, N3, N4 /* No-env intrinsics. */ +} functype_t; + +typedef union obj obj_t; + +struct any { + type_t type; + void *dummy[2]; + obj_t *next; /* GC free list */ +}; + +struct cons { + type_t type; + obj_t *car, *cdr; +}; + +struct string { + type_t type; + char *str; + obj_t *len; +}; + +struct chr { + type_t type; + int ch; +}; + +struct num { + type_t type; + long val; +}; + +struct sym { + type_t type; + obj_t *name; + obj_t *val; +}; + +struct func { + type_t type; + functype_t functype; + obj_t *env; + union { + obj_t *interp_fun; + obj_t *(*f0)(obj_t *); + obj_t *(*f1)(obj_t *, obj_t *); + obj_t *(*f2)(obj_t *, obj_t *, obj_t *); + obj_t *(*f3)(obj_t *, obj_t *, obj_t *, obj_t *); + obj_t *(*f4)(obj_t *, obj_t *, obj_t *, obj_t *, obj_t *); + obj_t *(*n0)(void); + obj_t *(*n1)(obj_t *); + obj_t *(*n2)(obj_t *, obj_t *); + obj_t *(*n3)(obj_t *, obj_t *, obj_t *); + obj_t *(*n4)(obj_t *, obj_t *, obj_t *, obj_t *); + } f; +}; + +enum vecindex { vec_alloc = -2, vec_fill = -1 }; + +struct vec { + type_t type; + /* vec points two elements down */ + /* vec[-2] is allocated size */ + /* vec[-1] is fill pointer */ + obj_t **vec; +}; + +struct stream { + type_t type; + void *handle; + struct stream_ops *ops; + obj_t *label_pushback; /* label-terminated pushback stack */ +}; + +struct stream_ops { + obj_t *(*read)(struct stream *); + obj_t *(*write)(struct stream *, obj_t *); + obj_t *(*close)(struct stream *); +}; + +/* + * Lazy cons. When initially constructed, acts as a promise. The car and cdr + * cache pointers are nil, and func points to a function. The job of the + * function is to force the promise: fill car and cdr, and then flip func to + * nil. After that, the lazy cons resembles an ordinary cons. Of course, either + * car or cdr can point to more lazy conses. + */ + +struct lazy_cons { + type_t type; + obj_t *car, *cdr; + obj_t *func; /* when nil, car and cdr are valid */ +}; + +struct cobj { + type_t type; + void *handle; + struct cobj_ops *ops; + obj_t *cls; +}; + +struct cobj_ops { + obj_t *(*equal)(obj_t *self, obj_t *other); + void (*print)(obj_t *self, FILE *); + void (*destroy)(obj_t *self); +}; + +union obj { + struct any t; + struct cons c; + struct string st; + struct chr ch; + struct num n; + struct sym s; + struct func f; + struct vec v; + struct stream sm; + struct lazy_cons lc; + struct cobj co; +}; + +extern obj_t *interned_syms; + +extern obj_t *t, *cons_t, *str_t, *chr_t, *num_t, *sym_t, *fun_t, *vec_t; +extern obj_t *stream_t, *lcons_t, *var, *regex, *set, *cset, *wild, *oneplus; +extern obj_t *zeroplus, *optional, *compound, *or; +extern obj_t *skip, *block, *next, *fail, *accept; +extern obj_t *all, *some, *none, *maybe, *collect, *until, *coll; +extern obj_t *output, *single, *frst, *lst, *empty, *repeat, *rep; +extern obj_t *flattn, *forget, *mrge, *bind, *cat, *dir; + +extern obj_t *zero, *one, *two, *negone, *maxint, *minint; +extern obj_t *null_string; +extern obj_t *null_list; /* (NIL) */ + +extern obj_t *identity_f; +extern obj_t *equal_f; + +extern const char *progname; +extern void *(*oom_realloc)(void *, size_t); + +obj_t *identity(obj_t *obj); +obj_t *typeof(obj_t *obj); +obj_t *car(obj_t *cons); +obj_t *cdr(obj_t *cons); +obj_t **car_l(obj_t *cons); +obj_t **cdr_l(obj_t *cons); +obj_t *first(obj_t *cons); +obj_t *rest(obj_t *cons); +obj_t *second(obj_t *cons); +obj_t *third(obj_t *cons); +obj_t *fourth(obj_t *cons); +obj_t *fifth(obj_t *cons); +obj_t *sixth(obj_t *cons); +obj_t **tail(obj_t *cons); +obj_t *copy_list(obj_t *list); +obj_t *nreverse(obj_t *in); +obj_t *reverse(obj_t *in); +obj_t *append2(obj_t *list1, obj_t *list2); +obj_t *nappend2(obj_t *list1, obj_t *list2); +obj_t *flatten(obj_t *list); +obj_t *memq(obj_t *obj, obj_t *list); +obj_t *tree_find(obj_t *obj, obj_t *tree); +obj_t *some_satisfy(obj_t *list, obj_t *pred, obj_t *key); +long c_num(obj_t *num); +obj_t *nump(obj_t *num); +obj_t *equal(obj_t *left, obj_t *right); +void *chk_malloc(size_t size); +void *chk_realloc(void*, size_t size); +void *chk_strdup(const char *str); +obj_t *cons(obj_t *car, obj_t *cdr); +obj_t *list(obj_t *first, ...); /* terminated by nao */ +obj_t *consp(obj_t *obj); +obj_t *nullp(obj_t *obj); +obj_t *atom(obj_t *obj); +obj_t *listp(obj_t *obj); +obj_t *length(obj_t *list); +obj_t *num(long val); +long c_num(obj_t *num); +obj_t *plus(obj_t *anum, obj_t *bnum); +obj_t *minus(obj_t *anum, obj_t *bnum); +obj_t *neg(obj_t *num); +obj_t *zerop(obj_t *num); +obj_t *gt(obj_t *anum, obj_t *bnum); +obj_t *lt(obj_t *anum, obj_t *bnum); +obj_t *ge(obj_t *anum, obj_t *bnum); +obj_t *le(obj_t *anum, obj_t *bnum); +obj_t *numeq(obj_t *anum, obj_t *bnum); +obj_t *max2(obj_t *anum, obj_t *bnum); +obj_t *min2(obj_t *anum, obj_t *bnum); +obj_t *string(char *str); +obj_t *mkstring(obj_t *len, obj_t *ch); +obj_t *copy_str(obj_t *str); +obj_t *stringp(obj_t *str); +obj_t *length_str(obj_t *str); +const char *c_str(obj_t *str); +obj_t *search_str(obj_t *haystack, obj_t *needle, obj_t *start_num, + obj_t *from_end); +obj_t *search_str_tree(obj_t *haystack, obj_t *tree, obj_t *start_num, + obj_t *from_end); +obj_t *sub_str(obj_t *str_in, obj_t *from_num, obj_t *to_num); +obj_t *cat_str(obj_t *list, obj_t *sep); +obj_t *trim_str(obj_t *str); +obj_t *chr(int ch); +int c_chr(obj_t *chr); +obj_t *sym_name(obj_t *sym); +obj_t *make_sym(obj_t *name); +obj_t *intern(obj_t *str); +obj_t *symbolp(obj_t *sym); +obj_t *symbol_name(obj_t *sym); +obj_t *func_f0(obj_t *, obj_t *(*fun)(obj_t *)); +obj_t *func_f1(obj_t *, obj_t *(*fun)(obj_t *, obj_t *)); +obj_t *func_f2(obj_t *, obj_t *(*fun)(obj_t *, obj_t *, obj_t *)); +obj_t *func_f3(obj_t *, obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *)); +obj_t *func_f4(obj_t *, obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *, + obj_t *)); +obj_t *func_n0(obj_t *(*fun)(void)); +obj_t *func_n1(obj_t *(*fun)(obj_t *)); +obj_t *func_n2(obj_t *(*fun)(obj_t *, obj_t *)); +obj_t *func_n3(obj_t *(*fun)(obj_t *, obj_t *, obj_t *)); +obj_t *func_n4(obj_t *(*fun)(obj_t *, obj_t *, obj_t *, obj_t *)); +obj_t *apply(obj_t *fun, obj_t *arglist); +obj_t *funcall(obj_t *fun); +obj_t *funcall1(obj_t *fun, obj_t *arg); +obj_t *funcall2(obj_t *fun, obj_t *arg1, obj_t *arg2); +obj_t *reduce_left(obj_t *fun, obj_t *list, obj_t *init, obj_t *key); +obj_t *bind2(obj_t *fun2, obj_t *arg); +obj_t *chain(obj_t *fun1_list); +obj_t *vector(obj_t *alloc); +obj_t *vec_get_fill(obj_t *vec); +obj_t *vec_set_fill(obj_t *vec, obj_t *fill); +obj_t **vecref_l(obj_t *vec, obj_t *ind); +obj_t *vec_push(obj_t *vec, obj_t *item); +obj_t *stdio_line_stream(FILE *f, obj_t *label); +obj_t *pipe_line_stream(FILE *f, obj_t *label); +obj_t *dirent_stream(DIR *d, obj_t *label); +obj_t *stream_get(obj_t *sm); +obj_t *stream_pushback(obj_t *sm, obj_t *obj); +obj_t *stream_put(obj_t *sm, obj_t *obj); +obj_t *stream_close(obj_t *sm); +obj_t *lazy_stream_cons(obj_t *stream); +obj_t *cobj(void *handle, obj_t *cls_sym, struct cobj_ops *ops); +void cobj_print_op(obj_t *, FILE *); /* Print function for struct cobj_ops */ +obj_t *assoc(obj_t *list, obj_t *key); +obj_t *acons_new(obj_t *list, obj_t *key, obj_t *value); +obj_t *alist_remove(obj_t *list, obj_t *keys); +obj_t *mapcar(obj_t *fun, obj_t *list); +obj_t *mappend(obj_t *fun, obj_t *list); +void obj_print(obj_t *obj, FILE *); +void init(const char *progname, void *(*oom_realloc)(void *, size_t)); +void dump(obj_t *obj, FILE *); +char *snarf_line(FILE *in); +obj_t *snarf(FILE *in); +obj_t *match(obj_t *spec, obj_t *data); + +#define nil ((obj_t *) 0) + +#define nao ((obj_t *) -1) /* "not an object", useful as a sentinel. */ + +#define eq(a, b) ((a) == (b) ? t : nil) + +#define if2(a, b) ((a) ? (b) : nil) + +#define if3(a, b, c) ((a) ? (b) : (c)) + +#define list_collect_decl(OUT, PTAIL) \ + obj_t *OUT = nil, **PTAIL = &OUT + +#define list_collect(PTAIL, OBJ) \ + do { \ + *PTAIL = cons(OBJ, nil); \ + PTAIL = cdr_l(*PTAIL); \ + } while(0) + +#define list_collect_nconc(PTAIL, OBJ) \ + do { \ + obj_t *o_b_j = (OBJ); \ + *PTAIL = o_b_j; \ + if (o_b_j) \ + PTAIL = tail(o_b_j); \ + } while (0) + +#define list_collect_append(PTAIL, OBJ) \ + do { \ + obj_t *o_b_j = copy_list(OBJ); \ + *PTAIL = o_b_j; \ + if (o_b_j) \ + PTAIL = tail(o_b_j); \ + } while (0) + +#define list_collect_terminate(PTAIL, OBJ) \ + do *PTAIL = (OBJ); while(0) + +#define cons_bind(CAR, CDR, CONS) \ + obj_t *c_o_n_s ## CAR ## CDR = CONS; \ + obj_t *CAR = car(c_o_n_s ## CAR ## CDR); \ + obj_t *CDR = cdr(c_o_n_s ## CAR ## CDR) diff --git a/regex.c b/regex.c new file mode 100644 index 00000000..a48b3ff5 --- /dev/null +++ b/regex.c @@ -0,0 +1,631 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include "lib.h" +#include "regex.h" + +#define NFA_SET_SIZE 512 + +#define CHAR_SET_INDEX(CH) ((CH) / (sizeof (bitcell_t) * CHAR_BIT)) +#define CHAR_SET_BIT(CH) ((CH) % (sizeof (bitcell_t) * CHAR_BIT)) + +void char_set_clear(char_set_t *set) +{ + static const char_set_t blank = { { 0 } }; + *set = blank; +} + +void char_set_compl(char_set_t *set) +{ + int i; + for (i = 0; i < CHAR_SET_SIZE; i++) + set->bitcell[i] ^= BITCELL_ALL1; +} + +void char_set_add(char_set_t *set, int ch) +{ + set->bitcell[CHAR_SET_INDEX(ch)] |= (1 << CHAR_SET_BIT(ch)); +} + +void char_set_add_range(char_set_t *set, int ch0, int ch1) +{ + if (ch0 <= ch1) { + int i; + int bt0 = CHAR_SET_BIT(ch0); + int bc0 = CHAR_SET_INDEX(ch0); + bitcell_t mask0 = ~((BITCELL_LIT(1) << bt0) - 1); + int bt1 = CHAR_SET_BIT(ch1); + int bc1 = CHAR_SET_INDEX(ch1); + bitcell_t mask1 = ((BITCELL_LIT(1) << (bt1 + 1) % 32) - 1); + + switch (bc1 - bc0) { + case 0: + set->bitcell[bc0] |= (mask0 & mask1); + break; + default: + set->bitcell[bc0] |= mask0; + set->bitcell[bc1] |= mask1; + case 1: + for (i = bc0 + 1; i < bc1; i++) + set->bitcell[i] = BITCELL_ALL1; + break; + } + } +} + +int char_set_contains(char_set_t *set, int ch) +{ + return (set->bitcell[CHAR_SET_INDEX(ch)] & (1 << CHAR_SET_BIT(ch))) != 0; +} + +nfa_state_t *nfa_state_accept(void) +{ + nfa_state_t *st = (nfa_state_t *) chk_malloc(sizeof *st); + st->a.kind = nfa_accept; + st->a.visited = 0; + return st; +} + +nfa_state_t *nfa_state_empty(nfa_state_t *t0, nfa_state_t *t1) +{ + nfa_state_t *st = (nfa_state_t *) chk_malloc(sizeof *st); + st->e.kind = nfa_empty; + st->e.visited = 0; + st->e.trans0 = t0; + st->e.trans1 = t1; + return st; +} + +nfa_state_t *nfa_state_single(nfa_state_t *t, int ch) +{ + nfa_state_t *st = (nfa_state_t *) chk_malloc(sizeof *st); + st->o.kind = nfa_single; + st->o.visited = 0; + st->o.trans = t; + st->o.ch = ch; + return st; +} + +nfa_state_t *nfa_state_wild(nfa_state_t *t) +{ + nfa_state_t *st = (nfa_state_t *) chk_malloc(sizeof *st); + st->o.kind = nfa_wild; + st->o.visited = 0; + st->o.trans = t; + st->o.ch = 0; + return st; +} + +void nfa_state_free(nfa_state_t *st) +{ + if (st->a.kind == nfa_set) + free(st->s.set); + free(st); +} + +void nfa_state_shallow_free(nfa_state_t *st) +{ + free(st); +} + +nfa_state_t *nfa_state_set(nfa_state_t *t) +{ + nfa_state_t *st = (nfa_state_t *) chk_malloc(sizeof *st); + char_set_t *cs = (char_set_t *) chk_malloc(sizeof *cs); + char_set_clear(cs); + st->s.kind = nfa_set; + st->s.visited = 0; + st->s.trans = t; + st->s.set = cs; + return st; +} + +/* + * An acceptance state is converted to an empty transition + * state with specified transitions. It thereby loses + * its acceptance state status. This is used during + * compilation to hook new output paths into an inner NFA, + * either back to itself, or to a new state in the + * surrounding new NFA. + */ +void nfa_state_empty_convert(nfa_state_t *acc, nfa_state_t *t0, nfa_state_t *t1) +{ + assert (acc->a.kind == nfa_accept); + acc->e.kind = nfa_empty; + acc->e.trans0 = t0; + acc->e.trans1 = t1; +} + +/* + * Acceptance state takes on the kind of st, and all associated + * data. I.e. we merge the identity of accept, + * with the contents of st, such that the new state has + * all of the outgoing arrows of st, and + * all of the incoming arrows of acc. + * This is easily done with an assignment, provided + * that st doesn't have any incoming arrows. + * We ensure that start states don't have any incoming + * arrows in the compiler, by ensuring that repetition + * operators terminate their backwards arrows on an + * existing start state, and allocate a new start + * state in front of it. + */ +void nfa_state_merge(nfa_state_t *acc, nfa_state_t *st) +{ + assert (acc->a.kind == nfa_accept); + *acc = *st; +} + +nfa_t nfa_make(nfa_state_t *s, nfa_state_t *acc) +{ + nfa_t ret; + ret.start = s; + ret.accept = acc; + return ret; +} + +/* + * Combine two NFA's representing regexps that are catenated. + * The acceptance state of the predecessor is merged with the start state of + * the successor. + */ +nfa_t nfa_combine(nfa_t pred, nfa_t succ) +{ + nfa_t ret; + ret.start = pred.start; + ret.accept = succ.accept; + nfa_state_merge(pred.accept, succ.start); + nfa_state_shallow_free(succ.start); /* No longer needed. */ + return ret; +} + +nfa_t nfa_compile_set(obj_t *args, int compl) +{ + nfa_state_t *acc = nfa_state_accept(); + nfa_state_t *s = nfa_state_set(acc); + char_set_t *set = s->s.set; + nfa_t ret = nfa_make(s, acc); + + for (; args; args = rest(args)) { + obj_t *item = first(args); + + if (consp(item)) { + obj_t *from = car(item); + obj_t *to = cdr(item); + + assert (typeof(from) == chr_t && typeof(to) == chr_t); + char_set_add_range(set, c_chr(from), c_chr(to)); + } else if (typeof(item) == chr_t) { + char_set_add(set, c_chr(item)); + } else { + assert(0 && "bad regex set"); + } + } + + if (compl) + char_set_compl(set); + + return ret; +} + +/* + * Input is the items from a regex form, + * not including the regex symbol. + * I.e. (rest '(regex ...)) not '(regex ...). + */ +nfa_t nfa_compile_regex(obj_t *items) +{ + if (nullp(items)) { + nfa_state_t *acc = nfa_state_accept(); + nfa_state_t *s = nfa_state_empty(acc, 0); + nfa_t nfa = nfa_make(s, acc); + return nfa; + } else { + obj_t *item = first(items), *others = rest(items); + nfa_t nfa; + + if (typeof(item) == chr_t) { + nfa_state_t *acc = nfa_state_accept(); + nfa_state_t *s = nfa_state_single(acc, c_chr(item)); + nfa = nfa_make(s, acc); + } else if (item == wild) { + nfa_state_t *acc = nfa_state_accept(); + nfa_state_t *s = nfa_state_wild(acc); + nfa = nfa_make(s, acc); + } else if (consp(item)) { + obj_t *sym = first(item); + obj_t *args = rest(item); + + if (sym == set) { + nfa = nfa_compile_set(args, 0); + } else if (sym == cset) { + nfa = nfa_compile_set(args, 1); + } else if (sym == compound) { + nfa = nfa_compile_regex(args); + } else if (sym == zeroplus) { + nfa_t nfa_args = nfa_compile_regex(args); + nfa_state_t *acc = nfa_state_accept(); + /* New start state has empty transitions going through + the inner NFA, or skipping it right to the new acceptance state. */ + nfa_state_t *s = nfa_state_empty(nfa_args.start, acc); + /* Convert acceptance state of inner NFA to one which has + an empty transition back to the start state, and + an empty transition to the new acceptance state. */ + nfa_state_empty_convert(nfa_args.accept, nfa_args.start, acc); + nfa = nfa_make(s, acc); + } else if (sym == oneplus) { + /* One-plus case differs from zero-plus in that the new start state + does not have an empty transition to the acceptance state. + So the inner NFA must be traversed once. */ + nfa_t nfa_args = nfa_compile_regex(args); + nfa_state_t *acc = nfa_state_accept(); + nfa_state_t *s = nfa_state_empty(nfa_args.start, 0); /* <-- diff */ + nfa_state_empty_convert(nfa_args.accept, nfa_args.start, acc); + nfa = nfa_make(s, acc); + } else if (sym == optional) { + /* In this case, we can keep the acceptance state of the inner + NFA as the acceptance state of the new NFA. We simply add + a new start state which can short-circuit to it via an empty + transition. */ + nfa_t nfa_args = nfa_compile_regex(args); + nfa_state_t *s = nfa_state_empty(nfa_args.start, nfa_args.accept); + nfa = nfa_make(s, nfa_args.accept); + } else if (sym == or) { + /* Simple: make a new start and acceptance state, which form + the ends of a spindle that goes through two branches. */ + nfa_t nfa_first = nfa_compile_regex(first(args)); + nfa_t nfa_second = nfa_compile_regex(second(args)); + nfa_state_t *acc = nfa_state_accept(); + /* New state s has empty transitions into each inner NFA. */ + nfa_state_t *s = nfa_state_empty(nfa_first.start, nfa_second.start); + /* Acceptance state of each inner NFA converted to empty + transition to new combined acceptance state. */ + nfa_state_empty_convert(nfa_first.accept, acc, 0); + nfa_state_empty_convert(nfa_second.accept, acc, 0); + nfa = nfa_make(s, acc); + } else { + assert (0 && "internal error: bad operator in regex"); + } + } else { + assert (0 && "internal error: bad regex item"); + } + + /* We made an NFA for the first item, but others follow. + Compile the others to an NFA recursively, then + stick it with this NFA. */ + if (others) { + nfa_t nfa_others = nfa_compile_regex(others); + nfa = nfa_combine(nfa, nfa_others); + } + + return nfa; + } +} + +int nfa_all_states(nfa_state_t **inout, int num, int visited) +{ + int i; + + for (i = 0; i < num; i++) + inout[i]->a.visited = visited; + + for (i = 0; i < num; i++) { + nfa_state_t *s = inout[i]; + + if (num >= NFA_SET_SIZE) + abort(); + + switch (s->a.kind) { + case nfa_accept: + break; + case nfa_empty: + { + nfa_state_t *e0 = s->e.trans0; + nfa_state_t *e1 = s->e.trans1; + + if (e0 && e0->a.visited != visited) { + e0->a.visited = visited; + inout[num++] = e0; + } + if (e1 && e1->a.visited != visited) { + e1->a.visited = visited; + inout[num++] = e1; + } + } + break; + case nfa_wild: + case nfa_single: + case nfa_set: + if (s->o.trans->a.visited != visited) { + s->o.trans->a.visited = visited; + inout[num++] = s->o.trans; + } + break; + } + } + + if (num > NFA_SET_SIZE) + abort(); + + return num; +} + +void nfa_free(nfa_t nfa) +{ + nfa_state_t **all = chk_malloc(NFA_SET_SIZE * sizeof *all); + int nstates, i; + + all[0] = nfa.start; + all[1] = nfa.accept; + + nstates = nfa_all_states(all, 2, nfa.start->a.visited); + + for (i = 0; i < nstates; i++) + nfa_state_free(all[i]); + + free(all); +} + +/* + * Compute the epsilon-closure of the NFA states stored in the set in, whose + * size is given by nin. The results are stored in the set out, the size of + * which is returned. The stack parameter provides storage used by the + * algorithm, so it doesn't have to be allocated and freed repeatedly. + * The visited parameter is a stamp used for marking states which are added + * to the epsilon-closure set, so that sets are not added twice. + * If any of the states added to the closure are acceptance states, + * the accept parameter is used to store the flag 1. + * + * An epsilon-closure is the set of all input states, plus all additional + * states which are reachable from that set with empty (epsilon) transitions. + * (Transitions that don't do not consume and match an input character). + */ +int nfa_closure(nfa_state_t **stack, nfa_state_t **in, int nin, + nfa_state_t **out, int visited, int *accept) +{ + int i, nout = 0; + int stackp = 0; + + /* First, add all states in the input state to the closure, + push them on the stack, and mark them as visited. */ + for (i = 0; i < nin; i++) { + if (stackp >= NFA_SET_SIZE) + abort(); + in[i]->a.visited = visited; + stack[stackp++] = in[i]; + out[nout++] = in[i]; + if (in[i]->a.kind == nfa_accept) + *accept = 1; + } + + while (stackp) { + nfa_state_t *top = stack[--stackp]; + + if (nout >= NFA_SET_SIZE) + abort(); + + /* Only states of type nfa_empty are interesting. + Each such state at most two epsilon transitions. */ + + if (top->a.kind == nfa_empty) { + nfa_state_t *e0 = top->e.trans0; + nfa_state_t *e1 = top->e.trans1; + + if (e0 && e0->a.visited != visited) { + e0->a.visited = visited; + stack[stackp++] = e0; + out[nout++] = e0; + if (e0->a.kind == nfa_accept) + *accept = 1; + } + + if (e1 && e1->a.visited != visited) { + e1->a.visited = visited; + stack[stackp++] = e1; + out[nout++] = e1; + if (e1->a.kind == nfa_accept) + *accept = 1; + } + } + } + + if (nout > NFA_SET_SIZE) + abort(); + + return nout; +} + +/* + * Compute the move set from a given set of NFA states. The move + * set is the set of states which are reachable from the set of + * input states on the consumpion of the input character given by ch. + */ +int nfa_move(nfa_state_t **in, int nin, nfa_state_t **out, int ch) +{ + int i, nmove; + + for (nmove = 0, i = 0; i < nin; i++) { + nfa_state_t *s = in[i]; + + switch (s->a.kind) { + case nfa_wild: + /* Unconditional match; don't have to look at ch. */ + break; + case nfa_single: + if (s->o.ch == ch) /* Character match. */ + break; + continue; /* no match */ + case nfa_set: + if (char_set_contains(s->s.set, ch)) /* Set match. */ + break; + continue; /* no match */ + default: + /* Epsilon-transition and acceptance states have no character moves. */ + continue; + } + + /* The state matches the character, so add it to the move set. + C trick: all character-transitioning state types have the + pointer to the next state in the same position, + among a common set of leading struct members in the union. */ + + if (nmove >= NFA_SET_SIZE) + abort(); + out[nmove++] = s->o.trans; + } + + return nmove; +} + +/* + * Match regex against the string in. The match is + * anchored to the front of the string; to search + * within the string, a .* must be added to the front + * of the regex. + * + * Returns the length of the prefix of the string + * which matches the regex. Or, if you will, + * the position of the first mismatching + * character. + * + * If the regex does not match at all, zero is + * returned. + * + * Matching stops when a state is reached from which + * there are no transitions on the next input character, + * or when the string runs out of characters. + * The most recently visited acceptance state then + * determines the match length (defaulting to zero + * if no acceptance states were encountered). + */ +long nfa_run(nfa_t nfa, const char *str) +{ + const char *last_accept_pos = 0, *ptr = str; + unsigned visited = nfa.start->a.visited + 1; + nfa_state_t **move = chk_malloc(NFA_SET_SIZE * sizeof *move); + nfa_state_t **clos = chk_malloc(NFA_SET_SIZE * sizeof *clos); + nfa_state_t **stack = chk_malloc(NFA_SET_SIZE * sizeof *stack); + int nmove = 1, nclos; + int accept = 0; + + move[0] = nfa.start; + + nclos = nfa_closure(stack, move, nmove, clos, visited++, &accept); + + if (accept) + last_accept_pos = ptr; + + for (; *ptr != 0; ptr++) { + int ch = *ptr; + + accept = 0; + + nmove = nfa_move(clos, nclos, move, ch); + nclos = nfa_closure(stack, move, nmove, clos, visited++, &accept); + + if (accept) + last_accept_pos = ptr + 1; + + if (nclos == 0) /* dead end; no match */ + break; + } + + nfa.start->a.visited = visited; + + free(stack); + free(clos); + free(move); + + return last_accept_pos ? last_accept_pos - str : -1; +} + +static obj_t *regex_equal(obj_t *self, obj_t *other) +{ + return self == other ? t : nil; /* eq equality only */ +} + +static void regex_destroy(obj_t *regex) +{ + nfa_t *pnfa = (nfa_t *) regex->co.handle; + nfa_free(*pnfa); + free(pnfa); + regex->co.handle = 0; +} + +static struct cobj_ops regex_obj_ops = { + regex_equal, cobj_print_op, regex_destroy +}; + +obj_t *regex_compile(obj_t *regex_sexp) +{ + nfa_t *pnfa = chk_malloc(sizeof *pnfa); + *pnfa = nfa_compile_regex(regex_sexp); + return cobj(pnfa, regex, ®ex_obj_ops); +} + +nfa_t *regex_nfa(obj_t *reg) +{ + assert (reg->co.type == COBJ && reg->co.cls == regex); + return (nfa_t *) reg->co.handle; +} + +obj_t *search_regex(obj_t *haystack, obj_t *needle_regex, obj_t *start_num, + obj_t *from_end) +{ + const char *h = c_str(haystack); + long len = c_num(length_str(haystack)); + long start = c_num(start_num); + nfa_t *pnfa = regex_nfa(needle_regex); + + if (start > len) { + return nil; + } else { + long begin = from_end ? len : start; + long end = from_end ? start - 1 : len + 1; + int incr = from_end ? -1 : 1; + long i; + + for (i = begin; i != end; i += incr) { + long span = nfa_run(*pnfa, h + i); + if (span >= 0) + return cons(num(i), num(span)); + } + + return nil; + } +} + +obj_t *match_regex(obj_t *str, obj_t *reg, obj_t *pos) +{ + nfa_t *pnfa = regex_nfa(reg); + long cpos = c_num(pos); + long span = nfa_run(*pnfa, c_str(str) + cpos); + return span >= 0 ? num(span + cpos) : nil; +} diff --git a/regex.h b/regex.h new file mode 100644 index 00000000..10fcf4b4 --- /dev/null +++ b/regex.h @@ -0,0 +1,107 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +typedef unsigned int bitcell_t; +#define BITCELL_ALL1 UINT_MAX +#define BITCELL_LIT(NUMTOKEN) NUMTOKEN ## U + +#define CHAR_SET_SIZE ((UCHAR_MAX + 1) / (sizeof (bitcell_t) * CHAR_BIT)) + +typedef struct char_set { + bitcell_t bitcell[CHAR_SET_SIZE]; +} char_set_t; + +void char_set_clear(char_set_t *); +void char_set_compl(char_set_t *); +void char_set_add(char_set_t *, int); +void char_set_add_range(char_set_t *, int, int); /* inclusive */ +int char_set_contains(char_set_t *, int); + +typedef enum { + nfa_accept, nfa_empty, nfa_wild, nfa_single, nfa_set +} nfa_kind_t; + +typedef union nfa_state nfa_state_t; + +struct nfa_state_accept { + nfa_kind_t kind; + unsigned visited; +}; + +struct nfa_state_empty { + nfa_kind_t kind; + unsigned visited; + nfa_state_t *trans0; + nfa_state_t *trans1; +}; + +struct nfa_state_single { + nfa_kind_t kind; + unsigned visited; + nfa_state_t *trans; + int ch; +}; + +struct nfa_state_set { + nfa_kind_t kind; + unsigned visited; + nfa_state_t *trans; + char_set_t *set; +}; + +union nfa_state { + struct nfa_state_accept a; + struct nfa_state_empty e; + struct nfa_state_single o; + struct nfa_state_set s; +}; + +nfa_state_t *nfa_state_accept(void); +nfa_state_t *nfa_state_empty(nfa_state_t *, nfa_state_t *); +nfa_state_t *nfa_state_single(nfa_state_t *, int ch); +nfa_state_t *nfa_state_wild(nfa_state_t *); +nfa_state_t *nfa_state_set(nfa_state_t *); +void nfa_state_free(nfa_state_t *st); +void nfa_state_shallow_free(nfa_state_t *st); +void nfa_state_merge(nfa_state_t *accept, nfa_state_t *); + +typedef struct nfa nfa_t; + +struct nfa { + nfa_state_t *start; + nfa_state_t *accept; +}; + +nfa_t nfa_compile_regex(obj_t *regex); +void nfa_free(nfa_t); +long nfa_run(nfa_t nfa, const char *str); +obj_t *regex_compile(obj_t *regex_sexp); +nfa_t *regex_nfa(obj_t *); +obj_t *search_regex(obj_t *haystack, obj_t *needle_regex, obj_t *start_num, + obj_t *from_end); +obj_t *match_regex(obj_t *str, obj_t *regex, obj_t *pos); diff --git a/tests/001/data b/tests/001/data new file mode 100644 index 00000000..fb74617d --- /dev/null +++ b/tests/001/data @@ -0,0 +1,87 @@ +UID PID PPID C STIME TTY TIME CMD +root 1 0 0 Aug21 ? 00:01:11 init [5] +root 2 1 0 Aug21 ? 00:00:00 [ksoftirqd/0] +root 3 1 0 Aug21 ? 00:01:23 [events/0] +root 4 3 0 Aug21 ? 00:00:00 [khelper] +root 5 3 0 Aug21 ? 00:00:00 [kacpid] +root 16 3 0 Aug21 ? 00:00:00 [kblockd/0] +root 29 3 0 Aug21 ? 00:00:00 [aio/0] +root 17 1 0 Aug21 ? 00:00:00 [khubd] +root 28 1 0 Aug21 ? 00:00:06 [kswapd0] +root 103 1 0 Aug21 ? 00:00:00 [kseriod] +root 175 1 0 Aug21 ? 00:00:00 [scsi_eh_0] +root 186 1 0 Aug21 ? 00:04:49 [kjournald] +root 870 1 0 Aug21 ? 00:00:00 udevd +root 1068 1 0 Aug21 ? 00:00:00 /sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0 +root 1235 1 0 Aug21 ? 00:00:00 [kjournald] +root 1236 1 0 Aug21 ? 00:00:09 [kjournald] +root 1620 1 0 Aug21 ? 00:00:16 syslogd -m 0 +root 1624 1 0 Aug21 ? 00:00:00 klogd -x +rpc 1645 1 0 Aug21 ? 00:00:08 portmap +rpcuser 1665 1 0 Aug21 ? 00:00:00 rpc.statd +root 1698 1 0 Aug21 ? 00:00:07 rpc.idmapd +root 1766 1 0 Aug21 ? 00:05:17 /usr/sbin/vmware-guestd --background /var/run/vmware-guestd.pid +root 1790 1 0 Aug21 ? 00:00:23 [rpciod] +root 1791 1 0 Aug21 ? 00:00:00 [lockd] +root 1821 1 0 Aug21 ? 00:00:00 ypbind +root 1839 1 0 Aug21 ? 00:00:00 /usr/sbin/acpid +root 1851 1 0 Aug21 ? 00:01:33 cupsd +root 1887 1 0 Aug21 ? 00:00:00 /usr/sbin/sshd +root 1902 1 0 Aug21 ? 00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid +root 1921 1 0 Aug21 ? 00:00:00 rpc.rquotad +root 1925 1 0 Aug21 ? 00:00:00 [nfsd] +root 1926 1 0 Aug21 ? 00:00:00 [nfsd] +root 1927 1 0 Aug21 ? 00:00:00 [nfsd] +root 1928 1 0 Aug21 ? 00:00:00 [nfsd] +root 1929 1 0 Aug21 ? 00:00:00 [nfsd] +root 1930 1 0 Aug21 ? 00:00:00 [nfsd] +root 1931 1 0 Aug21 ? 00:00:00 [nfsd] +root 1932 1 0 Aug21 ? 00:00:00 [nfsd] +root 1936 1 0 Aug21 ? 00:00:00 rpc.mountd +root 1963 1 0 Aug21 ? 00:00:29 crond +xfs 1989 1 0 Aug21 ? 00:00:01 xfs -droppriv -daemon +daemon 2008 1 0 Aug21 ? 00:00:03 /usr/sbin/atd +dbus 2027 1 0 Aug21 ? 00:00:00 dbus-daemon-1 --system +root 2041 1 0 Aug21 ? 00:00:00 cups-config-daemon +root 2052 1 0 Aug21 ? 00:05:00 hald +root 2062 1 0 Aug21 tty1 00:00:00 /sbin/mingetty tty1 +root 2124 1 0 Aug21 ? 00:00:00 /usr/bin/gdm-binary -nodaemon +root 2184 2124 0 Aug21 ? 00:00:00 /usr/bin/gdm-binary -nodaemon +root 2354 2184 1 Aug21 ? 12:18:15 /usr/X11R6/bin/X :0 -audit 0 -auth /var/gdm/:0.Xauth -nolisten tcp vt7 +kaz 2551 2184 0 Aug21 ? 00:00:01 /usr/bin/gnome-session +kaz 2579 1 0 Aug21 ? 00:00:00 /usr/bin/ssh-agent -s +kaz 2625 1 0 Aug21 ? 00:00:00 /usr/bin/dbus-launch --exit-with-session /etc/X11/xinit/Xclients +kaz 2626 1 0 Aug21 ? 00:00:00 dbus-daemon-1 --fork --print-pid 8 --print-address 6 --session +kaz 2631 1 0 Aug21 ? 00:00:47 /usr/libexec/gconfd-2 11 +kaz 2634 1 0 Aug21 ? 00:00:00 /usr/bin/gnome-keyring-daemon +kaz 2636 1 0 Aug21 ? 00:00:00 /usr/libexec/bonobo-activation-server --ac-activate --ior-output-fd=18 +kaz 2638 1 0 Aug21 ? 00:00:00 /usr/libexec/gnome-settings-daemon --oaf-activate-iid=OAFIID:GNOME_SettingsDaemon --oaf-ior-fd=22 +kaz 2644 1 0 Aug21 ? 00:13:10 /usr/libexec/gam_server +kaz 2661 1 0 Aug21 ? 00:01:18 xscreensaver -nosplash +kaz 2685 1 0 Aug21 ? 00:00:00 /usr/bin/metacity --sm-client-id=default1 +kaz 2689 1 0 Aug21 ? 00:00:02 gnome-panel --sm-client-id default2 +kaz 2691 1 0 Aug21 ? 00:27:25 nautilus --no-default-window --sm-client-id default3 +kaz 2693 1 0 Aug21 ? 00:00:00 gnome-volume-manager --sm-client-id default6 +kaz 2695 1 0 Aug21 ? 00:00:37 eggcups --sm-client-id default5 +kaz 2698 1 0 Aug21 ? 00:00:00 /usr/libexec/gnome-vfs-daemon --oaf-activate-iid=OAFIID:GNOME_VFS_Daemon_Factory --oaf-ior-fd=28 +kaz 2701 1 0 Aug21 ? 00:01:31 pam-panel-icon --sm-client-id default0 +kaz 2707 1 1 Aug21 ? 11:09:59 /usr/bin/python /usr/bin/rhn-applet-gui --sm-client-id default4 +root 2717 2701 0 Aug21 ? 00:02:30 /sbin/pam_timestamp_check -d root +kaz 2718 1 0 Aug21 ? 00:00:05 /usr/libexec/mapping-daemon +kaz 2720 1 0 Aug21 ? 00:00:00 /usr/libexec/wnck-applet --oaf-activate-iid=OAFIID:GNOME_Wncklet_Factory --oaf-ior-fd=30 +kaz 2722 1 0 Aug21 ? 00:14:36 /usr/libexec/mixer_applet2 --oaf-activate-iid=OAFIID:GNOME_MixerApplet_Factory --oaf-ior-fd=32 +kaz 2726 1 0 Aug21 ? 00:43:09 /usr/libexec/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=34 +kaz 2728 1 0 Aug21 ? 00:00:00 /usr/libexec/notification-area-applet --oaf-activate-iid=OAFIID:GNOME_NotificationAreaApplet_Factory --oaf-ior-fd=36 +root 30737 1 0 Aug26 ? 00:00:00 /sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0 +root 31905 1887 0 Aug27 ? 00:00:06 sshd: kaz [priv] +kaz 31907 31905 0 Aug27 ? 00:00:55 sshd: kaz@pts/2 +kaz 31908 31907 0 Aug27 pts/2 00:00:01 -bash +root 32672 1887 0 Aug27 ? 00:00:06 sshd: kaz [priv] +kaz 32674 32672 0 Aug27 ? 00:02:11 sshd: kaz@pts/4 +kaz 32675 32674 0 Aug27 pts/4 00:00:06 -bash +root 27121 3 0 Sep12 ? 00:00:00 [pdflush] +root 27243 3 0 Sep12 ? 00:00:31 [pdflush] +root 27682 1887 0 Sep12 ? 00:00:03 sshd: kaz [priv] +kaz 27684 27682 0 Sep12 ? 00:09:06 sshd: kaz@pts/1 +kaz 27685 27684 0 Sep12 pts/1 00:00:26 -bash +kaz 6481 27685 0 17:47 pts/1 00:00:00 ps -ef diff --git a/tests/001/query-1.expected b/tests/001/query-1.expected new file mode 100644 index 00000000..e55250c9 --- /dev/null +++ b/tests/001/query-1.expected @@ -0,0 +1,688 @@ +UID[0]="root" +UID[1]="root" +UID[2]="root" +UID[3]="root" +UID[4]="root" +UID[5]="root" +UID[6]="root" +UID[7]="root" +UID[8]="root" +UID[9]="root" +UID[10]="root" +UID[11]="root" +UID[12]="root" +UID[13]="root" +UID[14]="root" +UID[15]="root" +UID[16]="root" +UID[17]="root" +UID[18]="rpc" +UID[19]="rpcuser" +UID[20]="root" +UID[21]="root" +UID[22]="root" +UID[23]="root" +UID[24]="root" +UID[25]="root" +UID[26]="root" +UID[27]="root" +UID[28]="root" +UID[29]="root" +UID[30]="root" +UID[31]="root" +UID[32]="root" +UID[33]="root" +UID[34]="root" +UID[35]="root" +UID[36]="root" +UID[37]="root" +UID[38]="root" +UID[39]="root" +UID[40]="xfs" +UID[41]="daemon" +UID[42]="dbus" +UID[43]="root" +UID[44]="root" +UID[45]="root" +UID[46]="root" +UID[47]="root" +UID[48]="root" +UID[49]="kaz" +UID[50]="kaz" +UID[51]="kaz" +UID[52]="kaz" +UID[53]="kaz" +UID[54]="kaz" +UID[55]="kaz" +UID[56]="kaz" +UID[57]="kaz" +UID[58]="kaz" +UID[59]="kaz" +UID[60]="kaz" +UID[61]="kaz" +UID[62]="kaz" +UID[63]="kaz" +UID[64]="kaz" +UID[65]="kaz" +UID[66]="kaz" +UID[67]="root" +UID[68]="kaz" +UID[69]="kaz" +UID[70]="kaz" +UID[71]="kaz" +UID[72]="kaz" +UID[73]="root" +UID[74]="root" +UID[75]="kaz" +UID[76]="kaz" +UID[77]="root" +UID[78]="kaz" +UID[79]="kaz" +UID[80]="root" +UID[81]="root" +UID[82]="root" +UID[83]="kaz" +UID[84]="kaz" +UID[85]="kaz" +PID[0]="1" +PID[1]="2" +PID[2]="3" +PID[3]="4" +PID[4]="5" +PID[5]="16" +PID[6]="29" +PID[7]="17" +PID[8]="28" +PID[9]="103" +PID[10]="175" +PID[11]="186" +PID[12]="870" +PID[13]="1068" +PID[14]="1235" +PID[15]="1236" +PID[16]="1620" +PID[17]="1624" +PID[18]="1645" +PID[19]="1665" +PID[20]="1698" +PID[21]="1766" +PID[22]="1790" +PID[23]="1791" +PID[24]="1821" +PID[25]="1839" +PID[26]="1851" +PID[27]="1887" +PID[28]="1902" +PID[29]="1921" +PID[30]="1925" +PID[31]="1926" +PID[32]="1927" +PID[33]="1928" +PID[34]="1929" +PID[35]="1930" +PID[36]="1931" +PID[37]="1932" +PID[38]="1936" +PID[39]="1963" +PID[40]="1989" +PID[41]="2008" +PID[42]="2027" +PID[43]="2041" +PID[44]="2052" +PID[45]="2062" +PID[46]="2124" +PID[47]="2184" +PID[48]="2354" +PID[49]="2551" +PID[50]="2579" +PID[51]="2625" +PID[52]="2626" +PID[53]="2631" +PID[54]="2634" +PID[55]="2636" +PID[56]="2638" +PID[57]="2644" +PID[58]="2661" +PID[59]="2685" +PID[60]="2689" +PID[61]="2691" +PID[62]="2693" +PID[63]="2695" +PID[64]="2698" +PID[65]="2701" +PID[66]="2707" +PID[67]="2717" +PID[68]="2718" +PID[69]="2720" +PID[70]="2722" +PID[71]="2726" +PID[72]="2728" +PID[73]="30737" +PID[74]="31905" +PID[75]="31907" +PID[76]="31908" +PID[77]="32672" +PID[78]="32674" +PID[79]="32675" +PID[80]="27121" +PID[81]="27243" +PID[82]="27682" +PID[83]="27684" +PID[84]="27685" +PID[85]="6481" +PPID[0]="0" +PPID[1]="1" +PPID[2]="1" +PPID[3]="3" +PPID[4]="3" +PPID[5]="3" +PPID[6]="3" +PPID[7]="1" +PPID[8]="1" +PPID[9]="1" +PPID[10]="1" +PPID[11]="1" +PPID[12]="1" +PPID[13]="1" +PPID[14]="1" +PPID[15]="1" +PPID[16]="1" +PPID[17]="1" +PPID[18]="1" +PPID[19]="1" +PPID[20]="1" +PPID[21]="1" +PPID[22]="1" +PPID[23]="1" +PPID[24]="1" +PPID[25]="1" +PPID[26]="1" +PPID[27]="1" +PPID[28]="1" +PPID[29]="1" +PPID[30]="1" +PPID[31]="1" +PPID[32]="1" +PPID[33]="1" +PPID[34]="1" +PPID[35]="1" +PPID[36]="1" +PPID[37]="1" +PPID[38]="1" +PPID[39]="1" +PPID[40]="1" +PPID[41]="1" +PPID[42]="1" +PPID[43]="1" +PPID[44]="1" +PPID[45]="1" +PPID[46]="1" +PPID[47]="2124" +PPID[48]="2184" +PPID[49]="2184" +PPID[50]="1" +PPID[51]="1" +PPID[52]="1" +PPID[53]="1" +PPID[54]="1" +PPID[55]="1" +PPID[56]="1" +PPID[57]="1" +PPID[58]="1" +PPID[59]="1" +PPID[60]="1" +PPID[61]="1" +PPID[62]="1" +PPID[63]="1" +PPID[64]="1" +PPID[65]="1" +PPID[66]="1" +PPID[67]="2701" +PPID[68]="1" +PPID[69]="1" +PPID[70]="1" +PPID[71]="1" +PPID[72]="1" +PPID[73]="1" +PPID[74]="1887" +PPID[75]="31905" +PPID[76]="31907" +PPID[77]="1887" +PPID[78]="32672" +PPID[79]="32674" +PPID[80]="3" +PPID[81]="3" +PPID[82]="1887" +PPID[83]="27682" +PPID[84]="27684" +PPID[85]="27685" +C[0]="0" +C[1]="0" +C[2]="0" +C[3]="0" +C[4]="0" +C[5]="0" +C[6]="0" +C[7]="0" +C[8]="0" +C[9]="0" +C[10]="0" +C[11]="0" +C[12]="0" +C[13]="0" +C[14]="0" +C[15]="0" +C[16]="0" +C[17]="0" +C[18]="0" +C[19]="0" +C[20]="0" +C[21]="0" +C[22]="0" +C[23]="0" +C[24]="0" +C[25]="0" +C[26]="0" +C[27]="0" +C[28]="0" +C[29]="0" +C[30]="0" +C[31]="0" +C[32]="0" +C[33]="0" +C[34]="0" +C[35]="0" +C[36]="0" +C[37]="0" +C[38]="0" +C[39]="0" +C[40]="0" +C[41]="0" +C[42]="0" +C[43]="0" +C[44]="0" +C[45]="0" +C[46]="0" +C[47]="0" +C[48]="1" +C[49]="0" +C[50]="0" +C[51]="0" +C[52]="0" +C[53]="0" +C[54]="0" +C[55]="0" +C[56]="0" +C[57]="0" +C[58]="0" +C[59]="0" +C[60]="0" +C[61]="0" +C[62]="0" +C[63]="0" +C[64]="0" +C[65]="0" +C[66]="1" +C[67]="0" +C[68]="0" +C[69]="0" +C[70]="0" +C[71]="0" +C[72]="0" +C[73]="0" +C[74]="0" +C[75]="0" +C[76]="0" +C[77]="0" +C[78]="0" +C[79]="0" +C[80]="0" +C[81]="0" +C[82]="0" +C[83]="0" +C[84]="0" +C[85]="0" +STIME[0]="Aug21" +STIME[1]="Aug21" +STIME[2]="Aug21" +STIME[3]="Aug21" +STIME[4]="Aug21" +STIME[5]="Aug21" +STIME[6]="Aug21" +STIME[7]="Aug21" +STIME[8]="Aug21" +STIME[9]="Aug21" +STIME[10]="Aug21" +STIME[11]="Aug21" +STIME[12]="Aug21" +STIME[13]="Aug21" +STIME[14]="Aug21" +STIME[15]="Aug21" +STIME[16]="Aug21" +STIME[17]="Aug21" +STIME[18]="Aug21" +STIME[19]="Aug21" +STIME[20]="Aug21" +STIME[21]="Aug21" +STIME[22]="Aug21" +STIME[23]="Aug21" +STIME[24]="Aug21" +STIME[25]="Aug21" +STIME[26]="Aug21" +STIME[27]="Aug21" +STIME[28]="Aug21" +STIME[29]="Aug21" +STIME[30]="Aug21" +STIME[31]="Aug21" +STIME[32]="Aug21" +STIME[33]="Aug21" +STIME[34]="Aug21" +STIME[35]="Aug21" +STIME[36]="Aug21" +STIME[37]="Aug21" +STIME[38]="Aug21" +STIME[39]="Aug21" +STIME[40]="Aug21" +STIME[41]="Aug21" +STIME[42]="Aug21" +STIME[43]="Aug21" +STIME[44]="Aug21" +STIME[45]="Aug21" +STIME[46]="Aug21" +STIME[47]="Aug21" +STIME[48]="Aug21" +STIME[49]="Aug21" +STIME[50]="Aug21" +STIME[51]="Aug21" +STIME[52]="Aug21" +STIME[53]="Aug21" +STIME[54]="Aug21" +STIME[55]="Aug21" +STIME[56]="Aug21" +STIME[57]="Aug21" +STIME[58]="Aug21" +STIME[59]="Aug21" +STIME[60]="Aug21" +STIME[61]="Aug21" +STIME[62]="Aug21" +STIME[63]="Aug21" +STIME[64]="Aug21" +STIME[65]="Aug21" +STIME[66]="Aug21" +STIME[67]="Aug21" +STIME[68]="Aug21" +STIME[69]="Aug21" +STIME[70]="Aug21" +STIME[71]="Aug21" +STIME[72]="Aug21" +STIME[73]="Aug26" +STIME[74]="Aug27" +STIME[75]="Aug27" +STIME[76]="Aug27" +STIME[77]="Aug27" +STIME[78]="Aug27" +STIME[79]="Aug27" +STIME[80]="Sep12" +STIME[81]="Sep12" +STIME[82]="Sep12" +STIME[83]="Sep12" +STIME[84]="Sep12" +STIME[85]="17:47" +TTY[0]="?" +TTY[1]="?" +TTY[2]="?" +TTY[3]="?" +TTY[4]="?" +TTY[5]="?" +TTY[6]="?" +TTY[7]="?" +TTY[8]="?" +TTY[9]="?" +TTY[10]="?" +TTY[11]="?" +TTY[12]="?" +TTY[13]="?" +TTY[14]="?" +TTY[15]="?" +TTY[16]="?" +TTY[17]="?" +TTY[18]="?" +TTY[19]="?" +TTY[20]="?" +TTY[21]="?" +TTY[22]="?" +TTY[23]="?" +TTY[24]="?" +TTY[25]="?" +TTY[26]="?" +TTY[27]="?" +TTY[28]="?" +TTY[29]="?" +TTY[30]="?" +TTY[31]="?" +TTY[32]="?" +TTY[33]="?" +TTY[34]="?" +TTY[35]="?" +TTY[36]="?" +TTY[37]="?" +TTY[38]="?" +TTY[39]="?" +TTY[40]="?" +TTY[41]="?" +TTY[42]="?" +TTY[43]="?" +TTY[44]="?" +TTY[45]="tty1" +TTY[46]="?" +TTY[47]="?" +TTY[48]="?" +TTY[49]="?" +TTY[50]="?" +TTY[51]="?" +TTY[52]="?" +TTY[53]="?" +TTY[54]="?" +TTY[55]="?" +TTY[56]="?" +TTY[57]="?" +TTY[58]="?" +TTY[59]="?" +TTY[60]="?" +TTY[61]="?" +TTY[62]="?" +TTY[63]="?" +TTY[64]="?" +TTY[65]="?" +TTY[66]="?" +TTY[67]="?" +TTY[68]="?" +TTY[69]="?" +TTY[70]="?" +TTY[71]="?" +TTY[72]="?" +TTY[73]="?" +TTY[74]="?" +TTY[75]="?" +TTY[76]="pts/2" +TTY[77]="?" +TTY[78]="?" +TTY[79]="pts/4" +TTY[80]="?" +TTY[81]="?" +TTY[82]="?" +TTY[83]="?" +TTY[84]="pts/1" +TTY[85]="pts/1" +TIME[0]="00:01:11" +TIME[1]="00:00:00" +TIME[2]="00:01:23" +TIME[3]="00:00:00" +TIME[4]="00:00:00" +TIME[5]="00:00:00" +TIME[6]="00:00:00" +TIME[7]="00:00:00" +TIME[8]="00:00:06" +TIME[9]="00:00:00" +TIME[10]="00:00:00" +TIME[11]="00:04:49" +TIME[12]="00:00:00" +TIME[13]="00:00:00" +TIME[14]="00:00:00" +TIME[15]="00:00:09" +TIME[16]="00:00:16" +TIME[17]="00:00:00" +TIME[18]="00:00:08" +TIME[19]="00:00:00" +TIME[20]="00:00:07" +TIME[21]="00:05:17" +TIME[22]="00:00:23" +TIME[23]="00:00:00" +TIME[24]="00:00:00" +TIME[25]="00:00:00" +TIME[26]="00:01:33" +TIME[27]="00:00:00" +TIME[28]="00:00:00" +TIME[29]="00:00:00" +TIME[30]="00:00:00" +TIME[31]="00:00:00" +TIME[32]="00:00:00" +TIME[33]="00:00:00" +TIME[34]="00:00:00" +TIME[35]="00:00:00" +TIME[36]="00:00:00" +TIME[37]="00:00:00" +TIME[38]="00:00:00" +TIME[39]="00:00:29" +TIME[40]="00:00:01" +TIME[41]="00:00:03" +TIME[42]="00:00:00" +TIME[43]="00:00:00" +TIME[44]="00:05:00" +TIME[45]="00:00:00" +TIME[46]="00:00:00" +TIME[47]="00:00:00" +TIME[48]="12:18:15" +TIME[49]="00:00:01" +TIME[50]="00:00:00" +TIME[51]="00:00:00" +TIME[52]="00:00:00" +TIME[53]="00:00:47" +TIME[54]="00:00:00" +TIME[55]="00:00:00" +TIME[56]="00:00:00" +TIME[57]="00:13:10" +TIME[58]="00:01:18" +TIME[59]="00:00:00" +TIME[60]="00:00:02" +TIME[61]="00:27:25" +TIME[62]="00:00:00" +TIME[63]="00:00:37" +TIME[64]="00:00:00" +TIME[65]="00:01:31" +TIME[66]="11:09:59" +TIME[67]="00:02:30" +TIME[68]="00:00:05" +TIME[69]="00:00:00" +TIME[70]="00:14:36" +TIME[71]="00:43:09" +TIME[72]="00:00:00" +TIME[73]="00:00:00" +TIME[74]="00:00:06" +TIME[75]="00:00:55" +TIME[76]="00:00:01" +TIME[77]="00:00:06" +TIME[78]="00:02:11" +TIME[79]="00:00:06" +TIME[80]="00:00:00" +TIME[81]="00:00:31" +TIME[82]="00:00:03" +TIME[83]="00:09:06" +TIME[84]="00:00:26" +TIME[85]="00:00:00" +CMD[0]="init [5]" +CMD[1]="[ksoftirqd/0]" +CMD[2]="[events/0]" +CMD[3]="[khelper]" +CMD[4]="[kacpid]" +CMD[5]="[kblockd/0]" +CMD[6]="[aio/0]" +CMD[7]="[khubd]" +CMD[8]="[kswapd0]" +CMD[9]="[kseriod]" +CMD[10]="[scsi_eh_0]" +CMD[11]="[kjournald]" +CMD[12]="udevd" +CMD[13]="/sbin/dhclient -1" +CMD[14]="[kjournald]" +CMD[15]="[kjournald]" +CMD[16]="syslogd -m" +CMD[17]="klogd -x" +CMD[18]="portmap" +CMD[19]="rpc.statd" +CMD[20]="rpc.idmapd" +CMD[21]="/usr/sbin/vmware-guestd --background" +CMD[22]="[rpciod]" +CMD[23]="[lockd]" +CMD[24]="ypbind" +CMD[25]="/usr/sbin/acpid" +CMD[26]="cupsd" +CMD[27]="/usr/sbin/sshd" +CMD[28]="xinetd -stayalive" +CMD[29]="rpc.rquotad" +CMD[30]="[nfsd]" +CMD[31]="[nfsd]" +CMD[32]="[nfsd]" +CMD[33]="[nfsd]" +CMD[34]="[nfsd]" +CMD[35]="[nfsd]" +CMD[36]="[nfsd]" +CMD[37]="[nfsd]" +CMD[38]="rpc.mountd" +CMD[39]="crond" +CMD[40]="xfs -droppriv" +CMD[41]="/usr/sbin/atd" +CMD[42]="dbus-daemon-1 --system" +CMD[43]="cups-config-daemon" +CMD[44]="hald" +CMD[45]="/sbin/mingetty tty1" +CMD[46]="/usr/bin/gdm-binary -nodaemon" +CMD[47]="/usr/bin/gdm-binary -nodaemon" +CMD[48]="/usr/X11R6/bin/X :0" +CMD[49]="/usr/bin/gnome-session" +CMD[50]="/usr/bin/ssh-agent -s" +CMD[51]="/usr/bin/dbus-launch --exit-with-session" +CMD[52]="dbus-daemon-1 --fork" +CMD[53]="/usr/libexec/gconfd-2 11" +CMD[54]="/usr/bin/gnome-keyring-daemon" +CMD[55]="/usr/libexec/bonobo-activation-server --ac-activate" +CMD[56]="/usr/libexec/gnome-settings-daemon --oaf-activate-iid=OAFIID:GNOME_SettingsDaemon" +CMD[57]="/usr/libexec/gam_server" +CMD[58]="xscreensaver -nosplash" +CMD[59]="/usr/bin/metacity --sm-client-id=default1" +CMD[60]="gnome-panel --sm-client-id" +CMD[61]="nautilus --no-default-window" +CMD[62]="gnome-volume-manager --sm-client-id" +CMD[63]="eggcups --sm-client-id" +CMD[64]="/usr/libexec/gnome-vfs-daemon --oaf-activate-iid=OAFIID:GNOME_VFS_Daemon_Factory" +CMD[65]="pam-panel-icon --sm-client-id" +CMD[66]="/usr/bin/python /usr/bin/rhn-applet-gui" +CMD[67]="/sbin/pam_timestamp_check -d" +CMD[68]="/usr/libexec/mapping-daemon" +CMD[69]="/usr/libexec/wnck-applet --oaf-activate-iid=OAFIID:GNOME_Wncklet_Factory" +CMD[70]="/usr/libexec/mixer_applet2 --oaf-activate-iid=OAFIID:GNOME_MixerApplet_Factory" +CMD[71]="/usr/libexec/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory" +CMD[72]="/usr/libexec/notification-area-applet --oaf-activate-iid=OAFIID:GNOME_NotificationAreaApplet_Factory" +CMD[73]="/sbin/dhclient -1" +CMD[74]="sshd: kaz" +CMD[75]="sshd: kaz@pts/2" +CMD[76]="-bash" +CMD[77]="sshd: kaz" +CMD[78]="sshd: kaz@pts/4" +CMD[79]="-bash" +CMD[80]="[pdflush]" +CMD[81]="[pdflush]" +CMD[82]="sshd: kaz" +CMD[83]="sshd: kaz@pts/1" +CMD[84]="-bash" +CMD[85]="ps -ef" diff --git a/tests/001/query-1.txr b/tests/001/query-1.txr new file mode 100644 index 00000000..8b37b62d --- /dev/null +++ b/tests/001/query-1.txr @@ -0,0 +1,7 @@ +@# +@# This file is in the public domain. +@# It was authored by Kaz Kylheku in 2009 +@# +@(collect) +@UID@/ +/@{PID /[0-9]+/}@/ +/@PPID@/ +/@C@/ +/@STIME@/ +/@TTY@/ +/@TIME @{CMD /[^ ]+( +[^ ]+)?/}@/.*/ +@(end) diff --git a/tests/001/query-2.expected b/tests/001/query-2.expected new file mode 100644 index 00000000..90f363ce --- /dev/null +++ b/tests/001/query-2.expected @@ -0,0 +1,696 @@ +UID[0]="UID" +UID[1]="root" +UID[2]="root" +UID[3]="root" +UID[4]="root" +UID[5]="root" +UID[6]="root" +UID[7]="root" +UID[8]="root" +UID[9]="root" +UID[10]="root" +UID[11]="root" +UID[12]="root" +UID[13]="root" +UID[14]="root" +UID[15]="root" +UID[16]="root" +UID[17]="root" +UID[18]="root" +UID[19]="rpc" +UID[20]="rpcuser" +UID[21]="root" +UID[22]="root" +UID[23]="root" +UID[24]="root" +UID[25]="root" +UID[26]="root" +UID[27]="root" +UID[28]="root" +UID[29]="root" +UID[30]="root" +UID[31]="root" +UID[32]="root" +UID[33]="root" +UID[34]="root" +UID[35]="root" +UID[36]="root" +UID[37]="root" +UID[38]="root" +UID[39]="root" +UID[40]="root" +UID[41]="xfs" +UID[42]="daemon" +UID[43]="dbus" +UID[44]="root" +UID[45]="root" +UID[46]="root" +UID[47]="root" +UID[48]="root" +UID[49]="root" +UID[50]="kaz" +UID[51]="kaz" +UID[52]="kaz" +UID[53]="kaz" +UID[54]="kaz" +UID[55]="kaz" +UID[56]="kaz" +UID[57]="kaz" +UID[58]="kaz" +UID[59]="kaz" +UID[60]="kaz" +UID[61]="kaz" +UID[62]="kaz" +UID[63]="kaz" +UID[64]="kaz" +UID[65]="kaz" +UID[66]="kaz" +UID[67]="kaz" +UID[68]="root" +UID[69]="kaz" +UID[70]="kaz" +UID[71]="kaz" +UID[72]="kaz" +UID[73]="kaz" +UID[74]="root" +UID[75]="root" +UID[76]="kaz" +UID[77]="kaz" +UID[78]="root" +UID[79]="kaz" +UID[80]="kaz" +UID[81]="root" +UID[82]="root" +UID[83]="root" +UID[84]="kaz" +UID[85]="kaz" +UID[86]="kaz" +PID[0]="PID" +PID[1]="1" +PID[2]="2" +PID[3]="3" +PID[4]="4" +PID[5]="5" +PID[6]="16" +PID[7]="29" +PID[8]="17" +PID[9]="28" +PID[10]="103" +PID[11]="175" +PID[12]="186" +PID[13]="870" +PID[14]="1068" +PID[15]="1235" +PID[16]="1236" +PID[17]="1620" +PID[18]="1624" +PID[19]="1645" +PID[20]="1665" +PID[21]="1698" +PID[22]="1766" +PID[23]="1790" +PID[24]="1791" +PID[25]="1821" +PID[26]="1839" +PID[27]="1851" +PID[28]="1887" +PID[29]="1902" +PID[30]="1921" +PID[31]="1925" +PID[32]="1926" +PID[33]="1927" +PID[34]="1928" +PID[35]="1929" +PID[36]="1930" +PID[37]="1931" +PID[38]="1932" +PID[39]="1936" +PID[40]="1963" +PID[41]="1989" +PID[42]="2008" +PID[43]="2027" +PID[44]="2041" +PID[45]="2052" +PID[46]="2062" +PID[47]="2124" +PID[48]="2184" +PID[49]="2354" +PID[50]="2551" +PID[51]="2579" +PID[52]="2625" +PID[53]="2626" +PID[54]="2631" +PID[55]="2634" +PID[56]="2636" +PID[57]="2638" +PID[58]="2644" +PID[59]="2661" +PID[60]="2685" +PID[61]="2689" +PID[62]="2691" +PID[63]="2693" +PID[64]="2695" +PID[65]="2698" +PID[66]="2701" +PID[67]="2707" +PID[68]="2717" +PID[69]="2718" +PID[70]="2720" +PID[71]="2722" +PID[72]="2726" +PID[73]="2728" +PID[74]="30737" +PID[75]="31905" +PID[76]="31907" +PID[77]="31908" +PID[78]="32672" +PID[79]="32674" +PID[80]="32675" +PID[81]="27121" +PID[82]="27243" +PID[83]="27682" +PID[84]="27684" +PID[85]="27685" +PID[86]="6481" +PPID[0]="PPID" +PPID[1]="0" +PPID[2]="1" +PPID[3]="1" +PPID[4]="3" +PPID[5]="3" +PPID[6]="3" +PPID[7]="3" +PPID[8]="1" +PPID[9]="1" +PPID[10]="1" +PPID[11]="1" +PPID[12]="1" +PPID[13]="1" +PPID[14]="1" +PPID[15]="1" +PPID[16]="1" +PPID[17]="1" +PPID[18]="1" +PPID[19]="1" +PPID[20]="1" +PPID[21]="1" +PPID[22]="1" +PPID[23]="1" +PPID[24]="1" +PPID[25]="1" +PPID[26]="1" +PPID[27]="1" +PPID[28]="1" +PPID[29]="1" +PPID[30]="1" +PPID[31]="1" +PPID[32]="1" +PPID[33]="1" +PPID[34]="1" +PPID[35]="1" +PPID[36]="1" +PPID[37]="1" +PPID[38]="1" +PPID[39]="1" +PPID[40]="1" +PPID[41]="1" +PPID[42]="1" +PPID[43]="1" +PPID[44]="1" +PPID[45]="1" +PPID[46]="1" +PPID[47]="1" +PPID[48]="2124" +PPID[49]="2184" +PPID[50]="2184" +PPID[51]="1" +PPID[52]="1" +PPID[53]="1" +PPID[54]="1" +PPID[55]="1" +PPID[56]="1" +PPID[57]="1" +PPID[58]="1" +PPID[59]="1" +PPID[60]="1" +PPID[61]="1" +PPID[62]="1" +PPID[63]="1" +PPID[64]="1" +PPID[65]="1" +PPID[66]="1" +PPID[67]="1" +PPID[68]="2701" +PPID[69]="1" +PPID[70]="1" +PPID[71]="1" +PPID[72]="1" +PPID[73]="1" +PPID[74]="1" +PPID[75]="1887" +PPID[76]="31905" +PPID[77]="31907" +PPID[78]="1887" +PPID[79]="32672" +PPID[80]="32674" +PPID[81]="3" +PPID[82]="3" +PPID[83]="1887" +PPID[84]="27682" +PPID[85]="27684" +PPID[86]="27685" +C[0]="C" +C[1]="0" +C[2]="0" +C[3]="0" +C[4]="0" +C[5]="0" +C[6]="0" +C[7]="0" +C[8]="0" +C[9]="0" +C[10]="0" +C[11]="0" +C[12]="0" +C[13]="0" +C[14]="0" +C[15]="0" +C[16]="0" +C[17]="0" +C[18]="0" +C[19]="0" +C[20]="0" +C[21]="0" +C[22]="0" +C[23]="0" +C[24]="0" +C[25]="0" +C[26]="0" +C[27]="0" +C[28]="0" +C[29]="0" +C[30]="0" +C[31]="0" +C[32]="0" +C[33]="0" +C[34]="0" +C[35]="0" +C[36]="0" +C[37]="0" +C[38]="0" +C[39]="0" +C[40]="0" +C[41]="0" +C[42]="0" +C[43]="0" +C[44]="0" +C[45]="0" +C[46]="0" +C[47]="0" +C[48]="0" +C[49]="1" +C[50]="0" +C[51]="0" +C[52]="0" +C[53]="0" +C[54]="0" +C[55]="0" +C[56]="0" +C[57]="0" +C[58]="0" +C[59]="0" +C[60]="0" +C[61]="0" +C[62]="0" +C[63]="0" +C[64]="0" +C[65]="0" +C[66]="0" +C[67]="1" +C[68]="0" +C[69]="0" +C[70]="0" +C[71]="0" +C[72]="0" +C[73]="0" +C[74]="0" +C[75]="0" +C[76]="0" +C[77]="0" +C[78]="0" +C[79]="0" +C[80]="0" +C[81]="0" +C[82]="0" +C[83]="0" +C[84]="0" +C[85]="0" +C[86]="0" +STIME[0]="STIME" +STIME[1]="Aug21" +STIME[2]="Aug21" +STIME[3]="Aug21" +STIME[4]="Aug21" +STIME[5]="Aug21" +STIME[6]="Aug21" +STIME[7]="Aug21" +STIME[8]="Aug21" +STIME[9]="Aug21" +STIME[10]="Aug21" +STIME[11]="Aug21" +STIME[12]="Aug21" +STIME[13]="Aug21" +STIME[14]="Aug21" +STIME[15]="Aug21" +STIME[16]="Aug21" +STIME[17]="Aug21" +STIME[18]="Aug21" +STIME[19]="Aug21" +STIME[20]="Aug21" +STIME[21]="Aug21" +STIME[22]="Aug21" +STIME[23]="Aug21" +STIME[24]="Aug21" +STIME[25]="Aug21" +STIME[26]="Aug21" +STIME[27]="Aug21" +STIME[28]="Aug21" +STIME[29]="Aug21" +STIME[30]="Aug21" +STIME[31]="Aug21" +STIME[32]="Aug21" +STIME[33]="Aug21" +STIME[34]="Aug21" +STIME[35]="Aug21" +STIME[36]="Aug21" +STIME[37]="Aug21" +STIME[38]="Aug21" +STIME[39]="Aug21" +STIME[40]="Aug21" +STIME[41]="Aug21" +STIME[42]="Aug21" +STIME[43]="Aug21" +STIME[44]="Aug21" +STIME[45]="Aug21" +STIME[46]="Aug21" +STIME[47]="Aug21" +STIME[48]="Aug21" +STIME[49]="Aug21" +STIME[50]="Aug21" +STIME[51]="Aug21" +STIME[52]="Aug21" +STIME[53]="Aug21" +STIME[54]="Aug21" +STIME[55]="Aug21" +STIME[56]="Aug21" +STIME[57]="Aug21" +STIME[58]="Aug21" +STIME[59]="Aug21" +STIME[60]="Aug21" +STIME[61]="Aug21" +STIME[62]="Aug21" +STIME[63]="Aug21" +STIME[64]="Aug21" +STIME[65]="Aug21" +STIME[66]="Aug21" +STIME[67]="Aug21" +STIME[68]="Aug21" +STIME[69]="Aug21" +STIME[70]="Aug21" +STIME[71]="Aug21" +STIME[72]="Aug21" +STIME[73]="Aug21" +STIME[74]="Aug26" +STIME[75]="Aug27" +STIME[76]="Aug27" +STIME[77]="Aug27" +STIME[78]="Aug27" +STIME[79]="Aug27" +STIME[80]="Aug27" +STIME[81]="Sep12" +STIME[82]="Sep12" +STIME[83]="Sep12" +STIME[84]="Sep12" +STIME[85]="Sep12" +STIME[86]="17:47" +TTY[0]="TTY" +TTY[1]="?" +TTY[2]="?" +TTY[3]="?" +TTY[4]="?" +TTY[5]="?" +TTY[6]="?" +TTY[7]="?" +TTY[8]="?" +TTY[9]="?" +TTY[10]="?" +TTY[11]="?" +TTY[12]="?" +TTY[13]="?" +TTY[14]="?" +TTY[15]="?" +TTY[16]="?" +TTY[17]="?" +TTY[18]="?" +TTY[19]="?" +TTY[20]="?" +TTY[21]="?" +TTY[22]="?" +TTY[23]="?" +TTY[24]="?" +TTY[25]="?" +TTY[26]="?" +TTY[27]="?" +TTY[28]="?" +TTY[29]="?" +TTY[30]="?" +TTY[31]="?" +TTY[32]="?" +TTY[33]="?" +TTY[34]="?" +TTY[35]="?" +TTY[36]="?" +TTY[37]="?" +TTY[38]="?" +TTY[39]="?" +TTY[40]="?" +TTY[41]="?" +TTY[42]="?" +TTY[43]="?" +TTY[44]="?" +TTY[45]="?" +TTY[46]="tty1" +TTY[47]="?" +TTY[48]="?" +TTY[49]="?" +TTY[50]="?" +TTY[51]="?" +TTY[52]="?" +TTY[53]="?" +TTY[54]="?" +TTY[55]="?" +TTY[56]="?" +TTY[57]="?" +TTY[58]="?" +TTY[59]="?" +TTY[60]="?" +TTY[61]="?" +TTY[62]="?" +TTY[63]="?" +TTY[64]="?" +TTY[65]="?" +TTY[66]="?" +TTY[67]="?" +TTY[68]="?" +TTY[69]="?" +TTY[70]="?" +TTY[71]="?" +TTY[72]="?" +TTY[73]="?" +TTY[74]="?" +TTY[75]="?" +TTY[76]="?" +TTY[77]="pts/2" +TTY[78]="?" +TTY[79]="?" +TTY[80]="pts/4" +TTY[81]="?" +TTY[82]="?" +TTY[83]="?" +TTY[84]="?" +TTY[85]="pts/1" +TTY[86]="pts/1" +TIME[0]="TIME" +TIME[1]="00:01:11" +TIME[2]="00:00:00" +TIME[3]="00:01:23" +TIME[4]="00:00:00" +TIME[5]="00:00:00" +TIME[6]="00:00:00" +TIME[7]="00:00:00" +TIME[8]="00:00:00" +TIME[9]="00:00:06" +TIME[10]="00:00:00" +TIME[11]="00:00:00" +TIME[12]="00:04:49" +TIME[13]="00:00:00" +TIME[14]="00:00:00" +TIME[15]="00:00:00" +TIME[16]="00:00:09" +TIME[17]="00:00:16" +TIME[18]="00:00:00" +TIME[19]="00:00:08" +TIME[20]="00:00:00" +TIME[21]="00:00:07" +TIME[22]="00:05:17" +TIME[23]="00:00:23" +TIME[24]="00:00:00" +TIME[25]="00:00:00" +TIME[26]="00:00:00" +TIME[27]="00:01:33" +TIME[28]="00:00:00" +TIME[29]="00:00:00" +TIME[30]="00:00:00" +TIME[31]="00:00:00" +TIME[32]="00:00:00" +TIME[33]="00:00:00" +TIME[34]="00:00:00" +TIME[35]="00:00:00" +TIME[36]="00:00:00" +TIME[37]="00:00:00" +TIME[38]="00:00:00" +TIME[39]="00:00:00" +TIME[40]="00:00:29" +TIME[41]="00:00:01" +TIME[42]="00:00:03" +TIME[43]="00:00:00" +TIME[44]="00:00:00" +TIME[45]="00:05:00" +TIME[46]="00:00:00" +TIME[47]="00:00:00" +TIME[48]="00:00:00" +TIME[49]="12:18:15" +TIME[50]="00:00:01" +TIME[51]="00:00:00" +TIME[52]="00:00:00" +TIME[53]="00:00:00" +TIME[54]="00:00:47" +TIME[55]="00:00:00" +TIME[56]="00:00:00" +TIME[57]="00:00:00" +TIME[58]="00:13:10" +TIME[59]="00:01:18" +TIME[60]="00:00:00" +TIME[61]="00:00:02" +TIME[62]="00:27:25" +TIME[63]="00:00:00" +TIME[64]="00:00:37" +TIME[65]="00:00:00" +TIME[66]="00:01:31" +TIME[67]="11:09:59" +TIME[68]="00:02:30" +TIME[69]="00:00:05" +TIME[70]="00:00:00" +TIME[71]="00:14:36" +TIME[72]="00:43:09" +TIME[73]="00:00:00" +TIME[74]="00:00:00" +TIME[75]="00:00:06" +TIME[76]="00:00:55" +TIME[77]="00:00:01" +TIME[78]="00:00:06" +TIME[79]="00:02:11" +TIME[80]="00:00:06" +TIME[81]="00:00:00" +TIME[82]="00:00:31" +TIME[83]="00:00:03" +TIME[84]="00:09:06" +TIME[85]="00:00:26" +TIME[86]="00:00:00" +CMD[0]="CMD" +CMD[1]="init [5] " +CMD[2]="[ksoftirqd/0]" +CMD[3]="[events/0]" +CMD[4]="[khelper]" +CMD[5]="[kacpid]" +CMD[6]="[kblockd/0]" +CMD[7]="[aio/0]" +CMD[8]="[khubd]" +CMD[9]="[kswapd0]" +CMD[10]="[kseriod]" +CMD[11]="[scsi_eh_0]" +CMD[12]="[kjournald]" +CMD[13]="udevd" +CMD[14]="/sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0" +CMD[15]="[kjournald]" +CMD[16]="[kjournald]" +CMD[17]="syslogd -m 0" +CMD[18]="klogd -x" +CMD[19]="portmap" +CMD[20]="rpc.statd" +CMD[21]="rpc.idmapd" +CMD[22]="/usr/sbin/vmware-guestd --background /var/run/vmware-guestd.pid" +CMD[23]="[rpciod]" +CMD[24]="[lockd]" +CMD[25]="ypbind" +CMD[26]="/usr/sbin/acpid" +CMD[27]="cupsd" +CMD[28]="/usr/sbin/sshd" +CMD[29]="xinetd -stayalive -pidfile /var/run/xinetd.pid" +CMD[30]="rpc.rquotad" +CMD[31]="[nfsd]" +CMD[32]="[nfsd]" +CMD[33]="[nfsd]" +CMD[34]="[nfsd]" +CMD[35]="[nfsd]" +CMD[36]="[nfsd]" +CMD[37]="[nfsd]" +CMD[38]="[nfsd]" +CMD[39]="rpc.mountd" +CMD[40]="crond" +CMD[41]="xfs -droppriv -daemon" +CMD[42]="/usr/sbin/atd" +CMD[43]="dbus-daemon-1 --system" +CMD[44]="cups-config-daemon" +CMD[45]="hald" +CMD[46]="/sbin/mingetty tty1" +CMD[47]="/usr/bin/gdm-binary -nodaemon" +CMD[48]="/usr/bin/gdm-binary -nodaemon" +CMD[49]="/usr/X11R6/bin/X :0 -audit 0 -auth /var/gdm/:0.Xauth -nolisten tcp vt7" +CMD[50]="/usr/bin/gnome-session" +CMD[51]="/usr/bin/ssh-agent -s" +CMD[52]="/usr/bin/dbus-launch --exit-with-session /etc/X11/xinit/Xclients" +CMD[53]="dbus-daemon-1 --fork --print-pid 8 --print-address 6 --session" +CMD[54]="/usr/libexec/gconfd-2 11" +CMD[55]="/usr/bin/gnome-keyring-daemon" +CMD[56]="/usr/libexec/bonobo-activation-server --ac-activate --ior-output-fd=18" +CMD[57]="/usr/libexec/gnome-settings-daemon --oaf-activate-iid=OAFIID:GNOME_SettingsDaemon --oaf-ior-fd=22" +CMD[58]="/usr/libexec/gam_server" +CMD[59]="xscreensaver -nosplash" +CMD[60]="/usr/bin/metacity --sm-client-id=default1" +CMD[61]="gnome-panel --sm-client-id default2" +CMD[62]="nautilus --no-default-window --sm-client-id default3" +CMD[63]="gnome-volume-manager --sm-client-id default6" +CMD[64]="eggcups --sm-client-id default5" +CMD[65]="/usr/libexec/gnome-vfs-daemon --oaf-activate-iid=OAFIID:GNOME_VFS_Daemon_Factory --oaf-ior-fd=28" +CMD[66]="pam-panel-icon --sm-client-id default0" +CMD[67]="/usr/bin/python /usr/bin/rhn-applet-gui --sm-client-id default4" +CMD[68]="/sbin/pam_timestamp_check -d root" +CMD[69]="/usr/libexec/mapping-daemon" +CMD[70]="/usr/libexec/wnck-applet --oaf-activate-iid=OAFIID:GNOME_Wncklet_Factory --oaf-ior-fd=30" +CMD[71]="/usr/libexec/mixer_applet2 --oaf-activate-iid=OAFIID:GNOME_MixerApplet_Factory --oaf-ior-fd=32" +CMD[72]="/usr/libexec/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=34" +CMD[73]="/usr/libexec/notification-area-applet --oaf-activate-iid=OAFIID:GNOME_NotificationAreaApplet_Factory --oaf-ior-fd=36" +CMD[74]="/sbin/dhclient -1 -q -lf /var/lib/dhcp/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0" +CMD[75]="sshd: kaz [priv] " +CMD[76]="sshd: kaz@pts/2 " +CMD[77]="-bash" +CMD[78]="sshd: kaz [priv] " +CMD[79]="sshd: kaz@pts/4 " +CMD[80]="-bash" +CMD[81]="[pdflush]" +CMD[82]="[pdflush]" +CMD[83]="sshd: kaz [priv] " +CMD[84]="sshd: kaz@pts/1 " +CMD[85]="-bash" +CMD[86]="ps -ef" diff --git a/tests/001/query-2.txr b/tests/001/query-2.txr new file mode 100644 index 00000000..c040ca9f --- /dev/null +++ b/tests/001/query-2.txr @@ -0,0 +1,7 @@ +@# +@# This file is in the public domain. +@# It was authored by Kaz Kylheku in 2009 +@# +@(collect) +@{UID 8} @{PID 5} @{PPID 5} @{C 1} @{STIME 5} @{TTY 8} @{TIME 8} @CMD +@(end) diff --git a/tests/001/query-3.expected b/tests/001/query-3.expected new file mode 100644 index 00000000..4acab394 --- /dev/null +++ b/tests/001/query-3.expected @@ -0,0 +1,87 @@ +UID PID +root 1 +root 2 +root 3 +root 4 +root 5 +root 16 +root 29 +root 17 +root 28 +root 103 +root 175 +root 186 +root 870 +root 1068 +root 1235 +root 1236 +root 1620 +root 1624 +rpc 1645 +rpcuser 1665 +root 1698 +root 1766 +root 1790 +root 1791 +root 1821 +root 1839 +root 1851 +root 1887 +root 1902 +root 1921 +root 1925 +root 1926 +root 1927 +root 1928 +root 1929 +root 1930 +root 1931 +root 1932 +root 1936 +root 1963 +xfs 1989 +daemon 2008 +dbus 2027 +root 2041 +root 2052 +root 2062 +root 2124 +root 2184 +root 2354 +kaz 2551 +kaz 2579 +kaz 2625 +kaz 2626 +kaz 2631 +kaz 2634 +kaz 2636 +kaz 2638 +kaz 2644 +kaz 2661 +kaz 2685 +kaz 2689 +kaz 2691 +kaz 2693 +kaz 2695 +kaz 2698 +kaz 2701 +kaz 2707 +root 2717 +kaz 2718 +kaz 2720 +kaz 2722 +kaz 2726 +kaz 2728 +root 30737 +root 31905 +kaz 31907 +kaz 31908 +root 32672 +kaz 32674 +kaz 32675 +root 27121 +root 27243 +root 27682 +kaz 27684 +kaz 27685 +kaz 6481 diff --git a/tests/001/query-3.txr b/tests/001/query-3.txr new file mode 100644 index 00000000..ec12c9f2 --- /dev/null +++ b/tests/001/query-3.txr @@ -0,0 +1,21 @@ +@# +@# This file is in the public domain. +@# It was authored by Kaz Kylheku in 2009 +@# +@/.*/@# skip header +@(collect) +@ (coll)@{TOKEN /[^ ]+/}@(end) +@ (bind (UID PID PPID C STIME TTY TIME . CMD) TOKEN) +@ (cat CMD) @# +@ (forget TOKEN) +@(end) +@(output) +@(repeat) +@{UID 8} @{PID -5} +@(first) +UID PID +@{UID 8} @{PID -5} +@(empty) +No processes! +@(end) +@(end) diff --git a/tests/002/etc/passwd b/tests/002/etc/passwd new file mode 100644 index 00000000..d7bf21b0 --- /dev/null +++ b/tests/002/etc/passwd @@ -0,0 +1,32 @@ +root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +adm:x:3:4:adm:/var/adm:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/sbin/nologin +news:x:9:13:news:/etc/news: +uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin +operator:x:11:0:operator:/root:/sbin/nologin +games:x:12:100:games:/usr/games:/sbin/nologin +gopher:x:13:30:gopher:/var/gopher:/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin +nobody:x:99:99:Nobody:/:/sbin/nologin +dbus:x:81:81:System message bus:/:/sbin/nologin +vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin +rpm:x:37:37::/var/lib/rpm:/sbin/nologin +haldaemon:x:68:68:HAL daemon:/:/sbin/nologin +netdump:x:34:34:Network Crash Dump user:/var/crash:/bin/bash +nscd:x:28:28:NSCD Daemon:/:/sbin/nologin +sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin +rpc:x:32:32:Portmapper RPC user:/:/sbin/nologin +rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin +nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin +mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin +smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin +pcap:x:77:77::/var/arpwatch:/sbin/nologin +xfs:x:43:43:X Font Server:/etc/X11/fs:/sbin/nologin +ntp:x:38:38::/etc/ntp:/sbin/nologin +gdm:x:42:42::/var/gdm:/sbin/nologin diff --git a/tests/002/proc/1/status b/tests/002/proc/1/status new file mode 100644 index 00000000..722c84b6 --- /dev/null +++ b/tests/002/proc/1/status @@ -0,0 +1,31 @@ +Name: init +State: S (sleeping) +SleepAVG: 88% +Tgid: 1 +Pid: 1 +PPid: 0 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1920 kB +VmLck: 0 kB +VmRSS: 552 kB +VmData: 180 kB +VmStk: 324 kB +VmExe: 27 kB +VmLib: 1353 kB +StaBrk: 08050000 kB +Brk: 09714000 kB +StaStk: bffb2830 kB +ExecLim: 0804f000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: fffffffe57f0d8fc +SigCgt: 00000000280b2603 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1/task/1/stat b/tests/002/proc/1/task/1/stat new file mode 100644 index 00000000..cd0c6dd8 --- /dev/null +++ b/tests/002/proc/1/task/1/stat @@ -0,0 +1 @@ +1 (init) S 0 0 0 0 -1 4194560 787 8132519 20 1725 10 7247 29847 236686 16 0 1 0 56 1966080 138 4294967295 134512640 134541009 3220908080 3220898444 2340770 0 0 1475401980 671819267 3222765173 0 0 0 0 0 0 diff --git a/tests/002/proc/103/status b/tests/002/proc/103/status new file mode 100644 index 00000000..ce0c54f9 --- /dev/null +++ b/tests/002/proc/103/status @@ -0,0 +1,20 @@ +Name: kseriod +State: S (sleeping) +SleepAVG: 97% +Tgid: 103 +Pid: 103 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffbfff +SigIgn: 0000000000000000 +SigCgt: 0000000000004100 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/103/task/103/stat b/tests/002/proc/103/task/103/stat new file mode 100644 index 00000000..87dd4271 --- /dev/null +++ b/tests/002/proc/103/task/103/stat @@ -0,0 +1 @@ +103 (kseriod) S 1 1 1 0 -1 64 0 0 0 0 0 2 0 0 15 0 1 0 68 0 0 4294967295 0 0 0 0 0 0 2147467263 0 16640 3223538745 0 0 17 0 0 0 diff --git a/tests/002/proc/1068/status b/tests/002/proc/1068/status new file mode 100644 index 00000000..1ee30bf7 --- /dev/null +++ b/tests/002/proc/1068/status @@ -0,0 +1,31 @@ +Name: dhclient +State: S (sleeping) +SleepAVG: 90% +Tgid: 1068 +Pid: 1068 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 2872 kB +VmLck: 0 kB +VmRSS: 1068 kB +VmData: 328 kB +VmStk: 736 kB +VmExe: 349 kB +VmLib: 1391 kB +StaBrk: 080ae000 kB +Brk: 099d7000 kB +StaStk: bff4ae00 kB +ExecLim: 0809f000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1068/task/1068/stat b/tests/002/proc/1068/task/1068/stat new file mode 100644 index 00000000..31a36593 --- /dev/null +++ b/tests/002/proc/1068/task/1068/stat @@ -0,0 +1 @@ +1068 (dhclient) S 1 1068 1068 0 -1 4227136 231 33968 0 0 3 67 3 167 6 -10 1 0 4355 2940928 267 4294967295 134508544 134865956 3220483584 3220482684 2340770 0 0 0 0 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1235/status b/tests/002/proc/1235/status new file mode 100644 index 00000000..b7e28314 --- /dev/null +++ b/tests/002/proc/1235/status @@ -0,0 +1,20 @@ +Name: kjournald +State: S (sleeping) +SleepAVG: 9% +Tgid: 1235 +Pid: 1235 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1235/task/1235/stat b/tests/002/proc/1235/task/1235/stat new file mode 100644 index 00000000..18b620ce --- /dev/null +++ b/tests/002/proc/1235/task/1235/stat @@ -0,0 +1 @@ +1235 (kjournald) S 1 1 1 0 -1 4194368 0 0 0 0 0 0 0 0 24 0 1 0 6213 0 0 4294967295 0 0 0 0 0 0 2147483647 0 0 4170054760 0 0 17 0 0 0 diff --git a/tests/002/proc/1236/status b/tests/002/proc/1236/status new file mode 100644 index 00000000..459cdaf6 --- /dev/null +++ b/tests/002/proc/1236/status @@ -0,0 +1,20 @@ +Name: kjournald +State: S (sleeping) +SleepAVG: 98% +Tgid: 1236 +Pid: 1236 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 000000000000feff +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1236/task/1236/stat b/tests/002/proc/1236/task/1236/stat new file mode 100644 index 00000000..e0d98f40 --- /dev/null +++ b/tests/002/proc/1236/task/1236/stat @@ -0,0 +1 @@ +1236 (kjournald) S 1 1 1 0 -1 4194368 0 0 0 0 0 954 0 0 15 0 1 0 6217 0 0 4294967295 0 0 0 0 0 0 2147483647 0 65279 4170054760 0 0 17 0 0 0 diff --git a/tests/002/proc/15812/status b/tests/002/proc/15812/status new file mode 100644 index 00000000..597790df --- /dev/null +++ b/tests/002/proc/15812/status @@ -0,0 +1,31 @@ +Name: ssh +State: S (sleeping) +SleepAVG: 88% +Tgid: 15812 +Pid: 15812 +PPid: 32675 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 4184 kB +VmLck: 0 kB +VmRSS: 2348 kB +VmData: 644 kB +VmStk: 48 kB +VmExe: 230 kB +VmLib: 3066 kB +StaBrk: 0014f000 kB +Brk: 0806b000 kB +StaStk: bffff9a0 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000008004006 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/15812/task/15812/stat b/tests/002/proc/15812/task/15812/stat new file mode 100644 index 00000000..36790164 --- /dev/null +++ b/tests/002/proc/15812/task/15812/stat @@ -0,0 +1 @@ +15812 (ssh) S 32675 15812 32675 34820 15812 4194304 696 0 0 0 151 4315 0 0 16 0 1 0 184209784 4284416 587 4294967295 1118208 1354060 3221223840 3221214156 3086915490 0 0 4096 134234118 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/16/status b/tests/002/proc/16/status new file mode 100644 index 00000000..d14fa89b --- /dev/null +++ b/tests/002/proc/16/status @@ -0,0 +1,20 @@ +Name: kblockd/0 +State: S (sleeping) +SleepAVG: 98% +Tgid: 16 +Pid: 16 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/16/task/16/stat b/tests/002/proc/16/task/16/stat new file mode 100644 index 00000000..01052f69 --- /dev/null +++ b/tests/002/proc/16/task/16/stat @@ -0,0 +1 @@ +16 (kblockd/0) S 3 0 0 0 -1 32832 0 0 0 0 0 47 0 0 5 -10 1 0 62 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222484651 0 0 17 0 0 0 diff --git a/tests/002/proc/1620/status b/tests/002/proc/1620/status new file mode 100644 index 00000000..dccb9e72 --- /dev/null +++ b/tests/002/proc/1620/status @@ -0,0 +1,31 @@ +Name: syslogd +State: S (sleeping) +SleepAVG: 88% +Tgid: 1620 +Pid: 1620 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1516 kB +VmLck: 0 kB +VmRSS: 628 kB +VmData: 148 kB +VmStk: 16 kB +VmExe: 28 kB +VmLib: 1288 kB +StaBrk: 0011a000 kB +Brk: 08021000 kB +StaStk: bffffe20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000206 +SigCgt: 0000000000016001 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1620/task/1620/stat b/tests/002/proc/1620/task/1620/stat new file mode 100644 index 00000000..c3378aec --- /dev/null +++ b/tests/002/proc/1620/task/1620/stat @@ -0,0 +1 @@ +1620 (syslogd) S 1 1620 1620 0 -1 4194368 91 0 0 0 8 1685 0 0 16 0 1 3000 8195 1552384 157 4294967295 1118208 1147540 3221224992 3221223468 3086915490 0 0 518 90113 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1624/status b/tests/002/proc/1624/status new file mode 100644 index 00000000..6882a4a7 --- /dev/null +++ b/tests/002/proc/1624/status @@ -0,0 +1,31 @@ +Name: klogd +State: S (sleeping) +SleepAVG: 88% +Tgid: 1624 +Pid: 1624 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1456 kB +VmLck: 0 kB +VmRSS: 464 kB +VmData: 152 kB +VmStk: 8 kB +VmExe: 19 kB +VmLib: 1249 kB +StaBrk: 00118000 kB +Brk: 08021000 kB +StaStk: bffffe20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: fffffffe7ff1b4fc +SigCgt: 00000000000a4a03 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1624/task/1624/stat b/tests/002/proc/1624/task/1624/stat new file mode 100644 index 00000000..456fa43d --- /dev/null +++ b/tests/002/proc/1624/task/1624/stat @@ -0,0 +1 @@ +1624 (klogd) S 1 1624 1624 0 -1 4194624 41 0 0 0 0 6 0 0 16 0 1 0 8206 1490944 116 4294967295 1118208 1138592 3221224992 3221224740 3086915490 0 0 2146546940 674307 3222406663 0 0 17 0 0 0 diff --git a/tests/002/proc/16248/status b/tests/002/proc/16248/status new file mode 100644 index 00000000..0756ddf5 --- /dev/null +++ b/tests/002/proc/16248/status @@ -0,0 +1,31 @@ +Name: su +State: S (sleeping) +SleepAVG: 83% +Tgid: 16248 +Pid: 16248 +PPid: 31908 +TracerPid: 0 +Uid: 524 0 0 0 +Gid: 503 503 503 0 +FDSize: 256 +Groups: 501 503 512 +VmSize: 4300 kB +VmLck: 0 kB +VmRSS: 1216 kB +VmData: 392 kB +VmStk: 24 kB +VmExe: 18 kB +VmLib: 1690 kB +StaBrk: 00117000 kB +Brk: 08021000 kB +StaStk: bffff9a0 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffe7ffb9eff +SigIgn: 0000000000000000 +SigCgt: 0000000000004000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/16248/task/16248/stat b/tests/002/proc/16248/task/16248/stat new file mode 100644 index 00000000..709c1906 --- /dev/null +++ b/tests/002/proc/16248/task/16248/stat @@ -0,0 +1 @@ +16248 (su) S 31908 16248 31908 34818 29839 4194560 398 0 0 0 0 1 0 0 17 0 1 0 361193770 4403200 304 4294967295 1118208 1137492 3221223840 3221223220 3086915490 0 2147196671 0 16384 3222425215 0 0 17 0 0 0 diff --git a/tests/002/proc/16249/status b/tests/002/proc/16249/status new file mode 100644 index 00000000..fb71b0b0 --- /dev/null +++ b/tests/002/proc/16249/status @@ -0,0 +1,31 @@ +Name: bash +State: S (sleeping) +SleepAVG: 88% +Tgid: 16249 +Pid: 16249 +PPid: 16248 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 256 +Groups: 0 1 2 3 4 6 10 606 +VmSize: 4340 kB +VmLck: 0 kB +VmRSS: 1464 kB +VmData: 296 kB +VmStk: 20 kB +VmExe: 577 kB +VmLib: 1307 kB +StaBrk: 080e3000 kB +Brk: 08122000 kB +StaStk: bffffeb0 kB +ExecLim: 080d8000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000010000 +SigBlk: 0000000000010000 +SigIgn: 0000000000384004 +SigCgt: 000000004b813efb +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/16249/task/16249/stat b/tests/002/proc/16249/task/16249/stat new file mode 100644 index 00000000..186edd84 --- /dev/null +++ b/tests/002/proc/16249/task/16249/stat @@ -0,0 +1 @@ +16249 (bash) S 16248 16249 31908 34818 29839 4194560 4193 733480 0 0 3 90 15 3364 16 0 1 0 361193918 4444160 366 4294967295 134508544 135099520 3221225136 3221223204 2340770 0 65536 3686404 1266761467 3222425215 0 0 17 0 0 0 diff --git a/tests/002/proc/1645/status b/tests/002/proc/1645/status new file mode 100644 index 00000000..4084d915 --- /dev/null +++ b/tests/002/proc/1645/status @@ -0,0 +1,31 @@ +Name: portmap +State: S (sleeping) +SleepAVG: 88% +Tgid: 1645 +Pid: 1645 +PPid: 1 +TracerPid: 0 +Uid: 32 32 32 32 +Gid: 32 32 32 32 +FDSize: 32 +Groups: +VmSize: 1604 kB +VmLck: 0 kB +VmRSS: 632 kB +VmData: 156 kB +VmStk: 20 kB +VmExe: 27 kB +VmLib: 1357 kB +StaBrk: 00119000 kB +Brk: 08021000 kB +StaStk: bffffe30 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000011000 +SigCgt: 0000000000000002 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/1645/task/1645/stat b/tests/002/proc/1645/task/1645/stat new file mode 100644 index 00000000..dd085ba8 --- /dev/null +++ b/tests/002/proc/1645/task/1645/stat @@ -0,0 +1 @@ +1645 (portmap) S 1 1645 1645 0 -1 4194624 43040 0 1 0 29 870 0 0 16 0 1 0 8233 1642496 158 4294967295 1118208 1146168 3221225008 3221224700 3086915490 0 0 69632 2 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1665/status b/tests/002/proc/1665/status new file mode 100644 index 00000000..87c0b24f --- /dev/null +++ b/tests/002/proc/1665/status @@ -0,0 +1,31 @@ +Name: rpc.statd +State: S (sleeping) +SleepAVG: 88% +Tgid: 1665 +Pid: 1665 +PPid: 1 +TracerPid: 0 +Uid: 29 29 29 29 +Gid: 29 29 29 29 +FDSize: 32 +Groups: +VmSize: 1676 kB +VmLck: 0 kB +VmRSS: 796 kB +VmData: 156 kB +VmStk: 12 kB +VmExe: 38 kB +VmLib: 1414 kB +StaBrk: 0011c000 kB +Brk: 08021000 kB +StaStk: bffffe30 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000011000 +SigCgt: 0000000000004203 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/1665/task/1665/stat b/tests/002/proc/1665/task/1665/stat new file mode 100644 index 00000000..82a47421 --- /dev/null +++ b/tests/002/proc/1665/task/1665/stat @@ -0,0 +1 @@ +1665 (rpc.statd) S 1 1665 1665 0 -1 4194624 156 0 0 0 4 54 0 0 16 0 1 0 8250 1716224 199 4294967295 1118208 1157716 3221225008 3221224092 3086915490 0 0 69632 16899 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1698/status b/tests/002/proc/1698/status new file mode 100644 index 00000000..d7bc5d80 --- /dev/null +++ b/tests/002/proc/1698/status @@ -0,0 +1,31 @@ +Name: rpc.idmapd +State: S (sleeping) +SleepAVG: 88% +Tgid: 1698 +Pid: 1698 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 3964 kB +VmLck: 0 kB +VmRSS: 1044 kB +VmData: 344 kB +VmStk: 8 kB +VmExe: 39 kB +VmLib: 3393 kB +StaBrk: 08055000 kB +Brk: 08076000 kB +StaStk: bffffe20 kB +ExecLim: 08051000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000a01 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1698/task/1698/stat b/tests/002/proc/1698/task/1698/stat new file mode 100644 index 00000000..ece1a38d --- /dev/null +++ b/tests/002/proc/1698/task/1698/stat @@ -0,0 +1 @@ +1698 (rpc.idmapd) S 1 1698 1698 0 -1 4194368 44 0 0 0 3 814 0 0 16 0 1 0 8312 4059136 261 4294967295 134508544 134549496 3221224992 3221224160 2340770 0 0 0 2561 0 0 0 17 0 0 0 diff --git a/tests/002/proc/17/status b/tests/002/proc/17/status new file mode 100644 index 00000000..b5ce79c8 --- /dev/null +++ b/tests/002/proc/17/status @@ -0,0 +1,20 @@ +Name: khubd +State: S (sleeping) +SleepAVG: 0% +Tgid: 17 +Pid: 17 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffeff +SigIgn: 0000000000000000 +SigCgt: 0000000000004100 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/17/task/17/stat b/tests/002/proc/17/task/17/stat new file mode 100644 index 00000000..6efd905b --- /dev/null +++ b/tests/002/proc/17/task/17/stat @@ -0,0 +1 @@ +17 (khubd) S 1 1 1 0 -1 64 0 0 0 0 0 0 0 0 25 0 1 0 63 0 0 4294967295 0 0 0 0 0 0 2147483391 0 16640 3223828654 0 0 17 0 0 0 diff --git a/tests/002/proc/175/status b/tests/002/proc/175/status new file mode 100644 index 00000000..639924fa --- /dev/null +++ b/tests/002/proc/175/status @@ -0,0 +1,20 @@ +Name: scsi_eh_0 +State: S (sleeping) +SleepAVG: 29% +Tgid: 175 +Pid: 175 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/175/task/175/stat b/tests/002/proc/175/task/175/stat new file mode 100644 index 00000000..33f34646 --- /dev/null +++ b/tests/002/proc/175/task/175/stat @@ -0,0 +1 @@ +175 (scsi_eh_0) S 1 1 1 0 -1 32832 0 0 0 0 0 0 0 0 22 0 1 0 511 0 0 4294967295 0 0 0 0 0 0 2147483647 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1766/status b/tests/002/proc/1766/status new file mode 100644 index 00000000..8096c2ba --- /dev/null +++ b/tests/002/proc/1766/status @@ -0,0 +1,31 @@ +Name: vmware-guestd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1766 +Pid: 1766 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1588 kB +VmLck: 0 kB +VmRSS: 496 kB +VmData: 164 kB +VmStk: 16 kB +VmExe: 131 kB +VmLib: 1301 kB +StaBrk: 0806e000 kB +Brk: 0808f000 kB +StaStk: bffffdc0 kB +ExecLim: ffffffff +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000004a07 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1766/task/1766/stat b/tests/002/proc/1766/task/1766/stat new file mode 100644 index 00000000..116d84e4 --- /dev/null +++ b/tests/002/proc/1766/task/1766/stat @@ -0,0 +1 @@ +1766 (vmware-guestd) S 1 1766 1766 0 -1 320 99 134485 0 0 7949 24362 10 1014 15 0 1 0 8505 1626112 124 4294967295 134508544 134642788 3221224896 3221223516 2340770 0 0 0 18951 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1790/status b/tests/002/proc/1790/status new file mode 100644 index 00000000..44486c30 --- /dev/null +++ b/tests/002/proc/1790/status @@ -0,0 +1,20 @@ +Name: rpciod +State: S (sleeping) +SleepAVG: 98% +Tgid: 1790 +Pid: 1790 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffeff +SigIgn: 0000000000000000 +SigCgt: 0000000000000100 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1790/task/1790/stat b/tests/002/proc/1790/task/1790/stat new file mode 100644 index 00000000..dc92506d --- /dev/null +++ b/tests/002/proc/1790/task/1790/stat @@ -0,0 +1 @@ +1790 (rpciod) S 1 1 1 0 -1 4194368 0 0 0 0 0 2366 0 0 15 0 1 0 8870 0 0 4294967295 0 0 0 0 0 0 2147483391 0 256 4171735819 0 0 17 0 0 0 diff --git a/tests/002/proc/1791/status b/tests/002/proc/1791/status new file mode 100644 index 00000000..42548907 --- /dev/null +++ b/tests/002/proc/1791/status @@ -0,0 +1,20 @@ +Name: lockd +State: S (sleeping) +SleepAVG: 68% +Tgid: 1791 +Pid: 1791 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffeff +SigIgn: 0000000000000000 +SigCgt: 0000000000000100 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1791/task/1791/stat b/tests/002/proc/1791/task/1791/stat new file mode 100644 index 00000000..4f961c85 --- /dev/null +++ b/tests/002/proc/1791/task/1791/stat @@ -0,0 +1 @@ +1791 (lockd) S 1 1 1 0 -1 4194368 0 0 0 0 0 0 0 0 18 0 1 0 8871 0 0 4294967295 0 0 0 0 0 0 2147483391 0 256 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1821/status b/tests/002/proc/1821/status new file mode 100644 index 00000000..6d138cd8 --- /dev/null +++ b/tests/002/proc/1821/status @@ -0,0 +1,31 @@ +Name: ypbind +State: S (sleeping) +SleepAVG: 87% +Tgid: 1821 +Pid: 1821 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 24164 kB +VmLck: 0 kB +VmRSS: 808 kB +VmData: 20652 kB +VmStk: 16 kB +VmExe: 27 kB +VmLib: 1377 kB +StaBrk: 08050000 kB +Brk: 08071000 kB +StaStk: bffffe30 kB +ExecLim: 0804f000 +Threads: 3 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000014407 +SigIgn: 0000000000000000 +SigCgt: 0000000180000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1821/task/1821/stat b/tests/002/proc/1821/task/1821/stat new file mode 100644 index 00000000..d501d22c --- /dev/null +++ b/tests/002/proc/1821/task/1821/stat @@ -0,0 +1 @@ +1821 (ypbind) S 1 1820 1820 0 -1 4194624 42 0 0 0 0 1 0 0 17 0 3 0 8956 24743936 202 4294967295 134512640 134540552 3221225008 3221224476 2340770 0 82951 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1821/task/1822/stat b/tests/002/proc/1821/task/1822/stat new file mode 100644 index 00000000..63cb2b0c --- /dev/null +++ b/tests/002/proc/1821/task/1822/stat @@ -0,0 +1 @@ +1822 (ypbind) S 1 1820 1820 0 -1 4194368 5 0 0 0 0 0 0 0 23 0 3 0 8956 24743936 202 4294967295 134512640 134540552 3221225008 3084800692 2340770 0 0 0 0 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/1821/task/1826/stat b/tests/002/proc/1821/task/1826/stat new file mode 100644 index 00000000..5a396aff --- /dev/null +++ b/tests/002/proc/1821/task/1826/stat @@ -0,0 +1 @@ +1826 (ypbind) S 1 1820 1820 0 -1 4194624 7 0 0 0 18 5402 0 0 16 0 3 0 8959 24743936 202 4294967295 134512640 134540552 3221225008 3074310752 2340770 0 82951 0 0 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/1839/status b/tests/002/proc/1839/status new file mode 100644 index 00000000..9a9e8380 --- /dev/null +++ b/tests/002/proc/1839/status @@ -0,0 +1,31 @@ +Name: acpid +State: S (sleeping) +SleepAVG: 12% +Tgid: 1839 +Pid: 1839 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1460 kB +VmLck: 0 kB +VmRSS: 548 kB +VmData: 148 kB +VmStk: 16 kB +VmExe: 17 kB +VmLib: 1251 kB +StaBrk: 0804e000 kB +Brk: 0806f000 kB +StaStk: bffffe20 kB +ExecLim: 0804c000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000004007 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1839/task/1839/stat b/tests/002/proc/1839/task/1839/stat new file mode 100644 index 00000000..2573613f --- /dev/null +++ b/tests/002/proc/1839/task/1839/stat @@ -0,0 +1 @@ +1839 (acpid) S 1 1839 1839 0 -1 4194368 91 0 0 0 0 0 0 0 24 0 1 0 8976 1495040 137 4294967295 134508544 134526724 3221224992 3221224092 2340770 0 0 4096 16391 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1851/status b/tests/002/proc/1851/status new file mode 100644 index 00000000..84d5c10e --- /dev/null +++ b/tests/002/proc/1851/status @@ -0,0 +1,31 @@ +Name: cupsd +State: S (sleeping) +SleepAVG: 88% +Tgid: 1851 +Pid: 1851 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 7780 kB +VmLck: 0 kB +VmRSS: 2252 kB +VmData: 1544 kB +VmStk: 104 kB +VmExe: 243 kB +VmLib: 3649 kB +StaBrk: 00150000 kB +Brk: 08038000 kB +StaStk: bffffe30 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000016201 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1851/task/1851/stat b/tests/002/proc/1851/task/1851/stat new file mode 100644 index 00000000..6847d8b2 --- /dev/null +++ b/tests/002/proc/1851/task/1851/stat @@ -0,0 +1 @@ +1851 (cupsd) S 1 1851 1851 0 -1 4194624 12577 6075 1 5 154 9399 0 31 16 0 1 0 9095 7966720 563 4294967295 1118208 1367304 3221225008 3221207052 3086915490 0 0 4096 90625 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/186/status b/tests/002/proc/186/status new file mode 100644 index 00000000..6eac3e48 --- /dev/null +++ b/tests/002/proc/186/status @@ -0,0 +1,20 @@ +Name: kjournald +State: S (sleeping) +SleepAVG: 98% +Tgid: 186 +Pid: 186 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/186/task/186/stat b/tests/002/proc/186/task/186/stat new file mode 100644 index 00000000..941871d0 --- /dev/null +++ b/tests/002/proc/186/task/186/stat @@ -0,0 +1 @@ +186 (kjournald) S 1 1 1 0 -1 64 0 0 0 0 0 29336 0 0 15 0 1 0 845 0 0 4294967295 0 0 0 0 0 0 2147483647 0 0 4170054760 0 0 17 0 0 0 diff --git a/tests/002/proc/1887/status b/tests/002/proc/1887/status new file mode 100644 index 00000000..79391da3 --- /dev/null +++ b/tests/002/proc/1887/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 87% +Tgid: 1887 +Pid: 1887 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 3924 kB +VmLck: 0 kB +VmRSS: 1652 kB +VmData: 356 kB +VmStk: 16 kB +VmExe: 295 kB +VmLib: 3069 kB +StaBrk: 00161000 kB +Brk: 08021000 kB +StaStk: bffffe20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000014005 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1887/task/1887/stat b/tests/002/proc/1887/task/1887/stat new file mode 100644 index 00000000..848f1662 --- /dev/null +++ b/tests/002/proc/1887/task/1887/stat @@ -0,0 +1 @@ +1887 (sshd) S 1 1887 1887 0 -1 4194624 318 27221747 0 854 27 50 861229 380242 16 0 1 360000 9201 4018176 413 4294967295 1118208 1420332 3221224992 3221220652 3086915490 0 0 4096 81925 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1902/status b/tests/002/proc/1902/status new file mode 100644 index 00000000..9311271f --- /dev/null +++ b/tests/002/proc/1902/status @@ -0,0 +1,31 @@ +Name: xinetd +State: S (sleeping) +SleepAVG: 76% +Tgid: 1902 +Pid: 1902 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 2068 kB +VmLck: 0 kB +VmRSS: 860 kB +VmData: 316 kB +VmStk: 12 kB +VmExe: 143 kB +VmLib: 1533 kB +StaBrk: 00137000 kB +Brk: 08021000 kB +StaStk: bffffd90 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000381000 +SigCgt: 000000007fc3eeff +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1902/task/1902/stat b/tests/002/proc/1902/task/1902/stat new file mode 100644 index 00000000..9ff7cc6c --- /dev/null +++ b/tests/002/proc/1902/task/1902/stat @@ -0,0 +1 @@ +1902 (xinetd) S 1 1902 1902 0 -1 4194624 149 0 0 0 0 3 0 0 18 0 1 0 9223 2117632 215 4294967295 1118208 1265004 3221224848 3221224332 3086915490 0 0 3674112 2143547135 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1921/status b/tests/002/proc/1921/status new file mode 100644 index 00000000..0dc21447 --- /dev/null +++ b/tests/002/proc/1921/status @@ -0,0 +1,31 @@ +Name: rpc.rquotad +State: S (sleeping) +SleepAVG: 78% +Tgid: 1921 +Pid: 1921 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 3740 kB +VmLck: 0 kB +VmRSS: 812 kB +VmData: 156 kB +VmStk: 8 kB +VmExe: 58 kB +VmLib: 1414 kB +StaBrk: 00121000 kB +Brk: 08021000 kB +StaStk: bffffe20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000010000 +SigCgt: 0000000000004003 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1921/task/1921/stat b/tests/002/proc/1921/task/1921/stat new file mode 100644 index 00000000..24e001ea --- /dev/null +++ b/tests/002/proc/1921/task/1921/stat @@ -0,0 +1 @@ +1921 (rpc.rquotad) S 1 1921 1921 0 -1 4194368 10 0 0 0 0 0 0 0 16 0 1 0 9314 3829760 203 4294967295 1118208 1178312 3221224992 3221224428 3086915490 0 0 65536 16387 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1925/status b/tests/002/proc/1925/status new file mode 100644 index 00000000..4fa3ce56 --- /dev/null +++ b/tests/002/proc/1925/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1925 +Pid: 1925 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1925/task/1925/stat b/tests/002/proc/1925/task/1925/stat new file mode 100644 index 00000000..13126047 --- /dev/null +++ b/tests/002/proc/1925/task/1925/stat @@ -0,0 +1 @@ +1925 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1926/status b/tests/002/proc/1926/status new file mode 100644 index 00000000..1ddfdcba --- /dev/null +++ b/tests/002/proc/1926/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1926 +Pid: 1926 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1926/task/1926/stat b/tests/002/proc/1926/task/1926/stat new file mode 100644 index 00000000..a77e08ee --- /dev/null +++ b/tests/002/proc/1926/task/1926/stat @@ -0,0 +1 @@ +1926 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1927/status b/tests/002/proc/1927/status new file mode 100644 index 00000000..a1e35914 --- /dev/null +++ b/tests/002/proc/1927/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1927 +Pid: 1927 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1927/task/1927/stat b/tests/002/proc/1927/task/1927/stat new file mode 100644 index 00000000..39ae7655 --- /dev/null +++ b/tests/002/proc/1927/task/1927/stat @@ -0,0 +1 @@ +1927 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1928/status b/tests/002/proc/1928/status new file mode 100644 index 00000000..3d321e6a --- /dev/null +++ b/tests/002/proc/1928/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1928 +Pid: 1928 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1928/task/1928/stat b/tests/002/proc/1928/task/1928/stat new file mode 100644 index 00000000..e5d9a35c --- /dev/null +++ b/tests/002/proc/1928/task/1928/stat @@ -0,0 +1 @@ +1928 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1929/status b/tests/002/proc/1929/status new file mode 100644 index 00000000..eff4d826 --- /dev/null +++ b/tests/002/proc/1929/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1929 +Pid: 1929 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1929/task/1929/stat b/tests/002/proc/1929/task/1929/stat new file mode 100644 index 00000000..87ddc5d2 --- /dev/null +++ b/tests/002/proc/1929/task/1929/stat @@ -0,0 +1 @@ +1929 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1930/status b/tests/002/proc/1930/status new file mode 100644 index 00000000..47cc48e0 --- /dev/null +++ b/tests/002/proc/1930/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1930 +Pid: 1930 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1930/task/1930/stat b/tests/002/proc/1930/task/1930/stat new file mode 100644 index 00000000..80e19691 --- /dev/null +++ b/tests/002/proc/1930/task/1930/stat @@ -0,0 +1 @@ +1930 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9319 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1931/status b/tests/002/proc/1931/status new file mode 100644 index 00000000..083527ae --- /dev/null +++ b/tests/002/proc/1931/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1931 +Pid: 1931 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1931/task/1931/stat b/tests/002/proc/1931/task/1931/stat new file mode 100644 index 00000000..7622b243 --- /dev/null +++ b/tests/002/proc/1931/task/1931/stat @@ -0,0 +1 @@ +1931 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9320 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1932/status b/tests/002/proc/1932/status new file mode 100644 index 00000000..da0270e7 --- /dev/null +++ b/tests/002/proc/1932/status @@ -0,0 +1,20 @@ +Name: nfsd +State: S (sleeping) +SleepAVG: 98% +Tgid: 1932 +Pid: 1932 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: fffffffffffffef8 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1932/task/1932/stat b/tests/002/proc/1932/task/1932/stat new file mode 100644 index 00000000..f23746ae --- /dev/null +++ b/tests/002/proc/1932/task/1932/stat @@ -0,0 +1 @@ +1932 (nfsd) S 1 1 1 0 -1 5242944 0 0 0 0 0 0 0 0 15 0 1 0 9320 0 0 4294967295 0 0 0 0 0 0 2147483384 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1936/status b/tests/002/proc/1936/status new file mode 100644 index 00000000..24164d9e --- /dev/null +++ b/tests/002/proc/1936/status @@ -0,0 +1,31 @@ +Name: rpc.mountd +State: S (sleeping) +SleepAVG: 78% +Tgid: 1936 +Pid: 1936 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1720 kB +VmLck: 0 kB +VmRSS: 788 kB +VmData: 176 kB +VmStk: 16 kB +VmExe: 59 kB +VmLib: 1413 kB +StaBrk: 00126000 kB +Brk: 08021000 kB +StaStk: bffffe20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000011000 +SigCgt: 0000000000004003 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1936/task/1936/stat b/tests/002/proc/1936/task/1936/stat new file mode 100644 index 00000000..a73031b4 --- /dev/null +++ b/tests/002/proc/1936/task/1936/stat @@ -0,0 +1 @@ +1936 (rpc.mountd) S 1 1936 1936 0 -1 4194368 11 0 0 0 0 0 0 0 16 0 1 0 9342 1761280 197 4294967295 1118208 1178768 3221224992 3221224380 3086915490 0 0 69632 16387 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/1963/status b/tests/002/proc/1963/status new file mode 100644 index 00000000..07e9f495 --- /dev/null +++ b/tests/002/proc/1963/status @@ -0,0 +1,31 @@ +Name: crond +State: S (sleeping) +SleepAVG: 88% +Tgid: 1963 +Pid: 1963 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 3680 kB +VmLck: 0 kB +VmRSS: 844 kB +VmData: 148 kB +VmStk: 12 kB +VmExe: 34 kB +VmLib: 1382 kB +StaBrk: 0011b000 kB +Brk: 08021000 kB +StaStk: bffffe30 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000014003 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/1963/task/1963/stat b/tests/002/proc/1963/task/1963/stat new file mode 100644 index 00000000..8de2fa7c --- /dev/null +++ b/tests/002/proc/1963/task/1963/stat @@ -0,0 +1 @@ +1963 (crond) S 1 1963 1963 0 -1 4194368 147407 117767066 0 10 4 2984 51742 613826 16 0 1 0 9365 3768320 211 4294967295 1118208 1154032 3221225008 3221224132 3086915490 0 0 0 81923 0 0 0 17 0 0 0 diff --git a/tests/002/proc/1989/status b/tests/002/proc/1989/status new file mode 100644 index 00000000..286f5635 --- /dev/null +++ b/tests/002/proc/1989/status @@ -0,0 +1,31 @@ +Name: xfs +State: S (sleeping) +SleepAVG: 88% +Tgid: 1989 +Pid: 1989 +PPid: 1 +TracerPid: 0 +Uid: 43 43 43 43 +Gid: 43 43 43 43 +FDSize: 32 +Groups: 43 +VmSize: 3340 kB +VmLck: 0 kB +VmRSS: 1732 kB +VmData: 808 kB +VmStk: 24 kB +VmExe: 68 kB +VmLib: 2316 kB +StaBrk: 0805e000 kB +Brk: 08115000 kB +StaStk: bffffde0 kB +ExecLim: 08059000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000014a03 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/1989/task/1989/stat b/tests/002/proc/1989/task/1989/stat new file mode 100644 index 00000000..33f45f52 --- /dev/null +++ b/tests/002/proc/1989/task/1989/stat @@ -0,0 +1 @@ +1989 (xfs) S 1 1989 1989 0 -1 4194624 362 0 3 0 0 111 0 0 16 0 1 0 9444 3420160 433 4294967295 134508544 134578492 3221224928 3221224268 2340770 0 0 4096 84483 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2/status b/tests/002/proc/2/status new file mode 100644 index 00000000..62dfa2fd --- /dev/null +++ b/tests/002/proc/2/status @@ -0,0 +1,20 @@ +Name: ksoftirqd/0 +State: S (sleeping) +SleepAVG: 98% +Tgid: 2 +Pid: 2 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2/task/2/stat b/tests/002/proc/2/task/2/stat new file mode 100644 index 00000000..f6cbdbe0 --- /dev/null +++ b/tests/002/proc/2/task/2/stat @@ -0,0 +1 @@ +2 (ksoftirqd/0) S 1 0 0 0 -1 32832 0 0 0 0 0 21 0 0 34 19 1 0 56 0 0 4294967295 0 0 0 0 0 0 2147483647 0 0 3222430418 0 0 17 0 0 0 diff --git a/tests/002/proc/2008/status b/tests/002/proc/2008/status new file mode 100644 index 00000000..023cd6e2 --- /dev/null +++ b/tests/002/proc/2008/status @@ -0,0 +1,31 @@ +Name: atd +State: S (sleeping) +SleepAVG: 88% +Tgid: 2008 +Pid: 2008 +PPid: 1 +TracerPid: 0 +Uid: 0 2 2 2 +Gid: 0 2 2 2 +FDSize: 32 +Groups: +VmSize: 1552 kB +VmLck: 0 kB +VmRSS: 648 kB +VmData: 152 kB +VmStk: 8 kB +VmExe: 15 kB +VmLib: 1337 kB +StaBrk: 00116000 kB +Brk: 08021000 kB +StaStk: bffffe30 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000014003 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 0000000000000000 diff --git a/tests/002/proc/2008/task/2008/stat b/tests/002/proc/2008/task/2008/stat new file mode 100644 index 00000000..90dd8342 --- /dev/null +++ b/tests/002/proc/2008/task/2008/stat @@ -0,0 +1 @@ +2008 (atd) S 1 2008 2008 0 -1 4194368 27 0 0 0 1 324 0 0 16 0 1 0 9484 1589248 162 4294967295 1118208 1133868 3221225008 3221224180 3086915490 0 0 0 81923 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2027/status b/tests/002/proc/2027/status new file mode 100644 index 00000000..4fe16ecc --- /dev/null +++ b/tests/002/proc/2027/status @@ -0,0 +1,31 @@ +Name: dbus-daemon-1 +State: S (sleeping) +SleepAVG: 88% +Tgid: 2027 +Pid: 2027 +PPid: 1 +TracerPid: 0 +Uid: 81 81 81 81 +Gid: 81 81 81 81 +FDSize: 32 +Groups: +VmSize: 12588 kB +VmLck: 0 kB +VmRSS: 1396 kB +VmData: 10408 kB +VmStk: 12 kB +VmExe: 478 kB +VmLib: 1614 kB +StaBrk: 080c2000 kB +Brk: 080e3000 kB +StaStk: bffffe00 kB +ExecLim: 080c0000 +Threads: 2 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000180004001 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2027/task/2027/stat b/tests/002/proc/2027/task/2027/stat new file mode 100644 index 00000000..08e2c322 --- /dev/null +++ b/tests/002/proc/2027/task/2027/stat @@ -0,0 +1 @@ +2027 (dbus-daemon-1) S 1 2027 2027 0 -1 4194624 103 0 0 0 3 26 0 0 16 0 2 0 9624 12890112 349 4294967295 134512640 135003120 3221224960 3221223576 2340770 0 0 4096 16385 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2027/task/2032/stat b/tests/002/proc/2027/task/2032/stat new file mode 100644 index 00000000..f2728b16 --- /dev/null +++ b/tests/002/proc/2027/task/2032/stat @@ -0,0 +1 @@ +2032 (dbus-daemon-1) S 1 2027 2027 0 -1 4194368 1 0 0 0 0 0 0 0 17 0 2 0 9654 12890112 349 4294967295 134512640 135003120 3221224960 3086897108 2340770 0 0 4096 16385 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/2041/status b/tests/002/proc/2041/status new file mode 100644 index 00000000..7647f5a4 --- /dev/null +++ b/tests/002/proc/2041/status @@ -0,0 +1,31 @@ +Name: cups-config-dae +State: S (sleeping) +SleepAVG: 90% +Tgid: 2041 +Pid: 2041 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 2680 kB +VmLck: 0 kB +VmRSS: 1032 kB +VmData: 160 kB +VmStk: 4 kB +VmExe: 12 kB +VmLib: 2452 kB +StaBrk: 0804d000 kB +Brk: 0806e000 kB +StaStk: bffffe10 kB +ExecLim: 0804c000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2041/task/2041/stat b/tests/002/proc/2041/task/2041/stat new file mode 100644 index 00000000..31cd6415 --- /dev/null +++ b/tests/002/proc/2041/task/2041/stat @@ -0,0 +1 @@ +2041 (cups-config-dae) S 1 2041 2041 0 -1 4194368 190 0 0 0 0 3 0 0 16 0 1 0 9710 2744320 258 4294967295 134512640 134525464 3221224976 3221224584 2340770 0 0 4096 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2052/status b/tests/002/proc/2052/status new file mode 100644 index 00000000..67cabe42 --- /dev/null +++ b/tests/002/proc/2052/status @@ -0,0 +1,31 @@ +Name: hald +State: S (sleeping) +SleepAVG: 88% +Tgid: 2052 +Pid: 2052 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 5508 kB +VmLck: 0 kB +VmRSS: 3968 kB +VmData: 2436 kB +VmStk: 12 kB +VmExe: 198 kB +VmLib: 2762 kB +StaBrk: 08095000 kB +Brk: 08259000 kB +StaStk: bffffe30 kB +ExecLim: 08079000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000010014000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2052/task/2052/stat b/tests/002/proc/2052/task/2052/stat new file mode 100644 index 00000000..86a3b686 --- /dev/null +++ b/tests/002/proc/2052/task/2052/stat @@ -0,0 +1 @@ +2052 (hald) S 1 2052 2052 0 -1 4194624 4658 21123 2 1 505 29985 4 152 16 0 1 0 9776 5640192 992 4294967295 134508544 134711616 3221225008 3221224584 2340770 0 0 4096 268517376 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2062/status b/tests/002/proc/2062/status new file mode 100644 index 00000000..1d5064a0 --- /dev/null +++ b/tests/002/proc/2062/status @@ -0,0 +1,31 @@ +Name: mingetty +State: S (sleeping) +SleepAVG: 74% +Tgid: 2062 +Pid: 2062 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1440 kB +VmLck: 0 kB +VmRSS: 400 kB +VmData: 148 kB +VmStk: 4 kB +VmExe: 8 kB +VmLib: 1252 kB +StaBrk: 0804c000 kB +Brk: 0806d000 kB +StaStk: bffffe70 kB +ExecLim: 0804b000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2062/task/2062/stat b/tests/002/proc/2062/task/2062/stat new file mode 100644 index 00000000..6ce0fdbb --- /dev/null +++ b/tests/002/proc/2062/task/2062/stat @@ -0,0 +1 @@ +2062 (mingetty) S 1 2062 2062 1025 2062 4194560 118 0 0 0 0 1 0 0 18 0 1 0 9818 1474560 100 4294967295 134512640 134521080 3221225072 3221224116 2340770 0 0 0 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2124/status b/tests/002/proc/2124/status new file mode 100644 index 00000000..fae54999 --- /dev/null +++ b/tests/002/proc/2124/status @@ -0,0 +1,31 @@ +Name: gdm-binary +State: S (sleeping) +SleepAVG: 97% +Tgid: 2124 +Pid: 2124 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 256 +Groups: +VmSize: 10584 kB +VmLck: 0 kB +VmRSS: 2368 kB +VmData: 204 kB +VmStk: 12 kB +VmExe: 252 kB +VmLib: 7780 kB +StaBrk: 00153000 kB +Brk: 08021000 kB +StaStk: bffffb20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001800 +SigCgt: 0000000001814223 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2124/task/2124/stat b/tests/002/proc/2124/task/2124/stat new file mode 100644 index 00000000..d5e956ad --- /dev/null +++ b/tests/002/proc/2124/task/2124/stat @@ -0,0 +1 @@ +2124 (gdm-binary) S 1 2124 2124 0 -1 4194560 1760 3352 3 0 0 15 0 15 15 0 1 0 9924 10838016 592 4294967295 1118208 1376668 3221224224 3221222616 3086915490 0 0 536877056 25248291 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2184/status b/tests/002/proc/2184/status new file mode 100644 index 00000000..72f9493f --- /dev/null +++ b/tests/002/proc/2184/status @@ -0,0 +1,31 @@ +Name: gdm-binary +State: S (sleeping) +SleepAVG: 97% +Tgid: 2184 +Pid: 2184 +PPid: 2124 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 503 42 503 42 +FDSize: 32 +Groups: 501 503 512 +VmSize: 11176 kB +VmLck: 0 kB +VmRSS: 3368 kB +VmData: 440 kB +VmStk: 24 kB +VmExe: 252 kB +VmLib: 8024 kB +StaBrk: 00153000 kB +Brk: 08021000 kB +StaStk: bffffb20 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001200 +SigCgt: 0000000001014802 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2184/task/2184/stat b/tests/002/proc/2184/task/2184/stat new file mode 100644 index 00000000..cebb2379 --- /dev/null +++ b/tests/002/proc/2184/task/2184/stat @@ -0,0 +1 @@ +2184 (gdm-binary) S 2124 2184 2124 0 -1 4194624 517 6651 0 40 0 20 25 99 15 0 1 0 10022 11444224 842 4294967295 1118208 1376668 3221224224 3221221052 3086915490 0 0 536875520 16861186 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2354/status b/tests/002/proc/2354/status new file mode 100644 index 00000000..d18b6ea9 --- /dev/null +++ b/tests/002/proc/2354/status @@ -0,0 +1,31 @@ +Name: X +State: S (sleeping) +SleepAVG: 98% +Tgid: 2354 +Pid: 2354 +PPid: 2184 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: 0 +VmSize: 23376 kB +VmLck: 0 kB +VmRSS: 20472 kB +VmData: 16472 kB +VmStk: 28 kB +VmExe: 1523 kB +VmLib: 4345 kB +StaBrk: 08209000 kB +Brk: 087b2000 kB +StaStk: bffffab0 kB +ExecLim: b7fbe000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020301000 +SigCgt: 00000000518066cb +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2354/task/2354/stat b/tests/002/proc/2354/task/2354/stat new file mode 100644 index 00000000..f38d6d78 --- /dev/null +++ b/tests/002/proc/2354/task/2354/stat @@ -0,0 +1 @@ +2354 (X) S 2184 2354 2124 0 -1 4194560 11589 1368 0 0 2769826 1725037 26 9 15 0 1 0 10269 42811392 5118 4294967295 134508544 136068148 3221224112 3221222188 2340770 0 0 540020736 1367369419 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2551/status b/tests/002/proc/2551/status new file mode 100644 index 00000000..b6cd63db --- /dev/null +++ b/tests/002/proc/2551/status @@ -0,0 +1,31 @@ +Name: gnome-session +State: S (sleeping) +SleepAVG: 88% +Tgid: 2551 +Pid: 2551 +PPid: 2184 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 20324 kB +VmLck: 0 kB +VmRSS: 9800 kB +VmData: 2672 kB +VmStk: 64 kB +VmExe: 120 kB +VmLib: 14224 kB +StaBrk: 0806b000 kB +Brk: 08218000 kB +StaStk: bffffb50 kB +ExecLim: 08067000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 00000001800114f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2551/task/2551/stat b/tests/002/proc/2551/task/2551/stat new file mode 100644 index 00000000..34f5656a --- /dev/null +++ b/tests/002/proc/2551/task/2551/stat @@ -0,0 +1 @@ +2551 (gnome-session) S 2184 2551 2551 0 -1 4194560 5363 10700 11 11 4 100 0 63 16 0 1 0 43719 20811776 2450 4294967295 134512640 134636224 3221224272 3221223592 2340770 0 0 536870912 70896 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2579/status b/tests/002/proc/2579/status new file mode 100644 index 00000000..27062e20 --- /dev/null +++ b/tests/002/proc/2579/status @@ -0,0 +1,31 @@ +Name: ssh-agent +State: S (sleeping) +SleepAVG: 58% +Tgid: 2579 +Pid: 2579 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 99 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 3556 kB +VmLck: 0 kB +VmRSS: 1124 kB +VmData: 344 kB +VmStk: 8 kB +VmExe: 53 kB +VmLib: 2983 kB +StaBrk: 00121000 kB +Brk: 08021000 kB +StaStk: bffffde0 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001002 +SigCgt: 0000000000004001 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2579/task/2579/stat b/tests/002/proc/2579/task/2579/stat new file mode 100644 index 00000000..86030075 --- /dev/null +++ b/tests/002/proc/2579/task/2579/stat @@ -0,0 +1 @@ +2579 (ssh-agent) S 1 2579 2579 0 -1 4194368 19 0 0 0 0 0 0 0 18 0 1 0 43777 3641344 281 4294967295 1118208 1173240 3221224928 3221224476 3086915490 0 0 536875010 16385 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2625/status b/tests/002/proc/2625/status new file mode 100644 index 00000000..47e7e165 --- /dev/null +++ b/tests/002/proc/2625/status @@ -0,0 +1,31 @@ +Name: dbus-launch +State: S (sleeping) +SleepAVG: 88% +Tgid: 2625 +Pid: 2625 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 2472 kB +VmLck: 0 kB +VmRSS: 652 kB +VmData: 164 kB +VmStk: 8 kB +VmExe: 10 kB +VmLib: 2222 kB +StaBrk: 0804c000 kB +Brk: 0806d000 kB +StaStk: bffffb40 kB +ExecLim: 0804b000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 0000000000000001 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2625/task/2625/stat b/tests/002/proc/2625/task/2625/stat new file mode 100644 index 00000000..456cdaaf --- /dev/null +++ b/tests/002/proc/2625/task/2625/stat @@ -0,0 +1 @@ +2625 (dbus-launch) S 1 2551 2551 0 -1 4194368 95 0 0 0 0 0 0 0 16 0 1 0 43814 2531328 163 4294967295 134512640 134523568 3221224256 3221222556 2340770 0 0 536870912 1 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2626/status b/tests/002/proc/2626/status new file mode 100644 index 00000000..03251438 --- /dev/null +++ b/tests/002/proc/2626/status @@ -0,0 +1,31 @@ +Name: dbus-daemon-1 +State: S (sleeping) +SleepAVG: 97% +Tgid: 2626 +Pid: 2626 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 12588 kB +VmLck: 0 kB +VmRSS: 1364 kB +VmData: 10408 kB +VmStk: 12 kB +VmExe: 478 kB +VmLib: 1614 kB +StaBrk: 080c2000 kB +Brk: 080e3000 kB +StaStk: bffffb30 kB +ExecLim: 080c0000 +Threads: 2 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180004001 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2626/task/2626/stat b/tests/002/proc/2626/task/2626/stat new file mode 100644 index 00000000..3bad16f9 --- /dev/null +++ b/tests/002/proc/2626/task/2626/stat @@ -0,0 +1 @@ +2626 (dbus-daemon-1) S 1 2626 2626 0 -1 4194368 160 0 0 0 0 2 0 0 16 0 2 0 43817 12890112 341 4294967295 134512640 135003120 3221224240 3221222856 2340770 0 0 536875008 16385 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2626/task/2627/stat b/tests/002/proc/2626/task/2627/stat new file mode 100644 index 00000000..40ab4554 --- /dev/null +++ b/tests/002/proc/2626/task/2627/stat @@ -0,0 +1 @@ +2627 (dbus-daemon-1) S 1 2626 2626 0 -1 4194368 1 0 0 0 0 0 0 0 20 0 2 0 43818 12890112 341 4294967295 134512640 135003120 3221224240 3086897108 2340770 0 0 536875008 16385 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/2631/status b/tests/002/proc/2631/status new file mode 100644 index 00000000..f64f4d61 --- /dev/null +++ b/tests/002/proc/2631/status @@ -0,0 +1,31 @@ +Name: gconfd-2 +State: S (sleeping) +SleepAVG: 88% +Tgid: 2631 +Pid: 2631 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 9928 kB +VmLck: 0 kB +VmRSS: 6572 kB +VmData: 4792 kB +VmStk: 8 kB +VmExe: 47 kB +VmLib: 2873 kB +StaBrk: 08056000 kB +Brk: 084f8000 kB +StaStk: bffffb10 kB +ExecLim: 08054000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001002 +SigCgt: 00000001800046e9 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2631/task/2631/stat b/tests/002/proc/2631/task/2631/stat new file mode 100644 index 00000000..16b52632 --- /dev/null +++ b/tests/002/proc/2631/task/2631/stat @@ -0,0 +1 @@ +2631 (gconfd-2) S 1 2551 2551 0 -1 4194304 2657 0 1 0 86 4751 0 0 16 0 1 0 43842 10166272 1643 4294967295 134512640 134561456 3221224208 3221223384 2340770 0 0 536875010 18153 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2634/status b/tests/002/proc/2634/status new file mode 100644 index 00000000..f6b11b67 --- /dev/null +++ b/tests/002/proc/2634/status @@ -0,0 +1,31 @@ +Name: gnome-keyring-d +State: S (sleeping) +SleepAVG: 61% +Tgid: 2634 +Pid: 2634 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 2192 kB +VmLck: 0 kB +VmRSS: 1004 kB +VmData: 156 kB +VmStk: 8 kB +VmExe: 66 kB +VmLib: 1878 kB +StaBrk: 0805b000 kB +Brk: 0807c000 kB +StaStk: bffffad0 kB +ExecLim: 08059000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000000004003 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2634/task/2634/stat b/tests/002/proc/2634/task/2634/stat new file mode 100644 index 00000000..a19fdf35 --- /dev/null +++ b/tests/002/proc/2634/task/2634/stat @@ -0,0 +1 @@ +2634 (gnome-keyring-d) S 1 2551 2551 0 -1 4194368 59 0 0 0 0 0 0 0 19 0 1 0 44050 2244608 251 4294967295 134512640 134581220 3221224144 3221223768 2340770 0 0 536875008 16387 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2636/status b/tests/002/proc/2636/status new file mode 100644 index 00000000..78681966 --- /dev/null +++ b/tests/002/proc/2636/status @@ -0,0 +1,31 @@ +Name: bonobo-activati +State: S (sleeping) +SleepAVG: 98% +Tgid: 2636 +Pid: 2636 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 6984 kB +VmLck: 0 kB +VmRSS: 2756 kB +VmData: 608 kB +VmStk: 16 kB +VmExe: 69 kB +VmLib: 3999 kB +StaBrk: 0805d000 kB +Brk: 080e1000 kB +StaStk: bffffa30 kB +ExecLim: 0805a000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180000000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2636/task/2636/stat b/tests/002/proc/2636/task/2636/stat new file mode 100644 index 00000000..34bbe4eb --- /dev/null +++ b/tests/002/proc/2636/task/2636/stat @@ -0,0 +1 @@ +2636 (bonobo-activati) S 1 2636 2636 0 -1 4194304 1170 84 4 0 0 22 0 4 16 0 1 0 44059 7151616 689 4294967295 134512640 134583432 3221223984 3221223368 2340770 0 0 536875008 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2638/status b/tests/002/proc/2638/status new file mode 100644 index 00000000..7967b64d --- /dev/null +++ b/tests/002/proc/2638/status @@ -0,0 +1,31 @@ +Name: gnome-settings- +State: S (sleeping) +SleepAVG: 88% +Tgid: 2638 +Pid: 2638 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 18224 kB +VmLck: 0 kB +VmRSS: 6852 kB +VmData: 744 kB +VmStk: 68 kB +VmExe: 141 kB +VmLib: 14459 kB +StaBrk: 08072000 kB +Brk: 080f8000 kB +StaStk: bffff7a0 kB +ExecLim: 0806c000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180010cf0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2638/task/2638/stat b/tests/002/proc/2638/task/2638/stat new file mode 100644 index 00000000..b0011b44 --- /dev/null +++ b/tests/002/proc/2638/task/2638/stat @@ -0,0 +1 @@ +2638 (gnome-settings-) S 1 2636 2636 0 -1 4194304 2615 11311 5 0 1 29 1 47 16 0 1 0 44112 18661376 1713 4294967295 134512640 134657092 3221223328 3221222856 2340770 0 0 536875008 68848 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2644/status b/tests/002/proc/2644/status new file mode 100644 index 00000000..fbb4906e --- /dev/null +++ b/tests/002/proc/2644/status @@ -0,0 +1,31 @@ +Name: gam_server +State: S (sleeping) +SleepAVG: 88% +Tgid: 2644 +Pid: 2644 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 2304 kB +VmLck: 0 kB +VmRSS: 1264 kB +VmData: 288 kB +VmStk: 16 kB +VmExe: 40 kB +VmLib: 1880 kB +StaBrk: 08054000 kB +Brk: 08096000 kB +StaStk: bffff7e0 kB +ExecLim: 08053000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000210000800 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2644/task/2644/stat b/tests/002/proc/2644/task/2644/stat new file mode 100644 index 00000000..7e6a6389 --- /dev/null +++ b/tests/002/proc/2644/task/2644/stat @@ -0,0 +1 @@ +2644 (gam_server) S 1 2643 2643 0 -1 4194304 365 0 0 0 291 80080 0 0 16 0 1 0 44183 2359296 316 4294967295 134512640 134553980 3221223392 3221223016 2340770 0 0 536875008 268437504 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2661/status b/tests/002/proc/2661/status new file mode 100644 index 00000000..1e07a8a4 --- /dev/null +++ b/tests/002/proc/2661/status @@ -0,0 +1,31 @@ +Name: xscreensaver +State: S (sleeping) +SleepAVG: 88% +Tgid: 2661 +Pid: 2661 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 4584 kB +VmLck: 0 kB +VmRSS: 2336 kB +VmData: 552 kB +VmStk: 52 kB +VmExe: 204 kB +VmLib: 3588 kB +StaBrk: 0807d000 kB +Brk: 080c9000 kB +StaStk: bffff7f0 kB +ExecLim: 08079000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 00000000418144ff +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2661/task/2661/stat b/tests/002/proc/2661/task/2661/stat new file mode 100644 index 00000000..9da2461f --- /dev/null +++ b/tests/002/proc/2661/task/2661/stat @@ -0,0 +1 @@ +2661 (xscreensaver) S 1 2636 2636 0 -1 4194304 848 442 3 13 18 7929 0 1 16 0 1 0 44257 4694016 584 4294967295 134500352 134709912 3221223408 3221221372 2340770 0 0 536870912 1098990847 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2685/status b/tests/002/proc/2685/status new file mode 100644 index 00000000..b9a4012c --- /dev/null +++ b/tests/002/proc/2685/status @@ -0,0 +1,31 @@ +Name: metacity +State: S (sleeping) +SleepAVG: 98% +Tgid: 2685 +Pid: 2685 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 12332 kB +VmLck: 0 kB +VmRSS: 5260 kB +VmData: 768 kB +VmStk: 64 kB +VmExe: 430 kB +VmLib: 8582 kB +StaBrk: 080bd000 kB +Brk: 08167000 kB +StaStk: bffffa80 kB +ExecLim: 080b4000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000021001000 +SigCgt: 0000000180000000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2685/task/2685/stat b/tests/002/proc/2685/task/2685/stat new file mode 100644 index 00000000..41ba36c8 --- /dev/null +++ b/tests/002/proc/2685/task/2685/stat @@ -0,0 +1 @@ +2685 (metacity) S 1 2685 2685 0 -1 4194304 1755 697 5 1 5 30 0 1 15 0 1 0 44486 12627968 1315 4294967295 134512640 134953484 3221224064 3221223096 2340770 0 0 553652224 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2689/status b/tests/002/proc/2689/status new file mode 100644 index 00000000..73b53a1f --- /dev/null +++ b/tests/002/proc/2689/status @@ -0,0 +1,31 @@ +Name: gnome-panel +State: S (sleeping) +SleepAVG: 87% +Tgid: 2689 +Pid: 2689 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 22136 kB +VmLck: 0 kB +VmRSS: 12408 kB +VmData: 3808 kB +VmStk: 64 kB +VmExe: 436 kB +VmLib: 14536 kB +StaBrk: 080c1000 kB +Brk: 08446000 kB +StaStk: bffffa70 kB +ExecLim: 080b6000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180010cf0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2689/task/2689/stat b/tests/002/proc/2689/task/2689/stat new file mode 100644 index 00000000..fa62d4f6 --- /dev/null +++ b/tests/002/proc/2689/task/2689/stat @@ -0,0 +1 @@ +2689 (gnome-panel) S 1 2689 2689 0 -1 4194304 3290 0 10 0 27 220 0 0 17 0 1 0 44541 22667264 3102 4294967295 134512640 134959452 3221224048 3221223560 2340770 0 0 536875008 68848 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2691/status b/tests/002/proc/2691/status new file mode 100644 index 00000000..02e1e14e --- /dev/null +++ b/tests/002/proc/2691/status @@ -0,0 +1,31 @@ +Name: nautilus +State: S (sleeping) +SleepAVG: 98% +Tgid: 2691 +Pid: 2691 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 42136 kB +VmLck: 0 kB +VmRSS: 18296 kB +VmData: 21388 kB +VmStk: 72 kB +VmExe: 590 kB +VmLib: 16310 kB +StaBrk: 080ed000 kB +Brk: 0834f000 kB +StaStk: bffffa60 kB +ExecLim: 080dc000 +Threads: 10 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180010cf0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2691/task/2691/stat b/tests/002/proc/2691/task/2691/stat new file mode 100644 index 00000000..4c6319cf --- /dev/null +++ b/tests/002/proc/2691/task/2691/stat @@ -0,0 +1 @@ +2691 (nautilus) S 1 2691 2691 0 -1 4194304 6760 25 25 0 768 163818 0 4 15 0 10 0 44549 43147264 4574 4294967295 134512640 135116832 3221224032 3221223208 2340770 0 0 536875008 68848 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2691/task/2696/stat b/tests/002/proc/2691/task/2696/stat new file mode 100644 index 00000000..60c53157 --- /dev/null +++ b/tests/002/proc/2691/task/2696/stat @@ -0,0 +1 @@ +2696 (nautilus) S 1 2691 2691 0 -1 4194368 11 25 0 0 0 2 0 4 15 0 10 0 44786 43147264 4574 4294967295 134512640 135116832 3221224032 3084718936 2340770 0 0 536875008 68848 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2708/stat b/tests/002/proc/2691/task/2708/stat new file mode 100644 index 00000000..c27effae --- /dev/null +++ b/tests/002/proc/2691/task/2708/stat @@ -0,0 +1 @@ +2708 (nautilus) S 1 2691 2691 0 -1 4194368 4 25 0 0 0 0 0 4 15 0 10 0 44890 43147264 4574 4294967295 134512640 135116832 3221224032 3074229164 2340770 0 0 536875008 68848 3225405204 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2709/stat b/tests/002/proc/2691/task/2709/stat new file mode 100644 index 00000000..e21a2ead --- /dev/null +++ b/tests/002/proc/2691/task/2709/stat @@ -0,0 +1 @@ +2709 (nautilus) S 1 2691 2691 0 -1 4194368 12 25 0 0 0 2 0 4 15 0 10 0 44890 43147264 4574 4294967295 134512640 135116832 3221224032 3073962924 2340770 0 0 536875008 68848 3225409776 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2710/stat b/tests/002/proc/2691/task/2710/stat new file mode 100644 index 00000000..170584e9 --- /dev/null +++ b/tests/002/proc/2691/task/2710/stat @@ -0,0 +1 @@ +2710 (nautilus) S 1 2691 2691 0 -1 4194368 4 25 0 0 0 0 0 4 15 0 10 0 44890 43147264 4574 4294967295 134512640 135116832 3221224032 3073696684 2340770 0 0 536875008 68848 3225404448 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2711/stat b/tests/002/proc/2691/task/2711/stat new file mode 100644 index 00000000..b198b937 --- /dev/null +++ b/tests/002/proc/2691/task/2711/stat @@ -0,0 +1 @@ +2711 (nautilus) S 1 2691 2691 0 -1 4194368 3 25 0 0 0 0 0 4 15 0 10 0 44891 43147264 4574 4294967295 134512640 135116832 3221224032 3073430444 2340770 0 0 536875008 68848 3225410892 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2712/stat b/tests/002/proc/2691/task/2712/stat new file mode 100644 index 00000000..26d3fad8 --- /dev/null +++ b/tests/002/proc/2691/task/2712/stat @@ -0,0 +1 @@ +2712 (nautilus) S 1 2691 2691 0 -1 4194368 3 25 0 0 0 0 0 4 15 0 10 0 44891 43147264 4574 4294967295 134512640 135116832 3221224032 3073164204 2340770 0 0 536875008 68848 3225406032 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2713/stat b/tests/002/proc/2691/task/2713/stat new file mode 100644 index 00000000..fab4e652 --- /dev/null +++ b/tests/002/proc/2691/task/2713/stat @@ -0,0 +1 @@ +2713 (nautilus) S 1 2691 2691 0 -1 4194368 6 25 0 0 0 0 0 4 15 0 10 0 44891 43147264 4574 4294967295 134512640 135116832 3221224032 3072897964 2340770 0 0 536875008 68848 3225405132 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2714/stat b/tests/002/proc/2691/task/2714/stat new file mode 100644 index 00000000..46aacf24 --- /dev/null +++ b/tests/002/proc/2691/task/2714/stat @@ -0,0 +1 @@ +2714 (nautilus) S 1 2691 2691 0 -1 4194368 63 25 0 0 0 5 0 4 16 0 10 0 44891 43147264 4574 4294967295 134512640 135116832 3221224032 3072631724 2340770 0 0 536875008 68848 3225408660 0 0 -1 0 0 0 diff --git a/tests/002/proc/2691/task/2715/stat b/tests/002/proc/2691/task/2715/stat new file mode 100644 index 00000000..382b125b --- /dev/null +++ b/tests/002/proc/2691/task/2715/stat @@ -0,0 +1 @@ +2715 (nautilus) S 1 2691 2691 0 -1 4194368 7 25 0 0 0 1 0 4 15 0 10 0 44891 43147264 4574 4294967295 134512640 135116832 3221224032 3072365484 2340770 0 0 536875008 68848 3225407508 0 0 -1 0 0 0 diff --git a/tests/002/proc/2693/status b/tests/002/proc/2693/status new file mode 100644 index 00000000..723c6b52 --- /dev/null +++ b/tests/002/proc/2693/status @@ -0,0 +1,31 @@ +Name: gnome-volume-ma +State: S (sleeping) +SleepAVG: 88% +Tgid: 2693 +Pid: 2693 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 17928 kB +VmLck: 0 kB +VmRSS: 6212 kB +VmData: 612 kB +VmStk: 64 kB +VmExe: 17 kB +VmLib: 14459 kB +StaBrk: 08050000 kB +Brk: 080b6000 kB +StaStk: bffffa60 kB +ExecLim: 0804d000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 00000001800144f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2693/task/2693/stat b/tests/002/proc/2693/task/2693/stat new file mode 100644 index 00000000..8bda4bb5 --- /dev/null +++ b/tests/002/proc/2693/task/2693/stat @@ -0,0 +1 @@ +2693 (gnome-volume-ma) S 1 2693 2693 0 -1 4194304 1919 0 0 0 2 37 0 0 16 0 1 0 44557 18358272 1553 4294967295 134512640 134530528 3221224032 3221223496 2340770 0 0 536875008 83184 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2695/status b/tests/002/proc/2695/status new file mode 100644 index 00000000..a7785592 --- /dev/null +++ b/tests/002/proc/2695/status @@ -0,0 +1,31 @@ +Name: eggcups +State: S (sleeping) +SleepAVG: 88% +Tgid: 2695 +Pid: 2695 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 39476 kB +VmLck: 0 kB +VmRSS: 7744 kB +VmData: 21228 kB +VmStk: 64 kB +VmExe: 106 kB +VmLib: 14878 kB +StaBrk: 08067000 kB +Brk: 080ec000 kB +StaStk: bffffa70 kB +ExecLim: 08063000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001001 +SigCgt: 00000001800144f2 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2695/task/2695/stat b/tests/002/proc/2695/task/2695/stat new file mode 100644 index 00000000..bcca5a53 --- /dev/null +++ b/tests/002/proc/2695/task/2695/stat @@ -0,0 +1 @@ +2695 (eggcups) S 1 2695 2695 0 -1 4194304 1939 0 5 0 37 3761 0 0 16 0 1 0 44706 40423424 1936 4294967295 134512640 134622204 3221224048 3221223160 2340770 0 0 536875009 83186 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2698/status b/tests/002/proc/2698/status new file mode 100644 index 00000000..f2083aa3 --- /dev/null +++ b/tests/002/proc/2698/status @@ -0,0 +1,31 @@ +Name: gnome-vfs-daemo +State: S (sleeping) +SleepAVG: 87% +Tgid: 2698 +Pid: 2698 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 20048 kB +VmLck: 0 kB +VmRSS: 3552 kB +VmData: 10664 kB +VmStk: 20 kB +VmExe: 74 kB +VmLib: 6790 kB +StaBrk: 08066000 kB +Brk: 080a8000 kB +StaStk: bffff7a0 kB +ExecLim: 0805b000 +Threads: 2 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 0000000180010800 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2698/task/2698/stat b/tests/002/proc/2698/task/2698/stat new file mode 100644 index 00000000..5ba02563 --- /dev/null +++ b/tests/002/proc/2698/task/2698/stat @@ -0,0 +1 @@ +2698 (gnome-vfs-daemo) S 1 2636 2636 0 -1 4194304 1015 15 1 0 1 13 0 1 16 0 2 0 44787 20529152 888 4294967295 134512640 134589128 3221223328 3221222936 2340770 0 0 536875008 67584 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2698/task/2699/stat b/tests/002/proc/2698/task/2699/stat new file mode 100644 index 00000000..6ed657ad --- /dev/null +++ b/tests/002/proc/2698/task/2699/stat @@ -0,0 +1 @@ +2699 (gnome-vfs-daemo) S 1 2636 2636 0 -1 4194368 10 15 0 0 0 0 0 1 15 0 2 0 44798 20529152 888 4294967295 134512640 134589128 3221223328 3084776280 2340770 0 0 536875008 67584 0 0 0 -1 0 0 0 diff --git a/tests/002/proc/2701/status b/tests/002/proc/2701/status new file mode 100644 index 00000000..2ac68d03 --- /dev/null +++ b/tests/002/proc/2701/status @@ -0,0 +1,31 @@ +Name: pam-panel-icon +State: S (sleeping) +SleepAVG: 88% +Tgid: 2701 +Pid: 2701 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 12152 kB +VmLck: 0 kB +VmRSS: 4196 kB +VmData: 512 kB +VmStk: 64 kB +VmExe: 35 kB +VmLib: 9101 kB +StaBrk: 08053000 kB +Brk: 080b6000 kB +StaStk: bffffa60 kB +ExecLim: 08051000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 0000000180000000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2701/task/2701/stat b/tests/002/proc/2701/task/2701/stat new file mode 100644 index 00000000..5e5e4d0d --- /dev/null +++ b/tests/002/proc/2701/task/2701/stat @@ -0,0 +1 @@ +2701 (pam-panel-icon) S 1 2701 2701 0 -1 4194304 1202 0 0 0 37 9236 0 0 16 0 1 0 44814 12443648 1049 4294967295 134512640 134548696 3221224032 3221223576 2340770 0 0 536870912 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2707/status b/tests/002/proc/2707/status new file mode 100644 index 00000000..2d915b5a --- /dev/null +++ b/tests/002/proc/2707/status @@ -0,0 +1,31 @@ +Name: rhn-applet-gui +State: R (running) +SleepAVG: 98% +Tgid: 2707 +Pid: 2707 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 28748 kB +VmLck: 0 kB +VmRSS: 16676 kB +VmData: 5364 kB +VmStk: 100 kB +VmExe: 1 kB +VmLib: 19507 kB +StaBrk: 0804a000 kB +Brk: 082aa000 kB +StaStk: bffffa50 kB +ExecLim: 08049000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000021001000 +SigCgt: 00000001800104f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2707/task/2707/stat b/tests/002/proc/2707/task/2707/stat new file mode 100644 index 00000000..5b1c3e62 --- /dev/null +++ b/tests/002/proc/2707/task/2707/stat @@ -0,0 +1 @@ +2707 (rhn-applet-gui) S 1 2707 2707 0 -1 4194304 4561 0 19 0 64467 4019712 0 0 25 10 1 0 44857 29437952 4169 4294967295 134512640 134514336 3221224016 3221220104 2340770 0 0 553652224 66800 0 0 0 17 0 0 0 diff --git a/tests/002/proc/27121/status b/tests/002/proc/27121/status new file mode 100644 index 00000000..1326a5f1 --- /dev/null +++ b/tests/002/proc/27121/status @@ -0,0 +1,20 @@ +Name: pdflush +State: S (sleeping) +SleepAVG: 97% +Tgid: 27121 +Pid: 27121 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/27121/task/27121/stat b/tests/002/proc/27121/task/27121/stat new file mode 100644 index 00000000..bea101fe --- /dev/null +++ b/tests/002/proc/27121/task/27121/stat @@ -0,0 +1 @@ +27121 (pdflush) S 3 0 0 0 -1 41024 0 0 0 0 0 1 0 0 15 0 1 0 192847829 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222571503 0 0 17 0 0 0 diff --git a/tests/002/proc/2717/status b/tests/002/proc/2717/status new file mode 100644 index 00000000..2db485b0 --- /dev/null +++ b/tests/002/proc/2717/status @@ -0,0 +1,31 @@ +Name: pam_timestamp_c +State: S (sleeping) +SleepAVG: 88% +Tgid: 2717 +Pid: 2717 +PPid: 2701 +TracerPid: 0 +Uid: 524 0 0 0 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 1620 kB +VmLck: 0 kB +VmRSS: 640 kB +VmData: 156 kB +VmStk: 16 kB +VmExe: 4 kB +VmLib: 1392 kB +StaBrk: 0804b000 kB +Brk: 0806c000 kB +StaStk: bffffa70 kB +ExecLim: 0804a000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/2717/task/2717/stat b/tests/002/proc/2717/task/2717/stat new file mode 100644 index 00000000..e353ebe3 --- /dev/null +++ b/tests/002/proc/2717/task/2717/stat @@ -0,0 +1 @@ +2717 (pam_timestamp_c) S 2701 2701 2701 0 -1 4194560 201 0 0 0 71 15175 0 0 16 0 1 0 44953 1658880 160 4294967295 134512640 134517636 3221224048 3221214844 2340770 0 0 536870912 0 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/2718/status b/tests/002/proc/2718/status new file mode 100644 index 00000000..70b16ad9 --- /dev/null +++ b/tests/002/proc/2718/status @@ -0,0 +1,31 @@ +Name: mapping-daemon +State: S (sleeping) +SleepAVG: 88% +Tgid: 2718 +Pid: 2718 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 2108 kB +VmLck: 0 kB +VmRSS: 812 kB +VmData: 156 kB +VmStk: 8 kB +VmExe: 9 kB +VmLib: 1879 kB +StaBrk: 0804c000 kB +Brk: 0806d000 kB +StaStk: bffffa80 kB +ExecLim: 0804b000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2718/task/2718/stat b/tests/002/proc/2718/task/2718/stat new file mode 100644 index 00000000..de695b4e --- /dev/null +++ b/tests/002/proc/2718/task/2718/stat @@ -0,0 +1 @@ +2718 (mapping-daemon) S 1 2691 2691 0 -1 4194304 249 0 0 0 2 562 0 0 16 0 1 0 44956 2158592 203 4294967295 134512640 134522612 3221224064 3221223544 2340770 0 0 536870912 0 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2720/status b/tests/002/proc/2720/status new file mode 100644 index 00000000..fc792728 --- /dev/null +++ b/tests/002/proc/2720/status @@ -0,0 +1,31 @@ +Name: wnck-applet +State: S (sleeping) +SleepAVG: 88% +Tgid: 2720 +Pid: 2720 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 19696 kB +VmLck: 0 kB +VmRSS: 8536 kB +VmData: 1804 kB +VmStk: 68 kB +VmExe: 66 kB +VmLib: 14574 kB +StaBrk: 0805d000 kB +Brk: 081ec000 kB +StaStk: bffff7b0 kB +ExecLim: 08059000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 00000001800104f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2720/task/2720/stat b/tests/002/proc/2720/task/2720/stat new file mode 100644 index 00000000..70e66c8a --- /dev/null +++ b/tests/002/proc/2720/task/2720/stat @@ -0,0 +1 @@ +2720 (wnck-applet) S 1 2636 2636 0 -1 4194304 2257 0 3 0 9 65 0 0 16 0 1 0 45806 20168704 2134 4294967295 134512640 134580268 3221223344 3221222696 2340770 0 0 536875008 66800 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2722/status b/tests/002/proc/2722/status new file mode 100644 index 00000000..cd89611b --- /dev/null +++ b/tests/002/proc/2722/status @@ -0,0 +1,31 @@ +Name: mixer_applet2 +State: S (sleeping) +SleepAVG: 98% +Tgid: 2722 +Pid: 2722 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 21128 kB +VmLck: 0 kB +VmRSS: 9276 kB +VmData: 2188 kB +VmStk: 68 kB +VmExe: 29 kB +VmLib: 15639 kB +StaBrk: 08053000 kB +Brk: 08243000 kB +StaStk: bffff7a0 kB +ExecLim: 08050000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 00000001800100f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2722/task/2722/stat b/tests/002/proc/2722/task/2722/stat new file mode 100644 index 00000000..9dd73cdb --- /dev/null +++ b/tests/002/proc/2722/task/2722/stat @@ -0,0 +1 @@ +2722 (mixer_applet2) S 1 2636 2636 0 -1 4194304 2479 0 11 0 462 88674 0 0 15 0 1 0 45960 21635072 2319 4294967295 134512640 134542828 3221223328 3221222680 2340770 0 0 536875008 65776 0 0 0 17 0 0 0 diff --git a/tests/002/proc/27243/status b/tests/002/proc/27243/status new file mode 100644 index 00000000..71ce2ec0 --- /dev/null +++ b/tests/002/proc/27243/status @@ -0,0 +1,20 @@ +Name: pdflush +State: S (sleeping) +SleepAVG: 98% +Tgid: 27243 +Pid: 27243 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/27243/task/27243/stat b/tests/002/proc/27243/task/27243/stat new file mode 100644 index 00000000..850d4843 --- /dev/null +++ b/tests/002/proc/27243/task/27243/stat @@ -0,0 +1 @@ +27243 (pdflush) S 3 0 0 0 -1 41024 0 0 0 0 0 3224 0 0 15 0 1 0 192851014 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222571503 0 0 17 0 0 0 diff --git a/tests/002/proc/2726/status b/tests/002/proc/2726/status new file mode 100644 index 00000000..6b6be86f --- /dev/null +++ b/tests/002/proc/2726/status @@ -0,0 +1,31 @@ +Name: clock-applet +State: S (sleeping) +SleepAVG: 88% +Tgid: 2726 +Pid: 2726 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 19576 kB +VmLck: 0 kB +VmRSS: 8052 kB +VmData: 1012 kB +VmStk: 68 kB +VmExe: 92 kB +VmLib: 15472 kB +StaBrk: 08064000 kB +Brk: 0812b000 kB +StaStk: bffff7a0 kB +ExecLim: 08060000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 00000001800104f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2726/task/2726/stat b/tests/002/proc/2726/task/2726/stat new file mode 100644 index 00000000..208ce1a5 --- /dev/null +++ b/tests/002/proc/2726/task/2726/stat @@ -0,0 +1 @@ +2726 (clock-applet) S 1 2636 2636 0 -1 4194304 2152 0 6 0 5100 258062 0 0 16 0 1 0 46077 20045824 2013 4294967295 134512640 134607244 3221223328 3221222680 2340770 0 0 536875008 66800 0 0 0 17 0 0 0 diff --git a/tests/002/proc/2728/status b/tests/002/proc/2728/status new file mode 100644 index 00000000..ccb9860a --- /dev/null +++ b/tests/002/proc/2728/status @@ -0,0 +1,31 @@ +Name: notification-ar +State: S (sleeping) +SleepAVG: 97% +Tgid: 2728 +Pid: 2728 +PPid: 1 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 17888 kB +VmLck: 0 kB +VmRSS: 6800 kB +VmData: 756 kB +VmStk: 68 kB +VmExe: 23 kB +VmLib: 14261 kB +StaBrk: 08051000 kB +Brk: 080db000 kB +StaStk: bffff780 kB +ExecLim: 0804e000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000020001000 +SigCgt: 00000001800104f0 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/2728/task/2728/stat b/tests/002/proc/2728/task/2728/stat new file mode 100644 index 00000000..47fa70e5 --- /dev/null +++ b/tests/002/proc/2728/task/2728/stat @@ -0,0 +1 @@ +2728 (notification-ar) S 1 2636 2636 0 -1 4194304 1816 0 1 0 3 15 0 0 16 0 1 0 46126 18317312 1700 4294967295 134512640 134537192 3221223296 3221222648 2340770 0 0 536875008 66800 0 0 0 17 0 0 0 diff --git a/tests/002/proc/27682/status b/tests/002/proc/27682/status new file mode 100644 index 00000000..6c644758 --- /dev/null +++ b/tests/002/proc/27682/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 97% +Tgid: 27682 +Pid: 27682 +PPid: 1887 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 6836 kB +VmLck: 0 kB +VmRSS: 2368 kB +VmData: 436 kB +VmStk: 24 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08021000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000006001 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/27682/task/27682/stat b/tests/002/proc/27682/task/27682/stat new file mode 100644 index 00000000..5e7a9644 --- /dev/null +++ b/tests/002/proc/27682/task/27682/stat @@ -0,0 +1 @@ +27682 (sshd) S 1887 27682 27682 0 -1 4194560 1209 79 0 0 119 230 2 0 16 0 1 0 193311484 7000064 592 4294967295 1118208 1420332 3221224976 3221220452 3086915490 0 0 4096 24577 0 0 0 17 0 0 0 diff --git a/tests/002/proc/27684/status b/tests/002/proc/27684/status new file mode 100644 index 00000000..3a2542d6 --- /dev/null +++ b/tests/002/proc/27684/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 98% +Tgid: 27684 +Pid: 27684 +PPid: 27682 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 7012 kB +VmLck: 0 kB +VmRSS: 2456 kB +VmData: 596 kB +VmStk: 40 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08049000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000012000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/27684/task/27684/stat b/tests/002/proc/27684/task/27684/stat new file mode 100644 index 00000000..3f12ecc5 --- /dev/null +++ b/tests/002/proc/27684/task/27684/stat @@ -0,0 +1 @@ +27684 (sshd) S 27682 27682 27682 0 -1 4194624 126 0 0 0 2094 54068 0 0 15 0 1 0 193311752 7180288 614 4294967295 1118208 1420332 3221224976 3221220428 3086915490 0 0 4096 73728 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/27685/status b/tests/002/proc/27685/status new file mode 100644 index 00000000..2d59eb08 --- /dev/null +++ b/tests/002/proc/27685/status @@ -0,0 +1,31 @@ +Name: bash +State: S (sleeping) +SleepAVG: 82% +Tgid: 27685 +Pid: 27685 +PPid: 27684 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 5964 kB +VmLck: 0 kB +VmRSS: 2960 kB +VmData: 1584 kB +VmStk: 20 kB +VmExe: 577 kB +VmLib: 1415 kB +StaBrk: 080e3000 kB +Brk: 08262000 kB +StaStk: bffffe40 kB +ExecLim: 080d8000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000384004 +SigCgt: 000000004b813efb +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/27685/task/27685/stat b/tests/002/proc/27685/task/27685/stat new file mode 100644 index 00000000..4b79d09a --- /dev/null +++ b/tests/002/proc/27685/task/27685/stat @@ -0,0 +1 @@ +27685 (bash) S 27684 27685 27685 34817 27685 4194304 360749 21090866 0 85 72 3121 178898 151420 16 0 1 0 193311757 6107136 740 4294967295 134508544 135099520 3221225024 3221221396 2340770 0 0 3686404 1266761467 0 0 0 17 0 0 0 diff --git a/tests/002/proc/28/status b/tests/002/proc/28/status new file mode 100644 index 00000000..1e39d66a --- /dev/null +++ b/tests/002/proc/28/status @@ -0,0 +1,20 @@ +Name: kswapd0 +State: S (sleeping) +SleepAVG: 52% +Tgid: 28 +Pid: 28 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000000000 +SigCgt: 0000000000004100 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/28/task/28/stat b/tests/002/proc/28/task/28/stat new file mode 100644 index 00000000..c6e9af6b --- /dev/null +++ b/tests/002/proc/28/task/28/stat @@ -0,0 +1 @@ +28 (kswapd0) S 1 1 1 0 -1 264256 0 0 0 0 0 652 0 0 19 0 1 0 63 0 0 4294967295 0 0 0 0 0 0 2147483647 0 16640 3222597324 0 0 17 0 0 0 diff --git a/tests/002/proc/29/status b/tests/002/proc/29/status new file mode 100644 index 00000000..864a05c4 --- /dev/null +++ b/tests/002/proc/29/status @@ -0,0 +1,20 @@ +Name: aio/0 +State: S (sleeping) +SleepAVG: 19% +Tgid: 29 +Pid: 29 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/29/task/29/stat b/tests/002/proc/29/task/29/stat new file mode 100644 index 00000000..89e2592d --- /dev/null +++ b/tests/002/proc/29/task/29/stat @@ -0,0 +1 @@ +29 (aio/0) S 3 0 0 0 -1 32832 0 0 0 0 0 0 0 0 13 -10 1 0 63 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222484651 0 0 17 0 0 0 diff --git a/tests/002/proc/29840/status b/tests/002/proc/29840/status new file mode 100644 index 00000000..424da036 --- /dev/null +++ b/tests/002/proc/29840/status @@ -0,0 +1,31 @@ +Name: bash +State: R (running) +SleepAVG: 0% +Tgid: 29840 +Pid: 29840 +PPid: 16249 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 256 +Groups: 0 1 2 3 4 6 10 606 +VmSize: 4340 kB +VmLck: 0 kB +VmRSS: 1556 kB +VmData: 296 kB +VmStk: 20 kB +VmExe: 577 kB +VmLib: 1307 kB +StaBrk: 080e3000 kB +Brk: 08122000 kB +StaStk: bffffeb0 kB +ExecLim: 080d8000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000010002 +SigIgn: 0000000000000000 +SigCgt: 0000000008010002 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/29840/task/29840/stat b/tests/002/proc/29840/task/29840/stat new file mode 100644 index 00000000..8fdda47a --- /dev/null +++ b/tests/002/proc/29840/task/29840/stat @@ -0,0 +1 @@ +29840 (bash) R 16249 29839 31908 34818 29839 4194368 39208 238138 0 0 0 299 2 805 25 0 1 0 361410776 4444160 389 4294967295 134508544 135099520 3221225136 3221222148 2340770 0 65538 0 134283266 0 0 0 17 0 0 0 diff --git a/tests/002/proc/3/status b/tests/002/proc/3/status new file mode 100644 index 00000000..0e355850 --- /dev/null +++ b/tests/002/proc/3/status @@ -0,0 +1,20 @@ +Name: events/0 +State: S (sleeping) +SleepAVG: 98% +Tgid: 3 +Pid: 3 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/3/task/3/stat b/tests/002/proc/3/task/3/stat new file mode 100644 index 00000000..6b23245e --- /dev/null +++ b/tests/002/proc/3/task/3/stat @@ -0,0 +1 @@ +3 (events/0) S 1 0 0 0 -1 33088 0 0 0 0 0 8491 0 0 5 -10 1 0 59 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222484651 0 0 17 0 0 0 diff --git a/tests/002/proc/30737/status b/tests/002/proc/30737/status new file mode 100644 index 00000000..d59c8336 --- /dev/null +++ b/tests/002/proc/30737/status @@ -0,0 +1,31 @@ +Name: dhclient +State: S (sleeping) +SleepAVG: 89% +Tgid: 30737 +Pid: 30737 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 2156 kB +VmLck: 0 kB +VmRSS: 1120 kB +VmData: 336 kB +VmStk: 12 kB +VmExe: 349 kB +VmLib: 1483 kB +StaBrk: 080ae000 kB +Brk: 080f2000 kB +StaStk: bffffd70 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/30737/task/30737/stat b/tests/002/proc/30737/task/30737/stat new file mode 100644 index 00000000..57db355b --- /dev/null +++ b/tests/002/proc/30737/task/30737/stat @@ -0,0 +1 @@ +30737 (dhclient) S 1 30737 30737 0 -1 64 235 30892 0 0 3 42 3 133 16 0 1 0 43693773 2207744 280 4294967295 134508544 134865956 3221224816 3221223916 2340770 0 0 0 0 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/31905/status b/tests/002/proc/31905/status new file mode 100644 index 00000000..4043ed83 --- /dev/null +++ b/tests/002/proc/31905/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 97% +Tgid: 31905 +Pid: 31905 +PPid: 1887 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 6836 kB +VmLck: 0 kB +VmRSS: 2368 kB +VmData: 436 kB +VmStk: 24 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08021000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000006001 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/31905/task/31905/stat b/tests/002/proc/31905/task/31905/stat new file mode 100644 index 00000000..3e1a83a4 --- /dev/null +++ b/tests/002/proc/31905/task/31905/stat @@ -0,0 +1 @@ +31905 (sshd) S 1887 31905 31905 0 -1 4194560 1590 79 0 0 237 442 2 2 16 0 1 0 48905120 7000064 592 4294967295 1118208 1420332 3221224976 3221220452 3086915490 0 0 4096 24577 0 0 0 17 0 0 0 diff --git a/tests/002/proc/31907/status b/tests/002/proc/31907/status new file mode 100644 index 00000000..8909962b --- /dev/null +++ b/tests/002/proc/31907/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 98% +Tgid: 31907 +Pid: 31907 +PPid: 31905 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 7012 kB +VmLck: 0 kB +VmRSS: 2452 kB +VmData: 596 kB +VmStk: 40 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08049000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000012000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/31907/task/31907/stat b/tests/002/proc/31907/task/31907/stat new file mode 100644 index 00000000..03e624fd --- /dev/null +++ b/tests/002/proc/31907/task/31907/stat @@ -0,0 +1 @@ +31907 (sshd) S 31905 31905 31905 0 -1 4194624 124 0 0 0 1956 3984 0 0 15 0 1 0 48905454 7180288 613 4294967295 1118208 1420332 3221224976 3221220428 3086915490 0 0 4096 73728 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/31908/status b/tests/002/proc/31908/status new file mode 100644 index 00000000..220fddd7 --- /dev/null +++ b/tests/002/proc/31908/status @@ -0,0 +1,31 @@ +Name: bash +State: S (sleeping) +SleepAVG: 88% +Tgid: 31908 +Pid: 31908 +PPid: 31907 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 4568 kB +VmLck: 0 kB +VmRSS: 1700 kB +VmData: 404 kB +VmStk: 20 kB +VmExe: 577 kB +VmLib: 1411 kB +StaBrk: 080e3000 kB +Brk: 0813b000 kB +StaStk: bffffe40 kB +ExecLim: 080d8000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000010000 +SigIgn: 0000000000384004 +SigCgt: 000000004b813efb +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/31908/task/31908/stat b/tests/002/proc/31908/task/31908/stat new file mode 100644 index 00000000..73b91cbb --- /dev/null +++ b/tests/002/proc/31908/task/31908/stat @@ -0,0 +1 @@ +31908 (bash) S 31907 31908 31908 34818 29839 4194304 6479 200590 0 1 8 166 702 8118 15 0 1 0 48905458 4677632 425 4294967295 134508544 135099520 3221225024 3221223620 2340770 0 65536 3686404 1266761467 3222425215 0 0 17 0 0 0 diff --git a/tests/002/proc/32672/status b/tests/002/proc/32672/status new file mode 100644 index 00000000..5b73732a --- /dev/null +++ b/tests/002/proc/32672/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 98% +Tgid: 32672 +Pid: 32672 +PPid: 1887 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 6836 kB +VmLck: 0 kB +VmRSS: 2368 kB +VmData: 436 kB +VmStk: 24 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08021000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000006001 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/32672/task/32672/stat b/tests/002/proc/32672/task/32672/stat new file mode 100644 index 00000000..41f89907 --- /dev/null +++ b/tests/002/proc/32672/task/32672/stat @@ -0,0 +1 @@ +32672 (sshd) S 1887 32672 32672 0 -1 4194560 1585 79 0 0 228 406 2 1 16 0 1 0 50052803 7000064 592 4294967295 1118208 1420332 3221224976 3221220452 3086915490 0 0 4096 24577 0 0 0 17 0 0 0 diff --git a/tests/002/proc/32674/status b/tests/002/proc/32674/status new file mode 100644 index 00000000..10e40a47 --- /dev/null +++ b/tests/002/proc/32674/status @@ -0,0 +1,31 @@ +Name: sshd +State: S (sleeping) +SleepAVG: 98% +Tgid: 32674 +Pid: 32674 +PPid: 32672 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 32 +Groups: 501 503 512 +VmSize: 7012 kB +VmLck: 0 kB +VmRSS: 2456 kB +VmData: 596 kB +VmStk: 40 kB +VmExe: 295 kB +VmLib: 3277 kB +StaBrk: 00161000 kB +Brk: 08049000 kB +StaStk: bffffe10 kB +ExecLim: b8000000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000001000 +SigCgt: 0000000000012000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/32674/task/32674/stat b/tests/002/proc/32674/task/32674/stat new file mode 100644 index 00000000..a396a213 --- /dev/null +++ b/tests/002/proc/32674/task/32674/stat @@ -0,0 +1 @@ +32674 (sshd) S 32672 32672 32672 0 -1 4194624 126 0 0 0 2332 10862 0 0 15 0 1 0 50053044 7180288 614 4294967295 1118208 1420332 3221224976 3221220428 3086915490 0 0 4096 73728 3222765173 0 0 17 0 0 0 diff --git a/tests/002/proc/32675/status b/tests/002/proc/32675/status new file mode 100644 index 00000000..293ba9bc --- /dev/null +++ b/tests/002/proc/32675/status @@ -0,0 +1,31 @@ +Name: bash +State: S (sleeping) +SleepAVG: 88% +Tgid: 32675 +Pid: 32675 +PPid: 32674 +TracerPid: 0 +Uid: 524 524 524 524 +Gid: 503 503 503 503 +FDSize: 256 +Groups: 501 503 512 +VmSize: 4612 kB +VmLck: 0 kB +VmRSS: 1824 kB +VmData: 444 kB +VmStk: 24 kB +VmExe: 577 kB +VmLib: 1411 kB +StaBrk: 080e3000 kB +Brk: 08145000 kB +StaStk: bffffe40 kB +ExecLim: 080d8000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000010000 +SigIgn: 0000000000384004 +SigCgt: 000000004b813efb +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 diff --git a/tests/002/proc/32675/task/32675/stat b/tests/002/proc/32675/task/32675/stat new file mode 100644 index 00000000..ccdf4823 --- /dev/null +++ b/tests/002/proc/32675/task/32675/stat @@ -0,0 +1 @@ +32675 (bash) S 32674 32675 32675 34820 15812 4194304 50530 31756571 0 135 41 594 48025 222888 15 0 1 0 50053047 4722688 456 4294967295 134508544 135099520 3221225024 3221223620 2340770 0 65536 3686404 1266761467 3222425215 0 0 17 0 0 0 diff --git a/tests/002/proc/4/status b/tests/002/proc/4/status new file mode 100644 index 00000000..5691a7e8 --- /dev/null +++ b/tests/002/proc/4/status @@ -0,0 +1,20 @@ +Name: khelper +State: S (sleeping) +SleepAVG: 92% +Tgid: 4 +Pid: 4 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/4/task/4/stat b/tests/002/proc/4/task/4/stat new file mode 100644 index 00000000..b0d352e6 --- /dev/null +++ b/tests/002/proc/4/task/4/stat @@ -0,0 +1 @@ +4 (khelper) S 3 0 0 0 -1 32832 0 0 0 0 0 2 0 0 5 -10 1 0 59 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222484651 0 0 17 0 0 0 diff --git a/tests/002/proc/5/status b/tests/002/proc/5/status new file mode 100644 index 00000000..43a6ddf1 --- /dev/null +++ b/tests/002/proc/5/status @@ -0,0 +1,20 @@ +Name: kacpid +State: S (sleeping) +SleepAVG: 0% +Tgid: 5 +Pid: 5 +PPid: 3 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: ffffffffffffffff +SigIgn: 0000000000010000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 00000000ffffffff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/5/task/5/stat b/tests/002/proc/5/task/5/stat new file mode 100644 index 00000000..4c368098 --- /dev/null +++ b/tests/002/proc/5/task/5/stat @@ -0,0 +1 @@ +5 (kacpid) S 3 0 0 0 -1 32832 0 0 0 0 0 0 0 0 15 -10 1 0 59 0 0 4294967295 0 0 0 0 0 0 2147483647 65536 0 3222484651 0 0 17 0 0 0 diff --git a/tests/002/proc/870/status b/tests/002/proc/870/status new file mode 100644 index 00000000..fe77ae24 --- /dev/null +++ b/tests/002/proc/870/status @@ -0,0 +1,31 @@ +Name: udevd +State: S (sleeping) +SleepAVG: 87% +Tgid: 870 +Pid: 870 +PPid: 1 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 32 +Groups: +VmSize: 1608 kB +VmLck: 0 kB +VmRSS: 452 kB +VmData: 148 kB +VmStk: 116 kB +VmExe: 7 kB +VmLib: 1301 kB +StaBrk: 0804c000 kB +Brk: 095ee000 kB +StaStk: bffe51b0 kB +ExecLim: 0804a000 +Threads: 1 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000016002 +CapInh: 0000000000000000 +CapPrm: 00000000fffffeff +CapEff: 00000000fffffeff diff --git a/tests/002/proc/870/task/870/stat b/tests/002/proc/870/task/870/stat new file mode 100644 index 00000000..0e069338 --- /dev/null +++ b/tests/002/proc/870/task/870/stat @@ -0,0 +1 @@ +870 (udevd) S 1 870 870 0 -1 4227072 511 56426 0 13 0 8 4 477 6 -10 1 1000 3475 1646592 113 4294967295 134512640 134519928 3221115312 3221114028 2340770 0 0 0 90114 3222765173 0 0 17 0 0 0 diff --git a/tests/002/query-1.expected b/tests/002/query-1.expected new file mode 100644 index 00000000..3fb3a37e --- /dev/null +++ b/tests/002/query-1.expected @@ -0,0 +1,90 @@ +USER PID PPID S NAME THREADS +root 1 0 S init - +root 2 1 S ksoftirqd/0 - +root 3 1 S events/0 - +root 4 3 S khelper - +root 5 3 S kacpid - +root 16 3 S kblockd/0 - +root 17 1 S khubd - +root 28 1 S kswapd0 - +root 29 3 S aio/0 - +root 103 1 S kseriod - +root 175 1 S scsi_eh_0 - +root 186 1 S kjournald - +root 870 1 S udevd - +root 1068 1 S dhclient - +root 1235 1 S kjournald - +root 1236 1 S kjournald - +root 1620 1 S syslogd - +root 1624 1 S klogd - +rpc 1645 1 S portmap - +rpcuser 1665 1 S rpc.statd - +root 1698 1 S rpc.idmapd - +root 1766 1 S vmware-guestd - +root 1790 1 S rpciod - +root 1791 1 S lockd - +root 1821 1 S ypbind 1826, 1821 +root 1839 1 S acpid - +root 1851 1 S cupsd - +root 1887 1 S sshd - +root 1902 1 S xinetd - +root 1921 1 S rpc.rquotad - +root 1925 1 S nfsd - +root 1926 1 S nfsd - +root 1927 1 S nfsd - +root 1928 1 S nfsd - +root 1929 1 S nfsd - +root 1930 1 S nfsd - +root 1931 1 S nfsd - +root 1932 1 S nfsd - +root 1936 1 S rpc.mountd - +root 1963 1 S crond - +xfs 1989 1 S xfs - +root 2008 1 S atd - +dbus 2027 1 S dbus-daemon-1 2027 +root 2041 1 S cups-config-dae - +root 2052 1 S hald - +root 2062 1 S mingetty - +root 2124 1 S gdm-binary - +root 2184 2124 S gdm-binary - +root 2354 2184 S X - +524 2551 2184 S gnome-session - +524 2579 1 S ssh-agent - +524 2625 1 S dbus-launch - +524 2626 1 S dbus-daemon-1 2627 +524 2631 1 S gconfd-2 - +524 2634 1 S gnome-keyring-d - +524 2636 1 S bonobo-activati - +524 2638 1 S gnome-settings- - +524 2644 1 S gam_server - +524 2661 1 S xscreensaver - +524 2685 1 S metacity - +524 2689 1 S gnome-panel - +524 2691 1 S nautilus 2715, 2691, 2708, 2711, 2714, 2713, 2709, 2710, 2696 +524 2693 1 S gnome-volume-ma - +524 2695 1 S eggcups - +524 2698 1 S gnome-vfs-daemo 2698 +524 2701 1 S pam-panel-icon - +524 2707 1 R rhn-applet-gui - +524 2717 2701 S pam_timestamp_c - +524 2718 1 S mapping-daemon - +524 2720 1 S wnck-applet - +524 2722 1 S mixer_applet2 - +524 2726 1 S clock-applet - +524 2728 1 S notification-ar - +524 15812 32675 S ssh - +524 16248 31908 S su - +root 16249 16248 S bash - +root 27121 3 S pdflush - +root 27243 3 S pdflush - +root 27682 1887 S sshd - +524 27684 27682 S sshd - +524 27685 27684 S bash - +root 29840 16249 R bash - +root 30737 1 S dhclient - +root 31905 1887 S sshd - +524 31907 31905 S sshd - +524 31908 31907 S bash - +root 32672 1887 S sshd - +524 32674 32672 S sshd - +524 32675 32674 S bash - diff --git a/tests/002/query-1.txr b/tests/002/query-1.txr new file mode 100644 index 00000000..fd4db03b --- /dev/null +++ b/tests/002/query-1.txr @@ -0,0 +1,38 @@ +@# +@# This file is in the public domain. +@# It was authored by Kaz Kylheku in 2009 +@# +@(next)!ls @TESTDIR/proc | sort -n +@(collect) +@{process /[0-9]+/} +@ (next)@TESTDIR/proc/@process/status +Name: @name +State: @state (@state_desc) +SleepAVG: @sleep_avg% +Tgid: @tgid +Pid: @proc_id +PPid: @parent_id +@(bind pid proc_id) +@(bind ppid parent_id) +@(skip) +Uid: @uid @/.*/ +Gid: @gid @/.*/ +@ (next)$@TESTDIR/proc/@process/task +@ (collect) +@thr +@ (end) +@ (bind thread thr) +@ (some) +@ (next)@TESTDIR/etc/passwd +@ (skip) +@user:@pw:@uid:@/.*/ +@ (and) +@ (bind user uid) +@ (end) +@(end) +@(output) +USER PID PPID S NAME THREADS +@ (repeat) +@{user 8} @{proc_id -5} @{parent_id -5} @state @{name 16} @(rep)@thr, @(first)@(last)@thr@(single)-@(end) +@ (end) +@(end) diff --git a/txr.1 b/txr.1 new file mode 100644 index 00000000..79a5eeaa --- /dev/null +++ b/txr.1 @@ -0,0 +1,1741 @@ +.\"Copyright (C) 2009, Kaz Kylheku . +.\"All rights reserved. +.\" +.\"BSD License: +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\"THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +.TH txr 1 2009-09-09 "txr v. 011" "Text Extraction Utility" +.SH NAME +txr \- text extractor +.SH SYNOPSIS +.B txr [ options ] query-file { data-file }* +.sp +.SH DESCRIPTION +.B txr +is a query tool for extracting pieces of text buried in one or more text +file based on pattern matching. A +.B txr +query specifies a pattern which matches (a prefix of) entire file, or +multiple files. The pattern is matched against the material in the files, and +free variables occurring in the pattern are bound to the pieces of text +occurring in the corresponding positions. If the overall match is +successful, then +.B txr +can do one of two things: it can report the list of variables which were bound, +in the form of a set of variable assignments which can be evaluated by the +.B eval +command of the POSIX shell language, or generate a custom report according +to special directives in the query. + +In addition to embedded variables which implicitly match text, the +.B txr +query language supports a number of directives, for matching text using regular +expressions, for continuing a match in another file, for searching through a +file for the place where an entire sub-query matches, for collecting lists, and +for combining sub-queries using logical conjunction, disjunction and negation. + +When +.B txr +finds a match for a variable and binds it, if that variable occurs again +later in the query, the variable's text is substituted, forcing a match for +that exact text. Thus txr supports a rudimentary form of backreferencing +unification, if you will. For example, the query + + @FOO=@FOO + +will match material from the start of the line until the first equal sign, +and bind it to the variable +.IR FOO. +Then, the material which follows the equal sign to the end of the line must +match the contents bound to FOO. Hence the line "abc=abc" will match, but +"abc=xyz" will fail to match. + +Generally, the scope of a variable's binding +extends from its first successful match where the binding is established, to +the end of the query. Unsuccessful subqueries have no effect on the +bindings. Even if a failed subquery is partially successful, all of its +bindings are thrown away. Some directives treat the bindings emanating +from their subqueries in special ways. + +.SH ARGUMENTS AND OPTIONS + +Options other than -D may be combined together into a single argument. +The -v and -q options are mutually exclusive. The one which occurs +in the rightmost position in the argument list dominates. + +.IP -Dvar=value +Bind the variable +.IR var +to the value +.IR value +prior to processing the query. The name is in scope over the entire +query, so that all occurrence of the variable are substituted and +match the equivalent text. If the value contains commas, these +are interpreted as separators, which give rise to a list value. +For instance -Da,b,c creates a list of the strings "a", "b" and "c". +(See Collect Directive bellow). List variables provide a multiple +match. That is to say, if a list variable occurs in a query, a successful +match occurs if any of its values matches the text. If more than one +value matches the text, the first one is taken. + +.IP -Dvar +Binds the variable +.IR var +to an empty string value prior to processing the query. + +.IP -q +Quiet operation during matching. Certain error messages are not reported on the +standard error device (but the if the situations occur, they still fail the +query). This option does not suppress error generation during the parsing +of the query, only during its execution. + +.IP -v +Verbose operation. Detailed logging is enabled. + +.IP -b +Suppresses the printing of variable bindings for a successful query, and the +word .IR false for a failed query. The program still sets an appropriate +termination status. + +.IP -a num +Specifies the maximum number of array dimensions to use for variables +arising out of collect. The default is 1. Additional dimensions are +expressed using numeric suffixes in the generated variable names. +For instance, consider the three-dimensional list arising out of a triply +nested collect: ((("a" "b") ("c" "d")) (("e" "f") ("g" "h"))). +Suppose this is bound to a variable V. With -a 1, this will be +reported as: + + V_0_0[0]="a" + V_0_1[0]="b" + V_1_0[0]="c" + V_1_1[0]="d" + V_0_0[1]="e" + V_0_1[1]="f" + V_1_0[1]="g" + V_1_1[1]="h" + +The leftmost bracketed index is the most major index. That is to say, +the dimension order is: NAME_m_m+1_..._n[1][2]...[m-1]. + +.IP --help +Prints usage summary on standard output, and terminates successfully. + +.IP --version +Prints program version standard output, and terminates successfully. + +.IP -- +Signifies the end of the option list. This option does not combine with others, so for instance -b- does not mean -b --, but is an error. + +.IP - +This argument is not interpreted as an option, but treated as a filename +argument. After the first such argument, no more options are recognized. Even +if another argument looks like an option, it is treated as a name. +This special argument - means "read from standard input" instead of a file. +The query file, or any of the data files, may be specified using this option. +If two or more files are specified as -, the behavior is system-dependent. +It may be possible to indicate EOF from the interactive terminal, and +then specify more input which is interpreted as the second file, and so forth. + +.PP +After the options, the remaining arguments are files. The first file argument +specifies the query, and is mandatory. A file argument consisting of a single +- means to read the standard input instead of opening a file. A file argument +which begins with an exclamation symbol means that the rest of the argument is +a shell command which is to be run as a coprocess, and its output read like a +file. + +.PP +.B txr +begins by reading the query. The entire query is scanned, internalized +and then begins executing. No file is opened until the query calls for a match +for material from that file, but once opened, a file is always read in its +entirety and stored in memory. A query may complete (successfully or not) +before opening some or all of the files. + +If no files arguments are specified on the command line, it is up to the +query to open a file, pipe or standard input via the @(next) directive +prior to attempting to make a match. If a query attempts to match text, +but has run out of files to process, the match fails. + +.SH STATUS AND ERROR REPORTING +.B txr +sends errors and verbose logs to the standard error device. The following paragraphs apply when +.B txr +is run without enabling verbose mode. If verbose mode is enabled, then +.B txr +issues diagnostics on the standard error device even in situations which are +not erroneous. + +If the command line arguments are incorrect, or the query has a malformed +syntax, or fails to match, +.B txr +issues an error diagnostic and terminates with a failed status. + +If the query is accepted, but fails to execute, either due to a +semantic error or due to a mismatch against the data, +.B txr +terminates with a failed status, it also prints the word +.IR false +on standard output. (See NOTES ON FALSE below). Printing of false +is suppressed if the query executed one or more @(output) directive +directed to standard output. + +If the query is well-formed, and matches, then +.B txr +issues no diagnostics on standard error (except in the case of verbose +reporting enabled by -v). If no variables were bound in the query, then +nothing is printed on standard output. If the query has matched one or more +variables, then these variables are printed on standard output, in the form of +a shell script which, when evaluated, will cause shell variables to be +assigned. Printing of these variables is suppressed if the query executed one +or more @(output) directive directed to standard output. + +.SH BASIC QUERY SYNTAX AND SEMANTICS + +.SS Comments + +A query may contain comments which are delimited by the sequence @# and +extend to the end of the line. No whitespace can occur between the @ and #. +A comment which begins on a line swallows that entire line, as well as the +newline which terminates it. In essence, the entire comment disappears. +If the comment follows some material in a line, then it does not consume +the newline. Thus, the following two queries are equivalent: + + 1. @a@# comment: match whole line against variable @a + @# this comment disappears entirely + @b + + 2. @a + @b + +The comment after the @a does not consume the newline, but the +comment which follows does. Without this intuitive behavior, +line comment would give rise to empty lines that must match empty +lines in the data, leading to spurious mismatches. + +.SS Text + +character for character. Text which occurs at the beginning of a line matches +the beginning of a line. Text which starts in the middle of a line, other than +following a variable, must match exactly at the current position, where the +previous match left off. Moreover, if the text is the last element in the line, +its match is anchored to the end of the line. + +The semantics of text matching next to a variable is discussed in the following +section. + +A query may not leave unmatched material in a line which is covered by the +query. However, a query may leave unmatched lines. + +In the following example, the query matches the text, even though +the text has an extra line. + + Query: Four score and seven + years ago our + + Text: Four score and seven + years ago our + forefathers + +In the following example, the query +.B fails +to match the text, because the text has extra material on one +line. + + Query: I can carry nearly eighty gigs + in my head + + Text: I can carry nearly eighty gigs of data + in my head + +Needless to say, if the text has insufficient material relative +to the query, that is a failure also. + +To match arbitrary material from the current position to the end +of a line, the "match any sequence of characters, including empty" +regular expression @/.*/ can be used. Example: + + Query: I can carry nearly eighty gigs@/.*/ + + Text: I can carry nearly eighty gigs of data + +In this example, the query matches, since the regular expression +matches the string "of data". (See Regular Expressions section below). + +.SS Special Characters in Text + +Control characters may be embedded directly in a query (with the exception of +newline characters). An alternative to embedding is to use escape syntax. +The following escapes are supported: + +.IP @\\a +Alert character (ASCII 7, BEL). +.IP @\\b +Backspace (ASCII 8, BS). +.IP @\\t +Horizontal tab (ASCII 9, HT). +.IP @\\n +Line feed (ASCII 10, LF). Serves as abstract newline on POSIX systems. +.IP @\\v +Vertical tab (ASCII 11, VT). +.IP @\\f +Form feed (ASCII 12, FF). This character clears the screen on many +kinds of terminals, or ejects a page of text from a line printer. +.IP @\\r +Carriage return (ASCII 13, CR). +.IP @\\e +Escape (ASCII 27, ESC) +.IP @\\x +A @\\x followed by a sequence of hex digits is interpreted as a hexadecimal +numeric character code. For instance @\\x41 is the ASCII character A. +.IP @\\ +A @\\ followed by a sequence of octal digits (0 through 7) is interpreted +as an octal character code. For instance @\\010 is character 8, same as @\\b. +.PP + +Note that if a newline is embedded into a query line with @\\n, this +does not split the line into two; it's embedded into the line and +thus cannot match anything. However, @\\n may be useful in the @(cat) +directive and in @(output). + +.SS Variables + +Much of the query syntax consists of arbitrary text, which matches file data +character for character. Embedded within the query may be variables and +directives which are introduced by a @ character. Two consecutive @@ +characters encode a literal @. + +A variable matching or substitution directive is written in one of several +ways: + + @NAME + @{NAME} + @*NAME + @*{NAME} + @{NAME /RE/} + @{NAME NUMBER} + +The forms with an * indicate a long match, see Longest Match below. +The last two forms with the embedded regexp /RE/ or number have special +semantics, see Positive Match below. + +The name itself may consist of any combination of one or more letters, numbers, +and underscores, and must begin with a letter or underscore. Case is +sensitive, so that @FOO is different from @foo, which is different from @Foo. +The braces around a name can be used when material which follows would +otherwise be interpreted as being part of the name. For instance @FOO_bar +introduces the name "FOO_bar", whereas @{FOO}_bar means the variable named +"FOO" followed by the text "_bar". There may be whitespace between the @ and +the name, or opening brace. Whitespace is also allowed in the interior of the +braces. It is not significant. + +If a variable has no prior binding, then it specifies a match. The +match is determined from some current position in the data: the +character which immediately follows all that has been matched previously. +If a variable occurs at the start of a line, it matches some text +at the start of the line. If it occurs at the end of a line, it matches +everything from the current position to the end of the line. + +The extent of the matched text (the text bound to the variable) is determined +by looking at what follows the variable. A variable may be followed by a piece +of text, a regular expression directive, another variable, or nothing (i.e. +occurs at the end of a line). + +If the variable is followed by nothing, the +match extends from the current position in the data, to the end of the line. +Example: + + pattern: "a b c @FOO" + data: "a b c defghijk" + result: FOO="defghijk" + +If the variable is followed by text (all non-directive material extending to +the end of the line, or to the start of another directive), then the extent of +the match is determined by searching for the first occurrence of that text +within the line, starting at the current position. The variable matches +everything between the current position and the matching position (not +including the matching position). Any whitespace which follows the +variable (and is not enclosed inside braces that surround the variable +name) is part of the text. For example: + + pattern: "a b @FOO e f" + data: "a b c d e f" + result: FOO="c d" + +In the above example, the pattern text "a b " matches the +data "a b ". So when the @FOO variable is processed, the data being +matched is the remaining "c d e f". The text which follows @FOO +is " e f". This is found within the data "c d e f" at position 3 +(counting from 0). So positions 0-2 ("c d") constitute the matching +text which is bound to FOO. + +If the variable is followed by a regular expression directive, +the extent is determined by finding the closest match for the +regular expression. (See Regular Expressions section below). + +.SS Consecutive Variables + +If an unbound variable is followed by another unbound variable, the +combination is a semantic error which will fail the query. A +diagnostic message will be issued, unless operating in quiet mode via -q. +The reason is that there is no way to bind two consecutive variables to +an extent of text; this is an ambiguous situation, since there is no +matching criterion for dividing the text between two variables. +(In theory, a repetition of the same variable, like @FOO@FOO, could +find a solution by dividing the match extent in half, which would work +only in the case when it contains an even number of characters. +This behavior seems to have dubious value). + +An unbound variable may be followed by one which is bound. The bound +variable is replaced by the text which it denotes, and the logic proceeds +accordingly. Variables are never bound to regular expressions, so +the regular expression match does not arise in this case. +The @* syntax for longest match is available. Example: + + pattern: "@FOO:@BAR@FOO" + data: "xyz:defxyz" + result: FOO=xyz, BAR=def + +Here, FOO is matched with "xyz", based on the delimiting around the +colon. The colon in the pattern then matches the colon in the data, +so that BAR is considered for matching against "defxyz". +BAR is followed by FOO, which is already bound to "xyz". +Thus "xyz" is located in the "defxyz" data following "def", +and so BAR is bound to "def". + +If an unbound variable is followed by a variable which is bound to a list, or +nested list, then each character string in the list is tried in turn to produce +a match. The first match is taken. + +.SS Longest Match + +The closest-match behavior for text and regular expressions can be +overridden to longest match behavior. A special syntax is provided +for this: an asterisk between the @ and the variable, e.g: + + pattern: "a @*{FOO}cd" + data: "a b cdcdcdcd" + result: FOO="b cdcdcd" + + pattern: "a @{FOO}cd" + data: "a b cdcdcd" + result: FOO="b " + +In the former example, the match extends to the rightmost occurrence of "cd", +and so FOO receives "b cdcdcd". In the latter example, the * +syntax isn't used, and so a leftmost match takes place. The extent +covers only the "b ", stopping at the first "cd" occurrence. + +.SS Positive Match + +The syntax variants + + @{NAME /RE/} + @{NAME NUMBER} + +specify a variable binding that is driven by a positive match derived +from a regular expression or character count, rather than from trailing +material (which may be regarded as a "negative" match, since the variable is +bound to material which is +.B skipped +in order to match the trailing material). In the /RE/ form, the match +extends over all characters from the current position which match +the regular expression RE. + +In the NUMBER form, the match processes a field of text which +consists of the specified number of characters, which must be nonnegative +number. If the data line doesn't have that many characters starting at the +current position, the match fails. A match for zero characters produces an +empty string. The text which is actually matched by this construct +is all text within the specified field, but excluding leading and +trailing whitespace. If the field contains only spaces, then an empty +string is extracted. + +A number is made up of digits, optionally preceded by a + or - sign. + +This syntax is processed without consideration of what other +syntax follows. A positive match may be directly followed by an unbound +variable. + +.SS Regular Expressions + +Like text, a regular expression (regexp) must match text in the data. A regexp +which occurs at the beginning of a line matches the beginning of a line. A +regexp which occurs elsewhere, other than following a variable, must match +exactly starting at the current position, where the previous match left off. A +regexp which occurs at the end of a line must match from the current position +to the end of the line. + +The semantics of a regular expression which follow variables is +discussed in the preceding section Variables. + +A regular expression, as a standalone directive, looks like this: + + @/RE/ + +where RE is regular expression syntax. +.B txr +contains an original implementation of regular expressions, which +supports the following syntax: +.IP . +matches any character. +.IP [] +Character class: matches a single character, from the set specified by +the class. Supports basic regexp character class syntax; no POSIX +notation like [:digit:]. The class [a-zA-Z] means match an uppercase +or lowercase letter; the class [0-9a-f] means match a digit or +a lowercase letter, the class [^0-9] means match a non-digit, et cetera. +A ] or - can be used within a character class, but must be escaped +with a backslash. Two backslashes code for one backslash. So +for instance [\[\-] means match a [ or - character, [^^] means match +any character other than ^, and [\^\\] means match either a ^ or a +backslash. +.IP (RE) +If RE is a regular expression, then so is (RE). +The contents of parentheses denote one regular expression unit, so that for +instance in (RE)*, the * operator applies to the entire parenthesized group. +.IP (RE)? +optionally matches the preceding regular expression (RE). +.IP (RE)+ +matches the preceding expression one or more times. +.IP (RE)* +matches the preceding expression zero or more times. +.IP (RE1)(RE2) +Two consecutive regular expressions denote catenation: +the left expression must match, and then the right. + +.IP (RE1)|(RE2) +matches either the expression RE1 or RE2. + +.PP +Any of the special characters, including the delimiting /, can be escaped with +a backslash to suppress its meaning and denote the character itself. + +Furthermore, all of the same escapes are as described in the section Special +Characters in Text above---the difference is that in regular expressions, the @ +character is not required, so for example a tab is coded as \\t rather +than @\\t. + +Any escaped character which does not fall into the above escaping conventions, +or any unescaped character which is not a regular expression operator, denotes +one-position match of that character itself. + +Character classes and parentheses have the highest precedence. + +The postfix operators ?, + and * have the second highest precedence, and +associate left to right, so that in A+?*, the * applies to A+?, and the ? +applies to A+. + +Catenation is on the next lower precedence rung, so that AB? means "match A, +and then optionally B" not "match A and B, as one optional unit". The latter +must be written (AB)? using parentheses to override precedence. + +The disjunction operator | has the lowest precedence, lower than catenation. +Thus abc|def means "match abc, or match def". The meaning "match ab, +then c or d, then ef" must be expressed as ab(c|d)ef, or using +a character class: ab[cd]ef. + +In +.b txr, +regular expression matches do not span multiple lines. There is no way +to match a newline character since it's simply not internally represented in +the data. + +It's possible for a regular expression to match an empty string. +For instance, if the next input character is z, facing a +the regular expression /a?/, there is a zero-character match: +the regular expression's state machine can reach an acceptance +state without consuming any characters. Examples: + + pattern: @A@/a?/@/.*/ + data: zzzzz + result: A="" + + pattern: @{A /a?/}@B + data: zzzzz + result: A="", B="zzzz" + + pattern: @*A@/a?/ + data: zzzzz + result: A="zzzzz" + +In the first example, variable @A is followed by a regular expression +which can match an empty string. The expression faces the letter "z" +at position 0 in the data line. A zero-character match occurs there, +therefore the variable A takes on the empty string. The @/.*/ regular +expression then consumes the line. + +Similarly, in the second example, the /a?/ regular expression faces +a "z", and thus yields an empty string which is bound to A. Variable +@B consumes the entire line. + +The third example request the longest match for the variable binding. +Thus, a search takes place for the rightmost position where the +regular expression matches. The regular expression matches anywhere, +including the empty string after the last character, which is +the rightmost place. Thus variable A fetches the entire line. + +.SS Directives + +The general syntax of a directive is: + + @EXPR + +where expr is a parenthesized list of subexpressions. A subexpression +is an symbol, number, regular expression, or a parenthesized expression. +So, examples of valid directives are: + + @(banana) + + @(a b c (d e f)) + + @( a (b (c d) (e ) )) + + @(a /[a-z]*/ b) + +A symbol is lexically the same thing as a variable and the same rules +apply. Tokens that look like numbers are treated as numbers. + +Some directives are involved in structuring the overall syntax of the query. + +There are syntactic constraints that depend on the directive. For instance the +@(next) directive can take argument material, which is everything that follows +on the same line, until the end of the line. But @(skip) does not take +argument material. Most directives must be the first item of a line. + +A summary of the available directives follows: + +.IP @(next) +Continue matching in another file. + +.IP @(block) +The remaining query is treated as an anonymous or named block. +Blocks may be referenced by @(accept) and @(fail) directives. +Blocks are discussed in the section Blocks below. + +.IP @(skip) +Treat the remaining query as a subquery unit, and search the lines of +the input file until that subquery matches somewhere. +A skip is also an anonymous block. + +.IP @(some) +Match some clauses in parallel. At least one has to match. + +.IP @(all) +Match some clauses in parallel. Each one must match. + +.IP @(none) +Match some clauses in parallel. None must match. + +.IP @(maybe) +Match some clauses in parallel. None must match. + +.IP @(collect) +Search the data for multiple matches of a clause. Collect the +bindings in the clause into lists, which are output as array variables. +The @(collect) directive is line oriented. It works with a multi-line +pattern and scans line by line. A similar directive called @(coll) +works within one line. + +A collect is an anonymous block. + +.IP @(and) +Separator of clauses for @(some), @(all), and @(none). +Equivalent to @(or). Choice is stylistic. + +.IP @(or) +Separator of clauses for @(some), @(all), and @(none). +Equivalent to @(and). Choice is stylistic. + +.IP @(end) +Required terminator for @(some), @(all), @(none), @(maybe), @(collect), +@(output), and @(repeat). + +.IP @(fail) +Terminate the processing of a block, as if it were a failed match. +Blocks are discussed in the section Blocks below. + +.IP @(accept) +Terminate the processing of a block, as if it were a successful match. +What bindings emerge may depend on the kind of block: collect +has special semantics. Blocks are discussed in the section Blocks below. + +.IP @(flatten) +Normalizes a set of specified variables to one-dimensional lists. Those +variables which have scalar value are reduced to lists of that value. +Those which are lists of lists (to an arbitrary level of nesting) are converted +to flat lists of their leaf values. + +.IP @(merge) +Binds a new variable which is the result of merging two or more +other variables. Merging has somewhat complicated semantics. + +.IP @(cat) +Decimates a list (any number of dimensions) to a string, by catenating its +constituent strings, with an optional separator string between all of the +values. + +.IP @(bind) +Binds one or more variables against another variable using a structural +pattern. A limited form of unification takes place which can cause a match to +fail. + +.IP @(output) +A directive which encloses an output clause in the query. An output section +does not match text, but produces text. The directives above are not +understood in an output clause. + +.IP @(repeat) +A directive understood within an @(output) section, for repeating multi-line +text, with successive substitutions pulled from lists. A version @(rept) +produces repeated text within one line. + +.PP + +.SS The Next Directive + +The next directive comes in two forms. It can occur by itself as the +only element in a query line: + + @(next) + +Or it may be followed by material, which may contain variables. +All of the variables must be bound. For example: + + @(next)/path/to/@foo.txt + +Both forms indicate that the remainder of the query applies +to a new file. The lone @(next) switches to the next file in the +argument list which was passed to the +.B txr +utility. The second form diverts the remainder of the query to a file whose +name is given by the trailing material, after variable substitutions are +performed. + +Note that "remainder of the query" refers to the subquery in which +the next directive appears, not necessarily the entire query. + +For example, the following query looks for the line starting with "xyz" +at the top of the file "foo.txt", within a some directive. +After the @(end) which terminates the @(some), the "abc" is matched in the +current file. + + @(some) + @(next)foo.txt + xyz@suffix + @(end) + abc + +However, if the @(some) subquery successfully matched "xyz@suffix" within the +file foo.text, there is now a binding for the suffix variable, which +is globally visible to the remainder of the entire query. + +The @(next) directive supports the file name conventions as the command +line. The name - means standard input. Text which starts with a ! is +interpreted as a shell command whose output is read like a file. These +interpretations are applied after variable substitution. If the file is +specified as @a, but the variable a expands to "!echo foo", then the output of +the "echo foo" command will be processed. + +.SS The Skip Directive + +The skip directive considers the remainder of the query as a search +pattern. The remainder is no longer required to strictly match at the +current line in the current file. Rather, the current file is searched, +starting with the current line, for the first line where the entire remainder +of the query will successfully match. If no such line is found, the skip +directive fails. If a matching position is found, the remainder of +the query is understood to be processed there. + +Of course, the remainder of the query can itself contain skip directives. +Each such directive performs a recursive subsearch. + +The skip directive has an optional numeric argument. The value of this +argument limits the range of lines scanned for a match. Judicious use +of this feature can improve the performance of queries. + +Example: scan until "size: @SIZE" matches, which must happen within +the next 15 lines: + + @(skip 15) + size: @SIZE + +Without the range limitation skip will keep searching until it consumes +the entire input source. While sometimes this is what is intended, +often it is not. Sometimes a skip is nested within a collect, or +following another skip. For instance, consider: + + @(collect) + begin @BEG_SYMBOL + @(skip) + end @BEG_SYMBOL + @(end) + +The collect iterates over the entire input. But, potentially, so does +the skip. Suppose that "begin x" is matched, but the data has no +matching "end x". The skip will search in vain all the way to the end of the +data, and then the collect will try another iteration back at the +beginning, just one line down from the original starting point. If it is a +reasonable expectation that an "end x" occurs 15 lines of a "begin x", this can +be written instead: + + @(collect) + begin @BEG_SYMBOL + @(skip 15) + end @BEG_SYMBOL + @(end) + +.SS The Some, All, None and Maybe directives + +These directives combine multiple subqueries, which are applied at the same position in parallel. The syntax of all three follows this example: + + @(some) + + . + . + . + @(and) + + . + . + . + @(and) + + . + . + . + @(end) + +The @(some), @(all) or @(none) directive must appear as the only element in a +query line. It must be followed by at least one subquery clause, and terminated +by @(end). If there are two or more subqueries, these additional clauses are +indicated by @(and) or @(or), which are interchangeable. The @(and), @(or) and +@(end) directives also must appear as the only element in a query line. + +The syntax supports arbitrary nesting. For example: + + QUERY: SYNTAX TREE: + + @(all) all -+ + @ (skip) +- skip -+ + @ (some) | +- some -+ + it | | +- TEXT + @ (and) | | +- and + @ (none) | | +- none -+ + was | | | +- TEXT + @ (end) | | | +- end + @ (end) | | +- end + a dark | +- TEXT + @(end) *- end + +nesting can be indicated using whitespace between @ and the +directive expression. Thus, the above is an @(all) query containing a @(skip) +clause which applies to a @(some) that is followed by the the text +line "a dark". The @(some) clause combines the text line "it", +and a @(none) clause which contains just one clause consisting of +the line "was". + +The semantics of the some, all, none and maybe directives is: + +.IP @(all) +Each of the clauses is matched at the current position. If any of the +clauses fails to match, the directive fails (and thus does not produce +any variable bindings). + +.IP @(some) +Each of the clauses is matched at the current position. If any +of the clauses succeed, the directive succeeds. The bindings from +all successful clauses are retained. + +.IP @(none) +Each of the clauses is matched at the current position. The +directive succeeds only if all of the clauses fail. If +any clause succeeds, the directive fails. Thus, this +directive never produces variable bindings. + +.IP @(maybe) +Each of the clauses is matched at the current position. +The directive succeeds even if all of the clauses fail. +Whatever bindings are found in any of the clauses are +retained. + +When a @(some) or @(all) directive matches successfully, or a @(maybe) +directive matches something, the query advances by the greatest number of lines +matched in any of the subclauses. For instance if there are two subclauses, and +one of them matches three lines, but the other one matches five lines, then the +overall clause is considered to have made a five line match at its position. If +more directives follow, they begin matching five lines down from that position. + +.SS The Collect Directive + +The syntax of the collect directive is: + + @(collect) + ... lines of subquery + @(end) + +or with an until clause: + + @(collect) + ... lines of subquery + @(until) + ... lines of subquery + @(end) + + +The the subquery is matched repeatedly, starting at the current line. +If it fails to match, it is tried starting at the subsequent line. +If it matches successfully, it is tried at the line following the +entire extent of matched data, if there is one. Thus, the collected regions do +not overlap. + +The collect as a whole always succeeds, even if the subquery does not match at +any position, and even if the until clause does not match. That is to say, a +query will never fail for the reason that a collect didn't collect anything. + +If no until clause is specified, the collect is unbounded. It consumes the entire data file. If any query material follows such the collect clause, it will +fail if it tries to match anything in the current file; but of course, it +is possible to continue matching in another file by means of @(next). + +If an until clause is specified, the collection stops when that clause matches +at the current position (and that last position is also collected, if it +matches). If the collection is stopped by a match in the until clause, +any variables bound in that clause also emerge out of the overall collect +clause (but these bindings are single values, not lists). + +Example: + + Query: @(collect) + @a + @(until) + 42 + @(end) + + Data: 1 + 2 + 3 + 42 + 5 + 6 + + Output: a[0]="1" + a[1]="2" + a[2]="3" + a[3]="42" + +The binding variables within the clause of a collect are treated specially. +The multiple matches for each variable are collected into lists, +which then appear as array variables in the final output. + +Example: + + Query: @(collect) + @a:@b:@c + @(end) + + Data: John:Doe:101 + Mary:Jane:202 + Bob:Coder:313 + + Output: + a[0]="John" + a[1]="Mary" + a[2]="Bob" + b[0]="Doe" + b[1]="Jane" + b[2]="Coder" + c[0]="101" + c[1]="202" + c[2]="313" + +The query matches the data in three places, so each variable becomes +a list of three elements, reported as an array. + +Variables with list bindings may be referenced in a query. They denote a +multiple match. The -D command line option can establish a one-dimensional +list binding. + +Collect clauses may be nested. Variable matches collated into lists in an +inner collect, are again collated into nested lists in the outer collect. +Thus an unbound variable wrapped in N nestings of @(collect) will +be an N-dimensional list. A one dimensional list is a list of strings; +a two dimensional list is a list of lists of strings, etc. + +It is important to note that the variables which are bound within the main +clause of a collect---i.e. the variables which are subject to +collection---appear as normal one-value bindings. The collation into lists +happens outside of the collect. So for instance in the query: + + @(collect) + @x=@x + @(end) + +The left @x establishes a binding for some material preceding an equal sign. +The right @x refers to that binding. The value of @x is different in each +iteration, and these values are collected. What finally comes out of the +collect clause is list variable called x which holds each value that +was ever instantiated under that name within the collect clause. + +If the collect stops before exhausting the data file---that is to say, +it is terminated by a successful match in the until clause---then +the material consumed by the until clause is considered consumed. +The current position in the data set which now faces any further +query material is located beyond the last line which matches +the until clause. This is true even if the until clause and collect +clause both match simultaneously, and the clause matches a different +number of lines. If this last collect matches a greater number of lines +than the terminating until, then some of the material covered by this last +collect will be again matched by query lines which follow the collect +directive. + +.SS The Coll Directive + +The coll directive is a kind of miniature version of the collect directive. +Whereas the collect directive works with multi-line clauses on line-oriented +material, coll works within a single line. With coll, it is possible to +recognize repeating regularities within a line and collect lists. + +Regular-expression based Positive Match variables work well with coll. + +Example: collect a comma-separated list, terminated by a space. + + pattern: @(coll)@{A /[^, ]+/}@(until) @(end)@B + data: foo,bar,xyzzy blorch + result: A[0]="foo" + A[1]="bar" + A[2]="xyzzy" + B=blorch + +Here, the variable A is bound to tokens which match the regular +expression /[^, ]+/: non-empty sequence of characters other than commas or +spaces. + +Like its big cousin, the coll directive searches for matches. If no match +occurs at the current character position, it tries at the next character +position. Whenever a match occurs, it continues at the character position which +follows the last character of the match, if such a position exists. + +If not bounded by an until clause, it will exhaust the entire line. If the +until clause matches, then the remainder of the data line following the extent +consumed by the until clause is available for more matching. + +Coll clauses nest, and variables bound within a coll are available to within +the rest of the coll clause, including the until clause, and appear as single +values. The final list aggregation is only visible after the coll clause. + +The behavior of coll is troublesome, when delimited variables are used, +because in text file formats, the material which separates items is not +repeated after the last item. For instance, a comma-separated list usually +not appear as "a,b,c," but rather "a,b,c". There might not be any explicit +termination---the last item might be at the very end of the line. + +So for instance, the following result is not satisfactory: + + pattern: @(coll)@a @(end) + data: 1 2 3 4 5 + result: a[0]="1" + a[1]="2" + a[2]="3" + a[3]="4" + +What happened to the 5? After matching "4 ", coll continues to look for +matches. It tries "5", which does not match, because it is not followed by a +space. Then the line is consumed. So in this sequence, a valid item is either +followed by a space, or by nothing. So it is tempting to try this: + + pattern: @(coll)@a@/ ?/@(end) + data: 1 2 3 4 5 + result: a[0]="" + a[1]="" + a[2]="" + a[3]="" + a[4]="" + a[5]="" + a[6]="" + a[7]="" + a[8]="" + +however, the problem is that the regular expression / ?/ (match either a space +or nothing), matches at any position. So when it is used as a variable +delimiter, it matches at the current position, which binds the empty string to +the variable, the extent of the match being zero. In this situation, the coll +directive proceeds character by character. The solution is to use +positive matching: specify the regular expression which matches the item, +rather than a trying to match whatever follows. The collect directive will +recognize all items which match the regular expression. + + pattern: @(coll)@{a /[^ ]+/}@(end) + data: 1 2 3 4 5 + result: a[0]="1" + a[1]="2" + a[2]="3" + a[3]="4" + a[4]="5" + +The until clause can specify a pattern which, when recognized, terminates +the collection. So for instance, suppose that the list of items may +or may not be terminated by a semicolon. We must exclude +the semicolon from being a valid character inside an item, and +add an until clause which recognizes a semicolon: + + pattern: @(coll)@{a /[^ ;]+/}@(until);@(end) + + data: 1 2 3 4 5; + result: a[0]="1" + a[1]="2" + a[2]="3" + a[3]="4" + a[4]="5" + + data: 1 2 3 4 5 + result: a[0]="1" + a[1]="2" + a[2]="3" + a[3]="4" + a[4]="5" + +Semicolon or not, the items are collected properly. + +.SS The Flatten Directive. + +The flatten directive can be used to convert variables to one dimensional +lists. Variables which have a scalar value are converted to lists containing +that value. Variables which are multidimensional lists are flattened to +one-dimensional lists. + +Example (without @(flatten)) + + pattern: @b + @(collect) + @(collect) + @a + @(end) + @(end) + + data: 0 + 1 + 2 + 3 + 4 + 5 + + result: b="0" + a_0[0]="1" + a_1[0]="2" + a_2[0]="3" + a_3[0]="4" + a_4[0]="5" + +Example (with flatten): + + pattern: @b + @(collect) + @(collect) + @a + @(end) + @(end) + @(flatten a b) + + data: 0 + 1 + 2 + 3 + 4 + 5 + + result: b[0]="0" + a[0]="1" + a[1]="2" + a[2]="3" + a[3]="4" + a[4]="5" + + +.SS The Cat Directive + +The @(cat) directive converts a list variable into a single +piece of text. Optionally, a separating piece of text can be inserted +in between the elements. This piece is written to the right of +the @(cat) directive, and spans to the end of the line. It may +contain variable substitutions. + +Example: + + pattern: @(coll)@{a /[^ ]+/}@(end) + @(cat a): + data: 1 2 3 4 5 + result: a="1:2:3:4:5" + + +.SS The Bind Directive + +The @(bind) directive is a kind of pattern match, which matches one or more +variables on the left hand side to the value of a variable on the right hand +side. The right hand side variable must have a binding, or else the directive +fails. Any variables on the left hand side which are unbound receive a matching +piece of the right hand side value. Any variables on the left which are already +bound must match their corresponding value, or the bind fails. Any variables +which are already bound and which do match their corresponding value remain +unchanged (the match can be inexact). + +The simplest bind is of one variable against itself, for instance bind A +against A: + + @(bind A A) + +This will fail if A is not bound, (and complain loudly). If A is bound, it +succeeds, since A matches A. + +The next simplest bind binds one variable to another: + + @(bind A B) + +Here, if A is unbound, it takes on the same value as B. If A is bound, it has +to match B, or the bind fails. Matching means that either + +- A and B are the same text +- A is text, B is a list, and A occurs within B. +- vice versa: B is text, A is a list, and B occurs within A. +- A and B are lists and are either identical, or one is + found as substructure within the other. + +The left hand side of a bind can be a nested list pattern containing variables. +The last item of a list at any nesting level can be preceded by a dot, which +means that the variable matches the rest of the list from that position. + +Example: suppose that the list A contains ("now" "now" "brown" "cow"). Then the +directive @(bind (H N . C) A), assuming that H, N and C are unbound variables, +will bind H to "how", N to "now", and C to the remainder of the list ("brown" +"cow"). + +Example: suppose that the list A is nested to two dimensions and contains +(("how" "now") ("brown" "cow")). Then @(bind ((H N) (B C)) A) +binds H to "how", N to "now", B to "brown" and C to "cow". + +The dot notation may be used at any nesting level. it must be preceded and +followed by a symbol: the forms (.) (. X) and (X .) are invalid. + +.SH BLOCKS + +.SS Introduction + +Blocks are sections of a query which are denoted by a name. Blocks denoted by +the name nil are understood as anonymous. + +The @(block ) directive introduces a named block, except when the name is +the word nil. The @(block) directive introduces an unnamed block, equivalent +to @(block nil). + +The @(skip) and @(collect) directives introduce implicit anonymous blocks. + +.SS Block Scope + +The names of blocks are in a distinct namespace from the variable binding +space. So @(block foo) has no interaction with the variable @foo. + +A block extends from the @(block ...) directive which introduces it, +to the end of the subquery in which that directive is contained. For instance: + + @(some) + abc + @(block foo) + xyz + @(end) + +Here, the block foo occurs in a @(some) clause, and so it extends to the @(end) +which terminates that clause. After that @(end), the name foo is not +associated with a block (is not "in scope"). A block which is not contained in +any subquery extends to the end of the overall query. Blocks are never +terminated by @(end). + +The implicit anonymous blocks introduced by @(skip) has the same scope +as the @(skip): it extends over all of the material which follows the skip, to the end of the containing subquery. + +The scope of the implicit anonymous block introduced by @(collect) spans only +that collect coincides with the scope of that collect: from the @(collect) +to its matching @(end). + +.SS Block Nesting + +Blocks may nest, and nested blocks may have the same names as blocks in +which they are nested. For instance: + +@(block) +@(block) +... + +is a nesting of two anonymous blocks, and + +@(block foo) +@(block foo) + +is a nesting of two named blocks which happen to have the same name. +When a nested block has the same name as an outer block, it creates +a block scope in which the outer block is "shadowed"; that is to say, +directives which refer to that block name within the nested block refer to the +inner block, and not to the outer one. + +A more complicated example of nesting is: + +@(skip) +abc +@(block) +@(some) +@(block foo) +@(end) + +Here, the @(skip) introduces an anonymous block. The explicit anonymous +@(block) is nested within skip's anonymous block and shadows it. +The foo block is nested within both of these. + +.SS Block Semantics + +A block normally does nothing. The query material in the block is evaluated +normally. However, a block serves as a termination point for @(fail) and +@(accept) directives which are in scope of that block and refer to it. + +The precise meaning of these directives is: + +.IP @(fail ) + +Immediately terminate the enclosing query block called , as if that block failed to match anything. If more than one block by that name encloses +the directive, the inner-most block is terminated. No bindings +emerge from a failed block. + +.IP @(fail) + +Immediately terminate the innermost enclosing anonymous block, as if +that block failed to match. + +If the implicit block introduced by @(skip) is terminated in this manner, +this has the effect of causing the skip itself to fail. I.e. the behavior +is as if skip search did not find a match for the trailing material, +except that it takes place prematurely (before the end of the available +data source is reached). + +If the implicit block associated with a @(collect) is terminated this way, +then the entire collect fails. This is a special behavior, because a +collect normally does not fail, even if it matches and collects nothing! + +To prematurely terminate a collect by means of its anonymous block, without +failing it, use @(accept). + +.IP @(accept ) + +Immediately terminate the enclosing query block called , as if that block +successfully matched. If more than one block by that name encloses the +directive, the inner-most block is terminated. Any bindings established within +that block until this point emerge from that block. + +.IP @(accept) + +Immediately terminate the innermost enclosing anonymous block, as if +that block successfully mached. Any bindings established within +that block until this point emerge from that block. + +If the implicit block introduced by @(skip) is terminated in this manner, +this has the effect of causing the skip itself to succeed, as if +all of the trailing material succesfully matched. + +If the implicit block associated with a @(collect) is terminated this way, +then the collection stops. All bindings collected in the current iteration of +the collect are discarded. Bindings collected in previous iterations are +retained, and collated into lists in accordance with the semantics of collect. + +Example: alternative way to @(until) termination: + + @(collect) + @ (maybe) + --- + @ (accept) + @ (end) + @LINE + @(end) + +This query will collect entire lines into a list called LINE. However, +if the line --- is matched (by the embedded @(maybe)), the collection +is terminated. Only the lines up to, and not including the --- line, +are collected. The effect is similar to: + + @(collect) + @LINE + @(until) + --- + @(end) + +However, the following example has a different meaning: + + @(collect) + @LINE + @ (maybe) + --- + @ (accept) + @ (end) + @(end) + +Now, lines are collected until the end of the data source, or until a line is +found which is followed by a --- line. If such a line is found, +the collection stops, and that line is not included in the collection! +The @(accept) terminates the process of the collect body, and so the +action of collecting the last @LINE binding into the list is not performed. + +.SS Data Extent of Terminated Blocks + +A data block may have matched some material prior to being terminated by +accept. In that case, it is deemed to have only matched that material, +and not any material which follows. This may matter, depending on the context +in which the block occurs. + +Example: + + Query: @(some) + @(block foo) + @first + @(accept foo) + @ignored + @(end) + @second + + Data: 1 + 2 + 3 + + Output: first="1" + second="2" + +At the point where the accept occurs, the foo block has matched the first line, +bound the text "1" to the variable @first. The block is then terminated. +Not only does the @first binding emerge from this terminated block, but +what also emerges is that the block advanced the data past the first line to +the second line. So next, the @(some) directive ends, and propagates the +bindings and position. Thus the @second which follows then matches the second +line and takes the text "2". + +In the following query, the foo block occurs inside a maybe clause. +Inside the foo block there is a @(some) clause. Its first subclause +matches variable @first and then terminates block foo. Since block foo is +outside of the @(some) directive, this has the effect of terminating the +@(some) clause: + + Query: @(maybe) + @(block foo) + @ (some) + @first + @ (accept foo) + @ (or) + @one + @two + @three + @four + @ (end) + @(end) + @second + + Data: 1 + 2 + 3 + 4 + 5 + + Output: first="1" + second="2" + +The second clause of the @(some) directive, namely: + + @one + @two + @three + @four + +is never processed. The reason is that subclauses are processed in top +to bottom order, but the processing was aborted within the +first clause the @(accept foo). The @(some) construct never had the +opportunity to match four lines. + +If the @(accept foo) line is removed from the above query, the output +is different: + + Query: @(maybe) + @(block foo) + @ (some) + @first + @# <-- @(accept foo) removed from here!!! + @ (or) + @one + @two + @three + @four + @ (end) + @(end) + @second + + Data: 1 + 2 + 3 + 4 + 5 + + Output: first="1" + one="1" + two="2" + three="3" + four="4" + second="5" + +Now, all clauses of the @(some) directive have the opportunity to match. +The second clause grabs four lines, which is the longest match. +And so, the next line of input available for matching is 5, which goes +to the @second variable. + +.SH OUTPUT + +A +.B txr +query may perform custom output. Output is performed by @(output) clauses, +which may be embedded anywhere in the query, or placed at the end. Output +occurs as a side effect of producing a part of a query which contains an +@(output) directive, and is executed even if that part of the query ultimately +fails to find a match. Thus output can be useful for debugging. +An output clause specifies that its output goes to a file, pipe, or (by +default) standard output. If any output clause is executed whose destination is +standard output, +.B txr +makes a note of this, and later, just prior to termination, suppresses the +usual printing of the variable bindings or the word false. + +.SS The Output Directive + +The syntax of the @(output) directive is: + + @(output)...optional destination... + . + . one or more output directives or lines + . + @(end) + +The optional destination is a filename, the special name, - which +redirects to standard output, or a shell command preceded by the ! symbol. +Variables are substituted in the directive. + +.SS Output Text + +Text in an output clause is not matched against anything, but is output +verbatim to the destination file, device or command pipe. + +.SS Output Variables + +Variables occurring in an output clause do not match anything, but instead their +contents are output. A variable being output must be a simple string, not a +list. Lists may be output within @(repeat) or @(rep) clauses. A list variable +must be wrapped in as many nestings of these clauses as it has dimensions. For +instance, a two-dimensional list may be mentioned in output if it is inside a +@(rep) or @(repeat) clause which is itself wrapped inside another @(rep) or +@(repeat) clause. + +In an output clause, the @{NAME NUMBER} variable syntax generates fixed-width +field, which contains the variable's text. The absolute value of the +number specifies the field width. For instance -20 and 20 both specify a field +width of twenty. If the text is longer than the field, then it overflows the +field. If the text is shorter than the field, then it is left-adjusted within +that field, if the width is specified as a positive number, and right-adjusted +if the width is specified as negative. + +.SS The Repeat Directive + +The repeat directive is generates repeated text from a ``boilerplate'', +by taking successive elements from lists. The syntax of repeat is +like this: + + @(repeat) + . + . + main clause material, required + . + . + special clauses, optional + . + . + @(end) + +Repeat has four types of special clauses, any of which may be +specified with empty contents, or omitted entirely. They are explained +below. + +All of the material in the main clause and optional clauses +is examined for the presence of variables. If none of the variables +hold lists which contain at least one item, then no output is performed, +(unless the repeat specifies an @(empty) clause, see below). +Otherwise, among those variables which contain non-empty lists, repeat finds +the length of the longest list. This length of this list determines the number +of repetitions, R. + +If the repeat contains only a main clause, then the lines of this clause is +output R times. Over the first repetition, all of the variables which, outside +of the repeat, contain lists are locally rebound to just their first item. Over +the second repetition, all of the list variables are bound to their second +item, and so forth. Any variables which hold shorter lists than the longest +list eventually end up with empty values over some repetitions. + +Example: if the list A holds "1", "2" and "3"; the list B holds "A", "B"; +and the variable C holds "X", then + + @(repeat) + >> @C + >> @A @B + @(end) + +will produce three repetitions (since there are two lists, the longest +of which has three items). The output is: + + >> X + >> 1 A + >> X + >> 2 B + >> X + >> 3 + +The last line has a trailing space, since it is produced by "@A @B", +where @B has an empty value. Since C is not a list variable, it +produces the same value in each repetition. + +The special clauses are: + +.IP @(single) +If the repeat produces exactly one repetition, then the contents of this clause +are processed for that one and only repetition, instead of the main clause +or any other clause which would otherwise be processed. + +.IP @(first) +The body of this clause specifies an alternative body to be used for the first +repetition, instead of the material from the main clause. + +.IP @(last) +The body of this clause is used instead of the main clause for the last +repetition. + +.IP @(empty) +If the repeat produces no repetitions, then the body of this clause is output. +If this clause is absent or empty, the repeat produces no output. + +.PP +The precedence among the clauses which take an iteration is: +single > first > last > main. That is if two or more of these clauses +can apply to a repetition, then the leftmost one in this precedence list +applies. For instance, if there is just a single repetition, then any of these +special clause types can apply to that repetition, since it is the only +repetition, as well as the first and last one. In this situation, if +there is a single clause present, then the repetition is processed +using that clause. Otherwise, if there is a first clause present, that +clause is used. Failing that, a last clause applies. Only if none of these +clauses are present will the repetition be processed using the main clause. + +.SS Nested Repeats + +If a repeat clause encloses variables which holds multidimensional lists, +those lists require additional nesting levels of repeat (or rep). +It is an error to attempt to output a list variable which has not been +decimated into primary elements via a repeat construct. + +Suppose that a variable X is two-dimensional (contains a list of lists). X +must be twice nested in a repeat. The outer repeat will walk over the lists +contained in X. The inner repeat will walk over the elements of each of these +lists. + +A nested repeat may be embedded in any of the clauses of a repeat, +not only the main clause. + +.SS The Rep Directive + +The @(rep) directive is similar to @(repeat), but whereas @(repeat) is line +oriented, @(rep) generates material within a line. It has all the same clauses, +but everything is specified within one line: + + @(rep)... main material ... .... special clauses ...@(end) + +More than one @(rep) can occur within a line, mixed with other material. +A @(rep) can be nested within a @(repeat) or within another @(rep). + +.SS Repeat and Rep Examples + +Example 1: show the list L in parentheses, with spaces between +the elements, or the symbol NIL if the list is empty: + + @(output) + @(rep)@L @(single)(@L)@(first)(@L @(last)@L)@(empty)NIL@(end) + @(end) + +Here, the @(empty) clause specifies NIL. So if there are no repetitions, +the text NIL is produced. If there is a single item in the list L, +then @(single)(@L) produces that item between parentheses. Otherwise +if there are two or more items, the first item is produced with +a leading parenthesis followed by a space by @(first)(@L , and +the last item is produced with a closing parenthesis: @(last)@L). +All items in between are emitted with a trailing space by +the main clause: @(rep)@L . + +Example 2: show the list L like Example 1 above, but the empty list is (). + + @(output) + (@(rep)@L @(last)@L@(end)) + @(end) + +This is simpler. The parentheses are part of the text which +surrounds the @(rep) construct, produced unconditionally. +If the list L is empty, then @(rep) produces no output, resulting in (). +If the list L has one or more items, then they are produced with +spaces each one, except the last which has no space. +If the list has exactly one item, then the @(last) applies to it +instead of the main clause: it is produced with no trailing space. + +.SH NOTES ON FALSE + +The reason for printing the word +.IR false +on standard output when +a query doesn't match, in addition to returning a failed termination +status, is that the output of +.B txr +may be collected by a shell script, by the application of eval to command +substitution syntax. Printing +.IR false +will cause eval to evaluate the +.IR false +command, and thus failed status will propagate from the eval +itself. The eval command conceals the termination status of a +program run via command substitution. That is to say, if a program +fails, without producing output, its output is substituted into the eval +command which then succeeds, masking the failure of the program. For example: + + eval "$(false)" + +appears successful: the false utility indicates a failed status, but +produces no output. Eval evaluates an empty script and reports success; +the failed status of the false program is forgotten. +Note the difference between the above and this: + + eval "$(echo false)" + +This command has a failed status. The echo prints the word false and succeeds; +this false word is then evaluated as a script, and thus interpreted as the +false command which fails. This failure +.B is +propagated as the result of the eval +command. diff --git a/unwind.c b/unwind.c new file mode 100644 index 00000000..c573c16d --- /dev/null +++ b/unwind.c @@ -0,0 +1,88 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include "lib.h" +#include "unwind.h" + +static uw_frame_t *uw_stack; +static uw_frame_t *uw_exit_point; + +static void uw_unwind_to_exit_point() +{ + while (uw_stack && uw_stack != uw_exit_point) + uw_stack = uw_stack->uw.up; + + if (!uw_stack) + abort(); + + uw_exit_point = 0; + + switch (uw_stack->uw.type) { + case UW_BLOCK: + longjmp(uw_stack->bl.jb, 1); + break; + } + + abort(); +} + +void uw_push_block(uw_frame_t *fr, obj_t *tag) +{ + fr->bl.type = UW_BLOCK; + fr->bl.tag = tag; + fr->bl.result = nil; + fr->bl.up = uw_stack; + uw_stack = fr; +} + +void uw_pop_frame(uw_frame_t *fr) +{ + assert (fr == uw_stack); + uw_stack = uw_stack->uw.up; +} + +obj_t *uw_block_return(obj_t *tag, obj_t *result) +{ + uw_frame_t *ex; + + for (ex = uw_stack; ex != 0; ex = ex->uw.up) { + if (ex->uw.type == UW_BLOCK && ex->bl.tag == tag) + break; + } + + if (ex == 0) + return nil; + + ex->bl.result = result; + uw_exit_point = ex; + uw_unwind_to_exit_point(); + abort(); +} diff --git a/unwind.h b/unwind.h new file mode 100644 index 00000000..8863fdff --- /dev/null +++ b/unwind.h @@ -0,0 +1,66 @@ +/* Copyright 2009 + * Kaz Kylheku + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +typedef union uw_frame uw_frame_t; +typedef enum uw_frtype uw_frtype_t; + +enum uw_frtype { UW_BLOCK }; + +struct uw_common { + uw_frame_t *up; + uw_frtype_t type; +}; + +struct uw_block { + uw_frame_t *up; + uw_frtype_t type; + obj_t *tag; + obj_t *result; + jmp_buf jb; +}; + +union uw_frame { + struct uw_common uw; + struct uw_block bl; +}; + +void uw_push_block(uw_frame_t *, obj_t *tag); +obj_t *uw_block_return(obj_t *tag, obj_t *result); +void uw_pop_frame(uw_frame_t *); + +#define uw_block_begin(TAG, RESULTVAR) \ + obj_t *RESULTVAR = nil; \ + { \ + uw_frame_t uw_fr; \ + uw_push_block(&uw_fr, TAG); \ + if (setjmp(uw_fr.bl.jb)) { \ + RESULTVAR = uw_fr.bl.result; \ + } else { + +#define uw_block_end \ + } \ + uw_pop_frame(&uw_fr); \ + } -- cgit v1.2.3