]> git.pld-linux.org Git - packages/apparmor-parser.git/commitdiff
- rel 3; make profiles reloading work even if there is no free space on /tmp (from... auto/th/apparmor-parser-2_6_1-3
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Sat, 27 Aug 2011 18:13:25 +0000 (18:13 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    apparmor-parser-bzr.patch -> 1.4
    apparmor-parser.spec -> 1.37

apparmor-parser-bzr.patch
apparmor-parser.spec

index e3240af91f5eebba5fc31ac7a12bce6d588d901a..eeb43149980398f373bd0d63d55cd4447e575f5d 100644 (file)
-=== added file '.bzrignore'
---- .bzrignore 1970-01-01 00:00:00 +0000
-+++ .bzrignore 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,165 @@
-+parser/po/*.mo
-+parser/af_names.h
-+parser/cap_names.h
-+parser/tst_misc
-+parser/tst_regex
-+parser/tst_symtab
-+parser/tst_variable
-+parser/parser_lex.c
-+parser/parser_version.h
-+parser/parser_yacc.c
-+parser/parser_yacc.h
-+parser/pod2htm*.tmp
-+parser/*.7
-+parser/*.5
-+parser/*.8
-+parser/*.7.html
-+parser/*.5.html
-+parser/*.8.html
-+parser/common
-+parser/apparmor_parser
-+parser/libapparmor_re/regexp.cc
-+parser/techdoc.aux
-+parser/techdoc.log
-+parser/techdoc.pdf
-+parser/techdoc.toc
-+libraries/libapparmor/Makefile
-+libraries/libapparmor/Makefile.in
-+libraries/libapparmor/aclocal.m4
-+libraries/libapparmor/audit.log
-+libraries/libapparmor/autom4te.cache
-+libraries/libapparmor/compile
-+libraries/libapparmor/config.guess
-+libraries/libapparmor/config.log
-+libraries/libapparmor/config.status
-+libraries/libapparmor/config.sub
-+libraries/libapparmor/configure
-+libraries/libapparmor/depcomp
-+libraries/libapparmor/install-sh
-+libraries/libapparmor/libtool
-+libraries/libapparmor/ltmain.sh
-+libraries/libapparmor/missing
-+libraries/libapparmor/ylwrap
-+libraries/libapparmor/doc/Makefile
-+libraries/libapparmor/doc/Makefile.in
-+libraries/libapparmor/doc/aa_change_hat.2
-+libraries/libapparmor/src/.deps
-+libraries/libapparmor/src/.libs
-+libraries/libapparmor/src/Makefile
-+libraries/libapparmor/src/Makefile.in
-+libraries/libapparmor/src/af_protos.h
-+libraries/libapparmor/src/change_hat.lo
-+libraries/libapparmor/src/grammar.lo
-+libraries/libapparmor/src/libaalogparse.lo
-+libraries/libapparmor/src/libimmunix_warning.lo
-+libraries/libapparmor/src/scanner.lo
-+libraries/libapparmor/src/libapparmor.la
-+libraries/libapparmor/src/libimmunix.la
-+libraries/libapparmor/src/grammar.c
-+libraries/libapparmor/src/grammar.h
-+libraries/libapparmor/src/scanner.c
-+libraries/libapparmor/src/scanner.h
-+libraries/libapparmor/src/tst_aalogmisc
-+libraries/libapparmor/swig/Makefile
-+libraries/libapparmor/swig/Makefile.in
-+libraries/libapparmor/swig/perl/LibAppArmor.bs
-+libraries/libapparmor/swig/perl/LibAppArmor.pm
-+libraries/libapparmor/swig/perl/Makefile
-+libraries/libapparmor/swig/perl/Makefile.PL
-+libraries/libapparmor/swig/perl/Makefile.in
-+libraries/libapparmor/swig/perl/Makefile.perl
-+libraries/libapparmor/swig/perl/blib
-+libraries/libapparmor/swig/perl/libapparmor_wrap.c
-+libraries/libapparmor/swig/perl/pm_to_blib
-+libraries/libapparmor/swig/python/Makefile
-+libraries/libapparmor/swig/python/Makefile.in
-+libraries/libapparmor/swig/python/setup.py
-+libraries/libapparmor/swig/ruby/Makefile
-+libraries/libapparmor/swig/ruby/Makefile.in
-+libraries/libapparmor/testsuite/.deps
-+libraries/libapparmor/testsuite/.libs
-+libraries/libapparmor/testsuite/Makefile
-+libraries/libapparmor/testsuite/Makefile.in
-+libraries/libapparmor/testsuite/libaalogparse.log
-+libraries/libapparmor/testsuite/libaalogparse.sum
-+libraries/libapparmor/testsuite/site.exp
-+libraries/libapparmor/testsuite/test_multi.multi
-+libraries/libapparmor/testsuite/config/Makefile
-+libraries/libapparmor/testsuite/config/Makefile.in
-+libraries/libapparmor/testsuite/lib/Makefile
-+libraries/libapparmor/testsuite/lib/Makefile.in
-+libraries/libapparmor/testsuite/libaalogparse.test/Makefile
-+libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
-+libraries/libapparmor/testsuite/test_multi/out
-+changehat/mod_apparmor/.libs
-+changehat/mod_apparmor/common
-+changehat/pam_apparmor/common
-+changehat/tomcat_apparmor/common
-+utils/common
-+utils/*.8
-+utils/*.8.html
-+utils/*.5
-+utils/*.5.html
-+utils/*.tmp
-+utils/po/*.mo
-+tests/regression/apparmor/access
-+tests/regression/apparmor/changehat
-+tests/regression/apparmor/changehat_fail
-+tests/regression/apparmor/changehat_fork
-+tests/regression/apparmor/changehat_misc
-+tests/regression/apparmor/changehat_misc2
-+tests/regression/apparmor/changehat_pthread
-+tests/regression/apparmor/changehat_twice
-+tests/regression/apparmor/changehat_wrapper
-+tests/regression/apparmor/changeprofile
-+tests/regression/apparmor/chdir
-+tests/regression/apparmor/chgrp
-+tests/regression/apparmor/chmod
-+tests/regression/apparmor/chown
-+tests/regression/apparmor/clone
-+tests/regression/apparmor/deleted
-+tests/regression/apparmor/env_check
-+tests/regression/apparmor/environ
-+tests/regression/apparmor/exec
-+tests/regression/apparmor/exec_qual
-+tests/regression/apparmor/exec_qual2
-+tests/regression/apparmor/fchdir
-+tests/regression/apparmor/fchgrp
-+tests/regression/apparmor/fchmod
-+tests/regression/apparmor/fchown
-+tests/regression/apparmor/fork
-+tests/regression/apparmor/link
-+tests/regression/apparmor/link_subset
-+tests/regression/apparmor/mkdir
-+tests/regression/apparmor/mmap
-+tests/regression/apparmor/mount
-+tests/regression/apparmor/named_pipe
-+tests/regression/apparmor/net_raw
-+tests/regression/apparmor/open
-+tests/regression/apparmor/openat
-+tests/regression/apparmor/pipe
-+tests/regression/apparmor/ptrace
-+tests/regression/apparmor/ptrace_helper
-+tests/regression/apparmor/pwrite
-+tests/regression/apparmor/readdir
-+tests/regression/apparmor/rename
-+tests/regression/apparmor/rw
-+tests/regression/apparmor/swap
-+tests/regression/apparmor/symlink
-+tests/regression/apparmor/syscall_chroot
-+tests/regression/apparmor/syscall_mknod
-+tests/regression/apparmor/syscall_mlockall
-+tests/regression/apparmor/syscall_ptrace
-+tests/regression/apparmor/syscall_reboot
-+tests/regression/apparmor/syscall_setdomainname
-+tests/regression/apparmor/syscall_sethostname
-+tests/regression/apparmor/syscall_setpriority
-+tests/regression/apparmor/syscall_setscheduler
-+tests/regression/apparmor/syscall_sysctl
-+tests/regression/apparmor/sysctl_proc
-+tests/regression/apparmor/tcp
-+tests/regression/apparmor/unix_fd_client
-+tests/regression/apparmor/unix_fd_server
-+tests/regression/apparmor/unlink
-+tests/regression/apparmor/xattrs
-+tests/regression/apparmor/coredump
-
-=== added file 'README'
---- README     1970-01-01 00:00:00 +0000
-+++ README     2010-08-03 17:27:13 +0000
-@@ -0,0 +1,155 @@
-+------------
-+Introduction
-+------------
-+AppArmor protects systems from insecure or untrusted processes by
-+running them in restricted confinement, while still allowing processes
-+to share files, exercise privilege and communicate with other processes.
-+AppArmor is a Mandatory Access Control (MAC) mechanism which uses the
-+Linux Security Module (LSM) framework. The confinement's restrictions
-+are mandatory and are not bound to identity, group membership, or object
-+ownership. The protections provided are in addition to the kernel's
-+regular access control mechanisms (including DAC) and can be used to
-+restrict the superuser.
-+
-+The AppArmor kernel module and accompanying user-space tools are
-+available under the GPL license (the exception is the libapparmor
-+library, available under the LGPL license, which allows change_hat(2)
-+and change_profile(2) to be used by non-GPL binaries).
-+
-+For more information, you can read the techdoc.pdf (available after
-+building the parser) and http://apparmor.wiki.kernel.org.
-+
-+
-+-------------
-+Source Layout
-+-------------
-+
-+AppArmor consists of several different parts:
-+
-+changehat/    source for using changehat with Apache, PAM and Tomcat
-+common/               common makefile rules
-+desktop/      empty
-+kernel-patches/       patches for various kernel versions
-+libraries/    libapparmor source and language bindings
-+parser/               source for parser/loader and corresponding documentation
-+profiles/     configuration files, reference profiles and abstractions
-+tests/                regression and stress testsuites
-+utils/                high-level utilities for working with AppArmor
-+
-+
-+------------------------------------------
-+Building and Installing AppArmor Userspace
-+------------------------------------------
-+
-+To build and install AppArmor userspace on your system, build and install in
-+the following order.
-+
-+
-+libapparmor:
-+$ cd ./libraries/libapparmor
-+$ sh ./autogen.sh
-+$ sh ./configure --prefix=/usr --with-perl
-+$ make
-+$ make check
-+
-+
-+Utilities:
-+$ cd utils
-+$ make
-+$ make install
-+
-+
-+parser:
-+$ cd parser
-+$ make
-+$ make tests  # not strictly necessary as they are run during the
-+              # build by default
-+$ make install
-+
-+
-+Apache mod_apparmor:
-+$ cd changehat/mod_apparmor
-+$ LIBS="-lapparmor" make
-+$ make install
-+
-+
-+PAM AppArmor:
-+$ cd changehat/pam_apparmor
-+$ LIBS="-lapparmor -lpam" make
-+$ make install
-+
-+
-+Profiles:
-+$ cd profiles
-+$ make
-+$ make install
-+
-+
-+
-+-------------------
-+AppArmor Testsuites
-+-------------------
-+
-+A number of testsuites are in the AppArmor sources. Most have documentation on
-+usage and how to update and add tests. Below is a quick overview of their
-+location and how to run them.
-+
-+
-+Regression tests
-+----------------
-+For details on structure and adding tests, see
-+tests/regression/apparmor/README.
-+
-+To run:
-+$ cd tests/regression/apparmor (requires root)
-+$ make
-+$ sudo make tests
-+$ sudo bash open.sh -r         # runs and saves the last testcase from open.sh
-+
-+
-+Parser tests
-+------------
-+For details on structure and adding tests, see parser/tst/README.
-+
-+To run:
-+$ cd parser/tst
-+$ make
-+$ make tests
-+
-+
-+Libapparmor
-+-----------
-+For details on structure and adding tests, see libraries/libapparmor/README.
-+$ cd libraries/libapparmor
-+$ make check
-+
-+
-+Stress Tests
-+------------
-+To run AppArmor stress tests:
-+$ make all
-+
-+Use these:
-+$ ./change_hat
-+$ ./child
-+$ ./kill.sh
-+$ ./open
-+$ ./s.sh
-+
-+Or run all at once:
-+$ ./stress.sh
-+
-+Please note that the above will stress the system so much it may end up
-+invoking the OOM killer.
-+
-+To run parser stress tests (requires /usr/bin/ruby):
-+$ ./stress.sh
-+
-+(see stress.sh -h for options)
-+
-+-----------------------------------------------
-+Building and Installing AppArmor Kernel Patches
-+-----------------------------------------------
-+
-+TODO
-+
-
-=== modified file 'common/Make.rules'
---- common/Make.rules  2010-03-11 07:07:29 +0000
-+++ common/Make.rules  2010-08-03 17:27:13 +0000
-@@ -48,7 +48,7 @@
-                   echo "/tmp/${NAME}"  ; \
-                 fi ;)
- endif
--RPMHOSTVENDOR=$(shell rpm --eval "%{_host_vendor}")
-+RPMHOSTVENDOR=$(shell which rpm && rpm --eval "%{_host_vendor}")
- ifndef DISTRO
- DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
-                 echo slackware ; \
-@@ -92,30 +92,16 @@
- ifndef SPECFILE
- SPECFILE        = $(NAME).spec
- endif
--RELEASE = $(shell rpm -q --specfile --define "_sourcedir ." ${RPMARG} --qf "%{RELEASE}" ${SPECFILE})
-+RELEASE               = $(shell lsb_release -is) $(shell lsb_release -rs)
- RELEASE_DIR   = $(NAME)-$(VERSION)
- TARBALL               = $(NAME)-$(VERSION)-${REPO_VERSION}.tar.gz
--TAR           = /bin/tar czvp -h --exclude .svn --exclude CVS --exclude .cvsignore --exclude ${TARBALL} --exclude ${RELEASE_DIR}/${RELEASE_DIR}  $(shell test -f ${NAME}.exclude && echo "-X ${NAME}.exclude")
-+TAR           = /bin/tar czvp -h --exclude .svn --exclude .bzr --exclude .bzrignore --exclude ${TARBALL} --exclude ${RELEASE_DIR}/${RELEASE_DIR}  $(shell test -f ${NAME}.exclude && echo "-X ${NAME}.exclude")
- LDCONFIG      = /sbin/ldconfig
--CVSPKG_VERSION=$(shell rpm -q --specfile --define "_sourcedir ." ${RPMARG} ${SPECFILE} | head -1 | tr "." "_")
--
- RPMSUBDIRS=SOURCES SPECS BUILD BUILDROOT SRPMS RPMS/i386 RPMS/i586 \
-         RPMS/i686 RPMS/athlon RPMS/noarch RPMS/x86_64
- BUILDRPMSUBDIRS=$(foreach subdir, $(RPMSUBDIRS), $(BUILDDIR:/=)/$(subdir))
--.PHONY: cvs_tag
--cvs_tag:
--      cvs tag IMMUNIX-${CVSPKG_VERSION}
--
--.PHONY: checkin
--checkin:
--      if cvs -q up -d | grep -q "^\?" ; then echo "Hey! You have" \
--              "files in the directory you have not added into cvs."; exit 1; \
--      fi
--      cvs ci
--      make cvs_tag
--
- ifdef EXTERNAL_PACKAGE
- .PHONY: rpm
- rpm: clean $(BUILDRPMSUBDIRS)
-
-=== modified file 'libraries/libapparmor/src/aalogparse.h'
---- libraries/libapparmor/src/aalogparse.h     2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/aalogparse.h     2010-08-03 17:27:13 +0000
-@@ -129,6 +129,7 @@
-       unsigned long fsuid;            /* fsuid of task - if logged */
-       unsigned long ouid;             /* ouid of task - if logged */
-       char *profile;                  /* The name of the profile */
-+      char *comm;                     /* Command that triggered msg */
-       char *name;
-       char *name2;
-       char *namespace;
-
-=== modified file 'libraries/libapparmor/src/change_hat.c'
---- libraries/libapparmor/src/change_hat.c     2010-02-11 23:38:24 +0000
-+++ libraries/libapparmor/src/change_hat.c     2010-08-03 17:27:13 +0000
-@@ -194,7 +194,7 @@
-       /* setup command string which is of the form
-        * changehat <token>^hat1\0hat2\0hat3\0..\0
-        */
--      sprintf(buf, "%s %016x^", cmd, token);
-+      sprintf(buf, "%s %016lx^", cmd, token);
-       pos = buf + strlen(buf);
-       if (subprofiles) {
-               for (hats = subprofiles; *hats; hats++) {
-
-=== modified file 'libraries/libapparmor/src/grammar.y'
---- libraries/libapparmor/src/grammar.y        2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/grammar.y        2010-08-03 17:27:13 +0000
-@@ -1,6 +1,7 @@
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010, Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -96,6 +97,13 @@
- %token TOK_TYPE_HINT
- %token TOK_TYPE_STATUS
- %token TOK_TYPE_ERROR
-+%token TOK_TYPE_AA_REJECT
-+%token TOK_TYPE_AA_AUDIT
-+%token TOK_TYPE_AA_COMPLAIN
-+%token TOK_TYPE_AA_HINT
-+%token TOK_TYPE_AA_STATUS
-+%token TOK_TYPE_AA_ERROR
-+%token TOK_TYPE_LSM_AVC
- %token TOK_OLD_TYPE_APPARMOR
- %token TOK_OLD_APPARMOR_REJECT
- %token TOK_OLD_APPARMOR_PERMIT
-@@ -123,6 +131,7 @@
- %token TOK_OLD_FORK
- %token TOK_OLD_CHILD
-+%token TOK_KEY_APPARMOR
- %token TOK_KEY_TYPE
- %token TOK_KEY_MSG
- %token TOK_KEY_OPERATION
-@@ -146,6 +155,7 @@
- %token TOK_KEY_ERROR
- %token TOK_KEY_FSUID
- %token TOK_KEY_OUID
-+%token TOK_KEY_COMM
- %token TOK_SYSLOG_KERNEL
-@@ -168,13 +178,14 @@
-       ;
- new_syntax:
--        TOK_TYPE_REJECT audit_msg key_list { ret_record->event = AA_RECORD_DENIED; }
--      | TOK_TYPE_AUDIT audit_msg key_list { ret_record->event = AA_RECORD_AUDIT; }
--      | TOK_TYPE_COMPLAIN audit_msg key_list { ret_record->event = AA_RECORD_ALLOWED; }
--      | TOK_TYPE_HINT audit_msg key_list { ret_record->event = AA_RECORD_HINT; }
--      | TOK_TYPE_STATUS audit_msg key_list { ret_record->event = AA_RECORD_STATUS; }
--      | TOK_TYPE_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
-+        TOK_TYPE_AA_REJECT audit_msg key_list { ret_record->event = AA_RECORD_DENIED; }
-+      | TOK_TYPE_AA_AUDIT audit_msg key_list { ret_record->event = AA_RECORD_AUDIT; }
-+      | TOK_TYPE_AA_COMPLAIN audit_msg key_list { ret_record->event = AA_RECORD_ALLOWED; }
-+      | TOK_TYPE_AA_HINT audit_msg key_list { ret_record->event = AA_RECORD_HINT; }
-+      | TOK_TYPE_AA_STATUS audit_msg key_list { ret_record->event = AA_RECORD_STATUS; }
-+      | TOK_TYPE_AA_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
-       | TOK_TYPE_UNKNOWN audit_msg key_list { ret_record->event = lookup_aa_event($1); }
-+      | TOK_TYPE_LSM_AVC audit_msg key_list
-       ;
- other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
-@@ -366,7 +377,8 @@
- audit_id: TOK_AUDIT TOK_OPEN_PAREN TOK_AUDIT_DIGITS TOK_PERIOD TOK_AUDIT_DIGITS TOK_COLON TOK_AUDIT_DIGITS TOK_CLOSE_PAREN TOK_COLON
-       {
--              asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7);
-+              if (!asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7))
-+                      yyerror(scanner, YY_("Out of memory"));
-               ret_record->epoch = atol($3);
-               ret_record->audit_sub_id = atoi($7);
-               free($3);
-@@ -420,6 +432,18 @@
-       { ret_record->fsuid = $3;}
-       | TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
-       { ret_record->ouid = $3;}
-+      | TOK_KEY_COMM TOK_EQUALS TOK_QUOTED_STRING
-+      { ret_record->comm = $3;}
-+      | TOK_KEY_APPARMOR TOK_EQUALS apparmor_event
-+      ;
-+
-+apparmor_event:
-+        TOK_TYPE_REJECT       { ret_record->event = AA_RECORD_DENIED; }
-+      | TOK_TYPE_AUDIT        { ret_record->event = AA_RECORD_AUDIT; }
-+      | TOK_TYPE_COMPLAIN     { ret_record->event = AA_RECORD_ALLOWED; }
-+      | TOK_TYPE_HINT         { ret_record->event = AA_RECORD_HINT; }
-+      | TOK_TYPE_STATUS       { ret_record->event = AA_RECORD_STATUS; }
-+      | TOK_TYPE_ERROR        { ret_record->event = AA_RECORD_ERROR; }
-       ;
- key_pid: TOK_KEY_PID TOK_EQUALS TOK_DIGITS { ret_record->pid = $3; }
-
-=== modified file 'libraries/libapparmor/src/libaalogparse.c'
---- libraries/libapparmor/src/libaalogparse.c  2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/libaalogparse.c  2010-08-03 17:27:13 +0000
-@@ -56,6 +56,8 @@
-                       free(record->denied_mask);
-               if (record->profile != NULL)
-                       free(record->profile);
-+              if (record->comm != NULL)
-+                      free(record->comm);
-               if (record->name != NULL)
-                       free(record->name);
-               if (record->name2 != NULL)
-@@ -151,7 +153,8 @@
-       if (current->protocol_name) {
-               ret = strdup(current->protocol_name);
-       } else {
--              asprintf(&ret, "unknown(%u)", proto);
-+              if (!asprintf(&ret, "unknown(%u)", proto))
-+                      ret = NULL;
-       }
-       return ret;
-
-=== modified file 'libraries/libapparmor/src/scanner.l'
---- libraries/libapparmor/src/scanner.l        2010-02-10 23:13:55 +0000
-+++ libraries/libapparmor/src/scanner.l        2010-08-03 17:27:13 +0000
-@@ -1,6 +1,7 @@
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010, Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -30,6 +31,8 @@
- #include <assert.h>
-+#define YY_NO_INPUT
-+
- unsigned int string_buf_alloc = 0;
- unsigned int string_buf_len = 0;
- char *string_buf = NULL;
-@@ -84,12 +87,19 @@
- modes         ({mode_chars}+)|({mode_chars}+::{mode_chars}*)|(::{mode_chars}*)
- /* New message types */
--reject_type           "APPARMOR_DENIED"
--audit_type            "APPARMOR_AUDIT"
--complain_type         "APPARMOR_ALLOWED"
--hint_type             "APPARMOR_HINT"
--status_type           "APPARMOR_STATUS"
--error_type            "APPARMOR_ERROR"
-+aa_reject_type                "APPARMOR_DENIED"
-+aa_audit_type         "APPARMOR_AUDIT"
-+aa_complain_type      "APPARMOR_ALLOWED"
-+aa_hint_type          "APPARMOR_HINT"
-+aa_status_type                "APPARMOR_STATUS"
-+aa_error_type         "APPARMOR_ERROR"
-+reject_type           "\"DENIED\""
-+audit_type            "\"AUDIT\""
-+complain_type         "\"ALLOWED\""
-+hint_type             "\"HINT\""
-+status_type           "\"STATUS\""
-+error_type            "\"ERROR\""
-+lsm_avc_type          "AVC"
- unknown_type          UNKNOWN\[{digits}+\]
- other_audit_type      [[:alnum:]\[\]_-]+
-@@ -125,6 +135,7 @@
- /* Key tokens */
-+key_apparmor          "apparmor"
- key_type              "type"
- key_msg                       "msg"
- key_operation         "operation"
-@@ -147,6 +158,7 @@
- key_error             "error"
- key_fsuid             "fsuid"
- key_ouid              "ouid"
-+key_comm              "comm"
- audit                 "audit"
- /* syslog tokens */
-@@ -240,6 +252,13 @@
-       {hint_type}     { BEGIN(INITIAL); return(TOK_TYPE_HINT); }
-       {status_type}   { BEGIN(INITIAL); return(TOK_TYPE_STATUS); }
-       {error_type}    { BEGIN(INITIAL); return(TOK_TYPE_ERROR); }
-+      {aa_reject_type}        { BEGIN(INITIAL); return(TOK_TYPE_AA_REJECT); }
-+      {aa_audit_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_AUDIT); }
-+      {aa_complain_type}      { BEGIN(INITIAL); return(TOK_TYPE_AA_COMPLAIN); }
-+      {aa_hint_type}  { BEGIN(INITIAL); return(TOK_TYPE_AA_HINT); }
-+      {aa_status_type}        { BEGIN(INITIAL); return(TOK_TYPE_AA_STATUS); }
-+      {aa_error_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_ERROR); }
-+      {lsm_avc_type}  { BEGIN(INITIAL); return(TOK_TYPE_LSM_AVC); }
-       {unknown_type}  { char *yptr = yytext;
-                         while (*yptr && *yptr != '[')
-                               yptr++;
-@@ -300,6 +319,7 @@
-       {key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
- }
-+{key_apparmor}                { BEGIN(audit_types); return(TOK_KEY_APPARMOR); }
- {key_type}            { BEGIN(audit_types); return(TOK_KEY_TYPE); }
- {key_msg}             { return(TOK_KEY_MSG); }
- {key_operation}               { return(TOK_KEY_OPERATION); }
-@@ -321,6 +341,7 @@
- {key_error}           { return(TOK_KEY_ERROR); }
- {key_fsuid}           { return(TOK_KEY_FSUID); }
- {key_ouid}            { return(TOK_KEY_OUID); }
-+{key_comm}            { return(TOK_KEY_COMM); }
- {syslog_kernel}               { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
- {syslog_month}                { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
-
-=== modified file 'libraries/libapparmor/swig/perl/Makefile.am'
---- libraries/libapparmor/swig/perl/Makefile.am        2009-05-12 21:56:56 +0000
-+++ libraries/libapparmor/swig/perl/Makefile.am        2010-05-31 18:58:40 +0000
-@@ -1,7 +1,8 @@
- EXTRA_DIST =Makefile.PL libapparmor_wrap.c LibAppArmor.pm examples/*.pl
-+
-+if HAVE_PERL
- noinst_DATA =LibAppArmor.so
--if HAVE_PERL
- libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
-       $(SWIG) -perl -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
-@@ -27,4 +28,4 @@
- #rm -f Makefile.perl Makefile.perl.old
-       rm -f *.so # *.o
--endif
-\ No newline at end of file
-+endif
-
-=== modified file 'libraries/libapparmor/testsuite/test_multi.c'
---- libraries/libapparmor/testsuite/test_multi.c       2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/testsuite/test_multi.c       2010-08-03 17:27:13 +0000
-@@ -129,6 +129,10 @@
-               {
-                       printf("Name: %s\n", record->name);
-               }
-+              if (record->comm != NULL)
-+              {
-+                      printf("Command: %s\n", record->comm);
-+              }
-               if (record->name2 != NULL)
-               {
-                       printf("Name2: %s\n", record->name2);
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_01.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_01.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_01.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279948288.415:39): apparmor="DENIED" operation="open" parent=12332 profile="/usr/sbin/cupsd" name="/home/user/.ssh/" pid=12333 comm="ls" requested_mask="r" denied_mask="r" fsuid=0 ouid=1000
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_01.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_01.out        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_01.out        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_audit_01.in
-+Event type: AA_RECORD_DENIED
-+Audit ID: 1279948288.415:39
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 0
-+ouid: 1000
-+Profile: /usr/sbin/cupsd
-+Name: /home/user/.ssh/
-+Command: ls
-+Parent: 12332
-+PID: 12333
-+Epoch: 1279948288
-+Audit subid: 39
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_02.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_02.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_02.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279948227.175:27): apparmor="STATUS" operation="profile_replace" name="/sbin/dhclient3" pid=12291 comm="apparmor_parser"
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_02.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_02.out        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_02.out        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,10 @@
-+START
-+File: test_multi/avc_audit_02.in
-+Event type: AA_RECORD_STATUS
-+Audit ID: 1279948227.175:27
-+Operation: profile_replace
-+Name: /sbin/dhclient3
-+Command: apparmor_parser
-+PID: 12291
-+Epoch: 1279948227
-+Audit subid: 27
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_03.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_03.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_03.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279968846.035:77): apparmor="ALLOWED" operation="open" parent=7014 profile="/tmp/cat" name="/etc/passwd" pid=21645 comm="cat" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_03.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_03.out        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_03.out        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_audit_03.in
-+Event type: AA_RECORD_ALLOWED
-+Audit ID: 1279968846.035:77
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 1000
-+ouid: 0
-+Profile: /tmp/cat
-+Name: /etc/passwd
-+Command: cat
-+Parent: 7014
-+PID: 21645
-+Epoch: 1279968846
-+Audit subid: 77
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:25:33 spriggan kernel: [42416.178567] type=1400 audit(1279967133.365:54): apparmor="DENIED" operation="open" parent=19650 profile="/usr/sbin/cupsd" name="/boot/" pid=19651 comm="ls" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out       1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out       2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_syslog_01.in
-+Event type: AA_RECORD_DENIED
-+Audit ID: 1279967133.365:54
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 0
-+ouid: 0
-+Profile: /usr/sbin/cupsd
-+Name: /boot/
-+Command: ls
-+Parent: 19650
-+PID: 19651
-+Epoch: 1279967133
-+Audit subid: 54
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:24:41 spriggan kernel: [42364.269117] type=1400 audit(1279967081.455:42): apparmor="STATUS" operation="profile_replace" name="/sbin/dhclient3" pid=19610 comm="apparmor_parser"
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out       1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out       2010-08-03 17:27:13 +0000
-@@ -0,0 +1,10 @@
-+START
-+File: test_multi/avc_syslog_02.in
-+Event type: AA_RECORD_STATUS
-+Audit ID: 1279967081.455:42
-+Operation: profile_replace
-+Name: /sbin/dhclient3
-+Command: apparmor_parser
-+PID: 19610
-+Epoch: 1279967081
-+Audit subid: 42
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in        1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in        2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:54:06 spriggan kernel: [44128.842691] type=1400 audit(1279968846.035:77): apparmor="ALLOWED" operation="open" parent=7014 profile="/tmp/cat" name="/etc/passwd" pid=21645 comm="cat" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out       1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out       2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_syslog_03.in
-+Event type: AA_RECORD_ALLOWED
-+Audit ID: 1279968846.035:77
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 1000
-+ouid: 0
-+Profile: /tmp/cat
-+Name: /etc/passwd
-+Command: cat
-+Parent: 7014
-+PID: 21645
-+Epoch: 1279968846
-+Audit subid: 77
-
-=== modified file 'parser/COPYING.GPL'
---- parser/COPYING.GPL 2006-04-11 21:52:54 +0000
-+++ parser/COPYING.GPL 2010-08-03 17:27:13 +0000
-@@ -1,6 +1,5 @@
- This license applies to all source files within the SubDomain parser
--package, with the exception of md5.c and the files in the pcre/
--subdirectory, as they are covered under their own respective licenses.
-+package.
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
-=== modified file 'parser/Makefile'
---- parser/Makefile    2009-11-11 18:58:57 +0000
-+++ parser/Makefile    2010-08-03 17:27:13 +0000
-@@ -82,9 +82,6 @@
- AAREDIR= libapparmor_re
- AAREOBJECTS = ${AAREDIR}/libapparmor_re.a
--PCREDIR= pcre
--PCREOBJECTS = ${PCREDIR}/pcre.o
--
- LEX_C_FILES   = parser_lex.c
- YACC_C_FILES  = parser_yacc.c parser_yacc.h
-@@ -94,7 +91,7 @@
- TEST_OBJECTS = $(filter-out parser_lex.o, \
-              $(filter-out parser_yacc.o, \
--             $(filter-out parser_main.o, ${OBJECTS} ${PCREOBJECTS})))
-+             $(filter-out parser_main.o, ${OBJECTS})))
- ifdef V
-   VERBOSE = 1
-@@ -125,14 +122,25 @@
- techdoc.txt: techdoc/index.html
-       w3m -dump $< > $@
--all:  $(TOOLS) $(MANPAGES) ${HTMLMANPAGES} techdoc.pdf
-+# targets arranged this way so that people who don't want full docs can
-+# pick specific targets they want.
-+main:         $(TOOLS)
-       $(Q)make -C po all
--      $(Q)make -s tests
--
--apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
-+
-+manpages:     $(MANPAGES)
-+
-+htmlmanpages: $(HTMLMANPAGES)
-+
-+pdf:  techdoc.pdf
-+
-+docs: manpages htmlmanpages pdf
-+
-+all:  main docs tests
-+
-+apparmor_parser: $(OBJECTS) $(AAREOBJECTS)
-       rm -f ./libstdc++.a
-       ln -s `g++ -print-file-name=libstdc++.a`
--      g++ $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(PCREOBJECTS) $(LIBS) \
-+      g++ $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
-             ${LEXLIB}  $(AAREOBJECTS) -static-libgcc -L.
- parser_yacc.c parser_yacc.h: parser_yacc.y parser.h
-@@ -191,7 +199,7 @@
- af_names.h: /usr/include/bits/socket.h
-       LC_ALL=C sed -n -e '/$(__FILTER)/d' -e "s/^\#define[ \\t]\\+PF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/#ifndef AF_\\1\\n#  define AF_\\1 \\2\\n#endif\\nAA_GEN_NET_ENT(\"\\L\\1\", \\UAF_\\1)\\n/p" $< > $@
-       LC_ALL=C sed -n -e "s/^\#define[ \\t]\\+PF_MAX[ \\t]\\+\\([0-9]\\+\\)[ \\t]\\+.*/#define AA_AF_MAX \\1\n/p" $< >> $@
--      cat $@
-+      # cat $@
- cap_names.h: /usr/include/linux/capability.h
-       LC_ALL=C sed -n -e "/CAP_EMPTY_SET/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9xa-f]\\+\\)\\(.*\\)\$$/\{\"\\L\\1\", \\UCAP_\\1\},/p" $< > $@
-@@ -205,8 +213,8 @@
- tst_misc: parser_misc.c parser.h parser_yacc.h af_names.h cap_names.h
-       $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(BUILD_OUTPUT)
--tst_regex: parser_regex.c parser.h parser_yacc.h $(PCREOBJECTS)
--      $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(PCREOBJECTS) $(BUILD_OUTPUT)
-+tst_regex: parser_regex.c parser.h parser_yacc.h
-+      $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(BUILD_OUTPUT)
- .SILENT: check
- .PHONY: check
-@@ -214,7 +222,7 @@
- .SILENT: tests
- tests: ${TESTS}
--      for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done
-+      sh -e -c 'for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done'
-       $(Q)make -s -C tst tests
- .SILENT: check
-@@ -226,11 +234,6 @@
- $(AAREOBJECTS):
-       make -C $(AAREDIR)
--.SILENT: $(PCREOBJECTS)
--.PHONY: $(PCREOBJECTS)
--$(PCREOBJECTS):
--      make -C $(PCREDIR) "CFLAGS=$(EXTRA_CFLAGS)"
--
- .PHONY: install-rhel4
- install-rhel4: install-redhat
-@@ -293,7 +296,6 @@
-       rm -f af_names.h
-       rm -f cap_names.h
-       -rm -rf techdoc.{aux,log,pdf,toc,txt} techdoc/
--      make -s -C $(PCREDIR) clean
-       make -s -C $(AAREDIR) clean
-       make -s -C po clean
-
-=== modified file 'parser/README'
---- parser/README      2007-04-25 20:50:21 +0000
-+++ parser/README      2010-08-03 17:27:13 +0000
-@@ -11,11 +11,6 @@
- where we will attempt to conform to the RFP vulnerability disclosure
- protocol: http://www.wiretrip.net/rfp/policy.html
--The parser uses the PCRE (Perl Compatible Regular Expression) engine,
--which was written by Philip Hazel and is copyright by the University
--of Cambridge, England. For more information on the PCRE engine, see
--<ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/>
--
- Thanks.
- -- The AppArmor development team
-
-=== modified file 'parser/apparmor_parser.pod'
---- parser/apparmor_parser.pod 2010-01-07 18:03:49 +0000
-+++ parser/apparmor_parser.pod 2010-08-03 17:27:13 +0000
-@@ -80,6 +80,10 @@
- Writes a binary (cached) profile to stdout (implies -K and -T).
-+=item -o file, --ofile file
-+
-+Writes a binary (cached) profile to the specified file (implies -K and -T)
-+
- =item -b n, --base n
- Set the base directory for resolving #include directives
-@@ -149,11 +153,43 @@
- Print the version number and exit.
-+=item -p, --preprocess
-+
-+Dump the input profile to stdout out applying preprocessing flattening
-+includes into the output profile.
-+
- =item -d, --debug
- Given once, only checks the profiles to ensure syntactic correctness.
- Given twice, dumps its interpretation of the profile for checking.
-+=item -D n, --dump=n
-+
-+Debug flag for dumping various structures and passes of policy compilation.
-+A single dump flag can be specified per --dump option, but the dump flag
-+can be passed multiple times.  Note progress flags tend to also imply
-+the matching stats flag.
-+
-+  apparmor_parser --dump=dfa-stats --dump=trans-stats <file>
-+
-+Use --help=dump to see a full list of which dump flags are supported
-+
-+=item -O n, --optimize=n
-+
-+Set the optimization flags used by policy compilation.  A sinlge optimization
-+flag can be toggled per -O option, but the optimize flag can be passed
-+multiple times.  Turning off some phases of the optimization can make
-+it so that policy can't complete compilation due to size constraints
-+(it is entirely possible to create a dfa with millions of states that will
-+take days or longer to compile).
-+
-+Note: The parser is set to use a balanced default set of flags, that
-+will result in resonable compression but not take excessive amounts
-+of time to complete.
-+
-+Use --help=optimize to see a full list of which optimization flags are
-+supported.
-+
- =item -h, --help
- Give a quick reference guide.
-
-=== modified file 'parser/libapparmor_re/apparmor_re.h'
---- parser/libapparmor_re/apparmor_re.h        2010-01-28 01:20:13 +0000
-+++ parser/libapparmor_re/apparmor_re.h        2010-08-03 17:27:13 +0000
-@@ -35,6 +35,7 @@
-   DFA_DUMP_EQUIV_STATS =      1 << 19,
-   DFA_DUMP_MINIMIZE =         1 << 20,
-   DFA_DUMP_UNREACHABLE =      1 << 22,
-+  DFA_DUMP_RULE_EXPR =                1 << 23,
- } dfaflags_t;
- #ifdef __cplusplus
-@@ -48,9 +49,9 @@
- aare_ruleset_t *aare_new_ruleset(int reverse);
- void aare_delete_ruleset(aare_ruleset_t *rules);
- int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
--                uint32_t perms, uint32_t audit);
-+                uint32_t perms, uint32_t audit, dfaflags_t flags);
- int aare_add_rule_vec(aare_ruleset_t *rules, int deny, uint32_t perms,
--                    uint32_t audit, int count, char **rulev);
-+                    uint32_t audit, int count, char **rulev, dfaflags_t flags);
- void *aare_create_dfa(aare_ruleset_t *rules, size_t *size, dfaflags_t flags);
- void aare_reset_matchflags(void);
-
-=== modified file 'parser/libapparmor_re/regexp.y'
---- parser/libapparmor_re/regexp.y     2010-02-01 07:21:00 +0000
-+++ parser/libapparmor_re/regexp.y     2010-08-03 17:27:13 +0000
-@@ -102,6 +102,7 @@
-       /* child 0 is left, child 1 is right */
-       Node *child[2];
-+      unsigned int label;     /* unique number for debug etc */
-       /**
-        * We need reference counting for AcceptNodes: sharing AcceptNodes
-        * avoids introducing duplicate States with identical accept values.
-@@ -1208,12 +1209,11 @@
-  * Assign a consecutive number to each node. This is only needed for
-  * pretty-printing the debug output.
-  */
--map<Node *, int> node_label;
- void label_nodes(Node *root)
- {
-     int nodes = 0;
-     for (depth_first_traversal i(root); i; i++)
--      node_label.insert(make_pair(*i, nodes++));
-+       i->label = nodes++;
- }
- /**
-@@ -1225,7 +1225,7 @@
-     if (!state.empty()) {
-       State::iterator i = state.begin();
-       for(;;) {
--          os << node_label[*i];
-+         os << (*i)->label;
-           if (++i == state.end())
-               break;
-           os << ',';
-@@ -1240,15 +1240,15 @@
-  */
- void dump_syntax_tree(ostream& os, Node *node) {
-     for (depth_first_traversal i(node); i; i++) {
--      os << node_label[*i] << '\t';
-+      os << i->label << '\t';
-       if ((*i)->child[0] == 0)
-           os << **i << '\t' << (*i)->followpos << endl;
-       else {
-           if ((*i)->child[1] == 0)
--              os << node_label[(*i)->child[0]] << **i;
-+              os << (*i)->child[0]->label << **i;
-           else
--              os << node_label[(*i)->child[0]] << **i
--                 << node_label[(*i)->child[1]];
-+              os << (*i)->child[0]->label << **i
-+                 << (*i)->child[1]->label;
-           os << '\t' << (*i)->firstpos
-                      << (*i)->lastpos << endl;
-       }
-@@ -1256,22 +1256,17 @@
-     os << endl;
- }
--/* Comparison operator for sets of <State *>. */
--template<class T>
--class deref_less_than {
--public:
--    deref_less_than() { }
--    bool operator()(T a, T b)
--    {
--      return *a < *b;
--    }
-+/* Comparison operator for sets of <State *>.
-+ * Do compare pointer comparisom on set of <Node *>, the pointer comparison
-+ * allows us to determine which Sets of <Node *> we have seen already from
-+ * new ones when constructing the DFA.
-+ */
-+struct deref_less_than {
-+  bool operator()(State * const & lhs, State * const & rhs) const
-+  { return *lhs < *rhs; }
- };
--/**
-- * States in the DFA. The pointer comparison allows us to tell sets we
-- * have seen already from new ones when constructing the DFA.
-- */
--typedef set<State *, deref_less_than<State *> > States;
-+typedef set<State *, deref_less_than > States;
- typedef list<State *> Partition;
- /* Transitions in the DFA. */
- typedef map<State *, Cases> Trans;
-@@ -1370,6 +1365,13 @@
-               here.cases.insert(*j);
-       }
-     }
-+
-+    for (depth_first_traversal i(root); i; i++) {
-+          (*i)->firstpos.clear();
-+          (*i)->lastpos.clear();
-+          (*i)->followpos.clear();
-+    }
-+
-     if (flags & (DFA_DUMP_STATS))
-           fprintf(stderr, "\033[2KCreated dfa: states %ld\tmatching %d\tnonmatching %d\n", states.size(), match_count, nomatch_count);
-@@ -1715,7 +1717,9 @@
-                       Trans::iterator j = trans.find(*i);
-                       if (j != trans.end())
-                               trans.erase(j);
-+                      State *s = *i;
-                       states.erase(*i);
-+                      delete(s);
-               }
-       }
-@@ -2097,24 +2101,11 @@
-               /* if it overflows the next_check array it fits in as we will
-                * resize */
-               if (c >= next_check.size())
--                      goto resize;
-+                      return true;
-               if (next_check[c].second)
-                       return false;
-       }
--      return true;
--resize:
--      next_check.resize(base + cases.cases.rbegin()->first + 1);
--      size_t prev = pos;
--      size_t x = pos;
--      /* find last free list entry */
--      while (x) {
--              prev = x;
--              x = free_list[x].second;
--      }
--      x = free_list. size();
--      free_list.resize(base + cases.cases.rbegin()->first + 1);
--      init_free_list(free_list, prev, x);
-       return true;
- }
-@@ -2126,6 +2117,7 @@
- {
-       State *default_state = dfa.nonmatching;
-       size_t base = 0;
-+      int resize;
-       Trans::iterator i = dfa.trans.find(from);
-       if (i == dfa.trans.end()) {
-@@ -2142,6 +2134,7 @@
-               goto do_insert;
- repeat:
-+      resize = 0;
-       /* get the first free entry that won't underflow */
-       while (x && (x < c)) {
-               prev = x;
-@@ -2154,15 +2147,24 @@
-               x = free_list[x].second;
-       }
-       if (!x) {
-+              resize = 256 - cases.begin()->first;
-+              x = free_list.size();
-+              /* set prev to last free */
-+      } else if (x + 255 - cases.begin()->first >= next_check.size()) {
-+              resize = (255 - cases.begin()->first - (next_check.size() - 1 - x));
-+              for (size_t y = x; y; y = free_list[y].second)
-+                      prev = y;
-+      }
-+      if (resize) {
-               /* expand next_check and free_list */
--              x = free_list.size();
--              size_t range = cases.cases.rbegin()->first - cases.begin()->first + 1;
--              next_check.resize(next_check.size() + range);
--              free_list.resize(free_list.size() + range);
--              init_free_list(free_list, prev, x);
-+              size_t old_size = free_list.size();
-+              next_check.resize(next_check.size() + resize);
-+              free_list.resize(free_list.size() + resize);
-+              init_free_list(free_list, prev, old_size);
-               if (!first_free)
--                      first_free = x;
--              goto repeat;
-+                      first_free = old_size;;
-+              if (x == old_size)
-+                      goto repeat;
-       }
-       base = x - c;
-@@ -2194,8 +2196,9 @@
-       st.insert(make_pair(i->second, i->first));
-     }
--    os << "(accept, default, base):" << endl;
-+    os << "size=" << default_base.size() << " (accept, default, base):  {state} -> {default state}" << endl;
-     for (size_t i = 0; i < default_base.size(); i++) {
-+        os << i << ": ";
-       os << "(" << accept[i] << ", "
-          << num[default_base[i].first] << ", "
-          << default_base[i].second << ")";
-@@ -2206,7 +2209,7 @@
-       os << endl;
-     }
--    os << "(next, check):" << endl;
-+    os << "size=" << next_check.size() << " (next, check): {check state} -> {next state} : offset from base" << endl;
-     for (size_t i = 0; i < next_check.size(); i++) {
-       if (!next_check[i].second)
-           continue;
-@@ -2565,9 +2568,9 @@
- }
- extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
--                           uint32_t perms, uint32_t audit)
-+                           uint32_t perms, uint32_t audit,  dfaflags_t flags)
- {
--      return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule);
-+      return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule, flags);
- }
- #define FLAGS_WIDTH 2
-@@ -2598,7 +2601,8 @@
- extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
-                                uint32_t perms, uint32_t audit,
--                               int count, char **rulev)
-+                               int count, char **rulev,
-+                               dfaflags_t flags)
- {
-     Node *tree = NULL, *accept;
-     int exact_match;
-@@ -2715,6 +2719,18 @@
-       }
-     }
-+    if (flags & DFA_DUMP_RULE_EXPR) {
-+          cerr << "rule: ";
-+          cerr << rulev[0];
-+          for (int i = 1; i < count; i++) {
-+                  cerr << "\\x00";
-+                  cerr << rulev[i];
-+          }
-+          cerr << "  ->  ";
-+          tree->dump(cerr);
-+          cerr << "\n\n";
-+    }
-+
-     if (rules->root)
-       rules->root = new AltNode(rules->root, new CatNode(tree, accept));
-     else
-
-=== modified file 'parser/parser.h'
---- parser/parser.h    2010-02-17 20:21:52 +0000
-+++ parser/parser.h    2010-08-03 17:27:13 +0000
-@@ -4,6 +4,9 @@
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-  *
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd. (All rights reserved)
-+ *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-  *   License published by the Free Software Foundation.
-@@ -14,12 +17,12 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Novell, Inc. or Canonical
-+ *   Ltd.
-  */
- #include <netinet/in.h>
- #include <sys/resource.h>
--#include "pcre/internal.h"
- #include "immunix.h"
- #include "libapparmor_re/apparmor_re.h"
-@@ -40,7 +43,6 @@
- struct cod_pattern {
-       char *regex;            // posix regex
--      pcre *compiled;         // compiled regex, size is compiled->size
- };
- struct cod_entry {
-@@ -168,17 +170,20 @@
- #define OPTION_REMOVE   2
- #define OPTION_REPLACE  3
- #define OPTION_STDOUT 4
-+#define OPTION_OFILE  5
- #define AARE_NONE 0
--#define AARE_PCRE 1
- #define AARE_DFA 2
-+#define BOOL int
-+
- #define FLAG_CHANGEHAT_1_4  2
- #define FLAG_CHANGEHAT_1_5  3
- extern int flag_changehat_version;
- extern int read_implies_exec;
- extern dfaflags_t dfaflags;
--
-+extern int preprocess_only;
-+extern FILE *ofile;
- #define PATH_CHROOT_REL 0x1
- #define PATH_NS_REL 0x2
-@@ -280,12 +285,16 @@
- extern void free_cod_entries(struct cod_entry *list);
- /* parser_symtab.c */
-+struct set_value {;
-+      char *val;
-+      struct set_value *next;
-+};
- extern int add_boolean_var(const char *var, int boolean);
- extern int get_boolean_var(const char *var);
- extern int new_set_var(const char *var, const char *value);
- extern int add_set_value(const char *var, const char *value);
--extern void *get_set_var(const char *var);
--extern char *get_next_set_value(void **context);
-+extern struct set_value *get_set_var(const char *var);
-+extern char *get_next_set_value(struct set_value **context);
- extern void dump_symtab(void);
- extern void dump_expanded_symtab(void);
- void free_symtabs(void);
-@@ -312,7 +321,7 @@
- extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
- extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
- extern void post_process_nt_entries(struct codomain *cod);
--extern int post_process_policy(void);
-+extern int post_process_policy(int debug_only);
- extern int process_hat_regex(struct codomain *cod);
- extern int process_hat_variables(struct codomain *cod);
- extern int post_merge_rules(void);
-
-=== modified file 'parser/parser_include.c'
---- parser/parser_include.c    2009-07-24 12:18:12 +0000
-+++ parser/parser_include.c    2010-08-03 17:27:13 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -14,7 +14,7 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Canonical, Ltd.
-  */
- /* Handle subdomain includes, as a straight forward preprocessing phase.
-@@ -270,3 +270,63 @@
-       *s = 0;
-       return c;
- }
-+
-+struct include_stack_t {
-+      char *filename;
-+      int lineno;
-+      struct include_stack_t *next;
-+};
-+
-+struct include_stack_t *include_stack_head = NULL;
-+
-+static void start_include_position(char *filename)
-+{
-+      if (current_filename)
-+              free(current_filename);
-+      current_filename = strdup(filename ? filename : "stdin");
-+      current_lineno   = 1;
-+}
-+
-+void push_include_stack(char *filename)
-+{
-+      struct include_stack_t *include = NULL;
-+
-+      include = malloc(sizeof(*include));
-+      if (!include) {
-+              perror("malloc of included file stack tracker");
-+              /* failures in this area are non-fatal */
-+              return;
-+      }
-+
-+      include->filename  = strdup(current_filename);
-+      include->lineno    = current_lineno;
-+      include->next      = include_stack_head;
-+      include_stack_head = include;
-+
-+      start_include_position(filename);
-+}
-+
-+void pop_include_stack(void)
-+{
-+      struct include_stack_t *include = NULL;
-+
-+      if (!include_stack_head)
-+              return;
-+
-+      include = include_stack_head;
-+      include_stack_head = include->next;
-+
-+      if (current_filename)
-+              free(current_filename);
-+      current_filename = include->filename;
-+      current_lineno   = include->lineno;
-+      free(include);
-+}
-+
-+void reset_include_stack(char *filename)
-+{
-+      while (include_stack_head)
-+              pop_include_stack();
-+
-+      start_include_position(filename);
-+}
-
-=== modified file 'parser/parser_include.h'
---- parser/parser_include.h    2009-07-24 07:35:39 +0000
-+++ parser/parser_include.h    2010-06-05 06:11:20 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -14,13 +14,15 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Canonical, Ltd.
-  */
- #ifndef PARSER_INCLUDE_H
- #define PARSER_INCLUDE_H
- extern int preprocess_only;
-+extern int current_lineno;
-+extern char *current_filename;
- extern int add_search_dir(char *dir);
- extern void init_base_dir(void);
-@@ -29,4 +31,8 @@
- extern int do_include_preprocessing(char *profilename);
- FILE *search_path(char *filename, char **fullpath);
-+extern void push_include_stack(char *filename);
-+extern void pop_include_stack(void);
-+extern void reset_include_stack(char *filename);
-+
- #endif
-
-=== modified file 'parser/parser_interface.c'
---- parser/parser_interface.c  2010-03-09 09:38:12 +0000
-+++ parser/parser_interface.c  2010-08-03 17:27:13 +0000
-@@ -133,6 +133,9 @@
-                       PERROR(_("%s: Unable to write to stdout\n"),
-                              progname);
-                       break;
-+              case OPTION_OFILE:
-+                      PERROR(_("%s: Unable to write to output file\n"),
-+                             progname);
-               default:
-                       PERROR(_("%s: ASSERT: Invalid option: %d\n"),
-                              progname, option);
-@@ -155,6 +158,7 @@
-                              cod->name);
-                       break;
-               case OPTION_STDOUT:
-+              case OPTION_OFILE:
-                       break;
-               default:
-                       PERROR(_("%s: ASSERT: Invalid option: %d\n"),
-@@ -451,57 +455,6 @@
-       return 1;
- }
--int sd_serialize_pattern(sd_serialize *p, pcre *pat)
--{
--      if (!sd_write_struct(p, "pcre"))
--              return 0;
--      if (!sd_write32(p, pat->size - sizeof(pcre)))
--              return 0;
--      if (!sd_write32(p, pat->magic_number))
--              return 0;
--      if (!sd_write32(p, pat->options))
--              return 0;
--      if (!sd_write16(p, pat->top_bracket))
--              return 0;
--      if (!sd_write16(p, pat->top_backref))
--              return 0;
--      if (!sd_write8(p, pat->first_char))
--              return 0;
--      if (!sd_write8(p, pat->req_char))
--              return 0;
--      if (!sd_write8(p, pat->code[0]))
--              return 0;
--      if (!sd_write_blob(p, &pat->code[1], pat->size - sizeof(pcre), NULL))
--              return 0;
--      if (!sd_write_structend(p))
--              return 0;
--
--      return 1;
--}
--
--int sd_serialize_file_entry(sd_serialize *p, struct cod_entry *file_entry)
--{
--      PDEBUG("Writing file entry. name '%s'\n", file_entry->name);
--      if (!sd_write_struct(p, "fe"))
--              return 0;
--      if (!sd_write_string(p, file_entry->name, NULL))
--              return 0;
--      if (!sd_write32(p, file_entry->mode))
--              return 0;
--      if (!sd_write32(p, file_entry->pattern_type))
--              return 0;
--      if (file_entry->pattern_type == ePatternRegex) {
--              if (!sd_write_string(p, file_entry->pat.regex, NULL))
--                      return 0;
--              if (!sd_serialize_pattern(p, file_entry->pat.compiled))
--                      return 0;
--      }
--      if (!sd_write_structend(p))
--              return 0;
--
--      return 1;
--}
--
- int sd_serialize_dfa(sd_serialize *p, void *dfa, size_t size)
- {
-       if (dfa && !sd_write_aligned_blob(p, dfa, size, "aadfa"))
-@@ -594,18 +547,6 @@
-       return count;
- }
--int count_pcre_ents(struct cod_entry *list)
--{
--      struct cod_entry *entry;
--      int count = 0;
--      list_for_each(list, entry) {
--              if (entry->pattern_type == ePatternRegex) {
--                      count++;
--              }
--      }
--      return count;
--}
--
- int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
-                        int flattened)
- {
-@@ -724,47 +665,8 @@
-               if (!sd_serialize_xtable(p, profile->exec_table))
-                       return 0;
-       } else {
--              /* pcre globbing entries */
--              if (count_pcre_ents(profile->entries)) {
--                      if (!sd_write_list(p, "pgent"))
--                              return 0;
--                      list_for_each(profile->entries, entry) {
--                              if (entry->pattern_type == ePatternRegex) {
--                                      if (!sd_serialize_file_entry(p, entry))
--                                              return 0;
--                              }
--                      }
--                      if (!sd_write_listend(p))
--                              return 0;
--              }
--
--              /* simple globbing entries */
--              if (count_tailglob_ents(profile->entries)) {
--                      if (!sd_write_list(p, "sgent"))
--                              return 0;
--                      list_for_each(profile->entries, entry) {
--                              if (entry->pattern_type == ePatternTailGlob) {
--                                      if (!sd_serialize_file_entry(p, entry))
--                                              return 0;
--                              }
--                      }
--                      if (!sd_write_listend(p))
--                              return 0;
--              }
--
--              /* basic file entries */
--              if (count_file_ents(profile->entries)) {
--                      if (!sd_write_list(p, "fent"))
--                              return 0;
--                      list_for_each(profile->entries, entry) {
--                              if (entry->pattern_type == ePatternBasic) {
--                                      if (!sd_serialize_file_entry(p, entry))
--                                              return 0;
--                              }
--                      }
--                      if (!sd_write_listend(p))
--                              return 0;
--              }
-+              PERROR(_("Unknown pattern type\n"));
-+              return 1;
-       }
-       if (profile->hat_table && regex_type != AARE_DFA) {
-@@ -812,7 +714,7 @@
- int cache_fd = -1;
- int sd_serialize_codomain(int option, struct codomain *cod)
- {
--      int fd;
-+      int fd = -1;
-       int error = -ENOMEM, size, wsize;
-       sd_serialize *work_area;
-       char *filename = NULL;
-@@ -837,22 +739,29 @@
-               filename = "stdout";
-               fd = dup(1);
-               break;
-+      case OPTION_OFILE:
-+              fd = dup(fileno(ofile));
-+              break;
-       default:
-               error = -EINVAL;
-               goto exit;
-               break;
-       }
--      if (kernel_load && fd < 0) {
--              PERROR(_("Unable to open %s - %s\n"), filename,
--                     strerror(errno));
-+      if (fd < 0) {
-+              if (kernel_load)
-+                      PERROR(_("Unable to open %s - %s\n"), filename,
-+                             strerror(errno));
-+              else
-+                      PERROR(_("Unable to open output file - %s\n"),
-+                             strerror(errno));
-               error = -errno;
-               goto exit;
-       }
-       error = 0;
--      if (option != OPTION_STDOUT)
-+      if (option != OPTION_STDOUT && option != OPTION_OFILE)
-               free(filename);
-       if (option == OPTION_REMOVE) {
-@@ -918,7 +827,7 @@
-               }
-               size = work_area->pos - work_area->buffer;
--              if (kernel_load || option == OPTION_STDOUT) {
-+              if (kernel_load || option == OPTION_STDOUT || option == OPTION_OFILE) {
-                       wsize = write(fd, work_area->buffer, size);
-                       if (wsize < 0) {
-                               error = -errno;
-@@ -941,7 +850,7 @@
-               free_sd_serial(work_area);
-       }
--      if (kernel_load) close(fd);
-+      close(fd);
-       if (cod->hat_table && regex_type == AARE_DFA && option != OPTION_REMOVE) {
-               if (load_flattened_hats(cod) != 0)
-@@ -973,7 +882,7 @@
- int sd_load_buffer(int option, char *buffer, int size)
- {
--      int fd;
-+      int fd = -1;
-       int error = -ENOMEM, wsize, bsize;
-       char *filename = NULL;
-       char *b;
-
-=== modified file 'parser/parser_lex.l'
---- parser/parser_lex.l        2010-03-09 05:49:16 +0000
-+++ parser/parser_lex.l        2010-08-03 17:27:13 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -14,7 +14,7 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Canonical, Ltd.
-  */
- /* Definitions section */
-@@ -49,7 +49,12 @@
- #endif
- #define NPDEBUG(fmt, args...) /* Do nothing */
--int current_lineno = 1;
-+#define DUMP_PREPROCESS do { if (preprocess_only) ECHO; } while (0)
-+
-+#define YY_NO_INPUT
-+
-+int current_lineno     = 1;
-+char *current_filename = NULL;
- struct ignored_suffix_t {
-       char * text;
-@@ -80,14 +85,19 @@
-       char *fullpath = NULL;
-       if (search) {
-+              if (preprocess_only)
-+                      fprintf(yyout, "\n\n##included <%s>\n", filename);
-               include_file = search_path(filename, &fullpath);
-       } else {
-+              if (preprocess_only)
-+                      fprintf(yyout, "\n\n##included \"%s\"\n", filename);
-               fullpath = strdup(filename);
-               include_file = fopen(fullpath, "r");
-       }
-       if (!include_file)
--              yyerror(_("Could not open '%s'"), fullpath);
-+              yyerror(_("Could not open '%s'"),
-+                        fullpath ? fullpath: filename);
-         if (fstat(fileno(include_file), &my_stat))
-               yyerror(_("fstat failed for '%s'"), fullpath);
-@@ -95,6 +105,7 @@
-         if (S_ISREG(my_stat.st_mode)) {
-               yyin = include_file;
-               PDEBUG("Opened include \"%s\"\n", fullpath);
-+              push_include_stack(fullpath);
-               yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
-         }
-@@ -139,8 +150,9 @@
-                               yyerror(_("stat failed for '%s'"), dirent_path);
-                       if (S_ISREG(my_stat.st_mode)) {
-                               if (!(yyin = fopen(dirent_path,"r")))
--                                      yyerror(_("Could not open '%s'"), filename);
--                              PDEBUG("Opened include \"%s\"\n", filename);
-+                                      yyerror(_("Could not open '%s' in '%s'"), dirent_path, filename);
-+                              PDEBUG("Opened include \"%s\" in \"%s\"\n", dirent_path, filename);
-+                              push_include_stack(dirent_path);
-                               yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
-                       }
-               }
-@@ -227,6 +239,8 @@
- }
- <<EOF>> {
-+      fclose(yyin);
-+      pop_include_stack();
-       yypop_buffer_state();
-       if ( !YY_CURRENT_BUFFER ) yyterminate();
- }
-@@ -240,6 +254,7 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id =  processunquoted(yytext, yyleng);
-                       PDEBUG("Found sub name: \"%s\"\n",  yylval.id);
-                       BEGIN(INITIAL);
-@@ -253,6 +268,7 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id = processquoted(yytext, yyleng);
-                       PDEBUG("Found sub name: \"%s\"\n", yylval.id);
-                       BEGIN(INITIAL);
-@@ -260,6 +276,7 @@
-               }
-       [^\n]   {
-+                      DUMP_PREPROCESS;
-                       /* Something we didn't expect */
-                       yyerror(_("Found unexpected character: '%s'"), yytext);
-               }
-@@ -274,6 +291,7 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id = processunquoted(yytext, yyleng);
-                       PDEBUG("Found sub name: \"%s\"\n", yylval.id);
-                       BEGIN(INITIAL);
-@@ -287,14 +305,16 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id  = processquoted(yytext, yyleng);
-                       PDEBUG("Found sub name: \"%s\"\n", yylval.id);
-                       BEGIN(INITIAL);
-                       return TOK_ID;
-               }
--      {WS}+                   {  /* Ignoring whitespace */ }
-+      {WS}+   { DUMP_PREPROCESS; /* Ignoring whitespace */ }
-       [^\n]   {
-+                      DUMP_PREPROCESS;
-                       /* Something we didn't expect */
-                       yyerror(_("Found unexpected character: '%s'"), yytext);
-               }
-@@ -302,85 +322,99 @@
- <FLAGS_MODE>{
-       {FLAGOPEN_PAREN}        {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("FLag (\n");
-                       return TOK_FLAG_OPENPAREN;
-                       }
-       {FLAGCLOSE_PAREN}       {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Flag )\n");
-                       BEGIN(INITIAL);
-                       return TOK_FLAG_CLOSEPAREN;
-                       }
--      {WS}+           { /* Eat whitespace */ }
-+      {WS}+           { DUMP_PREPROCESS; /* Eat whitespace */ }
-       {FLAGSEP}       {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Flag , \n");
-                       return TOK_FLAG_SEP;
-                       }
-       {EQUALS}        {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Flag = \n");
-                       return TOK_EQUALS;
-                       }
-       {KEYWORD}       {
-+                      DUMP_PREPROCESS;
-                       yylval.flag_id = strdup(yytext);
-                       PDEBUG("Found flag: \"%s\"\n", yylval.flag_id);
-                       return TOK_FLAG_ID;
-                       }
-       [^\n]           {
-+                      DUMP_PREPROCESS;
-                       /* Something we didn't expect */
-                       yyerror(_("Found unexpected character: '%s'"), yytext);
-                       }
- }
- <ASSIGN_MODE>{
--      {WS}+           { /* Eat whitespace */ }
-+      {WS}+           { DUMP_PREPROCESS; /* Eat whitespace */ }
-       {ID}+           {
-+                      DUMP_PREPROCESS;
-                       yylval.var_val = processunquoted(yytext, yyleng);
-                       PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
-                       return TOK_VALUE;
-                       }
-       {QUOTED_ID}     {
-+                      DUMP_PREPROCESS;
-                       yylval.var_val = processquoted(yytext, yyleng);
-                       PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
-                       return TOK_VALUE;
-                       }
--      \\\n            { current_lineno++ ; }
-+      \\\n            { DUMP_PREPROCESS; current_lineno++ ; }
-       \r?\n           {
-+                      DUMP_PREPROCESS;
-                       current_lineno++;
-                       BEGIN(INITIAL);
-                       }
- }
- <NETWORK_MODE>{
--      {WS}+           { /* Eat whitespace */ }
-+      {WS}+           { DUMP_PREPROCESS; /* Eat whitespace */ }
-       {ID}+           {
-+                      DUMP_PREPROCESS;
-                       yylval.id = strdup(yytext);
-                       return TOK_ID;
-                       }
-       {END_OF_RULE}   {
-+                      DUMP_PREPROCESS;
-                       BEGIN(INITIAL);
-                       return TOK_END_OF_RULE;
-               }
-       [^\n]           {
-+                      DUMP_PREPROCESS;
-                         /* Something we didn't expect */
-                       yylval.id = strdup(yytext);
-                       yyerror(_("(network_mode) Found unexpected character: '%s'"), yylval.id);
-                       }
-       \r?\n           {
-+                      DUMP_PREPROCESS;
-                       current_lineno++;
-                       }
- }
- <CHANGE_PROFILE_MODE>{
-       {ARROW}         {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Matched a change profile arrow\n");
-                       return TOK_ARROW;
-                       }
-@@ -393,6 +427,7 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id = processunquoted(yytext, yyleng);
-                       PDEBUG("Found change profile name: \"%s\"\n", yylval.id);
-                       BEGIN(INITIAL);
-@@ -406,14 +441,16 @@
-                          * a longer match). So now, when I want to
-                          * match any random string, I go into a
-                          * separate state. */
-+                      DUMP_PREPROCESS;
-                       yylval.id = processquoted(yytext, yyleng);
-                       PDEBUG("Found change profile quoted name: \"%s\"\n", yylval.id);
-                       BEGIN(INITIAL);
-                       return TOK_ID;
-               }
--      {WS}+                   {  /* Ignoring whitespace */ }
-+      {WS}+                   {  DUMP_PREPROCESS; /* Ignoring whitespace */ }
-       [^\n]   {
-+                      DUMP_PREPROCESS;
-                       /* Something we didn't expect */
-                       yyerror(_("Found unexpected character: '%s'"), yytext);
-               }
-@@ -421,127 +458,147 @@
- #include/.*\r?\n       { /* include */
-                       PDEBUG("Matched #include\n");
--                      current_lineno++;
-                       BEGIN(INCLUDE);
-                       }
- #.*\r?\n              { /* normal comment */
-+                      DUMP_PREPROCESS;
-                       PDEBUG("comment(%d): %s\n", current_lineno, yytext);
-                       current_lineno++;
-                       BEGIN(INITIAL);
- }
--{END_OF_RULE}         { return TOK_END_OF_RULE; }
-+{END_OF_RULE}         { DUMP_PREPROCESS; return TOK_END_OF_RULE; }
- {SEPARATOR}           {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Matched a separator\n");
-                       BEGIN(SUB_NAME);
-                       return TOK_SEP;
-                       }
- {ARROW}                       {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Matched a arrow\n");
-                       return TOK_ARROW;
-                       }
- {EQUALS}              {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Matched equals for assignment\n");
-                       BEGIN(ASSIGN_MODE);
-                       return TOK_EQUALS;
-                       }
- {ADD_ASSIGN}          {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Matched additive value assignment\n");
-                       BEGIN(ASSIGN_MODE);
-                       return TOK_ADD_ASSIGN;
-                       }
- <RLIMIT_MODE>{
--      {WS}+           { /* Eat whitespace */ }
-+      {WS}+           { DUMP_PREPROCESS; /* Eat whitespace */ }
-       -?{NUMBER}[kKMG]?  {
-+                      DUMP_PREPROCESS;
-                       yylval.var_val = strdup(yytext);
-                       return TOK_VALUE;
-                       }
-       {KEYWORD}       {
-+                      DUMP_PREPROCESS;
-                       yylval.id = strdup(yytext);
-                       if (strcmp(yytext, "infinity") == 0)
-                               return TOK_VALUE;
-                       return TOK_ID;
-                       }
--      {LT_EQUAL}      { return TOK_LE; }
-+      {LT_EQUAL}      { DUMP_PREPROCESS; return TOK_LE; }
-       {END_OF_RULE}   {
-+                      DUMP_PREPROCESS;
-                       BEGIN(INITIAL);
-                       return TOK_END_OF_RULE;
-                       }
-       \\\n            {
-+                      DUMP_PREPROCESS;
-                       current_lineno++;
-                       BEGIN(INITIAL);
-                       }
-       \r?\n           {
-+                      DUMP_PREPROCESS;
-                       current_lineno++;
-                       BEGIN(INITIAL);
-                       }
- }
- {SET_VARIABLE}                {
-+                      DUMP_PREPROCESS;
-                       yylval.set_var = strdup(yytext);
-                       PDEBUG("Found set variable %s\n", yylval.set_var);
-                       return TOK_SET_VAR;
-                       }
- {BOOL_VARIABLE}               {
-+                      DUMP_PREPROCESS;
-                       yylval.bool_var = strdup(yytext);
-                       PDEBUG("Found boolean variable %s\n", yylval.bool_var);
-                       return TOK_BOOL_VAR;
-                       }
- {OPEN_BRACE}          {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Open Brace\n");
-                       return TOK_OPEN;
-                       }
- {CLOSE_BRACE}         {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Close Brace\n");
-                       return TOK_CLOSE;
-                       }
- {PATHNAME}            {
-+                      DUMP_PREPROCESS;
-                       yylval.id = processunquoted(yytext, yyleng);
-                       PDEBUG("Found id: \"%s\"\n", yylval.id);
-                       return TOK_ID;
-                       }
- {QPATHNAME}           {
-+                      DUMP_PREPROCESS;
-                       yylval.id = processquoted(yytext, yyleng);
-                       PDEBUG("Found id: \"%s\"\n", yylval.id);
-                       return TOK_ID;
-                       }
- {MODES}                       {
-+                      DUMP_PREPROCESS;
-                       yylval.mode = strdup(yytext);
-                       PDEBUG("Found modes: %s\n", yylval.mode);
-                       return TOK_MODE;
-                       }
- {HAT}                 {
-+                      DUMP_PREPROCESS;
-                       BEGIN(SUB_NAME2);
-                       return TOK_HAT;
-                       }
- {COLON}                       {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("Found a colon\n");
-                       return TOK_COLON;
-                       }
- {FLAGOPEN_PAREN}      {
-+                      DUMP_PREPROCESS;
-                       PDEBUG("FLag (\n");
-                       BEGIN(FLAGS_MODE);
-                       return TOK_FLAG_OPENPAREN;
-                       }
- {VARIABLE_NAME}               {
-+                      DUMP_PREPROCESS;
-                       int token = get_keyword_token(yytext);
-                       /* special cases */
-@@ -573,11 +630,13 @@
-                       return token;
-                       }
--{WS}+                 {  /* Ignoring whitespace */ }
-+{WS}+                 {  DUMP_PREPROCESS; /* Ignoring whitespace */ }
--\r?\n                 { current_lineno++ ; }
-+\r?\n                 { DUMP_PREPROCESS; current_lineno++ ; }
- [^\n]                 {
-+                      DUMP_PREPROCESS;
-+
-                         /* Something we didn't expect */
-                       yyerror(_("Found unexpected character: '%s'"), yytext);
-                       }
-
-=== modified file 'parser/parser_main.c'
---- parser/parser_main.c       2010-01-28 01:20:13 +0000
-+++ parser/parser_main.c       2010-08-03 17:27:13 +0000
-@@ -4,6 +4,9 @@
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-  *
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd. (All rights reserved)
-+ *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-  *   License published by the Free Software Foundation.
-@@ -14,7 +17,8 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Novell, Inc. or Canonical,
-+ *   Ltd.
-  */
- #include <stdio.h>
-@@ -26,6 +30,7 @@
- #include <fcntl.h>
- #include <mntent.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #include <locale.h>
- #define _(s) gettext(s)
-@@ -34,6 +39,8 @@
- #include <unistd.h>
- #include <sys/sysctl.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
- #include "parser.h"
- #include "parser_version.h"
-@@ -47,7 +54,6 @@
- #define MATCH_STRING "/sys/kernel/security/" MODULE_NAME "/matching"
- #define FLAGS_FILE "/sys/kernel/security/" MODULE_NAME "/features"
- #define MOUNTED_FS "/proc/mounts"
--#define PCRE "pattern=pcre"
- #define AADFA "pattern=aadfa"
- #define PRIVILEGED_OPS (write_cache || kernel_load)
-@@ -76,6 +82,8 @@
- #else
- int read_implies_exec = 0;
- #endif
-+int preprocess_only = 0;
-+int skip_mode_force = 0;
- char *subdomainbase = NULL;
- char *match_string = NULL;
-@@ -84,8 +92,7 @@
- int perms_create = 0;         /* perms contain create flag */
- char *profile_namespace = NULL;
- int flag_changehat_version = FLAG_CHANGEHAT_1_5;
--
--extern int current_lineno;
-+FILE *ofile = NULL;
- /* per-profile settings */
- int force_complain = 0;
-@@ -106,6 +113,7 @@
-       {"remove",              0, 0, 'R'},
-       {"names",               0, 0, 'N'},
-       {"stdout",              0, 0, 'S'},
-+      {"ofile",               1, 0, 'o'},
-       {"match-string",        1, 0, 'm'},
-       {"quiet",               0, 0, 'q'},
-       {"skip-kernel-load",    0, 0, 'Q'},
-@@ -121,6 +129,7 @@
-       {"Dump",                1, 0, 'D'},
-       {"optimize",            1, 0, 'O'},
-       {"Optimize",            1, 0, 'O'},
-+      {"preprocess",          0, 0, 'p'},
-       {NULL, 0, 0, 0},
- };
-@@ -145,6 +154,7 @@
-              "-B, --binary            Input is precompiled profile\n"
-              "-N, --names             Dump names of profiles in input.\n"
-              "-S, --stdout            Dump compiled profile to stdout\n"
-+             "-o n, --ofile n         Write output to file n\n"
-              "-b n, --base n          Set base dir and cwd\n"
-              "-I n, --Include n       Add n to the search path\n"
-              "-f n, --subdomainfs n   Set location of apparmor filesystem\n"
-@@ -160,9 +170,10 @@
-              "-Q, --skip-kernel-load  Do everything except loading into kernel\n"
-              "-V, --version           Display version info and exit\n"
-              "-d, --debug             Debug apparmor definitions\n"
-+             "-p, --preprocess        Dump preprocessed profile\n"
-              "-D [n], --dump          Dump internal info for debugging\n"
-              "-O [n], --Optimize      Control dfa optimizations\n"
--             "-h [command], --help    Display this text or info about command\n"
-+             "-h [cmd], --help[=cmd]  Display this text or info about cmd\n"
-              ,command);
- }
-@@ -175,6 +186,7 @@
-              "no option specified     Dump variables\n"
-              "variables               Dump variables\n"
-              "expanded-variables      Dump expanded variables\n"
-+             "rule-exprs              Dump rule to expr tree conversions\n"
-              "expr-stats              Dump stats on expr tree\n"
-              "expr-tree               Dump expression tree\n"
-              "expr-simple             Dump simplified expression tree\n"
-@@ -224,8 +236,10 @@
-       if (conf_quiet || names_only || option == OPTION_REMOVE)
-               return;
--      rc = asprintf(&newfmt, _("Warning (%s line %d): %s"),
-+      rc = asprintf(&newfmt, _("Warning from %s (%s%sline %d): %s"),
-                     profilename ? profilename : "stdin",
-+                    current_filename ? current_filename : "",
-+                    current_filename ? " " : "",
-                     current_lineno,
-                     fmt);
-       if (!newfmt)
-@@ -244,7 +258,7 @@
-       int count = 0;
-       option = OPTION_ADD;
--      while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:", long_options, &o)) != -1)
-+      while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
-       {
-               switch (c) {
-               case 0:
-@@ -258,7 +272,7 @@
-                       break;
-               case 'd':
-                       debug++;
--                      skip_cache = 1;
-+                      skip_read_cache = 1;
-                       break;
-               case 'h':
-                       if (!optarg) {
-@@ -285,6 +299,7 @@
-               case 'R':
-                       count++;
-                       option = OPTION_REMOVE;
-+                      skip_cache = 1;
-                       break;
-               case 'V':
-                       display_version();
-@@ -297,10 +312,12 @@
-                       set_base_dir(optarg);
-                       break;
-               case 'B':
--                      binary_input =1;
-+                      binary_input = 1;
-+                      skip_cache = 1;
-                       break;
-               case 'C':
-                       opt_force_complain = 1;
-+                      skip_cache = 1;
-                       break;
-               case 'N':
-                       names_only = 1;
-@@ -312,17 +329,31 @@
-                       skip_read_cache = 1;
-                       kernel_load = 0;
-                       break;
-+              case 'o':
-+                      count++;
-+                      option = OPTION_OFILE;
-+                      skip_read_cache = 1;
-+                      kernel_load = 0;
-+                      ofile = fopen(optarg, "w");
-+                      if (!ofile) {
-+                              PERROR("%s: Could not open file %s\n",
-+                                     progname, optarg);
-+                              exit(1);
-+                      }
-+                      break;
-               case 'f':
-                       subdomainbase = strndup(optarg, PATH_MAX);
-                       break;
-               case 'D':
--                      skip_cache = 1;
-+                      skip_read_cache = 1;
-                       if (!optarg) {
-                               dump_vars = 1;
-                       } else if (strcmp(optarg, "variables") == 0) {
-                               dump_vars = 1;
-                       } else if (strcmp(optarg, "expanded-variables") == 0) {
-                               dump_expanded_vars = 1;
-+                      } else if (strcmp(optarg, "rule-exprs") == 0) {
-+                              dfaflags |= DFA_DUMP_RULE_EXPR;
-                       } else if (strcmp(optarg, "expr-tree") == 0) {
-                               dfaflags |= DFA_DUMP_TREE;
-                       } else if (strcmp(optarg, "expr-simple") == 0) {
-@@ -359,7 +390,7 @@
-                       }
-                       break;
-               case 'O':
--                      skip_cache = 1;
-+                      skip_read_cache = 1;
-                       if (strcmp(optarg, "0") == 0) {
-                               dfaflags |= DFA_CONTROL_NO_TREE_NORMAL |
-                                       DFA_CONTROL_NO_TREE_SIMPLE |
-@@ -435,6 +466,13 @@
-               case 'Q':
-                       kernel_load = 0;
-                       break;
-+              case 'p':
-+                      count++;
-+                      kernel_load = 0;
-+                      skip_cache = 1;
-+                      preprocess_only = 1;
-+                      skip_mode_force = 1;
-+                      break;
-               default:
-                       display_usage(progname);
-                       exit(0);
-@@ -569,9 +607,6 @@
- out:
-       if (match_string) {
--              if (strstr(match_string, PCRE))
--                      regex_type = AARE_PCRE;
--
-               if (strstr(match_string, AADFA))
-                       regex_type = AARE_DFA;
-@@ -620,20 +655,6 @@
-       return;
- }
--/* return 1 --> PCRE should work fine
--   return 0 --> no PCRE support */
--static int regex_support(void) {
--      /* no match string, predates (or postdates?) the split matching
--      module design */
--      if (!match_string)
--              return 1;
--
--      if (regex_type != AARE_NONE)
--              return 1;
--
--      return 0;
--}
--
- int process_binary(int option, char *profilename)
- {
-       char *buffer = NULL;
-@@ -695,12 +716,33 @@
-       return retval;
- }
--void reset_parser(void)
-+void reset_parser(char *filename)
- {
-       free_aliases();
-       free_symtabs();
-       free_policies();
-       reset_regex();
-+      reset_include_stack(filename);
-+}
-+
-+int test_for_dir_mode(const char *basename, const char *linkdir)
-+{
-+      int rc = 0;
-+
-+      if (!skip_mode_force) {
-+              char *target = NULL;
-+              if (asprintf(&target, "%s/%s/%s", basedir, linkdir, basename) < 0) {
-+                      perror("asprintf");
-+                      exit(1);
-+              }
-+
-+              if (access(target, R_OK) == 0)
-+                      rc = 1;
-+
-+              free(target);
-+      }
-+
-+      return rc;
- }
- int process_profile(int option, char *profilename)
-@@ -727,37 +769,22 @@
-       if (profilename && option != OPTION_REMOVE) {
-               /* make decisions about disabled or complain-mode profiles */
--              char *target = NULL;
-               char *basename = strrchr(profilename, '/');
-               if (basename)
-                       basename++;
-               else
-                       basename = profilename;
--              if (asprintf(&target, "%s/%s/%s", basedir, "disable", basename) < 0) {
--                      perror("asprintf");
--                      exit(1);
--              }
--
--              if (access(target, R_OK) == 0) {
--                      if (!conf_quiet)
--                              PERROR("Skipping profile in %s/disable: %s\n", basedir, basename);
--                      free(target);
-+              if (test_for_dir_mode(basename, "disable")) {
-+                      if (!conf_quiet)
-+                              PERROR("Skipping profile in %s/disable: %s\n", basedir, basename);
-                       goto out;
-               }
--              free(target);
--
--              if (asprintf(&target, "%s/%s/%s", basedir, "force-complain", basename)<0) {
--                      perror("asprintf");
--                      exit(1);
--              }
--
--              if (access(target, R_OK) == 0) {
--                      if (!conf_quiet)
--                              PERROR("Warning: found %s in %s/force-complain, forcing complain mode\n", basename, basedir);
--                      force_complain = 1;
--              }
--              free(target);
-+
-+              if (test_for_dir_mode(basename, "force-complain")) {
-+                      PERROR("Warning: found %s in %s/force-complain, forcing complain mode\n", basename, basedir);
-+                      force_complain = 1;
-+              }
-               if (!force_complain && !skip_cache) {
-                       fstat(fileno(yyin), &stat_text);
-@@ -796,12 +823,15 @@
-       if (yyin)
-               yyrestart(yyin);
--      reset_parser();
-+      reset_parser(profilename);
-       retval = yyparse();
-       if (retval != 0)
-               goto out;
-+      if (preprocess_only)
-+              goto out;
-+
-       if (names_only) {
-               dump_policy_names();
-               goto out;
-@@ -812,7 +842,7 @@
-               goto out;
-       }
--      retval = post_process_policy();
-+      retval = post_process_policy(debug);
-       if (retval != 0) {
-               PERROR(_("%s: Errors found in file. Aborting.\n"), progname);
-               goto out;
-@@ -829,10 +859,6 @@
-               goto out;
-       }
--      if (!regex_support()) {
--              die_if_any_regex();
--      }
--
-       retval = load_policy(option);
- out:
-@@ -969,5 +995,8 @@
-               profilename = NULL;
-       }
-+      if (ofile)
-+              fclose(ofile);
-+
-       return retval;
- }
-
-=== modified file 'parser/parser_misc.c'
---- parser/parser_misc.c       2010-03-09 04:38:54 +0000
-+++ parser/parser_misc.c       2010-08-03 17:27:13 +0000
-@@ -19,6 +19,7 @@
- /* assistance routines */
-+#include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
-@@ -27,6 +28,7 @@
- #define _(s) gettext(s)
- #include <netinet/in.h>
- #include <linux/socket.h>
-+#include <linux/limits.h>
- #include <arpa/inet.h>
- #include <linux/capability.h>
-@@ -35,8 +37,10 @@
- /* #define DEBUG */
- #ifdef DEBUG
-+#undef PDEBUG
- #define PDEBUG(fmt, args...) printf("Lexer: " fmt, ## args)
- #else
-+#undef PDEBUG
- #define PDEBUG(fmt, args...)  /* Do nothing */
- #endif
- #define NPDEBUG(fmt, args...) /* Do nothing */
-@@ -102,7 +106,7 @@
- };
- /* for alpha matches, check for keywords */
--static int get_table_token(const char *name, struct keyword_table *table,
-+static int get_table_token(const char *name __unused, struct keyword_table *table,
-                          const char *keyword)
- {
-       int i;
-@@ -142,42 +146,6 @@
-       return get_table_token("rlimit", rlimit_table, name);
- }
--static struct keyword_table address_family[] = {
--/*    {"unix",        AF_UNIX},
--      {"local",       AF_LOCAL},      */
--      {"inet",        AF_INET},
--/*    {"ax25",        AF_AX25},
--      {"ipx",         AF_IPX},
--      {"appletalk",   AF_APPLETALK},
--      {"netrom",      AF_NETROM},
--      {"bridge",      AF_BRIDGE},
--      {"atmpvc",      AF_ATMPVC},
--      {"x25",         AF_X25}, */
--      {"inet6",       AF_INET6},
--/*    {"rose",        AF_ROSE},
--      {"decnet",      AF_DECnet},
--      {"netbeui",     AF_NETBEUI},
--      {"security",    AF_SECURITY},
--      {"key",         AF_KEY},
--      {"netlink",     AF_NETLINK},
--      {"route",       AF_ROUTE},
--      {"packet",      AF_PACKET},
--      {"ash",         AF_ASH},
--      {"econet",      AF_ECONET},
--      {"atmsvc",      AF_ATMSVC},
--      {"sna",         AF_SNA},
--      {"irda",        AF_IRDA},
--      {"pppox",       AF_PPPOX},
--      {"wanpipe",     AF_WANPIPE},
--      {"llc",         AF_LLC},
--      {"tipc",        AF_TIPC},
--      {"bluetooth",   AF_BLUETOOTH},
--      {"iucv",        AF_IUCV},
--      {"rxrpc",       AF_RXRPC}, */
--      /* terminate */
--      {NULL, 0}
--};
--
- struct network_tuple {
-       char *family_name;
-       unsigned int family;
-@@ -462,7 +430,7 @@
-       }
- }
--static int parse_sub_mode(const char *str_mode, const char *mode_desc)
-+static int parse_sub_mode(const char *str_mode, const char *mode_desc __unused)
- {
- #define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
-@@ -666,7 +634,6 @@
-       entry->pattern_type = ePatternInvalid;
-       entry->pat.regex = NULL;
--      entry->pat.compiled = NULL;
-       entry->next = NULL;
-@@ -692,7 +659,6 @@
-       /* XXX - need to create copies of the patterns, too */
-       entry->pattern_type = orig->pattern_type;
-       entry->pat.regex = NULL;
--      entry->pat.compiled = NULL;
-       entry->next = orig->next;
-@@ -713,8 +679,6 @@
-               free(list->link_name);
-       if (list->pat.regex)
-               free(list->pat.regex);
--      if (list->pat.compiled)
--              free(list->pat.compiled);
-       free(list);
- }
-
-=== modified file 'parser/parser_policy.c'
---- parser/parser_policy.c     2009-08-20 15:27:12 +0000
-+++ parser/parser_policy.c     2010-05-31 18:58:40 +0000
-@@ -4,6 +4,9 @@
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-  *
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd. (All rights reserved)
-+ *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-  *   License published by the Free Software Foundation.
-@@ -14,7 +17,8 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Novell, Inc. or Canonical,
-+ *   Ltd.
-  */
- #include <stdio.h>
-@@ -664,7 +668,7 @@
-       return ret;
- }
--int post_process_policy(void)
-+int post_process_policy(int debug_only)
- {
-       int retval = 0;
-@@ -696,11 +700,13 @@
-               return retval;
-       }
--      retval = post_process_regex();
--      if (retval != 0) {
--              PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
--                     progname);
--              return retval;
-+      if (!debug_only) {
-+              retval = post_process_regex();
-+              if (retval != 0) {
-+                      PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
-+                             progname);
-+                      return retval;
-+              }
-       }
-       return retval;
-
-=== modified file 'parser/parser_regex.c'
---- parser/parser_regex.c      2010-02-12 21:49:58 +0000
-+++ parser/parser_regex.c      2010-08-03 17:27:13 +0000
-@@ -21,6 +21,7 @@
- #include <stdarg.h>
- #include <string.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #define _(s) gettext(s)
- /* #define DEBUG */
-@@ -74,7 +75,6 @@
- {
-       char *sptr, *dptr;
-       BOOL seen_slash = 0;
--      int len;
-       if (!path || (strlen(path) < 2))
-               return;
-@@ -106,19 +106,6 @@
-               }
-       }
-       *dptr = 0;
--
--      if (regex_type != AARE_DFA) {
--              /* eliminate trailing slashes for versions of apparmor that
--               * do not use the dfa engine.
--               * Versions of apparmor which use the dfa engine use the
--               * trailing / to differentiate between file and directory
--               * matches
--               */
--              len = strlen(path);
--              if (len > 2 && path[len -1] == '/') {
--                      path[len - 1] = 0;
--              }
--      }
- }
- static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
-@@ -154,6 +141,9 @@
-       sptr = aare;
-       dptr = pcre;
-+      if (dfaflags & DFA_DUMP_RULE_EXPR)
-+              fprintf(stderr, "aare: %s   ->   ", aare);
-+
-       if (anchor)
-               /* anchor beginning of regular expression */
-               *dptr++ = '^';
-@@ -406,85 +396,13 @@
- out:
-       if (ret == FALSE)
-               ptype = ePatternInvalid;
-+
-+      if (dfaflags & DFA_DUMP_RULE_EXPR)
-+              fprintf(stderr, "%s\n", pcre);
-+
-       return ptype;
- }
--static int process_pcre_entry(struct cod_entry *entry)
--{
--      char tbuf[PATH_MAX + 3];        /* +3 for ^, $ and \0 */
--      int ret = TRUE;
--      pattern_t ptype;
--      int pos;
--      if (!entry)             /* shouldn't happen */
--              return TRUE;
--
--      ptype = convert_aaregex_to_pcre(entry->name, 1, tbuf, PATH_MAX+3, &pos);
--      if (ptype == ePatternInvalid)
--              return FALSE;
--
--      entry->pattern_type = ptype;
--
--      /*
--       * Only use buffer (tbuf) that we built above, if we
--       * identified a pattern requiring full regex support.
--       */
--      if (ptype == ePatternRegex) {
--              int pattlen = strlen(tbuf);
--
--              if ((entry->pat.regex = malloc(pattlen + 1))) {
--                      const char *errorreason;
--                      int errpos;
--
--                      strcpy(entry->pat.regex, tbuf);
--
--                      if ((entry->pat.compiled =
--                           pcre_compile(entry->pat.regex, 0,
--                                        &errorreason, &errpos,
--                                        NULL))) {
--                              /* NULL out tables, kernel will use a
--                               * private version
--                               */
--                              entry->pat.compiled->tables = NULL;
--                      } else {
--                              int i;
--
--                              PERROR(_("%s: Failed to compile regex '%s' [original: '%s']\n"),
--                                     progname, entry->pat.regex,
--                                     entry->name);
--
--                              PERROR(_("%s: error near               "),
--                                     progname);
--
--                              for (i = 0; i < errpos; i++) {
--                                      fputc('.', stderr);
--                              }
--
--                              fputc('^', stderr);
--                              fputc('\n', stderr);
--
--                              PERROR(_("%s: error reason: '%s'\n"),
--                                     progname, errorreason);
--
--                              free(entry->pat.regex);
--                              entry->pat.regex = NULL;
--
--                              ret = FALSE;
--                      }
--              } else {
--                      PERROR(_("%s: Failed to compile regex '%s' [original: '%s'] - malloc failed\n"),
--                             progname, entry->pat.regex, entry->name);
--
--                      ret = FALSE;
--              }
--      } else {
--              /* not a regex, scan input for any escape characters
--               * and remove, and reduce double \\ to a single */
--              filter_escapes(entry->name);
--      }               /* ptype == ePatternRegex */
--
--      return ret;
--}
--
- static const char *local_name(const char *name)
- {
-       const char *t;
-@@ -519,7 +437,7 @@
-               aare_ruleset_t *rule = aare_new_ruleset(0);
-               if (!rule)
-                       return FALSE;
--              if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0)) {
-+              if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
-                       aare_delete_ruleset(rule);
-                       return FALSE;
-               }
-@@ -529,7 +447,7 @@
-                               int len;
-                               convert_aaregex_to_pcre(alt->name, 0, tbuf,
-                                                       PATH_MAX + 3, &len);
--                              if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0)) {
-+                              if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
-                                       aare_delete_ruleset(rule);
-                                       return FALSE;
-                               }
-@@ -538,7 +456,7 @@
-               cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size,
-                                             dfaflags);
-               aare_delete_ruleset(rule);
--              if (!cod->xmatch)
-+              if (!cod->xmatch)
-                       return FALSE;
-       }
-@@ -581,11 +499,11 @@
-       if (entry->deny && (entry->mode & AA_LINK_BITS)) {
-               if (!aare_add_rule(dfarules, tbuf, entry->deny,
-                                  entry->mode & ~AA_LINK_BITS,
--                                 entry->audit & ~AA_LINK_BITS))
-+                                 entry->audit & ~AA_LINK_BITS, dfaflags))
-                       return FALSE;
-       } else if (entry->mode & ~AA_CHANGE_PROFILE) {
-               if (!aare_add_rule(dfarules, tbuf, entry->deny, entry->mode,
--                                 entry->audit))
-+                                 entry->audit, dfaflags))
-                       return FALSE;
-       }
-@@ -607,7 +525,7 @@
-                       perms |= LINK_TO_LINK_SUBSET(perms);
-                       vec[1] = "/[^/].*";
-               }
--              if (!aare_add_rule_vec(dfarules, entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec))
-+              if (!aare_add_rule_vec(dfarules, entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec, dfaflags))
-                       return FALSE;
-       }
-       if (entry->mode & AA_CHANGE_PROFILE) {
-@@ -618,10 +536,10 @@
-                       ptype = convert_aaregex_to_pcre(entry->namespace, 0, lbuf, PATH_MAX + 8, &pos);
-                       vec[0] = lbuf;
-                       vec[1] = tbuf;
--                      if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec))
-+                      if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec, dfaflags))
-                           return FALSE;
-               } else {
--                      if (!aare_add_rule(dfarules, tbuf, 0, AA_CHANGE_PROFILE, 0))
-+                if (!aare_add_rule(dfarules, tbuf, 0, AA_CHANGE_PROFILE, 0, dfaflags))
-                               return FALSE;
-               }
-       }
-@@ -631,10 +549,10 @@
-                       char *vec[2];
-                       vec[0] = entry->namespace;
-                       vec[1] = entry->name;
--                      if (!aare_add_rule_vec(dfarules, 0, mode, 0, 2, vec))
-+                      if (!aare_add_rule_vec(dfarules, 0, mode, 0, 2, vec, dfaflags))
-                           return FALSE;
-               } else {
--                      if (!aare_add_rule(dfarules, entry->name, 0, mode, 0))
-+                if (!aare_add_rule(dfarules, entry->name, 0, mode, 0, dfaflags))
-                               return FALSE;
-               }
-       }
-@@ -643,18 +561,13 @@
- int post_process_entries(struct codomain *cod)
- {
--      int ret = TRUE, rc;
-+      int ret = TRUE;
-       struct cod_entry *entry;
-       int count = 0;
-       list_for_each(cod->entries, entry) {
--              if (regex_type == AARE_DFA) {
--                      rc = process_dfa_entry(cod->dfarules, entry);
--              } else {
--                      filter_slashes(entry->name);
--                      rc = process_pcre_entry(entry);
--              }
--              if (!rc)
-+              if (regex_type == AARE_DFA &&
-+                  !process_dfa_entry(cod->dfarules, entry))
-                       ret = FALSE;
-               count++;
-       }
-@@ -770,7 +683,7 @@
-       test_string = strdup("///foo//////f//oo////////////////");
-       filter_slashes(test_string);
--      MY_TEST(strcmp(test_string, "/foo/f/oo") == 0, "simple tests");
-+      MY_TEST(strcmp(test_string, "/foo/f/oo/") == 0, "simple tests");
-       test_string = strdup("/foo/f/oo");
-       filter_slashes(test_string);
-@@ -802,13 +715,11 @@
-       test_string = strdup("/a/");
-       filter_slashes(test_string);
--      MY_TEST(strcmp(test_string, "/a") == 0, "simple test for /a/");
-+      MY_TEST(strcmp(test_string, "/a/") == 0, "simple test for /a/");
-       return rc;
- }
--int regex_type = AARE_PCRE;
--
- int main(void)
- {
-       int rc = 0;
-
-=== modified file 'parser/parser_symtab.c'
---- parser/parser_symtab.c     2009-07-24 13:24:53 +0000
-+++ parser/parser_symtab.c     2010-08-03 17:27:13 +0000
-@@ -23,6 +23,7 @@
- #include <string.h>
- #include <errno.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #define _(s) gettext(s)
- #include "immunix.h"
-@@ -33,11 +34,6 @@
-       sd_set,
- };
--struct set_value {
--      char *val;
--      struct set_value *next;
--};
--
- struct symtab {
-       char *var_name;
-       enum var_type type;
-@@ -288,7 +284,7 @@
- /* returns a pointer to the value list, which should be used as the
-  * argument to the get_next_set_value() function. */
--void *get_set_var(const char *var)
-+struct set_value *get_set_var(const char *var)
- {
-       struct symtab *result;
-       struct set_value *valuelist = NULL;
-@@ -321,16 +317,17 @@
- }
- /* iterator to walk the list of set values */
--char *get_next_set_value(void **list)
-+char *get_next_set_value(struct set_value **list)
- {
--      struct set_value **valuelist = (struct set_value **) list;
-+      struct set_value *next;
-       char *ret;
--      if (!valuelist || !(*valuelist))
-+      if (!list || !(*list))
-               return NULL;
--      ret = (*valuelist)->val;
--      (*valuelist) = (*valuelist)->next;
-+      ret = (*list)->val;
-+      next = (*list)->next;
-+      (*list) = next;
-       return ret;
- }
-@@ -429,10 +426,13 @@
-                       for (ref_item = ref->expanded; ref_item; ref_item = ref_item->next) {
-                               char *expanded_string;
--                              asprintf(&expanded_string, "%s%s%s",
-+                              if (!asprintf(&expanded_string, "%s%s%s",
-                                        split->prefix ?  split->prefix : "",
-                                        ref_item->val,
--                                       split->suffix ?  split->suffix : "");
-+                                       split->suffix ?  split->suffix : "")) {
-+                                      PERROR("Out of memory\n");
-+                                      exit(1);
-+                              }
-                               add_to_set(&work_list, expanded_string);
-                               free(expanded_string);
-                       }
-@@ -569,7 +569,7 @@
- {
-       int rc = 0;
-       int retval;
--      void *retptr;
-+      struct set_value *retptr;
-       struct symtab *a, *b;
-       a = new_symtab_entry("blah");
-
-=== modified file 'parser/parser_variable.c'
---- parser/parser_variable.c   2009-07-24 23:47:46 +0000
-+++ parser/parser_variable.c   2010-08-03 17:27:13 +0000
-@@ -17,10 +17,14 @@
-  *   along with this program; if not, contact Novell, Inc.
-  */
-+#include <ctype.h>
-+#include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <libintl.h>
-+#include <linux/limits.h>
-+
- #define _(s) gettext(s)
- /* #define DEBUG */
-@@ -124,7 +128,7 @@
- static int expand_entry_variables(struct cod_entry *entry)
- {
--      void *valuelist;
-+      struct set_value *valuelist;
-       int ret = TRUE;
-       char *value;
-       struct var_string *split_var;
-
-=== modified file 'parser/parser_yacc.y'
---- parser/parser_yacc.y       2010-02-17 20:21:52 +0000
-+++ parser/parser_yacc.y       2010-08-03 17:27:13 +0000
-@@ -1,9 +1,9 @@
- %{
--/* $Id$ */
--
- /*
-  *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-  *   NOVELL (All rights reserved)
-+ *   Copyright (c) 2010
-+ *   Canonical, Ltd.
-  *
-  *   This program is free software; you can redistribute it and/or
-  *   modify it under the terms of version 2 of the GNU General Public
-@@ -15,7 +15,7 @@
-  *   GNU General Public License for more details.
-  *
-  *   You should have received a copy of the GNU General Public License
-- *   along with this program; if not, contact Novell, Inc.
-+ *   along with this program; if not, contact Canonical, Ltd.
-  */
- #define YYERROR_VERBOSE 1
-@@ -32,6 +32,7 @@
- /* #define DEBUG */
- #include "parser.h"
-+#include "parser_include.h"
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-@@ -63,10 +64,6 @@
- #define CAP_TO_MASK(x) (1ull << (x))
--/* from lex_config, for nice error messages */
--/* extern char *current_file; */
--extern int current_lineno;
--
- struct value_list {
-       char *value;
-       struct value_list *next;
-@@ -415,7 +412,7 @@
- flagval:      TOK_FLAG_ID
-       {
--              struct flagval fv = {0, 0, 0};
-+              struct flagval fv = { 0, 0, 0, 0 };
-               if (strcmp($1, "debug") == 0) {
-                       yyerror(_("Profile flag 'debug' is no longer valid."));
-               } else if (strcmp($1, "complain") == 0) {
-@@ -1109,10 +1106,15 @@
-       va_end(arg);
-       if (profilename) {
--              PERROR(_("AppArmor parser error in %s at line %d: %s\n"),
--                     profilename, current_lineno, buf);
-+              PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
-+                     profilename,
-+                     current_filename ? " in " : "",
-+                     current_filename ? current_filename : "",
-+                     current_lineno, buf);
-       } else {
--              PERROR(_("AppArmor parser error, line %d: %s\n"),
-+              PERROR(_("AppArmor parser error,%s%s line %d: %s\n"),
-+                     current_filename ? " in " : "",
-+                     current_filename ? current_filename : "",
-                      current_lineno, buf);
-       }
-
-=== removed directory 'parser/pcre'
-=== removed file 'parser/pcre/Makefile'
---- parser/pcre/Makefile       2007-03-30 16:30:15 +0000
-+++ parser/pcre/Makefile       1970-01-01 00:00:00 +0000
-@@ -1,7 +0,0 @@
--all: pcre.o
--
--pcre.o:  pcre.c
--      $(CC) -c $(CFLAGS) $<
--
--clean:
--      rm -f pcre.o
-
-=== removed file 'parser/pcre/chartables.c'
---- parser/pcre/chartables.c   2006-04-11 21:52:54 +0000
-+++ parser/pcre/chartables.c   1970-01-01 00:00:00 +0000
-@@ -1,183 +0,0 @@
--/*************************************************
--*      Perl-Compatible Regular Expressions       *
--*************************************************/
--
--/* This file is automatically written by the dftables auxiliary 
--program. If you edit it by hand, you might like to edit the Makefile to 
--prevent its ever being regenerated.
--
--This file is #included in the compilation of pcre.c to build the default
--character tables which are used when no tables are passed to the compile
--function. */
--
--static unsigned char pcre_default_tables[] = {
--
--/* This table is a lower casing table. */
--
--    0,  1,  2,  3,  4,  5,  6,  7,
--    8,  9, 10, 11, 12, 13, 14, 15,
--   16, 17, 18, 19, 20, 21, 22, 23,
--   24, 25, 26, 27, 28, 29, 30, 31,
--   32, 33, 34, 35, 36, 37, 38, 39,
--   40, 41, 42, 43, 44, 45, 46, 47,
--   48, 49, 50, 51, 52, 53, 54, 55,
--   56, 57, 58, 59, 60, 61, 62, 63,
--   64, 97, 98, 99,100,101,102,103,
--  104,105,106,107,108,109,110,111,
--  112,113,114,115,116,117,118,119,
--  120,121,122, 91, 92, 93, 94, 95,
--   96, 97, 98, 99,100,101,102,103,
--  104,105,106,107,108,109,110,111,
--  112,113,114,115,116,117,118,119,
--  120,121,122,123,124,125,126,127,
--  128,129,130,131,132,133,134,135,
--  136,137,138,139,140,141,142,143,
--  144,145,146,147,148,149,150,151,
--  152,153,154,155,156,157,158,159,
--  160,161,162,163,164,165,166,167,
--  168,169,170,171,172,173,174,175,
--  176,177,178,179,180,181,182,183,
--  184,185,186,187,188,189,190,191,
--  192,193,194,195,196,197,198,199,
--  200,201,202,203,204,205,206,207,
--  208,209,210,211,212,213,214,215,
--  216,217,218,219,220,221,222,223,
--  224,225,226,227,228,229,230,231,
--  232,233,234,235,236,237,238,239,
--  240,241,242,243,244,245,246,247,
--  248,249,250,251,252,253,254,255,
--
--/* This table is a case flipping table. */
--
--    0,  1,  2,  3,  4,  5,  6,  7,
--    8,  9, 10, 11, 12, 13, 14, 15,
--   16, 17, 18, 19, 20, 21, 22, 23,
--   24, 25, 26, 27, 28, 29, 30, 31,
--   32, 33, 34, 35, 36, 37, 38, 39,
--   40, 41, 42, 43, 44, 45, 46, 47,
--   48, 49, 50, 51, 52, 53, 54, 55,
--   56, 57, 58, 59, 60, 61, 62, 63,
--   64, 97, 98, 99,100,101,102,103,
--  104,105,106,107,108,109,110,111,
--  112,113,114,115,116,117,118,119,
--  120,121,122, 91, 92, 93, 94, 95,
--   96, 65, 66, 67, 68, 69, 70, 71,
--   72, 73, 74, 75, 76, 77, 78, 79,
--   80, 81, 82, 83, 84, 85, 86, 87,
--   88, 89, 90,123,124,125,126,127,
--  128,129,130,131,132,133,134,135,
--  136,137,138,139,140,141,142,143,
--  144,145,146,147,148,149,150,151,
--  152,153,154,155,156,157,158,159,
--  160,161,162,163,164,165,166,167,
--  168,169,170,171,172,173,174,175,
--  176,177,178,179,180,181,182,183,
--  184,185,186,187,188,189,190,191,
--  192,193,194,195,196,197,198,199,
--  200,201,202,203,204,205,206,207,
--  208,209,210,211,212,213,214,215,
--  216,217,218,219,220,221,222,223,
--  224,225,226,227,228,229,230,231,
--  232,233,234,235,236,237,238,239,
--  240,241,242,243,244,245,246,247,
--  248,249,250,251,252,253,254,255,
--
--/* This table contains bit maps for various character classes.
--Each map is 32 bytes long and the bits run from the least
--significant end of each byte. The classes that have their own
--maps are: space, xdigit, digit, upper, lower, word, graph
--print, punct, and cntrl. Other classes are built from combinations. */
--
--  0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
--  0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
--  0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
--  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
--  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
--  0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--/* This table identifies various classes of character by individual bits:
--  0x01   white space character
--  0x02   letter
--  0x04   decimal digit
--  0x08   hexadecimal digit
--  0x10   alphanumeric or '_'
--  0x80   regular expression metacharacter or binary zero
--*/
--
--  0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
--  0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /*   8- 15 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
--  0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /*    - '  */
--  0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /*  ( - /  */
--  0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /*  0 - 7  */
--  0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /*  8 - ?  */
--  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  @ - G  */
--  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  H - O  */
--  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  P - W  */
--  0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /*  X - _  */
--  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  ` - g  */
--  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  h - o  */
--  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  p - w  */
--  0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /*  x -127 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
--  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
--
--/* End of chartables.c */
-
-=== removed file 'parser/pcre/config.h'
---- parser/pcre/config.h       2006-04-11 21:52:54 +0000
-+++ parser/pcre/config.h       1970-01-01 00:00:00 +0000
-@@ -1,48 +0,0 @@
--/* config.h.  Generated automatically by configure.  */
--
--/* On Unix systems config.in is converted by configure into config.h. PCRE is
--written in Standard C, but there are a few non-standard things it can cope
--with, allowing it to run on SunOS4 and other "close to standard" systems.
--
--On a non-Unix system you should just copy this file into config.h, and set up
--the macros the way you need them. You should normally change the definitions of
--HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf
--works, these cannot be made the defaults. If your system has bcopy() and not
--memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your
--system has neither bcopy() nor memmove(), leave them both as 0; an emulation
--function will be used. */
--
--/* Define to empty if the keyword does not work. */
--
--/* #undef const */
--
--/* Define to `unsigned' if <stddef.h> doesn't define size_t. */
--
--/* #undef size_t */
--
--/* The following two definitions are mainly for the benefit of SunOS4, which
--doesn't have the strerror() or memmove() functions that should be present in
--all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
--normally be defined with the value 1 for other systems, but unfortunately we
--can't make this the default because "configure" files generated by autoconf
--will only change 0 to 1; they won't change 1 to 0 if the functions are not
--found. */
--
--#define HAVE_STRERROR 1
--#define HAVE_MEMMOVE 1
--
--/* There are some non-Unix systems that don't even have bcopy(). If this macro
--is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
--HAVE_BCOPY is not relevant. */
--
--#define HAVE_BCOPY 1
--
--/* The value of NEWLINE determines the newline character. The default is to
--leave it up to the compiler, but some sites want to force a particular value.
--On Unix systems, "configure" can be used to override this default. */
--
--#ifndef NEWLINE
--#define NEWLINE '\n'
--#endif
--
--/* End */
-
-=== removed file 'parser/pcre/internal.h'
---- parser/pcre/internal.h     2006-04-11 21:52:54 +0000
-+++ parser/pcre/internal.h     1970-01-01 00:00:00 +0000
-@@ -1,412 +0,0 @@
--/*************************************************
--*      Perl-Compatible Regular Expressions       *
--*************************************************/
--
--
--/* This is a library of functions to support regular expressions whose syntax
--and semantics are as close as possible to those of the Perl 5 language. See
--the file Tech.Notes for some information on the internals.
--
--Written by: Philip Hazel <ph10@cam.ac.uk>
--
--           Copyright (c) 1997-2001 University of Cambridge
--
-------------------------------------------------------------------------------
--Permission is granted to anyone to use this software for any purpose on any
--computer system, and to redistribute it freely, subject to the following
--restrictions:
--
--1. This software is distributed in the hope that it will be useful,
--   but WITHOUT ANY WARRANTY; without even the implied warranty of
--   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--
--2. The origin of this software must not be misrepresented, either by
--   explicit claim or by omission.
--
--3. Altered versions must be plainly marked as such, and must not be
--   misrepresented as being the original software.
--
--4. If PCRE is embedded in any software that is released under the GNU
--   General Purpose Licence (GPL), then the terms of that licence shall
--   supersede any condition above with which it is incompatible.
-------------------------------------------------------------------------------
--*/
--
--/* This header contains definitions that are shared between the different
--modules, but which are not relevant to the outside. */
--
--/* Get the definitions provided by running "configure" */
--
--#include "config.h"
--
--/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(),
--define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY
--is set. Otherwise, include an emulating function for those systems that have
--neither (there some non-Unix environments where this is the case). This assumes
--that all calls to memmove are moving strings upwards in store, which is the
--case in PCRE. */
--
--#if ! HAVE_MEMMOVE
--#undef  memmove        /* some systems may have a macro */
--#if HAVE_BCOPY
--#define memmove(a, b, c) bcopy(b, a, c)
--#else
--void *
--pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n)
--{
--int i;
--dest += n;
--src += n;
--for (i = 0; i < n; ++i) *(--dest) =  *(--src);
--}
--#define memmove(a, b, c) pcre_memmove(a, b, c)
--#endif
--#endif
--
--/* Standard C headers plus the external interface definition */
--
--#include <ctype.h>
--#include <limits.h>
--#include <stddef.h>
--#include <stdio.h>
--#include <stdlib.h>
--#include <string.h>
--#include "pcre.h"
--
--/* In case there is no definition of offsetof() provided - though any proper
--Standard C system should have one. */
--
--#ifndef offsetof
--#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
--#endif
--
--/* These are the public options that can change during matching. */
--
--#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
--
--/* Private options flags start at the most significant end of the four bytes,
--but skip the top bit so we can use ints for convenience without getting tangled
--with negative values. The public options defined in pcre.h start at the least
--significant end. Make sure they don't overlap, though now that we have expanded
--to four bytes there is plenty of space. */
--
--#define PCRE_FIRSTSET      0x40000000  /* first_char is set */
--#define PCRE_REQCHSET      0x20000000  /* req_char is set */
--#define PCRE_STARTLINE     0x10000000  /* start after \n for multiline */
--#define PCRE_INGROUP       0x08000000  /* compiling inside a group */
--#define PCRE_ICHANGED      0x04000000  /* i option changes within regex */
--
--/* Options for the "extra" block produced by pcre_study(). */
--
--#define PCRE_STUDY_MAPPED   0x01     /* a map of starting chars exists */
--
--/* Masks for identifying the public options which are permitted at compile
--time, run time or study time, respectively. */
--
--#define PUBLIC_OPTIONS \
--  (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
--   PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8)
--
--#define PUBLIC_EXEC_OPTIONS \
--  (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY)
--
--#define PUBLIC_STUDY_OPTIONS 0   /* None defined */
--
--/* Magic number to provide a small check against being handed junk. */
--
--#define MAGIC_NUMBER  0x50435245UL   /* 'PCRE' */
--
--/* Miscellaneous definitions */
--
--typedef int BOOL;
--
--#define FALSE   0
--#define TRUE    1
--
--/* Escape items that are just an encoding of a particular data value. Note that
--ESC_N is defined as yet another macro, which is set in config.h to either \n
--(the default) or \r (which some people want). */
--
--#ifndef ESC_E
--#define ESC_E 27
--#endif
--
--#ifndef ESC_F
--#define ESC_F '\f'
--#endif
--
--#ifndef ESC_N
--#define ESC_N NEWLINE
--#endif
--
--#ifndef ESC_R
--#define ESC_R '\r'
--#endif
--
--#ifndef ESC_T
--#define ESC_T '\t'
--#endif
--
--/* These are escaped items that aren't just an encoding of a particular data
--value such as \n. They must have non-zero values, as check_escape() returns
--their negation. Also, they must appear in the same order as in the opcode
--definitions below, up to ESC_z. The final one must be ESC_REF as subsequent
--values are used for \1, \2, \3, etc. There is a test in the code for an escape
--greater than ESC_b and less than ESC_Z to detect the types that may be
--repeated. If any new escapes are put in-between that don't consume a character,
--that code will have to change. */
--
--enum { ESC_A = 1, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w,
--       ESC_Z, ESC_z, ESC_REF };
--
--/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
--that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
--OP_EOD must correspond in order to the list of escapes immediately above. */
--
--enum {
--  OP_END,            /* End of pattern */
--
--  /* Values corresponding to backslashed metacharacters */
--
--  OP_SOD,            /* Start of data: \A */
--  OP_NOT_WORD_BOUNDARY,  /* \B */
--  OP_WORD_BOUNDARY,      /* \b */
--  OP_NOT_DIGIT,          /* \D */
--  OP_DIGIT,              /* \d */
--  OP_NOT_WHITESPACE,     /* \S */
--  OP_WHITESPACE,         /* \s */
--  OP_NOT_WORDCHAR,       /* \W */
--  OP_WORDCHAR,           /* \w */
--  OP_EODN,           /* End of data or \n at end of data: \Z. */
--  OP_EOD,            /* End of data: \z */
--
--  OP_OPT,            /* Set runtime options */
--  OP_CIRC,           /* Start of line - varies with multiline switch */
--  OP_DOLL,           /* End of line - varies with multiline switch */
--  OP_ANY,            /* Match any character */
--  OP_CHARS,          /* Match string of characters */
--  OP_NOT,            /* Match anything but the following char */
--
--  OP_STAR,           /* The maximizing and minimizing versions of */
--  OP_MINSTAR,        /* all these opcodes must come in pairs, with */
--  OP_PLUS,           /* the minimizing one second. */
--  OP_MINPLUS,        /* This first set applies to single characters */
--  OP_QUERY,
--  OP_MINQUERY,
--  OP_UPTO,           /* From 0 to n matches */
--  OP_MINUPTO,
--  OP_EXACT,          /* Exactly n matches */
--
--  OP_NOTSTAR,        /* The maximizing and minimizing versions of */
--  OP_NOTMINSTAR,     /* all these opcodes must come in pairs, with */
--  OP_NOTPLUS,        /* the minimizing one second. */
--  OP_NOTMINPLUS,     /* This first set applies to "not" single characters */
--  OP_NOTQUERY,
--  OP_NOTMINQUERY,
--  OP_NOTUPTO,        /* From 0 to n matches */
--  OP_NOTMINUPTO,
--  OP_NOTEXACT,       /* Exactly n matches */
--
--  OP_TYPESTAR,       /* The maximizing and minimizing versions of */
--  OP_TYPEMINSTAR,    /* all these opcodes must come in pairs, with */
--  OP_TYPEPLUS,       /* the minimizing one second. These codes must */
--  OP_TYPEMINPLUS,    /* be in exactly the same order as those above. */
--  OP_TYPEQUERY,      /* This set applies to character types such as \d */
--  OP_TYPEMINQUERY,
--  OP_TYPEUPTO,       /* From 0 to n matches */
--  OP_TYPEMINUPTO,
--  OP_TYPEEXACT,      /* Exactly n matches */
--
--  OP_CRSTAR,         /* The maximizing and minimizing versions of */
--  OP_CRMINSTAR,      /* all these opcodes must come in pairs, with */
--  OP_CRPLUS,         /* the minimizing one second. These codes must */
--  OP_CRMINPLUS,      /* be in exactly the same order as those above. */
--  OP_CRQUERY,        /* These are for character classes and back refs */
--  OP_CRMINQUERY,
--  OP_CRRANGE,        /* These are different to the three seta above. */
--  OP_CRMINRANGE,
--
--  OP_CLASS,          /* Match a character class */
--  OP_REF,            /* Match a back reference */
--  OP_RECURSE,        /* Match this pattern recursively */
--
--  OP_ALT,            /* Start of alternation */
--  OP_KET,            /* End of group that doesn't have an unbounded repeat */
--  OP_KETRMAX,        /* These two must remain together and in this */
--  OP_KETRMIN,        /* order. They are for groups the repeat for ever. */
--
--  /* The assertions must come before ONCE and COND */
--
--  OP_ASSERT,         /* Positive lookahead */
--  OP_ASSERT_NOT,     /* Negative lookahead */
--  OP_ASSERTBACK,     /* Positive lookbehind */
--  OP_ASSERTBACK_NOT, /* Negative lookbehind */
--  OP_REVERSE,        /* Move pointer back - used in lookbehind assertions */
--
--  /* ONCE and COND must come after the assertions, with ONCE first, as there's
--  a test for >= ONCE for a subpattern that isn't an assertion. */
--
--  OP_ONCE,           /* Once matched, don't back up into the subpattern */
--  OP_COND,           /* Conditional group */
--  OP_CREF,           /* Used to hold an extraction string number (cond ref) */
--
--  OP_BRAZERO,        /* These two must remain together and in this */
--  OP_BRAMINZERO,     /* order. */
--
--  OP_BRANUMBER,      /* Used for extracting brackets whose number is greater
--                        than can fit into an opcode. */
--
--  OP_BRA             /* This and greater values are used for brackets that
--                        extract substrings up to a basic limit. After that,
--                        use is made of OP_BRANUMBER. */
--};
--
--/* The highest extraction number before we have to start using additional
--bytes. (Originally PCRE didn't have support for extraction counts highter than
--this number.) The value is limited by the number of opcodes left after OP_BRA,
--i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
--opcodes. */
--
--#define EXTRACT_BASIC_MAX  150
--
--/* The texts of compile-time error messages are defined as macros here so that
--they can be accessed by the POSIX wrapper and converted into error codes.  Yes,
--I could have used error codes in the first place, but didn't feel like changing
--just to accommodate the POSIX wrapper. */
--
--#define ERR1  "\\ at end of pattern"
--#define ERR2  "\\c at end of pattern"
--#define ERR3  "unrecognized character follows \\"
--#define ERR4  "numbers out of order in {} quantifier"
--#define ERR5  "number too big in {} quantifier"
--#define ERR6  "missing terminating ] for character class"
--#define ERR7  "invalid escape sequence in character class"
--#define ERR8  "range out of order in character class"
--#define ERR9  "nothing to repeat"
--#define ERR10 "operand of unlimited repeat could match the empty string"
--#define ERR11 "internal error: unexpected repeat"
--#define ERR12 "unrecognized character after (?"
--#define ERR13 "unused error"
--#define ERR14 "missing )"
--#define ERR15 "back reference to non-existent subpattern"
--#define ERR16 "erroffset passed as NULL"
--#define ERR17 "unknown option bit(s) set"
--#define ERR18 "missing ) after comment"
--#define ERR19 "parentheses nested too deeply"
--#define ERR20 "regular expression too large"
--#define ERR21 "failed to get memory"
--#define ERR22 "unmatched parentheses"
--#define ERR23 "internal error: code overflow"
--#define ERR24 "unrecognized character after (?<"
--#define ERR25 "lookbehind assertion is not fixed length"
--#define ERR26 "malformed number after (?("
--#define ERR27 "conditional group contains more than two branches"
--#define ERR28 "assertion expected after (?("
--#define ERR29 "(?p must be followed by )"
--#define ERR30 "unknown POSIX class name"
--#define ERR31 "POSIX collating elements are not supported"
--#define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support"
--#define ERR33 "characters with values > 255 are not yet supported in classes"
--#define ERR34 "character value in \\x{...} sequence is too large"
--#define ERR35 "invalid condition (?(0)"
--
--/* All character handling must be done as unsigned characters. Otherwise there
--are problems with top-bit-set characters and functions such as isspace().
--However, we leave the interface to the outside world as char *, because that
--should make things easier for callers. We define a short type for unsigned char
--to save lots of typing. I tried "uchar", but it causes problems on Digital
--Unix, where it is defined in sys/types, so use "uschar" instead. */
--
--typedef unsigned char uschar;
--
--/* The real format of the start of the pcre block; the actual code vector
--runs on as long as necessary after the end. */
--
--typedef struct real_pcre {
--  unsigned long int magic_number;
--  size_t size;
--  const unsigned char *tables;
--  unsigned long int options;
--  unsigned short int top_bracket;
--  unsigned short int top_backref;
--  uschar first_char;
--  uschar req_char;
--  uschar code[1];
--} real_pcre;
--
--/* The real format of the extra block returned by pcre_study(). */
--
--typedef struct real_pcre_extra {
--  uschar options;
--  uschar start_bits[32];
--} real_pcre_extra;
--
--
--/* Structure for passing "static" information around between the functions
--doing the compiling, so that they are thread-safe. */
--
--typedef struct compile_data {
--  const uschar *lcc;            /* Points to lower casing table */
--  const uschar *fcc;            /* Points to case-flipping table */
--  const uschar *cbits;          /* Points to character type table */
--  const uschar *ctypes;         /* Points to table of type maps */
--} compile_data;
--
--/* Structure for passing "static" information around between the functions
--doing the matching, so that they are thread-safe. */
--
--typedef struct match_data {
--  int    errorcode;             /* As it says */
--  int   *offset_vector;         /* Offset vector */
--  int    offset_end;            /* One past the end */
--  int    offset_max;            /* The maximum usable for return data */
--  const uschar *lcc;            /* Points to lower casing table */
--  const uschar *ctypes;         /* Points to table of type maps */
--  BOOL   offset_overflow;       /* Set if too many extractions */
--  BOOL   notbol;                /* NOTBOL flag */
--  BOOL   noteol;                /* NOTEOL flag */
--  BOOL   utf8;                  /* UTF8 flag */
--  BOOL   endonly;               /* Dollar not before final \n */
--  BOOL   notempty;              /* Empty string match not wanted */
--  const uschar *start_pattern;  /* For use when recursing */
--  const uschar *start_subject;  /* Start of the subject string */
--  const uschar *end_subject;    /* End of the subject string */
--  const uschar *start_match;    /* Start of this match attempt */
--  const uschar *end_match_ptr;  /* Subject position at end match */
--  int    end_offset_top;        /* Highwater mark at end of match */
--} match_data;
--
--/* Bit definitions for entries in the pcre_ctypes table. */
--
--#define ctype_space   0x01
--#define ctype_letter  0x02
--#define ctype_digit   0x04
--#define ctype_xdigit  0x08
--#define ctype_word    0x10   /* alphameric or '_' */
--#define ctype_meta    0x80   /* regexp meta char or zero (end pattern) */
--
--/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
--of bits for a class map. Some classes are built by combining these tables. */
--
--#define cbit_space     0      /* [:space:] or \s */
--#define cbit_xdigit   32      /* [:xdigit:] */
--#define cbit_digit    64      /* [:digit:] or \d */
--#define cbit_upper    96      /* [:upper:] */
--#define cbit_lower   128      /* [:lower:] */
--#define cbit_word    160      /* [:word:] or \w */
--#define cbit_graph   192      /* [:graph:] */
--#define cbit_print   224      /* [:print:] */
--#define cbit_punct   256      /* [:punct:] */
--#define cbit_cntrl   288      /* [:cntrl:] */
--#define cbit_length  320      /* Length of the cbits table */
--
--/* Offsets of the various tables from the base tables pointer, and
--total length. */
--
--#define lcc_offset      0
--#define fcc_offset    256
--#define cbits_offset  512
--#define ctypes_offset (cbits_offset + cbit_length)
--#define tables_length (ctypes_offset + 256)
--
--/* End of internal.h */
-
-=== removed file 'parser/pcre/pcre.c'
---- parser/pcre/pcre.c 2006-04-11 21:52:54 +0000
-+++ parser/pcre/pcre.c 1970-01-01 00:00:00 +0000
-@@ -1,5187 +0,0 @@
--/*************************************************
--*      Perl-Compatible Regular Expressions       *
--*************************************************/
--
--/*
--This is a library of functions to support regular expressions whose syntax
--and semantics are as close as possible to those of the Perl 5 language. See
--the file Tech.Notes for some information on the internals.
--
--Written by: Philip Hazel <ph10@cam.ac.uk>
--
--           Copyright (c) 1997-2001 University of Cambridge
--
-------------------------------------------------------------------------------
--Permission is granted to anyone to use this software for any purpose on any
--computer system, and to redistribute it freely, subject to the following
--restrictions:
--
--1. This software is distributed in the hope that it will be useful,
--   but WITHOUT ANY WARRANTY; without even the implied warranty of
--   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--
--2. The origin of this software must not be misrepresented, either by
--   explicit claim or by omission.
--
--3. Altered versions must be plainly marked as such, and must not be
--   misrepresented as being the original software.
--
--4. If PCRE is embedded in any software that is released under the GNU
--   General Purpose Licence (GPL), then the terms of that licence shall
--   supersede any condition above with which it is incompatible.
-------------------------------------------------------------------------------
--*/
--
--
--/* Define DEBUG to get debugging output on stdout. */
--
--/* #define DEBUG */
--
--/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
--inline, and there are *still* stupid compilers about that don't like indented
--pre-processor statements. I suppose it's only been 10 years... */
--
--#ifdef DEBUG
--#define DPRINTF(p) printf p
--#else
--#define DPRINTF(p) /*nothing*/
--#endif
--
--/* Include the internals header, which itself includes Standard C headers plus
--the external pcre header. */
--
--#include "internal.h"
--
--
--/* Allow compilation as C++ source code, should anybody want to do that. */
--
--#ifdef __cplusplus
--#define class pcre_class
--#endif
--
--
--/* Maximum number of items on the nested bracket stacks at compile time. This
--applies to the nesting of all kinds of parentheses. It does not limit
--un-nested, non-capturing parentheses. This number can be made bigger if
--necessary - it is used to dimension one int and one unsigned char vector at
--compile time. */
--
--#define BRASTACK_SIZE 200
--
--
--/* The number of bytes in a literal character string above which we can't add
--any more is different when UTF-8 characters may be encountered. */
--
--#ifdef SUPPORT_UTF8
--#define MAXLIT 250
--#else
--#define MAXLIT 255
--#endif
--
--
--/* Min and max values for the common repeats; for the maxima, 0 => infinity */
--
--static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
--static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
--
--/* Text forms of OP_ values and things, for debugging (not all used) */
--
--#ifdef DEBUG
--static const char *OP_names[] = {
--  "End", "\\A", "\\B", "\\b", "\\D", "\\d",
--  "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z",
--  "Opt", "^", "$", "Any", "chars", "not",
--  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
--  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
--  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
--  "*", "*?", "+", "+?", "?", "??", "{", "{",
--  "class", "Ref", "Recurse",
--  "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not",
--  "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref",
--  "Brazero", "Braminzero", "Branumber", "Bra"
--};
--#endif
--
--/* Table for handling escaped characters in the range '0'-'z'. Positive returns
--are simple data values; negative values are for special things like \d and so
--on. Zero means further processing is needed (for things like \x), or the escape
--is invalid. */
--
--static const short int escapes[] = {
--    0,      0,      0,      0,      0,      0,      0,      0,   /* 0 - 7 */
--    0,      0,    ':',    ';',    '<',    '=',    '>',    '?',   /* 8 - ? */
--  '@', -ESC_A, -ESC_B,      0, -ESC_D,      0,      0,      0,   /* @ - G */
--    0,      0,      0,      0,      0,      0,      0,      0,   /* H - O */
--    0,      0,      0, -ESC_S,      0,      0,      0, -ESC_W,   /* P - W */
--    0,      0, -ESC_Z,    '[',   '\\',    ']',    '^',    '_',   /* X - _ */
--  '`',      7, -ESC_b,      0, -ESC_d,  ESC_E,  ESC_F,      0,   /* ` - g */
--    0,      0,      0,      0,      0,      0,  ESC_N,      0,   /* h - o */
--    0,      0,  ESC_R, -ESC_s,  ESC_T,      0,      0, -ESC_w,   /* p - w */
--    0,      0, -ESC_z                                            /* x - z */
--};
--
--/* Tables of names of POSIX character classes and their lengths. The list is
--terminated by a zero length entry. The first three must be alpha, upper, lower,
--as this is assumed for handling case independence. */
--
--static const char *posix_names[] = {
--  "alpha", "lower", "upper",
--  "alnum", "ascii", "cntrl", "digit", "graph",
--  "print", "punct", "space", "word",  "xdigit" };
--
--static const uschar posix_name_lengths[] = {
--  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
--
--/* Table of class bit maps for each POSIX class; up to three may be combined
--to form the class. */
--
--static const int posix_class_maps[] = {
--  cbit_lower, cbit_upper, -1,             /* alpha */
--  cbit_lower, -1,         -1,             /* lower */
--  cbit_upper, -1,         -1,             /* upper */
--  cbit_digit, cbit_lower, cbit_upper,     /* alnum */
--  cbit_print, cbit_cntrl, -1,             /* ascii */
--  cbit_cntrl, -1,         -1,             /* cntrl */
--  cbit_digit, -1,         -1,             /* digit */
--  cbit_graph, -1,         -1,             /* graph */
--  cbit_print, -1,         -1,             /* print */
--  cbit_punct, -1,         -1,             /* punct */
--  cbit_space, -1,         -1,             /* space */
--  cbit_word,  -1,         -1,             /* word */
--  cbit_xdigit,-1,         -1              /* xdigit */
--};
--
--
--/* Definition to allow mutual recursion */
--
--static BOOL
--  compile_regex(int, int, int *, uschar **, const uschar **, const char **,
--    BOOL, int, int *, int *, compile_data *);
--
--/* Structure for building a chain of data that actually lives on the
--stack, for holding the values of the subject pointer at the start of each
--subpattern, so as to detect when an empty string has been matched by a
--subpattern - to break infinite loops. */
--
--typedef struct eptrblock {
--  struct eptrblock *prev;
--  const uschar *saved_eptr;
--} eptrblock;
--
--/* Flag bits for the match() function */
--
--#define match_condassert   0x01    /* Called to check a condition assertion */
--#define match_isgroup      0x02    /* Set if start of bracketed group */
--
--
--
--/*************************************************
--*               Global variables                 *
--*************************************************/
--
--/* PCRE is thread-clean and doesn't use any global variables in the normal
--sense. However, it calls memory allocation and free functions via the two
--indirections below, which are can be changed by the caller, but are shared
--between all threads. */
--
--void *(*pcre_malloc)(size_t) = malloc;
--void  (*pcre_free)(void *) = free;
--
--
--
--/*************************************************
--*    Macros and tables for character handling    *
--*************************************************/
--
--/* When UTF-8 encoding is being used, a character is no longer just a single
--byte. The macros for character handling generate simple sequences when used in
--byte-mode, and more complicated ones for UTF-8 characters. */
--
--#ifndef SUPPORT_UTF8
--#define GETCHARINC(c, eptr) c = *eptr++;
--#define GETCHARLEN(c, eptr, len) c = *eptr;
--#define BACKCHAR(eptr)
--
--#else   /* SUPPORT_UTF8 */
--
--/* Get the next UTF-8 character, advancing the pointer */
--
--#define GETCHARINC(c, eptr) \
--  c = *eptr++; \
--  if (md->utf8 && (c & 0xc0) == 0xc0) \
--    { \
--    int a = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
--    int s = 6*a; \
--    c = (c & utf8_table3[a]) << s; \
--    while (a-- > 0) \
--      { \
--      s -= 6; \
--      c |= (*eptr++ & 0x3f) << s; \
--      } \
--    }
--
--/* Get the next UTF-8 character, not advancing the pointer, setting length */
--
--#define GETCHARLEN(c, eptr, len) \
--  c = *eptr; \
--  len = 1; \
--  if (md->utf8 && (c & 0xc0) == 0xc0) \
--    { \
--    int i; \
--    int a = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
--    int s = 6*a; \
--    c = (c & utf8_table3[a]) << s; \
--    for (i = 1; i <= a; i++) \
--      { \
--      s -= 6; \
--      c |= (eptr[i] & 0x3f) << s; \
--      } \
--    len += a; \
--    }
--
--/* If the pointer is not at the start of a character, move it back until
--it is. */
--
--#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--;
--
--#endif
--
--
--
--/*************************************************
--*             Default character tables           *
--*************************************************/
--
--/* A default set of character tables is included in the PCRE binary. Its source
--is built by the maketables auxiliary program, which uses the default C ctypes
--functions, and put in the file chartables.c. These tables are used by PCRE
--whenever the caller of pcre_compile() does not provide an alternate set of
--tables. */
--
--#include "chartables.c"
--
--
--
--#ifdef SUPPORT_UTF8
--/*************************************************
--*           Tables for UTF-8 support             *
--*************************************************/
--
--/* These are the breakpoints for different numbers of bytes in a UTF-8
--character. */
--
--static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
--
--/* These are the indicator bits and the mask for the data bits to set in the
--first byte of a character, indexed by the number of additional bytes. */
--
--static int utf8_table2[] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
--static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
--
--/* Table of the number of extra characters, indexed by the first character
--masked with 0x3f. The highest number for a valid UTF-8 character is in fact
--0x3d. */
--
--static uschar utf8_table4[] = {
--  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
--  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
--  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
--  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
--
--
--/*************************************************
--*       Convert character value to UTF-8         *
--*************************************************/
--
--/* This function takes an integer value in the range 0 - 0x7fffffff
--and encodes it as a UTF-8 character in 0 to 6 bytes.
--
--Arguments:
--  cvalue     the character value
--  buffer     pointer to buffer for result - at least 6 bytes long
--
--Returns:     number of characters placed in the buffer
--*/
--
--static int
--ord2utf8(int cvalue, uschar *buffer)
--{
--register int i, j;
--for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
--  if (cvalue <= utf8_table1[i]) break;
--buffer += i;
--for (j = i; j > 0; j--)
-- {
-- *buffer-- = 0x80 | (cvalue & 0x3f);
-- cvalue >>= 6;
-- }
--*buffer = utf8_table2[i] | cvalue;
--return i + 1;
--}
--#endif
--
--
--
--/*************************************************
--*          Return version string                 *
--*************************************************/
--
--#define STRING(a)  # a
--#define XSTRING(s) STRING(s)
--
--const char *
--pcre_version(void)
--{
--return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
--}
--
--
--
--
--/*************************************************
--* (Obsolete) Return info about compiled pattern  *
--*************************************************/
--
--/* This is the original "info" function. It picks potentially useful data out
--of the private structure, but its interface was too rigid. It remains for
--backwards compatibility. The public options are passed back in an int - though
--the re->options field has been expanded to a long int, all the public options
--at the low end of it, and so even on 16-bit systems this will still be OK.
--Therefore, I haven't changed the API for pcre_info().
--
--Arguments:
--  external_re   points to compiled code
--  optptr        where to pass back the options
--  first_char    where to pass back the first character,
--                or -1 if multiline and all branches start ^,
--                or -2 otherwise
--
--Returns:        number of capturing subpatterns
--                or negative values on error
--*/
--
--int
--pcre_info(const pcre *external_re, int *optptr, int *first_char)
--{
--const real_pcre *re = (const real_pcre *)external_re;
--if (re == NULL) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS);
--if (first_char != NULL)
--  *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
--     ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
--return re->top_bracket;
--}
--
--
--
--/*************************************************
--*        Return info about compiled pattern      *
--*************************************************/
--
--/* This is a newer "info" function which has an extensible interface so
--that additional items can be added compatibly.
--
--Arguments:
--  external_re      points to compiled code
--  external_study   points to study data, or NULL
--  what             what information is required
--  where            where to put the information
--
--Returns:           0 if data returned, negative on error
--*/
--
--int
--pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what,
--  void *where)
--{
--const real_pcre *re = (const real_pcre *)external_re;
--const real_pcre_extra *study = (const real_pcre_extra *)study_data;
--
--if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--
--switch (what)
--  {
--  case PCRE_INFO_OPTIONS:
--  *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS;
--  break;
--
--  case PCRE_INFO_SIZE:
--  *((size_t *)where) = re->size;
--  break;
--
--  case PCRE_INFO_CAPTURECOUNT:
--  *((int *)where) = re->top_bracket;
--  break;
--
--  case PCRE_INFO_BACKREFMAX:
--  *((int *)where) = re->top_backref;
--  break;
--
--  case PCRE_INFO_FIRSTCHAR:
--  *((int *)where) =
--    ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
--    ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
--  break;
--
--  case PCRE_INFO_FIRSTTABLE:
--  *((const uschar **)where) =
--    (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)?
--      study->start_bits : NULL;
--  break;
--
--  case PCRE_INFO_LASTLITERAL:
--  *((int *)where) =
--    ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1;
--  break;
--
--  default: return PCRE_ERROR_BADOPTION;
--  }
--
--return 0;
--}
--
--
--
--#ifdef DEBUG
--/*************************************************
--*        Debugging function to print chars       *
--*************************************************/
--
--/* Print a sequence of chars in printable format, stopping at the end of the
--subject if the requested.
--
--Arguments:
--  p           points to characters
--  length      number to print
--  is_subject  TRUE if printing from within md->start_subject
--  md          pointer to matching data block, if is_subject is TRUE
--
--Returns:     nothing
--*/
--
--static void
--pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
--{
--int c;
--if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
--while (length-- > 0)
--  if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c);
--}
--#endif
--
--
--
--
--/*************************************************
--*            Handle escapes                      *
--*************************************************/
--
--/* This function is called when a \ has been encountered. It either returns a
--positive value for a simple escape such as \n, or a negative value which
--encodes one of the more complicated things such as \d. When UTF-8 is enabled,
--a positive value greater than 255 may be returned. On entry, ptr is pointing at
--the \. On exit, it is on the final character of the escape sequence.
--
--Arguments:
--  ptrptr     points to the pattern position pointer
--  errorptr   points to the pointer to the error message
--  bracount   number of previous extracting brackets
--  options    the options bits
--  isclass    TRUE if inside a character class
--  cd         pointer to char tables block
--
--Returns:     zero or positive => a data character
--             negative => a special escape sequence
--             on error, errorptr is set
--*/
--
--static int
--check_escape(const uschar **ptrptr, const char **errorptr, int bracount,
--  int options, BOOL isclass, compile_data *cd)
--{
--const uschar *ptr = *ptrptr;
--int c, i;
--
--/* If backslash is at the end of the pattern, it's an error. */
--
--c = *(++ptr);
--if (c == 0) *errorptr = ERR1;
--
--/* Digits or letters may have special meaning; all others are literals. */
--
--else if (c < '0' || c > 'z') {}
--
--/* Do an initial lookup in a table. A non-zero result is something that can be
--returned immediately. Otherwise further processing may be required. */
--
--else if ((i = escapes[c - '0']) != 0) c = i;
--
--/* Escapes that need further processing, or are illegal. */
--
--else
--  {
--  const uschar *oldptr;
--  switch (c)
--    {
--    /* The handling of escape sequences consisting of a string of digits
--    starting with one that is not zero is not straightforward. By experiment,
--    the way Perl works seems to be as follows:
--
--    Outside a character class, the digits are read as a decimal number. If the
--    number is less than 10, or if there are that many previous extracting
--    left brackets, then it is a back reference. Otherwise, up to three octal
--    digits are read to form an escaped byte. Thus \123 is likely to be octal
--    123 (cf \0123, which is octal 012 followed by the literal 3). If the octal
--    value is greater than 377, the least significant 8 bits are taken. Inside a
--    character class, \ followed by a digit is always an octal number. */
--
--    case '1': case '2': case '3': case '4': case '5':
--    case '6': case '7': case '8': case '9':
--
--    if (!isclass)
--      {
--      oldptr = ptr;
--      c -= '0';
--      while ((cd->ctypes[ptr[1]] & ctype_digit) != 0)
--        c = c * 10 + *(++ptr) - '0';
--      if (c < 10 || c <= bracount)
--        {
--        c = -(ESC_REF + c);
--        break;
--        }
--      ptr = oldptr;      /* Put the pointer back and fall through */
--      }
--
--    /* Handle an octal number following \. If the first digit is 8 or 9, Perl
--    generates a binary zero byte and treats the digit as a following literal.
--    Thus we have to pull back the pointer by one. */
--
--    if ((c = *ptr) >= '8')
--      {
--      ptr--;
--      c = 0;
--      break;
--      }
--
--    /* \0 always starts an octal number, but we may drop through to here with a
--    larger first octal digit. */
--
--    case '0':
--    c -= '0';
--    while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 &&
--      ptr[1] != '8' && ptr[1] != '9')
--        c = c * 8 + *(++ptr) - '0';
--    c &= 255;     /* Take least significant 8 bits */
--    break;
--
--    /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number
--    which can be greater than 0xff, but only if the ddd are hex digits. */
--
--    case 'x':
--#ifdef SUPPORT_UTF8
--    if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
--      {
--      const uschar *pt = ptr + 2;
--      register int count = 0;
--      c = 0;
--      while ((cd->ctypes[*pt] & ctype_xdigit) != 0)
--        {
--        count++;
--        c = c * 16 + cd->lcc[*pt] -
--          (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W');
--        pt++;
--        }
--      if (*pt == '}')
--        {
--        if (c < 0 || count > 8) *errorptr = ERR34;
--        ptr = pt;
--        break;
--        }
--      /* If the sequence of hex digits does not end with '}', then we don't
--      recognize this construct; fall through to the normal \x handling. */
--      }
--#endif
--
--    /* Read just a single hex char */
--
--    c = 0;
--    while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0)
--      {
--      ptr++;
--      c = c * 16 + cd->lcc[*ptr] -
--        (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W');
--      }
--    break;
--
--    /* Other special escapes not starting with a digit are straightforward */
--
--    case 'c':
--    c = *(++ptr);
--    if (c == 0)
--      {
--      *errorptr = ERR2;
--      return 0;
--      }
--
--    /* A letter is upper-cased; then the 0x40 bit is flipped */
--
--    if (c >= 'a' && c <= 'z') c = cd->fcc[c];
--    c ^= 0x40;
--    break;
--
--    /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
--    other alphameric following \ is an error if PCRE_EXTRA was set; otherwise,
--    for Perl compatibility, it is a literal. This code looks a bit odd, but
--    there used to be some cases other than the default, and there may be again
--    in future, so I haven't "optimized" it. */
--
--    default:
--    if ((options & PCRE_EXTRA) != 0) switch(c)
--      {
--      default:
--      *errorptr = ERR3;
--      break;
--      }
--    break;
--    }
--  }
--
--*ptrptr = ptr;
--return c;
--}
--
--
--
--/*************************************************
--*            Check for counted repeat            *
--*************************************************/
--
--/* This function is called when a '{' is encountered in a place where it might
--start a quantifier. It looks ahead to see if it really is a quantifier or not.
--It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
--where the ddds are digits.
--
--Arguments:
--  p         pointer to the first char after '{'
--  cd        pointer to char tables block
--
--Returns:    TRUE or FALSE
--*/
--
--static BOOL
--is_counted_repeat(const uschar *p, compile_data *cd)
--{
--if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
--while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
--if (*p == '}') return TRUE;
--
--if (*p++ != ',') return FALSE;
--if (*p == '}') return TRUE;
--
--if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
--while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
--return (*p == '}');
--}
--
--
--
--/*************************************************
--*         Read repeat counts                     *
--*************************************************/
--
--/* Read an item of the form {n,m} and return the values. This is called only
--after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
--so the syntax is guaranteed to be correct, but we need to check the values.
--
--Arguments:
--  p          pointer to first char after '{'
--  minp       pointer to int for min
--  maxp       pointer to int for max
--             returned as -1 if no max
--  errorptr   points to pointer to error message
--  cd         pointer to character tables clock
--
--Returns:     pointer to '}' on success;
--             current ptr on error, with errorptr set
--*/
--
--static const uschar *
--read_repeat_counts(const uschar *p, int *minp, int *maxp,
--  const char **errorptr, compile_data *cd)
--{
--int min = 0;
--int max = -1;
--
--/* Read the minimum value and do a paranoid check: a negative value indicates
--an integer overflow. */
--
--while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
--
--if (min < 0 || min > 65535) {
--  *errorptr = ERR5;
--  return p;
--}
--/* Read the maximum value if there is one, and again do a paranoid on its size.
--Also, max must not be less than min. */
--
--if (*p == '}') max = min; else
--  {
--  if (*(++p) != '}')
--    {
--    max = 0;
--    while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
--    if (max < 0 || max > 65535)
--      {
--      *errorptr = ERR5;
--      return p;
--      }
--    if (max < min)
--      {
--      *errorptr = ERR4;
--      return p;
--      }
--    }
--  }
--
--/* Fill in the required variables, and pass back the pointer to the terminating
--'}'. */
--
--*minp = min;
--*maxp = max;
--return p;
--}
--
--
--
--/*************************************************
--*        Find the fixed length of a pattern      *
--*************************************************/
--
--/* Scan a pattern and compute the fixed length of subject that will match it,
--if the length is fixed. This is needed for dealing with backward assertions.
--
--Arguments:
--  code     points to the start of the pattern (the bracket)
--  options  the compiling options
--
--Returns:   the fixed length, or -1 if there is no fixed length
--*/
--
--static int
--find_fixedlength(uschar *code, int options)
--{
--int length = -1;
--
--register int branchlength = 0;
--register uschar *cc = code + 3;
--
--/* Scan along the opcodes for this branch. If we get to the end of the
--branch, check the length against that of the other branches. */
--
--for (;;)
--  {
--  int d;
--  register int op = *cc;
--  if (op >= OP_BRA) op = OP_BRA;
--
--  switch (op)
--    {
--    case OP_BRA:
--    case OP_ONCE:
--    case OP_COND:
--    d = find_fixedlength(cc, options);
--    if (d < 0) return -1;
--    branchlength += d;
--    do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
--    cc += 3;
--    break;
--
--    /* Reached end of a branch; if it's a ket it is the end of a nested
--    call. If it's ALT it is an alternation in a nested call. If it is
--    END it's the end of the outer call. All can be handled by the same code. */
--
--    case OP_ALT:
--    case OP_KET:
--    case OP_KETRMAX:
--    case OP_KETRMIN:
--    case OP_END:
--    if (length < 0) length = branchlength;
--      else if (length != branchlength) return -1;
--    if (*cc != OP_ALT) return length;
--    cc += 3;
--    branchlength = 0;
--    break;
--
--    /* Skip over assertive subpatterns */
--
--    case OP_ASSERT:
--    case OP_ASSERT_NOT:
--    case OP_ASSERTBACK:
--    case OP_ASSERTBACK_NOT:
--    do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
--    cc += 3;
--    break;
--
--    /* Skip over things that don't match chars */
--
--    case OP_REVERSE:
--    case OP_BRANUMBER:
--    case OP_CREF:
--    cc++;
--    /* Fall through */
--
--    case OP_OPT:
--    cc++;
--    /* Fall through */
--
--    case OP_SOD:
--    case OP_EOD:
--    case OP_EODN:
--    case OP_CIRC:
--    case OP_DOLL:
--    case OP_NOT_WORD_BOUNDARY:
--    case OP_WORD_BOUNDARY:
--    cc++;
--    break;
--
--    /* Handle char strings. In UTF-8 mode we must count characters, not bytes.
--    This requires a scan of the string, unfortunately. We assume valid UTF-8
--    strings, so all we do is reduce the length by one for byte whose bits are
--    10xxxxxx. */
--
--    case OP_CHARS:
--    branchlength += *(++cc);
--#ifdef SUPPORT_UTF8
--    for (d = 1; d <= *cc; d++)
--      if ((cc[d] & 0xc0) == 0x80) branchlength--;
--#endif
--    cc += *cc + 1;
--    break;
--
--    /* Handle exact repetitions */
--
--    case OP_EXACT:
--    case OP_TYPEEXACT:
--    branchlength += (cc[1] << 8) + cc[2];
--    cc += 4;
--    break;
--
--    /* Handle single-char matchers */
--
--    case OP_NOT_DIGIT:
--    case OP_DIGIT:
--    case OP_NOT_WHITESPACE:
--    case OP_WHITESPACE:
--    case OP_NOT_WORDCHAR:
--    case OP_WORDCHAR:
--    case OP_ANY:
--    branchlength++;
--    cc++;
--    break;
--
--
--    /* Check a class for variable quantification */
--
--    case OP_CLASS:
--    cc += 33;
--
--    switch (*cc)
--      {
--      case OP_CRSTAR:
--      case OP_CRMINSTAR:
--      case OP_CRQUERY:
--      case OP_CRMINQUERY:
--      return -1;
--
--      case OP_CRRANGE:
--      case OP_CRMINRANGE:
--      if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1;
--      branchlength += (cc[1] << 8) + cc[2];
--      cc += 5;
--      break;
--
--      default:
--      branchlength++;
--      }
--    break;
--
--    /* Anything else is variable length */
--
--    default:
--    return -1;
--    }
--  }
--/* Control never gets here */
--}
--
--
--
--
--/*************************************************
--*           Check for POSIX class syntax         *
--*************************************************/
--
--/* This function is called when the sequence "[:" or "[." or "[=" is
--encountered in a character class. It checks whether this is followed by an
--optional ^ and then a sequence of letters, terminated by a matching ":]" or
--".]" or "=]".
--
--Argument:
--  ptr      pointer to the initial [
--  endptr   where to return the end pointer
--  cd       pointer to compile data
--
--Returns:   TRUE or FALSE
--*/
--
--static BOOL
--check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd)
--{
--int terminator;          /* Don't combine these lines; the Solaris cc */
--terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
--if (*(++ptr) == '^') ptr++;
--while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
--if (*ptr == terminator && ptr[1] == ']')
--  {
--  *endptr = ptr;
--  return TRUE;
--  }
--return FALSE;
--}
--
--
--
--
--/*************************************************
--*          Check POSIX class name                *
--*************************************************/
--
--/* This function is called to check the name given in a POSIX-style class entry
--such as [:alnum:].
--
--Arguments:
--  ptr        points to the first letter
--  len        the length of the name
--
--Returns:     a value representing the name, or -1 if unknown
--*/
--
--static int
--check_posix_name(const uschar *ptr, int len)
--{
--register int yield = 0;
--while (posix_name_lengths[yield] != 0)
--  {
--  if (len == posix_name_lengths[yield] &&
--    strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield;
--  yield++;
--  }
--return -1;
--}
--
--
--
--
--/*************************************************
--*           Compile one branch                   *
--*************************************************/
--
--/* Scan the pattern, compiling it into the code vector.
--
--Arguments:
--  options      the option bits
--  brackets     points to number of extracting brackets used
--  code         points to the pointer to the current code point
--  ptrptr       points to the current pattern pointer
--  errorptr     points to pointer to error message
--  optchanged   set to the value of the last OP_OPT item compiled
--  reqchar      set to the last literal character required, else -1
--  countlits    set to count of mandatory literal characters
--  cd           contains pointers to tables
--
--Returns:       TRUE on success
--               FALSE, with *errorptr set on error
--*/
--
--static BOOL
--compile_branch(int options, int *brackets, uschar **codeptr,
--  const uschar **ptrptr, const char **errorptr, int *optchanged,
--  int *reqchar, int *countlits, compile_data *cd)
--{
--int repeat_type, op_type;
--int repeat_min, repeat_max;
--int bravalue, length;
--int greedy_default, greedy_non_default;
--int prevreqchar;
--int condcount = 0;
--int subcountlits = 0;
--register int c;
--register uschar *code = *codeptr;
--uschar *tempcode;
--const uschar *ptr = *ptrptr;
--const uschar *tempptr;
--uschar *previous = NULL;
--uschar class[32];
--
--/* Set up the default and non-default settings for greediness */
--
--greedy_default = ((options & PCRE_UNGREEDY) != 0);
--greedy_non_default = greedy_default ^ 1;
--
--/* Initialize no required char, and count of literals */
--
--*reqchar = prevreqchar = -1;
--*countlits = 0;
--
--/* Switch on next character until the end of the branch */
--
--for (;; ptr++)
--  {
--  BOOL negate_class;
--  int class_charcount;
--  int class_lastchar;
--  int newoptions;
--  int skipbytes;
--  int subreqchar;
--
--  c = *ptr;
--  if ((options & PCRE_EXTENDED) != 0)
--    {
--    if ((cd->ctypes[c] & ctype_space) != 0) continue;
--    if (c == '#')
--      {
--      /* The space before the ; is to avoid a warning on a silly compiler
--      on the Macintosh. */
--      while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
--      continue;
--      }
--    }
--
--  switch(c)
--    {
--    /* The branch terminates at end of string, |, or ). */
--
--    case 0:
--    case '|':
--    case ')':
--    *codeptr = code;
--    *ptrptr = ptr;
--    return TRUE;
--
--    /* Handle single-character metacharacters */
--
--    case '^':
--    previous = NULL;
--    *code++ = OP_CIRC;
--    break;
--
--    case '$':
--    previous = NULL;
--    *code++ = OP_DOLL;
--    break;
--
--    case '.':
--    previous = code;
--    *code++ = OP_ANY;
--    break;
--
--    /* Character classes. These always build a 32-byte bitmap of the permitted
--    characters, except in the special case where there is only one character.
--    For negated classes, we build the map as usual, then invert it at the end.
--    */
--
--    case '[':
--    previous = code;
--    *code++ = OP_CLASS;
--
--    /* If the first character is '^', set the negation flag and skip it. */
--
--    if ((c = *(++ptr)) == '^')
--      {
--      negate_class = TRUE;
--      c = *(++ptr);
--      }
--    else negate_class = FALSE;
--
--    /* Keep a count of chars so that we can optimize the case of just a single
--    character. */
--
--    class_charcount = 0;
--    class_lastchar = -1;
--
--    /* Initialize the 32-char bit map to all zeros. We have to build the
--    map in a temporary bit of store, in case the class contains only 1
--    character, because in that case the compiled code doesn't use the
--    bit map. */
--
--    memset(class, 0, 32 * sizeof(uschar));
--
--    /* Process characters until ] is reached. By writing this as a "do" it
--    means that an initial ] is taken as a data character. */
--
--    do
--      {
--      if (c == 0)
--        {
--        *errorptr = ERR6;
--        goto FAILED;
--        }
--
--      /* Handle POSIX class names. Perl allows a negation extension of the
--      form [:^name]. A square bracket that doesn't match the syntax is
--      treated as a literal. We also recognize the POSIX constructions
--      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
--      5.6 does. */
--
--      if (c == '[' &&
--          (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
--          check_posix_syntax(ptr, &tempptr, cd))
--        {
--        BOOL local_negate = FALSE;
--        int posix_class, i;
--        register const uschar *cbits = cd->cbits;
--
--        if (ptr[1] != ':')
--          {
--          *errorptr = ERR31;
--          goto FAILED;
--          }
--
--        ptr += 2;
--        if (*ptr == '^')
--          {
--          local_negate = TRUE;
--          ptr++;
--          }
--
--        posix_class = check_posix_name(ptr, tempptr - ptr);
--        if (posix_class < 0)
--          {
--          *errorptr = ERR30;
--          goto FAILED;
--          }
--
--        /* If matching is caseless, upper and lower are converted to
--        alpha. This relies on the fact that the class table starts with
--        alpha, lower, upper as the first 3 entries. */
--
--        if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
--          posix_class = 0;
--
--        /* Or into the map we are building up to 3 of the static class
--        tables, or their negations. */
--
--        posix_class *= 3;
--        for (i = 0; i < 3; i++)
--          {
--          int taboffset = posix_class_maps[posix_class + i];
--          if (taboffset < 0) break;
--          if (local_negate)
--            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset];
--          else
--            for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset];
--          }
--
--        ptr = tempptr + 1;
--        class_charcount = 10;  /* Set > 1; assumes more than 1 per class */
--        continue;
--        }
--
--      /* Backslash may introduce a single character, or it may introduce one
--      of the specials, which just set a flag. Escaped items are checked for
--      validity in the pre-compiling pass. The sequence \b is a special case.
--      Inside a class (and only there) it is treated as backspace. Elsewhere
--      it marks a word boundary. Other escapes have preset maps ready to
--      or into the one we are building. We assume they have more than one
--      character in them, so set class_count bigger than one. */
--
--      if (c == '\\')
--        {
--        c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
--        if (-c == ESC_b) c = '\b';
--        else if (c < 0)
--          {
--          register const uschar *cbits = cd->cbits;
--          class_charcount = 10;
--          switch (-c)
--            {
--            case ESC_d:
--            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit];
--            continue;
--
--            case ESC_D:
--            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit];
--            continue;
--
--            case ESC_w:
--            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word];
--            continue;
--
--            case ESC_W:
--            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word];
--            continue;
--
--            case ESC_s:
--            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space];
--            continue;
--
--            case ESC_S:
--            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space];
--            continue;
--
--            default:
--            *errorptr = ERR7;
--            goto FAILED;
--            }
--          }
--
--        /* Fall through if single character, but don't at present allow
--        chars > 255 in UTF-8 mode. */
--
--#ifdef SUPPORT_UTF8
--        if (c > 255)
--          {
--          *errorptr = ERR33;
--          goto FAILED;
--          }
--#endif
--        }
--
--      /* A single character may be followed by '-' to form a range. However,
--      Perl does not permit ']' to be the end of the range. A '-' character
--      here is treated as a literal. */
--
--      if (ptr[1] == '-' && ptr[2] != ']')
--        {
--        int d;
--        ptr += 2;
--        d = *ptr;
--
--        if (d == 0)
--          {
--          *errorptr = ERR6;
--          goto FAILED;
--          }
--
--        /* The second part of a range can be a single-character escape, but
--        not any of the other escapes. Perl 5.6 treats a hyphen as a literal
--        in such circumstances. */
--
--        if (d == '\\')
--          {
--          const uschar *oldptr = ptr;
--          d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
--
--#ifdef SUPPORT_UTF8
--          if (d > 255)
--            {
--            *errorptr = ERR33;
--            goto FAILED;
--            }
--#endif
--          /* \b is backslash; any other special means the '-' was literal */
--
--          if (d < 0)
--            {
--            if (d == -ESC_b) d = '\b'; else
--              {
--              ptr = oldptr - 2;
--              goto SINGLE_CHARACTER;  /* A few lines below */
--              }
--            }
--          }
--
--        if (d < c)
--          {
--          *errorptr = ERR8;
--          goto FAILED;
--          }
--
--        for (; c <= d; c++)
--          {
--          class[c/8] |= (1 << (c&7));
--          if ((options & PCRE_CASELESS) != 0)
--            {
--            int uc = cd->fcc[c];           /* flip case */
--            class[uc/8] |= (1 << (uc&7));
--            }
--          class_charcount++;                /* in case a one-char range */
--          class_lastchar = c;
--          }
--        continue;   /* Go get the next char in the class */
--        }
--
--      /* Handle a lone single character - we can get here for a normal
--      non-escape char, or after \ that introduces a single character. */
--
--      SINGLE_CHARACTER:
--
--      class [c/8] |= (1 << (c&7));
--      if ((options & PCRE_CASELESS) != 0)
--        {
--        c = cd->fcc[c];   /* flip case */
--        class[c/8] |= (1 << (c&7));
--        }
--      class_charcount++;
--      class_lastchar = c;
--      }
--
--    /* Loop until ']' reached; the check for end of string happens inside the
--    loop. This "while" is the end of the "do" above. */
--
--    while ((c = *(++ptr)) != ']');
--
--    /* If class_charcount is 1 and class_lastchar is not negative, we saw
--    precisely one character. This doesn't need the whole 32-byte bit map.
--    We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if
--    it's negative. */
--
--    if (class_charcount == 1 && class_lastchar >= 0)
--      {
--      if (negate_class)
--        {
--        code[-1] = OP_NOT;
--        }
--      else
--        {
--        code[-1] = OP_CHARS;
--        *code++ = 1;
--        }
--      *code++ = class_lastchar;
--      }
--
--    /* Otherwise, negate the 32-byte map if necessary, and copy it into
--    the code vector. */
--
--    else
--      {
--      if (negate_class)
--        for (c = 0; c < 32; c++) code[c] = ~class[c];
--      else
--        memcpy(code, class, 32);
--      code += 32;
--      }
--    break;
--
--    /* Various kinds of repeat */
--
--    case '{':
--    if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR;
--    ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd);
--    if (*errorptr != NULL) goto FAILED;
--    goto REPEAT;
--
--    case '*':
--    repeat_min = 0;
--    repeat_max = -1;
--    goto REPEAT;
--
--    case '+':
--    repeat_min = 1;
--    repeat_max = -1;
--    goto REPEAT;
--
--    case '?':
--    repeat_min = 0;
--    repeat_max = 1;
--
--    REPEAT:
--    if (previous == NULL)
--      {
--      *errorptr = ERR9;
--      goto FAILED;
--      }
--
--    /* If the next character is '?' this is a minimizing repeat, by default,
--    but if PCRE_UNGREEDY is set, it works the other way round. Advance to the
--    next character. */
--
--    if (ptr[1] == '?')
--      { repeat_type = greedy_non_default; ptr++; }
--    else repeat_type = greedy_default;
--
--    /* If previous was a string of characters, chop off the last one and use it
--    as the subject of the repeat. If there was only one character, we can
--    abolish the previous item altogether. A repeat with a zero minimum wipes
--    out any reqchar setting, backing up to the previous value. We must also
--    adjust the countlits value. */
--
--    if (*previous == OP_CHARS)
--      {
--      int len = previous[1];
--
--      if (repeat_min == 0) *reqchar = prevreqchar;
--      *countlits += repeat_min - 1;
--
--      if (len == 1)
--        {
--        c = previous[2];
--        code = previous;
--        }
--      else
--        {
--        c = previous[len+1];
--        previous[1]--;
--        code--;
--        }
--      op_type = 0;                 /* Use single-char op codes */
--      goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
--      }
--
--    /* If previous was a single negated character ([^a] or similar), we use
--    one of the special opcodes, replacing it. The code is shared with single-
--    character repeats by adding a suitable offset into repeat_type. */
--
--    else if ((int)*previous == OP_NOT)
--      {
--      op_type = OP_NOTSTAR - OP_STAR;  /* Use "not" opcodes */
--      c = previous[1];
--      code = previous;
--      goto OUTPUT_SINGLE_REPEAT;
--      }
--
--    /* If previous was a character type match (\d or similar), abolish it and
--    create a suitable repeat item. The code is shared with single-character
--    repeats by adding a suitable offset into repeat_type. */
--
--    else if ((int)*previous < OP_EODN || *previous == OP_ANY)
--      {
--      op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
--      c = *previous;
--      code = previous;
--
--      OUTPUT_SINGLE_REPEAT:
--
--      /* If the maximum is zero then the minimum must also be zero; Perl allows
--      this case, so we do too - by simply omitting the item altogether. */
--
--      if (repeat_max == 0) goto END_REPEAT;
--
--      /* Combine the op_type with the repeat_type */
--
--      repeat_type += op_type;
--
--      /* A minimum of zero is handled either as the special case * or ?, or as
--      an UPTO, with the maximum given. */
--
--      if (repeat_min == 0)
--        {
--        if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
--          else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
--        else
--          {
--          *code++ = OP_UPTO + repeat_type;
--          *code++ = repeat_max >> 8;
--          *code++ = (repeat_max & 255);
--          }
--        }
--
--      /* The case {1,} is handled as the special case + */
--
--      else if (repeat_min == 1 && repeat_max == -1)
--        *code++ = OP_PLUS + repeat_type;
--
--      /* The case {n,n} is just an EXACT, while the general case {n,m} is
--      handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */
--
--      else
--        {
--        if (repeat_min != 1)
--          {
--          *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
--          *code++ = repeat_min >> 8;
--          *code++ = (repeat_min & 255);
--          }
--
--        /* If the mininum is 1 and the previous item was a character string,
--        we either have to put back the item that got cancelled if the string
--        length was 1, or add the character back onto the end of a longer
--        string. For a character type nothing need be done; it will just get
--        put back naturally. Note that the final character is always going to
--        get added below. */
--
--        else if (*previous == OP_CHARS)
--          {
--          if (code == previous) code += 2; else previous[1]++;
--          }
--
--        /*  For a single negated character we also have to put back the
--        item that got cancelled. */
--
--        else if (*previous == OP_NOT) code++;
--
--        /* If the maximum is unlimited, insert an OP_STAR. */
--
--        if (repeat_max < 0)
--          {
--          *code++ = c;
--          *code++ = OP_STAR + repeat_type;
--          }
--
--        /* Else insert an UPTO if the max is greater than the min. */
--
--        else if (repeat_max != repeat_min)
--          {
--          *code++ = c;
--          repeat_max -= repeat_min;
--          *code++ = OP_UPTO + repeat_type;
--          *code++ = repeat_max >> 8;
--          *code++ = (repeat_max & 255);
--          }
--        }
--
--      /* The character or character type itself comes last in all cases. */
--
--      *code++ = c;
--      }
--
--    /* If previous was a character class or a back reference, we put the repeat
--    stuff after it, but just skip the item if the repeat was {0,0}. */
--
--    else if (*previous == OP_CLASS || *previous == OP_REF)
--      {
--      if (repeat_max == 0)
--        {
--        code = previous;
--        goto END_REPEAT;
--        }
--      if (repeat_min == 0 && repeat_max == -1)
--        *code++ = OP_CRSTAR + repeat_type;
--      else if (repeat_min == 1 && repeat_max == -1)
--        *code++ = OP_CRPLUS + repeat_type;
--      else if (repeat_min == 0 && repeat_max == 1)
--        *code++ = OP_CRQUERY + repeat_type;
--      else
--        {
--        *code++ = OP_CRRANGE + repeat_type;
--        *code++ = repeat_min >> 8;
--        *code++ = repeat_min & 255;
--        if (repeat_max == -1) repeat_max = 0;  /* 2-byte encoding for max */
--        *code++ = repeat_max >> 8;
--        *code++ = repeat_max & 255;
--        }
--      }
--
--    /* If previous was a bracket group, we may have to replicate it in certain
--    cases. */
--
--    else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE ||
--             (int)*previous == OP_COND)
--      {
--      register int i;
--      int ketoffset = 0;
--      int len = code - previous;
--      uschar *bralink = NULL;
--
--      /* If the maximum repeat count is unlimited, find the end of the bracket
--      by scanning through from the start, and compute the offset back to it
--      from the current code pointer. There may be an OP_OPT setting following
--      the final KET, so we can't find the end just by going back from the code
--      pointer. */
--
--      if (repeat_max == -1)
--        {
--        register uschar *ket = previous;
--        do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET);
--        ketoffset = code - ket;
--        }
--
--      /* The case of a zero minimum is special because of the need to stick
--      OP_BRAZERO in front of it, and because the group appears once in the
--      data, whereas in other cases it appears the minimum number of times. For
--      this reason, it is simplest to treat this case separately, as otherwise
--      the code gets far too messy. There are several special subcases when the
--      minimum is zero. */
--
--      if (repeat_min == 0)
--        {
--        /* If we set up a required char from the bracket, we must back off
--        to the previous value and reset the countlits value too. */
--
--        if (subcountlits > 0)
--          {
--          *reqchar = prevreqchar;
--          *countlits -= subcountlits;
--          }
--
--        /* If the maximum is also zero, we just omit the group from the output
--        altogether. */
--
--        if (repeat_max == 0)
--          {
--          code = previous;
--          goto END_REPEAT;
--          }
--
--        /* If the maximum is 1 or unlimited, we just have to stick in the
--        BRAZERO and do no more at this point. */
--
--        if (repeat_max <= 1)
--          {
--          memmove(previous+1, previous, len);
--          code++;
--          *previous++ = OP_BRAZERO + repeat_type;
--          }
--
--        /* If the maximum is greater than 1 and limited, we have to replicate
--        in a nested fashion, sticking OP_BRAZERO before each set of brackets.
--        The first one has to be handled carefully because it's the original
--        copy, which has to be moved up. The remainder can be handled by code
--        that is common with the non-zero minimum case below. We just have to
--        adjust the value or repeat_max, since one less copy is required. */
--
--        else
--          {
--          int offset;
--          memmove(previous+4, previous, len);
--          code += 4;
--          *previous++ = OP_BRAZERO + repeat_type;
--          *previous++ = OP_BRA;
--
--          /* We chain together the bracket offset fields that have to be
--          filled in later when the ends of the brackets are reached. */
--
--          offset = (bralink == NULL)? 0 : previous - bralink;
--          bralink = previous;
--          *previous++ = offset >> 8;
--          *previous++ = offset & 255;
--          }
--
--        repeat_max--;
--        }
--
--      /* If the minimum is greater than zero, replicate the group as many
--      times as necessary, and adjust the maximum to the number of subsequent
--      copies that we need. */
--
--      else
--        {
--        for (i = 1; i < repeat_min; i++)
--          {
--          memcpy(code, previous, len);
--          code += len;
--          }
--        if (repeat_max > 0) repeat_max -= repeat_min;
--        }
--
--      /* This code is common to both the zero and non-zero minimum cases. If
--      the maximum is limited, it replicates the group in a nested fashion,
--      remembering the bracket starts on a stack. In the case of a zero minimum,
--      the first one was set up above. In all cases the repeat_max now specifies
--      the number of additional copies needed. */
--
--      if (repeat_max >= 0)
--        {
--        for (i = repeat_max - 1; i >= 0; i--)
--          {
--          *code++ = OP_BRAZERO + repeat_type;
--
--          /* All but the final copy start a new nesting, maintaining the
--          chain of brackets outstanding. */
--
--          if (i != 0)
--            {
--            int offset;
--            *code++ = OP_BRA;
--            offset = (bralink == NULL)? 0 : code - bralink;
--            bralink = code;
--            *code++ = offset >> 8;
--            *code++ = offset & 255;
--            }
--
--          memcpy(code, previous, len);
--          code += len;
--          }
--
--        /* Now chain through the pending brackets, and fill in their length
--        fields (which are holding the chain links pro tem). */
--
--        while (bralink != NULL)
--          {
--          int oldlinkoffset;
--          int offset = code - bralink + 1;
--          uschar *bra = code - offset;
--          oldlinkoffset = (bra[1] << 8) + bra[2];
--          bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
--          *code++ = OP_KET;
--          *code++ = bra[1] = offset >> 8;
--          *code++ = bra[2] = (offset & 255);
--          }
--        }
--
--      /* If the maximum is unlimited, set a repeater in the final copy. We
--      can't just offset backwards from the current code point, because we
--      don't know if there's been an options resetting after the ket. The
--      correct offset was computed above. */
--
--      else code[-ketoffset] = OP_KETRMAX + repeat_type;
--      }
--
--    /* Else there's some kind of shambles */
--
--    else
--      {
--      *errorptr = ERR11;
--      goto FAILED;
--      }
--
--    /* In all case we no longer have a previous item. */
--
--    END_REPEAT:
--    previous = NULL;
--    break;
--
--
--    /* Start of nested bracket sub-expression, or comment or lookahead or
--    lookbehind or option setting or condition. First deal with special things
--    that can come after a bracket; all are introduced by ?, and the appearance
--    of any of them means that this is not a referencing group. They were
--    checked for validity in the first pass over the string, so we don't have to
--    check for syntax errors here.  */
--
--    case '(':
--    newoptions = options;
--    skipbytes = 0;
--
--    if (*(++ptr) == '?')
--      {
--      int set, unset;
--      int *optset;
--
--      switch (*(++ptr))
--        {
--        case '#':                 /* Comment; skip to ket */
--        ptr++;
--        while (*ptr != ')') ptr++;
--        continue;
--
--        case ':':                 /* Non-extracting bracket */
--        bravalue = OP_BRA;
--        ptr++;
--        break;
--
--        case '(':
--        bravalue = OP_COND;       /* Conditional group */
--        if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0)
--          {
--          int condref = *ptr - '0';
--          while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
--          if (condref == 0)
--            {
--            *errorptr = ERR35;
--            goto FAILED;
--            }
--          ptr++;
--          code[3] = OP_CREF;
--          code[4] = condref >> 8;
--          code[5] = condref & 255;
--          skipbytes = 3;
--          }
--        else ptr--;
--        break;
--
--        case '=':                 /* Positive lookahead */
--        bravalue = OP_ASSERT;
--        ptr++;
--        break;
--
--        case '!':                 /* Negative lookahead */
--        bravalue = OP_ASSERT_NOT;
--        ptr++;
--        break;
--
--        case '<':                 /* Lookbehinds */
--        switch (*(++ptr))
--          {
--          case '=':               /* Positive lookbehind */
--          bravalue = OP_ASSERTBACK;
--          ptr++;
--          break;
--
--          case '!':               /* Negative lookbehind */
--          bravalue = OP_ASSERTBACK_NOT;
--          ptr++;
--          break;
--
--          default:                /* Syntax error */
--          *errorptr = ERR24;
--          goto FAILED;
--          }
--        break;
--
--        case '>':                 /* One-time brackets */
--        bravalue = OP_ONCE;
--        ptr++;
--        break;
--
--        case 'R':                 /* Pattern recursion */
--        *code++ = OP_RECURSE;
--        ptr++;
--        continue;
--
--        default:                  /* Option setting */
--        set = unset = 0;
--        optset = &set;
--
--        while (*ptr != ')' && *ptr != ':')
--          {
--          switch (*ptr++)
--            {
--            case '-': optset = &unset; break;
--
--            case 'i': *optset |= PCRE_CASELESS; break;
--            case 'm': *optset |= PCRE_MULTILINE; break;
--            case 's': *optset |= PCRE_DOTALL; break;
--            case 'x': *optset |= PCRE_EXTENDED; break;
--            case 'U': *optset |= PCRE_UNGREEDY; break;
--            case 'X': *optset |= PCRE_EXTRA; break;
--
--            default:
--            *errorptr = ERR12;
--            goto FAILED;
--            }
--          }
--
--        /* Set up the changed option bits, but don't change anything yet. */
--
--        newoptions = (options | set) & (~unset);
--
--        /* If the options ended with ')' this is not the start of a nested
--        group with option changes, so the options change at this level. At top
--        level there is nothing else to be done (the options will in fact have
--        been set from the start of compiling as a result of the first pass) but
--        at an inner level we must compile code to change the ims options if
--        necessary, and pass the new setting back so that it can be put at the
--        start of any following branches, and when this group ends, a resetting
--        item can be compiled. */
--
--        if (*ptr == ')')
--          {
--          if ((options & PCRE_INGROUP) != 0 &&
--              (options & PCRE_IMS) != (newoptions & PCRE_IMS))
--            {
--            *code++ = OP_OPT;
--            *code++ = *optchanged = newoptions & PCRE_IMS;
--            }
--          options = newoptions;  /* Change options at this level */
--          previous = NULL;       /* This item can't be repeated */
--          continue;              /* It is complete */
--          }
--
--        /* If the options ended with ':' we are heading into a nested group
--        with possible change of options. Such groups are non-capturing and are
--        not assertions of any kind. All we need to do is skip over the ':';
--        the newoptions value is handled below. */
--
--        bravalue = OP_BRA;
--        ptr++;
--        }
--      }
--
--    /* Else we have a referencing group; adjust the opcode. If the bracket
--    number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
--    arrange for the true number to follow later, in an OP_BRANUMBER item. */
--
--    else
--      {
--      if (++(*brackets) > EXTRACT_BASIC_MAX)
--        {
--        bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
--        code[3] = OP_BRANUMBER;
--        code[4] = *brackets >> 8;
--        code[5] = *brackets & 255;
--        skipbytes = 3;
--        }
--      else bravalue = OP_BRA + *brackets;
--      }
--
--    /* Process nested bracketed re. Assertions may not be repeated, but other
--    kinds can be. We copy code into a non-register variable in order to be able
--    to pass its address because some compilers complain otherwise. Pass in a
--    new setting for the ims options if they have changed. */
--
--    previous = (bravalue >= OP_ONCE)? code : NULL;
--    *code = bravalue;
--    tempcode = code;
--
--    if (!compile_regex(
--         options | PCRE_INGROUP,       /* Set for all nested groups */
--         ((options & PCRE_IMS) != (newoptions & PCRE_IMS))?
--           newoptions & PCRE_IMS : -1, /* Pass ims options if changed */
--         brackets,                     /* Extracting bracket count */
--         &tempcode,                    /* Where to put code (updated) */
--         &ptr,                         /* Input pointer (updated) */
--         errorptr,                     /* Where to put an error message */
--         (bravalue == OP_ASSERTBACK ||
--          bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
--         skipbytes,                    /* Skip over OP_COND/OP_BRANUMBER */
--         &subreqchar,                  /* For possible last char */
--         &subcountlits,                /* For literal count */
--         cd))                          /* Tables block */
--      goto FAILED;
--
--    /* At the end of compiling, code is still pointing to the start of the
--    group, while tempcode has been updated to point past the end of the group
--    and any option resetting that may follow it. The pattern pointer (ptr)
--    is on the bracket. */
--
--    /* If this is a conditional bracket, check that there are no more than
--    two branches in the group. */
--
--    else if (bravalue == OP_COND)
--      {
--      uschar *tc = code;
--      condcount = 0;
--
--      do {
--         condcount++;
--         tc += (tc[1] << 8) | tc[2];
--         }
--      while (*tc != OP_KET);
--
--      if (condcount > 2)
--        {
--        *errorptr = ERR27;
--        goto FAILED;
--        }
--      }
--
--    /* Handle updating of the required character. If the subpattern didn't
--    set one, leave it as it was. Otherwise, update it for normal brackets of
--    all kinds, forward assertions, and conditions with two branches. Don't
--    update the literal count for forward assertions, however. If the bracket
--    is followed by a quantifier with zero repeat, we have to back off. Hence
--    the definition of prevreqchar and subcountlits outside the main loop so
--    that they can be accessed for the back off. */
--
--    if (subreqchar > 0 &&
--         (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT ||
--         (bravalue == OP_COND && condcount == 2)))
--      {
--      prevreqchar = *reqchar;
--      *reqchar = subreqchar;
--      if (bravalue != OP_ASSERT) *countlits += subcountlits;
--      }
--
--    /* Now update the main code pointer to the end of the group. */
--
--    code = tempcode;
--
--    /* Error if hit end of pattern */
--
--    if (*ptr != ')')
--      {
--      *errorptr = ERR14;
--      goto FAILED;
--      }
--    break;
--
--    /* Check \ for being a real metacharacter; if not, fall through and handle
--    it as a data character at the start of a string. Escape items are checked
--    for validity in the pre-compiling pass. */
--
--    case '\\':
--    tempptr = ptr;
--    c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
--
--    /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
--    are arranged to be the negation of the corresponding OP_values. For the
--    back references, the values are ESC_REF plus the reference number. Only
--    back references and those types that consume a character may be repeated.
--    We can test for values between ESC_b and ESC_Z for the latter; this may
--    have to change if any new ones are ever created. */
--
--    if (c < 0)
--      {
--      if (-c >= ESC_REF)
--        {
--        int number = -c - ESC_REF;
--        previous = code;
--        *code++ = OP_REF;
--        *code++ = number >> 8;
--        *code++ = number & 255;
--        }
--      else
--        {
--        previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
--        *code++ = -c;
--        }
--      continue;
--      }
--
--    /* Data character: reset and fall through */
--
--    ptr = tempptr;
--    c = '\\';
--
--    /* Handle a run of data characters until a metacharacter is encountered.
--    The first character is guaranteed not to be whitespace or # when the
--    extended flag is set. */
--
--    NORMAL_CHAR:
--    default:
--    previous = code;
--    *code = OP_CHARS;
--    code += 2;
--    length = 0;
--
--    do
--      {
--      if ((options & PCRE_EXTENDED) != 0)
--        {
--        if ((cd->ctypes[c] & ctype_space) != 0) continue;
--        if (c == '#')
--          {
--          /* The space before the ; is to avoid a warning on a silly compiler
--          on the Macintosh. */
--          while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
--          if (c == 0) break;
--          continue;
--          }
--        }
--
--      /* Backslash may introduce a data char or a metacharacter. Escaped items
--      are checked for validity in the pre-compiling pass. Stop the string
--      before a metaitem. */
--
--      if (c == '\\')
--        {
--        tempptr = ptr;
--        c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
--        if (c < 0) { ptr = tempptr; break; }
--
--        /* If a character is > 127 in UTF-8 mode, we have to turn it into
--        two or more characters in the UTF-8 encoding. */
--
--#ifdef SUPPORT_UTF8
--        if (c > 127 && (options & PCRE_UTF8) != 0)
--          {
--          uschar buffer[8];
--          int len = ord2utf8(c, buffer);
--          for (c = 0; c < len; c++) *code++ = buffer[c];
--          length += len;
--          continue;
--          }
--#endif
--        }
--
--      /* Ordinary character or single-char escape */
--
--      *code++ = c;
--      length++;
--      }
--
--    /* This "while" is the end of the "do" above. */
--
--    while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0);
--
--    /* Update the last character and the count of literals */
--
--    prevreqchar = (length > 1)? code[-2] : *reqchar;
--    *reqchar = code[-1];
--    *countlits += length;
--
--    /* Compute the length and set it in the data vector, and advance to
--    the next state. */
--
--    previous[1] = length;
--    if (length < MAXLIT) ptr--;
--    break;
--    }
--  }                   /* end of big loop */
--
--/* Control never reaches here by falling through, only by a goto for all the
--error states. Pass back the position in the pattern so that it can be displayed
--to the user for diagnosing the error. */
--
--FAILED:
--*ptrptr = ptr;
--return FALSE;
--}
--
--
--
--
--/*************************************************
--*     Compile sequence of alternatives           *
--*************************************************/
--
--/* On entry, ptr is pointing past the bracket character, but on return
--it points to the closing bracket, or vertical bar, or end of string.
--The code variable is pointing at the byte into which the BRA operator has been
--stored. If the ims options are changed at the start (for a (?ims: group) or
--during any branch, we need to insert an OP_OPT item at the start of every
--following branch to ensure they get set correctly at run time, and also pass
--the new options into every subsequent branch compile.
--
--Argument:
--  options     the option bits
--  optchanged  new ims options to set as if (?ims) were at the start, or -1
--               for no change
--  brackets    -> int containing the number of extracting brackets used
--  codeptr     -> the address of the current code pointer
--  ptrptr      -> the address of the current pattern pointer
--  errorptr    -> pointer to error message
--  lookbehind  TRUE if this is a lookbehind assertion
--  skipbytes   skip this many bytes at start (for OP_COND, OP_BRANUMBER)
--  reqchar     -> place to put the last required character, or a negative number
--  countlits   -> place to put the shortest literal count of any branch
--  cd          points to the data block with tables pointers
--
--Returns:      TRUE on success
--*/
--
--static BOOL
--compile_regex(int options, int optchanged, int *brackets, uschar **codeptr,
--  const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes,
--  int *reqchar, int *countlits, compile_data *cd)
--{
--const uschar *ptr = *ptrptr;
--uschar *code = *codeptr;
--uschar *last_branch = code;
--uschar *start_bracket = code;
--uschar *reverse_count = NULL;
--int oldoptions = options & PCRE_IMS;
--int branchreqchar, branchcountlits;
--
--*reqchar = -1;
--*countlits = INT_MAX;
--code += 3 + skipbytes;
--
--/* Loop for each alternative branch */
--
--for (;;)
--  {
--  int length;
--
--  /* Handle change of options */
--
--  if (optchanged >= 0)
--    {
--    *code++ = OP_OPT;
--    *code++ = optchanged;
--    options = (options & ~PCRE_IMS) | optchanged;
--    }
--
--  /* Set up dummy OP_REVERSE if lookbehind assertion */
--
--  if (lookbehind)
--    {
--    *code++ = OP_REVERSE;
--    reverse_count = code;
--    *code++ = 0;
--    *code++ = 0;
--    }
--
--  /* Now compile the branch */
--
--  if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged,
--      &branchreqchar, &branchcountlits, cd))
--    {
--    *ptrptr = ptr;
--    return FALSE;
--    }
--
--  /* Fill in the length of the last branch */
--
--  length = code - last_branch;
--  last_branch[1] = length >> 8;
--  last_branch[2] = length & 255;
--
--  /* Save the last required character if all branches have the same; a current
--  value of -1 means unset, while -2 means "previous branch had no last required
--  char".  */
--
--  if (*reqchar != -2)
--    {
--    if (branchreqchar >= 0)
--      {
--      if (*reqchar == -1) *reqchar = branchreqchar;
--      else if (*reqchar != branchreqchar) *reqchar = -2;
--      }
--    else *reqchar = -2;
--    }
--
--  /* Keep the shortest literal count */
--
--  if (branchcountlits < *countlits) *countlits = branchcountlits;
--  DPRINTF(("literal count = %d min=%d\n", branchcountlits, *countlits));
--
--  /* If lookbehind, check that this branch matches a fixed-length string,
--  and put the length into the OP_REVERSE item. Temporarily mark the end of
--  the branch with OP_END. */
--
--  if (lookbehind)
--    {
--    *code = OP_END;
--    length = find_fixedlength(last_branch, options);
--    DPRINTF(("fixed length = %d\n", length));
--    if (length < 0)
--      {
--      *errorptr = ERR25;
--      *ptrptr = ptr;
--      return FALSE;
--      }
--    reverse_count[0] = (length >> 8);
--    reverse_count[1] = length & 255;
--    }
--
--  /* Reached end of expression, either ')' or end of pattern. Insert a
--  terminating ket and the length of the whole bracketed item, and return,
--  leaving the pointer at the terminating char. If any of the ims options
--  were changed inside the group, compile a resetting op-code following. */
--
--  if (*ptr != '|')
--    {
--    length = code - start_bracket;
--    *code++ = OP_KET;
--    *code++ = length >> 8;
--    *code++ = length & 255;
--    if (optchanged >= 0)
--      {
--      *code++ = OP_OPT;
--      *code++ = oldoptions;
--      }
--    *codeptr = code;
--    *ptrptr = ptr;
--    return TRUE;
--    }
--
--  /* Another branch follows; insert an "or" node and advance the pointer. */
--
--  *code = OP_ALT;
--  last_branch = code;
--  code += 3;
--  ptr++;
--  }
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--*      Find first significant op code            *
--*************************************************/
--
--/* This is called by several functions that scan a compiled expression looking
--for a fixed first character, or an anchoring op code etc. It skips over things
--that do not influence this. For one application, a change of caseless option is
--important.
--
--Arguments:
--  code       pointer to the start of the group
--  options    pointer to external options
--  optbit     the option bit whose changing is significant, or
--             zero if none are
--  optstop    TRUE to return on option change, otherwise change the options
--               value and continue
--
--Returns:     pointer to the first significant opcode
--*/
--
--static const uschar*
--first_significant_code(const uschar *code, int *options, int optbit,
--  BOOL optstop)
--{
--for (;;)
--  {
--  switch ((int)*code)
--    {
--    case OP_OPT:
--    if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit))
--      {
--      if (optstop) return code;
--      *options = (int)code[1];
--      }
--    code += 2;
--    break;
--
--    case OP_CREF:
--    case OP_BRANUMBER:
--    code += 3;
--    break;
--
--    case OP_WORD_BOUNDARY:
--    case OP_NOT_WORD_BOUNDARY:
--    code++;
--    break;
--
--    case OP_ASSERT_NOT:
--    case OP_ASSERTBACK:
--    case OP_ASSERTBACK_NOT:
--    do code += (code[1] << 8) + code[2]; while (*code == OP_ALT);
--    code += 3;
--    break;
--
--    default:
--    return code;
--    }
--  }
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--*          Check for anchored expression         *
--*************************************************/
--
--/* Try to find out if this is an anchored regular expression. Consider each
--alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
--all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
--it's anchored. However, if this is a multiline pattern, then only OP_SOD
--counts, since OP_CIRC can match in the middle.
--
--A branch is also implicitly anchored if it starts with .* and DOTALL is set,
--because that will try the rest of the pattern at all possible matching points,
--so there is no point trying them again.
--
--Arguments:
--  code       points to start of expression (the bracket)
--  options    points to the options setting
--
--Returns:     TRUE or FALSE
--*/
--
--static BOOL
--is_anchored(register const uschar *code, int *options)
--{
--do {
--   const uschar *scode = first_significant_code(code + 3, options,
--     PCRE_MULTILINE, FALSE);
--   register int op = *scode;
--   if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
--     { if (!is_anchored(scode, options)) return FALSE; }
--   else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) &&
--            (*options & PCRE_DOTALL) != 0)
--     { if (scode[1] != OP_ANY) return FALSE; }
--   else if (op != OP_SOD &&
--           ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC))
--     return FALSE;
--   code += (code[1] << 8) + code[2];
--   }
--while (*code == OP_ALT);
--return TRUE;
--}
--
--
--
--/*************************************************
--*         Check for starting with ^ or .*        *
--*************************************************/
--
--/* This is called to find out if every branch starts with ^ or .* so that
--"first char" processing can be done to speed things up in multiline
--matching and for non-DOTALL patterns that start with .* (which must start at
--the beginning or after \n).
--
--Argument:  points to start of expression (the bracket)
--Returns:   TRUE or FALSE
--*/
--
--static BOOL
--is_startline(const uschar *code)
--{
--do {
--   const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE);
--   register int op = *scode;
--   if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
--     { if (!is_startline(scode)) return FALSE; }
--   else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
--     { if (scode[1] != OP_ANY) return FALSE; }
--   else if (op != OP_CIRC) return FALSE;
--   code += (code[1] << 8) + code[2];
--   }
--while (*code == OP_ALT);
--return TRUE;
--}
--
--
--
--/*************************************************
--*          Check for fixed first char            *
--*************************************************/
--
--/* Try to find out if there is a fixed first character. This is called for
--unanchored expressions, as it speeds up their processing quite considerably.
--Consider each alternative branch. If they all start with the same char, or with
--a bracket all of whose alternatives start with the same char (recurse ad lib),
--then we return that char, otherwise -1.
--
--Arguments:
--  code       points to start of expression (the bracket)
--  options    pointer to the options (used to check casing changes)
--
--Returns:     -1 or the fixed first char
--*/
--
--static int
--find_firstchar(const uschar *code, int *options)
--{
--register int c = -1;
--do {
--   int d;
--   const uschar *scode = first_significant_code(code + 3, options,
--     PCRE_CASELESS, TRUE);
--   register int op = *scode;
--
--   if (op >= OP_BRA) op = OP_BRA;
--
--   switch(op)
--     {
--     default:
--     return -1;
--
--     case OP_BRA:
--     case OP_ASSERT:
--     case OP_ONCE:
--     case OP_COND:
--     if ((d = find_firstchar(scode, options)) < 0) return -1;
--     if (c < 0) c = d; else if (c != d) return -1;
--     break;
--
--     case OP_EXACT:       /* Fall through */
--     scode++;
--
--     case OP_CHARS:       /* Fall through */
--     scode++;
--
--     case OP_PLUS:
--     case OP_MINPLUS:
--     if (c < 0) c = scode[1]; else if (c != scode[1]) return -1;
--     break;
--     }
--
--   code += (code[1] << 8) + code[2];
--   }
--while (*code == OP_ALT);
--return c;
--}
--
--
--
--
--
--/*************************************************
--*        Compile a Regular Expression            *
--*************************************************/
--
--/* This function takes a string and returns a pointer to a block of store
--holding a compiled version of the expression.
--
--Arguments:
--  pattern      the regular expression
--  options      various option bits
--  errorptr     pointer to pointer to error text
--  erroroffset  ptr offset in pattern where error was detected
--  tables       pointer to character tables or NULL
--
--Returns:       pointer to compiled data block, or NULL on error,
--               with errorptr and erroroffset set
--*/
--
--pcre *
--pcre_compile(const char *pattern, int options, const char **errorptr,
--  int *erroroffset, const unsigned char *tables)
--{
--real_pcre *re;
--int length = 3;      /* For initial BRA plus length */
--int runlength;
--int c, reqchar, countlits;
--int bracount = 0;
--int top_backref = 0;
--int branch_extra = 0;
--int branch_newextra;
--unsigned int brastackptr = 0;
--size_t size;
--uschar *code;
--const uschar *ptr;
--compile_data compile_block;
--int brastack[BRASTACK_SIZE];
--uschar bralenstack[BRASTACK_SIZE];
--
--#ifdef DEBUG
--uschar *code_base, *code_end;
--#endif
--
--/* Can't support UTF8 unless PCRE has been compiled to include the code. */
--
--#ifndef SUPPORT_UTF8
--if ((options & PCRE_UTF8) != 0)
--  {
--  *errorptr = ERR32;
--  return NULL;
--  }
--#endif
--
--/* We can't pass back an error message if errorptr is NULL; I guess the best we
--can do is just return NULL. */
--
--if (errorptr == NULL) return NULL;
--*errorptr = NULL;
--
--/* However, we can give a message for this error */
--
--if (erroroffset == NULL)
--  {
--  *errorptr = ERR16;
--  return NULL;
--  }
--*erroroffset = 0;
--
--if ((options & ~PUBLIC_OPTIONS) != 0)
--  {
--  *errorptr = ERR17;
--  return NULL;
--  }
--
--/* Set up pointers to the individual character tables */
--
--if (tables == NULL) tables = pcre_default_tables;
--compile_block.lcc = tables + lcc_offset;
--compile_block.fcc = tables + fcc_offset;
--compile_block.cbits = tables + cbits_offset;
--compile_block.ctypes = tables + ctypes_offset;
--
--/* Reflect pattern for debugging output */
--
--DPRINTF(("------------------------------------------------------------------\n"));
--DPRINTF(("%s\n", pattern));
--
--/* The first thing to do is to make a pass over the pattern to compute the
--amount of store required to hold the compiled code. This does not have to be
--perfect as long as errors are overestimates. At the same time we can detect any
--internal flag settings. Make an attempt to correct for any counted white space
--if an "extended" flag setting appears late in the pattern. We can't be so
--clever for #-comments. */
--
--ptr = (const uschar *)(pattern - 1);
--while ((c = *(++ptr)) != 0)
--  {
--  int min, max;
--  int class_charcount;
--  int bracket_length;
--
--  if ((options & PCRE_EXTENDED) != 0)
--    {
--    if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
--    if (c == '#')
--      {
--      /* The space before the ; is to avoid a warning on a silly compiler
--      on the Macintosh. */
--      while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
--      continue;
--      }
--    }
--
--  switch(c)
--    {
--    /* A backslashed item may be an escaped "normal" character or a
--    character type. For a "normal" character, put the pointers and
--    character back so that tests for whitespace etc. in the input
--    are done correctly. */
--
--    case '\\':
--      {
--      const uschar *save_ptr = ptr;
--      c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block);
--      if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--      if (c >= 0)
--        {
--        ptr = save_ptr;
--        c = '\\';
--        goto NORMAL_CHAR;
--        }
--      }
--    length++;
--
--    /* A back reference needs an additional 2 bytes, plus either one or 5
--    bytes for a repeat. We also need to keep the value of the highest
--    back reference. */
--
--    if (c <= -ESC_REF)
--      {
--      int refnum = -c - ESC_REF;
--      if (refnum > top_backref) top_backref = refnum;
--      length += 2;   /* For single back reference */
--      if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
--        {
--        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
--        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--        if ((min == 0 && (max == 1 || max == -1)) ||
--          (min == 1 && max == -1))
--            length++;
--        else length += 5;
--        if (ptr[1] == '?') ptr++;
--        }
--      }
--    continue;
--
--    case '^':
--    case '.':
--    case '$':
--    case '*':     /* These repeats won't be after brackets; */
--    case '+':     /* those are handled separately */
--    case '?':
--    length++;
--    continue;
--
--    /* This covers the cases of repeats after a single char, metachar, class,
--    or back reference. */
--
--    case '{':
--    if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR;
--    ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block);
--    if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--    if ((min == 0 && (max == 1 || max == -1)) ||
--      (min == 1 && max == -1))
--        length++;
--    else
--      {
--      length--;   /* Uncount the original char or metachar */
--      if (min == 1) length++; else if (min > 0) length += 4;
--      if (max > 0) length += 4; else length += 2;
--      }
--    if (ptr[1] == '?') ptr++;
--    continue;
--
--    /* An alternation contains an offset to the next branch or ket. If any ims
--    options changed in the previous branch(es), and/or if we are in a
--    lookbehind assertion, extra space will be needed at the start of the
--    branch. This is handled by branch_extra. */
--
--    case '|':
--    length += 3 + branch_extra;
--    continue;
--
--    /* A character class uses 33 characters. Don't worry about character types
--    that aren't allowed in classes - they'll get picked up during the compile.
--    A character class that contains only one character uses 2 or 3 bytes,
--    depending on whether it is negated or not. Notice this where we can. */
--
--    case '[':
--    class_charcount = 0;
--    if (*(++ptr) == '^') ptr++;
--    do
--      {
--      if (*ptr == '\\')
--        {
--        int ch = check_escape(&ptr, errorptr, bracount, options, TRUE,
--          &compile_block);
--        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--        if (-ch == ESC_b) class_charcount++; else class_charcount = 10;
--        }
--      else class_charcount++;
--      ptr++;
--      }
--    while (*ptr != 0 && *ptr != ']');
--
--    /* Repeats for negated single chars are handled by the general code */
--
--    if (class_charcount == 1) length += 3; else
--      {
--      length += 33;
--
--      /* A repeat needs either 1 or 5 bytes. */
--
--      if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
--        {
--        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
--        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--        if ((min == 0 && (max == 1 || max == -1)) ||
--          (min == 1 && max == -1))
--            length++;
--        else length += 5;
--        if (ptr[1] == '?') ptr++;
--        }
--      }
--    continue;
--
--    /* Brackets may be genuine groups or special things */
--
--    case '(':
--    branch_newextra = 0;
--    bracket_length = 3;
--
--    /* Handle special forms of bracket, which all start (? */
--
--    if (ptr[1] == '?')
--      {
--      int set, unset;
--      int *optset;
--
--      switch (c = ptr[2])
--        {
--        /* Skip over comments entirely */
--        case '#':
--        ptr += 3;
--        while (*ptr != 0 && *ptr != ')') ptr++;
--        if (*ptr == 0)
--          {
--          *errorptr = ERR18;
--          goto PCRE_ERROR_RETURN;
--          }
--        continue;
--
--        /* Non-referencing groups and lookaheads just move the pointer on, and
--        then behave like a non-special bracket, except that they don't increment
--        the count of extracting brackets. Ditto for the "once only" bracket,
--        which is in Perl from version 5.005. */
--
--        case ':':
--        case '=':
--        case '!':
--        case '>':
--        ptr += 2;
--        break;
--
--        /* A recursive call to the regex is an extension, to provide the
--        facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */
--
--        case 'R':
--        if (ptr[3] != ')')
--          {
--          *errorptr = ERR29;
--          goto PCRE_ERROR_RETURN;
--          }
--        ptr += 3;
--        length += 1;
--        break;
--
--        /* Lookbehinds are in Perl from version 5.005 */
--
--        case '<':
--        if (ptr[3] == '=' || ptr[3] == '!')
--          {
--          ptr += 3;
--          branch_newextra = 3;
--          length += 3;         /* For the first branch */
--          break;
--          }
--        *errorptr = ERR24;
--        goto PCRE_ERROR_RETURN;
--
--        /* Conditionals are in Perl from version 5.005. The bracket must either
--        be followed by a number (for bracket reference) or by an assertion
--        group. */
--
--        case '(':
--        if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0)
--          {
--          ptr += 4;
--          length += 3;
--          while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++;
--          if (*ptr != ')')
--            {
--            *errorptr = ERR26;
--            goto PCRE_ERROR_RETURN;
--            }
--          }
--        else   /* An assertion must follow */
--          {
--          ptr++;   /* Can treat like ':' as far as spacing is concerned */
--          if (ptr[2] != '?' ||
--             (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') )
--            {
--            ptr += 2;    /* To get right offset in message */
--            *errorptr = ERR28;
--            goto PCRE_ERROR_RETURN;
--            }
--          }
--        break;
--
--        /* Else loop checking valid options until ) is met. Anything else is an
--        error. If we are without any brackets, i.e. at top level, the settings
--        act as if specified in the options, so massage the options immediately.
--        This is for backward compatibility with Perl 5.004. */
--
--        default:
--        set = unset = 0;
--        optset = &set;
--        ptr += 2;
--
--        for (;; ptr++)
--          {
--          c = *ptr;
--          switch (c)
--            {
--            case 'i':
--            *optset |= PCRE_CASELESS;
--            continue;
--
--            case 'm':
--            *optset |= PCRE_MULTILINE;
--            continue;
--
--            case 's':
--            *optset |= PCRE_DOTALL;
--            continue;
--
--            case 'x':
--            *optset |= PCRE_EXTENDED;
--            continue;
--
--            case 'X':
--            *optset |= PCRE_EXTRA;
--            continue;
--
--            case 'U':
--            *optset |= PCRE_UNGREEDY;
--            continue;
--
--            case '-':
--            optset = &unset;
--            continue;
--
--            /* A termination by ')' indicates an options-setting-only item;
--            this is global at top level; otherwise nothing is done here and
--            it is handled during the compiling process on a per-bracket-group
--            basis. */
--
--            case ')':
--            if (brastackptr == 0)
--              {
--              options = (options | set) & (~unset);
--              set = unset = 0;     /* To save length */
--              }
--            /* Fall through */
--
--            /* A termination by ':' indicates the start of a nested group with
--            the given options set. This is again handled at compile time, but
--            we must allow for compiled space if any of the ims options are
--            set. We also have to allow for resetting space at the end of
--            the group, which is why 4 is added to the length and not just 2.
--            If there are several changes of options within the same group, this
--            will lead to an over-estimate on the length, but this shouldn't
--            matter very much. We also have to allow for resetting options at
--            the start of any alternations, which we do by setting
--            branch_newextra to 2. Finally, we record whether the case-dependent
--            flag ever changes within the regex. This is used by the "required
--            character" code. */
--
--            case ':':
--            if (((set|unset) & PCRE_IMS) != 0)
--              {
--              length += 4;
--              branch_newextra = 2;
--              if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
--              }
--            goto END_OPTIONS;
--
--            /* Unrecognized option character */
--
--            default:
--            *errorptr = ERR12;
--            goto PCRE_ERROR_RETURN;
--            }
--          }
--
--        /* If we hit a closing bracket, that's it - this is a freestanding
--        option-setting. We need to ensure that branch_extra is updated if
--        necessary. The only values branch_newextra can have here are 0 or 2.
--        If the value is 2, then branch_extra must either be 2 or 5, depending
--        on whether this is a lookbehind group or not. */
--
--        END_OPTIONS:
--        if (c == ')')
--          {
--          if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3))
--            branch_extra += branch_newextra;
--          continue;
--          }
--
--        /* If options were terminated by ':' control comes here. Fall through
--        to handle the group below. */
--        }
--      }
--
--    /* Extracting brackets must be counted so we can process escapes in a
--    Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to
--    need an additional 3 bytes of store per extracting bracket. */
--
--    else
--      {
--      bracount++;
--      if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3;
--      }
--
--    /* Save length for computing whole length at end if there's a repeat that
--    requires duplication of the group. Also save the current value of
--    branch_extra, and start the new group with the new value. If non-zero, this
--    will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
--
--    if (brastackptr >= sizeof(brastack)/sizeof(int))
--      {
--      *errorptr = ERR19;
--      goto PCRE_ERROR_RETURN;
--      }
--
--    bralenstack[brastackptr] = branch_extra;
--    branch_extra = branch_newextra;
--
--    brastack[brastackptr++] = length;
--    length += bracket_length;
--    continue;
--
--    /* Handle ket. Look for subsequent max/min; for certain sets of values we
--    have to replicate this bracket up to that many times. If brastackptr is
--    0 this is an unmatched bracket which will generate an error, but take care
--    not to try to access brastack[-1] when computing the length and restoring
--    the branch_extra value. */
--
--    case ')':
--    length += 3;
--      {
--      int minval = 1;
--      int maxval = 1;
--      int duplength;
--
--      if (brastackptr > 0)
--        {
--        duplength = length - brastack[--brastackptr];
--        branch_extra = bralenstack[brastackptr];
--        }
--      else duplength = 0;
--
--      /* Leave ptr at the final char; for read_repeat_counts this happens
--      automatically; for the others we need an increment. */
--
--      if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block))
--        {
--        ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr,
--          &compile_block);
--        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--        }
--      else if (c == '*') { minval = 0; maxval = -1; ptr++; }
--      else if (c == '+') { maxval = -1; ptr++; }
--      else if (c == '?') { minval = 0; ptr++; }
--
--      /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
--      group, and if the maximum is greater than zero, we have to replicate
--      maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
--      bracket set - hence the 7. */
--
--      if (minval == 0)
--        {
--        length++;
--        if (maxval > 0) length += (maxval - 1) * (duplength + 7);
--        }
--
--      /* When the minimum is greater than zero, 1 we have to replicate up to
--      minval-1 times, with no additions required in the copies. Then, if
--      there is a limited maximum we have to replicate up to maxval-1 times
--      allowing for a BRAZERO item before each optional copy and nesting
--      brackets for all but one of the optional copies. */
--
--      else
--        {
--        length += (minval - 1) * duplength;
--        if (maxval > minval)   /* Need this test as maxval=-1 means no limit */
--          length += (maxval - minval) * (duplength + 7) - 6;
--        }
--      }
--    continue;
--
--    /* Non-special character. For a run of such characters the length required
--    is the number of characters + 2, except that the maximum run length is 255.
--    We won't get a skipped space or a non-data escape or the start of a #
--    comment as the first character, so the length can't be zero. */
--
--    NORMAL_CHAR:
--    default:
--    length += 2;
--    runlength = 0;
--    do
--      {
--      if ((options & PCRE_EXTENDED) != 0)
--        {
--        if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
--        if (c == '#')
--          {
--          /* The space before the ; is to avoid a warning on a silly compiler
--          on the Macintosh. */
--          while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
--          continue;
--          }
--        }
--
--      /* Backslash may introduce a data char or a metacharacter; stop the
--      string before the latter. */
--
--      if (c == '\\')
--        {
--        const uschar *saveptr = ptr;
--        c = check_escape(&ptr, errorptr, bracount, options, FALSE,
--          &compile_block);
--        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
--        if (c < 0) { ptr = saveptr; break; }
--
--#ifdef SUPPORT_UTF8
--        if (c > 127 && (options & PCRE_UTF8) != 0)
--          {
--          int i;
--          for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
--            if (c <= utf8_table1[i]) break;
--          runlength += i;
--          }
--#endif
--        }
--
--      /* Ordinary character or single-char escape */
--
--      runlength++;
--      }
--
--    /* This "while" is the end of the "do" above. */
--
--    while (runlength < MAXLIT &&
--      (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0);
--
--    ptr--;
--    length += runlength;
--    continue;
--    }
--  }
--
--length += 4;    /* For final KET and END */
--
--if (length > 65539)
--  {
--  *errorptr = ERR20;
--  return NULL;
--  }
--
--/* Compute the size of data block needed and get it, either from malloc or
--externally provided function. We specify "code[0]" in the offsetof() expression
--rather than just "code", because it has been reported that one broken compiler
--fails on "code" because it is also an independent variable. It should make no
--difference to the value of the offsetof(). */
--
--size = length + offsetof(real_pcre, code[0]);
--re = (real_pcre *)(pcre_malloc)(size);
--
--if (re == NULL)
--  {
--  *errorptr = ERR21;
--  return NULL;
--  }
--
--/* size of re is sloppily computed, memset to get consistent output */
--memset(re, 0, size);
--
--/* Put in the magic number, and save the size, options, and table pointer */
--
--re->magic_number = MAGIC_NUMBER;
--re->size = size;
--re->options = options;
--re->tables = tables;
--
--/* Set up a starting, non-extracting bracket, then compile the expression. On
--error, *errorptr will be set non-NULL, so we don't need to look at the result
--of the function here. */
--
--ptr = (const uschar *)pattern;
--code = re->code;
--*code = OP_BRA;
--bracount = 0;
--(void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, 0,
--  &reqchar, &countlits, &compile_block);
--re->top_bracket = bracount;
--re->top_backref = top_backref;
--
--/* If not reached end of pattern on success, there's an excess bracket. */
--
--if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22;
--
--/* Fill in the terminating state and check for disastrous overflow, but
--if debugging, leave the test till after things are printed out. */
--
--*code++ = OP_END;
--
--#ifndef DEBUG
--if (code - re->code > length) *errorptr = ERR23;
--#endif
--
--/* Give an error if there's back reference to a non-existent capturing
--subpattern. */
--
--if (top_backref > re->top_bracket) *errorptr = ERR15;
--
--/* Failed to compile */
--
--if (*errorptr != NULL)
--  {
--  (pcre_free)(re);
--  PCRE_ERROR_RETURN:
--  *erroroffset = ptr - (const uschar *)pattern;
--  return NULL;
--  }
--
--/* If the anchored option was not passed, set flag if we can determine that the
--pattern is anchored by virtue of ^ characters or \A or anything else (such as
--starting with .* when DOTALL is set).
--
--Otherwise, see if we can determine what the first character has to be, because
--that speeds up unanchored matches no end. If not, see if we can set the
--PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
--start with ^. and also when all branches start with .* for non-DOTALL matches.
--*/
--
--if ((options & PCRE_ANCHORED) == 0)
--  {
--  int temp_options = options;
--  if (is_anchored(re->code, &temp_options))
--    re->options |= PCRE_ANCHORED;
--  else
--    {
--    int ch = find_firstchar(re->code, &temp_options);
--    if (ch >= 0)
--      {
--      re->first_char = ch;
--      re->options |= PCRE_FIRSTSET;
--      }
--    else if (is_startline(re->code))
--      re->options |= PCRE_STARTLINE;
--    }
--  }
--
--/* Save the last required character if there are at least two literal
--characters on all paths, or if there is no first character setting. */
--
--if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0))
--  {
--  re->req_char = reqchar;
--  re->options |= PCRE_REQCHSET;
--  }
--
--/* Print out the compiled data for debugging */
--
--#ifdef DEBUG
--
--printf("Length = %d top_bracket = %d top_backref = %d\n",
--  length, re->top_bracket, re->top_backref);
--
--if (re->options != 0)
--  {
--  printf("%s%s%s%s%s%s%s%s%s\n",
--    ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
--    ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
--    ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
--    ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
--    ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
--    ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
--    ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "",
--    ((re->options & PCRE_EXTRA) != 0)? "extra " : "",
--    ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : "");
--  }
--
--if ((re->options & PCRE_FIRSTSET) != 0)
--  {
--  if (isprint(re->first_char)) printf("First char = %c\n", re->first_char);
--    else printf("First char = \\x%02x\n", re->first_char);
--  }
--
--if ((re->options & PCRE_REQCHSET) != 0)
--  {
--  if (isprint(re->req_char)) printf("Req char = %c\n", re->req_char);
--    else printf("Req char = \\x%02x\n", re->req_char);
--  }
--
--code_end = code;
--code_base = code = re->code;
--
--while (code < code_end)
--  {
--  int charlength;
--
--  printf("%3d ", code - code_base);
--
--  if (*code >= OP_BRA)
--    {
--    if (*code - OP_BRA > EXTRACT_BASIC_MAX)
--      printf("%3d Bra extra", (code[1] << 8) + code[2]);
--    else
--      printf("%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA);
--    code += 2;
--    }
--
--  else switch(*code)
--    {
--    case OP_OPT:
--    printf(" %.2x %s", code[1], OP_names[*code]);
--    code++;
--    break;
--
--    case OP_CHARS:
--    charlength = *(++code);
--    printf("%3d ", charlength);
--    while (charlength-- > 0)
--      if (isprint(c = *(++code))) printf("%c", c); else printf("\\x%02x", c);
--    break;
--
--    case OP_KETRMAX:
--    case OP_KETRMIN:
--    case OP_ALT:
--    case OP_KET:
--    case OP_ASSERT:
--    case OP_ASSERT_NOT:
--    case OP_ASSERTBACK:
--    case OP_ASSERTBACK_NOT:
--    case OP_ONCE:
--    case OP_REVERSE:
--    case OP_BRANUMBER:
--    case OP_COND:
--    case OP_CREF:
--    printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]);
--    code += 2;
--    break;
--
--    case OP_STAR:
--    case OP_MINSTAR:
--    case OP_PLUS:
--    case OP_MINPLUS:
--    case OP_QUERY:
--    case OP_MINQUERY:
--    case OP_TYPESTAR:
--    case OP_TYPEMINSTAR:
--    case OP_TYPEPLUS:
--    case OP_TYPEMINPLUS:
--    case OP_TYPEQUERY:
--    case OP_TYPEMINQUERY:
--    if (*code >= OP_TYPESTAR)
--      printf("    %s", OP_names[code[1]]);
--    else if (isprint(c = code[1])) printf("    %c", c);
--      else printf("    \\x%02x", c);
--    printf("%s", OP_names[*code++]);
--    break;
--
--    case OP_EXACT:
--    case OP_UPTO:
--    case OP_MINUPTO:
--    if (isprint(c = code[3])) printf("    %c{", c);
--      else printf("    \\x%02x{", c);
--    if (*code != OP_EXACT) printf("0,");
--    printf("%d}", (code[1] << 8) + code[2]);
--    if (*code == OP_MINUPTO) printf("?");
--    code += 3;
--    break;
--
--    case OP_TYPEEXACT:
--    case OP_TYPEUPTO:
--    case OP_TYPEMINUPTO:
--    printf("    %s{", OP_names[code[3]]);
--    if (*code != OP_TYPEEXACT) printf(",");
--    printf("%d}", (code[1] << 8) + code[2]);
--    if (*code == OP_TYPEMINUPTO) printf("?");
--    code += 3;
--    break;
--
--    case OP_NOT:
--    if (isprint(c = *(++code))) printf("    [^%c]", c);
--      else printf("    [^\\x%02x]", c);
--    break;
--
--    case OP_NOTSTAR:
--    case OP_NOTMINSTAR:
--    case OP_NOTPLUS:
--    case OP_NOTMINPLUS:
--    case OP_NOTQUERY:
--    case OP_NOTMINQUERY:
--    if (isprint(c = code[1])) printf("    [^%c]", c);
--      else printf("    [^\\x%02x]", c);
--    printf("%s", OP_names[*code++]);
--    break;
--
--    case OP_NOTEXACT:
--    case OP_NOTUPTO:
--    case OP_NOTMINUPTO:
--    if (isprint(c = code[3])) printf("    [^%c]{", c);
--      else printf("    [^\\x%02x]{", c);
--    if (*code != OP_NOTEXACT) printf(",");
--    printf("%d}", (code[1] << 8) + code[2]);
--    if (*code == OP_NOTMINUPTO) printf("?");
--    code += 3;
--    break;
--
--    case OP_REF:
--    printf("    \\%d", (code[1] << 8) | code[2]);
--    code += 3;
--    goto CLASS_REF_REPEAT;
--
--    case OP_CLASS:
--      {
--      int i, min, max;
--      code++;
--      printf("    [");
--
--      for (i = 0; i < 256; i++)
--        {
--        if ((code[i/8] & (1 << (i&7))) != 0)
--          {
--          int j;
--          for (j = i+1; j < 256; j++)
--            if ((code[j/8] & (1 << (j&7))) == 0) break;
--          if (i == '-' || i == ']') printf("\\");
--          if (isprint(i)) printf("%c", i); else printf("\\x%02x", i);
--          if (--j > i)
--            {
--            printf("-");
--            if (j == '-' || j == ']') printf("\\");
--            if (isprint(j)) printf("%c", j); else printf("\\x%02x", j);
--            }
--          i = j;
--          }
--        }
--      printf("]");
--      code += 32;
--
--      CLASS_REF_REPEAT:
--
--      switch(*code)
--        {
--        case OP_CRSTAR:
--        case OP_CRMINSTAR:
--        case OP_CRPLUS:
--        case OP_CRMINPLUS:
--        case OP_CRQUERY:
--        case OP_CRMINQUERY:
--        printf("%s", OP_names[*code]);
--        break;
--
--        case OP_CRRANGE:
--        case OP_CRMINRANGE:
--        min = (code[1] << 8) + code[2];
--        max = (code[3] << 8) + code[4];
--        if (max == 0) printf("{%d,}", min);
--        else printf("{%d,%d}", min, max);
--        if (*code == OP_CRMINRANGE) printf("?");
--        code += 4;
--        break;
--
--        default:
--        code--;
--        }
--      }
--    break;
--
--    /* Anything else is just a one-node item */
--
--    default:
--    printf("    %s", OP_names[*code]);
--    break;
--    }
--
--  code++;
--  printf("\n");
--  }
--printf("------------------------------------------------------------------\n");
--
--/* This check is done here in the debugging case so that the code that
--was compiled can be seen. */
--
--if (code - re->code > length)
--  {
--  *errorptr = ERR23;
--  (pcre_free)(re);
--  *erroroffset = ptr - (uschar *)pattern;
--  return NULL;
--  }
--#endif
--
--return (pcre *)re;
--}
--
--
--
--/*************************************************
--*          Match a back-reference                *
--*************************************************/
--
--/* If a back reference hasn't been set, the length that is passed is greater
--than the number of characters left in the string, so the match fails.
--
--Arguments:
--  offset      index into the offset vector
--  eptr        points into the subject
--  length      length to be matched
--  md          points to match data block
--  ims         the ims flags
--
--Returns:      TRUE if matched
--*/
--
--static BOOL
--match_ref(int offset, register const uschar *eptr, int length, match_data *md,
--  unsigned long int ims)
--{
--const uschar *p = md->start_subject + md->offset_vector[offset];
--
--#ifdef DEBUG
--if (eptr >= md->end_subject)
--  printf("matching subject <null>");
--else
--  {
--  printf("matching subject ");
--  pchars(eptr, length, TRUE, md);
--  }
--printf(" against backref ");
--pchars(p, length, FALSE, md);
--printf("\n");
--#endif
--
--/* Always fail if not enough characters left */
--
--if (length > md->end_subject - eptr) return FALSE;
--
--/* Separate the caselesss case for speed */
--
--if ((ims & PCRE_CASELESS) != 0)
--  {
--  while (length-- > 0)
--    if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
--  }
--else
--  { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
--
--return TRUE;
--}
--
--
--
--/*************************************************
--*         Match from current position            *
--*************************************************/
--
--/* On entry ecode points to the first opcode, and eptr to the first character
--in the subject string, while eptrb holds the value of eptr at the start of the
--last bracketed group - used for breaking infinite loops matching zero-length
--strings.
--
--Arguments:
--   eptr        pointer in subject
--   ecode       position in code
--   offset_top  current top pointer
--   md          pointer to "static" info for the match
--   ims         current /i, /m, and /s options
--   eptrb       pointer to chain of blocks containing eptr at start of
--                 brackets - for testing for empty matches
--   flags       can contain
--                 match_condassert - this is an assertion condition
--                 match_isgroup - this is the start of a bracketed group
--
--Returns:       TRUE if matched
--*/
--
--static BOOL
--match(register const uschar *eptr, register const uschar *ecode,
--  int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
--  int flags)
--{
--unsigned long int original_ims = ims;   /* Save for resetting on ')' */
--eptrblock newptrb;
--
--/* At the start of a bracketed group, add the current subject pointer to the
--stack of such pointers, to be re-instated at the end of the group when we hit
--the closing ket. When match() is called in other circumstances, we don't add to
--the stack. */
--
--if ((flags & match_isgroup) != 0)
--  {
--  newptrb.prev = eptrb;
--  newptrb.saved_eptr = eptr;
--  eptrb = &newptrb;
--  }
--
--/* Now start processing the operations. */
--
--for (;;)
--  {
--  int op = (int)*ecode;
--  int min, max, ctype;
--  register int i;
--  register int c;
--  BOOL minimize = FALSE;
--
--  /* Opening capturing bracket. If there is space in the offset vector, save
--  the current subject position in the working slot at the top of the vector. We
--  mustn't change the current values of the data slot, because they may be set
--  from a previous iteration of this group, and be referred to by a reference
--  inside the group.
--
--  If the bracket fails to match, we need to restore this value and also the
--  values of the final offsets, in case they were set by a previous iteration of
--  the same bracket.
--
--  If there isn't enough space in the offset vector, treat this as if it were a
--  non-capturing bracket. Don't worry about setting the flag for the error case
--  here; that is handled in the code for KET. */
--
--  if (op > OP_BRA)
--    {
--    int offset;
--    int number = op - OP_BRA;
--
--    /* For extended extraction brackets (large number), we have to fish out the
--    number from a dummy opcode at the start. */
--
--    if (number > EXTRACT_BASIC_MAX) number = (ecode[4] << 8) | ecode[5];
--    offset = number << 1;
--
--#ifdef DEBUG
--    printf("start bracket %d subject=", number);
--    pchars(eptr, 16, TRUE, md);
--    printf("\n");
--#endif
--
--    if (offset < md->offset_max)
--      {
--      int save_offset1 = md->offset_vector[offset];
--      int save_offset2 = md->offset_vector[offset+1];
--      int save_offset3 = md->offset_vector[md->offset_end - number];
--
--      DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
--      md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
--
--      do
--        {
--        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
--          return TRUE;
--        ecode += (ecode[1] << 8) + ecode[2];
--        }
--      while (*ecode == OP_ALT);
--
--      DPRINTF(("bracket %d failed\n", number));
--
--      md->offset_vector[offset] = save_offset1;
--      md->offset_vector[offset+1] = save_offset2;
--      md->offset_vector[md->offset_end - number] = save_offset3;
--
--      return FALSE;
--      }
--
--    /* Insufficient room for saving captured contents */
--
--    else op = OP_BRA;
--    }
--
--  /* Other types of node can be handled by a switch */
--
--  switch(op)
--    {
--    case OP_BRA:     /* Non-capturing bracket: optimized */
--    DPRINTF(("start bracket 0\n"));
--    do
--      {
--      if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
--        return TRUE;
--      ecode += (ecode[1] << 8) + ecode[2];
--      }
--    while (*ecode == OP_ALT);
--    DPRINTF(("bracket 0 failed\n"));
--    return FALSE;
--
--    /* Conditional group: compilation checked that there are no more than
--    two branches. If the condition is false, skipping the first branch takes us
--    past the end if there is only one branch, but that's OK because that is
--    exactly what going to the ket would do. */
--
--    case OP_COND:
--    if (ecode[3] == OP_CREF)         /* Condition is extraction test */
--      {
--      int offset = (ecode[4] << 9) | (ecode[5] << 1); /* Doubled ref number */
--      return match(eptr,
--        ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)?
--          6 : 3 + (ecode[1] << 8) + ecode[2]),
--        offset_top, md, ims, eptrb, match_isgroup);
--      }
--
--    /* The condition is an assertion. Call match() to evaluate it - setting
--    the final argument TRUE causes it to stop at the end of an assertion. */
--
--    else
--      {
--      if (match(eptr, ecode+3, offset_top, md, ims, NULL,
--          match_condassert | match_isgroup))
--        {
--        ecode += 3 + (ecode[4] << 8) + ecode[5];
--        while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2];
--        }
--      else ecode += (ecode[1] << 8) + ecode[2];
--      return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup);
--      }
--    /* Control never reaches here */
--
--    /* Skip over conditional reference or large extraction number data if
--    encountered. */
--
--    case OP_CREF:
--    case OP_BRANUMBER:
--    ecode += 3;
--    break;
--
--    /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched
--    an empty string - recursion will then try other alternatives, if any. */
--
--    case OP_END:
--    if (md->notempty && eptr == md->start_match) return FALSE;
--    md->end_match_ptr = eptr;          /* Record where we ended */
--    md->end_offset_top = offset_top;   /* and how many extracts were taken */
--    return TRUE;
--
--    /* Change option settings */
--
--    case OP_OPT:
--    ims = ecode[1];
--    ecode += 2;
--    DPRINTF(("ims set to %02lx\n", ims));
--    break;
--
--    /* Assertion brackets. Check the alternative branches in turn - the
--    matching won't pass the KET for an assertion. If any one branch matches,
--    the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
--    start of each branch to move the current point backwards, so the code at
--    this level is identical to the lookahead case. */
--
--    case OP_ASSERT:
--    case OP_ASSERTBACK:
--    do
--      {
--      if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break;
--      ecode += (ecode[1] << 8) + ecode[2];
--      }
--    while (*ecode == OP_ALT);
--    if (*ecode == OP_KET) return FALSE;
--
--    /* If checking an assertion for a condition, return TRUE. */
--
--    if ((flags & match_condassert) != 0) return TRUE;
--
--    /* Continue from after the assertion, updating the offsets high water
--    mark, since extracts may have been taken during the assertion. */
--
--    do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
--    ecode += 3;
--    offset_top = md->end_offset_top;
--    continue;
--
--    /* Negative assertion: all branches must fail to match */
--
--    case OP_ASSERT_NOT:
--    case OP_ASSERTBACK_NOT:
--    do
--      {
--      if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup))
--        return FALSE;
--      ecode += (ecode[1] << 8) + ecode[2];
--      }
--    while (*ecode == OP_ALT);
--
--    if ((flags & match_condassert) != 0) return TRUE;
--
--    ecode += 3;
--    continue;
--
--    /* Move the subject pointer back. This occurs only at the start of
--    each branch of a lookbehind assertion. If we are too close to the start to
--    move back, this match function fails. When working with UTF-8 we move
--    back a number of characters, not bytes. */
--
--    case OP_REVERSE:
--#ifdef SUPPORT_UTF8
--    c = (ecode[1] << 8) + ecode[2];
--    for (i = 0; i < c; i++)
--      {
--      eptr--;
--      BACKCHAR(eptr)
--      }
--#else
--    eptr -= (ecode[1] << 8) + ecode[2];
--#endif
--
--    if (eptr < md->start_subject) return FALSE;
--    ecode += 3;
--    break;
--
--    /* Recursion matches the current regex, nested. If there are any capturing
--    brackets started but not finished, we have to save their starting points
--    and reinstate them after the recursion. However, we don't know how many
--    such there are (offset_top records the completed total) so we just have
--    to save all the potential data. There may be up to 99 such values, which
--    is a bit large to put on the stack, but using malloc for small numbers
--    seems expensive. As a compromise, the stack is used when there are fewer
--    than 16 values to store; otherwise malloc is used. A problem is what to do
--    if the malloc fails ... there is no way of returning to the top level with
--    an error. Save the top 15 values on the stack, and accept that the rest
--    may be wrong. */
--
--    case OP_RECURSE:
--      {
--      BOOL rc;
--      int *save;
--      int stacksave[15];
--
--      c = md->offset_max;
--
--      if (c < 16) save = stacksave; else
--        {
--        save = (int *)(pcre_malloc)((c+1) * sizeof(int));
--        if (save == NULL)
--          {
--          save = stacksave;
--          c = 15;
--          }
--        }
--
--      for (i = 1; i <= c; i++)
--        save[i] = md->offset_vector[md->offset_end - i];
--      rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb,
--        match_isgroup);
--      for (i = 1; i <= c; i++)
--        md->offset_vector[md->offset_end - i] = save[i];
--      if (save != stacksave) (pcre_free)(save);
--      if (!rc) return FALSE;
--
--      /* In case the recursion has set more capturing values, save the final
--      number, then move along the subject till after the recursive match,
--      and advance one byte in the pattern code. */
--
--      offset_top = md->end_offset_top;
--      eptr = md->end_match_ptr;
--      ecode++;
--      }
--    break;
--
--    /* "Once" brackets are like assertion brackets except that after a match,
--    the point in the subject string is not moved back. Thus there can never be
--    a move back into the brackets. Check the alternative branches in turn - the
--    matching won't pass the KET for this kind of subpattern. If any one branch
--    matches, we carry on as at the end of a normal bracket, leaving the subject
--    pointer. */
--
--    case OP_ONCE:
--      {
--      const uschar *prev = ecode;
--      const uschar *saved_eptr = eptr;
--
--      do
--        {
--        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
--          break;
--        ecode += (ecode[1] << 8) + ecode[2];
--        }
--      while (*ecode == OP_ALT);
--
--      /* If hit the end of the group (which could be repeated), fail */
--
--      if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE;
--
--      /* Continue as from after the assertion, updating the offsets high water
--      mark, since extracts may have been taken. */
--
--      do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
--
--      offset_top = md->end_offset_top;
--      eptr = md->end_match_ptr;
--
--      /* For a non-repeating ket, just continue at this level. This also
--      happens for a repeating ket if no characters were matched in the group.
--      This is the forcible breaking of infinite loops as implemented in Perl
--      5.005. If there is an options reset, it will get obeyed in the normal
--      course of events. */
--
--      if (*ecode == OP_KET || eptr == saved_eptr)
--        {
--        ecode += 3;
--        break;
--        }
--
--      /* The repeating kets try the rest of the pattern or restart from the
--      preceding bracket, in the appropriate order. We need to reset any options
--      that changed within the bracket before re-running it, so check the next
--      opcode. */
--
--      if (ecode[3] == OP_OPT)
--        {
--        ims = (ims & ~PCRE_IMS) | ecode[4];
--        DPRINTF(("ims set to %02lx at group repeat\n", ims));
--        }
--
--      if (*ecode == OP_KETRMIN)
--        {
--        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
--            match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
--              return TRUE;
--        }
--      else  /* OP_KETRMAX */
--        {
--        if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
--            match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
--        }
--      }
--    return FALSE;
--
--    /* An alternation is the end of a branch; scan along to find the end of the
--    bracketed group and go to there. */
--
--    case OP_ALT:
--    do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
--    break;
--
--    /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
--    that it may occur zero times. It may repeat infinitely, or not at all -
--    i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
--    repeat limits are compiled as a number of copies, with the optional ones
--    preceded by BRAZERO or BRAMINZERO. */
--
--    case OP_BRAZERO:
--      {
--      const uschar *next = ecode+1;
--      if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup))
--        return TRUE;
--      do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
--      ecode = next + 3;
--      }
--    break;
--
--    case OP_BRAMINZERO:
--      {
--      const uschar *next = ecode+1;
--      do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
--      if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup))
--        return TRUE;
--      ecode++;
--      }
--    break;
--
--    /* End of a group, repeated or non-repeating. If we are at the end of
--    an assertion "group", stop matching and return TRUE, but record the
--    current high water mark for use by positive assertions. Do this also
--    for the "once" (not-backup up) groups. */
--
--    case OP_KET:
--    case OP_KETRMIN:
--    case OP_KETRMAX:
--      {
--      const uschar *prev = ecode - (ecode[1] << 8) - ecode[2];
--      const uschar *saved_eptr = eptrb->saved_eptr;
--
--      eptrb = eptrb->prev;    /* Back up the stack of bracket start pointers */
--
--      if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
--          *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
--          *prev == OP_ONCE)
--        {
--        md->end_match_ptr = eptr;      /* For ONCE */
--        md->end_offset_top = offset_top;
--        return TRUE;
--        }
--
--      /* In all other cases except a conditional group we have to check the
--      group number back at the start and if necessary complete handling an
--      extraction by setting the offsets and bumping the high water mark. */
--
--      if (*prev != OP_COND)
--        {
--        int offset;
--        int number = *prev - OP_BRA;
--
--        /* For extended extraction brackets (large number), we have to fish out
--        the number from a dummy opcode at the start. */
--
--        if (number > EXTRACT_BASIC_MAX) number = (prev[4] << 8) | prev[5];
--        offset = number << 1;
--
--#ifdef DEBUG
--        printf("end bracket %d", number);
--        printf("\n");
--#endif
--
--        if (number > 0)
--          {
--          if (offset >= md->offset_max) md->offset_overflow = TRUE; else
--            {
--            md->offset_vector[offset] =
--              md->offset_vector[md->offset_end - number];
--            md->offset_vector[offset+1] = eptr - md->start_subject;
--            if (offset_top <= offset) offset_top = offset + 2;
--            }
--          }
--        }
--
--      /* Reset the value of the ims flags, in case they got changed during
--      the group. */
--
--      ims = original_ims;
--      DPRINTF(("ims reset to %02lx\n", ims));
--
--      /* For a non-repeating ket, just continue at this level. This also
--      happens for a repeating ket if no characters were matched in the group.
--      This is the forcible breaking of infinite loops as implemented in Perl
--      5.005. If there is an options reset, it will get obeyed in the normal
--      course of events. */
--
--      if (*ecode == OP_KET || eptr == saved_eptr)
--        {
--        ecode += 3;
--        break;
--        }
--
--      /* The repeating kets try the rest of the pattern or restart from the
--      preceding bracket, in the appropriate order. */
--
--      if (*ecode == OP_KETRMIN)
--        {
--        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
--            match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
--              return TRUE;
--        }
--      else  /* OP_KETRMAX */
--        {
--        if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
--            match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
--        }
--      }
--    return FALSE;
--
--    /* Start of subject unless notbol, or after internal newline if multiline */
--
--    case OP_CIRC:
--    if (md->notbol && eptr == md->start_subject) return FALSE;
--    if ((ims & PCRE_MULTILINE) != 0)
--      {
--      if (eptr != md->start_subject && eptr[-1] != NEWLINE) return FALSE;
--      ecode++;
--      break;
--      }
--    /* ... else fall through */
--
--    /* Start of subject assertion */
--
--    case OP_SOD:
--    if (eptr != md->start_subject) return FALSE;
--    ecode++;
--    break;
--
--    /* Assert before internal newline if multiline, or before a terminating
--    newline unless endonly is set, else end of subject unless noteol is set. */
--
--    case OP_DOLL:
--    if ((ims & PCRE_MULTILINE) != 0)
--      {
--      if (eptr < md->end_subject) { if (*eptr != NEWLINE) return FALSE; }
--        else { if (md->noteol) return FALSE; }
--      ecode++;
--      break;
--      }
--    else
--      {
--      if (md->noteol) return FALSE;
--      if (!md->endonly)
--        {
--        if (eptr < md->end_subject - 1 ||
--           (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
--
--        ecode++;
--        break;
--        }
--      }
--    /* ... else fall through */
--
--    /* End of subject assertion (\z) */
--
--    case OP_EOD:
--    if (eptr < md->end_subject) return FALSE;
--    ecode++;
--    break;
--
--    /* End of subject or ending \n assertion (\Z) */
--
--    case OP_EODN:
--    if (eptr < md->end_subject - 1 ||
--       (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
--    ecode++;
--    break;
--
--    /* Word boundary assertions */
--
--    case OP_NOT_WORD_BOUNDARY:
--    case OP_WORD_BOUNDARY:
--      {
--      BOOL prev_is_word = (eptr != md->start_subject) &&
--        ((md->ctypes[eptr[-1]] & ctype_word) != 0);
--      BOOL cur_is_word = (eptr < md->end_subject) &&
--        ((md->ctypes[*eptr] & ctype_word) != 0);
--      if ((*ecode++ == OP_WORD_BOUNDARY)?
--           cur_is_word == prev_is_word : cur_is_word != prev_is_word)
--        return FALSE;
--      }
--    break;
--
--    /* Match a single character type; inline for speed */
--
--    case OP_ANY:
--    if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
--      return FALSE;
--    if (eptr++ >= md->end_subject) return FALSE;
--#ifdef SUPPORT_UTF8
--    if (md->utf8)
--      while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--#endif
--    ecode++;
--    break;
--
--    case OP_NOT_DIGIT:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_digit) != 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    case OP_DIGIT:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_digit) == 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    case OP_NOT_WHITESPACE:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_space) != 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    case OP_WHITESPACE:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_space) == 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    case OP_NOT_WORDCHAR:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_word) != 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    case OP_WORDCHAR:
--    if (eptr >= md->end_subject ||
--       (md->ctypes[*eptr++] & ctype_word) == 0)
--      return FALSE;
--    ecode++;
--    break;
--
--    /* Match a back reference, possibly repeatedly. Look past the end of the
--    item to see if there is repeat information following. The code is similar
--    to that for character classes, but repeated for efficiency. Then obey
--    similar code to character type repeats - written out again for speed.
--    However, if the referenced string is the empty string, always treat
--    it as matched, any number of times (otherwise there could be infinite
--    loops). */
--
--    case OP_REF:
--      {
--      int length;
--      int offset = (ecode[1] << 9) | (ecode[2] << 1); /* Doubled ref number */
--      ecode += 3;                                     /* Advance past item */
--
--      /* If the reference is unset, set the length to be longer than the amount
--      of subject left; this ensures that every attempt at a match fails. We
--      can't just fail here, because of the possibility of quantifiers with zero
--      minima. */
--
--      length = (offset >= offset_top || md->offset_vector[offset] < 0)?
--        md->end_subject - eptr + 1 :
--        md->offset_vector[offset+1] - md->offset_vector[offset];
--
--      /* Set up for repetition, or handle the non-repeated case */
--
--      switch (*ecode)
--        {
--        case OP_CRSTAR:
--        case OP_CRMINSTAR:
--        case OP_CRPLUS:
--        case OP_CRMINPLUS:
--        case OP_CRQUERY:
--        case OP_CRMINQUERY:
--        c = *ecode++ - OP_CRSTAR;
--        minimize = (c & 1) != 0;
--        min = rep_min[c];                 /* Pick up values from tables; */
--        max = rep_max[c];                 /* zero for max => infinity */
--        if (max == 0) max = INT_MAX;
--        break;
--
--        case OP_CRRANGE:
--        case OP_CRMINRANGE:
--        minimize = (*ecode == OP_CRMINRANGE);
--        min = (ecode[1] << 8) + ecode[2];
--        max = (ecode[3] << 8) + ecode[4];
--        if (max == 0) max = INT_MAX;
--        ecode += 5;
--        break;
--
--        default:               /* No repeat follows */
--        if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
--        eptr += length;
--        continue;              /* With the main loop */
--        }
--
--      /* If the length of the reference is zero, just continue with the
--      main loop. */
--
--      if (length == 0) continue;
--
--      /* First, ensure the minimum number of matches are present. We get back
--      the length of the reference string explicitly rather than passing the
--      address of eptr, so that eptr can be a register variable. */
--
--      for (i = 1; i <= min; i++)
--        {
--        if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
--        eptr += length;
--        }
--
--      /* If min = max, continue at the same level without recursion.
--      They are not both allowed to be zero. */
--
--      if (min == max) continue;
--
--      /* If minimizing, keep trying and advancing the pointer */
--
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || !match_ref(offset, eptr, length, md, ims))
--            return FALSE;
--          eptr += length;
--          }
--        /* Control never gets here */
--        }
--
--      /* If maximizing, find the longest string and work backwards */
--
--      else
--        {
--        const uschar *pp = eptr;
--        for (i = min; i < max; i++)
--          {
--          if (!match_ref(offset, eptr, length, md, ims)) break;
--          eptr += length;
--          }
--        while (eptr >= pp)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          eptr -= length;
--          }
--        return FALSE;
--        }
--      }
--    /* Control never gets here */
--
--
--
--    /* Match a character class, possibly repeatedly. Look past the end of the
--    item to see if there is repeat information following. Then obey similar
--    code to character type repeats - written out again for speed. */
--
--    case OP_CLASS:
--      {
--      const uschar *data = ecode + 1;  /* Save for matching */
--      ecode += 33;                     /* Advance past the item */
--
--      switch (*ecode)
--        {
--        case OP_CRSTAR:
--        case OP_CRMINSTAR:
--        case OP_CRPLUS:
--        case OP_CRMINPLUS:
--        case OP_CRQUERY:
--        case OP_CRMINQUERY:
--        c = *ecode++ - OP_CRSTAR;
--        minimize = (c & 1) != 0;
--        min = rep_min[c];                 /* Pick up values from tables; */
--        max = rep_max[c];                 /* zero for max => infinity */
--        if (max == 0) max = INT_MAX;
--        break;
--
--        case OP_CRRANGE:
--        case OP_CRMINRANGE:
--        minimize = (*ecode == OP_CRMINRANGE);
--        min = (ecode[1] << 8) + ecode[2];
--        max = (ecode[3] << 8) + ecode[4];
--        if (max == 0) max = INT_MAX;
--        ecode += 5;
--        break;
--
--        default:               /* No repeat follows */
--        min = max = 1;
--        break;
--        }
--
--      /* First, ensure the minimum number of matches are present. */
--
--      for (i = 1; i <= min; i++)
--        {
--        if (eptr >= md->end_subject) return FALSE;
--        GETCHARINC(c, eptr)         /* Get character; increment eptr */
--
--#ifdef SUPPORT_UTF8
--        /* We do not yet support class members > 255 */
--        if (c > 255) return FALSE;
--#endif
--
--        if ((data[c/8] & (1 << (c&7))) != 0) continue;
--        return FALSE;
--        }
--
--      /* If max == min we can continue with the main loop without the
--      need to recurse. */
--
--      if (min == max) continue;
--
--      /* If minimizing, keep testing the rest of the expression and advancing
--      the pointer while it matches the class. */
--
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || eptr >= md->end_subject) return FALSE;
--          GETCHARINC(c, eptr)       /* Get character; increment eptr */
--
--#ifdef SUPPORT_UTF8
--          /* We do not yet support class members > 255 */
--          if (c > 255) return FALSE;
--#endif
--          if ((data[c/8] & (1 << (c&7))) != 0) continue;
--          return FALSE;
--          }
--        /* Control never gets here */
--        }
--
--      /* If maximizing, find the longest possible run, then work backwards. */
--
--      else
--        {
--        const uschar *pp = eptr;
--        int len = 1;
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject) break;
--          GETCHARLEN(c, eptr, len)  /* Get character, set length if UTF-8 */
--
--#ifdef SUPPORT_UTF8
--          /* We do not yet support class members > 255 */
--          if (c > 255) break;
--#endif
--          if ((data[c/8] & (1 << (c&7))) == 0) break;
--          eptr += len;
--          }
--
--        while (eptr >= pp)
--          {
--          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--
--#ifdef SUPPORT_UTF8
--          BACKCHAR(eptr)
--#endif
--          }
--        return FALSE;
--        }
--      }
--    /* Control never gets here */
--
--    /* Match a run of characters */
--
--    case OP_CHARS:
--      {
--      register int length = ecode[1];
--      ecode += 2;
--
--#ifdef DEBUG    /* Sigh. Some compilers never learn. */
--      if (eptr >= md->end_subject)
--        printf("matching subject <null> against pattern ");
--      else
--        {
--        printf("matching subject ");
--        pchars(eptr, length, TRUE, md);
--        printf(" against pattern ");
--        }
--      pchars(ecode, length, FALSE, md);
--      printf("\n");
--#endif
--
--      if (length > md->end_subject - eptr) return FALSE;
--      if ((ims & PCRE_CASELESS) != 0)
--        {
--        while (length-- > 0)
--          if (md->lcc[*ecode++] != md->lcc[*eptr++])
--            return FALSE;
--        }
--      else
--        {
--        while (length-- > 0) if (*ecode++ != *eptr++) return FALSE;
--        }
--      }
--    break;
--
--    /* Match a single character repeatedly; different opcodes share code. */
--
--    case OP_EXACT:
--    min = max = (ecode[1] << 8) + ecode[2];
--    ecode += 3;
--    goto REPEATCHAR;
--
--    case OP_UPTO:
--    case OP_MINUPTO:
--    min = 0;
--    max = (ecode[1] << 8) + ecode[2];
--    minimize = *ecode == OP_MINUPTO;
--    ecode += 3;
--    goto REPEATCHAR;
--
--    case OP_STAR:
--    case OP_MINSTAR:
--    case OP_PLUS:
--    case OP_MINPLUS:
--    case OP_QUERY:
--    case OP_MINQUERY:
--    c = *ecode++ - OP_STAR;
--    minimize = (c & 1) != 0;
--    min = rep_min[c];                 /* Pick up values from tables; */
--    max = rep_max[c];                 /* zero for max => infinity */
--    if (max == 0) max = INT_MAX;
--
--    /* Common code for all repeated single-character matches. We can give
--    up quickly if there are fewer than the minimum number of characters left in
--    the subject. */
--
--    REPEATCHAR:
--    if (min > md->end_subject - eptr) return FALSE;
--    c = *ecode++;
--
--    /* The code is duplicated for the caseless and caseful cases, for speed,
--    since matching characters is likely to be quite common. First, ensure the
--    minimum number of matches are present. If min = max, continue at the same
--    level without recursing. Otherwise, if minimizing, keep trying the rest of
--    the expression and advancing one matching character if failing, up to the
--    maximum. Alternatively, if maximizing, find the maximum number of
--    characters and work backwards. */
--
--    DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max,
--      max, eptr));
--
--    if ((ims & PCRE_CASELESS) != 0)
--      {
--      c = md->lcc[c];
--      for (i = 1; i <= min; i++)
--        if (c != md->lcc[*eptr++]) return FALSE;
--      if (min == max) continue;
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || eptr >= md->end_subject ||
--              c != md->lcc[*eptr++])
--            return FALSE;
--          }
--        /* Control never gets here */
--        }
--      else
--        {
--        const uschar *pp = eptr;
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || c != md->lcc[*eptr]) break;
--          eptr++;
--          }
--        while (eptr >= pp)
--          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--        return FALSE;
--        }
--      /* Control never gets here */
--      }
--
--    /* Caseful comparisons */
--
--    else
--      {
--      for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE;
--      if (min == max) continue;
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE;
--          }
--        /* Control never gets here */
--        }
--      else
--        {
--        const uschar *pp = eptr;
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || c != *eptr) break;
--          eptr++;
--          }
--        while (eptr >= pp)
--         if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--           return TRUE;
--        return FALSE;
--        }
--      }
--    /* Control never gets here */
--
--    /* Match a negated single character */
--
--    case OP_NOT:
--    if (eptr >= md->end_subject) return FALSE;
--    ecode++;
--    if ((ims & PCRE_CASELESS) != 0)
--      {
--      if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE;
--      }
--    else
--      {
--      if (*ecode++ == *eptr++) return FALSE;
--      }
--    break;
--
--    /* Match a negated single character repeatedly. This is almost a repeat of
--    the code for a repeated single character, but I haven't found a nice way of
--    commoning these up that doesn't require a test of the positive/negative
--    option for each character match. Maybe that wouldn't add very much to the
--    time taken, but character matching *is* what this is all about... */
--
--    case OP_NOTEXACT:
--    min = max = (ecode[1] << 8) + ecode[2];
--    ecode += 3;
--    goto REPEATNOTCHAR;
--
--    case OP_NOTUPTO:
--    case OP_NOTMINUPTO:
--    min = 0;
--    max = (ecode[1] << 8) + ecode[2];
--    minimize = *ecode == OP_NOTMINUPTO;
--    ecode += 3;
--    goto REPEATNOTCHAR;
--
--    case OP_NOTSTAR:
--    case OP_NOTMINSTAR:
--    case OP_NOTPLUS:
--    case OP_NOTMINPLUS:
--    case OP_NOTQUERY:
--    case OP_NOTMINQUERY:
--    c = *ecode++ - OP_NOTSTAR;
--    minimize = (c & 1) != 0;
--    min = rep_min[c];                 /* Pick up values from tables; */
--    max = rep_max[c];                 /* zero for max => infinity */
--    if (max == 0) max = INT_MAX;
--
--    /* Common code for all repeated single-character matches. We can give
--    up quickly if there are fewer than the minimum number of characters left in
--    the subject. */
--
--    REPEATNOTCHAR:
--    if (min > md->end_subject - eptr) return FALSE;
--    c = *ecode++;
--
--    /* The code is duplicated for the caseless and caseful cases, for speed,
--    since matching characters is likely to be quite common. First, ensure the
--    minimum number of matches are present. If min = max, continue at the same
--    level without recursing. Otherwise, if minimizing, keep trying the rest of
--    the expression and advancing one matching character if failing, up to the
--    maximum. Alternatively, if maximizing, find the maximum number of
--    characters and work backwards. */
--
--    DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max,
--      max, eptr));
--
--    if ((ims & PCRE_CASELESS) != 0)
--      {
--      c = md->lcc[c];
--      for (i = 1; i <= min; i++)
--        if (c == md->lcc[*eptr++]) return FALSE;
--      if (min == max) continue;
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || eptr >= md->end_subject ||
--              c == md->lcc[*eptr++])
--            return FALSE;
--          }
--        /* Control never gets here */
--        }
--      else
--        {
--        const uschar *pp = eptr;
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || c == md->lcc[*eptr]) break;
--          eptr++;
--          }
--        while (eptr >= pp)
--          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--        return FALSE;
--        }
--      /* Control never gets here */
--      }
--
--    /* Caseful comparisons */
--
--    else
--      {
--      for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE;
--      if (min == max) continue;
--      if (minimize)
--        {
--        for (i = min;; i++)
--          {
--          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
--            return TRUE;
--          if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE;
--          }
--        /* Control never gets here */
--        }
--      else
--        {
--        const uschar *pp = eptr;
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || c == *eptr) break;
--          eptr++;
--          }
--        while (eptr >= pp)
--         if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--           return TRUE;
--        return FALSE;
--        }
--      }
--    /* Control never gets here */
--
--    /* Match a single character type repeatedly; several different opcodes
--    share code. This is very similar to the code for single characters, but we
--    repeat it in the interests of efficiency. */
--
--    case OP_TYPEEXACT:
--    min = max = (ecode[1] << 8) + ecode[2];
--    minimize = TRUE;
--    ecode += 3;
--    goto REPEATTYPE;
--
--    case OP_TYPEUPTO:
--    case OP_TYPEMINUPTO:
--    min = 0;
--    max = (ecode[1] << 8) + ecode[2];
--    minimize = *ecode == OP_TYPEMINUPTO;
--    ecode += 3;
--    goto REPEATTYPE;
--
--    case OP_TYPESTAR:
--    case OP_TYPEMINSTAR:
--    case OP_TYPEPLUS:
--    case OP_TYPEMINPLUS:
--    case OP_TYPEQUERY:
--    case OP_TYPEMINQUERY:
--    c = *ecode++ - OP_TYPESTAR;
--    minimize = (c & 1) != 0;
--    min = rep_min[c];                 /* Pick up values from tables; */
--    max = rep_max[c];                 /* zero for max => infinity */
--    if (max == 0) max = INT_MAX;
--
--    /* Common code for all repeated single character type matches */
--
--    REPEATTYPE:
--    ctype = *ecode++;      /* Code for the character type */
--
--    /* First, ensure the minimum number of matches are present. Use inline
--    code for maximizing the speed, and do the type test once at the start
--    (i.e. keep it out of the loop). Also we can test that there are at least
--    the minimum number of bytes before we start, except when doing '.' in
--    UTF8 mode. Leave the test in in all cases; in the special case we have
--    to test after each character. */
--
--    if (min > md->end_subject - eptr) return FALSE;
--    if (min > 0) switch(ctype)
--      {
--      case OP_ANY:
--#ifdef SUPPORT_UTF8
--      if (md->utf8)
--        {
--        for (i = 1; i <= min; i++)
--          {
--          if (eptr >= md->end_subject ||
--             (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
--            return FALSE;
--          while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--          }
--        break;
--        }
--#endif
--      /* Non-UTF8 can be faster */
--      if ((ims & PCRE_DOTALL) == 0)
--        { for (i = 1; i <= min; i++) if (*eptr++ == NEWLINE) return FALSE; }
--      else eptr += min;
--      break;
--
--      case OP_NOT_DIGIT:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE;
--      break;
--
--      case OP_DIGIT:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE;
--      break;
--
--      case OP_NOT_WHITESPACE:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE;
--      break;
--
--      case OP_WHITESPACE:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE;
--      break;
--
--      case OP_NOT_WORDCHAR:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_word) != 0)
--          return FALSE;
--      break;
--
--      case OP_WORDCHAR:
--      for (i = 1; i <= min; i++)
--        if ((md->ctypes[*eptr++] & ctype_word) == 0)
--          return FALSE;
--      break;
--      }
--
--    /* If min = max, continue at the same level without recursing */
--
--    if (min == max) continue;
--
--    /* If minimizing, we have to test the rest of the pattern before each
--    subsequent match. */
--
--    if (minimize)
--      {
--      for (i = min;; i++)
--        {
--        if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE;
--        if (i >= max || eptr >= md->end_subject) return FALSE;
--
--        c = *eptr++;
--        switch(ctype)
--          {
--          case OP_ANY:
--          if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return FALSE;
--#ifdef SUPPORT_UTF8
--          if (md->utf8)
--            while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--#endif
--          break;
--
--          case OP_NOT_DIGIT:
--          if ((md->ctypes[c] & ctype_digit) != 0) return FALSE;
--          break;
--
--          case OP_DIGIT:
--          if ((md->ctypes[c] & ctype_digit) == 0) return FALSE;
--          break;
--
--          case OP_NOT_WHITESPACE:
--          if ((md->ctypes[c] & ctype_space) != 0) return FALSE;
--          break;
--
--          case OP_WHITESPACE:
--          if  ((md->ctypes[c] & ctype_space) == 0) return FALSE;
--          break;
--
--          case OP_NOT_WORDCHAR:
--          if ((md->ctypes[c] & ctype_word) != 0) return FALSE;
--          break;
--
--          case OP_WORDCHAR:
--          if ((md->ctypes[c] & ctype_word) == 0) return FALSE;
--          break;
--          }
--        }
--      /* Control never gets here */
--      }
--
--    /* If maximizing it is worth using inline code for speed, doing the type
--    test once at the start (i.e. keep it out of the loop). */
--
--    else
--      {
--      const uschar *pp = eptr;
--      switch(ctype)
--        {
--        case OP_ANY:
--
--        /* Special code is required for UTF8, but when the maximum is unlimited
--        we don't need it. */
--
--#ifdef SUPPORT_UTF8
--        if (md->utf8 && max < INT_MAX)
--          {
--          if ((ims & PCRE_DOTALL) == 0)
--            {
--            for (i = min; i < max; i++)
--              {
--              if (eptr >= md->end_subject || *eptr++ == NEWLINE) break;
--              while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--              }
--            }
--          else
--            {
--            for (i = min; i < max; i++)
--              {
--              eptr++;
--              while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--              }
--            }
--          break;
--          }
--#endif
--        /* Non-UTF8 can be faster */
--        if ((ims & PCRE_DOTALL) == 0)
--          {
--          for (i = min; i < max; i++)
--            {
--            if (eptr >= md->end_subject || *eptr == NEWLINE) break;
--            eptr++;
--            }
--          }
--        else
--          {
--          c = max - min;
--          if (c > md->end_subject - eptr) c = md->end_subject - eptr;
--          eptr += c;
--          }
--        break;
--
--        case OP_NOT_DIGIT:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
--            break;
--          eptr++;
--          }
--        break;
--
--        case OP_DIGIT:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
--            break;
--          eptr++;
--          }
--        break;
--
--        case OP_NOT_WHITESPACE:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
--            break;
--          eptr++;
--          }
--        break;
--
--        case OP_WHITESPACE:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
--            break;
--          eptr++;
--          }
--        break;
--
--        case OP_NOT_WORDCHAR:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
--            break;
--          eptr++;
--          }
--        break;
--
--        case OP_WORDCHAR:
--        for (i = min; i < max; i++)
--          {
--          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
--            break;
--          eptr++;
--          }
--        break;
--        }
--
--      while (eptr >= pp)
--        {
--        if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
--          return TRUE;
--#ifdef SUPPORT_UTF8
--        if (md->utf8)
--          while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--;
--#endif
--        }
--      return FALSE;
--      }
--    /* Control never gets here */
--
--    /* There's been some horrible disaster. */
--
--    default:
--    DPRINTF(("Unknown opcode %d\n", *ecode));
--    md->errorcode = PCRE_ERROR_UNKNOWN_NODE;
--    return FALSE;
--    }
--
--  /* Do not stick any code in here without much thought; it is assumed
--  that "continue" in the code above comes out to here to repeat the main
--  loop. */
--
--  }             /* End of main loop */
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--*         Execute a Regular Expression           *
--*************************************************/
--
--/* This function applies a compiled re to a subject string and picks out
--portions of the string if it matches. Two elements in the vector are set for
--each substring: the offsets to the start and end of the substring.
--
--Arguments:
--  external_re     points to the compiled expression
--  external_extra  points to "hints" from pcre_study() or is NULL
--  subject         points to the subject string
--  length          length of subject string (may contain binary zeros)
--  start_offset    where to start in the subject string
--  options         option bits
--  offsets         points to a vector of ints to be filled in with offsets
--  offsetcount     the number of elements in the vector
--
--Returns:          > 0 => success; value is the number of elements filled in
--                  = 0 => success, but offsets is not big enough
--                   -1 => failed to match
--                 < -1 => some kind of unexpected problem
--*/
--
--int
--pcre_exec(const pcre *external_re, const pcre_extra *external_extra,
--  const char *subject, int length, int start_offset, int options, int *offsets,
--  int offsetcount)
--{
--int resetcount, ocount;
--int first_char = -1;
--int req_char = -1;
--int req_char2 = -1;
--unsigned long int ims = 0;
--match_data match_block;
--const uschar *start_bits = NULL;
--const uschar *start_match = (const uschar *)subject + start_offset;
--const uschar *end_subject;
--const uschar *req_char_ptr = start_match - 1;
--const real_pcre *re = (const real_pcre *)external_re;
--const real_pcre_extra *extra = (const real_pcre_extra *)external_extra;
--BOOL using_temporary_offsets = FALSE;
--BOOL anchored;
--BOOL startline;
--
--if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
--
--if (re == NULL || subject == NULL ||
--   (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--
--anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
--startline = (re->options & PCRE_STARTLINE) != 0;
--
--match_block.start_pattern = re->code;
--match_block.start_subject = (const uschar *)subject;
--match_block.end_subject = match_block.start_subject + length;
--end_subject = match_block.end_subject;
--
--match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
--match_block.utf8 = (re->options & PCRE_UTF8) != 0;
--
--match_block.notbol = (options & PCRE_NOTBOL) != 0;
--match_block.noteol = (options & PCRE_NOTEOL) != 0;
--match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
--
--match_block.errorcode = PCRE_ERROR_NOMATCH;     /* Default error */
--
--match_block.lcc = re->tables + lcc_offset;
--match_block.ctypes = re->tables + ctypes_offset;
--
--/* The ims options can vary during the matching as a result of the presence
--of (?ims) items in the pattern. They are kept in a local variable so that
--restoring at the exit of a group is easy. */
--
--ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
--
--/* If the expression has got more back references than the offsets supplied can
--hold, we get a temporary bit of working store to use during the matching.
--Otherwise, we can use the vector supplied, rounding down its size to a multiple
--of 3. */
--
--ocount = offsetcount - (offsetcount % 3);
--
--if (re->top_backref > 0 && re->top_backref >= ocount/3)
--  {
--  ocount = re->top_backref * 3 + 3;
--  match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
--  if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
--  using_temporary_offsets = TRUE;
--  DPRINTF(("Got memory to hold back references\n"));
--  }
--else match_block.offset_vector = offsets;
--
--match_block.offset_end = ocount;
--match_block.offset_max = (2*ocount)/3;
--match_block.offset_overflow = FALSE;
--
--/* Compute the minimum number of offsets that we need to reset each time. Doing
--this makes a huge difference to execution time when there aren't many brackets
--in the pattern. */
--
--resetcount = 2 + re->top_bracket * 2;
--if (resetcount > offsetcount) resetcount = ocount;
--
--/* Reset the working variable associated with each extraction. These should
--never be used unless previously set, but they get saved and restored, and so we
--initialize them to avoid reading uninitialized locations. */
--
--if (match_block.offset_vector != NULL)
--  {
--  register int *iptr = match_block.offset_vector + ocount;
--  register int *iend = iptr - resetcount/2 + 1;
--  while (--iptr >= iend) *iptr = -1;
--  }
--
--/* Set up the first character to match, if available. The first_char value is
--never set for an anchored regular expression, but the anchoring may be forced
--at run time, so we have to test for anchoring. The first char may be unset for
--an unanchored pattern, of course. If there's no first char and the pattern was
--studied, there may be a bitmap of possible first characters. */
--
--if (!anchored)
--  {
--  if ((re->options & PCRE_FIRSTSET) != 0)
--    {
--    first_char = re->first_char;
--    if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char];
--    }
--  else
--    if (!startline && extra != NULL &&
--      (extra->options & PCRE_STUDY_MAPPED) != 0)
--        start_bits = extra->start_bits;
--  }
--
--/* For anchored or unanchored matches, there may be a "last known required
--character" set. If the PCRE_CASELESS is set, implying that the match starts
--caselessly, or if there are any changes of this flag within the regex, set up
--both cases of the character. Otherwise set the two values the same, which will
--avoid duplicate testing (which takes significant time). This covers the vast
--majority of cases. It will be suboptimal when the case flag changes in a regex
--and the required character in fact is caseful. */
--
--if ((re->options & PCRE_REQCHSET) != 0)
--  {
--  req_char = re->req_char;
--  req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)?
--    (re->tables + fcc_offset)[req_char] : req_char;
--  }
--
--/* Loop for handling unanchored repeated matching attempts; for anchored regexs
--the loop runs just once. */
--
--do
--  {
--  int rc;
--  register int *iptr = match_block.offset_vector;
--  register int *iend = iptr + resetcount;
--
--  /* Reset the maximum number of extractions we might see. */
--
--  while (iptr < iend) *iptr++ = -1;
--
--  /* Advance to a unique first char if possible */
--
--  if (first_char >= 0)
--    {
--    if ((ims & PCRE_CASELESS) != 0)
--      while (start_match < end_subject &&
--             match_block.lcc[*start_match] != first_char)
--        start_match++;
--    else
--      while (start_match < end_subject && *start_match != first_char)
--        start_match++;
--    }
--
--  /* Or to just after \n for a multiline match if possible */
--
--  else if (startline)
--    {
--    if (start_match > match_block.start_subject + start_offset)
--      {
--      while (start_match < end_subject && start_match[-1] != NEWLINE)
--        start_match++;
--      }
--    }
--
--  /* Or to a non-unique first char after study */
--
--  else if (start_bits != NULL)
--    {
--    while (start_match < end_subject)
--      {
--      register int c = *start_match;
--      if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
--      }
--    }
--
--#ifdef DEBUG  /* Sigh. Some compilers never learn. */
--  printf(">>>> Match against: ");
--  pchars(start_match, end_subject - start_match, TRUE, &match_block);
--  printf("\n");
--#endif
--
--  /* If req_char is set, we know that that character must appear in the subject
--  for the match to succeed. If the first character is set, req_char must be
--  later in the subject; otherwise the test starts at the match point. This
--  optimization can save a huge amount of backtracking in patterns with nested
--  unlimited repeats that aren't going to match. We don't know what the state of
--  case matching may be when this character is hit, so test for it in both its
--  cases if necessary. However, the different cased versions will not be set up
--  unless PCRE_CASELESS was given or the casing state changes within the regex.
--  Writing separate code makes it go faster, as does using an autoincrement and
--  backing off on a match. */
--
--  if (req_char >= 0)
--    {
--    register const uschar *p = start_match + ((first_char >= 0)? 1 : 0);
--
--    /* We don't need to repeat the search if we haven't yet reached the
--    place we found it at last time. */
--
--    if (p > req_char_ptr)
--      {
--      /* Do a single test if no case difference is set up */
--
--      if (req_char == req_char2)
--        {
--        while (p < end_subject)
--          {
--          if (*p++ == req_char) { p--; break; }
--          }
--        }
--
--      /* Otherwise test for either case */
--
--      else
--        {
--        while (p < end_subject)
--          {
--          register int pp = *p++;
--          if (pp == req_char || pp == req_char2) { p--; break; }
--          }
--        }
--
--      /* If we can't find the required character, break the matching loop */
--
--      if (p >= end_subject) break;
--
--      /* If we have found the required character, save the point where we
--      found it, so that we don't search again next time round the loop if
--      the start hasn't passed this character yet. */
--
--      req_char_ptr = p;
--      }
--    }
--
--  /* When a match occurs, substrings will be set for all internal extractions;
--  we just need to set up the whole thing as substring 0 before returning. If
--  there were too many extractions, set the return code to zero. In the case
--  where we had to get some local store to hold offsets for backreferences, copy
--  those back references that we can. In this case there need not be overflow
--  if certain parts of the pattern were not used. */
--
--  match_block.start_match = start_match;
--  if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup))
--    continue;
--
--  /* Copy the offset information from temporary store if necessary */
--
--  if (using_temporary_offsets)
--    {
--    if (offsetcount >= 4)
--      {
--      memcpy(offsets + 2, match_block.offset_vector + 2,
--        (offsetcount - 2) * sizeof(int));
--      DPRINTF(("Copied offsets from temporary memory\n"));
--      }
--    if (match_block.end_offset_top > offsetcount)
--      match_block.offset_overflow = TRUE;
--
--    DPRINTF(("Freeing temporary memory\n"));
--    (pcre_free)(match_block.offset_vector);
--    }
--
--  rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
--
--  if (offsetcount < 2) rc = 0; else
--    {
--    offsets[0] = start_match - match_block.start_subject;
--    offsets[1] = match_block.end_match_ptr - match_block.start_subject;
--    }
--
--  DPRINTF((">>>> returning %d\n", rc));
--  return rc;
--  }
--
--/* This "while" is the end of the "do" above */
--
--while (!anchored &&
--       match_block.errorcode == PCRE_ERROR_NOMATCH &&
--       start_match++ < end_subject);
--
--if (using_temporary_offsets)
--  {
--  DPRINTF(("Freeing temporary memory\n"));
--  (pcre_free)(match_block.offset_vector);
--  }
--
--DPRINTF((">>>> returning %d\n", match_block.errorcode));
--
--return match_block.errorcode;
--}
--
--/* End of pcre.c */
-
-=== removed file 'parser/pcre/pcre.h'
---- parser/pcre/pcre.h 2006-04-11 21:52:54 +0000
-+++ parser/pcre/pcre.h 1970-01-01 00:00:00 +0000
-@@ -1,113 +0,0 @@
--/*************************************************
--*       Perl-Compatible Regular Expressions      *
--*************************************************/
--
--/* Copyright (c) 1997-2001 University of Cambridge */
--
--#ifndef _PCRE_H
--#define _PCRE_H
--
--/* The file pcre.h is build by "configure". Do not edit it; instead
--make changes to pcre.in. */
--
--#define PCRE_MAJOR          3
--#define PCRE_MINOR          9
--#define PCRE_DATE           02-Jan-2002
--
--/* Win32 uses DLL by default */
--
--#ifdef _WIN32
--# ifdef STATIC
--#  define PCRE_DL_IMPORT
--# else
--#  define PCRE_DL_IMPORT __declspec(dllimport)
--# endif
--#else
--# define PCRE_DL_IMPORT
--#endif
--
--/* Have to include stdlib.h in order to ensure that size_t is defined;
--it is needed here for malloc. */
--
--#include <stdlib.h>
--
--/* Allow for C++ users */
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--/* Options */
--
--#define PCRE_CASELESS        0x0001
--#define PCRE_MULTILINE       0x0002
--#define PCRE_DOTALL          0x0004
--#define PCRE_EXTENDED        0x0008
--#define PCRE_ANCHORED        0x0010
--#define PCRE_DOLLAR_ENDONLY  0x0020
--#define PCRE_EXTRA           0x0040
--#define PCRE_NOTBOL          0x0080
--#define PCRE_NOTEOL          0x0100
--#define PCRE_UNGREEDY        0x0200
--#define PCRE_NOTEMPTY        0x0400
--#define PCRE_UTF8            0x0800
--
--/* Exec-time and get-time error codes */
--
--#define PCRE_ERROR_NOMATCH        (-1)
--#define PCRE_ERROR_NULL           (-2)
--#define PCRE_ERROR_BADOPTION      (-3)
--#define PCRE_ERROR_BADMAGIC       (-4)
--#define PCRE_ERROR_UNKNOWN_NODE   (-5)
--#define PCRE_ERROR_NOMEMORY       (-6)
--#define PCRE_ERROR_NOSUBSTRING    (-7)
--
--/* Request types for pcre_fullinfo() */
--
--#define PCRE_INFO_OPTIONS         0
--#define PCRE_INFO_SIZE            1
--#define PCRE_INFO_CAPTURECOUNT    2
--#define PCRE_INFO_BACKREFMAX      3
--#define PCRE_INFO_FIRSTCHAR       4
--#define PCRE_INFO_FIRSTTABLE      5
--#define PCRE_INFO_LASTLITERAL     6
--
--/* Types */
--
--struct real_pcre;        /* declaration; the definition is private  */
--struct real_pcre_extra;  /* declaration; the definition is private */
--
--typedef struct real_pcre pcre;
--typedef struct real_pcre_extra pcre_extra;
--
--/* Store get and free functions. These can be set to alternative malloc/free
--functions if required. Some magic is required for Win32 DLL; it is null on
--other OS. */
--
--PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t);
--PCRE_DL_IMPORT extern void  (*pcre_free)(void *);
--
--#undef PCRE_DL_IMPORT
--
--/* Functions */
--
--extern pcre *pcre_compile(const char *, int, const char **, int *,
--              const unsigned char *);
--extern int  pcre_copy_substring(const char *, int *, int, int, char *, int);
--extern int  pcre_exec(const pcre *, const pcre_extra *, const char *,
--              int, int, int, int *, int);
--extern void pcre_free_substring(const char *);
--extern void pcre_free_substring_list(const char **);
--extern int  pcre_get_substring(const char *, int *, int, int, const char **);
--extern int  pcre_get_substring_list(const char *, int *, int, const char ***);
--extern int  pcre_info(const pcre *, int *, int *);
--extern int  pcre_fullinfo(const pcre *, const pcre_extra *, int, void *);
--extern const unsigned char *pcre_maketables(void);
--extern pcre_extra *pcre_study(const pcre *, int, const char **);
--extern const char *pcre_version(void);
--
--#ifdef __cplusplus
--}  /* extern "C" */
--#endif
--
--#endif /* End of pcre.h */
-
-=== modified file 'parser/tst/Makefile'
---- parser/tst/Makefile        2006-12-15 08:10:25 +0000
-+++ parser/tst/Makefile        2010-08-03 17:27:13 +0000
-@@ -1,8 +1,9 @@
- #
--# $Id$
--#
- PROVE=/usr/bin/prove
- TESTS=simple.pl
-+PARSER_DIR=..
-+PARSER_BIN=apparmor_parser
-+PARSER=$(PARSER_DIR)/$(PARSER_BIN)
- ifeq ($(VERBOSE),1)
-   PROVE_ARG=-v
-@@ -10,9 +11,23 @@
- all: tests
--.PHONY: tests
--tests: ../apparmor_parser
-+.PHONY: tests error_output parser_sanity
-+tests: error_output parser_sanity
-+
-+error_output: $(PARSER)
-+      $(PARSER) -S -I errors >/dev/null errors/okay.sd
-+      LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/single.sd | \
-+              grep -q "AppArmor parser error for errors/single.sd in errors/single.sd at line 3: Could not open 'failure'"
-+      LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/double.sd | \
-+              grep -q "AppArmor parser error for errors/double.sd in errors/includes/busted at line 67: Could not open 'does-not-exist'"
-+      LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/modefail.sd | \
-+              grep -q "AppArmor parser error for errors/modefail.sd in errors/modefail.sd at line 6: syntax error"
-+      LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/multi_include.sd | \
-+              grep -q "AppArmor parser error for errors/multi_include.sd in errors/multi_include.sd at line 12: Could not open 'failure'"
-+      @echo "Error Output: PASS"
-+
-+parser_sanity: $(PARSER)
-       $(Q)${PROVE} ${PROVE_ARG} ${TESTS}
--../apparmor_parser:
--      make -C .. apparmor_parser
-+$(PARSER):
-+      make -C $(PARSER_DIR) $(PARSER_BIN)
-
-=== modified file 'parser/tst/README'
---- parser/tst/README  2006-06-01 17:02:28 +0000
-+++ parser/tst/README  2010-06-05 06:11:20 +0000
-@@ -64,5 +64,3 @@
-     loop.
- Otherwise, the profile is passed on as-is to the subdomain parser.
--
--$Id$ 
-
-=== added directory 'parser/tst/errors'
-=== added file 'parser/tst/errors/double.sd'
---- parser/tst/errors/double.sd        1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/double.sd        2010-06-05 06:11:20 +0000
-@@ -0,0 +1,5 @@
-+#
-+/does/not/exist {
-+  #include <includes/base>
-+  #include <includes/busted>
-+}
-
-=== added directory 'parser/tst/errors/includes'
-=== added file 'parser/tst/errors/includes/base'
---- parser/tst/errors/includes/base    1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/includes/base    2010-06-05 06:11:20 +0000
-@@ -0,0 +1,81 @@
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+#    Copyright (C) 2002-2005 Novell/SUSE
-+#
-+#    This program is free software; you can redistribute it and/or
-+#    modify it under the terms of version 2 of the GNU General Public
-+#    License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+
-+
-+  # (Note that the ldd profile has inlined this file; if you make
-+  # modifications here, please consider including them in the ldd
-+  # profile as well.)
-+
-+  # The __canary_death_handler function writes a time-stamped log
-+  # message to /dev/log for logging by syslogd. So, /dev/log, timezones,
-+  # and localisations of date should be available EVERYWHERE, so
-+  # StackGuard, FormatGuard, etc., alerts can be properly logged.
-+  /dev/log                       w,
-+  /dev/urandom                   r,
-+  /etc/locale/**                 r,
-+  /etc/localtime                 r,
-+  /usr/share/locale/**           r,
-+  /usr/share/zoneinfo/**         r,
-+
-+  /usr/lib64/locale/**           r,
-+  /usr/lib64/gconv/*.so          r,
-+  /usr/lib64/gconv/gconv-modules*  r,
-+  /usr/lib/locale/**             r,
-+  /usr/lib/gconv/*.so            r,
-+  /usr/lib/gconv/gconv-modules*  r,
-+
-+  # used by glibc when binding to ephemeral ports
-+  /etc/bindresvport.blacklist    r,
-+
-+  # ld.so.cache and ld are used to load shared libraries; they are best
-+  # available everywhere
-+  /etc/ld.so.cache               r,
-+  # 'px' requires a profile to be available for the transition to
-+  # function; without a loaded profile, the kernel will fail the exec.
-+  /lib/ld-*.so                   px,
-+  /lib64/ld-*.so                 px,
-+  /opt/*-linux-uclibc/lib/ld-uClibc*so* px,
-+
-+  # we might as well allow everything to use common libraries
-+  /lib/lib*.so*                  r,
-+  /lib/tls/lib*.so*              r,
-+  /lib/power4/lib*.so*           r,
-+  /lib/power5/lib*.so*           r,
-+  /lib/power5+/lib*.so*          r,
-+  /lib64/power4/lib*.so*         r,
-+  /lib64/power5/lib*.so*         r,
-+  /lib64/power5+/lib*.so*        r,
-+  /usr/lib/*.so*                 r,
-+  /usr/lib/tls/lib*.so*          r,
-+  /usr/lib/power4/lib*.so*       r,
-+  /usr/lib/power5/lib*.so*       r,
-+  /usr/lib/power5+/lib*.so*      r,
-+  /lib64/lib*.so*                r,
-+  /lib64/tls/lib*.so*            r,
-+  /usr/lib64/*.so*               r,
-+  /usr/lib64/tls/lib*.so*        r,
-+
-+  # /dev/null is pretty harmless and frequently used
-+  /dev/null                      rw,
-+  # as is /dev/zero
-+  /dev/zero                      rw,
-+
-+  # Sometimes used to determine kernel/user interfaces to use
-+  /proc/sys/kernel/version       r,
-+  # Depending on which glibc routine uses this file, base may not be the
-+  # best place -- but many profiles require it, and it is quite harmless.
-+  /proc/sys/kernel/ngroups_max   r,
-+
-+  # glibc's sysconf(3) routine to determine free memory, etc
-+  /proc/meminfo                  r,
-+  /proc/stat                     r,
-+  /proc/cpuinfo                  r,
-
-=== added file 'parser/tst/errors/includes/busted'
---- parser/tst/errors/includes/busted  1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/includes/busted  2010-06-05 06:11:20 +0000
-@@ -0,0 +1,83 @@
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+#    Copyright (C) 2002-2005 Novell/SUSE
-+#
-+#    This program is free software; you can redistribute it and/or
-+#    modify it under the terms of version 2 of the GNU General Public
-+#    License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+
-+
-+  # (Note that the ldd profile has inlined this file; if you make
-+  # modifications here, please consider including them in the ldd
-+  # profile as well.)
-+
-+  # The __canary_death_handler function writes a time-stamped log
-+  # message to /dev/log for logging by syslogd. So, /dev/log, timezones,
-+  # and localisations of date should be available EVERYWHERE, so
-+  # StackGuard, FormatGuard, etc., alerts can be properly logged.
-+  /dev/log                       w,
-+  /dev/urandom                   r,
-+  /etc/locale/**                 r,
-+  /etc/localtime                 r,
-+  /usr/share/locale/**           r,
-+  /usr/share/zoneinfo/**         r,
-+
-+  /usr/lib64/locale/**           r,
-+  /usr/lib64/gconv/*.so          r,
-+  /usr/lib64/gconv/gconv-modules*  r,
-+  /usr/lib/locale/**             r,
-+  /usr/lib/gconv/*.so            r,
-+  /usr/lib/gconv/gconv-modules*  r,
-+
-+  # used by glibc when binding to ephemeral ports
-+  /etc/bindresvport.blacklist    r,
-+
-+  # ld.so.cache and ld are used to load shared libraries; they are best
-+  # available everywhere
-+  /etc/ld.so.cache               r,
-+  # 'px' requires a profile to be available for the transition to
-+  # function; without a loaded profile, the kernel will fail the exec.
-+  /lib/ld-*.so                   px,
-+  /lib64/ld-*.so                 px,
-+  /opt/*-linux-uclibc/lib/ld-uClibc*so* px,
-+
-+  # we might as well allow everything to use common libraries
-+  /lib/lib*.so*                  r,
-+  /lib/tls/lib*.so*              r,
-+  /lib/power4/lib*.so*           r,
-+  /lib/power5/lib*.so*           r,
-+  /lib/power5+/lib*.so*          r,
-+  /lib64/power4/lib*.so*         r,
-+  /lib64/power5/lib*.so*         r,
-+  /lib64/power5+/lib*.so*        r,
-+  /usr/lib/*.so*                 r,
-+  /usr/lib/tls/lib*.so*          r,
-+  /usr/lib/power4/lib*.so*       r,
-+  /usr/lib/power5/lib*.so*       r,
-+  /usr/lib/power5+/lib*.so*      r,
-+  /lib64/lib*.so*                r,
-+  /lib64/tls/lib*.so*            r,
-+  /usr/lib64/*.so*               r,
-+  /usr/lib64/tls/lib*.so*        r,
-+
-+  #include <does-not-exist>
-+
-+  # /dev/null is pretty harmless and frequently used
-+  /dev/null                      rw,
-+  # as is /dev/zero
-+  /dev/zero                      rw,
-+
-+  # Sometimes used to determine kernel/user interfaces to use
-+  /proc/sys/kernel/version       r,
-+  # Depending on which glibc routine uses this file, base may not be the
-+  # best place -- but many profiles require it, and it is quite harmless.
-+  /proc/sys/kernel/ngroups_max   r,
-+
-+  # glibc's sysconf(3) routine to determine free memory, etc
-+  /proc/meminfo                  r,
-+  /proc/stat                     r,
-+  /proc/cpuinfo                  r,
-
-=== added file 'parser/tst/errors/modefail.sd'
---- parser/tst/errors/modefail.sd      1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/modefail.sd      2010-08-03 17:27:13 +0000
-@@ -0,0 +1,7 @@
-+#     1
-+#     2
-+#     3
-+/does/not/exist {     # 4
-+  /lib/lib*.so rm,    # 5
-+  /fail abcdefgh,     # 6
-+}                     # 7
-
-=== added file 'parser/tst/errors/multi_include.sd'
---- parser/tst/errors/multi_include.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/multi_include.sd 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,13 @@
-+#
-+#
-+#
-+/does/not/exist {
-+  #include <includes/base>
-+  #include <includes/base>
-+  #include <includes/base>
-+  #include <includes/base>
-+
-+  /bin/true rix,
-+
-+  #include <failure>
-+}
-
-=== added file 'parser/tst/errors/okay.sd'
---- parser/tst/errors/okay.sd  1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/okay.sd  2010-06-05 06:11:20 +0000
-@@ -0,0 +1,4 @@
-+#
-+/does/not/exist {
-+  #include <includes/base>
-+}
-
-=== added file 'parser/tst/errors/single.sd'
---- parser/tst/errors/single.sd        1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/single.sd        2010-06-05 06:11:20 +0000
-@@ -0,0 +1,7 @@
-+#
-+#
-+#include <failure>
-+#
-+/does/not/exist {
-+  #include <includes/base>
-+}
-
-=== modified file 'profiles/apparmor.d/abstractions/base'
---- profiles/apparmor.d/abstractions/base      2010-01-03 21:16:38 +0000
-+++ profiles/apparmor.d/abstractions/base      2010-06-05 06:11:20 +0000
-@@ -85,6 +85,9 @@
-   # some applications will display license information
-   /usr/share/common-licenses/**  r,
-+  # glibc statvfs
-+  @{PROC}/filesystems            r,
-+
-   # Workaround https://launchpad.net/bugs/359338 until upstream handles stacked
-   # filesystems generally. This does not appreciably decrease security with
-   # Ubuntu profiles because the user is expected to have access to files owned
-
-=== modified file 'profiles/apparmor.d/abstractions/dbus'
---- profiles/apparmor.d/abstractions/dbus      2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/dbus      2010-08-03 17:27:13 +0000
-@@ -2,7 +2,7 @@
- # $Id$
- # ------------------------------------------------------------------
- #
--#    Copyright (C) 2009 Canonical Ltd.
-+#    Copyright (C) 2009-2010 Canonical Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -10,8 +10,5 @@
- #
- # ------------------------------------------------------------------
--  # System socket
-+  # System socket. Be careful when including this abstraction.
-   /var/run/dbus/system_bus_socket w,
--
--  # Machine id
--  /var/lib/dbus/machine-id r,
-
-=== added file 'profiles/apparmor.d/abstractions/dbus-session'
---- profiles/apparmor.d/abstractions/dbus-session      1970-01-01 00:00:00 +0000
-+++ profiles/apparmor.d/abstractions/dbus-session      2010-08-03 17:27:13 +0000
-@@ -0,0 +1,14 @@
-+# vim:syntax=apparmor
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+#    Copyright (C) 2010 Canonical Ltd.
-+#
-+#    This program is free software; you can redistribute it and/or
-+#    modify it under the terms of version 2 of the GNU General Public
-+#    License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+  /usr/bin/dbus-launch Pix,
-+  /var/lib/dbus/machine-id r,
-
-=== modified file 'profiles/apparmor.d/abstractions/fonts'
---- profiles/apparmor.d/abstractions/fonts     2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/fonts     2010-06-05 06:11:20 +0000
-@@ -15,6 +15,7 @@
-   /usr/lib/xorg/modules/fonts/**.so*    mr,
-+  /usr/share/fonts/                     r,
-   /usr/share/fonts/**                   r,
-   /etc/fonts/**                         r,
-
-=== modified file 'profiles/apparmor.d/abstractions/freedesktop.org'
---- profiles/apparmor.d/abstractions/freedesktop.org   2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/freedesktop.org   2010-06-05 06:11:20 +0000
-@@ -27,3 +27,7 @@
-   @{HOME}/.icons/                 r,
-   @{HOME}/.recently-used.xbel*    rw,
-   @{HOME}/.config/user-dirs.dirs  r,
-+  @{HOME}/.local/share/icons/     r,
-+  @{HOME}/.local/share/icons/**   r,
-+  @{HOME}/.local/share/mime/      r,
-+  @{HOME}/.local/share/mime/**    r,
-
-=== modified file 'profiles/apparmor.d/abstractions/gnome'
---- profiles/apparmor.d/abstractions/gnome     2009-11-10 20:04:26 +0000
-+++ profiles/apparmor.d/abstractions/gnome     2010-08-03 17:27:13 +0000
-@@ -3,7 +3,7 @@
- # ------------------------------------------------------------------
- #
- #    Copyright (C) 2002-2009 Novell/SUSE
--#    Copyright (C) 2009 Canonical Ltd.
-+#    Copyright (C) 2009-2010 Canonical Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -31,6 +31,7 @@
-   /etc/pango/*                    r,
-   /usr/lib{,32,64}/pango/**       mr,
-   /usr/lib{,32,64}/gtk-*/**       mr,
-+  /usr/lib{,32,64}/gdk-pixbuf-*/** mr,
-   # per-user gtk configuration
-   @{HOME}/.gnome/Gnome            r,
-
-=== modified file 'profiles/apparmor.d/abstractions/nameservice'
---- profiles/apparmor.d/abstractions/nameservice       2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/nameservice       2010-06-05 06:11:20 +0000
-@@ -77,3 +77,5 @@
-   network inet  dgram,
-   network inet6 dgram,
-+  # interface details
-+  @{PROC}/*/net/route r,
-
-=== modified file 'profiles/apparmor.d/abstractions/php5'
---- profiles/apparmor.d/abstractions/php5      2010-01-03 21:16:38 +0000
-+++ profiles/apparmor.d/abstractions/php5      2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # ------------------------------------------------------------------
- #
- #    Copyright (C) 2002-2006 Novell/SUSE
--#    Copyright (C) 2009 Canonical, Ltd.
-+#    Copyright (C) 2009-2010 Canonical Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -11,13 +11,13 @@
- # ------------------------------------------------------------------
-   # shared snippets for config files
--  /etc/php5/{conf.d,apache2,cli,fastcgi}/ r,
--  /etc/php5/{conf.d,apache2,cli,fastcgi}/*.ini r,
-+  /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/ r,
-+  /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/*.ini r,
-   # Xlibs
-   /usr/X11R6/lib{,32,64}/lib*.so* mr,
-   # php extensions
--  /usr/lib{64,}/php5/{libexec,extensions}/*.so mr,
-+  /usr/lib{64,}/php5/*/*.so mr,
-   # php5 session mmap socket
-   /var/lib/php5/session_mm_* rwlk,
-
-=== modified file 'profiles/apparmor.d/abstractions/samba'
---- profiles/apparmor.d/abstractions/samba     2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/samba     2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # $Id$
- # ------------------------------------------------------------------
- #
--#    Copyright (C) 2009 Canonical Ltd.
-+#    Copyright (C) 2009-2010 Canonical Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -12,7 +12,7 @@
-   /etc/samba/smb.conf r,
-   /usr/share/samba/*.dat r,
--  /var/lib/samba/**.tdb rw,
-+  /var/lib/samba/**.tdb rwk,
-   /var/log/samba/cores/* w,
-   /var/log/samba/log.* w,
-   /var/run/samba/*.tdb rw,
-
-=== modified file 'profiles/apparmor.d/abstractions/ubuntu-email'
---- profiles/apparmor.d/abstractions/ubuntu-email      2009-11-11 19:42:30 +0000
-+++ profiles/apparmor.d/abstractions/ubuntu-email      2010-08-03 17:27:13 +0000
-@@ -15,5 +15,5 @@
-   /usr/bin/tkrat Ux,
-   /usr/lib/thunderbird/thunderbird Ux,
--
-+  /usr/lib/thunderbird-3*/thunderbird Ux,
-
-=== modified file 'profiles/apparmor.d/abstractions/ubuntu-media-players'
---- profiles/apparmor.d/abstractions/ubuntu-media-players      2010-03-08 19:50:25 +0000
-+++ profiles/apparmor.d/abstractions/ubuntu-media-players      2010-08-03 17:27:13 +0000
-@@ -24,6 +24,7 @@
-   # mplayer
-   /etc/mplayerplug-in.conf r,
-+  /usr/bin/gmplayer Uxr,
-   /usr/bin/gnome-mplayer Uxr,
-   /usr/bin/kmplayer Uxr,
-   /usr/bin/mplayer Uxr,
-
-=== modified file 'profiles/apparmor.d/abstractions/user-tmp'
---- profiles/apparmor.d/abstractions/user-tmp  2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/user-tmp  2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # ------------------------------------------------------------------
- #
- #    Copyright (C) 2002-2009 Novell/SUSE
--#    Copyright (C) 2009 Canonical Ltd.
-+#    Copyright (C) 2009-2010 Canonical Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -11,11 +11,11 @@
- # ------------------------------------------------------------------
-   # per-user tmp directories
--  @{HOME}/tmp/**  rwkl,
--  @{HOME}/tmp/    rw,
-+  owner @{HOME}/tmp/**  rwkl,
-+  owner @{HOME}/tmp/    rw,
-   # global tmp directories
--  /var/tmp/**     rwkl,
--  /var/tmp/       rw,
--  /tmp/**         rwkl,
--  /tmp/           rw,
-+  owner /var/tmp/**     rwkl,
-+  owner /var/tmp/       rw,
-+  owner /tmp/**         rwkl,
-+  owner /tmp/           rw,
-
-=== renamed directory 'tests/regression/subdomain' => 'tests/regression/apparmor'
-=== modified file 'tests/regression/apparmor/Makefile'
---- tests/regression/subdomain/Makefile        2009-08-21 20:39:45 +0000
-+++ tests/regression/apparmor/Makefile 2010-08-03 17:27:13 +0000
-@@ -22,6 +22,7 @@
-     chmod.c \
-     chown.c \
-     clone.c \
-+    coredump.c \
-     deleted.c \
-     environ.c \
-     env_check.c \
-@@ -113,6 +114,7 @@
-       changehat_misc \
-       chdir \
-       clone \
-+      coredump \
-       deleted \
-       environ \
-       exec \
-@@ -158,27 +160,39 @@
- tests: all
-       @if [ `whoami` = "root" ] ;\
-       then \
-+              rc=0; \
-               for i in $(TESTS) ;\
-               do \
-                       echo ;\
-                       echo "running $$i" ;\
-                       bash $$i.sh ;\
-+                      if [ $$? -ne 0 ] ; then \
-+                              rc=1;\
-+                      fi;\
-               done ;\
-+              exit $$rc;\
-       else \
-               echo "must be root to run tests" ;\
-+              exit 1;\
-       fi
- alltests: all
-       @if [ `whoami` = "root" ] ;\
-       then \
-+              rc=0; \
-               for i in $(TESTS) $(RISKY_TESTS) ;\
-               do \
-                       echo ;\
-                       echo "running $$i" ;\
-                       bash $$i.sh ;\
-+                      if [ $$? -ne 0 ] ; then \
-+                              rc=1;\
-+                      fi;\
-               done ;\
-+              exit $$rc;\
-       else \
-               echo "must be root to run tests" ;\
-+              exit 1;\
-       fi
- clean:
-
-=== modified file 'tests/regression/apparmor/README'
---- tests/regression/subdomain/README  2006-09-15 22:39:59 +0000
-+++ tests/regression/apparmor/README   2010-08-03 17:27:13 +0000
-@@ -1,10 +1,10 @@
- Running tests
- =============
--Type "make tests" at the shell prompt, this will make the subprograms
--and run the tests.
-+Type "sudo make tests" at the shell prompt, this will make the
-+subprograms and run the tests.
--You must be root to execute make tests (a requirement of subdomain).
-+You must be root to execute "make tests" (a requirement of AppArmor).
- (There is also a 'make alltests', which adds a test for bug that, when
- triggered, would cause the kernel to crash.)
-@@ -12,10 +12,13 @@
- Test output
- ===========
--No output is displayed for a passing test.  The makefile will output
-+By default, no output is displayed for a passing test.  The makefile will
-+output:
-       running <testname> for each test.
--Output other than this indicates a problem.
-+To have verbose output with each subtest reporting successes, set the
-+environment variable VERBOSE=1:
-+      sudo VERBOSE=1 make tests
- There are three typical failure scenarios:
-       - Test failed when it was expected to pass
-@@ -29,7 +32,7 @@
- Common user changeable environment variables are stored in the file
- 'uservars.inc'.  Currently the path to the tmp directory, the path
--to the subdomain_parser executable, and any additional arguments to give
-+to the apparmor_parser executable, and any additional arguments to give
- to the parser are specified in this configuration file.
- (Note: the tmp directory specified in uservars.inc will have an added
-@@ -66,7 +69,7 @@
- directory will contain the files for the failed subtest.
- It may be necessary to create certain temp files in this directory in order to 
--have the test function correctly, see the subdomain profile 'profile' in the 
-+have the test function correctly, see the AppArmor profile 'profile' in the 
- directory in order to determine which files may need to be created to support
- the executable.
-@@ -155,7 +158,7 @@
-       <requirement placed on the shell script author by prologue.inc>
-       bin=$pwd
-       
--      <prologie.inc must be included before running any tests>
-+      <prologue.inc must be included before running any tests>
-       . $bin/prologue.inc
-       
-       <variable definitions used by this script?
-@@ -174,7 +177,7 @@
-       
-       # NOLINK PERMTEST
-       <generate a new profile allowing only r access to /bin/true>
--      <subdomain_parser will automatically be invoked in -r mode>
-+      <apparmor_parser will automatically be invoked in -r mode>
-       genprofile $file:$badperm
-       <run this test (exec) passing /bin/true as argv[1]>
-@@ -183,16 +186,11 @@
-       <Thats it. Exit status $rc is automatically returned by epilogue.inc>
--Additional documentation
--========================
--
--See the file 'subdomain_test.txt'
--
- Supporting files
- ================
- strace.sh     Not a test harness, used to support strace testing.
--mkprofile.sh  Not a test harness, used to generate subdomain profiles.
-+mkprofile.sh  Not a test harness, used to generate AppArmor profiles.
- prologue.inc  Must be dotted (included) into the test harness. Provides
-               support routines.
- epilogue.inc  Cleanup support, automatically called upon successful or
-@@ -222,17 +220,3 @@
-    This is not an error, rather a sign that bash noticed the kernel had killed 
-    a process which was attempting to use a bogus MAGIC number.  Alas, there is 
-    no way to get bash to not print this diagnostic
--
--3) Ptrace
--      Error: open passed. Test 'STRACE OPEN (x confinement)' 
--      was expected to 'fail'
-- 
--   Regression from 2.4.18 to 2.4.20. (We aren't sure on the first
--   endpoint, and the problem still happens in 2.4.20-20_imnx_10smp.)
--
--4) Open
--      Error: open passed. Test 'OPEN W (create)' was expected to 'fail'
--
--   LSM issue.  Flags passed to inode_permission are 0 if O_CREAT is used to
--   open file.  Need to submit a patch to inode_create hook to receive the
--   O_RDWR flags. See https://bugs.wirex.com/show_bug.cgi?id=2885
-
-=== modified file 'tests/regression/apparmor/changehat_misc.sh'
---- tests/regression/subdomain/changehat_misc.sh       2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/changehat_misc.sh        2010-08-03 17:27:13 +0000
-@@ -64,7 +64,7 @@
- echo "*** A 'Killed' message from bash is expected for the following test"
- runchecktest "CHANGEHAT (subprofile->subprofile w/ bad magic)" signal9 $subtest $subtest2 badmagic $file
--# 1. ATTEMPT TO CHANGEGAT TO AN INVALUD PROFILE, SHOULD PUT US INTO A NULL
-+# 1. ATTEMPT TO CHANGEHAT TO AN INVALID PROFILE, SHOULD PUT US INTO A NULL
- #    PROFILE
- # 2. ATTEMPT TO CHANGEHAT OUT WITH BAD TOKEN
- settest changehat_fail
-
-=== modified file 'tests/regression/apparmor/coredump.c'
---- tests/regression/subdomain/coredump.c      2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/coredump.c       2010-08-03 17:27:13 +0000
-@@ -1,7 +1,9 @@
-+#include <stdio.h>
- int *ptr;
- /*
-  *    Copyright (C) 2002-2005 Novell/SUSE
-+ *    Copyright (C) 2010 Canonical, Ltd
-  *
-  *    This program is free software; you can redistribute it and/or
-  *    modify it under the terms of the GNU General Public License as
-@@ -9,7 +11,7 @@
-  *    License.
-  */
--main()
-+int main(int argc, char *argv[])
- {
-       printf("This will cause a sigsegv\n");
-
-=== modified file 'tests/regression/apparmor/coredump.sh'
---- tests/regression/subdomain/coredump.sh     2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/coredump.sh      2010-08-03 17:27:13 +0000
-@@ -1,7 +1,6 @@
- #! /bin/bash
--# $Id$
--
- #     Copyright (C) 2002-2005 Novell/SUSE
-+#     Copyright (C) 2010 Canonical, Ltd
- #
- #     This program is free software; you can redistribute it and/or
- #     modify it under the terms of the GNU General Public License as
-@@ -11,26 +10,52 @@
- #=NAME coredump
- #=DESCRIPTION coredump test
-+cleancorefile()
-+{
-+      rm -f core core.*
-+}
-+
- checkcorefile()
- {
--_corefilelist=`echo core.*`
--if [ "$_corefilelist" = "core.*" ]
--then
--      _corefile=no
+=== modified file 'parser/rc.apparmor.functions'
+--- parser/rc.apparmor.functions       2011-08-13 12:15:58 +0000
++++ parser/rc.apparmor.functions       2011-08-26 22:55:43 +0000
+@@ -83,15 +83,6 @@
+ SUBDOMAINFS_MOUNTPOINT=$(grep subdomainfs /etc/fstab  | \
+       sed -e 's|^[[:space:]]*[^[:space:]]\+[[:space:]]\+\(/[^[:space:]]*\)[[:space:]]\+subdomainfs.*$|\1|' 2> /dev/null)
+-if [ -d "/var/lib/${MODULE}" ] ; then
+-      APPARMOR_TMPDIR="/var/lib/${MODULE}"
+-elif [ -d "/var/lib/${OLD_MODULE}" ] ; then
+-      APPARMOR_TMPDIR="/var/lib/${OLD_MODULE}"
 -else
--      _corefile=yes
--fi
--
--if [ "$1" = "yes" -a "$_corefile" = "no" ]
--then
--      echo "Error: corefile expected but not present - $2"
--elif [ "$1" = "no" -a "$_corefile"  = "yes" ]
--then
--      echo "Error: corefile present when not expected -- $2"
+-      APPARMOR_TMPDIR="/tmp"
 -fi
 -
--unset _corefile _corefilelist
--rm -f core.*
-+      # global _testdesc _pfmode _known outfile
-+      if [ ${1:0:1} == "x" ] ; then
-+              requirement=${1#x}
-+              _known=" (known problem)"
-+        else
-+              requirement=$1
-+              _known=""
-+        fi
-+
-+      _corefilelist=`echo core.*`
-+      if [ ! -f core ] && [ "$_corefilelist" = "core.*" ]
-+      then
-+              _corefile=no
-+      else
-+              _corefile=yes
-+      fi
-+
-+      if [ "$requirement" = "yes" -a "$_corefile" = "no" ] ; then
-+              if [ -n $_known ] ; then
-+                      echo -n "XFAIL: "
-+              fi
-+              echo "Error: corefile expected but not present - $2"
-+              if [ -z $_known ] ; then
-+                      cat $profile
-+                      testfailed
-+              fi
-+      elif [ "$requirement" = "no" -a "$_corefile"  = "yes" ] ; then
-+              if [ -n "$_known" ] ; then
-+                      echo -n "XFAIL: "
-+              fi
-+              echo "Error: corefile present when not expected -- $2"
-+              if [ -z "$_known" ] ; then
-+                      cat $profile
-+                      testfailed
-+              fi
-+      fi
-+
-+      unset _corefile _corefilelist
-+      cleancorefile
- }
- pwd=`dirname $0`
-@@ -45,15 +70,18 @@
- # enable coredumps
- ulimit -c 1000000
-+cleancorefile
-+checkcorefile no "COREDUMP (starting with clean slate)"
- # PASS TEST, no confinement
-+cleancorefile
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
- runchecktest "COREDUMP (no confinement)" signal11
- checkcorefile yes "COREDUMP (no confinement)"
- # PASS TEST, with r confinement
--genprofile $test:$coreperm
--cat $profile
-+cleancorefile
-+genprofile image=$test:$coreperm
- echo
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
-@@ -61,10 +89,10 @@
- checkcorefile yes "COREDUMP ($coreperm confinement)"
- # FAIL TEST, with x confinement
--genprofile $test:$nocoreperm
--cat $profile
-+cleancorefile
-+genprofile image=$test:$nocoreperm
- echo
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
- runchecktest "COREDUMP ($nocoreperm confinement)" signal11
--checkcorefile no "COREDUMP ($nocoreperm confinement)"
-+checkcorefile xno "COREDUMP ($nocoreperm confinement)"
-
-=== modified file 'tests/regression/apparmor/mkprofile.pl'
---- tests/regression/subdomain/mkprofile.pl    2009-11-11 18:44:26 +0000
-+++ tests/regression/apparmor/mkprofile.pl     2010-08-03 17:27:13 +0000
-@@ -5,7 +5,7 @@
- #
- # Gawd, I hate writing perl. It shows, too.
- #
--my $__VERSION__='$Id$';
-+my $__VERSION__=$0;
- use strict;
- use Getopt::Long;
-
-=== modified file 'tests/regression/apparmor/prologue.inc'
---- tests/regression/subdomain/prologue.inc    2010-02-07 07:04:57 +0000
-+++ tests/regression/apparmor/prologue.inc     2010-08-03 17:27:13 +0000
-@@ -1,9 +1,14 @@
- # vim:syntax=sh
- #
--# prologue.inc
--#
- # Test infrastructure support.
- #
-+# Copyright 2010 Canonical, Ltd.
-+#
-+#     This program is free software; you can redistribute it and/or
-+#     modify it under the terms of the GNU General Public License as
-+#     published by the Free Software Foundation, version 2 of the
-+#     License.
-+#
- # This file should be included by each test case
- # It does a lot of hidden 'magic',  Downside is that
- # this magic makes debugging fauling tests more difficult.
-@@ -93,8 +98,10 @@
-       while [ -h ${link} ]
-       do
--              if [ -x /usr/bin/readlink ] ; then 
--                      target=$(/usr/bin/readlink ${link})
-+              if [ -x /usr/bin/readlink ] ; then
-+                      target=$(/usr/bin/readlink -f ${link})
-+              elif [ -x /bin/readlink ] ; then
-+                      target=$(/bin/readlink -f ${link})
-               else 
-                       # I'm sure there's a more perlish way to do this
-                       target=$( perl -e "printf (\"%s\n\", readlink(\"${link}\"));") 
-@@ -251,6 +258,7 @@
-                       then
-                               echo "Error: ${testname} passed. Test '${_testdesc}' was expected to '${_pfmode}'"
-                               testfailed
-+                              return
-                       elif [ "$_pfmode" == "pass" -a -n "${_known}" ]
-                       then
-                               echo "Alert: ${testname} passed. Test '${_testdesc}' was marked as expected pass but known problem (xpass)"
-@@ -260,6 +268,7 @@
-                       then
-                               echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure '${ret}'"
-                               testfailed
-+                              return
-                       elif [ "$_pfmode" == "fail" -a -n "${_known}" ]
-                       then
-                               echo "Alert: ${testname} failed. Test '${_testdesc}' was marked as expected fail but known problem (xfail)."
-@@ -272,16 +281,23 @@
-                               then
-                                       echo "Error: ${testname} failed. Test '${_testdesc}' was expected to terminate with signal ${expectedsig}${_known}. Instead it terminated with signal ${killedsig}"
-                                       testfailed
-+                                      return
-                               fi
-                               ;;
-                       *)      echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'${_known}. Reason for failure 'killed by signal ${killedsig}'"
-                               testfailed
-+                              return
-                               ;;      
-                       esac
-                       ;;
-               *)      testerror
-+                      return
-                       ;;
-       esac
-+
-+      if [ -n "$VERBOSE" ]; then
-+              echo "ok: ${_testdesc}"
-+      fi
- }
- runchecktest()
-@@ -399,22 +415,12 @@
-               # it is most often used after --, in fact it is basically
-               # mandatory after --
-               case "$1" in
--                      profile=*) imagename=`echo $1 | sed 's/^profile=[rix]*//'`
--                               perm=`echo $1 | sed -n 's/^profile=\([rix]*\).*$/\1/p'`
--                               if [ -n "$perm" ]
--                               then
--                                      imageperm=$perm
--                               fi
--                               num_emitted=0
--                               shift
--                               ;;
--
--                      image=*) imagename=`echo $1 | sed 's/^image=[rix]*//'`
-+                      image=*) imagename=`echo $1 | sed 's/^image=\([^:]*\).*$/\1/'`
-                                if [ ! -x "$imagename" ]
-                                then
-                                       fatalerror "invalid imagename specified in input '$1'"
-                                fi
--                               perm=`echo $1 | sed -n 's/^image=\([rix]*\).*$/\1/p'`
-+                               perm=`echo $1 | sed -n 's/^image=[^:]*:\(.*\)$/\1/p'`
-                                if [ -n "$perm" ]
-                                then
-                                       imageperm=$perm
-
-=== modified file 'tests/regression/apparmor/pwrite.sh'
---- tests/regression/subdomain/pwrite.sh       2007-12-23 00:58:47 +0000
-+++ tests/regression/apparmor/pwrite.sh        2010-08-03 17:27:13 +0000
-@@ -27,7 +27,7 @@
- genprofile $file:$okperm
--runtestbg "PWRITE with w" pass $file
-+runtestbg "PREAD/PWRITE with rw" pass $file
- sleep 2
-
-=== modified file 'tests/regression/apparmor/swap.sh'
---- tests/regression/subdomain/swap.sh 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/swap.sh  2010-08-03 17:27:13 +0000
-@@ -32,7 +32,7 @@
- swap_file=$tmpdir/swapfile
- dd if=/dev/zero of=${swap_file} bs=1024 count=512 2> /dev/null
--/sbin/mkswap ${swap_file} > /dev/null
-+/sbin/mkswap -f ${swap_file} > /dev/null
- # TEST 1.  Make sure can enable and disable swap unconfined
-
-=== modified file 'tests/regression/apparmor/syscall.sh'
---- tests/regression/subdomain/syscall.sh      2007-12-23 01:02:50 +0000
-+++ tests/regression/apparmor/syscall.sh       2010-08-03 17:27:13 +0000
-@@ -1,7 +1,7 @@
- #! /bin/bash
--# $Id$
--
-+#
- #     Copyright (C) 2002-2005 Novell/SUSE
-+#     Copyright (C) 2010 Canonical, Ltd.
- #
- #     This program is free software; you can redistribute it and/or
- #     modify it under the terms of the GNU General Public License as
-@@ -114,9 +114,9 @@
- runchecktest "MKNOD sock (permissions)" fail s $mknod_file
- ##
--## D. SETHOSTNAME
-+## C. SYSCTL
- ##
--sh syscall_sysctl.sh
-+bash syscall_sysctl.sh
- ##
- ## D. SETHOSTNAME 
-
-=== modified file 'tests/regression/apparmor/syscall_mknod.c'
---- tests/regression/subdomain/syscall_mknod.c 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/syscall_mknod.c  2010-08-03 17:27:13 +0000
-@@ -19,7 +19,7 @@
- int main(int argc, char *argv[])
- {
--int fd, mode;
-+      int mode;
-       if (argc != 3){
-               fprintf(stderr, "usage: %s b|c|f|s|r file\n",
-@@ -49,8 +49,6 @@
-               return 1;
-       }
--      close(fd);
--
-       printf("PASS\n");
-       return 0;
-
-=== modified file 'tests/regression/apparmor/unix_fd_server.c'
---- tests/regression/subdomain/unix_fd_server.c        2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/unix_fd_server.c 2010-08-03 17:27:13 +0000
-@@ -2,6 +2,7 @@
- /*
-  *    Copyright (C) 2002-2005 Novell/SUSE
-+ *    Copyright (C) 2010 Canonical, Ltd.
-  *
-  *    This program is free software; you can redistribute it and/or
-  *    modify it under the terms of the GNU General Public License as
-@@ -134,6 +135,7 @@
-       }
-       /* Check for info re: reading the file */
-+      memset(inbound_buffer, 0, sizeof(inbound_buffer));
-       if (recv(in_sock, inbound_buffer, 16,0) == -1 ) {
-               fprintf(stderr, "FAIL - recv %s\n",
-                       strerror(errno));
-
-=== modified file 'tests/stress/parser/stress.rb'
---- tests/stress/parser/stress.rb      2008-11-26 22:16:48 +0000
-+++ tests/stress/parser/stress.rb      2010-05-31 18:58:40 +0000
-@@ -14,10 +14,27 @@
-   return sprintf("%0#{len}x", rand(2 ** (4 * len)))
- end
-+def get_random_regex()
-+  case rand(10)
-+    when 0..3
-+      return "{#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)}}"
-+    when 4..5
-+      return "[#{get_random_name(rand(5) + 1)}]"
-+    when 6..7
-+      return "*"
-+    when 8..9
-+      return "**"
-+  end
-+end
-+
- def get_random_path()
-   out = ""
--  0.upto(rand(20)) do
--    out = "#{out}/#{get_random_name(4)}"
-+  0.upto(rand(20) + 2) do
-+    if rand(4) == 0
-+      out = "#{out}/#{get_random_regex}"
-+    else
-+      out = "#{out}/#{get_random_name(rand(10) + 4)}"
-+    end
-   end
-   return out
- end
-@@ -83,7 +100,10 @@
-     "mknod",
-     "lease",
-     "audit_write",
--    "audit_control"
-+    "audit_control",
-+    "setfcap",
-+    "mac_override",
-+    "mac_admin"
-   ]
-   def initialize()
-@@ -95,6 +115,93 @@
-   end
- end
-+class NetRule < Rule
-+  # XXX Fill me in
-+end
-+
-+class RlimitRule < Rule
-+  RLIMIT_LIST = [
-+#"cpu",               # cpu rlimit not supported
-+    "fsize",
-+    "data",
-+    "stack",
-+    "core",
-+    "rss",
-+    "nofile",
-+    "ofile",
-+    "as",
-+    "nproc",
-+    "memlock",
-+    "locks",
-+    "sigpending",
-+    "msgqueue",
-+    "nice",
-+    "rtprio"
-+  ]
-+
-+  def initialize()
-+    @rlimit = RLIMIT_LIST[rand(RLIMIT_LIST.length)]
-+    if rand(20) == 0
-+      @limit = "infinity"
-+    elsif @rlimit == "nice"
-+      @limit = rand(40) - 20
-+    else
-+      @limit = rand(2 ** 31)
-+    end
-+  end
-+
-+  def to_s
-+    return "  set rlimit #{@rlimit} <= #{@limit},"
-+  end
-+end
-+
-+class Flags
-+  FLAG_LIST = [
-+    "complain",
-+    "audit",
-+    "chroot_relative",
-+    "namespace_relative",
-+    "mediate_deleted",
-+    "delegate_deleted",
-+    "attach_disconnected",
-+    "no_attach_disconnected",
-+    "chroot_attach",
-+    "chroot_no_attach"
-+  ]
-+
-+  FLAG_CONFLICTS = [
-+    ["chroot_relative", "namespace_relative"],
-+    ["mediate_deleted", "delegate_deleted"],
-+    ["attach_disconnected", "no_attach_disconnected"],
-+    ["chroot_attach", "chroot_no_attach"]
-+  ]
-+
-+  def initialize()
-+    @flags = []
-+    if rand(2) == 1
-+      return
-+    end
-+
-+    0.upto(4 - Math.log(rand(32) + 1).to_int) do |x|
-+      @flags << FLAG_LIST[rand(FLAG_LIST.length)]
-+    end
-+
-+    FLAG_CONFLICTS.each do |c|
-+      if @flags.include?(c[0]) and @flags.include?(c[1])
-+        @flags.delete(c[rand(2)])
-+      end
-+    end
-+  end
-+
-+  def to_s
-+    if @flags.empty?
-+      return ""
-+    end
-+    out = @flags.join(",")
-+    return "flags=(#{out})"
-+  end
-+end
-+
- def prefix_to_s(name)
-   out = []
-   out << "#"
-@@ -112,16 +219,19 @@
-     @rvalue = get_random_name()
-     @name = "/does/not/exist/#{@rvalue}"
-     @rules = []
-+    @flags = Flags.new()
-   end
-   def generate_rules
--    @rules << FileRule.new(@name, "rm")
-+    @rules << FileRule.new(@name, "rm").to_s
-     0.upto(rand($max_rules - $min_rules) + $min_rules) do |x|
-       case rand(100)
--        when 0..19
--          @rules << CapRule.new
--        when 19..100
--          @rules << FileRule.new
-+        when 0..14
-+          @rules << CapRule.new.to_s
-+        when 15..24
-+          @rules << RlimitRule.new.to_s
-+        when 25..100
-+          @rules << FileRule.new.to_s
-       end
-     end
-   end
-@@ -132,10 +242,10 @@
-     out << "# profile for #{@name}"
-     out << "# generated by #{__FILE__} #{$my_version}"
-     out << "#"
--    out << "#{@name} {"
-+    out << "#{@name} #{@flags} {"
-     out << "  #include <abstractions/base>"
-     out << ""
--    @rules.each { |r| out << r.to_s }
-+    @rules.sort.each { |r| out << "  #{r}" }
-     out << "}"
-     out << ""
-   end
-
-=== modified file 'utils/SubDomain.pm'
---- utils/SubDomain.pm 2010-03-10 23:30:06 +0000
-+++ utils/SubDomain.pm 2010-08-03 17:27:13 +0000
-@@ -2,6 +2,7 @@
- #
- # ----------------------------------------------------------------------
- #    Copyright (c) 2006 Novell, Inc. All Rights Reserved.
-+#    Copyright (c) 2010 Canonical, Ltd.
- #
- #    This program is free software; you can redistribute it and/or
- #    modify it under the terms of version 2 of the GNU General Public
-@@ -2413,10 +2414,13 @@
- our $seenmark;
- my $RE_LOG_v2_0_syslog = qr/SubDomain/;
- my $RE_LOG_v2_1_syslog = qr/kernel:\s+(\[[\d\.\s]+\]\s+)?(audit\([\d\.\:]+\):\s+)?type=150[1-6]/;
-+my $RE_LOG_v2_6_syslog = qr/kernel:\s+(\[[\d\.\s]+\]\s+)?type=\d+\s+audit\([\d\.\:]+\):\s+apparmor=/;
- my $RE_LOG_v2_0_audit  =
-     qr/type=(APPARMOR|UNKNOWN\[1500\]) msg=audit\([\d\.\:]+\):/;
- my $RE_LOG_v2_1_audit  =
-     qr/type=(UNKNOWN\[150[1-6]\]|APPARMOR_(AUDIT|ALLOWED|DENIED|HINT|STATUS|ERROR))/;
-+my $RE_LOG_v2_6_audit =
-+    qr/type=AVC\s+audit\([\d\.\:]+\):\s+apparmor=/;
- sub prefetch_next_log_entry {
-     # if we already have an existing cache entry, something's broken
-@@ -2434,6 +2438,8 @@
-         $RE_LOG_v2_0_audit  |
-         $RE_LOG_v2_1_audit  |
-         $RE_LOG_v2_1_syslog |
-+        $RE_LOG_v2_6_syslog |
-+        $RE_LOG_v2_6_audit  |
-         $logmark
-     }x);
- }
-@@ -6612,10 +6618,14 @@
-     LibAppArmor::free_record($event);
-     #map new c and d to w as logprof doesn't support them yet
--    $rmask =~ s/c/w/g;
--    $rmask =~ s/d/w/g;
--    $dmask =~ s/c/w/g;
--    $dmask =~ s/d/w/g;
-+    if ($rmask) {
-+        $rmask =~ s/c/w/g;
-+        $rmask =~ s/d/w/g;
-+    }
-+    if ($dmask) {
-+        $dmask =~ s/c/w/g;
-+        $dmask =~ s/d/w/g;
-+    }
-     if ($rmask && !validate_log_mode(hide_log_mode($rmask))) {
-         fatal_error(sprintf(gettext('Log contains unknown mode %s.'),
-
-=== modified file 'utils/apparmor_notify'
---- utils/apparmor_notify      2010-03-10 16:11:26 +0000
-+++ utils/apparmor_notify      2010-05-31 18:58:40 +0000
-@@ -30,8 +30,7 @@
- require Time::Local;
- require File::Basename;
--use vars qw($opt_p $opt_s $opt_l $opt_h $opt_v $opt_d $opt_w);
--use Getopt::Std;
-+use Getopt::Long;
- my %prefs;
- my $conf = "/etc/apparmor/notify.conf";
-@@ -67,7 +66,6 @@
- $ENV{SHELL} = "/bin/sh";
- defined($ENV{IFS}) and $ENV{IFS} = ' \t\n';
--print $0 . "\n";
- my $prog = File::Basename::basename($0);
- if ($prog !~ /^[a-zA-Z0-9_\-]+$/) {
-@@ -75,32 +73,66 @@
-     exitscript(1);
- }
--my $logfile = "/var/log/kern.log";
---e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
 -
- $> == $< or die "Cannot be suid\n";
- $) == $( or die "Cannot be sgid\n";
- my $login;
-+our $orig_euid = $>;
--getopts('dhlpvs:w:');
-+my $opt_d = '';
-+my $opt_h = '';
-+my $opt_l = '';
-+my $opt_p = '';
-+my $opt_v = '';
-+my $opt_f = '';
-+my $opt_s = 0;
-+my $opt_u = '';
-+my $opt_w = 0;
-+GetOptions(
-+    'debug|d'        => \$opt_d,
-+    'help|h'         => \$opt_h,
-+    'since-last|l'   => \$opt_l,
-+    'poll|p'         => \$opt_p,
-+    'verbose|v'      => \$opt_v,
-+    'file|f=s'       => \$opt_f,
-+    'since-days|s=n' => \$opt_s,
-+    'user|u=s'       => \$opt_u,
-+    'wait|w=n'       => \$opt_w,
-+);
- if ($opt_h) {
-     usage;
-     exitscript(0);
- }
+ # keep exit status from parser during profile load.  0 is good, 1 is bad
+ STATUS=0
+@@ -221,7 +212,6 @@
+ profiles_names_list() {
+       # run the parser on all of the apparmor profiles
+-      TMPFILE=$1
+       if [ ! -f "$PARSER" ]; then
+               aa_log_failure_msg "- AppArmor parser not found"
+               exit 1
+@@ -234,9 +224,9 @@
+       for profile in $PROFILE_DIR/*; do
+               if skip_profile "${profile}" && [ -f "${profile}" ] ; then
+-                      LIST_ADD=$($PARSER $ABSTRACTIONS -N "$profile" | grep -v '\^')
++                      LIST_ADD=$($PARSER $ABSTRACTIONS -N "$profile" )
+                       if [ $? -eq 0 ]; then
+-                              echo "$LIST_ADD" >>$TMPFILE
++                              echo "$LIST_ADD"
+                       fi
+               fi
+       done
+@@ -408,18 +398,16 @@
+       fi
  
-+# monitor file specified with -f, else use audit.log if auditd is running,
-+# otherwise kern.log
-+our $logfile = "/var/log/kern.log";
-+if ($opt_f) {
-+    -f $opt_f or die "'$opt_f' does not exist. Aborting\n";
-+    $logfile = $opt_f;
-+} else {
-+    -e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
+       retval=0
+-      #the list of profiles isn't stable once we start adding or removing
+-      #them so store to tmp first (in reverse order so hat profiles are removed first)
+-      MODULE_PLIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+-      sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | sort -r > "$MODULE_PLIST"
+-      cat "$MODULE_PLIST" | while read profile ; do
++      # We filter child profiles as removing the parent will remove
++      # the children
++      sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" \
++      LC_COLLATE=C sort | grep -v // | while read profile ; do
+               echo -n "$profile" > "$SFS_MOUNTPOINT/.remove"
+               rc=$?
+               if [ ${rc} -ne 0 ] ; then 
+                       retval=${rc}
+               fi
+       done
+-      rm "$MODULE_PLIST"
+       return ${retval}
+ }
+@@ -461,17 +449,33 @@
+       configure_owlsm
+       parse_profiles reload
+-      PNAMES_LIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+-      profiles_names_list ${PNAMES_LIST}
+-      MODULE_PLIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+       # Clean out running profiles not associated with the current profile
+       # set, excluding the libvirt dynamically generated profiles.
+-      sed  -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | egrep -v '^libvirt-[0-9a-f\-]+$' | sort >"$MODULE_PLIST"
+-      sort "$PNAMES_LIST" | comm -2 -3 "$MODULE_PLIST" - | while IFS= read profile ; do
++      # Note that we reverse sort the list of profiles to remove to
++      # ensure that child profiles (e.g. hats) are removed before the
++      # parent. We *do* need to remove the child profile and not rely
++      # on removing the parent profile when the profile has had its
++      # child profile names changed.
++      profiles_names_list | awk '
++BEGIN {
++  while (getline < "'${SFS_MOUNTPOINT}'/profiles" ) {
++    str = sub(/ \((enforce|complain)\)$/, "", $0);
++    if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
++      arr[$str] = $str
++  }
 +}
 +
-+-r $logfile or die "Cannot read '$logfile'\n";
-+our $logfile_inode = get_logfile_inode($logfile);
-+our $logfile_size = get_logfile_size($logfile);
- open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
- # Drop priviliges, if running as root
- if ($< == 0) {
-     $login = "root";
-     if (defined($ENV{SUDO_UID}) and defined($ENV{SUDO_GID})) {
-         POSIX::setgid($ENV{SUDO_GID}) or _error("Could not change gid");
--        POSIX::setuid($ENV{SUDO_UID}) or _error("Could not change uid");
-+        $> = $ENV{SUDO_UID} or _error("Could not change euid");
-         defined($ENV{SUDO_USER}) and $login = $ENV{SUDO_USER};
-     } else {
-+        my $drop_to = $nobody_user;
-+        if ($opt_u) {
-+            $drop_to = $opt_u;
-+        }
-         # nobody/nogroup
--        POSIX::setgid(scalar(getpwnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
--        POSIX::setuid(scalar(getpwnam($nobody_user))) or _error("Could not change uid to '$nobody_user'");
-+        POSIX::setgid(scalar(getgrnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
-+        $> = scalar(getpwnam($drop_to)) or _error("Could not change euid to '$drop_to'");
-     }
- } else {
-     $login = getlogin();
-@@ -111,7 +143,7 @@
-     readconf($conf);
-     if (defined($prefs{use_group})) {
-         my ($name, $passwd, $gid, $members) = getgrnam($prefs{use_group});
--        if (not defined($members) or not defined($login) or not grep { $_ eq $login } split(/ /, $members)) {
-+        if (not defined($members) or not defined($login) or (not grep { $_ eq $login } split(/ /, $members) and $login ne "root")) {
-             _error("'$login' must be in '$prefs{use_group}' group. Aborting");
-         }
-     }
-@@ -220,7 +252,6 @@
-     defined($name) and $formatted .= "Name: $name\n";
-     defined($denied) and $formatted .= "Denied: $denied\n";
-     defined($family) and defined ($sock_type) and $formatted .= "Family: $family\nSocket type: $sock_type\n";
--    #defined($date) and $since > 0 and $formatted .= "Date: ". scalar(localtime($date)) ."\n";
-     $formatted .= "Logfile: $logfile\n";
-     return $formatted;
-@@ -259,6 +290,26 @@
-     close(PS);
- }
-+sub send_message {
-+    my $msg = $_[0];
-+
-+    my $pid = fork();
-+    if ($pid == 0) {  # child
-+        # notify-send needs $< to be the unprivileged user
-+        $< = $>;
++{ if (length(arr[$0]) > 0) { delete arr[$0] } }
 +
-+        # 'system' uses execvp() so no shell metacharacters here.
-+        # $notify_exe is an absolute path so execvp won't search PATH.
-+        system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$msg";
-+        my $exit_code = $? >> 8;
-+        exit($exit_code);
++END {
++  for (key in arr)
++    if (length(arr[key]) > 0) {
++      printf("%s\n", arr[key])
 +    }
-+
-+    # parent
-+    waitpid($pid, 0);
-+    return $?;
 +}
-+
- sub do_notify {
-     my %seen;
-     my $seconds = 5;
-@@ -273,7 +324,7 @@
-         umask 0;
-         open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
-         open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
--        open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
-+        #open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
-         my $pid = fork();
-         exit if $pid;
-         die "Couldn't fork: $!" unless defined($pid);
-@@ -293,12 +344,24 @@
-     my $count = 0;
-     my $footer = "For more information, please see:\n$url";
-     my $first_run = 1;
--    my $since = $now - (int($opt_s) * 60 * 60 * 24);
-+    my $since = $now;
-+    if ($opt_s and int($opt_s) > 0) {
-+       $since = $since - (int($opt_s) * 60 * 60 * 24);
-+    }
-     for (my $i=0; $time_to_die == 0; $i++) {
-+        if ($logfile_inode != get_logfile_inode($logfile)) {
-+            _warn("$logfile changed inodes, reopening");
-+            reopen_logfile();
-+        } elsif (get_logfile_size($logfile) < $logfile_size) {
-+            _warn("$logfile is smaller, reopening");
-+            reopen_logfile();
-+        }
-         while(my $msg = <LOGFILE>) {
-             my @attrib;
--            if ($first_run == 1 and $opt_s) {
--                @attrib = parse_message($msg, $since);
-+            if ($first_run == 1) {
-+                if ($since != $now) {
-+                    @attrib = parse_message($msg, $since);
-+                }
-             } else {
-                 @attrib = parse_message($msg);
-             }
-@@ -340,12 +403,9 @@
-             $m .= $footer;
--          # 'system' uses execvp() so no shell metacharacters here.
--            # $notify_exe is an absolute path so execvp won't search PATH.
--            system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
--            my $exit_code = $? >> 8;
--            if ($exit_code != 0) {
--                _warn("'$notify_exe' exited with '$exit_code'");
-+            my $rc = send_message($m);
-+            if ($rc != 0) {
-+                _warn("'$notify_exe' exited with error '$rc'");
-                 $time_to_die = 1;
-                 last;
-             }
-@@ -356,7 +416,7 @@
-         if ($first_run) {
-             if ($count > 0) {
--                my $m = "$logfile contains $count existing denied message";
-+                my $m = "$logfile contains $count denied message";
-                 $count > 1 and $m .= "s";
-                 if ($opt_s) {
-                     $m .= " in the last ";
-@@ -368,7 +428,7 @@
-                 }
-                 $m .= ". ";
-                 $m .= $footer;
--                system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
-+                send_message($m);
-             }
-             $first_run = 0;
-         }
-@@ -390,6 +450,9 @@
- }
- sub show_since {
-+    my %msg_hash;
-+    my %last_date;
-+    my @msg_list;
-     my $count = 0;
-     while(my $msg = <LOGFILE>) {
-         my @attrib = parse_message($msg, $_[0]);
-@@ -397,10 +460,31 @@
-         my $m = format_message(@attrib);
-         $m ne "" or next;
--
--        $opt_v and print "$m\n";
-+        my $date = $attrib[6];
-+        if ($opt_v) {
-+            if (exists($msg_hash{$m})) {
-+                $msg_hash{$m}++;
-+                defined($date) and $last_date{$m} = scalar(localtime($date));
-+            } else {
-+                $msg_hash{$m} = 1;
-+                push(@msg_list, $m);
-+            }
-+        }
-         $count++;
-     }
-+    if ($opt_v) {
-+        foreach my $m (@msg_list) {
-+            print "$m";
-+            if ($msg_hash{$m} gt 1) {
-+                print "($msg_hash{$m} found";
-+                if (exists($last_date{$m})) {
-+                    print ", most recent from '$last_date{$m}'";
-+                }
-+                print ")\n";
-+            }
-+            print "\n";
-+        }
-+    }
-     return $count;
- }
-@@ -452,19 +536,63 @@
- sub usage {
-     my $s = <<'EOF';
- USAGE: apparmor_notify [OPTIONS]
-+
- Display AppArmor notifications or messages for DENIED entries.
- OPTIONS:
--  -p          poll AppArmor logs and display notifications
--  -l          display stats since last login
--  -s NUM      show stats for last NUM days (can be used alone or with -p)
--  -v          show messages with stats
--  -h          display this help
--  -w NUM      wait NUM seconds before displaying notifications (with -p)
-+  -p, --poll                  poll AppArmor logs and display notifications
-+  -f FILE, --file=FILE                search FILE for AppArmor messages
-+  -l, --since-last            display stats since last login
-+  -s NUM, --since-days=NUM    show stats for last NUM days (can be used alone
-+                              or with -p)
-+  -v, --verbose                       show messages with stats
-+  -h, --help                  display this help
-+  -u USER, --user=USER                user to drop privileges to when not using sudo
-+  -w NUM, --wait=NUM          wait NUM seconds before displaying
-+                              notifications (with -p)
- EOF
-     print $s;
++' | LC_COLLATE=C sort -r | while IFS= read profile ; do
+               echo -n "$profile" > "$SFS_MOUNTPOINT/.remove"
+       done
+-      rm "$MODULE_PLIST"
+-      rm "$PNAMES_LIST"
+       return 0
  }
  
-+sub reopen_logfile {
-+    # reopen the logfile, temporarily switching back to starting euid for
-+    # file permissions.
-+    close(LOGFILE);
-+
-+    my $old_euid = $>;
-+    my $change_euid = 0;
-+    if ($> != $<) {
-+        _debug("raising privileges to '$orig_euid' in reopen_logfile()");
-+        $change_euid = 1;
-+        $> = $orig_euid;
-+        $> == $orig_euid or die "Could not raise privileges\n";
-+    }
-+
-+    $logfile_inode = get_logfile_inode($logfile);
-+    $logfile_size = get_logfile_size($logfile);
-+    open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
-+
-+    if ($change_euid) {
-+        _debug("dropping privileges to '$old_euid' in reopen_logfile()");
-+        $> = $old_euid;
-+        $> == $old_euid or die "Could not drop privileges\n";
-+    }
-+}
-+
-+sub get_logfile_size {
-+    my $fn = $_[0];
-+    my $size;
-+    defined(($size = (stat($fn))[7])) or (sleep(10) and defined(($size = (stat($fn))[7])) or die "'$fn' disappeared. Aborting\n");
-+    return $size;
-+}
-+
-+sub get_logfile_inode {
-+    my $fn = $_[0];
-+    my $inode;
-+    defined(($inode = (stat($fn))[1])) or (sleep(10) and defined(($inode = (stat($fn))[1])) or die "'$fn' disappeared. Aborting\n");
-+    return $inode;
-+}
-+
- #
- # end Subroutines
- #
-
-=== modified file 'utils/apparmor_notify.pod'
---- utils/apparmor_notify.pod  2010-02-12 16:25:02 +0000
-+++ utils/apparmor_notify.pod  2010-05-31 18:58:40 +0000
-@@ -40,24 +40,37 @@
- =over 4
--=item -p
-+=item -p, --poll
- poll AppArmor logs and display desktop notifications. Can be used with '-s'
- option to display a summary on startup.
--=item -l
-+=item -f FILE, --file=FILE
-+
-+search FILE for AppArmor messages
-+
-+=item -l, --since-last
- show summary since last login.
--=item -s NUM
-+=item -s NUM, --since-days=NUM
- show summary for last NUM of days.
--=item -v
-+=item -u USER, --user=USER
-+
-+user to drop privileges to when running privileged. This has no effect when
-+running under sudo.
-+
-+=item -w NUM, --wait=NUM
-+
-+wait NUM seconds before displaying notifications (for use with -p)
-+
-+=item -v, --verbose
- show messages with summaries.
--=item -h
-+=item -h, --help
- displays a short usage statement.
 
index 8c9fd467dc19a847ea15e1ff8a79468ac0f9e7ab..3383064f4e2fa7d7af4283911f625f18d016d873 100644 (file)
@@ -5,7 +5,7 @@ Summary:        AppArmor userlevel parser utility
 Summary(pl.UTF-8):     Narzędzie przestrzeni użytkownika do przetwarzania AppArmor
 Name:          apparmor-parser
 Version:       2.6.1
-Release:       2
+Release:       3
 Epoch:         1
 License:       GPL
 Group:         Applications/System
@@ -25,6 +25,9 @@ BuildRequires:        libstdc++-static
 BuildRequires: perl-Test-Harness
 BuildRequires: perl-tools-devel
 BuildRequires: perl-tools-pod
+%if %{with tests}
+BuildRequires: perl-Locale-gettext
+%endif
 BuildRoot:     %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
 
 %description
@@ -40,8 +43,7 @@ SubDomain.
 
 %prep
 %setup -q -n apparmor-%{version}
-# reenable when needed
-#%patch0 -p0
+%patch0 -p0
 %patch1 -p0
 
 %build
This page took 0.900233 seconds and 4 git commands to generate.