=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
-+++ .bzrignore 2010-06-05 01:39:20 +0000
-@@ -0,0 +1,25 @@
++++ .bzrignore 2010-08-03 17:27:13 +0000
+@@ -0,0 +1,165 @@
+parser/po/*.mo
+parser/af_names.h
+parser/cap_names.h
+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-03-16 22:00:26 +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
+
\ 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-03-16 22:18:55 +0000
-@@ -125,9 +125,20 @@
++++ 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 $< > $@
+main: $(TOOLS)
$(Q)make -C po all
- $(Q)make -s tests
+-
+-apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
+
+manpages: $(MANPAGES)
+
+docs: manpages htmlmanpages pdf
+
+all: main docs tests
-
- apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
++
++apparmor_parser: $(OBJECTS) $(AAREOBJECTS)
rm -f ./libstdc++.a
-@@ -191,7 +202,7 @@
+ 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" $< >> $@
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" $< > $@
-@@ -214,7 +225,7 @@
+@@ -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}
$(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-04-03 23:24:06 +0000
-@@ -154,6 +154,33 @@
++++ 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.
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-03-13 10:23:23 +0000
-@@ -1715,7 +1715,9 @@
++++ 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);
}
}
+@@ -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-03-12 23:26:32 +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)
* 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 @@
+@@ -14,12 +17,12 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
*/
#include <netinet/in.h>
-@@ -280,12 +284,16 @@
+ #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 */
extern void dump_symtab(void);
extern void dump_expanded_symtab(void);
void free_symtabs(void);
-@@ -312,7 +320,7 @@
+@@ -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);
=== modified file 'parser/parser_include.c'
--- parser/parser_include.c 2009-07-24 12:18:12 +0000
-+++ parser/parser_include.c 2010-06-05 01:57:01 +0000
++++ parser/parser_include.c 2010-08-03 17:27:13 +0000
@@ -1,8 +1,8 @@
-/* $Id$ */
-
+ if (current_filename)
+ free(current_filename);
+ current_filename = strdup(filename ? filename : "stdin");
-+ current_lineno = 0;
++ current_lineno = 1;
+}
+
+void push_include_stack(char *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 01:57:01 +0000
++++ parser/parser_include.h 2010-06-05 06:11:20 +0000
@@ -1,8 +1,8 @@
-/* $Id$ */
-
+
#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-06-05 01:57:01 +0000
++++ parser/parser_lex.l 2010-08-03 17:27:13 +0000
@@ -1,8 +1,8 @@
-/* $Id$ */
-
*/
/* Definitions section */
-@@ -49,7 +49,8 @@
+@@ -49,7 +49,12 @@
#endif
#define NPDEBUG(fmt, args...) /* Do nothing */
-int current_lineno = 1;
-+int current_lineno = 0;
++#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;
-@@ -87,7 +88,8 @@
+@@ -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)
if (fstat(fileno(include_file), &my_stat))
yyerror(_("fstat failed for '%s'"), fullpath);
-@@ -95,6 +97,7 @@
+@@ -95,6 +105,7 @@
if (S_ISREG(my_stat.st_mode)) {
yyin = include_file;
PDEBUG("Opened include \"%s\"\n", fullpath);
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
}
-@@ -139,8 +142,9 @@
+@@ -139,8 +150,9 @@
yyerror(_("stat failed for '%s'"), dirent_path);
if (S_ISREG(my_stat.st_mode)) {
if (!(yyin = fopen(dirent_path,"r")))
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
}
-@@ -227,6 +231,8 @@
+@@ -227,6 +239,8 @@
}
<<EOF>> {
yypop_buffer_state();
if ( !YY_CURRENT_BUFFER ) yyterminate();
}
-
-=== modified file 'parser/parser_main.c'
---- parser/parser_main.c 2010-01-28 01:20:13 +0000
-+++ parser/parser_main.c 2010-06-05 01:47:44 +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.
- */
+@@ -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 @@
+ }
- #include <stdio.h>
-@@ -85,8 +89,6 @@
+ [^\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;
-
+-extern int current_lineno;
++FILE *ofile = NULL;
+
/* per-profile settings */
int force_complain = 0;
- char *profilename = NULL;
-@@ -224,8 +226,10 @@
+@@ -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;
current_lineno,
fmt);
if (!newfmt)
-@@ -258,7 +262,7 @@
+@@ -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++;
break;
case 'h':
if (!optarg) {
-@@ -316,7 +320,7 @@
+@@ -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':
if (!optarg) {
dump_vars = 1;
} else if (strcmp(optarg, "variables") == 0) {
-@@ -359,7 +363,7 @@
+ 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':
if (strcmp(optarg, "0") == 0) {
dfaflags |= DFA_CONTROL_NO_TREE_NORMAL |
DFA_CONTROL_NO_TREE_SIMPLE |
-@@ -695,12 +699,13 @@
+@@ -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;
}
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)
-@@ -796,7 +801,7 @@
+@@ -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);
retval = yyparse();
if (retval != 0)
-@@ -812,7 +817,7 @@
+ goto out;
+
++ if (preprocess_only)
++ goto out;
++
+ if (names_only) {
+ dump_policy_names();
+ goto out;
+@@ -812,7 +842,7 @@
goto out;
}
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-03-12 23:26:32 +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)
return retval;
-=== modified file 'parser/parser_symtab.c'
---- parser/parser_symtab.c 2009-07-24 13:24:53 +0000
-+++ parser/parser_symtab.c 2010-03-12 22:41:58 +0000
-@@ -33,11 +33,6 @@
- sd_set,
- };
-
--struct set_value {
-- char *val;
-- struct set_value *next;
--};
--
- struct symtab {
- char *var_name;
- enum var_type type;
-@@ -288,7 +283,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 +316,17 @@
- }
+=== 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)
- /* iterator to walk the list of set values */
--char *get_next_set_value(void **list)
-+char *get_next_set_value(struct set_value **list)
+ /* #define DEBUG */
+@@ -74,7 +75,6 @@
{
-- struct set_value **valuelist = (struct set_value **) list;
-+ struct set_value *next;
- char *ret;
+ char *sptr, *dptr;
+ BOOL seen_slash = 0;
+- int len;
-- if (!valuelist || !(*valuelist))
-+ if (!list || !(*list))
- return NULL;
+ 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;
+- }
+- }
+ }
-- ret = (*valuelist)->val;
-- (*valuelist) = (*valuelist)->next;
-+ ret = (*list)->val;
-+ next = (*list)->next;
-+ (*list) = next;
+ static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
+@@ -154,6 +141,9 @@
+ sptr = aare;
+ dptr = pcre;
- return ret;
++ 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;
}
-@@ -569,7 +565,7 @@
- {
- int rc = 0;
- int retval;
-- void *retptr;
+
+-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;
=== modified file 'parser/parser_variable.c'
--- parser/parser_variable.c 2009-07-24 23:47:46 +0000
-+++ parser/parser_variable.c 2010-03-12 23:20:22 +0000
-@@ -124,7 +124,7 @@
++++ 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)
{
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-06-05 01:57:01 +0000
-@@ -1,9 +1,9 @@
- %{
--/* $Id$ */
+=== 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) 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;
+-/* Copyright (c) 1997-2001 University of Cambridge */
-
- struct value_list {
- char *value;
- struct value_list *next;
-@@ -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);
- }
-
+-#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-06-05 01:47:44 +0000
++++ parser/tst/Makefile 2010-08-03 17:27:13 +0000
@@ -1,8 +1,9 @@
#
-# $Id$
ifeq ($(VERBOSE),1)
PROVE_ARG=-v
-@@ -10,9 +11,19 @@
+@@ -10,9 +11,23 @@
all: tests
+ 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)
=== modified file 'parser/tst/README'
--- parser/tst/README 2006-06-01 17:02:28 +0000
-+++ parser/tst/README 2010-06-05 01:47:44 +0000
++++ parser/tst/README 2010-06-05 06:11:20 +0000
@@ -64,5 +64,3 @@
loop.
=== 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 01:47:44 +0000
++++ parser/tst/errors/double.sd 2010-06-05 06:11:20 +0000
@@ -0,0 +1,5 @@
+#
+/does/not/exist {
=== 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 01:47:44 +0000
++++ parser/tst/errors/includes/base 2010-06-05 06:11:20 +0000
@@ -0,0 +1,81 @@
+# $Id$
+# ------------------------------------------------------------------
=== 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 01:47:44 +0000
++++ parser/tst/errors/includes/busted 2010-06-05 06:11:20 +0000
@@ -0,0 +1,83 @@
+# $Id$
+# ------------------------------------------------------------------
+ /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 01:47:44 +0000
++++ parser/tst/errors/okay.sd 2010-06-05 06:11:20 +0000
@@ -0,0 +1,4 @@
+#
+/does/not/exist {
=== 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 01:47:44 +0000
++++ parser/tst/errors/single.sd 2010-06-05 06:11:20 +0000
@@ -0,0 +1,7 @@
+#
+#
=== 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 00:43:11 +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,
# 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-04-19 17:38:17 +0000
++++ profiles/apparmor.d/abstractions/dbus-session 2010-08-03 17:27:13 +0000
@@ -0,0 +1,14 @@
+# vim:syntax=apparmor
+# $Id$
+#
+# ------------------------------------------------------------------
+
-+ #include <abstractions/dbus>
-+ /usr/bin/dbus-launch Uxr,
++ /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 00:44:30 +0000
++++ profiles/apparmor.d/abstractions/fonts 2010-06-05 06:11:20 +0000
@@ -15,6 +15,7 @@
/usr/lib/xorg/modules/fonts/**.so* mr,
=== 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 00:44:30 +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}/.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 00:44:59 +0000
++++ profiles/apparmor.d/abstractions/nameservice 2010-06-05 06:11:20 +0000
@@ -77,3 +77,5 @@
network inet dgram,
network inet6 dgram,
=== 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-03-30 17:34:32 +0000
++++ profiles/apparmor.d/abstractions/php5 2010-05-31 18:58:40 +0000
@@ -2,7 +2,7 @@
# ------------------------------------------------------------------
#
=== 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-03-25 23:13:00 +0000
++++ profiles/apparmor.d/abstractions/samba 2010-05-31 18:58:40 +0000
@@ -2,7 +2,7 @@
# $Id$
# ------------------------------------------------------------------
/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-12 08:52:23 +0000
++++ profiles/apparmor.d/abstractions/user-tmp 2010-05-31 18:58:40 +0000
@@ -2,7 +2,7 @@
# ------------------------------------------------------------------
#
+ owner /tmp/** rwkl,
+ owner /tmp/ rw,
-=== modified file 'tests/regression/subdomain/prologue.inc'
+=== 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
+-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"
+-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/subdomain/prologue.inc 2010-04-27 09:37:30 +0000
-@@ -93,8 +93,10 @@
++++ 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
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-03-15 18:31:38 +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
=== modified file 'utils/SubDomain.pm'
--- utils/SubDomain.pm 2010-03-10 23:30:06 +0000
-+++ utils/SubDomain.pm 2010-03-26 13:51:21 +0000
-@@ -6612,10 +6612,14 @@
++++ 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
=== modified file 'utils/apparmor_notify'
--- utils/apparmor_notify 2010-03-10 16:11:26 +0000
-+++ utils/apparmor_notify 2010-05-27 14:08:12 +0000
++++ utils/apparmor_notify 2010-05-31 18:58:40 +0000
@@ -30,8 +30,7 @@
require Time::Local;
require File::Basename;
=== modified file 'utils/apparmor_notify.pod'
--- utils/apparmor_notify.pod 2010-02-12 16:25:02 +0000
-+++ utils/apparmor_notify.pod 2010-05-12 08:46:22 +0000
++++ utils/apparmor_notify.pod 2010-05-31 18:58:40 +0000
@@ -40,24 +40,37 @@
=over 4