diff options
217 files changed, 11977 insertions, 0 deletions
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 <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + New features: + - named blocks; + - maybe clause; + - optional iteration bound on skip. + + * extract.y: includes added: "unwind.h", <setjmp.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 <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + * tests/002/query-1.txr: Modified to use $ to scan thread + subdirectories. + * tests/002/query-1.expected: Updated. + +2009-09-23 Kaz Kylheku <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + 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 <dirent.h> added. + * extract.l: inclusion of <dirent.h> 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 <dirent.h> added + +2009-09-23 Kaz Kylheku <kkylheku@gmail.com> + + 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 <kkylheku@gmail.com> + + * Makefile (LIBLEX): New variable. + Refer to lex library as -lfl, using variable + that can be overridden. + +2009-09-22 Kaz Kylheku <kkylheku@gmail.com> + + * 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 <kkylheku@gmail.com>. +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 <kkylheku@gmail.com> +# 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 <kkylheku@gmail.com> + * 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 <stdio.h> +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 <kkylheku@gmail.com> + * 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 <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include <dirent.h> +#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 + +%% + +<SPECIAL>{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; + } + + +<SPECIAL>\({WS}all{WS}\) { + BEGIN(INITIAL); + return ALL; + } + +<SPECIAL>\({WS}some{WS}\) { + BEGIN(INITIAL); + return SOME; + } + +<SPECIAL>\({WS}none{WS}\) { + BEGIN(INITIAL); + return NONE; + } + +<SPECIAL>\({WS}maybe{WS}\) { + BEGIN(INITIAL); + return MAYBE; + } + +<SPECIAL>\({WS}and{WS}\) { + BEGIN(INITIAL); + return AND; + } + +<SPECIAL>\({WS}or{WS}\) { + BEGIN(INITIAL); + return OR; + } + +<SPECIAL>\({WS}end{WS}\) { + BEGIN(INITIAL); + return END; + } + +<SPECIAL>\({WS}collect{WS}\) { + BEGIN(INITIAL); + return COLLECT; + } + +<SPECIAL>\({WS}coll{WS}\) { + BEGIN(INITIAL); + return COLL; + } + +<SPECIAL>\({WS}until{WS}\) { + BEGIN(INITIAL); + return UNTIL; + } + +<SPECIAL>\({WS}output{WS}\) { + BEGIN(INITIAL); + return OUTPUT; + } + +<SPECIAL>\({WS}repeat{WS}\) { + BEGIN(INITIAL); + return REPEAT; + } + + +<SPECIAL>\({WS}rep{WS}\) { + BEGIN(INITIAL); + return REP; + } + +<SPECIAL>\({WS}single{WS}\) { + BEGIN(INITIAL); + return SINGLE; + } + +<SPECIAL>\({WS}first{WS}\) { + BEGIN(INITIAL); + return FIRST; + } + +<SPECIAL>\({WS}last{WS}\) { + BEGIN(INITIAL); + return LAST; + } + +<SPECIAL>\({WS}empty{WS}\) { + BEGIN(INITIAL); + return EMPTY; + } + +<SPECIAL>\{|\( { + nesting++; + if (yytext[0] == '{') + closechar = '}'; + else + closechar = ')'; + return yytext[0]; + } + +<SPECIAL>\}|\) { + if (yytext[0] != closechar) { + yyerror("paren mismatch"); + BEGIN(INITIAL); + } else { + if (--nesting == 0) + BEGIN(INITIAL); + return yytext[0]; + } + } + +<SPECIAL>[\t ]+ { + /* Eat whitespace in directive */ + } + +<SPECIAL>@ { + if (nesting == 0) { + BEGIN(INITIAL); + yylval.lexeme = strdup("@"); + return TEXT; + } else { + yyerrorf(0, "bad character in directive: %c", yytext[0]); + } + } + +<SPECIAL>\n { + lineno++; + yyerror("newline in directive"); + } + +<SPECIAL>[/] { + BEGIN(REGEX); + return '/'; + } + +<SPECIAL>\. { + yylval.chr = '.'; + return '.'; + } + +<SPECIAL>[\\][abtnvfre] { + char lexeme[2]; + lexeme[0] = char_esc(yytext[1]); + lexeme[1] = 0; + yylval.lexeme = strdup(lexeme); + BEGIN(INITIAL); + return TEXT; + } + +<SPECIAL>[\\](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; + } + +<SPECIAL>. { + yyerrorf(0, "bad character in directive: '%c'", yytext[0]); + } + +<REGEX>[/] { + if (nesting == 0) + BEGIN(INITIAL); + else + BEGIN(SPECIAL); + yylval.chr = '/'; + return '/'; + } + + +<REGEX>[\\][abtnvfre] { + yylval.chr = char_esc(yytext[1]); + return REGCHAR; + } + +<REGEX>[\\](x[0-9a-fA-F]+|[0-9]+) { + yylval.chr = num_esc(yytext + 1); + return REGCHAR; + } + +<REGEX>\n { + lineno++; + yyerror("newline in regex"); + } + +<REGEX>[.*?+^] { + yylval.chr = yytext[0]; + return yytext[0]; + } + + +<REGEX>[\[\]\-] { + yylval.chr = yytext[0]; + return yytext[0]; + } + +<REGEX>[()|] { + yylval.chr = yytext[0]; + return yytext[0]; + } + +<REGEX>[\\]. { + yylval.chr = yytext[1]; + return REGCHAR; + } + +<REGEX>. { + yylval.chr = yytext[0]; + return REGCHAR; + } + +<INITIAL>[^@\n]+ { + yylval.lexeme = strdup(yytext); + return TEXT; + } + +<INITIAL>\n { + lineno++; + return '\n'; + } + +<INITIAL>@{WS}\* { + BEGIN(SPECIAL); + return '*'; + } + +<INITIAL>@ { + BEGIN(SPECIAL); + } + +<INITIAL>^@#.*\n { + /* eat whole line comment */ + lineno++; + } + +<INITIAL>@#.* { + /* comment to end of line */ + } + +%% + +void help(void) +{ + const char *text = +"\n" +"txr version %s\n" +"\n" +"copyright 2009, Kaz Kylheku <kkylheku@gmail.com>\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 <kkylheku@gmail.com> + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <limits.h> +#include <errno.h> +#include <dirent.h> +#include <setjmp.h> +#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 <lexeme> TEXT IDENT ALL SOME NONE MAYBE AND OR END COLLECT UNTIL COLL +%token <lexeme> OUTPUT REPEAT REP SINGLE FIRST LAST EMPTY +%token <num> NUMBER +%token <chr> REGCHAR + +%type <obj> spec clauses clause all_clause some_clause none_clause maybe_clause +%type <obj> collect_clause clause_parts additional_parts output_clause +%type <obj> line elems_opt elems elem var var_op list exprs expr +%type <obj> out_clauses out_clauses_opt out_clause +%type <obj> repeat_clause repeat_parts_opt o_line +%type <obj> o_elems_opt o_elems_opt2 o_elems o_elem rep_elem rep_parts_opt +%type <obj> regex regexpr regbranch +%type <obj> regterm regclass regclassterm regrange +%type <chr> 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 <sym> <pat>) ...) + and it must be transformed into + (<sym-substituted> <pat> ...) */ + 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; +} @@ -0,0 +1,368 @@ +/* Copyright 2009 + * Kaz Kylheku <kkylheku@gmail.com> + * 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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <assert.h> +#include <setjmp.h> +#include <dirent.h> +#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); + } + } +} @@ -0,0 +1,36 @@ +/* Copyright 2009 + * Kaz Kylheku <kkylheku@gmail.com> + * 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); @@ -0,0 +1,1609 @@ +/* Copyright 2009 + * Kaz Kylheku <kkylheku@gmail.com> + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <dirent.h> +#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, "#<function: f%d>", (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, "#<stream: "); + { + obj_t *iter; + /* skip stream pushback items to find label */ + for (iter = obj->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; +} @@ -0,0 +1,331 @@ +/* Copyright 2009 + * Kaz Kylheku <kkylheku@gmail.com> + * 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 <kkylheku@gmail.com> + * 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 <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <dirent.h> +#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 <kkylheku@gmail.com> + * 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 <limits.h> + +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 <kkylheku@gmail.com> 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 <kkylheku@gmail.com> 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 <kkylheku@gmail.com> 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 <kkylheku@gmail.com> 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) @@ -0,0 +1,1741 @@ +.\"Copyright (C) 2009, Kaz Kylheku <kkylheku@gmail.com>. +.\"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<hex> +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 @\\<octal> +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) + <subquery1> + . + . + . + @(and) + <subquery2> + . + . + . + @(and) + <subquery3> + . + . + . + @(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 <name>) 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 <name>) + +Immediately terminate the enclosing query block called <name>, 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 <name>) + +Immediately terminate the enclosing query block called <name>, 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 <kkylheku@gmail.com> + * 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 <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <setjmp.h> +#include <dirent.h> +#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 <kkylheku@gmail.com> + * 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); \ + } |