-=== added file '.bzrignore'
---- .bzrignore 1970-01-01 00:00:00 +0000
-+++ .bzrignore 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,165 @@
-+parser/po/*.mo
-+parser/af_names.h
-+parser/cap_names.h
-+parser/tst_misc
-+parser/tst_regex
-+parser/tst_symtab
-+parser/tst_variable
-+parser/parser_lex.c
-+parser/parser_version.h
-+parser/parser_yacc.c
-+parser/parser_yacc.h
-+parser/pod2htm*.tmp
-+parser/*.7
-+parser/*.5
-+parser/*.8
-+parser/*.7.html
-+parser/*.5.html
-+parser/*.8.html
-+parser/common
-+parser/apparmor_parser
-+parser/libapparmor_re/regexp.cc
-+parser/techdoc.aux
-+parser/techdoc.log
-+parser/techdoc.pdf
-+parser/techdoc.toc
-+libraries/libapparmor/Makefile
-+libraries/libapparmor/Makefile.in
-+libraries/libapparmor/aclocal.m4
-+libraries/libapparmor/audit.log
-+libraries/libapparmor/autom4te.cache
-+libraries/libapparmor/compile
-+libraries/libapparmor/config.guess
-+libraries/libapparmor/config.log
-+libraries/libapparmor/config.status
-+libraries/libapparmor/config.sub
-+libraries/libapparmor/configure
-+libraries/libapparmor/depcomp
-+libraries/libapparmor/install-sh
-+libraries/libapparmor/libtool
-+libraries/libapparmor/ltmain.sh
-+libraries/libapparmor/missing
-+libraries/libapparmor/ylwrap
-+libraries/libapparmor/doc/Makefile
-+libraries/libapparmor/doc/Makefile.in
-+libraries/libapparmor/doc/aa_change_hat.2
-+libraries/libapparmor/src/.deps
-+libraries/libapparmor/src/.libs
-+libraries/libapparmor/src/Makefile
-+libraries/libapparmor/src/Makefile.in
-+libraries/libapparmor/src/af_protos.h
-+libraries/libapparmor/src/change_hat.lo
-+libraries/libapparmor/src/grammar.lo
-+libraries/libapparmor/src/libaalogparse.lo
-+libraries/libapparmor/src/libimmunix_warning.lo
-+libraries/libapparmor/src/scanner.lo
-+libraries/libapparmor/src/libapparmor.la
-+libraries/libapparmor/src/libimmunix.la
-+libraries/libapparmor/src/grammar.c
-+libraries/libapparmor/src/grammar.h
-+libraries/libapparmor/src/scanner.c
-+libraries/libapparmor/src/scanner.h
-+libraries/libapparmor/src/tst_aalogmisc
-+libraries/libapparmor/swig/Makefile
-+libraries/libapparmor/swig/Makefile.in
-+libraries/libapparmor/swig/perl/LibAppArmor.bs
-+libraries/libapparmor/swig/perl/LibAppArmor.pm
-+libraries/libapparmor/swig/perl/Makefile
-+libraries/libapparmor/swig/perl/Makefile.PL
-+libraries/libapparmor/swig/perl/Makefile.in
-+libraries/libapparmor/swig/perl/Makefile.perl
-+libraries/libapparmor/swig/perl/blib
-+libraries/libapparmor/swig/perl/libapparmor_wrap.c
-+libraries/libapparmor/swig/perl/pm_to_blib
-+libraries/libapparmor/swig/python/Makefile
-+libraries/libapparmor/swig/python/Makefile.in
-+libraries/libapparmor/swig/python/setup.py
-+libraries/libapparmor/swig/ruby/Makefile
-+libraries/libapparmor/swig/ruby/Makefile.in
-+libraries/libapparmor/testsuite/.deps
-+libraries/libapparmor/testsuite/.libs
-+libraries/libapparmor/testsuite/Makefile
-+libraries/libapparmor/testsuite/Makefile.in
-+libraries/libapparmor/testsuite/libaalogparse.log
-+libraries/libapparmor/testsuite/libaalogparse.sum
-+libraries/libapparmor/testsuite/site.exp
-+libraries/libapparmor/testsuite/test_multi.multi
-+libraries/libapparmor/testsuite/config/Makefile
-+libraries/libapparmor/testsuite/config/Makefile.in
-+libraries/libapparmor/testsuite/lib/Makefile
-+libraries/libapparmor/testsuite/lib/Makefile.in
-+libraries/libapparmor/testsuite/libaalogparse.test/Makefile
-+libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
-+libraries/libapparmor/testsuite/test_multi/out
-+changehat/mod_apparmor/.libs
-+changehat/mod_apparmor/common
-+changehat/pam_apparmor/common
-+changehat/tomcat_apparmor/common
-+utils/common
-+utils/*.8
-+utils/*.8.html
-+utils/*.5
-+utils/*.5.html
-+utils/*.tmp
-+utils/po/*.mo
-+tests/regression/apparmor/access
-+tests/regression/apparmor/changehat
-+tests/regression/apparmor/changehat_fail
-+tests/regression/apparmor/changehat_fork
-+tests/regression/apparmor/changehat_misc
-+tests/regression/apparmor/changehat_misc2
-+tests/regression/apparmor/changehat_pthread
-+tests/regression/apparmor/changehat_twice
-+tests/regression/apparmor/changehat_wrapper
-+tests/regression/apparmor/changeprofile
-+tests/regression/apparmor/chdir
-+tests/regression/apparmor/chgrp
-+tests/regression/apparmor/chmod
-+tests/regression/apparmor/chown
-+tests/regression/apparmor/clone
-+tests/regression/apparmor/deleted
-+tests/regression/apparmor/env_check
-+tests/regression/apparmor/environ
-+tests/regression/apparmor/exec
-+tests/regression/apparmor/exec_qual
-+tests/regression/apparmor/exec_qual2
-+tests/regression/apparmor/fchdir
-+tests/regression/apparmor/fchgrp
-+tests/regression/apparmor/fchmod
-+tests/regression/apparmor/fchown
-+tests/regression/apparmor/fork
-+tests/regression/apparmor/link
-+tests/regression/apparmor/link_subset
-+tests/regression/apparmor/mkdir
-+tests/regression/apparmor/mmap
-+tests/regression/apparmor/mount
-+tests/regression/apparmor/named_pipe
-+tests/regression/apparmor/net_raw
-+tests/regression/apparmor/open
-+tests/regression/apparmor/openat
-+tests/regression/apparmor/pipe
-+tests/regression/apparmor/ptrace
-+tests/regression/apparmor/ptrace_helper
-+tests/regression/apparmor/pwrite
-+tests/regression/apparmor/readdir
-+tests/regression/apparmor/rename
-+tests/regression/apparmor/rw
-+tests/regression/apparmor/swap
-+tests/regression/apparmor/symlink
-+tests/regression/apparmor/syscall_chroot
-+tests/regression/apparmor/syscall_mknod
-+tests/regression/apparmor/syscall_mlockall
-+tests/regression/apparmor/syscall_ptrace
-+tests/regression/apparmor/syscall_reboot
-+tests/regression/apparmor/syscall_setdomainname
-+tests/regression/apparmor/syscall_sethostname
-+tests/regression/apparmor/syscall_setpriority
-+tests/regression/apparmor/syscall_setscheduler
-+tests/regression/apparmor/syscall_sysctl
-+tests/regression/apparmor/sysctl_proc
-+tests/regression/apparmor/tcp
-+tests/regression/apparmor/unix_fd_client
-+tests/regression/apparmor/unix_fd_server
-+tests/regression/apparmor/unlink
-+tests/regression/apparmor/xattrs
-+tests/regression/apparmor/coredump
-
-=== added file 'README'
---- README 1970-01-01 00:00:00 +0000
-+++ README 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,155 @@
-+------------
-+Introduction
-+------------
-+AppArmor protects systems from insecure or untrusted processes by
-+running them in restricted confinement, while still allowing processes
-+to share files, exercise privilege and communicate with other processes.
-+AppArmor is a Mandatory Access Control (MAC) mechanism which uses the
-+Linux Security Module (LSM) framework. The confinement's restrictions
-+are mandatory and are not bound to identity, group membership, or object
-+ownership. The protections provided are in addition to the kernel's
-+regular access control mechanisms (including DAC) and can be used to
-+restrict the superuser.
-+
-+The AppArmor kernel module and accompanying user-space tools are
-+available under the GPL license (the exception is the libapparmor
-+library, available under the LGPL license, which allows change_hat(2)
-+and change_profile(2) to be used by non-GPL binaries).
-+
-+For more information, you can read the techdoc.pdf (available after
-+building the parser) and http://apparmor.wiki.kernel.org.
-+
-+
-+-------------
-+Source Layout
-+-------------
-+
-+AppArmor consists of several different parts:
-+
-+changehat/ source for using changehat with Apache, PAM and Tomcat
-+common/ common makefile rules
-+desktop/ empty
-+kernel-patches/ patches for various kernel versions
-+libraries/ libapparmor source and language bindings
-+parser/ source for parser/loader and corresponding documentation
-+profiles/ configuration files, reference profiles and abstractions
-+tests/ regression and stress testsuites
-+utils/ high-level utilities for working with AppArmor
-+
-+
-+------------------------------------------
-+Building and Installing AppArmor Userspace
-+------------------------------------------
-+
-+To build and install AppArmor userspace on your system, build and install in
-+the following order.
-+
-+
-+libapparmor:
-+$ cd ./libraries/libapparmor
-+$ sh ./autogen.sh
-+$ sh ./configure --prefix=/usr --with-perl
-+$ make
-+$ make check
-+
-+
-+Utilities:
-+$ cd utils
-+$ make
-+$ make install
-+
-+
-+parser:
-+$ cd parser
-+$ make
-+$ make tests # not strictly necessary as they are run during the
-+ # build by default
-+$ make install
-+
-+
-+Apache mod_apparmor:
-+$ cd changehat/mod_apparmor
-+$ LIBS="-lapparmor" make
-+$ make install
-+
-+
-+PAM AppArmor:
-+$ cd changehat/pam_apparmor
-+$ LIBS="-lapparmor -lpam" make
-+$ make install
-+
-+
-+Profiles:
-+$ cd profiles
-+$ make
-+$ make install
-+
-+
-+
-+-------------------
-+AppArmor Testsuites
-+-------------------
-+
-+A number of testsuites are in the AppArmor sources. Most have documentation on
-+usage and how to update and add tests. Below is a quick overview of their
-+location and how to run them.
-+
-+
-+Regression tests
-+----------------
-+For details on structure and adding tests, see
-+tests/regression/apparmor/README.
-+
-+To run:
-+$ cd tests/regression/apparmor (requires root)
-+$ make
-+$ sudo make tests
-+$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
-+
-+
-+Parser tests
-+------------
-+For details on structure and adding tests, see parser/tst/README.
-+
-+To run:
-+$ cd parser/tst
-+$ make
-+$ make tests
-+
-+
-+Libapparmor
-+-----------
-+For details on structure and adding tests, see libraries/libapparmor/README.
-+$ cd libraries/libapparmor
-+$ make check
-+
-+
-+Stress Tests
-+------------
-+To run AppArmor stress tests:
-+$ make all
-+
-+Use these:
-+$ ./change_hat
-+$ ./child
-+$ ./kill.sh
-+$ ./open
-+$ ./s.sh
-+
-+Or run all at once:
-+$ ./stress.sh
-+
-+Please note that the above will stress the system so much it may end up
-+invoking the OOM killer.
-+
-+To run parser stress tests (requires /usr/bin/ruby):
-+$ ./stress.sh
-+
-+(see stress.sh -h for options)
-+
-+-----------------------------------------------
-+Building and Installing AppArmor Kernel Patches
-+-----------------------------------------------
-+
-+TODO
-+
-
-=== modified file 'common/Make.rules'
---- common/Make.rules 2010-03-11 07:07:29 +0000
-+++ common/Make.rules 2010-08-03 17:27:13 +0000
-@@ -48,7 +48,7 @@
- echo "/tmp/${NAME}" ; \
- fi ;)
- endif
--RPMHOSTVENDOR=$(shell rpm --eval "%{_host_vendor}")
-+RPMHOSTVENDOR=$(shell which rpm && rpm --eval "%{_host_vendor}")
- ifndef DISTRO
- DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
- echo slackware ; \
-@@ -92,30 +92,16 @@
- ifndef SPECFILE
- SPECFILE = $(NAME).spec
- endif
--RELEASE = $(shell rpm -q --specfile --define "_sourcedir ." ${RPMARG} --qf "%{RELEASE}" ${SPECFILE})
-+RELEASE = $(shell lsb_release -is) $(shell lsb_release -rs)
- RELEASE_DIR = $(NAME)-$(VERSION)
- TARBALL = $(NAME)-$(VERSION)-${REPO_VERSION}.tar.gz
--TAR = /bin/tar czvp -h --exclude .svn --exclude CVS --exclude .cvsignore --exclude ${TARBALL} --exclude ${RELEASE_DIR}/${RELEASE_DIR} $(shell test -f ${NAME}.exclude && echo "-X ${NAME}.exclude")
-+TAR = /bin/tar czvp -h --exclude .svn --exclude .bzr --exclude .bzrignore --exclude ${TARBALL} --exclude ${RELEASE_DIR}/${RELEASE_DIR} $(shell test -f ${NAME}.exclude && echo "-X ${NAME}.exclude")
- LDCONFIG = /sbin/ldconfig
-
--CVSPKG_VERSION=$(shell rpm -q --specfile --define "_sourcedir ." ${RPMARG} ${SPECFILE} | head -1 | tr "." "_")
--
- RPMSUBDIRS=SOURCES SPECS BUILD BUILDROOT SRPMS RPMS/i386 RPMS/i586 \
- RPMS/i686 RPMS/athlon RPMS/noarch RPMS/x86_64
- BUILDRPMSUBDIRS=$(foreach subdir, $(RPMSUBDIRS), $(BUILDDIR:/=)/$(subdir))
-
--.PHONY: cvs_tag
--cvs_tag:
-- cvs tag IMMUNIX-${CVSPKG_VERSION}
--
--.PHONY: checkin
--checkin:
-- if cvs -q up -d | grep -q "^\?" ; then echo "Hey! You have" \
-- "files in the directory you have not added into cvs."; exit 1; \
-- fi
-- cvs ci
-- make cvs_tag
--
- ifdef EXTERNAL_PACKAGE
- .PHONY: rpm
- rpm: clean $(BUILDRPMSUBDIRS)
-
-=== modified file 'libraries/libapparmor/src/aalogparse.h'
---- libraries/libapparmor/src/aalogparse.h 2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/aalogparse.h 2010-08-03 17:27:13 +0000
-@@ -129,6 +129,7 @@
- unsigned long fsuid; /* fsuid of task - if logged */
- unsigned long ouid; /* ouid of task - if logged */
- char *profile; /* The name of the profile */
-+ char *comm; /* Command that triggered msg */
- char *name;
- char *name2;
- char *namespace;
-
-=== modified file 'libraries/libapparmor/src/change_hat.c'
---- libraries/libapparmor/src/change_hat.c 2010-02-11 23:38:24 +0000
-+++ libraries/libapparmor/src/change_hat.c 2010-08-03 17:27:13 +0000
-@@ -194,7 +194,7 @@
- /* setup command string which is of the form
- * changehat <token>^hat1\0hat2\0hat3\0..\0
- */
-- sprintf(buf, "%s %016x^", cmd, token);
-+ sprintf(buf, "%s %016lx^", cmd, token);
- pos = buf + strlen(buf);
- if (subprofiles) {
- for (hats = subprofiles; *hats; hats++) {
-
-=== modified file 'libraries/libapparmor/src/grammar.y'
---- libraries/libapparmor/src/grammar.y 2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/grammar.y 2010-08-03 17:27:13 +0000
-@@ -1,6 +1,7 @@
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010, Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -96,6 +97,13 @@
- %token TOK_TYPE_HINT
- %token TOK_TYPE_STATUS
- %token TOK_TYPE_ERROR
-+%token TOK_TYPE_AA_REJECT
-+%token TOK_TYPE_AA_AUDIT
-+%token TOK_TYPE_AA_COMPLAIN
-+%token TOK_TYPE_AA_HINT
-+%token TOK_TYPE_AA_STATUS
-+%token TOK_TYPE_AA_ERROR
-+%token TOK_TYPE_LSM_AVC
- %token TOK_OLD_TYPE_APPARMOR
- %token TOK_OLD_APPARMOR_REJECT
- %token TOK_OLD_APPARMOR_PERMIT
-@@ -123,6 +131,7 @@
- %token TOK_OLD_FORK
- %token TOK_OLD_CHILD
-
-+%token TOK_KEY_APPARMOR
- %token TOK_KEY_TYPE
- %token TOK_KEY_MSG
- %token TOK_KEY_OPERATION
-@@ -146,6 +155,7 @@
- %token TOK_KEY_ERROR
- %token TOK_KEY_FSUID
- %token TOK_KEY_OUID
-+%token TOK_KEY_COMM
-
- %token TOK_SYSLOG_KERNEL
-
-@@ -168,13 +178,14 @@
- ;
-
- new_syntax:
-- TOK_TYPE_REJECT audit_msg key_list { ret_record->event = AA_RECORD_DENIED; }
-- | TOK_TYPE_AUDIT audit_msg key_list { ret_record->event = AA_RECORD_AUDIT; }
-- | TOK_TYPE_COMPLAIN audit_msg key_list { ret_record->event = AA_RECORD_ALLOWED; }
-- | TOK_TYPE_HINT audit_msg key_list { ret_record->event = AA_RECORD_HINT; }
-- | TOK_TYPE_STATUS audit_msg key_list { ret_record->event = AA_RECORD_STATUS; }
-- | TOK_TYPE_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
-+ TOK_TYPE_AA_REJECT audit_msg key_list { ret_record->event = AA_RECORD_DENIED; }
-+ | TOK_TYPE_AA_AUDIT audit_msg key_list { ret_record->event = AA_RECORD_AUDIT; }
-+ | TOK_TYPE_AA_COMPLAIN audit_msg key_list { ret_record->event = AA_RECORD_ALLOWED; }
-+ | TOK_TYPE_AA_HINT audit_msg key_list { ret_record->event = AA_RECORD_HINT; }
-+ | TOK_TYPE_AA_STATUS audit_msg key_list { ret_record->event = AA_RECORD_STATUS; }
-+ | TOK_TYPE_AA_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
- | TOK_TYPE_UNKNOWN audit_msg key_list { ret_record->event = lookup_aa_event($1); }
-+ | TOK_TYPE_LSM_AVC audit_msg key_list
- ;
-
- other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
-@@ -366,7 +377,8 @@
-
- audit_id: TOK_AUDIT TOK_OPEN_PAREN TOK_AUDIT_DIGITS TOK_PERIOD TOK_AUDIT_DIGITS TOK_COLON TOK_AUDIT_DIGITS TOK_CLOSE_PAREN TOK_COLON
- {
-- asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7);
-+ if (!asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7))
-+ yyerror(scanner, YY_("Out of memory"));
- ret_record->epoch = atol($3);
- ret_record->audit_sub_id = atoi($7);
- free($3);
-@@ -420,6 +432,18 @@
- { ret_record->fsuid = $3;}
- | TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
- { ret_record->ouid = $3;}
-+ | TOK_KEY_COMM TOK_EQUALS TOK_QUOTED_STRING
-+ { ret_record->comm = $3;}
-+ | TOK_KEY_APPARMOR TOK_EQUALS apparmor_event
-+ ;
-+
-+apparmor_event:
-+ TOK_TYPE_REJECT { ret_record->event = AA_RECORD_DENIED; }
-+ | TOK_TYPE_AUDIT { ret_record->event = AA_RECORD_AUDIT; }
-+ | TOK_TYPE_COMPLAIN { ret_record->event = AA_RECORD_ALLOWED; }
-+ | TOK_TYPE_HINT { ret_record->event = AA_RECORD_HINT; }
-+ | TOK_TYPE_STATUS { ret_record->event = AA_RECORD_STATUS; }
-+ | TOK_TYPE_ERROR { ret_record->event = AA_RECORD_ERROR; }
- ;
-
- key_pid: TOK_KEY_PID TOK_EQUALS TOK_DIGITS { ret_record->pid = $3; }
-
-=== modified file 'libraries/libapparmor/src/libaalogparse.c'
---- libraries/libapparmor/src/libaalogparse.c 2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/src/libaalogparse.c 2010-08-03 17:27:13 +0000
-@@ -56,6 +56,8 @@
- free(record->denied_mask);
- if (record->profile != NULL)
- free(record->profile);
-+ if (record->comm != NULL)
-+ free(record->comm);
- if (record->name != NULL)
- free(record->name);
- if (record->name2 != NULL)
-@@ -151,7 +153,8 @@
- if (current->protocol_name) {
- ret = strdup(current->protocol_name);
- } else {
-- asprintf(&ret, "unknown(%u)", proto);
-+ if (!asprintf(&ret, "unknown(%u)", proto))
-+ ret = NULL;
- }
-
- return ret;
-
-=== modified file 'libraries/libapparmor/src/scanner.l'
---- libraries/libapparmor/src/scanner.l 2010-02-10 23:13:55 +0000
-+++ libraries/libapparmor/src/scanner.l 2010-08-03 17:27:13 +0000
-@@ -1,6 +1,7 @@
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010, Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -30,6 +31,8 @@
-
- #include <assert.h>
-
-+#define YY_NO_INPUT
-+
- unsigned int string_buf_alloc = 0;
- unsigned int string_buf_len = 0;
- char *string_buf = NULL;
-@@ -84,12 +87,19 @@
- modes ({mode_chars}+)|({mode_chars}+::{mode_chars}*)|(::{mode_chars}*)
- /* New message types */
-
--reject_type "APPARMOR_DENIED"
--audit_type "APPARMOR_AUDIT"
--complain_type "APPARMOR_ALLOWED"
--hint_type "APPARMOR_HINT"
--status_type "APPARMOR_STATUS"
--error_type "APPARMOR_ERROR"
-+aa_reject_type "APPARMOR_DENIED"
-+aa_audit_type "APPARMOR_AUDIT"
-+aa_complain_type "APPARMOR_ALLOWED"
-+aa_hint_type "APPARMOR_HINT"
-+aa_status_type "APPARMOR_STATUS"
-+aa_error_type "APPARMOR_ERROR"
-+reject_type "\"DENIED\""
-+audit_type "\"AUDIT\""
-+complain_type "\"ALLOWED\""
-+hint_type "\"HINT\""
-+status_type "\"STATUS\""
-+error_type "\"ERROR\""
-+lsm_avc_type "AVC"
- unknown_type UNKNOWN\[{digits}+\]
- other_audit_type [[:alnum:]\[\]_-]+
-
-@@ -125,6 +135,7 @@
-
- /* Key tokens */
-
-+key_apparmor "apparmor"
- key_type "type"
- key_msg "msg"
- key_operation "operation"
-@@ -147,6 +158,7 @@
- key_error "error"
- key_fsuid "fsuid"
- key_ouid "ouid"
-+key_comm "comm"
- audit "audit"
-
- /* syslog tokens */
-@@ -240,6 +252,13 @@
- {hint_type} { BEGIN(INITIAL); return(TOK_TYPE_HINT); }
- {status_type} { BEGIN(INITIAL); return(TOK_TYPE_STATUS); }
- {error_type} { BEGIN(INITIAL); return(TOK_TYPE_ERROR); }
-+ {aa_reject_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_REJECT); }
-+ {aa_audit_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_AUDIT); }
-+ {aa_complain_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_COMPLAIN); }
-+ {aa_hint_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_HINT); }
-+ {aa_status_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_STATUS); }
-+ {aa_error_type} { BEGIN(INITIAL); return(TOK_TYPE_AA_ERROR); }
-+ {lsm_avc_type} { BEGIN(INITIAL); return(TOK_TYPE_LSM_AVC); }
- {unknown_type} { char *yptr = yytext;
- while (*yptr && *yptr != '[')
- yptr++;
-@@ -300,6 +319,7 @@
- {key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
- }
-
-+{key_apparmor} { BEGIN(audit_types); return(TOK_KEY_APPARMOR); }
- {key_type} { BEGIN(audit_types); return(TOK_KEY_TYPE); }
- {key_msg} { return(TOK_KEY_MSG); }
- {key_operation} { return(TOK_KEY_OPERATION); }
-@@ -321,6 +341,7 @@
- {key_error} { return(TOK_KEY_ERROR); }
- {key_fsuid} { return(TOK_KEY_FSUID); }
- {key_ouid} { return(TOK_KEY_OUID); }
-+{key_comm} { return(TOK_KEY_COMM); }
-
- {syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
- {syslog_month} { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
-
-=== modified file 'libraries/libapparmor/swig/perl/Makefile.am'
---- libraries/libapparmor/swig/perl/Makefile.am 2009-05-12 21:56:56 +0000
-+++ libraries/libapparmor/swig/perl/Makefile.am 2010-05-31 18:58:40 +0000
-@@ -1,7 +1,8 @@
- EXTRA_DIST =Makefile.PL libapparmor_wrap.c LibAppArmor.pm examples/*.pl
-+
-+if HAVE_PERL
- noinst_DATA =LibAppArmor.so
-
--if HAVE_PERL
- libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
- $(SWIG) -perl -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
-
-@@ -27,4 +28,4 @@
- #rm -f Makefile.perl Makefile.perl.old
- rm -f *.so # *.o
-
--endif
-\ No newline at end of file
-+endif
-
-=== modified file 'libraries/libapparmor/testsuite/test_multi.c'
---- libraries/libapparmor/testsuite/test_multi.c 2009-09-18 21:13:04 +0000
-+++ libraries/libapparmor/testsuite/test_multi.c 2010-08-03 17:27:13 +0000
-@@ -129,6 +129,10 @@
- {
- printf("Name: %s\n", record->name);
- }
-+ if (record->comm != NULL)
-+ {
-+ printf("Command: %s\n", record->comm);
-+ }
- if (record->name2 != NULL)
- {
- printf("Name2: %s\n", record->name2);
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_01.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_01.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_01.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279948288.415:39): apparmor="DENIED" operation="open" parent=12332 profile="/usr/sbin/cupsd" name="/home/user/.ssh/" pid=12333 comm="ls" requested_mask="r" denied_mask="r" fsuid=0 ouid=1000
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_01.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_01.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_01.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_audit_01.in
-+Event type: AA_RECORD_DENIED
-+Audit ID: 1279948288.415:39
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 0
-+ouid: 1000
-+Profile: /usr/sbin/cupsd
-+Name: /home/user/.ssh/
-+Command: ls
-+Parent: 12332
-+PID: 12333
-+Epoch: 1279948288
-+Audit subid: 39
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_02.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_02.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_02.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279948227.175:27): apparmor="STATUS" operation="profile_replace" name="/sbin/dhclient3" pid=12291 comm="apparmor_parser"
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_02.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_02.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_02.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,10 @@
-+START
-+File: test_multi/avc_audit_02.in
-+Event type: AA_RECORD_STATUS
-+Audit ID: 1279948227.175:27
-+Operation: profile_replace
-+Name: /sbin/dhclient3
-+Command: apparmor_parser
-+PID: 12291
-+Epoch: 1279948227
-+Audit subid: 27
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_03.in'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_03.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_03.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+type=AVC msg=audit(1279968846.035:77): apparmor="ALLOWED" operation="open" parent=7014 profile="/tmp/cat" name="/etc/passwd" pid=21645 comm="cat" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_audit_03.out'
---- libraries/libapparmor/testsuite/test_multi/avc_audit_03.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_audit_03.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_audit_03.in
-+Event type: AA_RECORD_ALLOWED
-+Audit ID: 1279968846.035:77
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 1000
-+ouid: 0
-+Profile: /tmp/cat
-+Name: /etc/passwd
-+Command: cat
-+Parent: 7014
-+PID: 21645
-+Epoch: 1279968846
-+Audit subid: 77
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_01.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:25:33 spriggan kernel: [42416.178567] type=1400 audit(1279967133.365:54): apparmor="DENIED" operation="open" parent=19650 profile="/usr/sbin/cupsd" name="/boot/" pid=19651 comm="ls" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_01.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_syslog_01.in
-+Event type: AA_RECORD_DENIED
-+Audit ID: 1279967133.365:54
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 0
-+ouid: 0
-+Profile: /usr/sbin/cupsd
-+Name: /boot/
-+Command: ls
-+Parent: 19650
-+PID: 19651
-+Epoch: 1279967133
-+Audit subid: 54
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_02.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:24:41 spriggan kernel: [42364.269117] type=1400 audit(1279967081.455:42): apparmor="STATUS" operation="profile_replace" name="/sbin/dhclient3" pid=19610 comm="apparmor_parser"
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_02.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,10 @@
-+START
-+File: test_multi/avc_syslog_02.in
-+Event type: AA_RECORD_STATUS
-+Audit ID: 1279967081.455:42
-+Operation: profile_replace
-+Name: /sbin/dhclient3
-+Command: apparmor_parser
-+PID: 19610
-+Epoch: 1279967081
-+Audit subid: 42
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_03.in 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,1 @@
-+Jul 24 12:54:06 spriggan kernel: [44128.842691] type=1400 audit(1279968846.035:77): apparmor="ALLOWED" operation="open" parent=7014 profile="/tmp/cat" name="/etc/passwd" pid=21645 comm="cat" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
-
-=== added file 'libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out'
---- libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out 1970-01-01 00:00:00 +0000
-+++ libraries/libapparmor/testsuite/test_multi/avc_syslog_03.out 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,16 @@
-+START
-+File: test_multi/avc_syslog_03.in
-+Event type: AA_RECORD_ALLOWED
-+Audit ID: 1279968846.035:77
-+Operation: open
-+Mask: r
-+Denied Mask: r
-+fsuid: 1000
-+ouid: 0
-+Profile: /tmp/cat
-+Name: /etc/passwd
-+Command: cat
-+Parent: 7014
-+PID: 21645
-+Epoch: 1279968846
-+Audit subid: 77
-
-=== modified file 'parser/COPYING.GPL'
---- parser/COPYING.GPL 2006-04-11 21:52:54 +0000
-+++ parser/COPYING.GPL 2010-08-03 17:27:13 +0000
-@@ -1,6 +1,5 @@
- This license applies to all source files within the SubDomain parser
--package, with the exception of md5.c and the files in the pcre/
--subdirectory, as they are covered under their own respective licenses.
-+package.
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
-=== modified file 'parser/Makefile'
---- parser/Makefile 2009-11-11 18:58:57 +0000
-+++ parser/Makefile 2010-08-03 17:27:13 +0000
-@@ -82,9 +82,6 @@
- AAREDIR= libapparmor_re
- AAREOBJECTS = ${AAREDIR}/libapparmor_re.a
-
--PCREDIR= pcre
--PCREOBJECTS = ${PCREDIR}/pcre.o
--
- LEX_C_FILES = parser_lex.c
- YACC_C_FILES = parser_yacc.c parser_yacc.h
-
-@@ -94,7 +91,7 @@
-
- TEST_OBJECTS = $(filter-out parser_lex.o, \
- $(filter-out parser_yacc.o, \
-- $(filter-out parser_main.o, ${OBJECTS} ${PCREOBJECTS})))
-+ $(filter-out parser_main.o, ${OBJECTS})))
-
- ifdef V
- VERBOSE = 1
-@@ -125,14 +122,25 @@
- techdoc.txt: techdoc/index.html
- w3m -dump $< > $@
-
--all: $(TOOLS) $(MANPAGES) ${HTMLMANPAGES} techdoc.pdf
-+# targets arranged this way so that people who don't want full docs can
-+# pick specific targets they want.
-+main: $(TOOLS)
- $(Q)make -C po all
-- $(Q)make -s tests
--
--apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
-+
-+manpages: $(MANPAGES)
-+
-+htmlmanpages: $(HTMLMANPAGES)
-+
-+pdf: techdoc.pdf
-+
-+docs: manpages htmlmanpages pdf
-+
-+all: main docs tests
-+
-+apparmor_parser: $(OBJECTS) $(AAREOBJECTS)
- rm -f ./libstdc++.a
- ln -s `g++ -print-file-name=libstdc++.a`
-- g++ $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(PCREOBJECTS) $(LIBS) \
-+ g++ $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
- ${LEXLIB} $(AAREOBJECTS) -static-libgcc -L.
-
- parser_yacc.c parser_yacc.h: parser_yacc.y parser.h
-@@ -191,7 +199,7 @@
- af_names.h: /usr/include/bits/socket.h
- LC_ALL=C sed -n -e '/$(__FILTER)/d' -e "s/^\#define[ \\t]\\+PF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/#ifndef AF_\\1\\n# define AF_\\1 \\2\\n#endif\\nAA_GEN_NET_ENT(\"\\L\\1\", \\UAF_\\1)\\n/p" $< > $@
- LC_ALL=C sed -n -e "s/^\#define[ \\t]\\+PF_MAX[ \\t]\\+\\([0-9]\\+\\)[ \\t]\\+.*/#define AA_AF_MAX \\1\n/p" $< >> $@
-- cat $@
-+ # cat $@
-
- cap_names.h: /usr/include/linux/capability.h
- LC_ALL=C sed -n -e "/CAP_EMPTY_SET/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9xa-f]\\+\\)\\(.*\\)\$$/\{\"\\L\\1\", \\UCAP_\\1\},/p" $< > $@
-@@ -205,8 +213,8 @@
- tst_misc: parser_misc.c parser.h parser_yacc.h af_names.h cap_names.h
- $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(BUILD_OUTPUT)
-
--tst_regex: parser_regex.c parser.h parser_yacc.h $(PCREOBJECTS)
-- $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(PCREOBJECTS) $(BUILD_OUTPUT)
-+tst_regex: parser_regex.c parser.h parser_yacc.h
-+ $(Q)$(CC) -DUNIT_TEST $(EXTRA_CFLAGS) $(TEST_FLAGS) -o $@ $< $(BUILD_OUTPUT)
-
- .SILENT: check
- .PHONY: check
-@@ -214,7 +222,7 @@
-
- .SILENT: tests
- tests: ${TESTS}
-- for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done
-+ sh -e -c 'for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done'
- $(Q)make -s -C tst tests
-
- .SILENT: check
-@@ -226,11 +234,6 @@
- $(AAREOBJECTS):
- make -C $(AAREDIR)
-
--.SILENT: $(PCREOBJECTS)
--.PHONY: $(PCREOBJECTS)
--$(PCREOBJECTS):
-- make -C $(PCREDIR) "CFLAGS=$(EXTRA_CFLAGS)"
--
- .PHONY: install-rhel4
- install-rhel4: install-redhat
-
-@@ -293,7 +296,6 @@
- rm -f af_names.h
- rm -f cap_names.h
- -rm -rf techdoc.{aux,log,pdf,toc,txt} techdoc/
-- make -s -C $(PCREDIR) clean
- make -s -C $(AAREDIR) clean
- make -s -C po clean
-
-
-=== modified file 'parser/README'
---- parser/README 2007-04-25 20:50:21 +0000
-+++ parser/README 2010-08-03 17:27:13 +0000
-@@ -11,11 +11,6 @@
- where we will attempt to conform to the RFP vulnerability disclosure
- protocol: http://www.wiretrip.net/rfp/policy.html
-
--The parser uses the PCRE (Perl Compatible Regular Expression) engine,
--which was written by Philip Hazel and is copyright by the University
--of Cambridge, England. For more information on the PCRE engine, see
--<ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/>
--
- Thanks.
-
- -- The AppArmor development team
-
-=== modified file 'parser/apparmor_parser.pod'
---- parser/apparmor_parser.pod 2010-01-07 18:03:49 +0000
-+++ parser/apparmor_parser.pod 2010-08-03 17:27:13 +0000
-@@ -80,6 +80,10 @@
-
- Writes a binary (cached) profile to stdout (implies -K and -T).
-
-+=item -o file, --ofile file
-+
-+Writes a binary (cached) profile to the specified file (implies -K and -T)
-+
- =item -b n, --base n
-
- Set the base directory for resolving #include directives
-@@ -149,11 +153,43 @@
-
- Print the version number and exit.
-
-+=item -p, --preprocess
-+
-+Dump the input profile to stdout out applying preprocessing flattening
-+includes into the output profile.
-+
- =item -d, --debug
-
- Given once, only checks the profiles to ensure syntactic correctness.
- Given twice, dumps its interpretation of the profile for checking.
-
-+=item -D n, --dump=n
-+
-+Debug flag for dumping various structures and passes of policy compilation.
-+A single dump flag can be specified per --dump option, but the dump flag
-+can be passed multiple times. Note progress flags tend to also imply
-+the matching stats flag.
-+
-+ apparmor_parser --dump=dfa-stats --dump=trans-stats <file>
-+
-+Use --help=dump to see a full list of which dump flags are supported
-+
-+=item -O n, --optimize=n
-+
-+Set the optimization flags used by policy compilation. A sinlge optimization
-+flag can be toggled per -O option, but the optimize flag can be passed
-+multiple times. Turning off some phases of the optimization can make
-+it so that policy can't complete compilation due to size constraints
-+(it is entirely possible to create a dfa with millions of states that will
-+take days or longer to compile).
-+
-+Note: The parser is set to use a balanced default set of flags, that
-+will result in resonable compression but not take excessive amounts
-+of time to complete.
-+
-+Use --help=optimize to see a full list of which optimization flags are
-+supported.
-+
- =item -h, --help
-
- Give a quick reference guide.
-
-=== modified file 'parser/libapparmor_re/apparmor_re.h'
---- parser/libapparmor_re/apparmor_re.h 2010-01-28 01:20:13 +0000
-+++ parser/libapparmor_re/apparmor_re.h 2010-08-03 17:27:13 +0000
-@@ -35,6 +35,7 @@
- DFA_DUMP_EQUIV_STATS = 1 << 19,
- DFA_DUMP_MINIMIZE = 1 << 20,
- DFA_DUMP_UNREACHABLE = 1 << 22,
-+ DFA_DUMP_RULE_EXPR = 1 << 23,
- } dfaflags_t;
-
- #ifdef __cplusplus
-@@ -48,9 +49,9 @@
- aare_ruleset_t *aare_new_ruleset(int reverse);
- void aare_delete_ruleset(aare_ruleset_t *rules);
- int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
-- uint32_t perms, uint32_t audit);
-+ uint32_t perms, uint32_t audit, dfaflags_t flags);
- int aare_add_rule_vec(aare_ruleset_t *rules, int deny, uint32_t perms,
-- uint32_t audit, int count, char **rulev);
-+ uint32_t audit, int count, char **rulev, dfaflags_t flags);
- void *aare_create_dfa(aare_ruleset_t *rules, size_t *size, dfaflags_t flags);
- void aare_reset_matchflags(void);
-
-
-=== modified file 'parser/libapparmor_re/regexp.y'
---- parser/libapparmor_re/regexp.y 2010-02-01 07:21:00 +0000
-+++ parser/libapparmor_re/regexp.y 2010-08-03 17:27:13 +0000
-@@ -102,6 +102,7 @@
- /* child 0 is left, child 1 is right */
- Node *child[2];
-
-+ unsigned int label; /* unique number for debug etc */
- /**
- * We need reference counting for AcceptNodes: sharing AcceptNodes
- * avoids introducing duplicate States with identical accept values.
-@@ -1208,12 +1209,11 @@
- * Assign a consecutive number to each node. This is only needed for
- * pretty-printing the debug output.
- */
--map<Node *, int> node_label;
- void label_nodes(Node *root)
- {
- int nodes = 0;
- for (depth_first_traversal i(root); i; i++)
-- node_label.insert(make_pair(*i, nodes++));
-+ i->label = nodes++;
- }
-
- /**
-@@ -1225,7 +1225,7 @@
- if (!state.empty()) {
- State::iterator i = state.begin();
- for(;;) {
-- os << node_label[*i];
-+ os << (*i)->label;
- if (++i == state.end())
- break;
- os << ',';
-@@ -1240,15 +1240,15 @@
- */
- void dump_syntax_tree(ostream& os, Node *node) {
- for (depth_first_traversal i(node); i; i++) {
-- os << node_label[*i] << '\t';
-+ os << i->label << '\t';
- if ((*i)->child[0] == 0)
- os << **i << '\t' << (*i)->followpos << endl;
- else {
- if ((*i)->child[1] == 0)
-- os << node_label[(*i)->child[0]] << **i;
-+ os << (*i)->child[0]->label << **i;
- else
-- os << node_label[(*i)->child[0]] << **i
-- << node_label[(*i)->child[1]];
-+ os << (*i)->child[0]->label << **i
-+ << (*i)->child[1]->label;
- os << '\t' << (*i)->firstpos
- << (*i)->lastpos << endl;
- }
-@@ -1256,22 +1256,17 @@
- os << endl;
- }
-
--/* Comparison operator for sets of <State *>. */
--template<class T>
--class deref_less_than {
--public:
-- deref_less_than() { }
-- bool operator()(T a, T b)
-- {
-- return *a < *b;
-- }
-+/* Comparison operator for sets of <State *>.
-+ * Do compare pointer comparisom on set of <Node *>, the pointer comparison
-+ * allows us to determine which Sets of <Node *> we have seen already from
-+ * new ones when constructing the DFA.
-+ */
-+struct deref_less_than {
-+ bool operator()(State * const & lhs, State * const & rhs) const
-+ { return *lhs < *rhs; }
- };
-
--/**
-- * States in the DFA. The pointer comparison allows us to tell sets we
-- * have seen already from new ones when constructing the DFA.
-- */
--typedef set<State *, deref_less_than<State *> > States;
-+typedef set<State *, deref_less_than > States;
- typedef list<State *> Partition;
- /* Transitions in the DFA. */
- typedef map<State *, Cases> Trans;
-@@ -1370,6 +1365,13 @@
- here.cases.insert(*j);
- }
- }
-+
-+ for (depth_first_traversal i(root); i; i++) {
-+ (*i)->firstpos.clear();
-+ (*i)->lastpos.clear();
-+ (*i)->followpos.clear();
-+ }
-+
- if (flags & (DFA_DUMP_STATS))
- fprintf(stderr, "\033[2KCreated dfa: states %ld\tmatching %d\tnonmatching %d\n", states.size(), match_count, nomatch_count);
-
-@@ -1715,7 +1717,9 @@
- Trans::iterator j = trans.find(*i);
- if (j != trans.end())
- trans.erase(j);
-+ State *s = *i;
- states.erase(*i);
-+ delete(s);
- }
- }
-
-@@ -2097,24 +2101,11 @@
- /* if it overflows the next_check array it fits in as we will
- * resize */
- if (c >= next_check.size())
-- goto resize;
-+ return true;
- if (next_check[c].second)
- return false;
- }
-- return true;
-
--resize:
-- next_check.resize(base + cases.cases.rbegin()->first + 1);
-- size_t prev = pos;
-- size_t x = pos;
-- /* find last free list entry */
-- while (x) {
-- prev = x;
-- x = free_list[x].second;
-- }
-- x = free_list. size();
-- free_list.resize(base + cases.cases.rbegin()->first + 1);
-- init_free_list(free_list, prev, x);
- return true;
- }
-
-@@ -2126,6 +2117,7 @@
- {
- State *default_state = dfa.nonmatching;
- size_t base = 0;
-+ int resize;
-
- Trans::iterator i = dfa.trans.find(from);
- if (i == dfa.trans.end()) {
-@@ -2142,6 +2134,7 @@
- goto do_insert;
-
- repeat:
-+ resize = 0;
- /* get the first free entry that won't underflow */
- while (x && (x < c)) {
- prev = x;
-@@ -2154,15 +2147,24 @@
- x = free_list[x].second;
- }
- if (!x) {
-+ resize = 256 - cases.begin()->first;
-+ x = free_list.size();
-+ /* set prev to last free */
-+ } else if (x + 255 - cases.begin()->first >= next_check.size()) {
-+ resize = (255 - cases.begin()->first - (next_check.size() - 1 - x));
-+ for (size_t y = x; y; y = free_list[y].second)
-+ prev = y;
-+ }
-+ if (resize) {
- /* expand next_check and free_list */
-- x = free_list.size();
-- size_t range = cases.cases.rbegin()->first - cases.begin()->first + 1;
-- next_check.resize(next_check.size() + range);
-- free_list.resize(free_list.size() + range);
-- init_free_list(free_list, prev, x);
-+ size_t old_size = free_list.size();
-+ next_check.resize(next_check.size() + resize);
-+ free_list.resize(free_list.size() + resize);
-+ init_free_list(free_list, prev, old_size);
- if (!first_free)
-- first_free = x;
-- goto repeat;
-+ first_free = old_size;;
-+ if (x == old_size)
-+ goto repeat;
- }
-
- base = x - c;
-@@ -2194,8 +2196,9 @@
- st.insert(make_pair(i->second, i->first));
- }
-
-- os << "(accept, default, base):" << endl;
-+ os << "size=" << default_base.size() << " (accept, default, base): {state} -> {default state}" << endl;
- for (size_t i = 0; i < default_base.size(); i++) {
-+ os << i << ": ";
- os << "(" << accept[i] << ", "
- << num[default_base[i].first] << ", "
- << default_base[i].second << ")";
-@@ -2206,7 +2209,7 @@
- os << endl;
- }
-
-- os << "(next, check):" << endl;
-+ os << "size=" << next_check.size() << " (next, check): {check state} -> {next state} : offset from base" << endl;
- for (size_t i = 0; i < next_check.size(); i++) {
- if (!next_check[i].second)
- continue;
-@@ -2565,9 +2568,9 @@
- }
-
- extern "C" int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny,
-- uint32_t perms, uint32_t audit)
-+ uint32_t perms, uint32_t audit, dfaflags_t flags)
- {
-- return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule);
-+ return aare_add_rule_vec(rules, deny, perms, audit, 1, &rule, flags);
- }
-
- #define FLAGS_WIDTH 2
-@@ -2598,7 +2601,8 @@
-
- extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
- uint32_t perms, uint32_t audit,
-- int count, char **rulev)
-+ int count, char **rulev,
-+ dfaflags_t flags)
- {
- Node *tree = NULL, *accept;
- int exact_match;
-@@ -2715,6 +2719,18 @@
- }
- }
-
-+ if (flags & DFA_DUMP_RULE_EXPR) {
-+ cerr << "rule: ";
-+ cerr << rulev[0];
-+ for (int i = 1; i < count; i++) {
-+ cerr << "\\x00";
-+ cerr << rulev[i];
-+ }
-+ cerr << " -> ";
-+ tree->dump(cerr);
-+ cerr << "\n\n";
-+ }
-+
- if (rules->root)
- rules->root = new AltNode(rules->root, new CatNode(tree, accept));
- else
-
-=== modified file 'parser/parser.h'
---- parser/parser.h 2010-02-17 20:21:52 +0000
-+++ parser/parser.h 2010-08-03 17:27:13 +0000
-@@ -4,6 +4,9 @@
- * Copyright (c) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
- *
-+ * Copyright (c) 2010
-+ * Canonical, Ltd. (All rights reserved)
-+ *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License published by the Free Software Foundation.
-@@ -14,12 +17,12 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Novell, Inc. or Canonical
-+ * Ltd.
- */
-
- #include <netinet/in.h>
- #include <sys/resource.h>
--#include "pcre/internal.h"
- #include "immunix.h"
- #include "libapparmor_re/apparmor_re.h"
-
-@@ -40,7 +43,6 @@
-
- struct cod_pattern {
- char *regex; // posix regex
-- pcre *compiled; // compiled regex, size is compiled->size
- };
-
- struct cod_entry {
-@@ -168,17 +170,20 @@
- #define OPTION_REMOVE 2
- #define OPTION_REPLACE 3
- #define OPTION_STDOUT 4
-+#define OPTION_OFILE 5
-
- #define AARE_NONE 0
--#define AARE_PCRE 1
- #define AARE_DFA 2
-
-+#define BOOL int
-+
- #define FLAG_CHANGEHAT_1_4 2
- #define FLAG_CHANGEHAT_1_5 3
- extern int flag_changehat_version;
- extern int read_implies_exec;
- extern dfaflags_t dfaflags;
--
-+extern int preprocess_only;
-+extern FILE *ofile;
-
- #define PATH_CHROOT_REL 0x1
- #define PATH_NS_REL 0x2
-@@ -280,12 +285,16 @@
- extern void free_cod_entries(struct cod_entry *list);
-
- /* parser_symtab.c */
-+struct set_value {;
-+ char *val;
-+ struct set_value *next;
-+};
- extern int add_boolean_var(const char *var, int boolean);
- extern int get_boolean_var(const char *var);
- extern int new_set_var(const char *var, const char *value);
- extern int add_set_value(const char *var, const char *value);
--extern void *get_set_var(const char *var);
--extern char *get_next_set_value(void **context);
-+extern struct set_value *get_set_var(const char *var);
-+extern char *get_next_set_value(struct set_value **context);
- extern void dump_symtab(void);
- extern void dump_expanded_symtab(void);
- void free_symtabs(void);
-@@ -312,7 +321,7 @@
- extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
- extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
- extern void post_process_nt_entries(struct codomain *cod);
--extern int post_process_policy(void);
-+extern int post_process_policy(int debug_only);
- extern int process_hat_regex(struct codomain *cod);
- extern int process_hat_variables(struct codomain *cod);
- extern int post_merge_rules(void);
-
-=== modified file 'parser/parser_include.c'
---- parser/parser_include.c 2009-07-24 12:18:12 +0000
-+++ parser/parser_include.c 2010-08-03 17:27:13 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010
-+ * Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -14,7 +14,7 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Canonical, Ltd.
- */
-
- /* Handle subdomain includes, as a straight forward preprocessing phase.
-@@ -270,3 +270,63 @@
- *s = 0;
- return c;
- }
-+
-+struct include_stack_t {
-+ char *filename;
-+ int lineno;
-+ struct include_stack_t *next;
-+};
-+
-+struct include_stack_t *include_stack_head = NULL;
-+
-+static void start_include_position(char *filename)
-+{
-+ if (current_filename)
-+ free(current_filename);
-+ current_filename = strdup(filename ? filename : "stdin");
-+ current_lineno = 1;
-+}
-+
-+void push_include_stack(char *filename)
-+{
-+ struct include_stack_t *include = NULL;
-+
-+ include = malloc(sizeof(*include));
-+ if (!include) {
-+ perror("malloc of included file stack tracker");
-+ /* failures in this area are non-fatal */
-+ return;
-+ }
-+
-+ include->filename = strdup(current_filename);
-+ include->lineno = current_lineno;
-+ include->next = include_stack_head;
-+ include_stack_head = include;
-+
-+ start_include_position(filename);
-+}
-+
-+void pop_include_stack(void)
-+{
-+ struct include_stack_t *include = NULL;
-+
-+ if (!include_stack_head)
-+ return;
-+
-+ include = include_stack_head;
-+ include_stack_head = include->next;
-+
-+ if (current_filename)
-+ free(current_filename);
-+ current_filename = include->filename;
-+ current_lineno = include->lineno;
-+ free(include);
-+}
-+
-+void reset_include_stack(char *filename)
-+{
-+ while (include_stack_head)
-+ pop_include_stack();
-+
-+ start_include_position(filename);
-+}
-
-=== modified file 'parser/parser_include.h'
---- parser/parser_include.h 2009-07-24 07:35:39 +0000
-+++ parser/parser_include.h 2010-06-05 06:11:20 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010
-+ * Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -14,13 +14,15 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Canonical, Ltd.
- */
-
- #ifndef PARSER_INCLUDE_H
- #define PARSER_INCLUDE_H
-
- extern int preprocess_only;
-+extern int current_lineno;
-+extern char *current_filename;
-
- extern int add_search_dir(char *dir);
- extern void init_base_dir(void);
-@@ -29,4 +31,8 @@
- extern int do_include_preprocessing(char *profilename);
- FILE *search_path(char *filename, char **fullpath);
-
-+extern void push_include_stack(char *filename);
-+extern void pop_include_stack(void);
-+extern void reset_include_stack(char *filename);
-+
- #endif
-
-=== modified file 'parser/parser_interface.c'
---- parser/parser_interface.c 2010-03-09 09:38:12 +0000
-+++ parser/parser_interface.c 2010-08-03 17:27:13 +0000
-@@ -133,6 +133,9 @@
- PERROR(_("%s: Unable to write to stdout\n"),
- progname);
- break;
-+ case OPTION_OFILE:
-+ PERROR(_("%s: Unable to write to output file\n"),
-+ progname);
- default:
- PERROR(_("%s: ASSERT: Invalid option: %d\n"),
- progname, option);
-@@ -155,6 +158,7 @@
- cod->name);
- break;
- case OPTION_STDOUT:
-+ case OPTION_OFILE:
- break;
- default:
- PERROR(_("%s: ASSERT: Invalid option: %d\n"),
-@@ -451,57 +455,6 @@
- return 1;
- }
-
--int sd_serialize_pattern(sd_serialize *p, pcre *pat)
--{
-- if (!sd_write_struct(p, "pcre"))
-- return 0;
-- if (!sd_write32(p, pat->size - sizeof(pcre)))
-- return 0;
-- if (!sd_write32(p, pat->magic_number))
-- return 0;
-- if (!sd_write32(p, pat->options))
-- return 0;
-- if (!sd_write16(p, pat->top_bracket))
-- return 0;
-- if (!sd_write16(p, pat->top_backref))
-- return 0;
-- if (!sd_write8(p, pat->first_char))
-- return 0;
-- if (!sd_write8(p, pat->req_char))
-- return 0;
-- if (!sd_write8(p, pat->code[0]))
-- return 0;
-- if (!sd_write_blob(p, &pat->code[1], pat->size - sizeof(pcre), NULL))
-- return 0;
-- if (!sd_write_structend(p))
-- return 0;
--
-- return 1;
--}
--
--int sd_serialize_file_entry(sd_serialize *p, struct cod_entry *file_entry)
--{
-- PDEBUG("Writing file entry. name '%s'\n", file_entry->name);
-- if (!sd_write_struct(p, "fe"))
-- return 0;
-- if (!sd_write_string(p, file_entry->name, NULL))
-- return 0;
-- if (!sd_write32(p, file_entry->mode))
-- return 0;
-- if (!sd_write32(p, file_entry->pattern_type))
-- return 0;
-- if (file_entry->pattern_type == ePatternRegex) {
-- if (!sd_write_string(p, file_entry->pat.regex, NULL))
-- return 0;
-- if (!sd_serialize_pattern(p, file_entry->pat.compiled))
-- return 0;
-- }
-- if (!sd_write_structend(p))
-- return 0;
--
-- return 1;
--}
--
- int sd_serialize_dfa(sd_serialize *p, void *dfa, size_t size)
- {
- if (dfa && !sd_write_aligned_blob(p, dfa, size, "aadfa"))
-@@ -594,18 +547,6 @@
- return count;
- }
-
--int count_pcre_ents(struct cod_entry *list)
--{
-- struct cod_entry *entry;
-- int count = 0;
-- list_for_each(list, entry) {
-- if (entry->pattern_type == ePatternRegex) {
-- count++;
-- }
-- }
-- return count;
--}
--
- int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
- int flattened)
- {
-@@ -724,47 +665,8 @@
- if (!sd_serialize_xtable(p, profile->exec_table))
- return 0;
- } else {
-- /* pcre globbing entries */
-- if (count_pcre_ents(profile->entries)) {
-- if (!sd_write_list(p, "pgent"))
-- return 0;
-- list_for_each(profile->entries, entry) {
-- if (entry->pattern_type == ePatternRegex) {
-- if (!sd_serialize_file_entry(p, entry))
-- return 0;
-- }
-- }
-- if (!sd_write_listend(p))
-- return 0;
-- }
--
-- /* simple globbing entries */
-- if (count_tailglob_ents(profile->entries)) {
-- if (!sd_write_list(p, "sgent"))
-- return 0;
-- list_for_each(profile->entries, entry) {
-- if (entry->pattern_type == ePatternTailGlob) {
-- if (!sd_serialize_file_entry(p, entry))
-- return 0;
-- }
-- }
-- if (!sd_write_listend(p))
-- return 0;
-- }
--
-- /* basic file entries */
-- if (count_file_ents(profile->entries)) {
-- if (!sd_write_list(p, "fent"))
-- return 0;
-- list_for_each(profile->entries, entry) {
-- if (entry->pattern_type == ePatternBasic) {
-- if (!sd_serialize_file_entry(p, entry))
-- return 0;
-- }
-- }
-- if (!sd_write_listend(p))
-- return 0;
-- }
-+ PERROR(_("Unknown pattern type\n"));
-+ return 1;
- }
-
- if (profile->hat_table && regex_type != AARE_DFA) {
-@@ -812,7 +714,7 @@
- int cache_fd = -1;
- int sd_serialize_codomain(int option, struct codomain *cod)
- {
-- int fd;
-+ int fd = -1;
- int error = -ENOMEM, size, wsize;
- sd_serialize *work_area;
- char *filename = NULL;
-@@ -837,22 +739,29 @@
- filename = "stdout";
- fd = dup(1);
- break;
-+ case OPTION_OFILE:
-+ fd = dup(fileno(ofile));
-+ break;
- default:
- error = -EINVAL;
- goto exit;
- break;
- }
-
-- if (kernel_load && fd < 0) {
-- PERROR(_("Unable to open %s - %s\n"), filename,
-- strerror(errno));
-+ if (fd < 0) {
-+ if (kernel_load)
-+ PERROR(_("Unable to open %s - %s\n"), filename,
-+ strerror(errno));
-+ else
-+ PERROR(_("Unable to open output file - %s\n"),
-+ strerror(errno));
- error = -errno;
- goto exit;
- }
-
- error = 0;
-
-- if (option != OPTION_STDOUT)
-+ if (option != OPTION_STDOUT && option != OPTION_OFILE)
- free(filename);
-
- if (option == OPTION_REMOVE) {
-@@ -918,7 +827,7 @@
- }
-
- size = work_area->pos - work_area->buffer;
-- if (kernel_load || option == OPTION_STDOUT) {
-+ if (kernel_load || option == OPTION_STDOUT || option == OPTION_OFILE) {
- wsize = write(fd, work_area->buffer, size);
- if (wsize < 0) {
- error = -errno;
-@@ -941,7 +850,7 @@
- free_sd_serial(work_area);
- }
-
-- if (kernel_load) close(fd);
-+ close(fd);
-
- if (cod->hat_table && regex_type == AARE_DFA && option != OPTION_REMOVE) {
- if (load_flattened_hats(cod) != 0)
-@@ -973,7 +882,7 @@
-
- int sd_load_buffer(int option, char *buffer, int size)
- {
-- int fd;
-+ int fd = -1;
- int error = -ENOMEM, wsize, bsize;
- char *filename = NULL;
- char *b;
-
-=== modified file 'parser/parser_lex.l'
---- parser/parser_lex.l 2010-03-09 05:49:16 +0000
-+++ parser/parser_lex.l 2010-08-03 17:27:13 +0000
-@@ -1,8 +1,8 @@
--/* $Id$ */
--
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010
-+ * Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -14,7 +14,7 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Canonical, Ltd.
- */
-
- /* Definitions section */
-@@ -49,7 +49,12 @@
- #endif
- #define NPDEBUG(fmt, args...) /* Do nothing */
-
--int current_lineno = 1;
-+#define DUMP_PREPROCESS do { if (preprocess_only) ECHO; } while (0)
-+
-+#define YY_NO_INPUT
-+
-+int current_lineno = 1;
-+char *current_filename = NULL;
-
- struct ignored_suffix_t {
- char * text;
-@@ -80,14 +85,19 @@
- char *fullpath = NULL;
-
- if (search) {
-+ if (preprocess_only)
-+ fprintf(yyout, "\n\n##included <%s>\n", filename);
- include_file = search_path(filename, &fullpath);
- } else {
-+ if (preprocess_only)
-+ fprintf(yyout, "\n\n##included \"%s\"\n", filename);
- fullpath = strdup(filename);
- include_file = fopen(fullpath, "r");
- }
-
- if (!include_file)
-- yyerror(_("Could not open '%s'"), fullpath);
-+ yyerror(_("Could not open '%s'"),
-+ fullpath ? fullpath: filename);
-
- if (fstat(fileno(include_file), &my_stat))
- yyerror(_("fstat failed for '%s'"), fullpath);
-@@ -95,6 +105,7 @@
- if (S_ISREG(my_stat.st_mode)) {
- yyin = include_file;
- PDEBUG("Opened include \"%s\"\n", fullpath);
-+ push_include_stack(fullpath);
- yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
- }
-
-@@ -139,8 +150,9 @@
- yyerror(_("stat failed for '%s'"), dirent_path);
- if (S_ISREG(my_stat.st_mode)) {
- if (!(yyin = fopen(dirent_path,"r")))
-- yyerror(_("Could not open '%s'"), filename);
-- PDEBUG("Opened include \"%s\"\n", filename);
-+ yyerror(_("Could not open '%s' in '%s'"), dirent_path, filename);
-+ PDEBUG("Opened include \"%s\" in \"%s\"\n", dirent_path, filename);
-+ push_include_stack(dirent_path);
- yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
- }
- }
-@@ -227,6 +239,8 @@
- }
-
- <<EOF>> {
-+ fclose(yyin);
-+ pop_include_stack();
- yypop_buffer_state();
- if ( !YY_CURRENT_BUFFER ) yyterminate();
- }
-@@ -240,6 +254,7 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processunquoted(yytext, yyleng);
- PDEBUG("Found sub name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
-@@ -253,6 +268,7 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processquoted(yytext, yyleng);
- PDEBUG("Found sub name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
-@@ -260,6 +276,7 @@
- }
-
- [^\n] {
-+ DUMP_PREPROCESS;
- /* Something we didn't expect */
- yyerror(_("Found unexpected character: '%s'"), yytext);
- }
-@@ -274,6 +291,7 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processunquoted(yytext, yyleng);
- PDEBUG("Found sub name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
-@@ -287,14 +305,16 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processquoted(yytext, yyleng);
- PDEBUG("Found sub name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
- return TOK_ID;
- }
-
-- {WS}+ { /* Ignoring whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
- [^\n] {
-+ DUMP_PREPROCESS;
- /* Something we didn't expect */
- yyerror(_("Found unexpected character: '%s'"), yytext);
- }
-@@ -302,85 +322,99 @@
-
- <FLAGS_MODE>{
- {FLAGOPEN_PAREN} {
-+ DUMP_PREPROCESS;
- PDEBUG("FLag (\n");
- return TOK_FLAG_OPENPAREN;
- }
- {FLAGCLOSE_PAREN} {
-+ DUMP_PREPROCESS;
- PDEBUG("Flag )\n");
- BEGIN(INITIAL);
- return TOK_FLAG_CLOSEPAREN;
- }
-
-- {WS}+ { /* Eat whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
-
- {FLAGSEP} {
-+ DUMP_PREPROCESS;
- PDEBUG("Flag , \n");
- return TOK_FLAG_SEP;
- }
-
- {EQUALS} {
-+ DUMP_PREPROCESS;
- PDEBUG("Flag = \n");
- return TOK_EQUALS;
- }
- {KEYWORD} {
-+ DUMP_PREPROCESS;
- yylval.flag_id = strdup(yytext);
- PDEBUG("Found flag: \"%s\"\n", yylval.flag_id);
- return TOK_FLAG_ID;
- }
-
- [^\n] {
-+ DUMP_PREPROCESS;
- /* Something we didn't expect */
- yyerror(_("Found unexpected character: '%s'"), yytext);
- }
- }
-
- <ASSIGN_MODE>{
-- {WS}+ { /* Eat whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
-
- {ID}+ {
-+ DUMP_PREPROCESS;
- yylval.var_val = processunquoted(yytext, yyleng);
- PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
- return TOK_VALUE;
- }
-
- {QUOTED_ID} {
-+ DUMP_PREPROCESS;
- yylval.var_val = processquoted(yytext, yyleng);
- PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
- return TOK_VALUE;
- }
-
-- \\\n { current_lineno++ ; }
-+ \\\n { DUMP_PREPROCESS; current_lineno++ ; }
-
- \r?\n {
-+ DUMP_PREPROCESS;
- current_lineno++;
- BEGIN(INITIAL);
- }
- }
-
- <NETWORK_MODE>{
-- {WS}+ { /* Eat whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
-
- {ID}+ {
-+ DUMP_PREPROCESS;
- yylval.id = strdup(yytext);
- return TOK_ID;
- }
- {END_OF_RULE} {
-+ DUMP_PREPROCESS;
- BEGIN(INITIAL);
- return TOK_END_OF_RULE;
- }
- [^\n] {
-+ DUMP_PREPROCESS;
- /* Something we didn't expect */
- yylval.id = strdup(yytext);
- yyerror(_("(network_mode) Found unexpected character: '%s'"), yylval.id);
- }
-
- \r?\n {
-+ DUMP_PREPROCESS;
- current_lineno++;
- }
- }
-
- <CHANGE_PROFILE_MODE>{
- {ARROW} {
-+ DUMP_PREPROCESS;
- PDEBUG("Matched a change profile arrow\n");
- return TOK_ARROW;
- }
-@@ -393,6 +427,7 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processunquoted(yytext, yyleng);
- PDEBUG("Found change profile name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
-@@ -406,14 +441,16 @@
- * a longer match). So now, when I want to
- * match any random string, I go into a
- * separate state. */
-+ DUMP_PREPROCESS;
- yylval.id = processquoted(yytext, yyleng);
- PDEBUG("Found change profile quoted name: \"%s\"\n", yylval.id);
- BEGIN(INITIAL);
- return TOK_ID;
- }
-
-- {WS}+ { /* Ignoring whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
- [^\n] {
-+ DUMP_PREPROCESS;
- /* Something we didn't expect */
- yyerror(_("Found unexpected character: '%s'"), yytext);
- }
-@@ -421,127 +458,147 @@
-
- #include/.*\r?\n { /* include */
- PDEBUG("Matched #include\n");
-- current_lineno++;
- BEGIN(INCLUDE);
- }
-
- #.*\r?\n { /* normal comment */
-+ DUMP_PREPROCESS;
- PDEBUG("comment(%d): %s\n", current_lineno, yytext);
- current_lineno++;
- BEGIN(INITIAL);
- }
-
--{END_OF_RULE} { return TOK_END_OF_RULE; }
-+{END_OF_RULE} { DUMP_PREPROCESS; return TOK_END_OF_RULE; }
-
- {SEPARATOR} {
-+ DUMP_PREPROCESS;
- PDEBUG("Matched a separator\n");
- BEGIN(SUB_NAME);
- return TOK_SEP;
- }
- {ARROW} {
-+ DUMP_PREPROCESS;
- PDEBUG("Matched a arrow\n");
- return TOK_ARROW;
- }
- {EQUALS} {
-+ DUMP_PREPROCESS;
- PDEBUG("Matched equals for assignment\n");
- BEGIN(ASSIGN_MODE);
- return TOK_EQUALS;
- }
- {ADD_ASSIGN} {
-+ DUMP_PREPROCESS;
- PDEBUG("Matched additive value assignment\n");
- BEGIN(ASSIGN_MODE);
- return TOK_ADD_ASSIGN;
- }
- <RLIMIT_MODE>{
-- {WS}+ { /* Eat whitespace */ }
-+ {WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
-
-
- -?{NUMBER}[kKMG]? {
-+ DUMP_PREPROCESS;
- yylval.var_val = strdup(yytext);
- return TOK_VALUE;
- }
-
- {KEYWORD} {
-+ DUMP_PREPROCESS;
- yylval.id = strdup(yytext);
- if (strcmp(yytext, "infinity") == 0)
- return TOK_VALUE;
- return TOK_ID;
- }
-
-- {LT_EQUAL} { return TOK_LE; }
-+ {LT_EQUAL} { DUMP_PREPROCESS; return TOK_LE; }
-
- {END_OF_RULE} {
-+ DUMP_PREPROCESS;
- BEGIN(INITIAL);
- return TOK_END_OF_RULE;
- }
-
- \\\n {
-+ DUMP_PREPROCESS;
- current_lineno++;
- BEGIN(INITIAL);
- }
-
- \r?\n {
-+ DUMP_PREPROCESS;
- current_lineno++;
- BEGIN(INITIAL);
- }
- }
-
- {SET_VARIABLE} {
-+ DUMP_PREPROCESS;
- yylval.set_var = strdup(yytext);
- PDEBUG("Found set variable %s\n", yylval.set_var);
- return TOK_SET_VAR;
- }
-
- {BOOL_VARIABLE} {
-+ DUMP_PREPROCESS;
- yylval.bool_var = strdup(yytext);
- PDEBUG("Found boolean variable %s\n", yylval.bool_var);
- return TOK_BOOL_VAR;
- }
-
- {OPEN_BRACE} {
-+ DUMP_PREPROCESS;
- PDEBUG("Open Brace\n");
- return TOK_OPEN;
- }
- {CLOSE_BRACE} {
-+ DUMP_PREPROCESS;
- PDEBUG("Close Brace\n");
- return TOK_CLOSE;
- }
-
- {PATHNAME} {
-+ DUMP_PREPROCESS;
- yylval.id = processunquoted(yytext, yyleng);
- PDEBUG("Found id: \"%s\"\n", yylval.id);
- return TOK_ID;
- }
-
- {QPATHNAME} {
-+ DUMP_PREPROCESS;
- yylval.id = processquoted(yytext, yyleng);
- PDEBUG("Found id: \"%s\"\n", yylval.id);
- return TOK_ID;
- }
-
- {MODES} {
-+ DUMP_PREPROCESS;
- yylval.mode = strdup(yytext);
- PDEBUG("Found modes: %s\n", yylval.mode);
- return TOK_MODE;
- }
-
- {HAT} {
-+ DUMP_PREPROCESS;
- BEGIN(SUB_NAME2);
- return TOK_HAT;
- }
-
- {COLON} {
-+ DUMP_PREPROCESS;
- PDEBUG("Found a colon\n");
- return TOK_COLON;
- }
-
- {FLAGOPEN_PAREN} {
-+ DUMP_PREPROCESS;
- PDEBUG("FLag (\n");
- BEGIN(FLAGS_MODE);
- return TOK_FLAG_OPENPAREN;
- }
-
- {VARIABLE_NAME} {
-+ DUMP_PREPROCESS;
- int token = get_keyword_token(yytext);
-
- /* special cases */
-@@ -573,11 +630,13 @@
- return token;
- }
-
--{WS}+ { /* Ignoring whitespace */ }
-+{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
-
--\r?\n { current_lineno++ ; }
-+\r?\n { DUMP_PREPROCESS; current_lineno++ ; }
-
- [^\n] {
-+ DUMP_PREPROCESS;
-+
- /* Something we didn't expect */
- yyerror(_("Found unexpected character: '%s'"), yytext);
- }
-
-=== modified file 'parser/parser_main.c'
---- parser/parser_main.c 2010-01-28 01:20:13 +0000
-+++ parser/parser_main.c 2010-08-03 17:27:13 +0000
-@@ -4,6 +4,9 @@
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
- *
-+ * Copyright (c) 2010
-+ * Canonical, Ltd. (All rights reserved)
-+ *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License published by the Free Software Foundation.
-@@ -14,7 +17,8 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Novell, Inc. or Canonical,
-+ * Ltd.
- */
-
- #include <stdio.h>
-@@ -26,6 +30,7 @@
- #include <fcntl.h>
- #include <mntent.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #include <locale.h>
- #define _(s) gettext(s)
-
-@@ -34,6 +39,8 @@
-
- #include <unistd.h>
- #include <sys/sysctl.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-
- #include "parser.h"
- #include "parser_version.h"
-@@ -47,7 +54,6 @@
- #define MATCH_STRING "/sys/kernel/security/" MODULE_NAME "/matching"
- #define FLAGS_FILE "/sys/kernel/security/" MODULE_NAME "/features"
- #define MOUNTED_FS "/proc/mounts"
--#define PCRE "pattern=pcre"
- #define AADFA "pattern=aadfa"
-
- #define PRIVILEGED_OPS (write_cache || kernel_load)
-@@ -76,6 +82,8 @@
- #else
- int read_implies_exec = 0;
- #endif
-+int preprocess_only = 0;
-+int skip_mode_force = 0;
-
- char *subdomainbase = NULL;
- char *match_string = NULL;
-@@ -84,8 +92,7 @@
- int perms_create = 0; /* perms contain create flag */
- char *profile_namespace = NULL;
- int flag_changehat_version = FLAG_CHANGEHAT_1_5;
--
--extern int current_lineno;
-+FILE *ofile = NULL;
-
- /* per-profile settings */
- int force_complain = 0;
-@@ -106,6 +113,7 @@
- {"remove", 0, 0, 'R'},
- {"names", 0, 0, 'N'},
- {"stdout", 0, 0, 'S'},
-+ {"ofile", 1, 0, 'o'},
- {"match-string", 1, 0, 'm'},
- {"quiet", 0, 0, 'q'},
- {"skip-kernel-load", 0, 0, 'Q'},
-@@ -121,6 +129,7 @@
- {"Dump", 1, 0, 'D'},
- {"optimize", 1, 0, 'O'},
- {"Optimize", 1, 0, 'O'},
-+ {"preprocess", 0, 0, 'p'},
- {NULL, 0, 0, 0},
- };
-
-@@ -145,6 +154,7 @@
- "-B, --binary Input is precompiled profile\n"
- "-N, --names Dump names of profiles in input.\n"
- "-S, --stdout Dump compiled profile to stdout\n"
-+ "-o n, --ofile n Write output to file n\n"
- "-b n, --base n Set base dir and cwd\n"
- "-I n, --Include n Add n to the search path\n"
- "-f n, --subdomainfs n Set location of apparmor filesystem\n"
-@@ -160,9 +170,10 @@
- "-Q, --skip-kernel-load Do everything except loading into kernel\n"
- "-V, --version Display version info and exit\n"
- "-d, --debug Debug apparmor definitions\n"
-+ "-p, --preprocess Dump preprocessed profile\n"
- "-D [n], --dump Dump internal info for debugging\n"
- "-O [n], --Optimize Control dfa optimizations\n"
-- "-h [command], --help Display this text or info about command\n"
-+ "-h [cmd], --help[=cmd] Display this text or info about cmd\n"
- ,command);
- }
-
-@@ -175,6 +186,7 @@
- "no option specified Dump variables\n"
- "variables Dump variables\n"
- "expanded-variables Dump expanded variables\n"
-+ "rule-exprs Dump rule to expr tree conversions\n"
- "expr-stats Dump stats on expr tree\n"
- "expr-tree Dump expression tree\n"
- "expr-simple Dump simplified expression tree\n"
-@@ -224,8 +236,10 @@
- if (conf_quiet || names_only || option == OPTION_REMOVE)
- return;
-
-- rc = asprintf(&newfmt, _("Warning (%s line %d): %s"),
-+ rc = asprintf(&newfmt, _("Warning from %s (%s%sline %d): %s"),
- profilename ? profilename : "stdin",
-+ current_filename ? current_filename : "",
-+ current_filename ? " " : "",
- current_lineno,
- fmt);
- if (!newfmt)
-@@ -244,7 +258,7 @@
- int count = 0;
- option = OPTION_ADD;
-
-- while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:", long_options, &o)) != -1)
-+ while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
- {
- switch (c) {
- case 0:
-@@ -258,7 +272,7 @@
- break;
- case 'd':
- debug++;
-- skip_cache = 1;
-+ skip_read_cache = 1;
- break;
- case 'h':
- if (!optarg) {
-@@ -285,6 +299,7 @@
- case 'R':
- count++;
- option = OPTION_REMOVE;
-+ skip_cache = 1;
- break;
- case 'V':
- display_version();
-@@ -297,10 +312,12 @@
- set_base_dir(optarg);
- break;
- case 'B':
-- binary_input =1;
-+ binary_input = 1;
-+ skip_cache = 1;
- break;
- case 'C':
- opt_force_complain = 1;
-+ skip_cache = 1;
- break;
- case 'N':
- names_only = 1;
-@@ -312,17 +329,31 @@
- skip_read_cache = 1;
- kernel_load = 0;
- break;
-+ case 'o':
-+ count++;
-+ option = OPTION_OFILE;
-+ skip_read_cache = 1;
-+ kernel_load = 0;
-+ ofile = fopen(optarg, "w");
-+ if (!ofile) {
-+ PERROR("%s: Could not open file %s\n",
-+ progname, optarg);
-+ exit(1);
-+ }
-+ break;
- case 'f':
- subdomainbase = strndup(optarg, PATH_MAX);
- break;
- case 'D':
-- skip_cache = 1;
-+ skip_read_cache = 1;
- if (!optarg) {
- dump_vars = 1;
- } else if (strcmp(optarg, "variables") == 0) {
- dump_vars = 1;
- } else if (strcmp(optarg, "expanded-variables") == 0) {
- dump_expanded_vars = 1;
-+ } else if (strcmp(optarg, "rule-exprs") == 0) {
-+ dfaflags |= DFA_DUMP_RULE_EXPR;
- } else if (strcmp(optarg, "expr-tree") == 0) {
- dfaflags |= DFA_DUMP_TREE;
- } else if (strcmp(optarg, "expr-simple") == 0) {
-@@ -359,7 +390,7 @@
- }
- break;
- case 'O':
-- skip_cache = 1;
-+ skip_read_cache = 1;
- if (strcmp(optarg, "0") == 0) {
- dfaflags |= DFA_CONTROL_NO_TREE_NORMAL |
- DFA_CONTROL_NO_TREE_SIMPLE |
-@@ -435,6 +466,13 @@
- case 'Q':
- kernel_load = 0;
- break;
-+ case 'p':
-+ count++;
-+ kernel_load = 0;
-+ skip_cache = 1;
-+ preprocess_only = 1;
-+ skip_mode_force = 1;
-+ break;
- default:
- display_usage(progname);
- exit(0);
-@@ -569,9 +607,6 @@
-
- out:
- if (match_string) {
-- if (strstr(match_string, PCRE))
-- regex_type = AARE_PCRE;
--
- if (strstr(match_string, AADFA))
- regex_type = AARE_DFA;
-
-@@ -620,20 +655,6 @@
- return;
- }
-
--/* return 1 --> PCRE should work fine
-- return 0 --> no PCRE support */
--static int regex_support(void) {
-- /* no match string, predates (or postdates?) the split matching
-- module design */
-- if (!match_string)
-- return 1;
--
-- if (regex_type != AARE_NONE)
-- return 1;
--
-- return 0;
--}
--
- int process_binary(int option, char *profilename)
- {
- char *buffer = NULL;
-@@ -695,12 +716,33 @@
- return retval;
- }
-
--void reset_parser(void)
-+void reset_parser(char *filename)
- {
- free_aliases();
- free_symtabs();
- free_policies();
- reset_regex();
-+ reset_include_stack(filename);
-+}
-+
-+int test_for_dir_mode(const char *basename, const char *linkdir)
-+{
-+ int rc = 0;
-+
-+ if (!skip_mode_force) {
-+ char *target = NULL;
-+ if (asprintf(&target, "%s/%s/%s", basedir, linkdir, basename) < 0) {
-+ perror("asprintf");
-+ exit(1);
-+ }
-+
-+ if (access(target, R_OK) == 0)
-+ rc = 1;
-+
-+ free(target);
-+ }
-+
-+ return rc;
- }
-
- int process_profile(int option, char *profilename)
-@@ -727,37 +769,22 @@
-
- if (profilename && option != OPTION_REMOVE) {
- /* make decisions about disabled or complain-mode profiles */
-- char *target = NULL;
- char *basename = strrchr(profilename, '/');
- if (basename)
- basename++;
- else
- basename = profilename;
-
-- if (asprintf(&target, "%s/%s/%s", basedir, "disable", basename) < 0) {
-- perror("asprintf");
-- exit(1);
-- }
--
-- if (access(target, R_OK) == 0) {
-- if (!conf_quiet)
-- PERROR("Skipping profile in %s/disable: %s\n", basedir, basename);
-- free(target);
-+ if (test_for_dir_mode(basename, "disable")) {
-+ if (!conf_quiet)
-+ PERROR("Skipping profile in %s/disable: %s\n", basedir, basename);
- goto out;
- }
-- free(target);
--
-- if (asprintf(&target, "%s/%s/%s", basedir, "force-complain", basename)<0) {
-- perror("asprintf");
-- exit(1);
-- }
--
-- if (access(target, R_OK) == 0) {
-- if (!conf_quiet)
-- PERROR("Warning: found %s in %s/force-complain, forcing complain mode\n", basename, basedir);
-- force_complain = 1;
-- }
-- free(target);
-+
-+ if (test_for_dir_mode(basename, "force-complain")) {
-+ PERROR("Warning: found %s in %s/force-complain, forcing complain mode\n", basename, basedir);
-+ force_complain = 1;
-+ }
-
- if (!force_complain && !skip_cache) {
- fstat(fileno(yyin), &stat_text);
-@@ -796,12 +823,15 @@
-
- if (yyin)
- yyrestart(yyin);
-- reset_parser();
-+ reset_parser(profilename);
-
- retval = yyparse();
- if (retval != 0)
- goto out;
-
-+ if (preprocess_only)
-+ goto out;
-+
- if (names_only) {
- dump_policy_names();
- goto out;
-@@ -812,7 +842,7 @@
- goto out;
- }
-
-- retval = post_process_policy();
-+ retval = post_process_policy(debug);
- if (retval != 0) {
- PERROR(_("%s: Errors found in file. Aborting.\n"), progname);
- goto out;
-@@ -829,10 +859,6 @@
- goto out;
- }
-
-- if (!regex_support()) {
-- die_if_any_regex();
-- }
--
- retval = load_policy(option);
-
- out:
-@@ -969,5 +995,8 @@
- profilename = NULL;
- }
-
-+ if (ofile)
-+ fclose(ofile);
-+
- return retval;
- }
-
-=== modified file 'parser/parser_misc.c'
---- parser/parser_misc.c 2010-03-09 04:38:54 +0000
-+++ parser/parser_misc.c 2010-08-03 17:27:13 +0000
-@@ -19,6 +19,7 @@
-
- /* assistance routines */
-
-+#include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
-@@ -27,6 +28,7 @@
- #define _(s) gettext(s)
- #include <netinet/in.h>
- #include <linux/socket.h>
-+#include <linux/limits.h>
- #include <arpa/inet.h>
- #include <linux/capability.h>
-
-@@ -35,8 +37,10 @@
-
- /* #define DEBUG */
- #ifdef DEBUG
-+#undef PDEBUG
- #define PDEBUG(fmt, args...) printf("Lexer: " fmt, ## args)
- #else
-+#undef PDEBUG
- #define PDEBUG(fmt, args...) /* Do nothing */
- #endif
- #define NPDEBUG(fmt, args...) /* Do nothing */
-@@ -102,7 +106,7 @@
- };
-
- /* for alpha matches, check for keywords */
--static int get_table_token(const char *name, struct keyword_table *table,
-+static int get_table_token(const char *name __unused, struct keyword_table *table,
- const char *keyword)
- {
- int i;
-@@ -142,42 +146,6 @@
- return get_table_token("rlimit", rlimit_table, name);
- }
-
--static struct keyword_table address_family[] = {
--/* {"unix", AF_UNIX},
-- {"local", AF_LOCAL}, */
-- {"inet", AF_INET},
--/* {"ax25", AF_AX25},
-- {"ipx", AF_IPX},
-- {"appletalk", AF_APPLETALK},
-- {"netrom", AF_NETROM},
-- {"bridge", AF_BRIDGE},
-- {"atmpvc", AF_ATMPVC},
-- {"x25", AF_X25}, */
-- {"inet6", AF_INET6},
--/* {"rose", AF_ROSE},
-- {"decnet", AF_DECnet},
-- {"netbeui", AF_NETBEUI},
-- {"security", AF_SECURITY},
-- {"key", AF_KEY},
-- {"netlink", AF_NETLINK},
-- {"route", AF_ROUTE},
-- {"packet", AF_PACKET},
-- {"ash", AF_ASH},
-- {"econet", AF_ECONET},
-- {"atmsvc", AF_ATMSVC},
-- {"sna", AF_SNA},
-- {"irda", AF_IRDA},
-- {"pppox", AF_PPPOX},
-- {"wanpipe", AF_WANPIPE},
-- {"llc", AF_LLC},
-- {"tipc", AF_TIPC},
-- {"bluetooth", AF_BLUETOOTH},
-- {"iucv", AF_IUCV},
-- {"rxrpc", AF_RXRPC}, */
-- /* terminate */
-- {NULL, 0}
--};
--
- struct network_tuple {
- char *family_name;
- unsigned int family;
-@@ -462,7 +430,7 @@
- }
- }
-
--static int parse_sub_mode(const char *str_mode, const char *mode_desc)
-+static int parse_sub_mode(const char *str_mode, const char *mode_desc __unused)
- {
-
- #define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
-@@ -666,7 +634,6 @@
-
- entry->pattern_type = ePatternInvalid;
- entry->pat.regex = NULL;
-- entry->pat.compiled = NULL;
-
- entry->next = NULL;
-
-@@ -692,7 +659,6 @@
- /* XXX - need to create copies of the patterns, too */
- entry->pattern_type = orig->pattern_type;
- entry->pat.regex = NULL;
-- entry->pat.compiled = NULL;
-
- entry->next = orig->next;
-
-@@ -713,8 +679,6 @@
- free(list->link_name);
- if (list->pat.regex)
- free(list->pat.regex);
-- if (list->pat.compiled)
-- free(list->pat.compiled);
- free(list);
- }
-
-
-=== modified file 'parser/parser_policy.c'
---- parser/parser_policy.c 2009-08-20 15:27:12 +0000
-+++ parser/parser_policy.c 2010-05-31 18:58:40 +0000
-@@ -4,6 +4,9 @@
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
- *
-+ * Copyright (c) 2010
-+ * Canonical, Ltd. (All rights reserved)
-+ *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License published by the Free Software Foundation.
-@@ -14,7 +17,8 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Novell, Inc. or Canonical,
-+ * Ltd.
- */
-
- #include <stdio.h>
-@@ -664,7 +668,7 @@
- return ret;
- }
-
--int post_process_policy(void)
-+int post_process_policy(int debug_only)
- {
- int retval = 0;
-
-@@ -696,11 +700,13 @@
- return retval;
- }
-
-- retval = post_process_regex();
-- if (retval != 0) {
-- PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
-- progname);
-- return retval;
-+ if (!debug_only) {
-+ retval = post_process_regex();
-+ if (retval != 0) {
-+ PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
-+ progname);
-+ return retval;
-+ }
- }
-
- return retval;
-
-=== modified file 'parser/parser_regex.c'
---- parser/parser_regex.c 2010-02-12 21:49:58 +0000
-+++ parser/parser_regex.c 2010-08-03 17:27:13 +0000
-@@ -21,6 +21,7 @@
- #include <stdarg.h>
- #include <string.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #define _(s) gettext(s)
-
- /* #define DEBUG */
-@@ -74,7 +75,6 @@
- {
- char *sptr, *dptr;
- BOOL seen_slash = 0;
-- int len;
-
- if (!path || (strlen(path) < 2))
- return;
-@@ -106,19 +106,6 @@
- }
- }
- *dptr = 0;
--
-- if (regex_type != AARE_DFA) {
-- /* eliminate trailing slashes for versions of apparmor that
-- * do not use the dfa engine.
-- * Versions of apparmor which use the dfa engine use the
-- * trailing / to differentiate between file and directory
-- * matches
-- */
-- len = strlen(path);
-- if (len > 2 && path[len -1] == '/') {
-- path[len - 1] = 0;
-- }
-- }
- }
-
- static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
-@@ -154,6 +141,9 @@
- sptr = aare;
- dptr = pcre;
-
-+ if (dfaflags & DFA_DUMP_RULE_EXPR)
-+ fprintf(stderr, "aare: %s -> ", aare);
-+
- if (anchor)
- /* anchor beginning of regular expression */
- *dptr++ = '^';
-@@ -406,85 +396,13 @@
- out:
- if (ret == FALSE)
- ptype = ePatternInvalid;
-+
-+ if (dfaflags & DFA_DUMP_RULE_EXPR)
-+ fprintf(stderr, "%s\n", pcre);
-+
- return ptype;
- }
-
--static int process_pcre_entry(struct cod_entry *entry)
--{
-- char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
-- int ret = TRUE;
-- pattern_t ptype;
-- int pos;
-- if (!entry) /* shouldn't happen */
-- return TRUE;
--
-- ptype = convert_aaregex_to_pcre(entry->name, 1, tbuf, PATH_MAX+3, &pos);
-- if (ptype == ePatternInvalid)
-- return FALSE;
--
-- entry->pattern_type = ptype;
--
-- /*
-- * Only use buffer (tbuf) that we built above, if we
-- * identified a pattern requiring full regex support.
-- */
-- if (ptype == ePatternRegex) {
-- int pattlen = strlen(tbuf);
--
-- if ((entry->pat.regex = malloc(pattlen + 1))) {
-- const char *errorreason;
-- int errpos;
--
-- strcpy(entry->pat.regex, tbuf);
--
-- if ((entry->pat.compiled =
-- pcre_compile(entry->pat.regex, 0,
-- &errorreason, &errpos,
-- NULL))) {
-- /* NULL out tables, kernel will use a
-- * private version
-- */
-- entry->pat.compiled->tables = NULL;
-- } else {
-- int i;
--
-- PERROR(_("%s: Failed to compile regex '%s' [original: '%s']\n"),
-- progname, entry->pat.regex,
-- entry->name);
--
-- PERROR(_("%s: error near "),
-- progname);
--
-- for (i = 0; i < errpos; i++) {
-- fputc('.', stderr);
-- }
--
-- fputc('^', stderr);
-- fputc('\n', stderr);
--
-- PERROR(_("%s: error reason: '%s'\n"),
-- progname, errorreason);
--
-- free(entry->pat.regex);
-- entry->pat.regex = NULL;
--
-- ret = FALSE;
-- }
-- } else {
-- PERROR(_("%s: Failed to compile regex '%s' [original: '%s'] - malloc failed\n"),
-- progname, entry->pat.regex, entry->name);
--
-- ret = FALSE;
-- }
-- } else {
-- /* not a regex, scan input for any escape characters
-- * and remove, and reduce double \\ to a single */
-- filter_escapes(entry->name);
-- } /* ptype == ePatternRegex */
--
-- return ret;
--}
--
- static const char *local_name(const char *name)
- {
- const char *t;
-@@ -519,7 +437,7 @@
- aare_ruleset_t *rule = aare_new_ruleset(0);
- if (!rule)
- return FALSE;
-- if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0)) {
-+ if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
- aare_delete_ruleset(rule);
- return FALSE;
- }
-@@ -529,7 +447,7 @@
- int len;
- convert_aaregex_to_pcre(alt->name, 0, tbuf,
- PATH_MAX + 3, &len);
-- if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0)) {
-+ if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
- aare_delete_ruleset(rule);
- return FALSE;
- }
-@@ -538,7 +456,7 @@
- cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size,
- dfaflags);
- aare_delete_ruleset(rule);
-- if (!cod->xmatch)
-+ if (!cod->xmatch)
- return FALSE;
- }
-
-@@ -581,11 +499,11 @@
- if (entry->deny && (entry->mode & AA_LINK_BITS)) {
- if (!aare_add_rule(dfarules, tbuf, entry->deny,
- entry->mode & ~AA_LINK_BITS,
-- entry->audit & ~AA_LINK_BITS))
-+ entry->audit & ~AA_LINK_BITS, dfaflags))
- return FALSE;
- } else if (entry->mode & ~AA_CHANGE_PROFILE) {
- if (!aare_add_rule(dfarules, tbuf, entry->deny, entry->mode,
-- entry->audit))
-+ entry->audit, dfaflags))
- return FALSE;
- }
-
-@@ -607,7 +525,7 @@
- perms |= LINK_TO_LINK_SUBSET(perms);
- vec[1] = "/[^/].*";
- }
-- if (!aare_add_rule_vec(dfarules, entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec))
-+ if (!aare_add_rule_vec(dfarules, entry->deny, perms, entry->audit & AA_LINK_BITS, 2, vec, dfaflags))
- return FALSE;
- }
- if (entry->mode & AA_CHANGE_PROFILE) {
-@@ -618,10 +536,10 @@
- ptype = convert_aaregex_to_pcre(entry->namespace, 0, lbuf, PATH_MAX + 8, &pos);
- vec[0] = lbuf;
- vec[1] = tbuf;
-- if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec))
-+ if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec, dfaflags))
- return FALSE;
- } else {
-- if (!aare_add_rule(dfarules, tbuf, 0, AA_CHANGE_PROFILE, 0))
-+ if (!aare_add_rule(dfarules, tbuf, 0, AA_CHANGE_PROFILE, 0, dfaflags))
- return FALSE;
- }
- }
-@@ -631,10 +549,10 @@
- char *vec[2];
- vec[0] = entry->namespace;
- vec[1] = entry->name;
-- if (!aare_add_rule_vec(dfarules, 0, mode, 0, 2, vec))
-+ if (!aare_add_rule_vec(dfarules, 0, mode, 0, 2, vec, dfaflags))
- return FALSE;
- } else {
-- if (!aare_add_rule(dfarules, entry->name, 0, mode, 0))
-+ if (!aare_add_rule(dfarules, entry->name, 0, mode, 0, dfaflags))
- return FALSE;
- }
- }
-@@ -643,18 +561,13 @@
-
- int post_process_entries(struct codomain *cod)
- {
-- int ret = TRUE, rc;
-+ int ret = TRUE;
- struct cod_entry *entry;
- int count = 0;
-
- list_for_each(cod->entries, entry) {
-- if (regex_type == AARE_DFA) {
-- rc = process_dfa_entry(cod->dfarules, entry);
-- } else {
-- filter_slashes(entry->name);
-- rc = process_pcre_entry(entry);
-- }
-- if (!rc)
-+ if (regex_type == AARE_DFA &&
-+ !process_dfa_entry(cod->dfarules, entry))
- ret = FALSE;
- count++;
- }
-@@ -770,7 +683,7 @@
-
- test_string = strdup("///foo//////f//oo////////////////");
- filter_slashes(test_string);
-- MY_TEST(strcmp(test_string, "/foo/f/oo") == 0, "simple tests");
-+ MY_TEST(strcmp(test_string, "/foo/f/oo/") == 0, "simple tests");
-
- test_string = strdup("/foo/f/oo");
- filter_slashes(test_string);
-@@ -802,13 +715,11 @@
-
- test_string = strdup("/a/");
- filter_slashes(test_string);
-- MY_TEST(strcmp(test_string, "/a") == 0, "simple test for /a/");
-+ MY_TEST(strcmp(test_string, "/a/") == 0, "simple test for /a/");
-
- return rc;
- }
-
--int regex_type = AARE_PCRE;
--
- int main(void)
- {
- int rc = 0;
-
-=== modified file 'parser/parser_symtab.c'
---- parser/parser_symtab.c 2009-07-24 13:24:53 +0000
-+++ parser/parser_symtab.c 2010-08-03 17:27:13 +0000
-@@ -23,6 +23,7 @@
- #include <string.h>
- #include <errno.h>
- #include <libintl.h>
-+#include <linux/limits.h>
- #define _(s) gettext(s)
-
- #include "immunix.h"
-@@ -33,11 +34,6 @@
- sd_set,
- };
-
--struct set_value {
-- char *val;
-- struct set_value *next;
--};
--
- struct symtab {
- char *var_name;
- enum var_type type;
-@@ -288,7 +284,7 @@
-
- /* returns a pointer to the value list, which should be used as the
- * argument to the get_next_set_value() function. */
--void *get_set_var(const char *var)
-+struct set_value *get_set_var(const char *var)
- {
- struct symtab *result;
- struct set_value *valuelist = NULL;
-@@ -321,16 +317,17 @@
- }
-
- /* iterator to walk the list of set values */
--char *get_next_set_value(void **list)
-+char *get_next_set_value(struct set_value **list)
- {
-- struct set_value **valuelist = (struct set_value **) list;
-+ struct set_value *next;
- char *ret;
-
-- if (!valuelist || !(*valuelist))
-+ if (!list || !(*list))
- return NULL;
-
-- ret = (*valuelist)->val;
-- (*valuelist) = (*valuelist)->next;
-+ ret = (*list)->val;
-+ next = (*list)->next;
-+ (*list) = next;
-
- return ret;
- }
-@@ -429,10 +426,13 @@
-
- for (ref_item = ref->expanded; ref_item; ref_item = ref_item->next) {
- char *expanded_string;
-- asprintf(&expanded_string, "%s%s%s",
-+ if (!asprintf(&expanded_string, "%s%s%s",
- split->prefix ? split->prefix : "",
- ref_item->val,
-- split->suffix ? split->suffix : "");
-+ split->suffix ? split->suffix : "")) {
-+ PERROR("Out of memory\n");
-+ exit(1);
-+ }
- add_to_set(&work_list, expanded_string);
- free(expanded_string);
- }
-@@ -569,7 +569,7 @@
- {
- int rc = 0;
- int retval;
-- void *retptr;
-+ struct set_value *retptr;
- struct symtab *a, *b;
-
- a = new_symtab_entry("blah");
-
-=== modified file 'parser/parser_variable.c'
---- parser/parser_variable.c 2009-07-24 23:47:46 +0000
-+++ parser/parser_variable.c 2010-08-03 17:27:13 +0000
-@@ -17,10 +17,14 @@
- * along with this program; if not, contact Novell, Inc.
- */
-
-+#include <ctype.h>
-+#include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <libintl.h>
-+#include <linux/limits.h>
-+
- #define _(s) gettext(s)
-
- /* #define DEBUG */
-@@ -124,7 +128,7 @@
-
- static int expand_entry_variables(struct cod_entry *entry)
- {
-- void *valuelist;
-+ struct set_value *valuelist;
- int ret = TRUE;
- char *value;
- struct var_string *split_var;
-
-=== modified file 'parser/parser_yacc.y'
---- parser/parser_yacc.y 2010-02-17 20:21:52 +0000
-+++ parser/parser_yacc.y 2010-08-03 17:27:13 +0000
-@@ -1,9 +1,9 @@
- %{
--/* $Id$ */
--
- /*
- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- * NOVELL (All rights reserved)
-+ * Copyright (c) 2010
-+ * Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
-@@ -15,7 +15,7 @@
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, contact Novell, Inc.
-+ * along with this program; if not, contact Canonical, Ltd.
- */
-
- #define YYERROR_VERBOSE 1
-@@ -32,6 +32,7 @@
- /* #define DEBUG */
-
- #include "parser.h"
-+#include "parser_include.h"
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-@@ -63,10 +64,6 @@
-
- #define CAP_TO_MASK(x) (1ull << (x))
-
--/* from lex_config, for nice error messages */
--/* extern char *current_file; */
--extern int current_lineno;
--
- struct value_list {
- char *value;
- struct value_list *next;
-@@ -415,7 +412,7 @@
-
- flagval: TOK_FLAG_ID
- {
-- struct flagval fv = {0, 0, 0};
-+ struct flagval fv = { 0, 0, 0, 0 };
- if (strcmp($1, "debug") == 0) {
- yyerror(_("Profile flag 'debug' is no longer valid."));
- } else if (strcmp($1, "complain") == 0) {
-@@ -1109,10 +1106,15 @@
- va_end(arg);
-
- if (profilename) {
-- PERROR(_("AppArmor parser error in %s at line %d: %s\n"),
-- profilename, current_lineno, buf);
-+ PERROR(_("AppArmor parser error for %s%s%s at line %d: %s\n"),
-+ profilename,
-+ current_filename ? " in " : "",
-+ current_filename ? current_filename : "",
-+ current_lineno, buf);
- } else {
-- PERROR(_("AppArmor parser error, line %d: %s\n"),
-+ PERROR(_("AppArmor parser error,%s%s line %d: %s\n"),
-+ current_filename ? " in " : "",
-+ current_filename ? current_filename : "",
- current_lineno, buf);
- }
-
-
-=== removed directory 'parser/pcre'
-=== removed file 'parser/pcre/Makefile'
---- parser/pcre/Makefile 2007-03-30 16:30:15 +0000
-+++ parser/pcre/Makefile 1970-01-01 00:00:00 +0000
-@@ -1,7 +0,0 @@
--all: pcre.o
--
--pcre.o: pcre.c
-- $(CC) -c $(CFLAGS) $<
--
--clean:
-- rm -f pcre.o
-
-=== removed file 'parser/pcre/chartables.c'
---- parser/pcre/chartables.c 2006-04-11 21:52:54 +0000
-+++ parser/pcre/chartables.c 1970-01-01 00:00:00 +0000
-@@ -1,183 +0,0 @@
--/*************************************************
--* Perl-Compatible Regular Expressions *
--*************************************************/
--
--/* This file is automatically written by the dftables auxiliary
--program. If you edit it by hand, you might like to edit the Makefile to
--prevent its ever being regenerated.
--
--This file is #included in the compilation of pcre.c to build the default
--character tables which are used when no tables are passed to the compile
--function. */
--
--static unsigned char pcre_default_tables[] = {
--
--/* This table is a lower casing table. */
--
-- 0, 1, 2, 3, 4, 5, 6, 7,
-- 8, 9, 10, 11, 12, 13, 14, 15,
-- 16, 17, 18, 19, 20, 21, 22, 23,
-- 24, 25, 26, 27, 28, 29, 30, 31,
-- 32, 33, 34, 35, 36, 37, 38, 39,
-- 40, 41, 42, 43, 44, 45, 46, 47,
-- 48, 49, 50, 51, 52, 53, 54, 55,
-- 56, 57, 58, 59, 60, 61, 62, 63,
-- 64, 97, 98, 99,100,101,102,103,
-- 104,105,106,107,108,109,110,111,
-- 112,113,114,115,116,117,118,119,
-- 120,121,122, 91, 92, 93, 94, 95,
-- 96, 97, 98, 99,100,101,102,103,
-- 104,105,106,107,108,109,110,111,
-- 112,113,114,115,116,117,118,119,
-- 120,121,122,123,124,125,126,127,
-- 128,129,130,131,132,133,134,135,
-- 136,137,138,139,140,141,142,143,
-- 144,145,146,147,148,149,150,151,
-- 152,153,154,155,156,157,158,159,
-- 160,161,162,163,164,165,166,167,
-- 168,169,170,171,172,173,174,175,
-- 176,177,178,179,180,181,182,183,
-- 184,185,186,187,188,189,190,191,
-- 192,193,194,195,196,197,198,199,
-- 200,201,202,203,204,205,206,207,
-- 208,209,210,211,212,213,214,215,
-- 216,217,218,219,220,221,222,223,
-- 224,225,226,227,228,229,230,231,
-- 232,233,234,235,236,237,238,239,
-- 240,241,242,243,244,245,246,247,
-- 248,249,250,251,252,253,254,255,
--
--/* This table is a case flipping table. */
--
-- 0, 1, 2, 3, 4, 5, 6, 7,
-- 8, 9, 10, 11, 12, 13, 14, 15,
-- 16, 17, 18, 19, 20, 21, 22, 23,
-- 24, 25, 26, 27, 28, 29, 30, 31,
-- 32, 33, 34, 35, 36, 37, 38, 39,
-- 40, 41, 42, 43, 44, 45, 46, 47,
-- 48, 49, 50, 51, 52, 53, 54, 55,
-- 56, 57, 58, 59, 60, 61, 62, 63,
-- 64, 97, 98, 99,100,101,102,103,
-- 104,105,106,107,108,109,110,111,
-- 112,113,114,115,116,117,118,119,
-- 120,121,122, 91, 92, 93, 94, 95,
-- 96, 65, 66, 67, 68, 69, 70, 71,
-- 72, 73, 74, 75, 76, 77, 78, 79,
-- 80, 81, 82, 83, 84, 85, 86, 87,
-- 88, 89, 90,123,124,125,126,127,
-- 128,129,130,131,132,133,134,135,
-- 136,137,138,139,140,141,142,143,
-- 144,145,146,147,148,149,150,151,
-- 152,153,154,155,156,157,158,159,
-- 160,161,162,163,164,165,166,167,
-- 168,169,170,171,172,173,174,175,
-- 176,177,178,179,180,181,182,183,
-- 184,185,186,187,188,189,190,191,
-- 192,193,194,195,196,197,198,199,
-- 200,201,202,203,204,205,206,207,
-- 208,209,210,211,212,213,214,215,
-- 216,217,218,219,220,221,222,223,
-- 224,225,226,227,228,229,230,231,
-- 232,233,234,235,236,237,238,239,
-- 240,241,242,243,244,245,246,247,
-- 248,249,250,251,252,253,254,255,
--
--/* This table contains bit maps for various character classes.
--Each map is 32 bytes long and the bits run from the least
--significant end of each byte. The classes that have their own
--maps are: space, xdigit, digit, upper, lower, word, graph
--print, punct, and cntrl. Other classes are built from combinations. */
--
-- 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
-- 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
-- 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
-- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
-- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
-- 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
-- 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
--
--/* This table identifies various classes of character by individual bits:
-- 0x01 white space character
-- 0x02 letter
-- 0x04 decimal digit
-- 0x08 hexadecimal digit
-- 0x10 alphanumeric or '_'
-- 0x80 regular expression metacharacter or binary zero
--*/
--
-- 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
-- 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
-- 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */
-- 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
-- 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
-- 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
-- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
-- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
-- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
-- 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */
-- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
-- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
-- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
-- 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
--
--/* End of chartables.c */
-
-=== removed file 'parser/pcre/config.h'
---- parser/pcre/config.h 2006-04-11 21:52:54 +0000
-+++ parser/pcre/config.h 1970-01-01 00:00:00 +0000
-@@ -1,48 +0,0 @@
--/* config.h. Generated automatically by configure. */
--
--/* On Unix systems config.in is converted by configure into config.h. PCRE is
--written in Standard C, but there are a few non-standard things it can cope
--with, allowing it to run on SunOS4 and other "close to standard" systems.
--
--On a non-Unix system you should just copy this file into config.h, and set up
--the macros the way you need them. You should normally change the definitions of
--HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf
--works, these cannot be made the defaults. If your system has bcopy() and not
--memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your
--system has neither bcopy() nor memmove(), leave them both as 0; an emulation
--function will be used. */
--
--/* Define to empty if the keyword does not work. */
--
--/* #undef const */
--
--/* Define to `unsigned' if <stddef.h> doesn't define size_t. */
--
--/* #undef size_t */
--
--/* The following two definitions are mainly for the benefit of SunOS4, which
--doesn't have the strerror() or memmove() functions that should be present in
--all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
--normally be defined with the value 1 for other systems, but unfortunately we
--can't make this the default because "configure" files generated by autoconf
--will only change 0 to 1; they won't change 1 to 0 if the functions are not
--found. */
--
--#define HAVE_STRERROR 1
--#define HAVE_MEMMOVE 1
--
--/* There are some non-Unix systems that don't even have bcopy(). If this macro
--is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
--HAVE_BCOPY is not relevant. */
--
--#define HAVE_BCOPY 1
--
--/* The value of NEWLINE determines the newline character. The default is to
--leave it up to the compiler, but some sites want to force a particular value.
--On Unix systems, "configure" can be used to override this default. */
--
--#ifndef NEWLINE
--#define NEWLINE '\n'
--#endif
--
--/* End */
-
-=== removed file 'parser/pcre/internal.h'
---- parser/pcre/internal.h 2006-04-11 21:52:54 +0000
-+++ parser/pcre/internal.h 1970-01-01 00:00:00 +0000
-@@ -1,412 +0,0 @@
--/*************************************************
--* Perl-Compatible Regular Expressions *
--*************************************************/
--
--
--/* This is a library of functions to support regular expressions whose syntax
--and semantics are as close as possible to those of the Perl 5 language. See
--the file Tech.Notes for some information on the internals.
--
--Written by: Philip Hazel <ph10@cam.ac.uk>
--
-- Copyright (c) 1997-2001 University of Cambridge
--
-------------------------------------------------------------------------------
--Permission is granted to anyone to use this software for any purpose on any
--computer system, and to redistribute it freely, subject to the following
--restrictions:
--
--1. This software is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--
--2. The origin of this software must not be misrepresented, either by
-- explicit claim or by omission.
--
--3. Altered versions must be plainly marked as such, and must not be
-- misrepresented as being the original software.
--
--4. If PCRE is embedded in any software that is released under the GNU
-- General Purpose Licence (GPL), then the terms of that licence shall
-- supersede any condition above with which it is incompatible.
-------------------------------------------------------------------------------
--*/
--
--/* This header contains definitions that are shared between the different
--modules, but which are not relevant to the outside. */
--
--/* Get the definitions provided by running "configure" */
--
--#include "config.h"
--
--/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(),
--define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY
--is set. Otherwise, include an emulating function for those systems that have
--neither (there some non-Unix environments where this is the case). This assumes
--that all calls to memmove are moving strings upwards in store, which is the
--case in PCRE. */
--
--#if ! HAVE_MEMMOVE
--#undef memmove /* some systems may have a macro */
--#if HAVE_BCOPY
--#define memmove(a, b, c) bcopy(b, a, c)
--#else
--void *
--pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n)
--{
--int i;
--dest += n;
--src += n;
--for (i = 0; i < n; ++i) *(--dest) = *(--src);
--}
--#define memmove(a, b, c) pcre_memmove(a, b, c)
--#endif
--#endif
--
--/* Standard C headers plus the external interface definition */
--
--#include <ctype.h>
--#include <limits.h>
--#include <stddef.h>
--#include <stdio.h>
--#include <stdlib.h>
--#include <string.h>
--#include "pcre.h"
--
--/* In case there is no definition of offsetof() provided - though any proper
--Standard C system should have one. */
--
--#ifndef offsetof
--#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
--#endif
--
--/* These are the public options that can change during matching. */
--
--#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
--
--/* Private options flags start at the most significant end of the four bytes,
--but skip the top bit so we can use ints for convenience without getting tangled
--with negative values. The public options defined in pcre.h start at the least
--significant end. Make sure they don't overlap, though now that we have expanded
--to four bytes there is plenty of space. */
--
--#define PCRE_FIRSTSET 0x40000000 /* first_char is set */
--#define PCRE_REQCHSET 0x20000000 /* req_char is set */
--#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */
--#define PCRE_INGROUP 0x08000000 /* compiling inside a group */
--#define PCRE_ICHANGED 0x04000000 /* i option changes within regex */
--
--/* Options for the "extra" block produced by pcre_study(). */
--
--#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */
--
--/* Masks for identifying the public options which are permitted at compile
--time, run time or study time, respectively. */
--
--#define PUBLIC_OPTIONS \
-- (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
-- PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8)
--
--#define PUBLIC_EXEC_OPTIONS \
-- (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY)
--
--#define PUBLIC_STUDY_OPTIONS 0 /* None defined */
--
--/* Magic number to provide a small check against being handed junk. */
--
--#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
--
--/* Miscellaneous definitions */
--
--typedef int BOOL;
--
--#define FALSE 0
--#define TRUE 1
--
--/* Escape items that are just an encoding of a particular data value. Note that
--ESC_N is defined as yet another macro, which is set in config.h to either \n
--(the default) or \r (which some people want). */
--
--#ifndef ESC_E
--#define ESC_E 27
--#endif
--
--#ifndef ESC_F
--#define ESC_F '\f'
--#endif
--
--#ifndef ESC_N
--#define ESC_N NEWLINE
--#endif
--
--#ifndef ESC_R
--#define ESC_R '\r'
--#endif
--
--#ifndef ESC_T
--#define ESC_T '\t'
--#endif
--
--/* These are escaped items that aren't just an encoding of a particular data
--value such as \n. They must have non-zero values, as check_escape() returns
--their negation. Also, they must appear in the same order as in the opcode
--definitions below, up to ESC_z. The final one must be ESC_REF as subsequent
--values are used for \1, \2, \3, etc. There is a test in the code for an escape
--greater than ESC_b and less than ESC_Z to detect the types that may be
--repeated. If any new escapes are put in-between that don't consume a character,
--that code will have to change. */
--
--enum { ESC_A = 1, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w,
-- ESC_Z, ESC_z, ESC_REF };
--
--/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
--that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
--OP_EOD must correspond in order to the list of escapes immediately above. */
--
--enum {
-- OP_END, /* End of pattern */
--
-- /* Values corresponding to backslashed metacharacters */
--
-- OP_SOD, /* Start of data: \A */
-- OP_NOT_WORD_BOUNDARY, /* \B */
-- OP_WORD_BOUNDARY, /* \b */
-- OP_NOT_DIGIT, /* \D */
-- OP_DIGIT, /* \d */
-- OP_NOT_WHITESPACE, /* \S */
-- OP_WHITESPACE, /* \s */
-- OP_NOT_WORDCHAR, /* \W */
-- OP_WORDCHAR, /* \w */
-- OP_EODN, /* End of data or \n at end of data: \Z. */
-- OP_EOD, /* End of data: \z */
--
-- OP_OPT, /* Set runtime options */
-- OP_CIRC, /* Start of line - varies with multiline switch */
-- OP_DOLL, /* End of line - varies with multiline switch */
-- OP_ANY, /* Match any character */
-- OP_CHARS, /* Match string of characters */
-- OP_NOT, /* Match anything but the following char */
--
-- OP_STAR, /* The maximizing and minimizing versions of */
-- OP_MINSTAR, /* all these opcodes must come in pairs, with */
-- OP_PLUS, /* the minimizing one second. */
-- OP_MINPLUS, /* This first set applies to single characters */
-- OP_QUERY,
-- OP_MINQUERY,
-- OP_UPTO, /* From 0 to n matches */
-- OP_MINUPTO,
-- OP_EXACT, /* Exactly n matches */
--
-- OP_NOTSTAR, /* The maximizing and minimizing versions of */
-- OP_NOTMINSTAR, /* all these opcodes must come in pairs, with */
-- OP_NOTPLUS, /* the minimizing one second. */
-- OP_NOTMINPLUS, /* This first set applies to "not" single characters */
-- OP_NOTQUERY,
-- OP_NOTMINQUERY,
-- OP_NOTUPTO, /* From 0 to n matches */
-- OP_NOTMINUPTO,
-- OP_NOTEXACT, /* Exactly n matches */
--
-- OP_TYPESTAR, /* The maximizing and minimizing versions of */
-- OP_TYPEMINSTAR, /* all these opcodes must come in pairs, with */
-- OP_TYPEPLUS, /* the minimizing one second. These codes must */
-- OP_TYPEMINPLUS, /* be in exactly the same order as those above. */
-- OP_TYPEQUERY, /* This set applies to character types such as \d */
-- OP_TYPEMINQUERY,
-- OP_TYPEUPTO, /* From 0 to n matches */
-- OP_TYPEMINUPTO,
-- OP_TYPEEXACT, /* Exactly n matches */
--
-- OP_CRSTAR, /* The maximizing and minimizing versions of */
-- OP_CRMINSTAR, /* all these opcodes must come in pairs, with */
-- OP_CRPLUS, /* the minimizing one second. These codes must */
-- OP_CRMINPLUS, /* be in exactly the same order as those above. */
-- OP_CRQUERY, /* These are for character classes and back refs */
-- OP_CRMINQUERY,
-- OP_CRRANGE, /* These are different to the three seta above. */
-- OP_CRMINRANGE,
--
-- OP_CLASS, /* Match a character class */
-- OP_REF, /* Match a back reference */
-- OP_RECURSE, /* Match this pattern recursively */
--
-- OP_ALT, /* Start of alternation */
-- OP_KET, /* End of group that doesn't have an unbounded repeat */
-- OP_KETRMAX, /* These two must remain together and in this */
-- OP_KETRMIN, /* order. They are for groups the repeat for ever. */
--
-- /* The assertions must come before ONCE and COND */
--
-- OP_ASSERT, /* Positive lookahead */
-- OP_ASSERT_NOT, /* Negative lookahead */
-- OP_ASSERTBACK, /* Positive lookbehind */
-- OP_ASSERTBACK_NOT, /* Negative lookbehind */
-- OP_REVERSE, /* Move pointer back - used in lookbehind assertions */
--
-- /* ONCE and COND must come after the assertions, with ONCE first, as there's
-- a test for >= ONCE for a subpattern that isn't an assertion. */
--
-- OP_ONCE, /* Once matched, don't back up into the subpattern */
-- OP_COND, /* Conditional group */
-- OP_CREF, /* Used to hold an extraction string number (cond ref) */
--
-- OP_BRAZERO, /* These two must remain together and in this */
-- OP_BRAMINZERO, /* order. */
--
-- OP_BRANUMBER, /* Used for extracting brackets whose number is greater
-- than can fit into an opcode. */
--
-- OP_BRA /* This and greater values are used for brackets that
-- extract substrings up to a basic limit. After that,
-- use is made of OP_BRANUMBER. */
--};
--
--/* The highest extraction number before we have to start using additional
--bytes. (Originally PCRE didn't have support for extraction counts highter than
--this number.) The value is limited by the number of opcodes left after OP_BRA,
--i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
--opcodes. */
--
--#define EXTRACT_BASIC_MAX 150
--
--/* The texts of compile-time error messages are defined as macros here so that
--they can be accessed by the POSIX wrapper and converted into error codes. Yes,
--I could have used error codes in the first place, but didn't feel like changing
--just to accommodate the POSIX wrapper. */
--
--#define ERR1 "\\ at end of pattern"
--#define ERR2 "\\c at end of pattern"
--#define ERR3 "unrecognized character follows \\"
--#define ERR4 "numbers out of order in {} quantifier"
--#define ERR5 "number too big in {} quantifier"
--#define ERR6 "missing terminating ] for character class"
--#define ERR7 "invalid escape sequence in character class"
--#define ERR8 "range out of order in character class"
--#define ERR9 "nothing to repeat"
--#define ERR10 "operand of unlimited repeat could match the empty string"
--#define ERR11 "internal error: unexpected repeat"
--#define ERR12 "unrecognized character after (?"
--#define ERR13 "unused error"
--#define ERR14 "missing )"
--#define ERR15 "back reference to non-existent subpattern"
--#define ERR16 "erroffset passed as NULL"
--#define ERR17 "unknown option bit(s) set"
--#define ERR18 "missing ) after comment"
--#define ERR19 "parentheses nested too deeply"
--#define ERR20 "regular expression too large"
--#define ERR21 "failed to get memory"
--#define ERR22 "unmatched parentheses"
--#define ERR23 "internal error: code overflow"
--#define ERR24 "unrecognized character after (?<"
--#define ERR25 "lookbehind assertion is not fixed length"
--#define ERR26 "malformed number after (?("
--#define ERR27 "conditional group contains more than two branches"
--#define ERR28 "assertion expected after (?("
--#define ERR29 "(?p must be followed by )"
--#define ERR30 "unknown POSIX class name"
--#define ERR31 "POSIX collating elements are not supported"
--#define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support"
--#define ERR33 "characters with values > 255 are not yet supported in classes"
--#define ERR34 "character value in \\x{...} sequence is too large"
--#define ERR35 "invalid condition (?(0)"
--
--/* All character handling must be done as unsigned characters. Otherwise there
--are problems with top-bit-set characters and functions such as isspace().
--However, we leave the interface to the outside world as char *, because that
--should make things easier for callers. We define a short type for unsigned char
--to save lots of typing. I tried "uchar", but it causes problems on Digital
--Unix, where it is defined in sys/types, so use "uschar" instead. */
--
--typedef unsigned char uschar;
--
--/* The real format of the start of the pcre block; the actual code vector
--runs on as long as necessary after the end. */
--
--typedef struct real_pcre {
-- unsigned long int magic_number;
-- size_t size;
-- const unsigned char *tables;
-- unsigned long int options;
-- unsigned short int top_bracket;
-- unsigned short int top_backref;
-- uschar first_char;
-- uschar req_char;
-- uschar code[1];
--} real_pcre;
--
--/* The real format of the extra block returned by pcre_study(). */
--
--typedef struct real_pcre_extra {
-- uschar options;
-- uschar start_bits[32];
--} real_pcre_extra;
--
--
--/* Structure for passing "static" information around between the functions
--doing the compiling, so that they are thread-safe. */
--
--typedef struct compile_data {
-- const uschar *lcc; /* Points to lower casing table */
-- const uschar *fcc; /* Points to case-flipping table */
-- const uschar *cbits; /* Points to character type table */
-- const uschar *ctypes; /* Points to table of type maps */
--} compile_data;
--
--/* Structure for passing "static" information around between the functions
--doing the matching, so that they are thread-safe. */
--
--typedef struct match_data {
-- int errorcode; /* As it says */
-- int *offset_vector; /* Offset vector */
-- int offset_end; /* One past the end */
-- int offset_max; /* The maximum usable for return data */
-- const uschar *lcc; /* Points to lower casing table */
-- const uschar *ctypes; /* Points to table of type maps */
-- BOOL offset_overflow; /* Set if too many extractions */
-- BOOL notbol; /* NOTBOL flag */
-- BOOL noteol; /* NOTEOL flag */
-- BOOL utf8; /* UTF8 flag */
-- BOOL endonly; /* Dollar not before final \n */
-- BOOL notempty; /* Empty string match not wanted */
-- const uschar *start_pattern; /* For use when recursing */
-- const uschar *start_subject; /* Start of the subject string */
-- const uschar *end_subject; /* End of the subject string */
-- const uschar *start_match; /* Start of this match attempt */
-- const uschar *end_match_ptr; /* Subject position at end match */
-- int end_offset_top; /* Highwater mark at end of match */
--} match_data;
--
--/* Bit definitions for entries in the pcre_ctypes table. */
--
--#define ctype_space 0x01
--#define ctype_letter 0x02
--#define ctype_digit 0x04
--#define ctype_xdigit 0x08
--#define ctype_word 0x10 /* alphameric or '_' */
--#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
--
--/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
--of bits for a class map. Some classes are built by combining these tables. */
--
--#define cbit_space 0 /* [:space:] or \s */
--#define cbit_xdigit 32 /* [:xdigit:] */
--#define cbit_digit 64 /* [:digit:] or \d */
--#define cbit_upper 96 /* [:upper:] */
--#define cbit_lower 128 /* [:lower:] */
--#define cbit_word 160 /* [:word:] or \w */
--#define cbit_graph 192 /* [:graph:] */
--#define cbit_print 224 /* [:print:] */
--#define cbit_punct 256 /* [:punct:] */
--#define cbit_cntrl 288 /* [:cntrl:] */
--#define cbit_length 320 /* Length of the cbits table */
--
--/* Offsets of the various tables from the base tables pointer, and
--total length. */
--
--#define lcc_offset 0
--#define fcc_offset 256
--#define cbits_offset 512
--#define ctypes_offset (cbits_offset + cbit_length)
--#define tables_length (ctypes_offset + 256)
--
--/* End of internal.h */
-
-=== removed file 'parser/pcre/pcre.c'
---- parser/pcre/pcre.c 2006-04-11 21:52:54 +0000
-+++ parser/pcre/pcre.c 1970-01-01 00:00:00 +0000
-@@ -1,5187 +0,0 @@
--/*************************************************
--* Perl-Compatible Regular Expressions *
--*************************************************/
--
--/*
--This is a library of functions to support regular expressions whose syntax
--and semantics are as close as possible to those of the Perl 5 language. See
--the file Tech.Notes for some information on the internals.
--
--Written by: Philip Hazel <ph10@cam.ac.uk>
--
-- Copyright (c) 1997-2001 University of Cambridge
--
-------------------------------------------------------------------------------
--Permission is granted to anyone to use this software for any purpose on any
--computer system, and to redistribute it freely, subject to the following
--restrictions:
--
--1. This software is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--
--2. The origin of this software must not be misrepresented, either by
-- explicit claim or by omission.
--
--3. Altered versions must be plainly marked as such, and must not be
-- misrepresented as being the original software.
--
--4. If PCRE is embedded in any software that is released under the GNU
-- General Purpose Licence (GPL), then the terms of that licence shall
-- supersede any condition above with which it is incompatible.
-------------------------------------------------------------------------------
--*/
--
--
--/* Define DEBUG to get debugging output on stdout. */
--
--/* #define DEBUG */
--
--/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
--inline, and there are *still* stupid compilers about that don't like indented
--pre-processor statements. I suppose it's only been 10 years... */
--
--#ifdef DEBUG
--#define DPRINTF(p) printf p
--#else
--#define DPRINTF(p) /*nothing*/
--#endif
--
--/* Include the internals header, which itself includes Standard C headers plus
--the external pcre header. */
--
--#include "internal.h"
--
--
--/* Allow compilation as C++ source code, should anybody want to do that. */
--
--#ifdef __cplusplus
--#define class pcre_class
--#endif
--
--
--/* Maximum number of items on the nested bracket stacks at compile time. This
--applies to the nesting of all kinds of parentheses. It does not limit
--un-nested, non-capturing parentheses. This number can be made bigger if
--necessary - it is used to dimension one int and one unsigned char vector at
--compile time. */
--
--#define BRASTACK_SIZE 200
--
--
--/* The number of bytes in a literal character string above which we can't add
--any more is different when UTF-8 characters may be encountered. */
--
--#ifdef SUPPORT_UTF8
--#define MAXLIT 250
--#else
--#define MAXLIT 255
--#endif
--
--
--/* Min and max values for the common repeats; for the maxima, 0 => infinity */
--
--static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
--static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
--
--/* Text forms of OP_ values and things, for debugging (not all used) */
--
--#ifdef DEBUG
--static const char *OP_names[] = {
-- "End", "\\A", "\\B", "\\b", "\\D", "\\d",
-- "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z",
-- "Opt", "^", "$", "Any", "chars", "not",
-- "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
-- "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
-- "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
-- "*", "*?", "+", "+?", "?", "??", "{", "{",
-- "class", "Ref", "Recurse",
-- "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not",
-- "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref",
-- "Brazero", "Braminzero", "Branumber", "Bra"
--};
--#endif
--
--/* Table for handling escaped characters in the range '0'-'z'. Positive returns
--are simple data values; negative values are for special things like \d and so
--on. Zero means further processing is needed (for things like \x), or the escape
--is invalid. */
--
--static const short int escapes[] = {
-- 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */
-- 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */
-- '@', -ESC_A, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */
-- 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
-- 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */
-- 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */
-- '`', 7, -ESC_b, 0, -ESC_d, ESC_E, ESC_F, 0, /* ` - g */
-- 0, 0, 0, 0, 0, 0, ESC_N, 0, /* h - o */
-- 0, 0, ESC_R, -ESC_s, ESC_T, 0, 0, -ESC_w, /* p - w */
-- 0, 0, -ESC_z /* x - z */
--};
--
--/* Tables of names of POSIX character classes and their lengths. The list is
--terminated by a zero length entry. The first three must be alpha, upper, lower,
--as this is assumed for handling case independence. */
--
--static const char *posix_names[] = {
-- "alpha", "lower", "upper",
-- "alnum", "ascii", "cntrl", "digit", "graph",
-- "print", "punct", "space", "word", "xdigit" };
--
--static const uschar posix_name_lengths[] = {
-- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
--
--/* Table of class bit maps for each POSIX class; up to three may be combined
--to form the class. */
--
--static const int posix_class_maps[] = {
-- cbit_lower, cbit_upper, -1, /* alpha */
-- cbit_lower, -1, -1, /* lower */
-- cbit_upper, -1, -1, /* upper */
-- cbit_digit, cbit_lower, cbit_upper, /* alnum */
-- cbit_print, cbit_cntrl, -1, /* ascii */
-- cbit_cntrl, -1, -1, /* cntrl */
-- cbit_digit, -1, -1, /* digit */
-- cbit_graph, -1, -1, /* graph */
-- cbit_print, -1, -1, /* print */
-- cbit_punct, -1, -1, /* punct */
-- cbit_space, -1, -1, /* space */
-- cbit_word, -1, -1, /* word */
-- cbit_xdigit,-1, -1 /* xdigit */
--};
--
--
--/* Definition to allow mutual recursion */
--
--static BOOL
-- compile_regex(int, int, int *, uschar **, const uschar **, const char **,
-- BOOL, int, int *, int *, compile_data *);
--
--/* Structure for building a chain of data that actually lives on the
--stack, for holding the values of the subject pointer at the start of each
--subpattern, so as to detect when an empty string has been matched by a
--subpattern - to break infinite loops. */
--
--typedef struct eptrblock {
-- struct eptrblock *prev;
-- const uschar *saved_eptr;
--} eptrblock;
--
--/* Flag bits for the match() function */
--
--#define match_condassert 0x01 /* Called to check a condition assertion */
--#define match_isgroup 0x02 /* Set if start of bracketed group */
--
--
--
--/*************************************************
--* Global variables *
--*************************************************/
--
--/* PCRE is thread-clean and doesn't use any global variables in the normal
--sense. However, it calls memory allocation and free functions via the two
--indirections below, which are can be changed by the caller, but are shared
--between all threads. */
--
--void *(*pcre_malloc)(size_t) = malloc;
--void (*pcre_free)(void *) = free;
--
--
--
--/*************************************************
--* Macros and tables for character handling *
--*************************************************/
--
--/* When UTF-8 encoding is being used, a character is no longer just a single
--byte. The macros for character handling generate simple sequences when used in
--byte-mode, and more complicated ones for UTF-8 characters. */
--
--#ifndef SUPPORT_UTF8
--#define GETCHARINC(c, eptr) c = *eptr++;
--#define GETCHARLEN(c, eptr, len) c = *eptr;
--#define BACKCHAR(eptr)
--
--#else /* SUPPORT_UTF8 */
--
--/* Get the next UTF-8 character, advancing the pointer */
--
--#define GETCHARINC(c, eptr) \
-- c = *eptr++; \
-- if (md->utf8 && (c & 0xc0) == 0xc0) \
-- { \
-- int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
-- int s = 6*a; \
-- c = (c & utf8_table3[a]) << s; \
-- while (a-- > 0) \
-- { \
-- s -= 6; \
-- c |= (*eptr++ & 0x3f) << s; \
-- } \
-- }
--
--/* Get the next UTF-8 character, not advancing the pointer, setting length */
--
--#define GETCHARLEN(c, eptr, len) \
-- c = *eptr; \
-- len = 1; \
-- if (md->utf8 && (c & 0xc0) == 0xc0) \
-- { \
-- int i; \
-- int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \
-- int s = 6*a; \
-- c = (c & utf8_table3[a]) << s; \
-- for (i = 1; i <= a; i++) \
-- { \
-- s -= 6; \
-- c |= (eptr[i] & 0x3f) << s; \
-- } \
-- len += a; \
-- }
--
--/* If the pointer is not at the start of a character, move it back until
--it is. */
--
--#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--;
--
--#endif
--
--
--
--/*************************************************
--* Default character tables *
--*************************************************/
--
--/* A default set of character tables is included in the PCRE binary. Its source
--is built by the maketables auxiliary program, which uses the default C ctypes
--functions, and put in the file chartables.c. These tables are used by PCRE
--whenever the caller of pcre_compile() does not provide an alternate set of
--tables. */
--
--#include "chartables.c"
--
--
--
--#ifdef SUPPORT_UTF8
--/*************************************************
--* Tables for UTF-8 support *
--*************************************************/
--
--/* These are the breakpoints for different numbers of bytes in a UTF-8
--character. */
--
--static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
--
--/* These are the indicator bits and the mask for the data bits to set in the
--first byte of a character, indexed by the number of additional bytes. */
--
--static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
--static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
--
--/* Table of the number of extra characters, indexed by the first character
--masked with 0x3f. The highest number for a valid UTF-8 character is in fact
--0x3d. */
--
--static uschar utf8_table4[] = {
-- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-- 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
--
--
--/*************************************************
--* Convert character value to UTF-8 *
--*************************************************/
--
--/* This function takes an integer value in the range 0 - 0x7fffffff
--and encodes it as a UTF-8 character in 0 to 6 bytes.
--
--Arguments:
-- cvalue the character value
-- buffer pointer to buffer for result - at least 6 bytes long
--
--Returns: number of characters placed in the buffer
--*/
--
--static int
--ord2utf8(int cvalue, uschar *buffer)
--{
--register int i, j;
--for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
-- if (cvalue <= utf8_table1[i]) break;
--buffer += i;
--for (j = i; j > 0; j--)
-- {
-- *buffer-- = 0x80 | (cvalue & 0x3f);
-- cvalue >>= 6;
-- }
--*buffer = utf8_table2[i] | cvalue;
--return i + 1;
--}
--#endif
--
--
--
--/*************************************************
--* Return version string *
--*************************************************/
--
--#define STRING(a) # a
--#define XSTRING(s) STRING(s)
--
--const char *
--pcre_version(void)
--{
--return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
--}
--
--
--
--
--/*************************************************
--* (Obsolete) Return info about compiled pattern *
--*************************************************/
--
--/* This is the original "info" function. It picks potentially useful data out
--of the private structure, but its interface was too rigid. It remains for
--backwards compatibility. The public options are passed back in an int - though
--the re->options field has been expanded to a long int, all the public options
--at the low end of it, and so even on 16-bit systems this will still be OK.
--Therefore, I haven't changed the API for pcre_info().
--
--Arguments:
-- external_re points to compiled code
-- optptr where to pass back the options
-- first_char where to pass back the first character,
-- or -1 if multiline and all branches start ^,
-- or -2 otherwise
--
--Returns: number of capturing subpatterns
-- or negative values on error
--*/
--
--int
--pcre_info(const pcre *external_re, int *optptr, int *first_char)
--{
--const real_pcre *re = (const real_pcre *)external_re;
--if (re == NULL) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS);
--if (first_char != NULL)
-- *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
-- ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
--return re->top_bracket;
--}
--
--
--
--/*************************************************
--* Return info about compiled pattern *
--*************************************************/
--
--/* This is a newer "info" function which has an extensible interface so
--that additional items can be added compatibly.
--
--Arguments:
-- external_re points to compiled code
-- external_study points to study data, or NULL
-- what what information is required
-- where where to put the information
--
--Returns: 0 if data returned, negative on error
--*/
--
--int
--pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what,
-- void *where)
--{
--const real_pcre *re = (const real_pcre *)external_re;
--const real_pcre_extra *study = (const real_pcre_extra *)study_data;
--
--if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--
--switch (what)
-- {
-- case PCRE_INFO_OPTIONS:
-- *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS;
-- break;
--
-- case PCRE_INFO_SIZE:
-- *((size_t *)where) = re->size;
-- break;
--
-- case PCRE_INFO_CAPTURECOUNT:
-- *((int *)where) = re->top_bracket;
-- break;
--
-- case PCRE_INFO_BACKREFMAX:
-- *((int *)where) = re->top_backref;
-- break;
--
-- case PCRE_INFO_FIRSTCHAR:
-- *((int *)where) =
-- ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
-- ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
-- break;
--
-- case PCRE_INFO_FIRSTTABLE:
-- *((const uschar **)where) =
-- (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)?
-- study->start_bits : NULL;
-- break;
--
-- case PCRE_INFO_LASTLITERAL:
-- *((int *)where) =
-- ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1;
-- break;
--
-- default: return PCRE_ERROR_BADOPTION;
-- }
--
--return 0;
--}
--
--
--
--#ifdef DEBUG
--/*************************************************
--* Debugging function to print chars *
--*************************************************/
--
--/* Print a sequence of chars in printable format, stopping at the end of the
--subject if the requested.
--
--Arguments:
-- p points to characters
-- length number to print
-- is_subject TRUE if printing from within md->start_subject
-- md pointer to matching data block, if is_subject is TRUE
--
--Returns: nothing
--*/
--
--static void
--pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
--{
--int c;
--if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
--while (length-- > 0)
-- if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c);
--}
--#endif
--
--
--
--
--/*************************************************
--* Handle escapes *
--*************************************************/
--
--/* This function is called when a \ has been encountered. It either returns a
--positive value for a simple escape such as \n, or a negative value which
--encodes one of the more complicated things such as \d. When UTF-8 is enabled,
--a positive value greater than 255 may be returned. On entry, ptr is pointing at
--the \. On exit, it is on the final character of the escape sequence.
--
--Arguments:
-- ptrptr points to the pattern position pointer
-- errorptr points to the pointer to the error message
-- bracount number of previous extracting brackets
-- options the options bits
-- isclass TRUE if inside a character class
-- cd pointer to char tables block
--
--Returns: zero or positive => a data character
-- negative => a special escape sequence
-- on error, errorptr is set
--*/
--
--static int
--check_escape(const uschar **ptrptr, const char **errorptr, int bracount,
-- int options, BOOL isclass, compile_data *cd)
--{
--const uschar *ptr = *ptrptr;
--int c, i;
--
--/* If backslash is at the end of the pattern, it's an error. */
--
--c = *(++ptr);
--if (c == 0) *errorptr = ERR1;
--
--/* Digits or letters may have special meaning; all others are literals. */
--
--else if (c < '0' || c > 'z') {}
--
--/* Do an initial lookup in a table. A non-zero result is something that can be
--returned immediately. Otherwise further processing may be required. */
--
--else if ((i = escapes[c - '0']) != 0) c = i;
--
--/* Escapes that need further processing, or are illegal. */
--
--else
-- {
-- const uschar *oldptr;
-- switch (c)
-- {
-- /* The handling of escape sequences consisting of a string of digits
-- starting with one that is not zero is not straightforward. By experiment,
-- the way Perl works seems to be as follows:
--
-- Outside a character class, the digits are read as a decimal number. If the
-- number is less than 10, or if there are that many previous extracting
-- left brackets, then it is a back reference. Otherwise, up to three octal
-- digits are read to form an escaped byte. Thus \123 is likely to be octal
-- 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal
-- value is greater than 377, the least significant 8 bits are taken. Inside a
-- character class, \ followed by a digit is always an octal number. */
--
-- case '1': case '2': case '3': case '4': case '5':
-- case '6': case '7': case '8': case '9':
--
-- if (!isclass)
-- {
-- oldptr = ptr;
-- c -= '0';
-- while ((cd->ctypes[ptr[1]] & ctype_digit) != 0)
-- c = c * 10 + *(++ptr) - '0';
-- if (c < 10 || c <= bracount)
-- {
-- c = -(ESC_REF + c);
-- break;
-- }
-- ptr = oldptr; /* Put the pointer back and fall through */
-- }
--
-- /* Handle an octal number following \. If the first digit is 8 or 9, Perl
-- generates a binary zero byte and treats the digit as a following literal.
-- Thus we have to pull back the pointer by one. */
--
-- if ((c = *ptr) >= '8')
-- {
-- ptr--;
-- c = 0;
-- break;
-- }
--
-- /* \0 always starts an octal number, but we may drop through to here with a
-- larger first octal digit. */
--
-- case '0':
-- c -= '0';
-- while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 &&
-- ptr[1] != '8' && ptr[1] != '9')
-- c = c * 8 + *(++ptr) - '0';
-- c &= 255; /* Take least significant 8 bits */
-- break;
--
-- /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number
-- which can be greater than 0xff, but only if the ddd are hex digits. */
--
-- case 'x':
--#ifdef SUPPORT_UTF8
-- if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
-- {
-- const uschar *pt = ptr + 2;
-- register int count = 0;
-- c = 0;
-- while ((cd->ctypes[*pt] & ctype_xdigit) != 0)
-- {
-- count++;
-- c = c * 16 + cd->lcc[*pt] -
-- (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W');
-- pt++;
-- }
-- if (*pt == '}')
-- {
-- if (c < 0 || count > 8) *errorptr = ERR34;
-- ptr = pt;
-- break;
-- }
-- /* If the sequence of hex digits does not end with '}', then we don't
-- recognize this construct; fall through to the normal \x handling. */
-- }
--#endif
--
-- /* Read just a single hex char */
--
-- c = 0;
-- while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0)
-- {
-- ptr++;
-- c = c * 16 + cd->lcc[*ptr] -
-- (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W');
-- }
-- break;
--
-- /* Other special escapes not starting with a digit are straightforward */
--
-- case 'c':
-- c = *(++ptr);
-- if (c == 0)
-- {
-- *errorptr = ERR2;
-- return 0;
-- }
--
-- /* A letter is upper-cased; then the 0x40 bit is flipped */
--
-- if (c >= 'a' && c <= 'z') c = cd->fcc[c];
-- c ^= 0x40;
-- break;
--
-- /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
-- other alphameric following \ is an error if PCRE_EXTRA was set; otherwise,
-- for Perl compatibility, it is a literal. This code looks a bit odd, but
-- there used to be some cases other than the default, and there may be again
-- in future, so I haven't "optimized" it. */
--
-- default:
-- if ((options & PCRE_EXTRA) != 0) switch(c)
-- {
-- default:
-- *errorptr = ERR3;
-- break;
-- }
-- break;
-- }
-- }
--
--*ptrptr = ptr;
--return c;
--}
--
--
--
--/*************************************************
--* Check for counted repeat *
--*************************************************/
--
--/* This function is called when a '{' is encountered in a place where it might
--start a quantifier. It looks ahead to see if it really is a quantifier or not.
--It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
--where the ddds are digits.
--
--Arguments:
-- p pointer to the first char after '{'
-- cd pointer to char tables block
--
--Returns: TRUE or FALSE
--*/
--
--static BOOL
--is_counted_repeat(const uschar *p, compile_data *cd)
--{
--if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
--while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
--if (*p == '}') return TRUE;
--
--if (*p++ != ',') return FALSE;
--if (*p == '}') return TRUE;
--
--if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
--while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
--return (*p == '}');
--}
--
--
--
--/*************************************************
--* Read repeat counts *
--*************************************************/
--
--/* Read an item of the form {n,m} and return the values. This is called only
--after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
--so the syntax is guaranteed to be correct, but we need to check the values.
--
--Arguments:
-- p pointer to first char after '{'
-- minp pointer to int for min
-- maxp pointer to int for max
-- returned as -1 if no max
-- errorptr points to pointer to error message
-- cd pointer to character tables clock
--
--Returns: pointer to '}' on success;
-- current ptr on error, with errorptr set
--*/
--
--static const uschar *
--read_repeat_counts(const uschar *p, int *minp, int *maxp,
-- const char **errorptr, compile_data *cd)
--{
--int min = 0;
--int max = -1;
--
--/* Read the minimum value and do a paranoid check: a negative value indicates
--an integer overflow. */
--
--while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
--
--if (min < 0 || min > 65535) {
-- *errorptr = ERR5;
-- return p;
--}
--/* Read the maximum value if there is one, and again do a paranoid on its size.
--Also, max must not be less than min. */
--
--if (*p == '}') max = min; else
-- {
-- if (*(++p) != '}')
-- {
-- max = 0;
-- while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
-- if (max < 0 || max > 65535)
-- {
-- *errorptr = ERR5;
-- return p;
-- }
-- if (max < min)
-- {
-- *errorptr = ERR4;
-- return p;
-- }
-- }
-- }
--
--/* Fill in the required variables, and pass back the pointer to the terminating
--'}'. */
--
--*minp = min;
--*maxp = max;
--return p;
--}
--
--
--
--/*************************************************
--* Find the fixed length of a pattern *
--*************************************************/
--
--/* Scan a pattern and compute the fixed length of subject that will match it,
--if the length is fixed. This is needed for dealing with backward assertions.
--
--Arguments:
-- code points to the start of the pattern (the bracket)
-- options the compiling options
--
--Returns: the fixed length, or -1 if there is no fixed length
--*/
--
--static int
--find_fixedlength(uschar *code, int options)
--{
--int length = -1;
--
--register int branchlength = 0;
--register uschar *cc = code + 3;
--
--/* Scan along the opcodes for this branch. If we get to the end of the
--branch, check the length against that of the other branches. */
--
--for (;;)
-- {
-- int d;
-- register int op = *cc;
-- if (op >= OP_BRA) op = OP_BRA;
--
-- switch (op)
-- {
-- case OP_BRA:
-- case OP_ONCE:
-- case OP_COND:
-- d = find_fixedlength(cc, options);
-- if (d < 0) return -1;
-- branchlength += d;
-- do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
-- cc += 3;
-- break;
--
-- /* Reached end of a branch; if it's a ket it is the end of a nested
-- call. If it's ALT it is an alternation in a nested call. If it is
-- END it's the end of the outer call. All can be handled by the same code. */
--
-- case OP_ALT:
-- case OP_KET:
-- case OP_KETRMAX:
-- case OP_KETRMIN:
-- case OP_END:
-- if (length < 0) length = branchlength;
-- else if (length != branchlength) return -1;
-- if (*cc != OP_ALT) return length;
-- cc += 3;
-- branchlength = 0;
-- break;
--
-- /* Skip over assertive subpatterns */
--
-- case OP_ASSERT:
-- case OP_ASSERT_NOT:
-- case OP_ASSERTBACK:
-- case OP_ASSERTBACK_NOT:
-- do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
-- cc += 3;
-- break;
--
-- /* Skip over things that don't match chars */
--
-- case OP_REVERSE:
-- case OP_BRANUMBER:
-- case OP_CREF:
-- cc++;
-- /* Fall through */
--
-- case OP_OPT:
-- cc++;
-- /* Fall through */
--
-- case OP_SOD:
-- case OP_EOD:
-- case OP_EODN:
-- case OP_CIRC:
-- case OP_DOLL:
-- case OP_NOT_WORD_BOUNDARY:
-- case OP_WORD_BOUNDARY:
-- cc++;
-- break;
--
-- /* Handle char strings. In UTF-8 mode we must count characters, not bytes.
-- This requires a scan of the string, unfortunately. We assume valid UTF-8
-- strings, so all we do is reduce the length by one for byte whose bits are
-- 10xxxxxx. */
--
-- case OP_CHARS:
-- branchlength += *(++cc);
--#ifdef SUPPORT_UTF8
-- for (d = 1; d <= *cc; d++)
-- if ((cc[d] & 0xc0) == 0x80) branchlength--;
--#endif
-- cc += *cc + 1;
-- break;
--
-- /* Handle exact repetitions */
--
-- case OP_EXACT:
-- case OP_TYPEEXACT:
-- branchlength += (cc[1] << 8) + cc[2];
-- cc += 4;
-- break;
--
-- /* Handle single-char matchers */
--
-- case OP_NOT_DIGIT:
-- case OP_DIGIT:
-- case OP_NOT_WHITESPACE:
-- case OP_WHITESPACE:
-- case OP_NOT_WORDCHAR:
-- case OP_WORDCHAR:
-- case OP_ANY:
-- branchlength++;
-- cc++;
-- break;
--
--
-- /* Check a class for variable quantification */
--
-- case OP_CLASS:
-- cc += 33;
--
-- switch (*cc)
-- {
-- case OP_CRSTAR:
-- case OP_CRMINSTAR:
-- case OP_CRQUERY:
-- case OP_CRMINQUERY:
-- return -1;
--
-- case OP_CRRANGE:
-- case OP_CRMINRANGE:
-- if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1;
-- branchlength += (cc[1] << 8) + cc[2];
-- cc += 5;
-- break;
--
-- default:
-- branchlength++;
-- }
-- break;
--
-- /* Anything else is variable length */
--
-- default:
-- return -1;
-- }
-- }
--/* Control never gets here */
--}
--
--
--
--
--/*************************************************
--* Check for POSIX class syntax *
--*************************************************/
--
--/* This function is called when the sequence "[:" or "[." or "[=" is
--encountered in a character class. It checks whether this is followed by an
--optional ^ and then a sequence of letters, terminated by a matching ":]" or
--".]" or "=]".
--
--Argument:
-- ptr pointer to the initial [
-- endptr where to return the end pointer
-- cd pointer to compile data
--
--Returns: TRUE or FALSE
--*/
--
--static BOOL
--check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd)
--{
--int terminator; /* Don't combine these lines; the Solaris cc */
--terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */
--if (*(++ptr) == '^') ptr++;
--while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
--if (*ptr == terminator && ptr[1] == ']')
-- {
-- *endptr = ptr;
-- return TRUE;
-- }
--return FALSE;
--}
--
--
--
--
--/*************************************************
--* Check POSIX class name *
--*************************************************/
--
--/* This function is called to check the name given in a POSIX-style class entry
--such as [:alnum:].
--
--Arguments:
-- ptr points to the first letter
-- len the length of the name
--
--Returns: a value representing the name, or -1 if unknown
--*/
--
--static int
--check_posix_name(const uschar *ptr, int len)
--{
--register int yield = 0;
--while (posix_name_lengths[yield] != 0)
-- {
-- if (len == posix_name_lengths[yield] &&
-- strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield;
-- yield++;
-- }
--return -1;
--}
--
--
--
--
--/*************************************************
--* Compile one branch *
--*************************************************/
--
--/* Scan the pattern, compiling it into the code vector.
--
--Arguments:
-- options the option bits
-- brackets points to number of extracting brackets used
-- code points to the pointer to the current code point
-- ptrptr points to the current pattern pointer
-- errorptr points to pointer to error message
-- optchanged set to the value of the last OP_OPT item compiled
-- reqchar set to the last literal character required, else -1
-- countlits set to count of mandatory literal characters
-- cd contains pointers to tables
--
--Returns: TRUE on success
-- FALSE, with *errorptr set on error
--*/
--
--static BOOL
--compile_branch(int options, int *brackets, uschar **codeptr,
-- const uschar **ptrptr, const char **errorptr, int *optchanged,
-- int *reqchar, int *countlits, compile_data *cd)
--{
--int repeat_type, op_type;
--int repeat_min, repeat_max;
--int bravalue, length;
--int greedy_default, greedy_non_default;
--int prevreqchar;
--int condcount = 0;
--int subcountlits = 0;
--register int c;
--register uschar *code = *codeptr;
--uschar *tempcode;
--const uschar *ptr = *ptrptr;
--const uschar *tempptr;
--uschar *previous = NULL;
--uschar class[32];
--
--/* Set up the default and non-default settings for greediness */
--
--greedy_default = ((options & PCRE_UNGREEDY) != 0);
--greedy_non_default = greedy_default ^ 1;
--
--/* Initialize no required char, and count of literals */
--
--*reqchar = prevreqchar = -1;
--*countlits = 0;
--
--/* Switch on next character until the end of the branch */
--
--for (;; ptr++)
-- {
-- BOOL negate_class;
-- int class_charcount;
-- int class_lastchar;
-- int newoptions;
-- int skipbytes;
-- int subreqchar;
--
-- c = *ptr;
-- if ((options & PCRE_EXTENDED) != 0)
-- {
-- if ((cd->ctypes[c] & ctype_space) != 0) continue;
-- if (c == '#')
-- {
-- /* The space before the ; is to avoid a warning on a silly compiler
-- on the Macintosh. */
-- while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
-- continue;
-- }
-- }
--
-- switch(c)
-- {
-- /* The branch terminates at end of string, |, or ). */
--
-- case 0:
-- case '|':
-- case ')':
-- *codeptr = code;
-- *ptrptr = ptr;
-- return TRUE;
--
-- /* Handle single-character metacharacters */
--
-- case '^':
-- previous = NULL;
-- *code++ = OP_CIRC;
-- break;
--
-- case '$':
-- previous = NULL;
-- *code++ = OP_DOLL;
-- break;
--
-- case '.':
-- previous = code;
-- *code++ = OP_ANY;
-- break;
--
-- /* Character classes. These always build a 32-byte bitmap of the permitted
-- characters, except in the special case where there is only one character.
-- For negated classes, we build the map as usual, then invert it at the end.
-- */
--
-- case '[':
-- previous = code;
-- *code++ = OP_CLASS;
--
-- /* If the first character is '^', set the negation flag and skip it. */
--
-- if ((c = *(++ptr)) == '^')
-- {
-- negate_class = TRUE;
-- c = *(++ptr);
-- }
-- else negate_class = FALSE;
--
-- /* Keep a count of chars so that we can optimize the case of just a single
-- character. */
--
-- class_charcount = 0;
-- class_lastchar = -1;
--
-- /* Initialize the 32-char bit map to all zeros. We have to build the
-- map in a temporary bit of store, in case the class contains only 1
-- character, because in that case the compiled code doesn't use the
-- bit map. */
--
-- memset(class, 0, 32 * sizeof(uschar));
--
-- /* Process characters until ] is reached. By writing this as a "do" it
-- means that an initial ] is taken as a data character. */
--
-- do
-- {
-- if (c == 0)
-- {
-- *errorptr = ERR6;
-- goto FAILED;
-- }
--
-- /* Handle POSIX class names. Perl allows a negation extension of the
-- form [:^name]. A square bracket that doesn't match the syntax is
-- treated as a literal. We also recognize the POSIX constructions
-- [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
-- 5.6 does. */
--
-- if (c == '[' &&
-- (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
-- check_posix_syntax(ptr, &tempptr, cd))
-- {
-- BOOL local_negate = FALSE;
-- int posix_class, i;
-- register const uschar *cbits = cd->cbits;
--
-- if (ptr[1] != ':')
-- {
-- *errorptr = ERR31;
-- goto FAILED;
-- }
--
-- ptr += 2;
-- if (*ptr == '^')
-- {
-- local_negate = TRUE;
-- ptr++;
-- }
--
-- posix_class = check_posix_name(ptr, tempptr - ptr);
-- if (posix_class < 0)
-- {
-- *errorptr = ERR30;
-- goto FAILED;
-- }
--
-- /* If matching is caseless, upper and lower are converted to
-- alpha. This relies on the fact that the class table starts with
-- alpha, lower, upper as the first 3 entries. */
--
-- if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
-- posix_class = 0;
--
-- /* Or into the map we are building up to 3 of the static class
-- tables, or their negations. */
--
-- posix_class *= 3;
-- for (i = 0; i < 3; i++)
-- {
-- int taboffset = posix_class_maps[posix_class + i];
-- if (taboffset < 0) break;
-- if (local_negate)
-- for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset];
-- else
-- for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset];
-- }
--
-- ptr = tempptr + 1;
-- class_charcount = 10; /* Set > 1; assumes more than 1 per class */
-- continue;
-- }
--
-- /* Backslash may introduce a single character, or it may introduce one
-- of the specials, which just set a flag. Escaped items are checked for
-- validity in the pre-compiling pass. The sequence \b is a special case.
-- Inside a class (and only there) it is treated as backspace. Elsewhere
-- it marks a word boundary. Other escapes have preset maps ready to
-- or into the one we are building. We assume they have more than one
-- character in them, so set class_count bigger than one. */
--
-- if (c == '\\')
-- {
-- c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
-- if (-c == ESC_b) c = '\b';
-- else if (c < 0)
-- {
-- register const uschar *cbits = cd->cbits;
-- class_charcount = 10;
-- switch (-c)
-- {
-- case ESC_d:
-- for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit];
-- continue;
--
-- case ESC_D:
-- for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit];
-- continue;
--
-- case ESC_w:
-- for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word];
-- continue;
--
-- case ESC_W:
-- for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word];
-- continue;
--
-- case ESC_s:
-- for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space];
-- continue;
--
-- case ESC_S:
-- for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space];
-- continue;
--
-- default:
-- *errorptr = ERR7;
-- goto FAILED;
-- }
-- }
--
-- /* Fall through if single character, but don't at present allow
-- chars > 255 in UTF-8 mode. */
--
--#ifdef SUPPORT_UTF8
-- if (c > 255)
-- {
-- *errorptr = ERR33;
-- goto FAILED;
-- }
--#endif
-- }
--
-- /* A single character may be followed by '-' to form a range. However,
-- Perl does not permit ']' to be the end of the range. A '-' character
-- here is treated as a literal. */
--
-- if (ptr[1] == '-' && ptr[2] != ']')
-- {
-- int d;
-- ptr += 2;
-- d = *ptr;
--
-- if (d == 0)
-- {
-- *errorptr = ERR6;
-- goto FAILED;
-- }
--
-- /* The second part of a range can be a single-character escape, but
-- not any of the other escapes. Perl 5.6 treats a hyphen as a literal
-- in such circumstances. */
--
-- if (d == '\\')
-- {
-- const uschar *oldptr = ptr;
-- d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
--
--#ifdef SUPPORT_UTF8
-- if (d > 255)
-- {
-- *errorptr = ERR33;
-- goto FAILED;
-- }
--#endif
-- /* \b is backslash; any other special means the '-' was literal */
--
-- if (d < 0)
-- {
-- if (d == -ESC_b) d = '\b'; else
-- {
-- ptr = oldptr - 2;
-- goto SINGLE_CHARACTER; /* A few lines below */
-- }
-- }
-- }
--
-- if (d < c)
-- {
-- *errorptr = ERR8;
-- goto FAILED;
-- }
--
-- for (; c <= d; c++)
-- {
-- class[c/8] |= (1 << (c&7));
-- if ((options & PCRE_CASELESS) != 0)
-- {
-- int uc = cd->fcc[c]; /* flip case */
-- class[uc/8] |= (1 << (uc&7));
-- }
-- class_charcount++; /* in case a one-char range */
-- class_lastchar = c;
-- }
-- continue; /* Go get the next char in the class */
-- }
--
-- /* Handle a lone single character - we can get here for a normal
-- non-escape char, or after \ that introduces a single character. */
--
-- SINGLE_CHARACTER:
--
-- class [c/8] |= (1 << (c&7));
-- if ((options & PCRE_CASELESS) != 0)
-- {
-- c = cd->fcc[c]; /* flip case */
-- class[c/8] |= (1 << (c&7));
-- }
-- class_charcount++;
-- class_lastchar = c;
-- }
--
-- /* Loop until ']' reached; the check for end of string happens inside the
-- loop. This "while" is the end of the "do" above. */
--
-- while ((c = *(++ptr)) != ']');
--
-- /* If class_charcount is 1 and class_lastchar is not negative, we saw
-- precisely one character. This doesn't need the whole 32-byte bit map.
-- We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if
-- it's negative. */
--
-- if (class_charcount == 1 && class_lastchar >= 0)
-- {
-- if (negate_class)
-- {
-- code[-1] = OP_NOT;
-- }
-- else
-- {
-- code[-1] = OP_CHARS;
-- *code++ = 1;
-- }
-- *code++ = class_lastchar;
-- }
--
-- /* Otherwise, negate the 32-byte map if necessary, and copy it into
-- the code vector. */
--
-- else
-- {
-- if (negate_class)
-- for (c = 0; c < 32; c++) code[c] = ~class[c];
-- else
-- memcpy(code, class, 32);
-- code += 32;
-- }
-- break;
--
-- /* Various kinds of repeat */
--
-- case '{':
-- if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR;
-- ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd);
-- if (*errorptr != NULL) goto FAILED;
-- goto REPEAT;
--
-- case '*':
-- repeat_min = 0;
-- repeat_max = -1;
-- goto REPEAT;
--
-- case '+':
-- repeat_min = 1;
-- repeat_max = -1;
-- goto REPEAT;
--
-- case '?':
-- repeat_min = 0;
-- repeat_max = 1;
--
-- REPEAT:
-- if (previous == NULL)
-- {
-- *errorptr = ERR9;
-- goto FAILED;
-- }
--
-- /* If the next character is '?' this is a minimizing repeat, by default,
-- but if PCRE_UNGREEDY is set, it works the other way round. Advance to the
-- next character. */
--
-- if (ptr[1] == '?')
-- { repeat_type = greedy_non_default; ptr++; }
-- else repeat_type = greedy_default;
--
-- /* If previous was a string of characters, chop off the last one and use it
-- as the subject of the repeat. If there was only one character, we can
-- abolish the previous item altogether. A repeat with a zero minimum wipes
-- out any reqchar setting, backing up to the previous value. We must also
-- adjust the countlits value. */
--
-- if (*previous == OP_CHARS)
-- {
-- int len = previous[1];
--
-- if (repeat_min == 0) *reqchar = prevreqchar;
-- *countlits += repeat_min - 1;
--
-- if (len == 1)
-- {
-- c = previous[2];
-- code = previous;
-- }
-- else
-- {
-- c = previous[len+1];
-- previous[1]--;
-- code--;
-- }
-- op_type = 0; /* Use single-char op codes */
-- goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */
-- }
--
-- /* If previous was a single negated character ([^a] or similar), we use
-- one of the special opcodes, replacing it. The code is shared with single-
-- character repeats by adding a suitable offset into repeat_type. */
--
-- else if ((int)*previous == OP_NOT)
-- {
-- op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */
-- c = previous[1];
-- code = previous;
-- goto OUTPUT_SINGLE_REPEAT;
-- }
--
-- /* If previous was a character type match (\d or similar), abolish it and
-- create a suitable repeat item. The code is shared with single-character
-- repeats by adding a suitable offset into repeat_type. */
--
-- else if ((int)*previous < OP_EODN || *previous == OP_ANY)
-- {
-- op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
-- c = *previous;
-- code = previous;
--
-- OUTPUT_SINGLE_REPEAT:
--
-- /* If the maximum is zero then the minimum must also be zero; Perl allows
-- this case, so we do too - by simply omitting the item altogether. */
--
-- if (repeat_max == 0) goto END_REPEAT;
--
-- /* Combine the op_type with the repeat_type */
--
-- repeat_type += op_type;
--
-- /* A minimum of zero is handled either as the special case * or ?, or as
-- an UPTO, with the maximum given. */
--
-- if (repeat_min == 0)
-- {
-- if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
-- else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
-- else
-- {
-- *code++ = OP_UPTO + repeat_type;
-- *code++ = repeat_max >> 8;
-- *code++ = (repeat_max & 255);
-- }
-- }
--
-- /* The case {1,} is handled as the special case + */
--
-- else if (repeat_min == 1 && repeat_max == -1)
-- *code++ = OP_PLUS + repeat_type;
--
-- /* The case {n,n} is just an EXACT, while the general case {n,m} is
-- handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */
--
-- else
-- {
-- if (repeat_min != 1)
-- {
-- *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */
-- *code++ = repeat_min >> 8;
-- *code++ = (repeat_min & 255);
-- }
--
-- /* If the mininum is 1 and the previous item was a character string,
-- we either have to put back the item that got cancelled if the string
-- length was 1, or add the character back onto the end of a longer
-- string. For a character type nothing need be done; it will just get
-- put back naturally. Note that the final character is always going to
-- get added below. */
--
-- else if (*previous == OP_CHARS)
-- {
-- if (code == previous) code += 2; else previous[1]++;
-- }
--
-- /* For a single negated character we also have to put back the
-- item that got cancelled. */
--
-- else if (*previous == OP_NOT) code++;
--
-- /* If the maximum is unlimited, insert an OP_STAR. */
--
-- if (repeat_max < 0)
-- {
-- *code++ = c;
-- *code++ = OP_STAR + repeat_type;
-- }
--
-- /* Else insert an UPTO if the max is greater than the min. */
--
-- else if (repeat_max != repeat_min)
-- {
-- *code++ = c;
-- repeat_max -= repeat_min;
-- *code++ = OP_UPTO + repeat_type;
-- *code++ = repeat_max >> 8;
-- *code++ = (repeat_max & 255);
-- }
-- }
--
-- /* The character or character type itself comes last in all cases. */
--
-- *code++ = c;
-- }
--
-- /* If previous was a character class or a back reference, we put the repeat
-- stuff after it, but just skip the item if the repeat was {0,0}. */
--
-- else if (*previous == OP_CLASS || *previous == OP_REF)
-- {
-- if (repeat_max == 0)
-- {
-- code = previous;
-- goto END_REPEAT;
-- }
-- if (repeat_min == 0 && repeat_max == -1)
-- *code++ = OP_CRSTAR + repeat_type;
-- else if (repeat_min == 1 && repeat_max == -1)
-- *code++ = OP_CRPLUS + repeat_type;
-- else if (repeat_min == 0 && repeat_max == 1)
-- *code++ = OP_CRQUERY + repeat_type;
-- else
-- {
-- *code++ = OP_CRRANGE + repeat_type;
-- *code++ = repeat_min >> 8;
-- *code++ = repeat_min & 255;
-- if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */
-- *code++ = repeat_max >> 8;
-- *code++ = repeat_max & 255;
-- }
-- }
--
-- /* If previous was a bracket group, we may have to replicate it in certain
-- cases. */
--
-- else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE ||
-- (int)*previous == OP_COND)
-- {
-- register int i;
-- int ketoffset = 0;
-- int len = code - previous;
-- uschar *bralink = NULL;
--
-- /* If the maximum repeat count is unlimited, find the end of the bracket
-- by scanning through from the start, and compute the offset back to it
-- from the current code pointer. There may be an OP_OPT setting following
-- the final KET, so we can't find the end just by going back from the code
-- pointer. */
--
-- if (repeat_max == -1)
-- {
-- register uschar *ket = previous;
-- do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET);
-- ketoffset = code - ket;
-- }
--
-- /* The case of a zero minimum is special because of the need to stick
-- OP_BRAZERO in front of it, and because the group appears once in the
-- data, whereas in other cases it appears the minimum number of times. For
-- this reason, it is simplest to treat this case separately, as otherwise
-- the code gets far too messy. There are several special subcases when the
-- minimum is zero. */
--
-- if (repeat_min == 0)
-- {
-- /* If we set up a required char from the bracket, we must back off
-- to the previous value and reset the countlits value too. */
--
-- if (subcountlits > 0)
-- {
-- *reqchar = prevreqchar;
-- *countlits -= subcountlits;
-- }
--
-- /* If the maximum is also zero, we just omit the group from the output
-- altogether. */
--
-- if (repeat_max == 0)
-- {
-- code = previous;
-- goto END_REPEAT;
-- }
--
-- /* If the maximum is 1 or unlimited, we just have to stick in the
-- BRAZERO and do no more at this point. */
--
-- if (repeat_max <= 1)
-- {
-- memmove(previous+1, previous, len);
-- code++;
-- *previous++ = OP_BRAZERO + repeat_type;
-- }
--
-- /* If the maximum is greater than 1 and limited, we have to replicate
-- in a nested fashion, sticking OP_BRAZERO before each set of brackets.
-- The first one has to be handled carefully because it's the original
-- copy, which has to be moved up. The remainder can be handled by code
-- that is common with the non-zero minimum case below. We just have to
-- adjust the value or repeat_max, since one less copy is required. */
--
-- else
-- {
-- int offset;
-- memmove(previous+4, previous, len);
-- code += 4;
-- *previous++ = OP_BRAZERO + repeat_type;
-- *previous++ = OP_BRA;
--
-- /* We chain together the bracket offset fields that have to be
-- filled in later when the ends of the brackets are reached. */
--
-- offset = (bralink == NULL)? 0 : previous - bralink;
-- bralink = previous;
-- *previous++ = offset >> 8;
-- *previous++ = offset & 255;
-- }
--
-- repeat_max--;
-- }
--
-- /* If the minimum is greater than zero, replicate the group as many
-- times as necessary, and adjust the maximum to the number of subsequent
-- copies that we need. */
--
-- else
-- {
-- for (i = 1; i < repeat_min; i++)
-- {
-- memcpy(code, previous, len);
-- code += len;
-- }
-- if (repeat_max > 0) repeat_max -= repeat_min;
-- }
--
-- /* This code is common to both the zero and non-zero minimum cases. If
-- the maximum is limited, it replicates the group in a nested fashion,
-- remembering the bracket starts on a stack. In the case of a zero minimum,
-- the first one was set up above. In all cases the repeat_max now specifies
-- the number of additional copies needed. */
--
-- if (repeat_max >= 0)
-- {
-- for (i = repeat_max - 1; i >= 0; i--)
-- {
-- *code++ = OP_BRAZERO + repeat_type;
--
-- /* All but the final copy start a new nesting, maintaining the
-- chain of brackets outstanding. */
--
-- if (i != 0)
-- {
-- int offset;
-- *code++ = OP_BRA;
-- offset = (bralink == NULL)? 0 : code - bralink;
-- bralink = code;
-- *code++ = offset >> 8;
-- *code++ = offset & 255;
-- }
--
-- memcpy(code, previous, len);
-- code += len;
-- }
--
-- /* Now chain through the pending brackets, and fill in their length
-- fields (which are holding the chain links pro tem). */
--
-- while (bralink != NULL)
-- {
-- int oldlinkoffset;
-- int offset = code - bralink + 1;
-- uschar *bra = code - offset;
-- oldlinkoffset = (bra[1] << 8) + bra[2];
-- bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
-- *code++ = OP_KET;
-- *code++ = bra[1] = offset >> 8;
-- *code++ = bra[2] = (offset & 255);
-- }
-- }
--
-- /* If the maximum is unlimited, set a repeater in the final copy. We
-- can't just offset backwards from the current code point, because we
-- don't know if there's been an options resetting after the ket. The
-- correct offset was computed above. */
--
-- else code[-ketoffset] = OP_KETRMAX + repeat_type;
-- }
--
-- /* Else there's some kind of shambles */
--
-- else
-- {
-- *errorptr = ERR11;
-- goto FAILED;
-- }
--
-- /* In all case we no longer have a previous item. */
--
-- END_REPEAT:
-- previous = NULL;
-- break;
--
--
-- /* Start of nested bracket sub-expression, or comment or lookahead or
-- lookbehind or option setting or condition. First deal with special things
-- that can come after a bracket; all are introduced by ?, and the appearance
-- of any of them means that this is not a referencing group. They were
-- checked for validity in the first pass over the string, so we don't have to
-- check for syntax errors here. */
--
-- case '(':
-- newoptions = options;
-- skipbytes = 0;
--
-- if (*(++ptr) == '?')
-- {
-- int set, unset;
-- int *optset;
--
-- switch (*(++ptr))
-- {
-- case '#': /* Comment; skip to ket */
-- ptr++;
-- while (*ptr != ')') ptr++;
-- continue;
--
-- case ':': /* Non-extracting bracket */
-- bravalue = OP_BRA;
-- ptr++;
-- break;
--
-- case '(':
-- bravalue = OP_COND; /* Conditional group */
-- if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0)
-- {
-- int condref = *ptr - '0';
-- while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
-- if (condref == 0)
-- {
-- *errorptr = ERR35;
-- goto FAILED;
-- }
-- ptr++;
-- code[3] = OP_CREF;
-- code[4] = condref >> 8;
-- code[5] = condref & 255;
-- skipbytes = 3;
-- }
-- else ptr--;
-- break;
--
-- case '=': /* Positive lookahead */
-- bravalue = OP_ASSERT;
-- ptr++;
-- break;
--
-- case '!': /* Negative lookahead */
-- bravalue = OP_ASSERT_NOT;
-- ptr++;
-- break;
--
-- case '<': /* Lookbehinds */
-- switch (*(++ptr))
-- {
-- case '=': /* Positive lookbehind */
-- bravalue = OP_ASSERTBACK;
-- ptr++;
-- break;
--
-- case '!': /* Negative lookbehind */
-- bravalue = OP_ASSERTBACK_NOT;
-- ptr++;
-- break;
--
-- default: /* Syntax error */
-- *errorptr = ERR24;
-- goto FAILED;
-- }
-- break;
--
-- case '>': /* One-time brackets */
-- bravalue = OP_ONCE;
-- ptr++;
-- break;
--
-- case 'R': /* Pattern recursion */
-- *code++ = OP_RECURSE;
-- ptr++;
-- continue;
--
-- default: /* Option setting */
-- set = unset = 0;
-- optset = &set;
--
-- while (*ptr != ')' && *ptr != ':')
-- {
-- switch (*ptr++)
-- {
-- case '-': optset = &unset; break;
--
-- case 'i': *optset |= PCRE_CASELESS; break;
-- case 'm': *optset |= PCRE_MULTILINE; break;
-- case 's': *optset |= PCRE_DOTALL; break;
-- case 'x': *optset |= PCRE_EXTENDED; break;
-- case 'U': *optset |= PCRE_UNGREEDY; break;
-- case 'X': *optset |= PCRE_EXTRA; break;
--
-- default:
-- *errorptr = ERR12;
-- goto FAILED;
-- }
-- }
--
-- /* Set up the changed option bits, but don't change anything yet. */
--
-- newoptions = (options | set) & (~unset);
--
-- /* If the options ended with ')' this is not the start of a nested
-- group with option changes, so the options change at this level. At top
-- level there is nothing else to be done (the options will in fact have
-- been set from the start of compiling as a result of the first pass) but
-- at an inner level we must compile code to change the ims options if
-- necessary, and pass the new setting back so that it can be put at the
-- start of any following branches, and when this group ends, a resetting
-- item can be compiled. */
--
-- if (*ptr == ')')
-- {
-- if ((options & PCRE_INGROUP) != 0 &&
-- (options & PCRE_IMS) != (newoptions & PCRE_IMS))
-- {
-- *code++ = OP_OPT;
-- *code++ = *optchanged = newoptions & PCRE_IMS;
-- }
-- options = newoptions; /* Change options at this level */
-- previous = NULL; /* This item can't be repeated */
-- continue; /* It is complete */
-- }
--
-- /* If the options ended with ':' we are heading into a nested group
-- with possible change of options. Such groups are non-capturing and are
-- not assertions of any kind. All we need to do is skip over the ':';
-- the newoptions value is handled below. */
--
-- bravalue = OP_BRA;
-- ptr++;
-- }
-- }
--
-- /* Else we have a referencing group; adjust the opcode. If the bracket
-- number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
-- arrange for the true number to follow later, in an OP_BRANUMBER item. */
--
-- else
-- {
-- if (++(*brackets) > EXTRACT_BASIC_MAX)
-- {
-- bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
-- code[3] = OP_BRANUMBER;
-- code[4] = *brackets >> 8;
-- code[5] = *brackets & 255;
-- skipbytes = 3;
-- }
-- else bravalue = OP_BRA + *brackets;
-- }
--
-- /* Process nested bracketed re. Assertions may not be repeated, but other
-- kinds can be. We copy code into a non-register variable in order to be able
-- to pass its address because some compilers complain otherwise. Pass in a
-- new setting for the ims options if they have changed. */
--
-- previous = (bravalue >= OP_ONCE)? code : NULL;
-- *code = bravalue;
-- tempcode = code;
--
-- if (!compile_regex(
-- options | PCRE_INGROUP, /* Set for all nested groups */
-- ((options & PCRE_IMS) != (newoptions & PCRE_IMS))?
-- newoptions & PCRE_IMS : -1, /* Pass ims options if changed */
-- brackets, /* Extracting bracket count */
-- &tempcode, /* Where to put code (updated) */
-- &ptr, /* Input pointer (updated) */
-- errorptr, /* Where to put an error message */
-- (bravalue == OP_ASSERTBACK ||
-- bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
-- skipbytes, /* Skip over OP_COND/OP_BRANUMBER */
-- &subreqchar, /* For possible last char */
-- &subcountlits, /* For literal count */
-- cd)) /* Tables block */
-- goto FAILED;
--
-- /* At the end of compiling, code is still pointing to the start of the
-- group, while tempcode has been updated to point past the end of the group
-- and any option resetting that may follow it. The pattern pointer (ptr)
-- is on the bracket. */
--
-- /* If this is a conditional bracket, check that there are no more than
-- two branches in the group. */
--
-- else if (bravalue == OP_COND)
-- {
-- uschar *tc = code;
-- condcount = 0;
--
-- do {
-- condcount++;
-- tc += (tc[1] << 8) | tc[2];
-- }
-- while (*tc != OP_KET);
--
-- if (condcount > 2)
-- {
-- *errorptr = ERR27;
-- goto FAILED;
-- }
-- }
--
-- /* Handle updating of the required character. If the subpattern didn't
-- set one, leave it as it was. Otherwise, update it for normal brackets of
-- all kinds, forward assertions, and conditions with two branches. Don't
-- update the literal count for forward assertions, however. If the bracket
-- is followed by a quantifier with zero repeat, we have to back off. Hence
-- the definition of prevreqchar and subcountlits outside the main loop so
-- that they can be accessed for the back off. */
--
-- if (subreqchar > 0 &&
-- (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT ||
-- (bravalue == OP_COND && condcount == 2)))
-- {
-- prevreqchar = *reqchar;
-- *reqchar = subreqchar;
-- if (bravalue != OP_ASSERT) *countlits += subcountlits;
-- }
--
-- /* Now update the main code pointer to the end of the group. */
--
-- code = tempcode;
--
-- /* Error if hit end of pattern */
--
-- if (*ptr != ')')
-- {
-- *errorptr = ERR14;
-- goto FAILED;
-- }
-- break;
--
-- /* Check \ for being a real metacharacter; if not, fall through and handle
-- it as a data character at the start of a string. Escape items are checked
-- for validity in the pre-compiling pass. */
--
-- case '\\':
-- tempptr = ptr;
-- c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
--
-- /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
-- are arranged to be the negation of the corresponding OP_values. For the
-- back references, the values are ESC_REF plus the reference number. Only
-- back references and those types that consume a character may be repeated.
-- We can test for values between ESC_b and ESC_Z for the latter; this may
-- have to change if any new ones are ever created. */
--
-- if (c < 0)
-- {
-- if (-c >= ESC_REF)
-- {
-- int number = -c - ESC_REF;
-- previous = code;
-- *code++ = OP_REF;
-- *code++ = number >> 8;
-- *code++ = number & 255;
-- }
-- else
-- {
-- previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
-- *code++ = -c;
-- }
-- continue;
-- }
--
-- /* Data character: reset and fall through */
--
-- ptr = tempptr;
-- c = '\\';
--
-- /* Handle a run of data characters until a metacharacter is encountered.
-- The first character is guaranteed not to be whitespace or # when the
-- extended flag is set. */
--
-- NORMAL_CHAR:
-- default:
-- previous = code;
-- *code = OP_CHARS;
-- code += 2;
-- length = 0;
--
-- do
-- {
-- if ((options & PCRE_EXTENDED) != 0)
-- {
-- if ((cd->ctypes[c] & ctype_space) != 0) continue;
-- if (c == '#')
-- {
-- /* The space before the ; is to avoid a warning on a silly compiler
-- on the Macintosh. */
-- while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
-- if (c == 0) break;
-- continue;
-- }
-- }
--
-- /* Backslash may introduce a data char or a metacharacter. Escaped items
-- are checked for validity in the pre-compiling pass. Stop the string
-- before a metaitem. */
--
-- if (c == '\\')
-- {
-- tempptr = ptr;
-- c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
-- if (c < 0) { ptr = tempptr; break; }
--
-- /* If a character is > 127 in UTF-8 mode, we have to turn it into
-- two or more characters in the UTF-8 encoding. */
--
--#ifdef SUPPORT_UTF8
-- if (c > 127 && (options & PCRE_UTF8) != 0)
-- {
-- uschar buffer[8];
-- int len = ord2utf8(c, buffer);
-- for (c = 0; c < len; c++) *code++ = buffer[c];
-- length += len;
-- continue;
-- }
--#endif
-- }
--
-- /* Ordinary character or single-char escape */
--
-- *code++ = c;
-- length++;
-- }
--
-- /* This "while" is the end of the "do" above. */
--
-- while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0);
--
-- /* Update the last character and the count of literals */
--
-- prevreqchar = (length > 1)? code[-2] : *reqchar;
-- *reqchar = code[-1];
-- *countlits += length;
--
-- /* Compute the length and set it in the data vector, and advance to
-- the next state. */
--
-- previous[1] = length;
-- if (length < MAXLIT) ptr--;
-- break;
-- }
-- } /* end of big loop */
--
--/* Control never reaches here by falling through, only by a goto for all the
--error states. Pass back the position in the pattern so that it can be displayed
--to the user for diagnosing the error. */
--
--FAILED:
--*ptrptr = ptr;
--return FALSE;
--}
--
--
--
--
--/*************************************************
--* Compile sequence of alternatives *
--*************************************************/
--
--/* On entry, ptr is pointing past the bracket character, but on return
--it points to the closing bracket, or vertical bar, or end of string.
--The code variable is pointing at the byte into which the BRA operator has been
--stored. If the ims options are changed at the start (for a (?ims: group) or
--during any branch, we need to insert an OP_OPT item at the start of every
--following branch to ensure they get set correctly at run time, and also pass
--the new options into every subsequent branch compile.
--
--Argument:
-- options the option bits
-- optchanged new ims options to set as if (?ims) were at the start, or -1
-- for no change
-- brackets -> int containing the number of extracting brackets used
-- codeptr -> the address of the current code pointer
-- ptrptr -> the address of the current pattern pointer
-- errorptr -> pointer to error message
-- lookbehind TRUE if this is a lookbehind assertion
-- skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER)
-- reqchar -> place to put the last required character, or a negative number
-- countlits -> place to put the shortest literal count of any branch
-- cd points to the data block with tables pointers
--
--Returns: TRUE on success
--*/
--
--static BOOL
--compile_regex(int options, int optchanged, int *brackets, uschar **codeptr,
-- const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes,
-- int *reqchar, int *countlits, compile_data *cd)
--{
--const uschar *ptr = *ptrptr;
--uschar *code = *codeptr;
--uschar *last_branch = code;
--uschar *start_bracket = code;
--uschar *reverse_count = NULL;
--int oldoptions = options & PCRE_IMS;
--int branchreqchar, branchcountlits;
--
--*reqchar = -1;
--*countlits = INT_MAX;
--code += 3 + skipbytes;
--
--/* Loop for each alternative branch */
--
--for (;;)
-- {
-- int length;
--
-- /* Handle change of options */
--
-- if (optchanged >= 0)
-- {
-- *code++ = OP_OPT;
-- *code++ = optchanged;
-- options = (options & ~PCRE_IMS) | optchanged;
-- }
--
-- /* Set up dummy OP_REVERSE if lookbehind assertion */
--
-- if (lookbehind)
-- {
-- *code++ = OP_REVERSE;
-- reverse_count = code;
-- *code++ = 0;
-- *code++ = 0;
-- }
--
-- /* Now compile the branch */
--
-- if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged,
-- &branchreqchar, &branchcountlits, cd))
-- {
-- *ptrptr = ptr;
-- return FALSE;
-- }
--
-- /* Fill in the length of the last branch */
--
-- length = code - last_branch;
-- last_branch[1] = length >> 8;
-- last_branch[2] = length & 255;
--
-- /* Save the last required character if all branches have the same; a current
-- value of -1 means unset, while -2 means "previous branch had no last required
-- char". */
--
-- if (*reqchar != -2)
-- {
-- if (branchreqchar >= 0)
-- {
-- if (*reqchar == -1) *reqchar = branchreqchar;
-- else if (*reqchar != branchreqchar) *reqchar = -2;
-- }
-- else *reqchar = -2;
-- }
--
-- /* Keep the shortest literal count */
--
-- if (branchcountlits < *countlits) *countlits = branchcountlits;
-- DPRINTF(("literal count = %d min=%d\n", branchcountlits, *countlits));
--
-- /* If lookbehind, check that this branch matches a fixed-length string,
-- and put the length into the OP_REVERSE item. Temporarily mark the end of
-- the branch with OP_END. */
--
-- if (lookbehind)
-- {
-- *code = OP_END;
-- length = find_fixedlength(last_branch, options);
-- DPRINTF(("fixed length = %d\n", length));
-- if (length < 0)
-- {
-- *errorptr = ERR25;
-- *ptrptr = ptr;
-- return FALSE;
-- }
-- reverse_count[0] = (length >> 8);
-- reverse_count[1] = length & 255;
-- }
--
-- /* Reached end of expression, either ')' or end of pattern. Insert a
-- terminating ket and the length of the whole bracketed item, and return,
-- leaving the pointer at the terminating char. If any of the ims options
-- were changed inside the group, compile a resetting op-code following. */
--
-- if (*ptr != '|')
-- {
-- length = code - start_bracket;
-- *code++ = OP_KET;
-- *code++ = length >> 8;
-- *code++ = length & 255;
-- if (optchanged >= 0)
-- {
-- *code++ = OP_OPT;
-- *code++ = oldoptions;
-- }
-- *codeptr = code;
-- *ptrptr = ptr;
-- return TRUE;
-- }
--
-- /* Another branch follows; insert an "or" node and advance the pointer. */
--
-- *code = OP_ALT;
-- last_branch = code;
-- code += 3;
-- ptr++;
-- }
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--* Find first significant op code *
--*************************************************/
--
--/* This is called by several functions that scan a compiled expression looking
--for a fixed first character, or an anchoring op code etc. It skips over things
--that do not influence this. For one application, a change of caseless option is
--important.
--
--Arguments:
-- code pointer to the start of the group
-- options pointer to external options
-- optbit the option bit whose changing is significant, or
-- zero if none are
-- optstop TRUE to return on option change, otherwise change the options
-- value and continue
--
--Returns: pointer to the first significant opcode
--*/
--
--static const uschar*
--first_significant_code(const uschar *code, int *options, int optbit,
-- BOOL optstop)
--{
--for (;;)
-- {
-- switch ((int)*code)
-- {
-- case OP_OPT:
-- if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit))
-- {
-- if (optstop) return code;
-- *options = (int)code[1];
-- }
-- code += 2;
-- break;
--
-- case OP_CREF:
-- case OP_BRANUMBER:
-- code += 3;
-- break;
--
-- case OP_WORD_BOUNDARY:
-- case OP_NOT_WORD_BOUNDARY:
-- code++;
-- break;
--
-- case OP_ASSERT_NOT:
-- case OP_ASSERTBACK:
-- case OP_ASSERTBACK_NOT:
-- do code += (code[1] << 8) + code[2]; while (*code == OP_ALT);
-- code += 3;
-- break;
--
-- default:
-- return code;
-- }
-- }
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--* Check for anchored expression *
--*************************************************/
--
--/* Try to find out if this is an anchored regular expression. Consider each
--alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
--all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
--it's anchored. However, if this is a multiline pattern, then only OP_SOD
--counts, since OP_CIRC can match in the middle.
--
--A branch is also implicitly anchored if it starts with .* and DOTALL is set,
--because that will try the rest of the pattern at all possible matching points,
--so there is no point trying them again.
--
--Arguments:
-- code points to start of expression (the bracket)
-- options points to the options setting
--
--Returns: TRUE or FALSE
--*/
--
--static BOOL
--is_anchored(register const uschar *code, int *options)
--{
--do {
-- const uschar *scode = first_significant_code(code + 3, options,
-- PCRE_MULTILINE, FALSE);
-- register int op = *scode;
-- if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
-- { if (!is_anchored(scode, options)) return FALSE; }
-- else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) &&
-- (*options & PCRE_DOTALL) != 0)
-- { if (scode[1] != OP_ANY) return FALSE; }
-- else if (op != OP_SOD &&
-- ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC))
-- return FALSE;
-- code += (code[1] << 8) + code[2];
-- }
--while (*code == OP_ALT);
--return TRUE;
--}
--
--
--
--/*************************************************
--* Check for starting with ^ or .* *
--*************************************************/
--
--/* This is called to find out if every branch starts with ^ or .* so that
--"first char" processing can be done to speed things up in multiline
--matching and for non-DOTALL patterns that start with .* (which must start at
--the beginning or after \n).
--
--Argument: points to start of expression (the bracket)
--Returns: TRUE or FALSE
--*/
--
--static BOOL
--is_startline(const uschar *code)
--{
--do {
-- const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE);
-- register int op = *scode;
-- if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
-- { if (!is_startline(scode)) return FALSE; }
-- else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
-- { if (scode[1] != OP_ANY) return FALSE; }
-- else if (op != OP_CIRC) return FALSE;
-- code += (code[1] << 8) + code[2];
-- }
--while (*code == OP_ALT);
--return TRUE;
--}
--
--
--
--/*************************************************
--* Check for fixed first char *
--*************************************************/
--
--/* Try to find out if there is a fixed first character. This is called for
--unanchored expressions, as it speeds up their processing quite considerably.
--Consider each alternative branch. If they all start with the same char, or with
--a bracket all of whose alternatives start with the same char (recurse ad lib),
--then we return that char, otherwise -1.
--
--Arguments:
-- code points to start of expression (the bracket)
-- options pointer to the options (used to check casing changes)
--
--Returns: -1 or the fixed first char
--*/
--
--static int
--find_firstchar(const uschar *code, int *options)
--{
--register int c = -1;
--do {
-- int d;
-- const uschar *scode = first_significant_code(code + 3, options,
-- PCRE_CASELESS, TRUE);
-- register int op = *scode;
--
-- if (op >= OP_BRA) op = OP_BRA;
--
-- switch(op)
-- {
-- default:
-- return -1;
--
-- case OP_BRA:
-- case OP_ASSERT:
-- case OP_ONCE:
-- case OP_COND:
-- if ((d = find_firstchar(scode, options)) < 0) return -1;
-- if (c < 0) c = d; else if (c != d) return -1;
-- break;
--
-- case OP_EXACT: /* Fall through */
-- scode++;
--
-- case OP_CHARS: /* Fall through */
-- scode++;
--
-- case OP_PLUS:
-- case OP_MINPLUS:
-- if (c < 0) c = scode[1]; else if (c != scode[1]) return -1;
-- break;
-- }
--
-- code += (code[1] << 8) + code[2];
-- }
--while (*code == OP_ALT);
--return c;
--}
--
--
--
--
--
--/*************************************************
--* Compile a Regular Expression *
--*************************************************/
--
--/* This function takes a string and returns a pointer to a block of store
--holding a compiled version of the expression.
--
--Arguments:
-- pattern the regular expression
-- options various option bits
-- errorptr pointer to pointer to error text
-- erroroffset ptr offset in pattern where error was detected
-- tables pointer to character tables or NULL
--
--Returns: pointer to compiled data block, or NULL on error,
-- with errorptr and erroroffset set
--*/
--
--pcre *
--pcre_compile(const char *pattern, int options, const char **errorptr,
-- int *erroroffset, const unsigned char *tables)
--{
--real_pcre *re;
--int length = 3; /* For initial BRA plus length */
--int runlength;
--int c, reqchar, countlits;
--int bracount = 0;
--int top_backref = 0;
--int branch_extra = 0;
--int branch_newextra;
--unsigned int brastackptr = 0;
--size_t size;
--uschar *code;
--const uschar *ptr;
--compile_data compile_block;
--int brastack[BRASTACK_SIZE];
--uschar bralenstack[BRASTACK_SIZE];
--
--#ifdef DEBUG
--uschar *code_base, *code_end;
--#endif
--
--/* Can't support UTF8 unless PCRE has been compiled to include the code. */
--
--#ifndef SUPPORT_UTF8
--if ((options & PCRE_UTF8) != 0)
-- {
-- *errorptr = ERR32;
-- return NULL;
-- }
--#endif
--
--/* We can't pass back an error message if errorptr is NULL; I guess the best we
--can do is just return NULL. */
--
--if (errorptr == NULL) return NULL;
--*errorptr = NULL;
--
--/* However, we can give a message for this error */
--
--if (erroroffset == NULL)
-- {
-- *errorptr = ERR16;
-- return NULL;
-- }
--*erroroffset = 0;
--
--if ((options & ~PUBLIC_OPTIONS) != 0)
-- {
-- *errorptr = ERR17;
-- return NULL;
-- }
--
--/* Set up pointers to the individual character tables */
--
--if (tables == NULL) tables = pcre_default_tables;
--compile_block.lcc = tables + lcc_offset;
--compile_block.fcc = tables + fcc_offset;
--compile_block.cbits = tables + cbits_offset;
--compile_block.ctypes = tables + ctypes_offset;
--
--/* Reflect pattern for debugging output */
--
--DPRINTF(("------------------------------------------------------------------\n"));
--DPRINTF(("%s\n", pattern));
--
--/* The first thing to do is to make a pass over the pattern to compute the
--amount of store required to hold the compiled code. This does not have to be
--perfect as long as errors are overestimates. At the same time we can detect any
--internal flag settings. Make an attempt to correct for any counted white space
--if an "extended" flag setting appears late in the pattern. We can't be so
--clever for #-comments. */
--
--ptr = (const uschar *)(pattern - 1);
--while ((c = *(++ptr)) != 0)
-- {
-- int min, max;
-- int class_charcount;
-- int bracket_length;
--
-- if ((options & PCRE_EXTENDED) != 0)
-- {
-- if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
-- if (c == '#')
-- {
-- /* The space before the ; is to avoid a warning on a silly compiler
-- on the Macintosh. */
-- while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
-- continue;
-- }
-- }
--
-- switch(c)
-- {
-- /* A backslashed item may be an escaped "normal" character or a
-- character type. For a "normal" character, put the pointers and
-- character back so that tests for whitespace etc. in the input
-- are done correctly. */
--
-- case '\\':
-- {
-- const uschar *save_ptr = ptr;
-- c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if (c >= 0)
-- {
-- ptr = save_ptr;
-- c = '\\';
-- goto NORMAL_CHAR;
-- }
-- }
-- length++;
--
-- /* A back reference needs an additional 2 bytes, plus either one or 5
-- bytes for a repeat. We also need to keep the value of the highest
-- back reference. */
--
-- if (c <= -ESC_REF)
-- {
-- int refnum = -c - ESC_REF;
-- if (refnum > top_backref) top_backref = refnum;
-- length += 2; /* For single back reference */
-- if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
-- {
-- ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if ((min == 0 && (max == 1 || max == -1)) ||
-- (min == 1 && max == -1))
-- length++;
-- else length += 5;
-- if (ptr[1] == '?') ptr++;
-- }
-- }
-- continue;
--
-- case '^':
-- case '.':
-- case '$':
-- case '*': /* These repeats won't be after brackets; */
-- case '+': /* those are handled separately */
-- case '?':
-- length++;
-- continue;
--
-- /* This covers the cases of repeats after a single char, metachar, class,
-- or back reference. */
--
-- case '{':
-- if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR;
-- ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if ((min == 0 && (max == 1 || max == -1)) ||
-- (min == 1 && max == -1))
-- length++;
-- else
-- {
-- length--; /* Uncount the original char or metachar */
-- if (min == 1) length++; else if (min > 0) length += 4;
-- if (max > 0) length += 4; else length += 2;
-- }
-- if (ptr[1] == '?') ptr++;
-- continue;
--
-- /* An alternation contains an offset to the next branch or ket. If any ims
-- options changed in the previous branch(es), and/or if we are in a
-- lookbehind assertion, extra space will be needed at the start of the
-- branch. This is handled by branch_extra. */
--
-- case '|':
-- length += 3 + branch_extra;
-- continue;
--
-- /* A character class uses 33 characters. Don't worry about character types
-- that aren't allowed in classes - they'll get picked up during the compile.
-- A character class that contains only one character uses 2 or 3 bytes,
-- depending on whether it is negated or not. Notice this where we can. */
--
-- case '[':
-- class_charcount = 0;
-- if (*(++ptr) == '^') ptr++;
-- do
-- {
-- if (*ptr == '\\')
-- {
-- int ch = check_escape(&ptr, errorptr, bracount, options, TRUE,
-- &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if (-ch == ESC_b) class_charcount++; else class_charcount = 10;
-- }
-- else class_charcount++;
-- ptr++;
-- }
-- while (*ptr != 0 && *ptr != ']');
--
-- /* Repeats for negated single chars are handled by the general code */
--
-- if (class_charcount == 1) length += 3; else
-- {
-- length += 33;
--
-- /* A repeat needs either 1 or 5 bytes. */
--
-- if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
-- {
-- ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if ((min == 0 && (max == 1 || max == -1)) ||
-- (min == 1 && max == -1))
-- length++;
-- else length += 5;
-- if (ptr[1] == '?') ptr++;
-- }
-- }
-- continue;
--
-- /* Brackets may be genuine groups or special things */
--
-- case '(':
-- branch_newextra = 0;
-- bracket_length = 3;
--
-- /* Handle special forms of bracket, which all start (? */
--
-- if (ptr[1] == '?')
-- {
-- int set, unset;
-- int *optset;
--
-- switch (c = ptr[2])
-- {
-- /* Skip over comments entirely */
-- case '#':
-- ptr += 3;
-- while (*ptr != 0 && *ptr != ')') ptr++;
-- if (*ptr == 0)
-- {
-- *errorptr = ERR18;
-- goto PCRE_ERROR_RETURN;
-- }
-- continue;
--
-- /* Non-referencing groups and lookaheads just move the pointer on, and
-- then behave like a non-special bracket, except that they don't increment
-- the count of extracting brackets. Ditto for the "once only" bracket,
-- which is in Perl from version 5.005. */
--
-- case ':':
-- case '=':
-- case '!':
-- case '>':
-- ptr += 2;
-- break;
--
-- /* A recursive call to the regex is an extension, to provide the
-- facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */
--
-- case 'R':
-- if (ptr[3] != ')')
-- {
-- *errorptr = ERR29;
-- goto PCRE_ERROR_RETURN;
-- }
-- ptr += 3;
-- length += 1;
-- break;
--
-- /* Lookbehinds are in Perl from version 5.005 */
--
-- case '<':
-- if (ptr[3] == '=' || ptr[3] == '!')
-- {
-- ptr += 3;
-- branch_newextra = 3;
-- length += 3; /* For the first branch */
-- break;
-- }
-- *errorptr = ERR24;
-- goto PCRE_ERROR_RETURN;
--
-- /* Conditionals are in Perl from version 5.005. The bracket must either
-- be followed by a number (for bracket reference) or by an assertion
-- group. */
--
-- case '(':
-- if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0)
-- {
-- ptr += 4;
-- length += 3;
-- while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++;
-- if (*ptr != ')')
-- {
-- *errorptr = ERR26;
-- goto PCRE_ERROR_RETURN;
-- }
-- }
-- else /* An assertion must follow */
-- {
-- ptr++; /* Can treat like ':' as far as spacing is concerned */
-- if (ptr[2] != '?' ||
-- (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') )
-- {
-- ptr += 2; /* To get right offset in message */
-- *errorptr = ERR28;
-- goto PCRE_ERROR_RETURN;
-- }
-- }
-- break;
--
-- /* Else loop checking valid options until ) is met. Anything else is an
-- error. If we are without any brackets, i.e. at top level, the settings
-- act as if specified in the options, so massage the options immediately.
-- This is for backward compatibility with Perl 5.004. */
--
-- default:
-- set = unset = 0;
-- optset = &set;
-- ptr += 2;
--
-- for (;; ptr++)
-- {
-- c = *ptr;
-- switch (c)
-- {
-- case 'i':
-- *optset |= PCRE_CASELESS;
-- continue;
--
-- case 'm':
-- *optset |= PCRE_MULTILINE;
-- continue;
--
-- case 's':
-- *optset |= PCRE_DOTALL;
-- continue;
--
-- case 'x':
-- *optset |= PCRE_EXTENDED;
-- continue;
--
-- case 'X':
-- *optset |= PCRE_EXTRA;
-- continue;
--
-- case 'U':
-- *optset |= PCRE_UNGREEDY;
-- continue;
--
-- case '-':
-- optset = &unset;
-- continue;
--
-- /* A termination by ')' indicates an options-setting-only item;
-- this is global at top level; otherwise nothing is done here and
-- it is handled during the compiling process on a per-bracket-group
-- basis. */
--
-- case ')':
-- if (brastackptr == 0)
-- {
-- options = (options | set) & (~unset);
-- set = unset = 0; /* To save length */
-- }
-- /* Fall through */
--
-- /* A termination by ':' indicates the start of a nested group with
-- the given options set. This is again handled at compile time, but
-- we must allow for compiled space if any of the ims options are
-- set. We also have to allow for resetting space at the end of
-- the group, which is why 4 is added to the length and not just 2.
-- If there are several changes of options within the same group, this
-- will lead to an over-estimate on the length, but this shouldn't
-- matter very much. We also have to allow for resetting options at
-- the start of any alternations, which we do by setting
-- branch_newextra to 2. Finally, we record whether the case-dependent
-- flag ever changes within the regex. This is used by the "required
-- character" code. */
--
-- case ':':
-- if (((set|unset) & PCRE_IMS) != 0)
-- {
-- length += 4;
-- branch_newextra = 2;
-- if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
-- }
-- goto END_OPTIONS;
--
-- /* Unrecognized option character */
--
-- default:
-- *errorptr = ERR12;
-- goto PCRE_ERROR_RETURN;
-- }
-- }
--
-- /* If we hit a closing bracket, that's it - this is a freestanding
-- option-setting. We need to ensure that branch_extra is updated if
-- necessary. The only values branch_newextra can have here are 0 or 2.
-- If the value is 2, then branch_extra must either be 2 or 5, depending
-- on whether this is a lookbehind group or not. */
--
-- END_OPTIONS:
-- if (c == ')')
-- {
-- if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3))
-- branch_extra += branch_newextra;
-- continue;
-- }
--
-- /* If options were terminated by ':' control comes here. Fall through
-- to handle the group below. */
-- }
-- }
--
-- /* Extracting brackets must be counted so we can process escapes in a
-- Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to
-- need an additional 3 bytes of store per extracting bracket. */
--
-- else
-- {
-- bracount++;
-- if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3;
-- }
--
-- /* Save length for computing whole length at end if there's a repeat that
-- requires duplication of the group. Also save the current value of
-- branch_extra, and start the new group with the new value. If non-zero, this
-- will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
--
-- if (brastackptr >= sizeof(brastack)/sizeof(int))
-- {
-- *errorptr = ERR19;
-- goto PCRE_ERROR_RETURN;
-- }
--
-- bralenstack[brastackptr] = branch_extra;
-- branch_extra = branch_newextra;
--
-- brastack[brastackptr++] = length;
-- length += bracket_length;
-- continue;
--
-- /* Handle ket. Look for subsequent max/min; for certain sets of values we
-- have to replicate this bracket up to that many times. If brastackptr is
-- 0 this is an unmatched bracket which will generate an error, but take care
-- not to try to access brastack[-1] when computing the length and restoring
-- the branch_extra value. */
--
-- case ')':
-- length += 3;
-- {
-- int minval = 1;
-- int maxval = 1;
-- int duplength;
--
-- if (brastackptr > 0)
-- {
-- duplength = length - brastack[--brastackptr];
-- branch_extra = bralenstack[brastackptr];
-- }
-- else duplength = 0;
--
-- /* Leave ptr at the final char; for read_repeat_counts this happens
-- automatically; for the others we need an increment. */
--
-- if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block))
-- {
-- ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr,
-- &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- }
-- else if (c == '*') { minval = 0; maxval = -1; ptr++; }
-- else if (c == '+') { maxval = -1; ptr++; }
-- else if (c == '?') { minval = 0; ptr++; }
--
-- /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
-- group, and if the maximum is greater than zero, we have to replicate
-- maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
-- bracket set - hence the 7. */
--
-- if (minval == 0)
-- {
-- length++;
-- if (maxval > 0) length += (maxval - 1) * (duplength + 7);
-- }
--
-- /* When the minimum is greater than zero, 1 we have to replicate up to
-- minval-1 times, with no additions required in the copies. Then, if
-- there is a limited maximum we have to replicate up to maxval-1 times
-- allowing for a BRAZERO item before each optional copy and nesting
-- brackets for all but one of the optional copies. */
--
-- else
-- {
-- length += (minval - 1) * duplength;
-- if (maxval > minval) /* Need this test as maxval=-1 means no limit */
-- length += (maxval - minval) * (duplength + 7) - 6;
-- }
-- }
-- continue;
--
-- /* Non-special character. For a run of such characters the length required
-- is the number of characters + 2, except that the maximum run length is 255.
-- We won't get a skipped space or a non-data escape or the start of a #
-- comment as the first character, so the length can't be zero. */
--
-- NORMAL_CHAR:
-- default:
-- length += 2;
-- runlength = 0;
-- do
-- {
-- if ((options & PCRE_EXTENDED) != 0)
-- {
-- if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
-- if (c == '#')
-- {
-- /* The space before the ; is to avoid a warning on a silly compiler
-- on the Macintosh. */
-- while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
-- continue;
-- }
-- }
--
-- /* Backslash may introduce a data char or a metacharacter; stop the
-- string before the latter. */
--
-- if (c == '\\')
-- {
-- const uschar *saveptr = ptr;
-- c = check_escape(&ptr, errorptr, bracount, options, FALSE,
-- &compile_block);
-- if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
-- if (c < 0) { ptr = saveptr; break; }
--
--#ifdef SUPPORT_UTF8
-- if (c > 127 && (options & PCRE_UTF8) != 0)
-- {
-- int i;
-- for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
-- if (c <= utf8_table1[i]) break;
-- runlength += i;
-- }
--#endif
-- }
--
-- /* Ordinary character or single-char escape */
--
-- runlength++;
-- }
--
-- /* This "while" is the end of the "do" above. */
--
-- while (runlength < MAXLIT &&
-- (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0);
--
-- ptr--;
-- length += runlength;
-- continue;
-- }
-- }
--
--length += 4; /* For final KET and END */
--
--if (length > 65539)
-- {
-- *errorptr = ERR20;
-- return NULL;
-- }
--
--/* Compute the size of data block needed and get it, either from malloc or
--externally provided function. We specify "code[0]" in the offsetof() expression
--rather than just "code", because it has been reported that one broken compiler
--fails on "code" because it is also an independent variable. It should make no
--difference to the value of the offsetof(). */
--
--size = length + offsetof(real_pcre, code[0]);
--re = (real_pcre *)(pcre_malloc)(size);
--
--if (re == NULL)
-- {
-- *errorptr = ERR21;
-- return NULL;
-- }
--
--/* size of re is sloppily computed, memset to get consistent output */
--memset(re, 0, size);
--
--/* Put in the magic number, and save the size, options, and table pointer */
--
--re->magic_number = MAGIC_NUMBER;
--re->size = size;
--re->options = options;
--re->tables = tables;
--
--/* Set up a starting, non-extracting bracket, then compile the expression. On
--error, *errorptr will be set non-NULL, so we don't need to look at the result
--of the function here. */
--
--ptr = (const uschar *)pattern;
--code = re->code;
--*code = OP_BRA;
--bracount = 0;
--(void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, 0,
-- &reqchar, &countlits, &compile_block);
--re->top_bracket = bracount;
--re->top_backref = top_backref;
--
--/* If not reached end of pattern on success, there's an excess bracket. */
--
--if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22;
--
--/* Fill in the terminating state and check for disastrous overflow, but
--if debugging, leave the test till after things are printed out. */
--
--*code++ = OP_END;
--
--#ifndef DEBUG
--if (code - re->code > length) *errorptr = ERR23;
--#endif
--
--/* Give an error if there's back reference to a non-existent capturing
--subpattern. */
--
--if (top_backref > re->top_bracket) *errorptr = ERR15;
--
--/* Failed to compile */
--
--if (*errorptr != NULL)
-- {
-- (pcre_free)(re);
-- PCRE_ERROR_RETURN:
-- *erroroffset = ptr - (const uschar *)pattern;
-- return NULL;
-- }
--
--/* If the anchored option was not passed, set flag if we can determine that the
--pattern is anchored by virtue of ^ characters or \A or anything else (such as
--starting with .* when DOTALL is set).
--
--Otherwise, see if we can determine what the first character has to be, because
--that speeds up unanchored matches no end. If not, see if we can set the
--PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
--start with ^. and also when all branches start with .* for non-DOTALL matches.
--*/
--
--if ((options & PCRE_ANCHORED) == 0)
-- {
-- int temp_options = options;
-- if (is_anchored(re->code, &temp_options))
-- re->options |= PCRE_ANCHORED;
-- else
-- {
-- int ch = find_firstchar(re->code, &temp_options);
-- if (ch >= 0)
-- {
-- re->first_char = ch;
-- re->options |= PCRE_FIRSTSET;
-- }
-- else if (is_startline(re->code))
-- re->options |= PCRE_STARTLINE;
-- }
-- }
--
--/* Save the last required character if there are at least two literal
--characters on all paths, or if there is no first character setting. */
--
--if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0))
-- {
-- re->req_char = reqchar;
-- re->options |= PCRE_REQCHSET;
-- }
--
--/* Print out the compiled data for debugging */
--
--#ifdef DEBUG
--
--printf("Length = %d top_bracket = %d top_backref = %d\n",
-- length, re->top_bracket, re->top_backref);
--
--if (re->options != 0)
-- {
-- printf("%s%s%s%s%s%s%s%s%s\n",
-- ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
-- ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
-- ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
-- ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
-- ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
-- ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
-- ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "",
-- ((re->options & PCRE_EXTRA) != 0)? "extra " : "",
-- ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : "");
-- }
--
--if ((re->options & PCRE_FIRSTSET) != 0)
-- {
-- if (isprint(re->first_char)) printf("First char = %c\n", re->first_char);
-- else printf("First char = \\x%02x\n", re->first_char);
-- }
--
--if ((re->options & PCRE_REQCHSET) != 0)
-- {
-- if (isprint(re->req_char)) printf("Req char = %c\n", re->req_char);
-- else printf("Req char = \\x%02x\n", re->req_char);
-- }
--
--code_end = code;
--code_base = code = re->code;
--
--while (code < code_end)
-- {
-- int charlength;
--
-- printf("%3d ", code - code_base);
--
-- if (*code >= OP_BRA)
-- {
-- if (*code - OP_BRA > EXTRACT_BASIC_MAX)
-- printf("%3d Bra extra", (code[1] << 8) + code[2]);
-- else
-- printf("%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA);
-- code += 2;
-- }
--
-- else switch(*code)
-- {
-- case OP_OPT:
-- printf(" %.2x %s", code[1], OP_names[*code]);
-- code++;
-- break;
--
-- case OP_CHARS:
-- charlength = *(++code);
-- printf("%3d ", charlength);
-- while (charlength-- > 0)
-- if (isprint(c = *(++code))) printf("%c", c); else printf("\\x%02x", c);
-- break;
--
-- case OP_KETRMAX:
-- case OP_KETRMIN:
-- case OP_ALT:
-- case OP_KET:
-- case OP_ASSERT:
-- case OP_ASSERT_NOT:
-- case OP_ASSERTBACK:
-- case OP_ASSERTBACK_NOT:
-- case OP_ONCE:
-- case OP_REVERSE:
-- case OP_BRANUMBER:
-- case OP_COND:
-- case OP_CREF:
-- printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]);
-- code += 2;
-- break;
--
-- case OP_STAR:
-- case OP_MINSTAR:
-- case OP_PLUS:
-- case OP_MINPLUS:
-- case OP_QUERY:
-- case OP_MINQUERY:
-- case OP_TYPESTAR:
-- case OP_TYPEMINSTAR:
-- case OP_TYPEPLUS:
-- case OP_TYPEMINPLUS:
-- case OP_TYPEQUERY:
-- case OP_TYPEMINQUERY:
-- if (*code >= OP_TYPESTAR)
-- printf(" %s", OP_names[code[1]]);
-- else if (isprint(c = code[1])) printf(" %c", c);
-- else printf(" \\x%02x", c);
-- printf("%s", OP_names[*code++]);
-- break;
--
-- case OP_EXACT:
-- case OP_UPTO:
-- case OP_MINUPTO:
-- if (isprint(c = code[3])) printf(" %c{", c);
-- else printf(" \\x%02x{", c);
-- if (*code != OP_EXACT) printf("0,");
-- printf("%d}", (code[1] << 8) + code[2]);
-- if (*code == OP_MINUPTO) printf("?");
-- code += 3;
-- break;
--
-- case OP_TYPEEXACT:
-- case OP_TYPEUPTO:
-- case OP_TYPEMINUPTO:
-- printf(" %s{", OP_names[code[3]]);
-- if (*code != OP_TYPEEXACT) printf(",");
-- printf("%d}", (code[1] << 8) + code[2]);
-- if (*code == OP_TYPEMINUPTO) printf("?");
-- code += 3;
-- break;
--
-- case OP_NOT:
-- if (isprint(c = *(++code))) printf(" [^%c]", c);
-- else printf(" [^\\x%02x]", c);
-- break;
--
-- case OP_NOTSTAR:
-- case OP_NOTMINSTAR:
-- case OP_NOTPLUS:
-- case OP_NOTMINPLUS:
-- case OP_NOTQUERY:
-- case OP_NOTMINQUERY:
-- if (isprint(c = code[1])) printf(" [^%c]", c);
-- else printf(" [^\\x%02x]", c);
-- printf("%s", OP_names[*code++]);
-- break;
--
-- case OP_NOTEXACT:
-- case OP_NOTUPTO:
-- case OP_NOTMINUPTO:
-- if (isprint(c = code[3])) printf(" [^%c]{", c);
-- else printf(" [^\\x%02x]{", c);
-- if (*code != OP_NOTEXACT) printf(",");
-- printf("%d}", (code[1] << 8) + code[2]);
-- if (*code == OP_NOTMINUPTO) printf("?");
-- code += 3;
-- break;
--
-- case OP_REF:
-- printf(" \\%d", (code[1] << 8) | code[2]);
-- code += 3;
-- goto CLASS_REF_REPEAT;
--
-- case OP_CLASS:
-- {
-- int i, min, max;
-- code++;
-- printf(" [");
--
-- for (i = 0; i < 256; i++)
-- {
-- if ((code[i/8] & (1 << (i&7))) != 0)
-- {
-- int j;
-- for (j = i+1; j < 256; j++)
-- if ((code[j/8] & (1 << (j&7))) == 0) break;
-- if (i == '-' || i == ']') printf("\\");
-- if (isprint(i)) printf("%c", i); else printf("\\x%02x", i);
-- if (--j > i)
-- {
-- printf("-");
-- if (j == '-' || j == ']') printf("\\");
-- if (isprint(j)) printf("%c", j); else printf("\\x%02x", j);
-- }
-- i = j;
-- }
-- }
-- printf("]");
-- code += 32;
--
-- CLASS_REF_REPEAT:
--
-- switch(*code)
-- {
-- case OP_CRSTAR:
-- case OP_CRMINSTAR:
-- case OP_CRPLUS:
-- case OP_CRMINPLUS:
-- case OP_CRQUERY:
-- case OP_CRMINQUERY:
-- printf("%s", OP_names[*code]);
-- break;
--
-- case OP_CRRANGE:
-- case OP_CRMINRANGE:
-- min = (code[1] << 8) + code[2];
-- max = (code[3] << 8) + code[4];
-- if (max == 0) printf("{%d,}", min);
-- else printf("{%d,%d}", min, max);
-- if (*code == OP_CRMINRANGE) printf("?");
-- code += 4;
-- break;
--
-- default:
-- code--;
-- }
-- }
-- break;
--
-- /* Anything else is just a one-node item */
--
-- default:
-- printf(" %s", OP_names[*code]);
-- break;
-- }
--
-- code++;
-- printf("\n");
-- }
--printf("------------------------------------------------------------------\n");
--
--/* This check is done here in the debugging case so that the code that
--was compiled can be seen. */
--
--if (code - re->code > length)
-- {
-- *errorptr = ERR23;
-- (pcre_free)(re);
-- *erroroffset = ptr - (uschar *)pattern;
-- return NULL;
-- }
--#endif
--
--return (pcre *)re;
--}
--
--
--
--/*************************************************
--* Match a back-reference *
--*************************************************/
--
--/* If a back reference hasn't been set, the length that is passed is greater
--than the number of characters left in the string, so the match fails.
--
--Arguments:
-- offset index into the offset vector
-- eptr points into the subject
-- length length to be matched
-- md points to match data block
-- ims the ims flags
--
--Returns: TRUE if matched
--*/
--
--static BOOL
--match_ref(int offset, register const uschar *eptr, int length, match_data *md,
-- unsigned long int ims)
--{
--const uschar *p = md->start_subject + md->offset_vector[offset];
--
--#ifdef DEBUG
--if (eptr >= md->end_subject)
-- printf("matching subject <null>");
--else
-- {
-- printf("matching subject ");
-- pchars(eptr, length, TRUE, md);
-- }
--printf(" against backref ");
--pchars(p, length, FALSE, md);
--printf("\n");
--#endif
--
--/* Always fail if not enough characters left */
--
--if (length > md->end_subject - eptr) return FALSE;
--
--/* Separate the caselesss case for speed */
--
--if ((ims & PCRE_CASELESS) != 0)
-- {
-- while (length-- > 0)
-- if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
-- }
--else
-- { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
--
--return TRUE;
--}
--
--
--
--/*************************************************
--* Match from current position *
--*************************************************/
--
--/* On entry ecode points to the first opcode, and eptr to the first character
--in the subject string, while eptrb holds the value of eptr at the start of the
--last bracketed group - used for breaking infinite loops matching zero-length
--strings.
--
--Arguments:
-- eptr pointer in subject
-- ecode position in code
-- offset_top current top pointer
-- md pointer to "static" info for the match
-- ims current /i, /m, and /s options
-- eptrb pointer to chain of blocks containing eptr at start of
-- brackets - for testing for empty matches
-- flags can contain
-- match_condassert - this is an assertion condition
-- match_isgroup - this is the start of a bracketed group
--
--Returns: TRUE if matched
--*/
--
--static BOOL
--match(register const uschar *eptr, register const uschar *ecode,
-- int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
-- int flags)
--{
--unsigned long int original_ims = ims; /* Save for resetting on ')' */
--eptrblock newptrb;
--
--/* At the start of a bracketed group, add the current subject pointer to the
--stack of such pointers, to be re-instated at the end of the group when we hit
--the closing ket. When match() is called in other circumstances, we don't add to
--the stack. */
--
--if ((flags & match_isgroup) != 0)
-- {
-- newptrb.prev = eptrb;
-- newptrb.saved_eptr = eptr;
-- eptrb = &newptrb;
-- }
--
--/* Now start processing the operations. */
--
--for (;;)
-- {
-- int op = (int)*ecode;
-- int min, max, ctype;
-- register int i;
-- register int c;
-- BOOL minimize = FALSE;
--
-- /* Opening capturing bracket. If there is space in the offset vector, save
-- the current subject position in the working slot at the top of the vector. We
-- mustn't change the current values of the data slot, because they may be set
-- from a previous iteration of this group, and be referred to by a reference
-- inside the group.
--
-- If the bracket fails to match, we need to restore this value and also the
-- values of the final offsets, in case they were set by a previous iteration of
-- the same bracket.
--
-- If there isn't enough space in the offset vector, treat this as if it were a
-- non-capturing bracket. Don't worry about setting the flag for the error case
-- here; that is handled in the code for KET. */
--
-- if (op > OP_BRA)
-- {
-- int offset;
-- int number = op - OP_BRA;
--
-- /* For extended extraction brackets (large number), we have to fish out the
-- number from a dummy opcode at the start. */
--
-- if (number > EXTRACT_BASIC_MAX) number = (ecode[4] << 8) | ecode[5];
-- offset = number << 1;
--
--#ifdef DEBUG
-- printf("start bracket %d subject=", number);
-- pchars(eptr, 16, TRUE, md);
-- printf("\n");
--#endif
--
-- if (offset < md->offset_max)
-- {
-- int save_offset1 = md->offset_vector[offset];
-- int save_offset2 = md->offset_vector[offset+1];
-- int save_offset3 = md->offset_vector[md->offset_end - number];
--
-- DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
-- md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
--
-- do
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- ecode += (ecode[1] << 8) + ecode[2];
-- }
-- while (*ecode == OP_ALT);
--
-- DPRINTF(("bracket %d failed\n", number));
--
-- md->offset_vector[offset] = save_offset1;
-- md->offset_vector[offset+1] = save_offset2;
-- md->offset_vector[md->offset_end - number] = save_offset3;
--
-- return FALSE;
-- }
--
-- /* Insufficient room for saving captured contents */
--
-- else op = OP_BRA;
-- }
--
-- /* Other types of node can be handled by a switch */
--
-- switch(op)
-- {
-- case OP_BRA: /* Non-capturing bracket: optimized */
-- DPRINTF(("start bracket 0\n"));
-- do
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- ecode += (ecode[1] << 8) + ecode[2];
-- }
-- while (*ecode == OP_ALT);
-- DPRINTF(("bracket 0 failed\n"));
-- return FALSE;
--
-- /* Conditional group: compilation checked that there are no more than
-- two branches. If the condition is false, skipping the first branch takes us
-- past the end if there is only one branch, but that's OK because that is
-- exactly what going to the ket would do. */
--
-- case OP_COND:
-- if (ecode[3] == OP_CREF) /* Condition is extraction test */
-- {
-- int offset = (ecode[4] << 9) | (ecode[5] << 1); /* Doubled ref number */
-- return match(eptr,
-- ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)?
-- 6 : 3 + (ecode[1] << 8) + ecode[2]),
-- offset_top, md, ims, eptrb, match_isgroup);
-- }
--
-- /* The condition is an assertion. Call match() to evaluate it - setting
-- the final argument TRUE causes it to stop at the end of an assertion. */
--
-- else
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, NULL,
-- match_condassert | match_isgroup))
-- {
-- ecode += 3 + (ecode[4] << 8) + ecode[5];
-- while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2];
-- }
-- else ecode += (ecode[1] << 8) + ecode[2];
-- return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup);
-- }
-- /* Control never reaches here */
--
-- /* Skip over conditional reference or large extraction number data if
-- encountered. */
--
-- case OP_CREF:
-- case OP_BRANUMBER:
-- ecode += 3;
-- break;
--
-- /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched
-- an empty string - recursion will then try other alternatives, if any. */
--
-- case OP_END:
-- if (md->notempty && eptr == md->start_match) return FALSE;
-- md->end_match_ptr = eptr; /* Record where we ended */
-- md->end_offset_top = offset_top; /* and how many extracts were taken */
-- return TRUE;
--
-- /* Change option settings */
--
-- case OP_OPT:
-- ims = ecode[1];
-- ecode += 2;
-- DPRINTF(("ims set to %02lx\n", ims));
-- break;
--
-- /* Assertion brackets. Check the alternative branches in turn - the
-- matching won't pass the KET for an assertion. If any one branch matches,
-- the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
-- start of each branch to move the current point backwards, so the code at
-- this level is identical to the lookahead case. */
--
-- case OP_ASSERT:
-- case OP_ASSERTBACK:
-- do
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break;
-- ecode += (ecode[1] << 8) + ecode[2];
-- }
-- while (*ecode == OP_ALT);
-- if (*ecode == OP_KET) return FALSE;
--
-- /* If checking an assertion for a condition, return TRUE. */
--
-- if ((flags & match_condassert) != 0) return TRUE;
--
-- /* Continue from after the assertion, updating the offsets high water
-- mark, since extracts may have been taken during the assertion. */
--
-- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
-- ecode += 3;
-- offset_top = md->end_offset_top;
-- continue;
--
-- /* Negative assertion: all branches must fail to match */
--
-- case OP_ASSERT_NOT:
-- case OP_ASSERTBACK_NOT:
-- do
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup))
-- return FALSE;
-- ecode += (ecode[1] << 8) + ecode[2];
-- }
-- while (*ecode == OP_ALT);
--
-- if ((flags & match_condassert) != 0) return TRUE;
--
-- ecode += 3;
-- continue;
--
-- /* Move the subject pointer back. This occurs only at the start of
-- each branch of a lookbehind assertion. If we are too close to the start to
-- move back, this match function fails. When working with UTF-8 we move
-- back a number of characters, not bytes. */
--
-- case OP_REVERSE:
--#ifdef SUPPORT_UTF8
-- c = (ecode[1] << 8) + ecode[2];
-- for (i = 0; i < c; i++)
-- {
-- eptr--;
-- BACKCHAR(eptr)
-- }
--#else
-- eptr -= (ecode[1] << 8) + ecode[2];
--#endif
--
-- if (eptr < md->start_subject) return FALSE;
-- ecode += 3;
-- break;
--
-- /* Recursion matches the current regex, nested. If there are any capturing
-- brackets started but not finished, we have to save their starting points
-- and reinstate them after the recursion. However, we don't know how many
-- such there are (offset_top records the completed total) so we just have
-- to save all the potential data. There may be up to 99 such values, which
-- is a bit large to put on the stack, but using malloc for small numbers
-- seems expensive. As a compromise, the stack is used when there are fewer
-- than 16 values to store; otherwise malloc is used. A problem is what to do
-- if the malloc fails ... there is no way of returning to the top level with
-- an error. Save the top 15 values on the stack, and accept that the rest
-- may be wrong. */
--
-- case OP_RECURSE:
-- {
-- BOOL rc;
-- int *save;
-- int stacksave[15];
--
-- c = md->offset_max;
--
-- if (c < 16) save = stacksave; else
-- {
-- save = (int *)(pcre_malloc)((c+1) * sizeof(int));
-- if (save == NULL)
-- {
-- save = stacksave;
-- c = 15;
-- }
-- }
--
-- for (i = 1; i <= c; i++)
-- save[i] = md->offset_vector[md->offset_end - i];
-- rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb,
-- match_isgroup);
-- for (i = 1; i <= c; i++)
-- md->offset_vector[md->offset_end - i] = save[i];
-- if (save != stacksave) (pcre_free)(save);
-- if (!rc) return FALSE;
--
-- /* In case the recursion has set more capturing values, save the final
-- number, then move along the subject till after the recursive match,
-- and advance one byte in the pattern code. */
--
-- offset_top = md->end_offset_top;
-- eptr = md->end_match_ptr;
-- ecode++;
-- }
-- break;
--
-- /* "Once" brackets are like assertion brackets except that after a match,
-- the point in the subject string is not moved back. Thus there can never be
-- a move back into the brackets. Check the alternative branches in turn - the
-- matching won't pass the KET for this kind of subpattern. If any one branch
-- matches, we carry on as at the end of a normal bracket, leaving the subject
-- pointer. */
--
-- case OP_ONCE:
-- {
-- const uschar *prev = ecode;
-- const uschar *saved_eptr = eptr;
--
-- do
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
-- break;
-- ecode += (ecode[1] << 8) + ecode[2];
-- }
-- while (*ecode == OP_ALT);
--
-- /* If hit the end of the group (which could be repeated), fail */
--
-- if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE;
--
-- /* Continue as from after the assertion, updating the offsets high water
-- mark, since extracts may have been taken. */
--
-- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
--
-- offset_top = md->end_offset_top;
-- eptr = md->end_match_ptr;
--
-- /* For a non-repeating ket, just continue at this level. This also
-- happens for a repeating ket if no characters were matched in the group.
-- This is the forcible breaking of infinite loops as implemented in Perl
-- 5.005. If there is an options reset, it will get obeyed in the normal
-- course of events. */
--
-- if (*ecode == OP_KET || eptr == saved_eptr)
-- {
-- ecode += 3;
-- break;
-- }
--
-- /* The repeating kets try the rest of the pattern or restart from the
-- preceding bracket, in the appropriate order. We need to reset any options
-- that changed within the bracket before re-running it, so check the next
-- opcode. */
--
-- if (ecode[3] == OP_OPT)
-- {
-- ims = (ims & ~PCRE_IMS) | ecode[4];
-- DPRINTF(("ims set to %02lx at group repeat\n", ims));
-- }
--
-- if (*ecode == OP_KETRMIN)
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
-- match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- }
-- else /* OP_KETRMAX */
-- {
-- if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
-- match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
-- }
-- }
-- return FALSE;
--
-- /* An alternation is the end of a branch; scan along to find the end of the
-- bracketed group and go to there. */
--
-- case OP_ALT:
-- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
-- break;
--
-- /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
-- that it may occur zero times. It may repeat infinitely, or not at all -
-- i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
-- repeat limits are compiled as a number of copies, with the optional ones
-- preceded by BRAZERO or BRAMINZERO. */
--
-- case OP_BRAZERO:
-- {
-- const uschar *next = ecode+1;
-- if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
-- ecode = next + 3;
-- }
-- break;
--
-- case OP_BRAMINZERO:
-- {
-- const uschar *next = ecode+1;
-- do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
-- if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- ecode++;
-- }
-- break;
--
-- /* End of a group, repeated or non-repeating. If we are at the end of
-- an assertion "group", stop matching and return TRUE, but record the
-- current high water mark for use by positive assertions. Do this also
-- for the "once" (not-backup up) groups. */
--
-- case OP_KET:
-- case OP_KETRMIN:
-- case OP_KETRMAX:
-- {
-- const uschar *prev = ecode - (ecode[1] << 8) - ecode[2];
-- const uschar *saved_eptr = eptrb->saved_eptr;
--
-- eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */
--
-- if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
-- *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
-- *prev == OP_ONCE)
-- {
-- md->end_match_ptr = eptr; /* For ONCE */
-- md->end_offset_top = offset_top;
-- return TRUE;
-- }
--
-- /* In all other cases except a conditional group we have to check the
-- group number back at the start and if necessary complete handling an
-- extraction by setting the offsets and bumping the high water mark. */
--
-- if (*prev != OP_COND)
-- {
-- int offset;
-- int number = *prev - OP_BRA;
--
-- /* For extended extraction brackets (large number), we have to fish out
-- the number from a dummy opcode at the start. */
--
-- if (number > EXTRACT_BASIC_MAX) number = (prev[4] << 8) | prev[5];
-- offset = number << 1;
--
--#ifdef DEBUG
-- printf("end bracket %d", number);
-- printf("\n");
--#endif
--
-- if (number > 0)
-- {
-- if (offset >= md->offset_max) md->offset_overflow = TRUE; else
-- {
-- md->offset_vector[offset] =
-- md->offset_vector[md->offset_end - number];
-- md->offset_vector[offset+1] = eptr - md->start_subject;
-- if (offset_top <= offset) offset_top = offset + 2;
-- }
-- }
-- }
--
-- /* Reset the value of the ims flags, in case they got changed during
-- the group. */
--
-- ims = original_ims;
-- DPRINTF(("ims reset to %02lx\n", ims));
--
-- /* For a non-repeating ket, just continue at this level. This also
-- happens for a repeating ket if no characters were matched in the group.
-- This is the forcible breaking of infinite loops as implemented in Perl
-- 5.005. If there is an options reset, it will get obeyed in the normal
-- course of events. */
--
-- if (*ecode == OP_KET || eptr == saved_eptr)
-- {
-- ecode += 3;
-- break;
-- }
--
-- /* The repeating kets try the rest of the pattern or restart from the
-- preceding bracket, in the appropriate order. */
--
-- if (*ecode == OP_KETRMIN)
-- {
-- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
-- match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
-- return TRUE;
-- }
-- else /* OP_KETRMAX */
-- {
-- if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
-- match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
-- }
-- }
-- return FALSE;
--
-- /* Start of subject unless notbol, or after internal newline if multiline */
--
-- case OP_CIRC:
-- if (md->notbol && eptr == md->start_subject) return FALSE;
-- if ((ims & PCRE_MULTILINE) != 0)
-- {
-- if (eptr != md->start_subject && eptr[-1] != NEWLINE) return FALSE;
-- ecode++;
-- break;
-- }
-- /* ... else fall through */
--
-- /* Start of subject assertion */
--
-- case OP_SOD:
-- if (eptr != md->start_subject) return FALSE;
-- ecode++;
-- break;
--
-- /* Assert before internal newline if multiline, or before a terminating
-- newline unless endonly is set, else end of subject unless noteol is set. */
--
-- case OP_DOLL:
-- if ((ims & PCRE_MULTILINE) != 0)
-- {
-- if (eptr < md->end_subject) { if (*eptr != NEWLINE) return FALSE; }
-- else { if (md->noteol) return FALSE; }
-- ecode++;
-- break;
-- }
-- else
-- {
-- if (md->noteol) return FALSE;
-- if (!md->endonly)
-- {
-- if (eptr < md->end_subject - 1 ||
-- (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
--
-- ecode++;
-- break;
-- }
-- }
-- /* ... else fall through */
--
-- /* End of subject assertion (\z) */
--
-- case OP_EOD:
-- if (eptr < md->end_subject) return FALSE;
-- ecode++;
-- break;
--
-- /* End of subject or ending \n assertion (\Z) */
--
-- case OP_EODN:
-- if (eptr < md->end_subject - 1 ||
-- (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
-- ecode++;
-- break;
--
-- /* Word boundary assertions */
--
-- case OP_NOT_WORD_BOUNDARY:
-- case OP_WORD_BOUNDARY:
-- {
-- BOOL prev_is_word = (eptr != md->start_subject) &&
-- ((md->ctypes[eptr[-1]] & ctype_word) != 0);
-- BOOL cur_is_word = (eptr < md->end_subject) &&
-- ((md->ctypes[*eptr] & ctype_word) != 0);
-- if ((*ecode++ == OP_WORD_BOUNDARY)?
-- cur_is_word == prev_is_word : cur_is_word != prev_is_word)
-- return FALSE;
-- }
-- break;
--
-- /* Match a single character type; inline for speed */
--
-- case OP_ANY:
-- if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
-- return FALSE;
-- if (eptr++ >= md->end_subject) return FALSE;
--#ifdef SUPPORT_UTF8
-- if (md->utf8)
-- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--#endif
-- ecode++;
-- break;
--
-- case OP_NOT_DIGIT:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_digit) != 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- case OP_DIGIT:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_digit) == 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- case OP_NOT_WHITESPACE:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_space) != 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- case OP_WHITESPACE:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_space) == 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- case OP_NOT_WORDCHAR:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_word) != 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- case OP_WORDCHAR:
-- if (eptr >= md->end_subject ||
-- (md->ctypes[*eptr++] & ctype_word) == 0)
-- return FALSE;
-- ecode++;
-- break;
--
-- /* Match a back reference, possibly repeatedly. Look past the end of the
-- item to see if there is repeat information following. The code is similar
-- to that for character classes, but repeated for efficiency. Then obey
-- similar code to character type repeats - written out again for speed.
-- However, if the referenced string is the empty string, always treat
-- it as matched, any number of times (otherwise there could be infinite
-- loops). */
--
-- case OP_REF:
-- {
-- int length;
-- int offset = (ecode[1] << 9) | (ecode[2] << 1); /* Doubled ref number */
-- ecode += 3; /* Advance past item */
--
-- /* If the reference is unset, set the length to be longer than the amount
-- of subject left; this ensures that every attempt at a match fails. We
-- can't just fail here, because of the possibility of quantifiers with zero
-- minima. */
--
-- length = (offset >= offset_top || md->offset_vector[offset] < 0)?
-- md->end_subject - eptr + 1 :
-- md->offset_vector[offset+1] - md->offset_vector[offset];
--
-- /* Set up for repetition, or handle the non-repeated case */
--
-- switch (*ecode)
-- {
-- case OP_CRSTAR:
-- case OP_CRMINSTAR:
-- case OP_CRPLUS:
-- case OP_CRMINPLUS:
-- case OP_CRQUERY:
-- case OP_CRMINQUERY:
-- c = *ecode++ - OP_CRSTAR;
-- minimize = (c & 1) != 0;
-- min = rep_min[c]; /* Pick up values from tables; */
-- max = rep_max[c]; /* zero for max => infinity */
-- if (max == 0) max = INT_MAX;
-- break;
--
-- case OP_CRRANGE:
-- case OP_CRMINRANGE:
-- minimize = (*ecode == OP_CRMINRANGE);
-- min = (ecode[1] << 8) + ecode[2];
-- max = (ecode[3] << 8) + ecode[4];
-- if (max == 0) max = INT_MAX;
-- ecode += 5;
-- break;
--
-- default: /* No repeat follows */
-- if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
-- eptr += length;
-- continue; /* With the main loop */
-- }
--
-- /* If the length of the reference is zero, just continue with the
-- main loop. */
--
-- if (length == 0) continue;
--
-- /* First, ensure the minimum number of matches are present. We get back
-- the length of the reference string explicitly rather than passing the
-- address of eptr, so that eptr can be a register variable. */
--
-- for (i = 1; i <= min; i++)
-- {
-- if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
-- eptr += length;
-- }
--
-- /* If min = max, continue at the same level without recursion.
-- They are not both allowed to be zero. */
--
-- if (min == max) continue;
--
-- /* If minimizing, keep trying and advancing the pointer */
--
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || !match_ref(offset, eptr, length, md, ims))
-- return FALSE;
-- eptr += length;
-- }
-- /* Control never gets here */
-- }
--
-- /* If maximizing, find the longest string and work backwards */
--
-- else
-- {
-- const uschar *pp = eptr;
-- for (i = min; i < max; i++)
-- {
-- if (!match_ref(offset, eptr, length, md, ims)) break;
-- eptr += length;
-- }
-- while (eptr >= pp)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- eptr -= length;
-- }
-- return FALSE;
-- }
-- }
-- /* Control never gets here */
--
--
--
-- /* Match a character class, possibly repeatedly. Look past the end of the
-- item to see if there is repeat information following. Then obey similar
-- code to character type repeats - written out again for speed. */
--
-- case OP_CLASS:
-- {
-- const uschar *data = ecode + 1; /* Save for matching */
-- ecode += 33; /* Advance past the item */
--
-- switch (*ecode)
-- {
-- case OP_CRSTAR:
-- case OP_CRMINSTAR:
-- case OP_CRPLUS:
-- case OP_CRMINPLUS:
-- case OP_CRQUERY:
-- case OP_CRMINQUERY:
-- c = *ecode++ - OP_CRSTAR;
-- minimize = (c & 1) != 0;
-- min = rep_min[c]; /* Pick up values from tables; */
-- max = rep_max[c]; /* zero for max => infinity */
-- if (max == 0) max = INT_MAX;
-- break;
--
-- case OP_CRRANGE:
-- case OP_CRMINRANGE:
-- minimize = (*ecode == OP_CRMINRANGE);
-- min = (ecode[1] << 8) + ecode[2];
-- max = (ecode[3] << 8) + ecode[4];
-- if (max == 0) max = INT_MAX;
-- ecode += 5;
-- break;
--
-- default: /* No repeat follows */
-- min = max = 1;
-- break;
-- }
--
-- /* First, ensure the minimum number of matches are present. */
--
-- for (i = 1; i <= min; i++)
-- {
-- if (eptr >= md->end_subject) return FALSE;
-- GETCHARINC(c, eptr) /* Get character; increment eptr */
--
--#ifdef SUPPORT_UTF8
-- /* We do not yet support class members > 255 */
-- if (c > 255) return FALSE;
--#endif
--
-- if ((data[c/8] & (1 << (c&7))) != 0) continue;
-- return FALSE;
-- }
--
-- /* If max == min we can continue with the main loop without the
-- need to recurse. */
--
-- if (min == max) continue;
--
-- /* If minimizing, keep testing the rest of the expression and advancing
-- the pointer while it matches the class. */
--
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || eptr >= md->end_subject) return FALSE;
-- GETCHARINC(c, eptr) /* Get character; increment eptr */
--
--#ifdef SUPPORT_UTF8
-- /* We do not yet support class members > 255 */
-- if (c > 255) return FALSE;
--#endif
-- if ((data[c/8] & (1 << (c&7))) != 0) continue;
-- return FALSE;
-- }
-- /* Control never gets here */
-- }
--
-- /* If maximizing, find the longest possible run, then work backwards. */
--
-- else
-- {
-- const uschar *pp = eptr;
-- int len = 1;
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject) break;
-- GETCHARLEN(c, eptr, len) /* Get character, set length if UTF-8 */
--
--#ifdef SUPPORT_UTF8
-- /* We do not yet support class members > 255 */
-- if (c > 255) break;
--#endif
-- if ((data[c/8] & (1 << (c&7))) == 0) break;
-- eptr += len;
-- }
--
-- while (eptr >= pp)
-- {
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
--
--#ifdef SUPPORT_UTF8
-- BACKCHAR(eptr)
--#endif
-- }
-- return FALSE;
-- }
-- }
-- /* Control never gets here */
--
-- /* Match a run of characters */
--
-- case OP_CHARS:
-- {
-- register int length = ecode[1];
-- ecode += 2;
--
--#ifdef DEBUG /* Sigh. Some compilers never learn. */
-- if (eptr >= md->end_subject)
-- printf("matching subject <null> against pattern ");
-- else
-- {
-- printf("matching subject ");
-- pchars(eptr, length, TRUE, md);
-- printf(" against pattern ");
-- }
-- pchars(ecode, length, FALSE, md);
-- printf("\n");
--#endif
--
-- if (length > md->end_subject - eptr) return FALSE;
-- if ((ims & PCRE_CASELESS) != 0)
-- {
-- while (length-- > 0)
-- if (md->lcc[*ecode++] != md->lcc[*eptr++])
-- return FALSE;
-- }
-- else
-- {
-- while (length-- > 0) if (*ecode++ != *eptr++) return FALSE;
-- }
-- }
-- break;
--
-- /* Match a single character repeatedly; different opcodes share code. */
--
-- case OP_EXACT:
-- min = max = (ecode[1] << 8) + ecode[2];
-- ecode += 3;
-- goto REPEATCHAR;
--
-- case OP_UPTO:
-- case OP_MINUPTO:
-- min = 0;
-- max = (ecode[1] << 8) + ecode[2];
-- minimize = *ecode == OP_MINUPTO;
-- ecode += 3;
-- goto REPEATCHAR;
--
-- case OP_STAR:
-- case OP_MINSTAR:
-- case OP_PLUS:
-- case OP_MINPLUS:
-- case OP_QUERY:
-- case OP_MINQUERY:
-- c = *ecode++ - OP_STAR;
-- minimize = (c & 1) != 0;
-- min = rep_min[c]; /* Pick up values from tables; */
-- max = rep_max[c]; /* zero for max => infinity */
-- if (max == 0) max = INT_MAX;
--
-- /* Common code for all repeated single-character matches. We can give
-- up quickly if there are fewer than the minimum number of characters left in
-- the subject. */
--
-- REPEATCHAR:
-- if (min > md->end_subject - eptr) return FALSE;
-- c = *ecode++;
--
-- /* The code is duplicated for the caseless and caseful cases, for speed,
-- since matching characters is likely to be quite common. First, ensure the
-- minimum number of matches are present. If min = max, continue at the same
-- level without recursing. Otherwise, if minimizing, keep trying the rest of
-- the expression and advancing one matching character if failing, up to the
-- maximum. Alternatively, if maximizing, find the maximum number of
-- characters and work backwards. */
--
-- DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max,
-- max, eptr));
--
-- if ((ims & PCRE_CASELESS) != 0)
-- {
-- c = md->lcc[c];
-- for (i = 1; i <= min; i++)
-- if (c != md->lcc[*eptr++]) return FALSE;
-- if (min == max) continue;
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || eptr >= md->end_subject ||
-- c != md->lcc[*eptr++])
-- return FALSE;
-- }
-- /* Control never gets here */
-- }
-- else
-- {
-- const uschar *pp = eptr;
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || c != md->lcc[*eptr]) break;
-- eptr++;
-- }
-- while (eptr >= pp)
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- return FALSE;
-- }
-- /* Control never gets here */
-- }
--
-- /* Caseful comparisons */
--
-- else
-- {
-- for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE;
-- if (min == max) continue;
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE;
-- }
-- /* Control never gets here */
-- }
-- else
-- {
-- const uschar *pp = eptr;
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || c != *eptr) break;
-- eptr++;
-- }
-- while (eptr >= pp)
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- return FALSE;
-- }
-- }
-- /* Control never gets here */
--
-- /* Match a negated single character */
--
-- case OP_NOT:
-- if (eptr >= md->end_subject) return FALSE;
-- ecode++;
-- if ((ims & PCRE_CASELESS) != 0)
-- {
-- if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE;
-- }
-- else
-- {
-- if (*ecode++ == *eptr++) return FALSE;
-- }
-- break;
--
-- /* Match a negated single character repeatedly. This is almost a repeat of
-- the code for a repeated single character, but I haven't found a nice way of
-- commoning these up that doesn't require a test of the positive/negative
-- option for each character match. Maybe that wouldn't add very much to the
-- time taken, but character matching *is* what this is all about... */
--
-- case OP_NOTEXACT:
-- min = max = (ecode[1] << 8) + ecode[2];
-- ecode += 3;
-- goto REPEATNOTCHAR;
--
-- case OP_NOTUPTO:
-- case OP_NOTMINUPTO:
-- min = 0;
-- max = (ecode[1] << 8) + ecode[2];
-- minimize = *ecode == OP_NOTMINUPTO;
-- ecode += 3;
-- goto REPEATNOTCHAR;
--
-- case OP_NOTSTAR:
-- case OP_NOTMINSTAR:
-- case OP_NOTPLUS:
-- case OP_NOTMINPLUS:
-- case OP_NOTQUERY:
-- case OP_NOTMINQUERY:
-- c = *ecode++ - OP_NOTSTAR;
-- minimize = (c & 1) != 0;
-- min = rep_min[c]; /* Pick up values from tables; */
-- max = rep_max[c]; /* zero for max => infinity */
-- if (max == 0) max = INT_MAX;
--
-- /* Common code for all repeated single-character matches. We can give
-- up quickly if there are fewer than the minimum number of characters left in
-- the subject. */
--
-- REPEATNOTCHAR:
-- if (min > md->end_subject - eptr) return FALSE;
-- c = *ecode++;
--
-- /* The code is duplicated for the caseless and caseful cases, for speed,
-- since matching characters is likely to be quite common. First, ensure the
-- minimum number of matches are present. If min = max, continue at the same
-- level without recursing. Otherwise, if minimizing, keep trying the rest of
-- the expression and advancing one matching character if failing, up to the
-- maximum. Alternatively, if maximizing, find the maximum number of
-- characters and work backwards. */
--
-- DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max,
-- max, eptr));
--
-- if ((ims & PCRE_CASELESS) != 0)
-- {
-- c = md->lcc[c];
-- for (i = 1; i <= min; i++)
-- if (c == md->lcc[*eptr++]) return FALSE;
-- if (min == max) continue;
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || eptr >= md->end_subject ||
-- c == md->lcc[*eptr++])
-- return FALSE;
-- }
-- /* Control never gets here */
-- }
-- else
-- {
-- const uschar *pp = eptr;
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || c == md->lcc[*eptr]) break;
-- eptr++;
-- }
-- while (eptr >= pp)
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- return FALSE;
-- }
-- /* Control never gets here */
-- }
--
-- /* Caseful comparisons */
--
-- else
-- {
-- for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE;
-- if (min == max) continue;
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE;
-- }
-- /* Control never gets here */
-- }
-- else
-- {
-- const uschar *pp = eptr;
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || c == *eptr) break;
-- eptr++;
-- }
-- while (eptr >= pp)
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
-- return FALSE;
-- }
-- }
-- /* Control never gets here */
--
-- /* Match a single character type repeatedly; several different opcodes
-- share code. This is very similar to the code for single characters, but we
-- repeat it in the interests of efficiency. */
--
-- case OP_TYPEEXACT:
-- min = max = (ecode[1] << 8) + ecode[2];
-- minimize = TRUE;
-- ecode += 3;
-- goto REPEATTYPE;
--
-- case OP_TYPEUPTO:
-- case OP_TYPEMINUPTO:
-- min = 0;
-- max = (ecode[1] << 8) + ecode[2];
-- minimize = *ecode == OP_TYPEMINUPTO;
-- ecode += 3;
-- goto REPEATTYPE;
--
-- case OP_TYPESTAR:
-- case OP_TYPEMINSTAR:
-- case OP_TYPEPLUS:
-- case OP_TYPEMINPLUS:
-- case OP_TYPEQUERY:
-- case OP_TYPEMINQUERY:
-- c = *ecode++ - OP_TYPESTAR;
-- minimize = (c & 1) != 0;
-- min = rep_min[c]; /* Pick up values from tables; */
-- max = rep_max[c]; /* zero for max => infinity */
-- if (max == 0) max = INT_MAX;
--
-- /* Common code for all repeated single character type matches */
--
-- REPEATTYPE:
-- ctype = *ecode++; /* Code for the character type */
--
-- /* First, ensure the minimum number of matches are present. Use inline
-- code for maximizing the speed, and do the type test once at the start
-- (i.e. keep it out of the loop). Also we can test that there are at least
-- the minimum number of bytes before we start, except when doing '.' in
-- UTF8 mode. Leave the test in in all cases; in the special case we have
-- to test after each character. */
--
-- if (min > md->end_subject - eptr) return FALSE;
-- if (min > 0) switch(ctype)
-- {
-- case OP_ANY:
--#ifdef SUPPORT_UTF8
-- if (md->utf8)
-- {
-- for (i = 1; i <= min; i++)
-- {
-- if (eptr >= md->end_subject ||
-- (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
-- return FALSE;
-- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
-- }
-- break;
-- }
--#endif
-- /* Non-UTF8 can be faster */
-- if ((ims & PCRE_DOTALL) == 0)
-- { for (i = 1; i <= min; i++) if (*eptr++ == NEWLINE) return FALSE; }
-- else eptr += min;
-- break;
--
-- case OP_NOT_DIGIT:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE;
-- break;
--
-- case OP_DIGIT:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE;
-- break;
--
-- case OP_NOT_WHITESPACE:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE;
-- break;
--
-- case OP_WHITESPACE:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE;
-- break;
--
-- case OP_NOT_WORDCHAR:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_word) != 0)
-- return FALSE;
-- break;
--
-- case OP_WORDCHAR:
-- for (i = 1; i <= min; i++)
-- if ((md->ctypes[*eptr++] & ctype_word) == 0)
-- return FALSE;
-- break;
-- }
--
-- /* If min = max, continue at the same level without recursing */
--
-- if (min == max) continue;
--
-- /* If minimizing, we have to test the rest of the pattern before each
-- subsequent match. */
--
-- if (minimize)
-- {
-- for (i = min;; i++)
-- {
-- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE;
-- if (i >= max || eptr >= md->end_subject) return FALSE;
--
-- c = *eptr++;
-- switch(ctype)
-- {
-- case OP_ANY:
-- if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return FALSE;
--#ifdef SUPPORT_UTF8
-- if (md->utf8)
-- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
--#endif
-- break;
--
-- case OP_NOT_DIGIT:
-- if ((md->ctypes[c] & ctype_digit) != 0) return FALSE;
-- break;
--
-- case OP_DIGIT:
-- if ((md->ctypes[c] & ctype_digit) == 0) return FALSE;
-- break;
--
-- case OP_NOT_WHITESPACE:
-- if ((md->ctypes[c] & ctype_space) != 0) return FALSE;
-- break;
--
-- case OP_WHITESPACE:
-- if ((md->ctypes[c] & ctype_space) == 0) return FALSE;
-- break;
--
-- case OP_NOT_WORDCHAR:
-- if ((md->ctypes[c] & ctype_word) != 0) return FALSE;
-- break;
--
-- case OP_WORDCHAR:
-- if ((md->ctypes[c] & ctype_word) == 0) return FALSE;
-- break;
-- }
-- }
-- /* Control never gets here */
-- }
--
-- /* If maximizing it is worth using inline code for speed, doing the type
-- test once at the start (i.e. keep it out of the loop). */
--
-- else
-- {
-- const uschar *pp = eptr;
-- switch(ctype)
-- {
-- case OP_ANY:
--
-- /* Special code is required for UTF8, but when the maximum is unlimited
-- we don't need it. */
--
--#ifdef SUPPORT_UTF8
-- if (md->utf8 && max < INT_MAX)
-- {
-- if ((ims & PCRE_DOTALL) == 0)
-- {
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || *eptr++ == NEWLINE) break;
-- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
-- }
-- }
-- else
-- {
-- for (i = min; i < max; i++)
-- {
-- eptr++;
-- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
-- }
-- }
-- break;
-- }
--#endif
-- /* Non-UTF8 can be faster */
-- if ((ims & PCRE_DOTALL) == 0)
-- {
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || *eptr == NEWLINE) break;
-- eptr++;
-- }
-- }
-- else
-- {
-- c = max - min;
-- if (c > md->end_subject - eptr) c = md->end_subject - eptr;
-- eptr += c;
-- }
-- break;
--
-- case OP_NOT_DIGIT:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
-- break;
-- eptr++;
-- }
-- break;
--
-- case OP_DIGIT:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
-- break;
-- eptr++;
-- }
-- break;
--
-- case OP_NOT_WHITESPACE:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
-- break;
-- eptr++;
-- }
-- break;
--
-- case OP_WHITESPACE:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
-- break;
-- eptr++;
-- }
-- break;
--
-- case OP_NOT_WORDCHAR:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
-- break;
-- eptr++;
-- }
-- break;
--
-- case OP_WORDCHAR:
-- for (i = min; i < max; i++)
-- {
-- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
-- break;
-- eptr++;
-- }
-- break;
-- }
--
-- while (eptr >= pp)
-- {
-- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
-- return TRUE;
--#ifdef SUPPORT_UTF8
-- if (md->utf8)
-- while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--;
--#endif
-- }
-- return FALSE;
-- }
-- /* Control never gets here */
--
-- /* There's been some horrible disaster. */
--
-- default:
-- DPRINTF(("Unknown opcode %d\n", *ecode));
-- md->errorcode = PCRE_ERROR_UNKNOWN_NODE;
-- return FALSE;
-- }
--
-- /* Do not stick any code in here without much thought; it is assumed
-- that "continue" in the code above comes out to here to repeat the main
-- loop. */
--
-- } /* End of main loop */
--/* Control never reaches here */
--}
--
--
--
--
--/*************************************************
--* Execute a Regular Expression *
--*************************************************/
--
--/* This function applies a compiled re to a subject string and picks out
--portions of the string if it matches. Two elements in the vector are set for
--each substring: the offsets to the start and end of the substring.
--
--Arguments:
-- external_re points to the compiled expression
-- external_extra points to "hints" from pcre_study() or is NULL
-- subject points to the subject string
-- length length of subject string (may contain binary zeros)
-- start_offset where to start in the subject string
-- options option bits
-- offsets points to a vector of ints to be filled in with offsets
-- offsetcount the number of elements in the vector
--
--Returns: > 0 => success; value is the number of elements filled in
-- = 0 => success, but offsets is not big enough
-- -1 => failed to match
-- < -1 => some kind of unexpected problem
--*/
--
--int
--pcre_exec(const pcre *external_re, const pcre_extra *external_extra,
-- const char *subject, int length, int start_offset, int options, int *offsets,
-- int offsetcount)
--{
--int resetcount, ocount;
--int first_char = -1;
--int req_char = -1;
--int req_char2 = -1;
--unsigned long int ims = 0;
--match_data match_block;
--const uschar *start_bits = NULL;
--const uschar *start_match = (const uschar *)subject + start_offset;
--const uschar *end_subject;
--const uschar *req_char_ptr = start_match - 1;
--const real_pcre *re = (const real_pcre *)external_re;
--const real_pcre_extra *extra = (const real_pcre_extra *)external_extra;
--BOOL using_temporary_offsets = FALSE;
--BOOL anchored;
--BOOL startline;
--
--if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
--
--if (re == NULL || subject == NULL ||
-- (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
--if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
--
--anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
--startline = (re->options & PCRE_STARTLINE) != 0;
--
--match_block.start_pattern = re->code;
--match_block.start_subject = (const uschar *)subject;
--match_block.end_subject = match_block.start_subject + length;
--end_subject = match_block.end_subject;
--
--match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
--match_block.utf8 = (re->options & PCRE_UTF8) != 0;
--
--match_block.notbol = (options & PCRE_NOTBOL) != 0;
--match_block.noteol = (options & PCRE_NOTEOL) != 0;
--match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
--
--match_block.errorcode = PCRE_ERROR_NOMATCH; /* Default error */
--
--match_block.lcc = re->tables + lcc_offset;
--match_block.ctypes = re->tables + ctypes_offset;
--
--/* The ims options can vary during the matching as a result of the presence
--of (?ims) items in the pattern. They are kept in a local variable so that
--restoring at the exit of a group is easy. */
--
--ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
--
--/* If the expression has got more back references than the offsets supplied can
--hold, we get a temporary bit of working store to use during the matching.
--Otherwise, we can use the vector supplied, rounding down its size to a multiple
--of 3. */
--
--ocount = offsetcount - (offsetcount % 3);
--
--if (re->top_backref > 0 && re->top_backref >= ocount/3)
-- {
-- ocount = re->top_backref * 3 + 3;
-- match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
-- if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
-- using_temporary_offsets = TRUE;
-- DPRINTF(("Got memory to hold back references\n"));
-- }
--else match_block.offset_vector = offsets;
--
--match_block.offset_end = ocount;
--match_block.offset_max = (2*ocount)/3;
--match_block.offset_overflow = FALSE;
--
--/* Compute the minimum number of offsets that we need to reset each time. Doing
--this makes a huge difference to execution time when there aren't many brackets
--in the pattern. */
--
--resetcount = 2 + re->top_bracket * 2;
--if (resetcount > offsetcount) resetcount = ocount;
--
--/* Reset the working variable associated with each extraction. These should
--never be used unless previously set, but they get saved and restored, and so we
--initialize them to avoid reading uninitialized locations. */
--
--if (match_block.offset_vector != NULL)
-- {
-- register int *iptr = match_block.offset_vector + ocount;
-- register int *iend = iptr - resetcount/2 + 1;
-- while (--iptr >= iend) *iptr = -1;
-- }
--
--/* Set up the first character to match, if available. The first_char value is
--never set for an anchored regular expression, but the anchoring may be forced
--at run time, so we have to test for anchoring. The first char may be unset for
--an unanchored pattern, of course. If there's no first char and the pattern was
--studied, there may be a bitmap of possible first characters. */
--
--if (!anchored)
-- {
-- if ((re->options & PCRE_FIRSTSET) != 0)
-- {
-- first_char = re->first_char;
-- if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char];
-- }
-- else
-- if (!startline && extra != NULL &&
-- (extra->options & PCRE_STUDY_MAPPED) != 0)
-- start_bits = extra->start_bits;
-- }
--
--/* For anchored or unanchored matches, there may be a "last known required
--character" set. If the PCRE_CASELESS is set, implying that the match starts
--caselessly, or if there are any changes of this flag within the regex, set up
--both cases of the character. Otherwise set the two values the same, which will
--avoid duplicate testing (which takes significant time). This covers the vast
--majority of cases. It will be suboptimal when the case flag changes in a regex
--and the required character in fact is caseful. */
--
--if ((re->options & PCRE_REQCHSET) != 0)
-- {
-- req_char = re->req_char;
-- req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)?
-- (re->tables + fcc_offset)[req_char] : req_char;
-- }
--
--/* Loop for handling unanchored repeated matching attempts; for anchored regexs
--the loop runs just once. */
--
--do
-- {
-- int rc;
-- register int *iptr = match_block.offset_vector;
-- register int *iend = iptr + resetcount;
--
-- /* Reset the maximum number of extractions we might see. */
--
-- while (iptr < iend) *iptr++ = -1;
--
-- /* Advance to a unique first char if possible */
--
-- if (first_char >= 0)
-- {
-- if ((ims & PCRE_CASELESS) != 0)
-- while (start_match < end_subject &&
-- match_block.lcc[*start_match] != first_char)
-- start_match++;
-- else
-- while (start_match < end_subject && *start_match != first_char)
-- start_match++;
-- }
--
-- /* Or to just after \n for a multiline match if possible */
--
-- else if (startline)
-- {
-- if (start_match > match_block.start_subject + start_offset)
-- {
-- while (start_match < end_subject && start_match[-1] != NEWLINE)
-- start_match++;
-- }
-- }
--
-- /* Or to a non-unique first char after study */
--
-- else if (start_bits != NULL)
-- {
-- while (start_match < end_subject)
-- {
-- register int c = *start_match;
-- if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
-- }
-- }
--
--#ifdef DEBUG /* Sigh. Some compilers never learn. */
-- printf(">>>> Match against: ");
-- pchars(start_match, end_subject - start_match, TRUE, &match_block);
-- printf("\n");
--#endif
--
-- /* If req_char is set, we know that that character must appear in the subject
-- for the match to succeed. If the first character is set, req_char must be
-- later in the subject; otherwise the test starts at the match point. This
-- optimization can save a huge amount of backtracking in patterns with nested
-- unlimited repeats that aren't going to match. We don't know what the state of
-- case matching may be when this character is hit, so test for it in both its
-- cases if necessary. However, the different cased versions will not be set up
-- unless PCRE_CASELESS was given or the casing state changes within the regex.
-- Writing separate code makes it go faster, as does using an autoincrement and
-- backing off on a match. */
--
-- if (req_char >= 0)
-- {
-- register const uschar *p = start_match + ((first_char >= 0)? 1 : 0);
--
-- /* We don't need to repeat the search if we haven't yet reached the
-- place we found it at last time. */
--
-- if (p > req_char_ptr)
-- {
-- /* Do a single test if no case difference is set up */
--
-- if (req_char == req_char2)
-- {
-- while (p < end_subject)
-- {
-- if (*p++ == req_char) { p--; break; }
-- }
-- }
--
-- /* Otherwise test for either case */
--
-- else
-- {
-- while (p < end_subject)
-- {
-- register int pp = *p++;
-- if (pp == req_char || pp == req_char2) { p--; break; }
-- }
-- }
--
-- /* If we can't find the required character, break the matching loop */
--
-- if (p >= end_subject) break;
--
-- /* If we have found the required character, save the point where we
-- found it, so that we don't search again next time round the loop if
-- the start hasn't passed this character yet. */
--
-- req_char_ptr = p;
-- }
-- }
--
-- /* When a match occurs, substrings will be set for all internal extractions;
-- we just need to set up the whole thing as substring 0 before returning. If
-- there were too many extractions, set the return code to zero. In the case
-- where we had to get some local store to hold offsets for backreferences, copy
-- those back references that we can. In this case there need not be overflow
-- if certain parts of the pattern were not used. */
--
-- match_block.start_match = start_match;
-- if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup))
-- continue;
--
-- /* Copy the offset information from temporary store if necessary */
--
-- if (using_temporary_offsets)
-- {
-- if (offsetcount >= 4)
-- {
-- memcpy(offsets + 2, match_block.offset_vector + 2,
-- (offsetcount - 2) * sizeof(int));
-- DPRINTF(("Copied offsets from temporary memory\n"));
-- }
-- if (match_block.end_offset_top > offsetcount)
-- match_block.offset_overflow = TRUE;
--
-- DPRINTF(("Freeing temporary memory\n"));
-- (pcre_free)(match_block.offset_vector);
-- }
--
-- rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
--
-- if (offsetcount < 2) rc = 0; else
-- {
-- offsets[0] = start_match - match_block.start_subject;
-- offsets[1] = match_block.end_match_ptr - match_block.start_subject;
-- }
--
-- DPRINTF((">>>> returning %d\n", rc));
-- return rc;
-- }
--
--/* This "while" is the end of the "do" above */
--
--while (!anchored &&
-- match_block.errorcode == PCRE_ERROR_NOMATCH &&
-- start_match++ < end_subject);
--
--if (using_temporary_offsets)
-- {
-- DPRINTF(("Freeing temporary memory\n"));
-- (pcre_free)(match_block.offset_vector);
-- }
--
--DPRINTF((">>>> returning %d\n", match_block.errorcode));
--
--return match_block.errorcode;
--}
--
--/* End of pcre.c */
-
-=== removed file 'parser/pcre/pcre.h'
---- parser/pcre/pcre.h 2006-04-11 21:52:54 +0000
-+++ parser/pcre/pcre.h 1970-01-01 00:00:00 +0000
-@@ -1,113 +0,0 @@
--/*************************************************
--* Perl-Compatible Regular Expressions *
--*************************************************/
--
--/* Copyright (c) 1997-2001 University of Cambridge */
--
--#ifndef _PCRE_H
--#define _PCRE_H
--
--/* The file pcre.h is build by "configure". Do not edit it; instead
--make changes to pcre.in. */
--
--#define PCRE_MAJOR 3
--#define PCRE_MINOR 9
--#define PCRE_DATE 02-Jan-2002
--
--/* Win32 uses DLL by default */
--
--#ifdef _WIN32
--# ifdef STATIC
--# define PCRE_DL_IMPORT
--# else
--# define PCRE_DL_IMPORT __declspec(dllimport)
--# endif
--#else
--# define PCRE_DL_IMPORT
--#endif
--
--/* Have to include stdlib.h in order to ensure that size_t is defined;
--it is needed here for malloc. */
--
--#include <stdlib.h>
--
--/* Allow for C++ users */
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--/* Options */
--
--#define PCRE_CASELESS 0x0001
--#define PCRE_MULTILINE 0x0002
--#define PCRE_DOTALL 0x0004
--#define PCRE_EXTENDED 0x0008
--#define PCRE_ANCHORED 0x0010
--#define PCRE_DOLLAR_ENDONLY 0x0020
--#define PCRE_EXTRA 0x0040
--#define PCRE_NOTBOL 0x0080
--#define PCRE_NOTEOL 0x0100
--#define PCRE_UNGREEDY 0x0200
--#define PCRE_NOTEMPTY 0x0400
--#define PCRE_UTF8 0x0800
--
--/* Exec-time and get-time error codes */
--
--#define PCRE_ERROR_NOMATCH (-1)
--#define PCRE_ERROR_NULL (-2)
--#define PCRE_ERROR_BADOPTION (-3)
--#define PCRE_ERROR_BADMAGIC (-4)
--#define PCRE_ERROR_UNKNOWN_NODE (-5)
--#define PCRE_ERROR_NOMEMORY (-6)
--#define PCRE_ERROR_NOSUBSTRING (-7)
--
--/* Request types for pcre_fullinfo() */
--
--#define PCRE_INFO_OPTIONS 0
--#define PCRE_INFO_SIZE 1
--#define PCRE_INFO_CAPTURECOUNT 2
--#define PCRE_INFO_BACKREFMAX 3
--#define PCRE_INFO_FIRSTCHAR 4
--#define PCRE_INFO_FIRSTTABLE 5
--#define PCRE_INFO_LASTLITERAL 6
--
--/* Types */
--
--struct real_pcre; /* declaration; the definition is private */
--struct real_pcre_extra; /* declaration; the definition is private */
--
--typedef struct real_pcre pcre;
--typedef struct real_pcre_extra pcre_extra;
--
--/* Store get and free functions. These can be set to alternative malloc/free
--functions if required. Some magic is required for Win32 DLL; it is null on
--other OS. */
--
--PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t);
--PCRE_DL_IMPORT extern void (*pcre_free)(void *);
--
--#undef PCRE_DL_IMPORT
--
--/* Functions */
--
--extern pcre *pcre_compile(const char *, int, const char **, int *,
-- const unsigned char *);
--extern int pcre_copy_substring(const char *, int *, int, int, char *, int);
--extern int pcre_exec(const pcre *, const pcre_extra *, const char *,
-- int, int, int, int *, int);
--extern void pcre_free_substring(const char *);
--extern void pcre_free_substring_list(const char **);
--extern int pcre_get_substring(const char *, int *, int, int, const char **);
--extern int pcre_get_substring_list(const char *, int *, int, const char ***);
--extern int pcre_info(const pcre *, int *, int *);
--extern int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *);
--extern const unsigned char *pcre_maketables(void);
--extern pcre_extra *pcre_study(const pcre *, int, const char **);
--extern const char *pcre_version(void);
--
--#ifdef __cplusplus
--} /* extern "C" */
--#endif
--
--#endif /* End of pcre.h */
-
-=== modified file 'parser/tst/Makefile'
---- parser/tst/Makefile 2006-12-15 08:10:25 +0000
-+++ parser/tst/Makefile 2010-08-03 17:27:13 +0000
-@@ -1,8 +1,9 @@
- #
--# $Id$
--#
- PROVE=/usr/bin/prove
- TESTS=simple.pl
-+PARSER_DIR=..
-+PARSER_BIN=apparmor_parser
-+PARSER=$(PARSER_DIR)/$(PARSER_BIN)
-
- ifeq ($(VERBOSE),1)
- PROVE_ARG=-v
-@@ -10,9 +11,23 @@
-
- all: tests
-
--.PHONY: tests
--tests: ../apparmor_parser
-+.PHONY: tests error_output parser_sanity
-+tests: error_output parser_sanity
-+
-+error_output: $(PARSER)
-+ $(PARSER) -S -I errors >/dev/null errors/okay.sd
-+ LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/single.sd | \
-+ grep -q "AppArmor parser error for errors/single.sd in errors/single.sd at line 3: Could not open 'failure'"
-+ LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/double.sd | \
-+ grep -q "AppArmor parser error for errors/double.sd in errors/includes/busted at line 67: Could not open 'does-not-exist'"
-+ LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/modefail.sd | \
-+ grep -q "AppArmor parser error for errors/modefail.sd in errors/modefail.sd at line 6: syntax error"
-+ LANG=C $(PARSER) -S -I errors 2>&1 >/dev/null errors/multi_include.sd | \
-+ grep -q "AppArmor parser error for errors/multi_include.sd in errors/multi_include.sd at line 12: Could not open 'failure'"
-+ @echo "Error Output: PASS"
-+
-+parser_sanity: $(PARSER)
- $(Q)${PROVE} ${PROVE_ARG} ${TESTS}
-
--../apparmor_parser:
-- make -C .. apparmor_parser
-+$(PARSER):
-+ make -C $(PARSER_DIR) $(PARSER_BIN)
-
-=== modified file 'parser/tst/README'
---- parser/tst/README 2006-06-01 17:02:28 +0000
-+++ parser/tst/README 2010-06-05 06:11:20 +0000
-@@ -64,5 +64,3 @@
- loop.
-
- Otherwise, the profile is passed on as-is to the subdomain parser.
--
--$Id$
-
-=== added directory 'parser/tst/errors'
-=== added file 'parser/tst/errors/double.sd'
---- parser/tst/errors/double.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/double.sd 2010-06-05 06:11:20 +0000
-@@ -0,0 +1,5 @@
-+#
-+/does/not/exist {
-+ #include <includes/base>
-+ #include <includes/busted>
-+}
-
-=== added directory 'parser/tst/errors/includes'
-=== added file 'parser/tst/errors/includes/base'
---- parser/tst/errors/includes/base 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/includes/base 2010-06-05 06:11:20 +0000
-@@ -0,0 +1,81 @@
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+# Copyright (C) 2002-2005 Novell/SUSE
-+#
-+# This program is free software; you can redistribute it and/or
-+# modify it under the terms of version 2 of the GNU General Public
-+# License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+
-+
-+ # (Note that the ldd profile has inlined this file; if you make
-+ # modifications here, please consider including them in the ldd
-+ # profile as well.)
-+
-+ # The __canary_death_handler function writes a time-stamped log
-+ # message to /dev/log for logging by syslogd. So, /dev/log, timezones,
-+ # and localisations of date should be available EVERYWHERE, so
-+ # StackGuard, FormatGuard, etc., alerts can be properly logged.
-+ /dev/log w,
-+ /dev/urandom r,
-+ /etc/locale/** r,
-+ /etc/localtime r,
-+ /usr/share/locale/** r,
-+ /usr/share/zoneinfo/** r,
-+
-+ /usr/lib64/locale/** r,
-+ /usr/lib64/gconv/*.so r,
-+ /usr/lib64/gconv/gconv-modules* r,
-+ /usr/lib/locale/** r,
-+ /usr/lib/gconv/*.so r,
-+ /usr/lib/gconv/gconv-modules* r,
-+
-+ # used by glibc when binding to ephemeral ports
-+ /etc/bindresvport.blacklist r,
-+
-+ # ld.so.cache and ld are used to load shared libraries; they are best
-+ # available everywhere
-+ /etc/ld.so.cache r,
-+ # 'px' requires a profile to be available for the transition to
-+ # function; without a loaded profile, the kernel will fail the exec.
-+ /lib/ld-*.so px,
-+ /lib64/ld-*.so px,
-+ /opt/*-linux-uclibc/lib/ld-uClibc*so* px,
-+
-+ # we might as well allow everything to use common libraries
-+ /lib/lib*.so* r,
-+ /lib/tls/lib*.so* r,
-+ /lib/power4/lib*.so* r,
-+ /lib/power5/lib*.so* r,
-+ /lib/power5+/lib*.so* r,
-+ /lib64/power4/lib*.so* r,
-+ /lib64/power5/lib*.so* r,
-+ /lib64/power5+/lib*.so* r,
-+ /usr/lib/*.so* r,
-+ /usr/lib/tls/lib*.so* r,
-+ /usr/lib/power4/lib*.so* r,
-+ /usr/lib/power5/lib*.so* r,
-+ /usr/lib/power5+/lib*.so* r,
-+ /lib64/lib*.so* r,
-+ /lib64/tls/lib*.so* r,
-+ /usr/lib64/*.so* r,
-+ /usr/lib64/tls/lib*.so* r,
-+
-+ # /dev/null is pretty harmless and frequently used
-+ /dev/null rw,
-+ # as is /dev/zero
-+ /dev/zero rw,
-+
-+ # Sometimes used to determine kernel/user interfaces to use
-+ /proc/sys/kernel/version r,
-+ # Depending on which glibc routine uses this file, base may not be the
-+ # best place -- but many profiles require it, and it is quite harmless.
-+ /proc/sys/kernel/ngroups_max r,
-+
-+ # glibc's sysconf(3) routine to determine free memory, etc
-+ /proc/meminfo r,
-+ /proc/stat r,
-+ /proc/cpuinfo r,
-
-=== added file 'parser/tst/errors/includes/busted'
---- parser/tst/errors/includes/busted 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/includes/busted 2010-06-05 06:11:20 +0000
-@@ -0,0 +1,83 @@
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+# Copyright (C) 2002-2005 Novell/SUSE
-+#
-+# This program is free software; you can redistribute it and/or
-+# modify it under the terms of version 2 of the GNU General Public
-+# License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+
-+
-+ # (Note that the ldd profile has inlined this file; if you make
-+ # modifications here, please consider including them in the ldd
-+ # profile as well.)
-+
-+ # The __canary_death_handler function writes a time-stamped log
-+ # message to /dev/log for logging by syslogd. So, /dev/log, timezones,
-+ # and localisations of date should be available EVERYWHERE, so
-+ # StackGuard, FormatGuard, etc., alerts can be properly logged.
-+ /dev/log w,
-+ /dev/urandom r,
-+ /etc/locale/** r,
-+ /etc/localtime r,
-+ /usr/share/locale/** r,
-+ /usr/share/zoneinfo/** r,
-+
-+ /usr/lib64/locale/** r,
-+ /usr/lib64/gconv/*.so r,
-+ /usr/lib64/gconv/gconv-modules* r,
-+ /usr/lib/locale/** r,
-+ /usr/lib/gconv/*.so r,
-+ /usr/lib/gconv/gconv-modules* r,
-+
-+ # used by glibc when binding to ephemeral ports
-+ /etc/bindresvport.blacklist r,
-+
-+ # ld.so.cache and ld are used to load shared libraries; they are best
-+ # available everywhere
-+ /etc/ld.so.cache r,
-+ # 'px' requires a profile to be available for the transition to
-+ # function; without a loaded profile, the kernel will fail the exec.
-+ /lib/ld-*.so px,
-+ /lib64/ld-*.so px,
-+ /opt/*-linux-uclibc/lib/ld-uClibc*so* px,
-+
-+ # we might as well allow everything to use common libraries
-+ /lib/lib*.so* r,
-+ /lib/tls/lib*.so* r,
-+ /lib/power4/lib*.so* r,
-+ /lib/power5/lib*.so* r,
-+ /lib/power5+/lib*.so* r,
-+ /lib64/power4/lib*.so* r,
-+ /lib64/power5/lib*.so* r,
-+ /lib64/power5+/lib*.so* r,
-+ /usr/lib/*.so* r,
-+ /usr/lib/tls/lib*.so* r,
-+ /usr/lib/power4/lib*.so* r,
-+ /usr/lib/power5/lib*.so* r,
-+ /usr/lib/power5+/lib*.so* r,
-+ /lib64/lib*.so* r,
-+ /lib64/tls/lib*.so* r,
-+ /usr/lib64/*.so* r,
-+ /usr/lib64/tls/lib*.so* r,
-+
-+ #include <does-not-exist>
-+
-+ # /dev/null is pretty harmless and frequently used
-+ /dev/null rw,
-+ # as is /dev/zero
-+ /dev/zero rw,
-+
-+ # Sometimes used to determine kernel/user interfaces to use
-+ /proc/sys/kernel/version r,
-+ # Depending on which glibc routine uses this file, base may not be the
-+ # best place -- but many profiles require it, and it is quite harmless.
-+ /proc/sys/kernel/ngroups_max r,
-+
-+ # glibc's sysconf(3) routine to determine free memory, etc
-+ /proc/meminfo r,
-+ /proc/stat r,
-+ /proc/cpuinfo r,
-
-=== added file 'parser/tst/errors/modefail.sd'
---- parser/tst/errors/modefail.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/modefail.sd 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,7 @@
-+# 1
-+# 2
-+# 3
-+/does/not/exist { # 4
-+ /lib/lib*.so rm, # 5
-+ /fail abcdefgh, # 6
-+} # 7
-
-=== added file 'parser/tst/errors/multi_include.sd'
---- parser/tst/errors/multi_include.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/multi_include.sd 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,13 @@
-+#
-+#
-+#
-+/does/not/exist {
-+ #include <includes/base>
-+ #include <includes/base>
-+ #include <includes/base>
-+ #include <includes/base>
-+
-+ /bin/true rix,
-+
-+ #include <failure>
-+}
-
-=== added file 'parser/tst/errors/okay.sd'
---- parser/tst/errors/okay.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/okay.sd 2010-06-05 06:11:20 +0000
-@@ -0,0 +1,4 @@
-+#
-+/does/not/exist {
-+ #include <includes/base>
-+}
-
-=== added file 'parser/tst/errors/single.sd'
---- parser/tst/errors/single.sd 1970-01-01 00:00:00 +0000
-+++ parser/tst/errors/single.sd 2010-06-05 06:11:20 +0000
-@@ -0,0 +1,7 @@
-+#
-+#
-+#include <failure>
-+#
-+/does/not/exist {
-+ #include <includes/base>
-+}
-
-=== modified file 'profiles/apparmor.d/abstractions/base'
---- profiles/apparmor.d/abstractions/base 2010-01-03 21:16:38 +0000
-+++ profiles/apparmor.d/abstractions/base 2010-06-05 06:11:20 +0000
-@@ -85,6 +85,9 @@
- # some applications will display license information
- /usr/share/common-licenses/** r,
-
-+ # glibc statvfs
-+ @{PROC}/filesystems r,
-+
- # Workaround https://launchpad.net/bugs/359338 until upstream handles stacked
- # filesystems generally. This does not appreciably decrease security with
- # Ubuntu profiles because the user is expected to have access to files owned
-
-=== modified file 'profiles/apparmor.d/abstractions/dbus'
---- profiles/apparmor.d/abstractions/dbus 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/dbus 2010-08-03 17:27:13 +0000
-@@ -2,7 +2,7 @@
- # $Id$
- # ------------------------------------------------------------------
- #
--# Copyright (C) 2009 Canonical Ltd.
-+# Copyright (C) 2009-2010 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -10,8 +10,5 @@
- #
- # ------------------------------------------------------------------
-
-- # System socket
-+ # System socket. Be careful when including this abstraction.
- /var/run/dbus/system_bus_socket w,
--
-- # Machine id
-- /var/lib/dbus/machine-id r,
-
-=== added file 'profiles/apparmor.d/abstractions/dbus-session'
---- profiles/apparmor.d/abstractions/dbus-session 1970-01-01 00:00:00 +0000
-+++ profiles/apparmor.d/abstractions/dbus-session 2010-08-03 17:27:13 +0000
-@@ -0,0 +1,14 @@
-+# vim:syntax=apparmor
-+# $Id$
-+# ------------------------------------------------------------------
-+#
-+# Copyright (C) 2010 Canonical Ltd.
-+#
-+# This program is free software; you can redistribute it and/or
-+# modify it under the terms of version 2 of the GNU General Public
-+# License published by the Free Software Foundation.
-+#
-+# ------------------------------------------------------------------
-+
-+ /usr/bin/dbus-launch Pix,
-+ /var/lib/dbus/machine-id r,
-
-=== modified file 'profiles/apparmor.d/abstractions/fonts'
---- profiles/apparmor.d/abstractions/fonts 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/fonts 2010-06-05 06:11:20 +0000
-@@ -15,6 +15,7 @@
-
- /usr/lib/xorg/modules/fonts/**.so* mr,
-
-+ /usr/share/fonts/ r,
- /usr/share/fonts/** r,
-
- /etc/fonts/** r,
-
-=== modified file 'profiles/apparmor.d/abstractions/freedesktop.org'
---- profiles/apparmor.d/abstractions/freedesktop.org 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/freedesktop.org 2010-06-05 06:11:20 +0000
-@@ -27,3 +27,7 @@
- @{HOME}/.icons/ r,
- @{HOME}/.recently-used.xbel* rw,
- @{HOME}/.config/user-dirs.dirs r,
-+ @{HOME}/.local/share/icons/ r,
-+ @{HOME}/.local/share/icons/** r,
-+ @{HOME}/.local/share/mime/ r,
-+ @{HOME}/.local/share/mime/** r,
-
-=== modified file 'profiles/apparmor.d/abstractions/gnome'
---- profiles/apparmor.d/abstractions/gnome 2009-11-10 20:04:26 +0000
-+++ profiles/apparmor.d/abstractions/gnome 2010-08-03 17:27:13 +0000
-@@ -3,7 +3,7 @@
- # ------------------------------------------------------------------
- #
- # Copyright (C) 2002-2009 Novell/SUSE
--# Copyright (C) 2009 Canonical Ltd.
-+# Copyright (C) 2009-2010 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -31,6 +31,7 @@
- /etc/pango/* r,
- /usr/lib{,32,64}/pango/** mr,
- /usr/lib{,32,64}/gtk-*/** mr,
-+ /usr/lib{,32,64}/gdk-pixbuf-*/** mr,
-
- # per-user gtk configuration
- @{HOME}/.gnome/Gnome r,
-
-=== modified file 'profiles/apparmor.d/abstractions/nameservice'
---- profiles/apparmor.d/abstractions/nameservice 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/nameservice 2010-06-05 06:11:20 +0000
-@@ -77,3 +77,5 @@
- network inet dgram,
- network inet6 dgram,
-
-+ # interface details
-+ @{PROC}/*/net/route r,
-
-=== modified file 'profiles/apparmor.d/abstractions/php5'
---- profiles/apparmor.d/abstractions/php5 2010-01-03 21:16:38 +0000
-+++ profiles/apparmor.d/abstractions/php5 2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # ------------------------------------------------------------------
- #
- # Copyright (C) 2002-2006 Novell/SUSE
--# Copyright (C) 2009 Canonical, Ltd.
-+# Copyright (C) 2009-2010 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -11,13 +11,13 @@
- # ------------------------------------------------------------------
-
- # shared snippets for config files
-- /etc/php5/{conf.d,apache2,cli,fastcgi}/ r,
-- /etc/php5/{conf.d,apache2,cli,fastcgi}/*.ini r,
-+ /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/ r,
-+ /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/*.ini r,
-
- # Xlibs
- /usr/X11R6/lib{,32,64}/lib*.so* mr,
- # php extensions
-- /usr/lib{64,}/php5/{libexec,extensions}/*.so mr,
-+ /usr/lib{64,}/php5/*/*.so mr,
-
- # php5 session mmap socket
- /var/lib/php5/session_mm_* rwlk,
-
-=== modified file 'profiles/apparmor.d/abstractions/samba'
---- profiles/apparmor.d/abstractions/samba 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/samba 2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # $Id$
- # ------------------------------------------------------------------
- #
--# Copyright (C) 2009 Canonical Ltd.
-+# Copyright (C) 2009-2010 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -12,7 +12,7 @@
-
- /etc/samba/smb.conf r,
- /usr/share/samba/*.dat r,
-- /var/lib/samba/**.tdb rw,
-+ /var/lib/samba/**.tdb rwk,
- /var/log/samba/cores/* w,
- /var/log/samba/log.* w,
- /var/run/samba/*.tdb rw,
-
-=== modified file 'profiles/apparmor.d/abstractions/ubuntu-email'
---- profiles/apparmor.d/abstractions/ubuntu-email 2009-11-11 19:42:30 +0000
-+++ profiles/apparmor.d/abstractions/ubuntu-email 2010-08-03 17:27:13 +0000
-@@ -15,5 +15,5 @@
- /usr/bin/tkrat Ux,
-
- /usr/lib/thunderbird/thunderbird Ux,
--
-+ /usr/lib/thunderbird-3*/thunderbird Ux,
-
-
-=== modified file 'profiles/apparmor.d/abstractions/ubuntu-media-players'
---- profiles/apparmor.d/abstractions/ubuntu-media-players 2010-03-08 19:50:25 +0000
-+++ profiles/apparmor.d/abstractions/ubuntu-media-players 2010-08-03 17:27:13 +0000
-@@ -24,6 +24,7 @@
-
- # mplayer
- /etc/mplayerplug-in.conf r,
-+ /usr/bin/gmplayer Uxr,
- /usr/bin/gnome-mplayer Uxr,
- /usr/bin/kmplayer Uxr,
- /usr/bin/mplayer Uxr,
-
-=== modified file 'profiles/apparmor.d/abstractions/user-tmp'
---- profiles/apparmor.d/abstractions/user-tmp 2009-11-04 20:25:42 +0000
-+++ profiles/apparmor.d/abstractions/user-tmp 2010-05-31 18:58:40 +0000
-@@ -2,7 +2,7 @@
- # ------------------------------------------------------------------
- #
- # Copyright (C) 2002-2009 Novell/SUSE
--# Copyright (C) 2009 Canonical Ltd.
-+# Copyright (C) 2009-2010 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -11,11 +11,11 @@
- # ------------------------------------------------------------------
-
- # per-user tmp directories
-- @{HOME}/tmp/** rwkl,
-- @{HOME}/tmp/ rw,
-+ owner @{HOME}/tmp/** rwkl,
-+ owner @{HOME}/tmp/ rw,
-
- # global tmp directories
-- /var/tmp/** rwkl,
-- /var/tmp/ rw,
-- /tmp/** rwkl,
-- /tmp/ rw,
-+ owner /var/tmp/** rwkl,
-+ owner /var/tmp/ rw,
-+ owner /tmp/** rwkl,
-+ owner /tmp/ rw,
-
-=== renamed directory 'tests/regression/subdomain' => 'tests/regression/apparmor'
-=== modified file 'tests/regression/apparmor/Makefile'
---- tests/regression/subdomain/Makefile 2009-08-21 20:39:45 +0000
-+++ tests/regression/apparmor/Makefile 2010-08-03 17:27:13 +0000
-@@ -22,6 +22,7 @@
- chmod.c \
- chown.c \
- clone.c \
-+ coredump.c \
- deleted.c \
- environ.c \
- env_check.c \
-@@ -113,6 +114,7 @@
- changehat_misc \
- chdir \
- clone \
-+ coredump \
- deleted \
- environ \
- exec \
-@@ -158,27 +160,39 @@
- tests: all
- @if [ `whoami` = "root" ] ;\
- then \
-+ rc=0; \
- for i in $(TESTS) ;\
- do \
- echo ;\
- echo "running $$i" ;\
- bash $$i.sh ;\
-+ if [ $$? -ne 0 ] ; then \
-+ rc=1;\
-+ fi;\
- done ;\
-+ exit $$rc;\
- else \
- echo "must be root to run tests" ;\
-+ exit 1;\
- fi
-
- alltests: all
- @if [ `whoami` = "root" ] ;\
- then \
-+ rc=0; \
- for i in $(TESTS) $(RISKY_TESTS) ;\
- do \
- echo ;\
- echo "running $$i" ;\
- bash $$i.sh ;\
-+ if [ $$? -ne 0 ] ; then \
-+ rc=1;\
-+ fi;\
- done ;\
-+ exit $$rc;\
- else \
- echo "must be root to run tests" ;\
-+ exit 1;\
- fi
-
- clean:
-
-=== modified file 'tests/regression/apparmor/README'
---- tests/regression/subdomain/README 2006-09-15 22:39:59 +0000
-+++ tests/regression/apparmor/README 2010-08-03 17:27:13 +0000
-@@ -1,10 +1,10 @@
- Running tests
- =============
-
--Type "make tests" at the shell prompt, this will make the subprograms
--and run the tests.
-+Type "sudo make tests" at the shell prompt, this will make the
-+subprograms and run the tests.
-
--You must be root to execute make tests (a requirement of subdomain).
-+You must be root to execute "make tests" (a requirement of AppArmor).
-
- (There is also a 'make alltests', which adds a test for bug that, when
- triggered, would cause the kernel to crash.)
-@@ -12,10 +12,13 @@
- Test output
- ===========
-
--No output is displayed for a passing test. The makefile will output
-+By default, no output is displayed for a passing test. The makefile will
-+output:
- running <testname> for each test.
-
--Output other than this indicates a problem.
-+To have verbose output with each subtest reporting successes, set the
-+environment variable VERBOSE=1:
-+ sudo VERBOSE=1 make tests
-
- There are three typical failure scenarios:
- - Test failed when it was expected to pass
-@@ -29,7 +32,7 @@
-
- Common user changeable environment variables are stored in the file
- 'uservars.inc'. Currently the path to the tmp directory, the path
--to the subdomain_parser executable, and any additional arguments to give
-+to the apparmor_parser executable, and any additional arguments to give
- to the parser are specified in this configuration file.
-
- (Note: the tmp directory specified in uservars.inc will have an added
-@@ -66,7 +69,7 @@
- directory will contain the files for the failed subtest.
-
- It may be necessary to create certain temp files in this directory in order to
--have the test function correctly, see the subdomain profile 'profile' in the
-+have the test function correctly, see the AppArmor profile 'profile' in the
- directory in order to determine which files may need to be created to support
- the executable.
-
-@@ -155,7 +158,7 @@
- <requirement placed on the shell script author by prologue.inc>
- bin=$pwd
-
-- <prologie.inc must be included before running any tests>
-+ <prologue.inc must be included before running any tests>
- . $bin/prologue.inc
-
- <variable definitions used by this script?
-@@ -174,7 +177,7 @@
-
- # NOLINK PERMTEST
- <generate a new profile allowing only r access to /bin/true>
-- <subdomain_parser will automatically be invoked in -r mode>
-+ <apparmor_parser will automatically be invoked in -r mode>
- genprofile $file:$badperm
-
- <run this test (exec) passing /bin/true as argv[1]>
-@@ -183,16 +186,11 @@
-
- <Thats it. Exit status $rc is automatically returned by epilogue.inc>
-
--Additional documentation
--========================
--
--See the file 'subdomain_test.txt'
--
- Supporting files
- ================
-
- strace.sh Not a test harness, used to support strace testing.
--mkprofile.sh Not a test harness, used to generate subdomain profiles.
-+mkprofile.sh Not a test harness, used to generate AppArmor profiles.
- prologue.inc Must be dotted (included) into the test harness. Provides
- support routines.
- epilogue.inc Cleanup support, automatically called upon successful or
-@@ -222,17 +220,3 @@
- This is not an error, rather a sign that bash noticed the kernel had killed
- a process which was attempting to use a bogus MAGIC number. Alas, there is
- no way to get bash to not print this diagnostic
--
--3) Ptrace
-- Error: open passed. Test 'STRACE OPEN (x confinement)'
-- was expected to 'fail'
--
-- Regression from 2.4.18 to 2.4.20. (We aren't sure on the first
-- endpoint, and the problem still happens in 2.4.20-20_imnx_10smp.)
--
--4) Open
-- Error: open passed. Test 'OPEN W (create)' was expected to 'fail'
--
-- LSM issue. Flags passed to inode_permission are 0 if O_CREAT is used to
-- open file. Need to submit a patch to inode_create hook to receive the
-- O_RDWR flags. See https://bugs.wirex.com/show_bug.cgi?id=2885
-
-=== modified file 'tests/regression/apparmor/changehat_misc.sh'
---- tests/regression/subdomain/changehat_misc.sh 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/changehat_misc.sh 2010-08-03 17:27:13 +0000
-@@ -64,7 +64,7 @@
- echo "*** A 'Killed' message from bash is expected for the following test"
- runchecktest "CHANGEHAT (subprofile->subprofile w/ bad magic)" signal9 $subtest $subtest2 badmagic $file
-
--# 1. ATTEMPT TO CHANGEGAT TO AN INVALUD PROFILE, SHOULD PUT US INTO A NULL
-+# 1. ATTEMPT TO CHANGEHAT TO AN INVALID PROFILE, SHOULD PUT US INTO A NULL
- # PROFILE
- # 2. ATTEMPT TO CHANGEHAT OUT WITH BAD TOKEN
- settest changehat_fail
-
-=== modified file 'tests/regression/apparmor/coredump.c'
---- tests/regression/subdomain/coredump.c 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/coredump.c 2010-08-03 17:27:13 +0000
-@@ -1,7 +1,9 @@
-+#include <stdio.h>
- int *ptr;
-
- /*
- * Copyright (C) 2002-2005 Novell/SUSE
-+ * Copyright (C) 2010 Canonical, Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
-@@ -9,7 +11,7 @@
- * License.
- */
-
--main()
-+int main(int argc, char *argv[])
- {
- printf("This will cause a sigsegv\n");
-
-
-=== modified file 'tests/regression/apparmor/coredump.sh'
---- tests/regression/subdomain/coredump.sh 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/coredump.sh 2010-08-03 17:27:13 +0000
-@@ -1,7 +1,6 @@
- #! /bin/bash
--# $Id$
--
- # Copyright (C) 2002-2005 Novell/SUSE
-+# Copyright (C) 2010 Canonical, Ltd
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License as
-@@ -11,26 +10,52 @@
- #=NAME coredump
- #=DESCRIPTION coredump test
-
-+cleancorefile()
-+{
-+ rm -f core core.*
-+}
-+
- checkcorefile()
- {
--_corefilelist=`echo core.*`
--if [ "$_corefilelist" = "core.*" ]
--then
-- _corefile=no
+=== modified file 'parser/rc.apparmor.functions'
+--- parser/rc.apparmor.functions 2011-08-13 12:15:58 +0000
++++ parser/rc.apparmor.functions 2011-08-26 22:55:43 +0000
+@@ -83,15 +83,6 @@
+ SUBDOMAINFS_MOUNTPOINT=$(grep subdomainfs /etc/fstab | \
+ sed -e 's|^[[:space:]]*[^[:space:]]\+[[:space:]]\+\(/[^[:space:]]*\)[[:space:]]\+subdomainfs.*$|\1|' 2> /dev/null)
+
+-if [ -d "/var/lib/${MODULE}" ] ; then
+- APPARMOR_TMPDIR="/var/lib/${MODULE}"
+-elif [ -d "/var/lib/${OLD_MODULE}" ] ; then
+- APPARMOR_TMPDIR="/var/lib/${OLD_MODULE}"
-else
-- _corefile=yes
--fi
--
--if [ "$1" = "yes" -a "$_corefile" = "no" ]
--then
-- echo "Error: corefile expected but not present - $2"
--elif [ "$1" = "no" -a "$_corefile" = "yes" ]
--then
-- echo "Error: corefile present when not expected -- $2"
+- APPARMOR_TMPDIR="/tmp"
-fi
-
--unset _corefile _corefilelist
--rm -f core.*
-+ # global _testdesc _pfmode _known outfile
-+ if [ ${1:0:1} == "x" ] ; then
-+ requirement=${1#x}
-+ _known=" (known problem)"
-+ else
-+ requirement=$1
-+ _known=""
-+ fi
-+
-+ _corefilelist=`echo core.*`
-+ if [ ! -f core ] && [ "$_corefilelist" = "core.*" ]
-+ then
-+ _corefile=no
-+ else
-+ _corefile=yes
-+ fi
-+
-+ if [ "$requirement" = "yes" -a "$_corefile" = "no" ] ; then
-+ if [ -n $_known ] ; then
-+ echo -n "XFAIL: "
-+ fi
-+ echo "Error: corefile expected but not present - $2"
-+ if [ -z $_known ] ; then
-+ cat $profile
-+ testfailed
-+ fi
-+ elif [ "$requirement" = "no" -a "$_corefile" = "yes" ] ; then
-+ if [ -n "$_known" ] ; then
-+ echo -n "XFAIL: "
-+ fi
-+ echo "Error: corefile present when not expected -- $2"
-+ if [ -z "$_known" ] ; then
-+ cat $profile
-+ testfailed
-+ fi
-+ fi
-+
-+ unset _corefile _corefilelist
-+ cleancorefile
- }
-
- pwd=`dirname $0`
-@@ -45,15 +70,18 @@
-
- # enable coredumps
- ulimit -c 1000000
-+cleancorefile
-+checkcorefile no "COREDUMP (starting with clean slate)"
-
- # PASS TEST, no confinement
-+cleancorefile
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
- runchecktest "COREDUMP (no confinement)" signal11
- checkcorefile yes "COREDUMP (no confinement)"
-
- # PASS TEST, with r confinement
--genprofile $test:$coreperm
--cat $profile
-+cleancorefile
-+genprofile image=$test:$coreperm
-
- echo
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
-@@ -61,10 +89,10 @@
- checkcorefile yes "COREDUMP ($coreperm confinement)"
-
- # FAIL TEST, with x confinement
--genprofile $test:$nocoreperm
--cat $profile
-+cleancorefile
-+genprofile image=$test:$nocoreperm
-
- echo
- echo "*** A 'Segmentation Fault' message from bash is expected for the following test"
- runchecktest "COREDUMP ($nocoreperm confinement)" signal11
--checkcorefile no "COREDUMP ($nocoreperm confinement)"
-+checkcorefile xno "COREDUMP ($nocoreperm confinement)"
-
-=== modified file 'tests/regression/apparmor/mkprofile.pl'
---- tests/regression/subdomain/mkprofile.pl 2009-11-11 18:44:26 +0000
-+++ tests/regression/apparmor/mkprofile.pl 2010-08-03 17:27:13 +0000
-@@ -5,7 +5,7 @@
- #
- # Gawd, I hate writing perl. It shows, too.
- #
--my $__VERSION__='$Id$';
-+my $__VERSION__=$0;
-
- use strict;
- use Getopt::Long;
-
-=== modified file 'tests/regression/apparmor/prologue.inc'
---- tests/regression/subdomain/prologue.inc 2010-02-07 07:04:57 +0000
-+++ tests/regression/apparmor/prologue.inc 2010-08-03 17:27:13 +0000
-@@ -1,9 +1,14 @@
- # vim:syntax=sh
- #
--# prologue.inc
--#
- # Test infrastructure support.
- #
-+# Copyright 2010 Canonical, Ltd.
-+#
-+# This program is free software; you can redistribute it and/or
-+# modify it under the terms of the GNU General Public License as
-+# published by the Free Software Foundation, version 2 of the
-+# License.
-+#
- # This file should be included by each test case
- # It does a lot of hidden 'magic', Downside is that
- # this magic makes debugging fauling tests more difficult.
-@@ -93,8 +98,10 @@
-
- while [ -h ${link} ]
- do
-- if [ -x /usr/bin/readlink ] ; then
-- target=$(/usr/bin/readlink ${link})
-+ if [ -x /usr/bin/readlink ] ; then
-+ target=$(/usr/bin/readlink -f ${link})
-+ elif [ -x /bin/readlink ] ; then
-+ target=$(/bin/readlink -f ${link})
- else
- # I'm sure there's a more perlish way to do this
- target=$( perl -e "printf (\"%s\n\", readlink(\"${link}\"));")
-@@ -251,6 +258,7 @@
- then
- echo "Error: ${testname} passed. Test '${_testdesc}' was expected to '${_pfmode}'"
- testfailed
-+ return
- elif [ "$_pfmode" == "pass" -a -n "${_known}" ]
- then
- echo "Alert: ${testname} passed. Test '${_testdesc}' was marked as expected pass but known problem (xpass)"
-@@ -260,6 +268,7 @@
- then
- echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure '${ret}'"
- testfailed
-+ return
- elif [ "$_pfmode" == "fail" -a -n "${_known}" ]
- then
- echo "Alert: ${testname} failed. Test '${_testdesc}' was marked as expected fail but known problem (xfail)."
-@@ -272,16 +281,23 @@
- then
- echo "Error: ${testname} failed. Test '${_testdesc}' was expected to terminate with signal ${expectedsig}${_known}. Instead it terminated with signal ${killedsig}"
- testfailed
-+ return
- fi
- ;;
- *) echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'${_known}. Reason for failure 'killed by signal ${killedsig}'"
- testfailed
-+ return
- ;;
- esac
- ;;
- *) testerror
-+ return
- ;;
- esac
-+
-+ if [ -n "$VERBOSE" ]; then
-+ echo "ok: ${_testdesc}"
-+ fi
- }
-
- runchecktest()
-@@ -399,22 +415,12 @@
- # it is most often used after --, in fact it is basically
- # mandatory after --
- case "$1" in
-- profile=*) imagename=`echo $1 | sed 's/^profile=[rix]*//'`
-- perm=`echo $1 | sed -n 's/^profile=\([rix]*\).*$/\1/p'`
-- if [ -n "$perm" ]
-- then
-- imageperm=$perm
-- fi
-- num_emitted=0
-- shift
-- ;;
--
-- image=*) imagename=`echo $1 | sed 's/^image=[rix]*//'`
-+ image=*) imagename=`echo $1 | sed 's/^image=\([^:]*\).*$/\1/'`
- if [ ! -x "$imagename" ]
- then
- fatalerror "invalid imagename specified in input '$1'"
- fi
-- perm=`echo $1 | sed -n 's/^image=\([rix]*\).*$/\1/p'`
-+ perm=`echo $1 | sed -n 's/^image=[^:]*:\(.*\)$/\1/p'`
- if [ -n "$perm" ]
- then
- imageperm=$perm
-
-=== modified file 'tests/regression/apparmor/pwrite.sh'
---- tests/regression/subdomain/pwrite.sh 2007-12-23 00:58:47 +0000
-+++ tests/regression/apparmor/pwrite.sh 2010-08-03 17:27:13 +0000
-@@ -27,7 +27,7 @@
-
- genprofile $file:$okperm
-
--runtestbg "PWRITE with w" pass $file
-+runtestbg "PREAD/PWRITE with rw" pass $file
-
- sleep 2
-
-
-=== modified file 'tests/regression/apparmor/swap.sh'
---- tests/regression/subdomain/swap.sh 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/swap.sh 2010-08-03 17:27:13 +0000
-@@ -32,7 +32,7 @@
- swap_file=$tmpdir/swapfile
-
- dd if=/dev/zero of=${swap_file} bs=1024 count=512 2> /dev/null
--/sbin/mkswap ${swap_file} > /dev/null
-+/sbin/mkswap -f ${swap_file} > /dev/null
-
- # TEST 1. Make sure can enable and disable swap unconfined
-
-
-=== modified file 'tests/regression/apparmor/syscall.sh'
---- tests/regression/subdomain/syscall.sh 2007-12-23 01:02:50 +0000
-+++ tests/regression/apparmor/syscall.sh 2010-08-03 17:27:13 +0000
-@@ -1,7 +1,7 @@
- #! /bin/bash
--# $Id$
--
-+#
- # Copyright (C) 2002-2005 Novell/SUSE
-+# Copyright (C) 2010 Canonical, Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License as
-@@ -114,9 +114,9 @@
- runchecktest "MKNOD sock (permissions)" fail s $mknod_file
-
- ##
--## D. SETHOSTNAME
-+## C. SYSCTL
- ##
--sh syscall_sysctl.sh
-+bash syscall_sysctl.sh
-
- ##
- ## D. SETHOSTNAME
-
-=== modified file 'tests/regression/apparmor/syscall_mknod.c'
---- tests/regression/subdomain/syscall_mknod.c 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/syscall_mknod.c 2010-08-03 17:27:13 +0000
-@@ -19,7 +19,7 @@
-
- int main(int argc, char *argv[])
- {
--int fd, mode;
-+ int mode;
-
- if (argc != 3){
- fprintf(stderr, "usage: %s b|c|f|s|r file\n",
-@@ -49,8 +49,6 @@
- return 1;
- }
-
-- close(fd);
--
- printf("PASS\n");
-
- return 0;
-
-=== modified file 'tests/regression/apparmor/unix_fd_server.c'
---- tests/regression/subdomain/unix_fd_server.c 2006-05-19 17:32:14 +0000
-+++ tests/regression/apparmor/unix_fd_server.c 2010-08-03 17:27:13 +0000
-@@ -2,6 +2,7 @@
-
- /*
- * Copyright (C) 2002-2005 Novell/SUSE
-+ * Copyright (C) 2010 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
-@@ -134,6 +135,7 @@
- }
-
- /* Check for info re: reading the file */
-+ memset(inbound_buffer, 0, sizeof(inbound_buffer));
- if (recv(in_sock, inbound_buffer, 16,0) == -1 ) {
- fprintf(stderr, "FAIL - recv %s\n",
- strerror(errno));
-
-=== modified file 'tests/stress/parser/stress.rb'
---- tests/stress/parser/stress.rb 2008-11-26 22:16:48 +0000
-+++ tests/stress/parser/stress.rb 2010-05-31 18:58:40 +0000
-@@ -14,10 +14,27 @@
- return sprintf("%0#{len}x", rand(2 ** (4 * len)))
- end
-
-+def get_random_regex()
-+ case rand(10)
-+ when 0..3
-+ return "{#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)}}"
-+ when 4..5
-+ return "[#{get_random_name(rand(5) + 1)}]"
-+ when 6..7
-+ return "*"
-+ when 8..9
-+ return "**"
-+ end
-+end
-+
- def get_random_path()
- out = ""
-- 0.upto(rand(20)) do
-- out = "#{out}/#{get_random_name(4)}"
-+ 0.upto(rand(20) + 2) do
-+ if rand(4) == 0
-+ out = "#{out}/#{get_random_regex}"
-+ else
-+ out = "#{out}/#{get_random_name(rand(10) + 4)}"
-+ end
- end
- return out
- end
-@@ -83,7 +100,10 @@
- "mknod",
- "lease",
- "audit_write",
-- "audit_control"
-+ "audit_control",
-+ "setfcap",
-+ "mac_override",
-+ "mac_admin"
- ]
-
- def initialize()
-@@ -95,6 +115,93 @@
- end
- end
-
-+class NetRule < Rule
-+ # XXX Fill me in
-+end
-+
-+class RlimitRule < Rule
-+ RLIMIT_LIST = [
-+#"cpu", # cpu rlimit not supported
-+ "fsize",
-+ "data",
-+ "stack",
-+ "core",
-+ "rss",
-+ "nofile",
-+ "ofile",
-+ "as",
-+ "nproc",
-+ "memlock",
-+ "locks",
-+ "sigpending",
-+ "msgqueue",
-+ "nice",
-+ "rtprio"
-+ ]
-+
-+ def initialize()
-+ @rlimit = RLIMIT_LIST[rand(RLIMIT_LIST.length)]
-+ if rand(20) == 0
-+ @limit = "infinity"
-+ elsif @rlimit == "nice"
-+ @limit = rand(40) - 20
-+ else
-+ @limit = rand(2 ** 31)
-+ end
-+ end
-+
-+ def to_s
-+ return " set rlimit #{@rlimit} <= #{@limit},"
-+ end
-+end
-+
-+class Flags
-+ FLAG_LIST = [
-+ "complain",
-+ "audit",
-+ "chroot_relative",
-+ "namespace_relative",
-+ "mediate_deleted",
-+ "delegate_deleted",
-+ "attach_disconnected",
-+ "no_attach_disconnected",
-+ "chroot_attach",
-+ "chroot_no_attach"
-+ ]
-+
-+ FLAG_CONFLICTS = [
-+ ["chroot_relative", "namespace_relative"],
-+ ["mediate_deleted", "delegate_deleted"],
-+ ["attach_disconnected", "no_attach_disconnected"],
-+ ["chroot_attach", "chroot_no_attach"]
-+ ]
-+
-+ def initialize()
-+ @flags = []
-+ if rand(2) == 1
-+ return
-+ end
-+
-+ 0.upto(4 - Math.log(rand(32) + 1).to_int) do |x|
-+ @flags << FLAG_LIST[rand(FLAG_LIST.length)]
-+ end
-+
-+ FLAG_CONFLICTS.each do |c|
-+ if @flags.include?(c[0]) and @flags.include?(c[1])
-+ @flags.delete(c[rand(2)])
-+ end
-+ end
-+ end
-+
-+ def to_s
-+ if @flags.empty?
-+ return ""
-+ end
-+ out = @flags.join(",")
-+ return "flags=(#{out})"
-+ end
-+end
-+
- def prefix_to_s(name)
- out = []
- out << "#"
-@@ -112,16 +219,19 @@
- @rvalue = get_random_name()
- @name = "/does/not/exist/#{@rvalue}"
- @rules = []
-+ @flags = Flags.new()
- end
-
- def generate_rules
-- @rules << FileRule.new(@name, "rm")
-+ @rules << FileRule.new(@name, "rm").to_s
- 0.upto(rand($max_rules - $min_rules) + $min_rules) do |x|
- case rand(100)
-- when 0..19
-- @rules << CapRule.new
-- when 19..100
-- @rules << FileRule.new
-+ when 0..14
-+ @rules << CapRule.new.to_s
-+ when 15..24
-+ @rules << RlimitRule.new.to_s
-+ when 25..100
-+ @rules << FileRule.new.to_s
- end
- end
- end
-@@ -132,10 +242,10 @@
- out << "# profile for #{@name}"
- out << "# generated by #{__FILE__} #{$my_version}"
- out << "#"
-- out << "#{@name} {"
-+ out << "#{@name} #{@flags} {"
- out << " #include <abstractions/base>"
- out << ""
-- @rules.each { |r| out << r.to_s }
-+ @rules.sort.each { |r| out << " #{r}" }
- out << "}"
- out << ""
- end
-
-=== modified file 'utils/SubDomain.pm'
---- utils/SubDomain.pm 2010-03-10 23:30:06 +0000
-+++ utils/SubDomain.pm 2010-08-03 17:27:13 +0000
-@@ -2,6 +2,7 @@
- #
- # ----------------------------------------------------------------------
- # Copyright (c) 2006 Novell, Inc. All Rights Reserved.
-+# Copyright (c) 2010 Canonical, Ltd.
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of version 2 of the GNU General Public
-@@ -2413,10 +2414,13 @@
- our $seenmark;
- my $RE_LOG_v2_0_syslog = qr/SubDomain/;
- my $RE_LOG_v2_1_syslog = qr/kernel:\s+(\[[\d\.\s]+\]\s+)?(audit\([\d\.\:]+\):\s+)?type=150[1-6]/;
-+my $RE_LOG_v2_6_syslog = qr/kernel:\s+(\[[\d\.\s]+\]\s+)?type=\d+\s+audit\([\d\.\:]+\):\s+apparmor=/;
- my $RE_LOG_v2_0_audit =
- qr/type=(APPARMOR|UNKNOWN\[1500\]) msg=audit\([\d\.\:]+\):/;
- my $RE_LOG_v2_1_audit =
- qr/type=(UNKNOWN\[150[1-6]\]|APPARMOR_(AUDIT|ALLOWED|DENIED|HINT|STATUS|ERROR))/;
-+my $RE_LOG_v2_6_audit =
-+ qr/type=AVC\s+audit\([\d\.\:]+\):\s+apparmor=/;
-
- sub prefetch_next_log_entry {
- # if we already have an existing cache entry, something's broken
-@@ -2434,6 +2438,8 @@
- $RE_LOG_v2_0_audit |
- $RE_LOG_v2_1_audit |
- $RE_LOG_v2_1_syslog |
-+ $RE_LOG_v2_6_syslog |
-+ $RE_LOG_v2_6_audit |
- $logmark
- }x);
- }
-@@ -6612,10 +6618,14 @@
- LibAppArmor::free_record($event);
-
- #map new c and d to w as logprof doesn't support them yet
-- $rmask =~ s/c/w/g;
-- $rmask =~ s/d/w/g;
-- $dmask =~ s/c/w/g;
-- $dmask =~ s/d/w/g;
-+ if ($rmask) {
-+ $rmask =~ s/c/w/g;
-+ $rmask =~ s/d/w/g;
-+ }
-+ if ($dmask) {
-+ $dmask =~ s/c/w/g;
-+ $dmask =~ s/d/w/g;
-+ }
-
- if ($rmask && !validate_log_mode(hide_log_mode($rmask))) {
- fatal_error(sprintf(gettext('Log contains unknown mode %s.'),
-
-=== modified file 'utils/apparmor_notify'
---- utils/apparmor_notify 2010-03-10 16:11:26 +0000
-+++ utils/apparmor_notify 2010-05-31 18:58:40 +0000
-@@ -30,8 +30,7 @@
- require Time::Local;
- require File::Basename;
-
--use vars qw($opt_p $opt_s $opt_l $opt_h $opt_v $opt_d $opt_w);
--use Getopt::Std;
-+use Getopt::Long;
-
- my %prefs;
- my $conf = "/etc/apparmor/notify.conf";
-@@ -67,7 +66,6 @@
- $ENV{SHELL} = "/bin/sh";
- defined($ENV{IFS}) and $ENV{IFS} = ' \t\n';
-
--print $0 . "\n";
- my $prog = File::Basename::basename($0);
-
- if ($prog !~ /^[a-zA-Z0-9_\-]+$/) {
-@@ -75,32 +73,66 @@
- exitscript(1);
- }
-
--my $logfile = "/var/log/kern.log";
---e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
-
- $> == $< or die "Cannot be suid\n";
- $) == $( or die "Cannot be sgid\n";
-
- my $login;
-+our $orig_euid = $>;
-
--getopts('dhlpvs:w:');
-+my $opt_d = '';
-+my $opt_h = '';
-+my $opt_l = '';
-+my $opt_p = '';
-+my $opt_v = '';
-+my $opt_f = '';
-+my $opt_s = 0;
-+my $opt_u = '';
-+my $opt_w = 0;
-+GetOptions(
-+ 'debug|d' => \$opt_d,
-+ 'help|h' => \$opt_h,
-+ 'since-last|l' => \$opt_l,
-+ 'poll|p' => \$opt_p,
-+ 'verbose|v' => \$opt_v,
-+ 'file|f=s' => \$opt_f,
-+ 'since-days|s=n' => \$opt_s,
-+ 'user|u=s' => \$opt_u,
-+ 'wait|w=n' => \$opt_w,
-+);
- if ($opt_h) {
- usage;
- exitscript(0);
- }
+ # keep exit status from parser during profile load. 0 is good, 1 is bad
+ STATUS=0
+
+@@ -221,7 +212,6 @@
+
+ profiles_names_list() {
+ # run the parser on all of the apparmor profiles
+- TMPFILE=$1
+ if [ ! -f "$PARSER" ]; then
+ aa_log_failure_msg "- AppArmor parser not found"
+ exit 1
+@@ -234,9 +224,9 @@
+
+ for profile in $PROFILE_DIR/*; do
+ if skip_profile "${profile}" && [ -f "${profile}" ] ; then
+- LIST_ADD=$($PARSER $ABSTRACTIONS -N "$profile" | grep -v '\^')
++ LIST_ADD=$($PARSER $ABSTRACTIONS -N "$profile" )
+ if [ $? -eq 0 ]; then
+- echo "$LIST_ADD" >>$TMPFILE
++ echo "$LIST_ADD"
+ fi
+ fi
+ done
+@@ -408,18 +398,16 @@
+ fi
-+# monitor file specified with -f, else use audit.log if auditd is running,
-+# otherwise kern.log
-+our $logfile = "/var/log/kern.log";
-+if ($opt_f) {
-+ -f $opt_f or die "'$opt_f' does not exist. Aborting\n";
-+ $logfile = $opt_f;
-+} else {
-+ -e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
+ retval=0
+- #the list of profiles isn't stable once we start adding or removing
+- #them so store to tmp first (in reverse order so hat profiles are removed first)
+- MODULE_PLIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+- sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | sort -r > "$MODULE_PLIST"
+- cat "$MODULE_PLIST" | while read profile ; do
++ # We filter child profiles as removing the parent will remove
++ # the children
++ sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" \
++ LC_COLLATE=C sort | grep -v // | while read profile ; do
+ echo -n "$profile" > "$SFS_MOUNTPOINT/.remove"
+ rc=$?
+ if [ ${rc} -ne 0 ] ; then
+ retval=${rc}
+ fi
+ done
+- rm "$MODULE_PLIST"
+ return ${retval}
+ }
+
+@@ -461,17 +449,33 @@
+
+ configure_owlsm
+ parse_profiles reload
+- PNAMES_LIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+- profiles_names_list ${PNAMES_LIST}
+- MODULE_PLIST=$(mktemp ${APPARMOR_TMPDIR}/tmp.XXXXXXXX)
+ # Clean out running profiles not associated with the current profile
+ # set, excluding the libvirt dynamically generated profiles.
+- sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | egrep -v '^libvirt-[0-9a-f\-]+$' | sort >"$MODULE_PLIST"
+- sort "$PNAMES_LIST" | comm -2 -3 "$MODULE_PLIST" - | while IFS= read profile ; do
++ # Note that we reverse sort the list of profiles to remove to
++ # ensure that child profiles (e.g. hats) are removed before the
++ # parent. We *do* need to remove the child profile and not rely
++ # on removing the parent profile when the profile has had its
++ # child profile names changed.
++ profiles_names_list | awk '
++BEGIN {
++ while (getline < "'${SFS_MOUNTPOINT}'/profiles" ) {
++ str = sub(/ \((enforce|complain)\)$/, "", $0);
++ if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
++ arr[$str] = $str
++ }
+}
+
-+-r $logfile or die "Cannot read '$logfile'\n";
-+our $logfile_inode = get_logfile_inode($logfile);
-+our $logfile_size = get_logfile_size($logfile);
- open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
- # Drop priviliges, if running as root
- if ($< == 0) {
- $login = "root";
- if (defined($ENV{SUDO_UID}) and defined($ENV{SUDO_GID})) {
- POSIX::setgid($ENV{SUDO_GID}) or _error("Could not change gid");
-- POSIX::setuid($ENV{SUDO_UID}) or _error("Could not change uid");
-+ $> = $ENV{SUDO_UID} or _error("Could not change euid");
- defined($ENV{SUDO_USER}) and $login = $ENV{SUDO_USER};
- } else {
-+ my $drop_to = $nobody_user;
-+ if ($opt_u) {
-+ $drop_to = $opt_u;
-+ }
- # nobody/nogroup
-- POSIX::setgid(scalar(getpwnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
-- POSIX::setuid(scalar(getpwnam($nobody_user))) or _error("Could not change uid to '$nobody_user'");
-+ POSIX::setgid(scalar(getgrnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
-+ $> = scalar(getpwnam($drop_to)) or _error("Could not change euid to '$drop_to'");
- }
- } else {
- $login = getlogin();
-@@ -111,7 +143,7 @@
- readconf($conf);
- if (defined($prefs{use_group})) {
- my ($name, $passwd, $gid, $members) = getgrnam($prefs{use_group});
-- if (not defined($members) or not defined($login) or not grep { $_ eq $login } split(/ /, $members)) {
-+ if (not defined($members) or not defined($login) or (not grep { $_ eq $login } split(/ /, $members) and $login ne "root")) {
- _error("'$login' must be in '$prefs{use_group}' group. Aborting");
- }
- }
-@@ -220,7 +252,6 @@
- defined($name) and $formatted .= "Name: $name\n";
- defined($denied) and $formatted .= "Denied: $denied\n";
- defined($family) and defined ($sock_type) and $formatted .= "Family: $family\nSocket type: $sock_type\n";
-- #defined($date) and $since > 0 and $formatted .= "Date: ". scalar(localtime($date)) ."\n";
- $formatted .= "Logfile: $logfile\n";
-
- return $formatted;
-@@ -259,6 +290,26 @@
- close(PS);
- }
-
-+sub send_message {
-+ my $msg = $_[0];
-+
-+ my $pid = fork();
-+ if ($pid == 0) { # child
-+ # notify-send needs $< to be the unprivileged user
-+ $< = $>;
++{ if (length(arr[$0]) > 0) { delete arr[$0] } }
+
-+ # 'system' uses execvp() so no shell metacharacters here.
-+ # $notify_exe is an absolute path so execvp won't search PATH.
-+ system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$msg";
-+ my $exit_code = $? >> 8;
-+ exit($exit_code);
++END {
++ for (key in arr)
++ if (length(arr[key]) > 0) {
++ printf("%s\n", arr[key])
+ }
-+
-+ # parent
-+ waitpid($pid, 0);
-+ return $?;
+}
-+
- sub do_notify {
- my %seen;
- my $seconds = 5;
-@@ -273,7 +324,7 @@
- umask 0;
- open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
- open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
-- open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
-+ #open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
- my $pid = fork();
- exit if $pid;
- die "Couldn't fork: $!" unless defined($pid);
-@@ -293,12 +344,24 @@
- my $count = 0;
- my $footer = "For more information, please see:\n$url";
- my $first_run = 1;
-- my $since = $now - (int($opt_s) * 60 * 60 * 24);
-+ my $since = $now;
-+ if ($opt_s and int($opt_s) > 0) {
-+ $since = $since - (int($opt_s) * 60 * 60 * 24);
-+ }
- for (my $i=0; $time_to_die == 0; $i++) {
-+ if ($logfile_inode != get_logfile_inode($logfile)) {
-+ _warn("$logfile changed inodes, reopening");
-+ reopen_logfile();
-+ } elsif (get_logfile_size($logfile) < $logfile_size) {
-+ _warn("$logfile is smaller, reopening");
-+ reopen_logfile();
-+ }
- while(my $msg = <LOGFILE>) {
- my @attrib;
-- if ($first_run == 1 and $opt_s) {
-- @attrib = parse_message($msg, $since);
-+ if ($first_run == 1) {
-+ if ($since != $now) {
-+ @attrib = parse_message($msg, $since);
-+ }
- } else {
- @attrib = parse_message($msg);
- }
-@@ -340,12 +403,9 @@
-
- $m .= $footer;
-
-- # 'system' uses execvp() so no shell metacharacters here.
-- # $notify_exe is an absolute path so execvp won't search PATH.
-- system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
-- my $exit_code = $? >> 8;
-- if ($exit_code != 0) {
-- _warn("'$notify_exe' exited with '$exit_code'");
-+ my $rc = send_message($m);
-+ if ($rc != 0) {
-+ _warn("'$notify_exe' exited with error '$rc'");
- $time_to_die = 1;
- last;
- }
-@@ -356,7 +416,7 @@
-
- if ($first_run) {
- if ($count > 0) {
-- my $m = "$logfile contains $count existing denied message";
-+ my $m = "$logfile contains $count denied message";
- $count > 1 and $m .= "s";
- if ($opt_s) {
- $m .= " in the last ";
-@@ -368,7 +428,7 @@
- }
- $m .= ". ";
- $m .= $footer;
-- system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
-+ send_message($m);
- }
- $first_run = 0;
- }
-@@ -390,6 +450,9 @@
- }
-
- sub show_since {
-+ my %msg_hash;
-+ my %last_date;
-+ my @msg_list;
- my $count = 0;
- while(my $msg = <LOGFILE>) {
- my @attrib = parse_message($msg, $_[0]);
-@@ -397,10 +460,31 @@
-
- my $m = format_message(@attrib);
- $m ne "" or next;
--
-- $opt_v and print "$m\n";
-+ my $date = $attrib[6];
-+ if ($opt_v) {
-+ if (exists($msg_hash{$m})) {
-+ $msg_hash{$m}++;
-+ defined($date) and $last_date{$m} = scalar(localtime($date));
-+ } else {
-+ $msg_hash{$m} = 1;
-+ push(@msg_list, $m);
-+ }
-+ }
- $count++;
- }
-+ if ($opt_v) {
-+ foreach my $m (@msg_list) {
-+ print "$m";
-+ if ($msg_hash{$m} gt 1) {
-+ print "($msg_hash{$m} found";
-+ if (exists($last_date{$m})) {
-+ print ", most recent from '$last_date{$m}'";
-+ }
-+ print ")\n";
-+ }
-+ print "\n";
-+ }
-+ }
- return $count;
- }
-
-@@ -452,19 +536,63 @@
- sub usage {
- my $s = <<'EOF';
- USAGE: apparmor_notify [OPTIONS]
-+
- Display AppArmor notifications or messages for DENIED entries.
-
- OPTIONS:
-- -p poll AppArmor logs and display notifications
-- -l display stats since last login
-- -s NUM show stats for last NUM days (can be used alone or with -p)
-- -v show messages with stats
-- -h display this help
-- -w NUM wait NUM seconds before displaying notifications (with -p)
-+ -p, --poll poll AppArmor logs and display notifications
-+ -f FILE, --file=FILE search FILE for AppArmor messages
-+ -l, --since-last display stats since last login
-+ -s NUM, --since-days=NUM show stats for last NUM days (can be used alone
-+ or with -p)
-+ -v, --verbose show messages with stats
-+ -h, --help display this help
-+ -u USER, --user=USER user to drop privileges to when not using sudo
-+ -w NUM, --wait=NUM wait NUM seconds before displaying
-+ notifications (with -p)
- EOF
- print $s;
++' | LC_COLLATE=C sort -r | while IFS= read profile ; do
+ echo -n "$profile" > "$SFS_MOUNTPOINT/.remove"
+ done
+- rm "$MODULE_PLIST"
+- rm "$PNAMES_LIST"
+ return 0
}
-+sub reopen_logfile {
-+ # reopen the logfile, temporarily switching back to starting euid for
-+ # file permissions.
-+ close(LOGFILE);
-+
-+ my $old_euid = $>;
-+ my $change_euid = 0;
-+ if ($> != $<) {
-+ _debug("raising privileges to '$orig_euid' in reopen_logfile()");
-+ $change_euid = 1;
-+ $> = $orig_euid;
-+ $> == $orig_euid or die "Could not raise privileges\n";
-+ }
-+
-+ $logfile_inode = get_logfile_inode($logfile);
-+ $logfile_size = get_logfile_size($logfile);
-+ open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
-+
-+ if ($change_euid) {
-+ _debug("dropping privileges to '$old_euid' in reopen_logfile()");
-+ $> = $old_euid;
-+ $> == $old_euid or die "Could not drop privileges\n";
-+ }
-+}
-+
-+sub get_logfile_size {
-+ my $fn = $_[0];
-+ my $size;
-+ defined(($size = (stat($fn))[7])) or (sleep(10) and defined(($size = (stat($fn))[7])) or die "'$fn' disappeared. Aborting\n");
-+ return $size;
-+}
-+
-+sub get_logfile_inode {
-+ my $fn = $_[0];
-+ my $inode;
-+ defined(($inode = (stat($fn))[1])) or (sleep(10) and defined(($inode = (stat($fn))[1])) or die "'$fn' disappeared. Aborting\n");
-+ return $inode;
-+}
-+
- #
- # end Subroutines
- #
-
-=== modified file 'utils/apparmor_notify.pod'
---- utils/apparmor_notify.pod 2010-02-12 16:25:02 +0000
-+++ utils/apparmor_notify.pod 2010-05-31 18:58:40 +0000
-@@ -40,24 +40,37 @@
-
- =over 4
-
--=item -p
-+=item -p, --poll
-
- poll AppArmor logs and display desktop notifications. Can be used with '-s'
- option to display a summary on startup.
-
--=item -l
-+=item -f FILE, --file=FILE
-+
-+search FILE for AppArmor messages
-+
-+=item -l, --since-last
-
- show summary since last login.
-
--=item -s NUM
-+=item -s NUM, --since-days=NUM
-
- show summary for last NUM of days.
-
--=item -v
-+=item -u USER, --user=USER
-+
-+user to drop privileges to when running privileged. This has no effect when
-+running under sudo.
-+
-+=item -w NUM, --wait=NUM
-+
-+wait NUM seconds before displaying notifications (for use with -p)
-+
-+=item -v, --verbose
-
- show messages with summaries.
-
--=item -h
-+=item -h, --help
-
- displays a short usage statement.
-