home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky comp.mail.elm:3355 comp.sources.bugs:273
- Newsgroups: comp.mail.elm,comp.sources.bugs
- Path: sparky!uunet!ukma!cs.widener.edu!dsinc!syd
- From: syd@dsinc.DSI.COM (Syd Weinstein)
- Subject: elm 2.4 Patch #9
- Message-ID: <1992Nov17.191856.8050@DSI.COM>
- Followup-To: poster
- Summary: This is an official patch for elm 2.4 system. Please apply it.
- Sender: syd@DSI.COM (Syd Weinstein)
- Priority: HIGH
- Organization: Datacomp Systems, Inc., Huntingdon Valley, PA 19006
- Date: Tue, 17 Nov 1992 19:18:56 GMT
- Lines: 1977
-
- part 1 of a 2 part patch
-
- I think that the code in 'newmbox.c' which handles bad 'Content-length'
- entries is incomplete. The file-ptr for the mail file is
- backed up, but the file-ptr of the temp file WAS LEFT UNMODIFIED !
- From langesw.ssw.de!root Wed Nov 11 14:28:57 1992
-
- When elm copies the temp mailbox back to the mail spool to resync or
- quit, it changes to the mailgroup before attempting to diddle in the
- mail spool, but when it copies the temp mailbox back to the mail spool
- after editing, it forgets to change to mailgroup. This patch appears
- to work, but I haven't exhaustively checked for some path that leaves
- the gid set
- wrong. From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
-
- There's an error in two messages in s_aliases.m which causes elm2.4
- to core dump when resyncronize aliases. (%s/%s) should be (%c/%c).
-
- This bug doesn't show up unless you use message cataloges, since the default
- message in a_quit.c is correct.
- From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
-
- Fix how nls emulation lib gencat links prev pointers
- From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
-
- The alias message_count isn't set to zero if the last alias has
- been deleted from the alias table. As no aliases are reread from
- the aliases database the message_count is left as it was before.
-
- Fixed that the function do_newalias() sometimes returns without freeing
- the buffer allocated before. The patch adds these free calls.
-
- When you erroneously type a number in your folder elm asks you for
- a new current message number. But now if you erase this one number
- and leave the string empty elm will set the new current message to
- the second message on our sun4! The patch adds a check for an empty
- string and returns the current number if no number was entered.
- From: vogt@isa.de (Gerald Vogt)
-
- The situation is that the .elm/aliases file is missing, but
- .elm/aliases.dir and .elm/aliases.pag exist (isn't serendipity
- wonderful?). The ndbz functions tolerate this and just put a NULL
- pointer in the db structure for the data file FILE pointer. However,
- get_one_alias() in listalias and elm doesn't account for the db_open()
- succeeding but the dbz_basef field being NULL, so it passes the NULL
- pointer to fread(). Detect null and return 0
- From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
-
- Clear the screen before displaying MIME:
- From: marius@rhi.hi.is (Marius Olafsson)
-
- Add regexp processing to filter.
- Add execc operator
- From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
-
- Fix: From rn, say "| patch -p -N -d DIR", where DIR is your elm source
- directory. Outside of rn, say "cd DIR; patch -p -N <thisarticle".
- If you don't have the patch program, apply the following by hand,
- or get patch (version 2.0, latest patchlevel).
-
- After patching:
- Do nothing, apply patch 10 next
-
- If patch indicates that patchlevel is the wrong version, you may need
- to apply one or more previous patches, or the patch may already
- have been applied. See the patchlevel.h file to find out what has or
- has not been applied. In any event, don't continue with the patch.
-
- If you are missing previous patches they can be obtained from our:
- archive server.
-
- Syd Weinstein
- elm@DSI.COM
-
- The patches are available from the dsinc archive server
- Send the following message to archive-server@DSI.COM for
- a list of available patches:
-
- Subject: patch list
- send index elm
-
- Index: hdrs/patchlevel.h
- Prereq: "8"
- *** ../elm2.4/hdrs/patchlevel.h Tue Nov 10 15:20:28 1992
- --- hdrs/patchlevel.h Sat Nov 14 16:40:24 1992
- ***************
- *** 1 ****
- ! #define PATCHLEVEL "8"
- --- 1 ----
- ! #define PATCHLEVEL "9"
-
- Index: Configure
- Prereq: 5.6
- *** ../elm2.4/Configure Tue Oct 27 11:17:21 1992
- --- Configure Tue Nov 17 13:19:52 1992
- ***************
- *** 8,14 ****
- # and edit it to reflect your system. Some packages may include samples
- # of config.h for certain machines, so you might look for one of those.)
- #
- ! # $Header: /home/syd/elm.rel/RCS/Configure,v 5.6 1992/10/25 02:18:36 syd Exp $
- #
- # Yes, you may rip this off to use in other distribution packages.
- # (Note: this Configure script was generated automatically. Rather than
- --- 8,14 ----
- # and edit it to reflect your system. Some packages may include samples
- # of config.h for certain machines, so you might look for one of those.)
- #
- ! # $Header: /home/syd/elm.rel/RCS/Configure,v 5.9 1992/11/17 18:19:47 syd Exp $
- #
- # Yes, you may rip this off to use in other distribution packages.
- # (Note: this Configure script was generated automatically. Rather than
- ***************
- *** 205,210 ****
- --- 205,211 ----
- d_termio=''
- d_termios=''
- d_tz_min=''
- + d_tzname=''
- d_useembed=''
- d_utimbuf=''
- d_vfork=''
- ***************
- *** 303,309 ****
- attrlist="$attrlist $mc68k __STDC__ UTS M_I8086 M_I186 M_I286 M_I386"
- attrlist="$attrlist i186 __m88k__ m88k DGUX __DGUX__ NeXT _AIX"
- pth="/bin /usr/bin /usr/ucb /sbin /usr/sbin /usr/local /usr/local/bin /usr/lbin"
- ! pth="$pth /usr/5bin /vol/local/bin /etc /usr/bsd /usr/lib /usr/css/lib /lib"
- pth="$pth /usr/local/lib /sys5.3/bin /sys5.3/usr/bin /bsd4.3/bin /bsd4.3/usr/bin /bsd4.3/usr/ucb"
- pth="$pth /usr/convex /usr/mmdf/bin /usr/mmdf/lib ${BSDBASE-/bsd}/usr/ucb ${BSDBASE-/bsd}/bin ${BSDBASE-/bsd}/usr/bin"
-
- --- 304,310 ----
- attrlist="$attrlist $mc68k __STDC__ UTS M_I8086 M_I186 M_I286 M_I386"
- attrlist="$attrlist i186 __m88k__ m88k DGUX __DGUX__ NeXT _AIX"
- pth="/bin /usr/bin /usr/ucb /sbin /usr/sbin /usr/local /usr/local/bin /usr/lbin"
- ! pth="$pth /usr/5bin /vol/local/bin /etc /usr/bsd /usr/lib /usr/ccs/lib /usr/ccs/bin /lib"
- pth="$pth /usr/local/lib /sys5.3/bin /sys5.3/usr/bin /bsd4.3/bin /bsd4.3/usr/bin /bsd4.3/usr/ucb"
- pth="$pth /usr/convex /usr/mmdf/bin /usr/mmdf/lib ${BSDBASE-/bsd}/usr/ucb ${BSDBASE-/bsd}/bin ${BSDBASE-/bsd}/usr/bin"
-
- ***************
- *** 798,804 ****
- if $test -f "$uname"; then
- uname_os=`uname -s`
- uname_rel=`uname -r`
- ! uname_rel=`expr "$uname" : "\(...\).*"`
- else
- uname_os=unknown
- uname_rel=unknown
- --- 799,805 ----
- if $test -f "$uname"; then
- uname_os=`uname -s`
- uname_rel=`uname -r`
- ! uname_rel=`expr "$uname_rel" : "\(...\).*"`
- else
- uname_os=unknown
- uname_rel=unknown
- ***************
- *** 810,816 ****
- echo exit 0 >usg
- echo exit 1 >v7
- elif $contains SIGTSTP foo >/dev/null 2>&1 ; then
- ! if $test "$uname_os" = "SunOs" -a "$uname_rel" = "4.1" ; then
- echo "Looks like SunOs 4.1, a USG system, but we'll see..."
- echo exit 1 >bsd
- echo exit 0 >usg
- --- 811,817 ----
- echo exit 0 >usg
- echo exit 1 >v7
- elif $contains SIGTSTP foo >/dev/null 2>&1 ; then
- ! if $test "(" $uname_os" = "SunOS" -a "$uname_rel" = "4.1")" ; then
- echo "Looks like SunOs 4.1, a USG system, but we'll see..."
- echo exit 1 >bsd
- echo exit 0 >usg
- ***************
- *** 1405,1411 ****
-
- case "$ccflags" in
- '') case "$cc" in
- ! *gcc*) dflt='-fpcc-struct-return';;
- *) dflt='';;
- esac
- ;;
- --- 1406,1412 ----
-
- case "$ccflags" in
- '') case "$cc" in
- ! *gcc*) dflt='-fpcc-struct-return -traditional';;
- *) dflt='';;
- esac
- ;;
- ***************
- *** 3700,3705 ****
- --- 3701,3710 ----
- d_tz_min="$undef"
- fi
- $rm -f try.c
- + : see if there is a tzname
- + set tzname d_tzname
- + eval $inlibc
- +
- : check for valid reply/to fields
- case "$d_useembed" in
- "$define") dflt=y;;
- ***************
- *** 4516,4521 ****
- --- 4521,4527 ----
- d_termio='$d_termio'
- d_termios='$d_termios'
- d_tz_min='$d_tz_min'
- + d_tzname='$d_tzname'
- d_useembed='$d_useembed'
- d_utimbuf='$d_utimbuf'
- d_vfork='$d_vfork'
-
- Index: config.h.SH
- *** ../elm2.4/config.h.SH Tue Oct 27 11:17:22 1992
- --- config.h.SH Sat Nov 14 21:11:40 1992
- ***************
- *** 496,501 ****
- --- 496,506 ----
- */
- #$d_tz_min TZ_MINUTESWEST /**/
-
- + /* TZNAME:
- + * This symbol, if defined, indicates that extern char *tzname[] exists.
- + */
- + #$d_tzname TZNAME /**/
- +
- /* USE_EMBEDDED_ADDRESSES:
- * This symbol, if defined, indicates that replyto: and from:
- * headers can be trusted.
-
- Index: Instruct
- *** ../elm2.4/Instruct Sat Oct 3 18:12:32 1992
- --- Instruct Sat Nov 14 20:07:24 1992
- ***************
- *** 1,7 ****
- Instructions
- ------------
-
- ! Last Update: $Date: 1992/10/03 22:12:17 $
-
-
- This file contains instructions on how to create and install
- --- 1,7 ----
- Instructions
- ------------
-
- ! Last Update: $Date: 1992/11/15 01:07:19 $
-
-
- This file contains instructions on how to create and install
- ***************
- *** 16,22 ****
-
- $ sh Configure
-
- ! Answer the questions of that program,, then let it create the
- localized Makefiles and system definition files for you. When it's
- done you can double check the configuration (or customize it further)
- by reading the Configuration Guide and then rerunning Configure.
- --- 16,22 ----
-
- $ sh Configure
-
- ! Answer the questions of that program, then let it create the
- localized Makefiles and system definition files for you. When it's
- done you can double check the configuration (or customize it further)
- by reading the Configuration Guide and then rerunning Configure.
-
- Index: MANIFEST
- *** ../elm2.4/MANIFEST Tue Nov 10 15:20:21 1992
- --- MANIFEST Sat Nov 14 20:35:44 1992
- ***************
- *** 43,48 ****
- --- 43,49 ----
- filter/filter.c
- filter/lock.c
- filter/parse.c
- + filter/regexp.c
- filter/rules.c
- filter/summarize.c
- filter/utils.c
- ***************
- *** 59,64 ****
- --- 60,66 ----
- hdrs/ndbz.h
- hdrs/nl_types.h
- hdrs/patchlevel.h
- + hdrs/regexp.h
- hdrs/s_aliases.h
- hdrs/s_answer.h
- hdrs/s_arepdaem.h
-
- Index: README
- *** ../elm2.4/README Tue Nov 10 15:20:21 1992
- --- README Sat Nov 14 20:06:38 1992
- ***************
- *** 2,8 ****
-
- See the NOTICE and Instruct files for further details.
-
- ! It is IMPERITIVE that all users rerun newalias after installing
- Elm 2.4 when upgrading from a previous version. Elm's behavior
- with aliases could be unpredictible if this step is not performed.
-
- --- 2,8 ----
-
- See the NOTICE and Instruct files for further details.
-
- ! It is IMPERATIVE that all users rerun newalias after installing
- Elm 2.4 when upgrading from a previous version. Elm's behavior
- with aliases could be unpredictible if this step is not performed.
-
-
- Index: doc/Filter.guid
- Prereq: 5.1
- *** ../elm2.4/doc/Filter.guid Sat Oct 3 16:54:23 1992
- --- doc/Filter.guid Sat Nov 14 20:41:50 1992
- ***************
- *** 1,4 ****
- ! .\" @(#)$Id: Filter.guid,v 5.1 1992/10/03 20:51:50 syd Exp $
- .\"
- .\" A guide to the Elm Filter program
- .\" format with:
- --- 1,4 ----
- ! .\" @(#)$Id: Filter.guid,v 5.2 1992/11/15 01:41:50 syd Exp $
- .\"
- .\" A guide to the Elm Filter program
- .\" format with:
- ***************
- *** 12,17 ****
- --- 12,22 ----
- .\" Syd Weinstein elm@DSI.COM (dsinc!elm)
- .\"
- .\" $Log: Filter.guid,v $
- + .\" Revision 5.2 1992/11/15 01:41:50 syd
- + .\" Add regexp processing to filter.
- + .\" Add execc operator
- + .\" From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
- + .\"
- .\" Revision 5.1 1992/10/03 20:51:50 syd
- .\" Initial checkin as of 2.4 Release at PL0
- .\"
- ***************
- *** 145,150 ****
- --- 150,159 ----
- The \f2value\f1 is any quoted string that is to be matched against
- or number if ``lines'' is the field being considered.
- .sp
- + The relation ``matches'' (or ``~'') takes an egrep like regular expression
- + as the \f2value\f1. The regular expression must be enclosed in pairs of ``/''.
- + If you need a ``/'' in your expression write it as ``\\/''.
- + .sp
- Individual conditions are joined together by using the word ``and'',
- and the logic of a condition can be flipped by using ``not'' as the
- first word (e.g. `not subject "joe"'). We'll see more examples of
- ***************
- *** 162,167 ****
- --- 171,177 ----
- forward \f2address\f1
- forwardc \f2address\f1
- execute \f2command\f1
- + executec \f2command\f1
- leave
- .in 0
- .fi
- ***************
- *** 172,190 ****
- \f3forwardc\f1 sends the message to the specified address and leaves a copy in your mailbox;
- \f3execute\f1 feeds the message to the specified command (or complex
- sequence of commands) as standard input;
- and \f3leave\f1 leaves the message in your mailbox.
- .sp
- NOTE: The execute command assumes that you are doing something
- useful with incoming mail. The command does \f2not\f1
- ! automatically append the message to your mail spool. A
- ! command such as:
- .sp
- ! if (from = "dave") then echo mail from dave > /dev/tty
- .sp
- will result in \f2losing\f1 your mail. A more suitable
- use for execute would be:
- .sp
- ! if (from = "boss") then vacation pat
- .sp
- Foldernames can contain any of a number of macros, too, as we'll see in
- the example ruleset below. The macros available for the string fields are;
- --- 182,201 ----
- \f3forwardc\f1 sends the message to the specified address and leaves a copy in your mailbox;
- \f3execute\f1 feeds the message to the specified command (or complex
- sequence of commands) as standard input;
- + \f3executec\f1 is like \f3execute\f1 but also leaves a copy in your mailbox;
- and \f3leave\f1 leaves the message in your mailbox.
- .sp
- NOTE: The execute command assumes that you are doing something
- useful with incoming mail. The command does \f2not\f1
- ! automatically append the message to your mail spool. Use executec for that.
- ! A command such as:
- .sp
- ! if (from = "dave") then execute "echo mail from dave > /dev/tty"
- .sp
- will result in \f2losing\f1 your mail. A more suitable
- use for execute would be:
- .sp
- ! if (from = "boss") then execute "vacation pat"
- .sp
- Foldernames can contain any of a number of macros, too, as we'll see in
- the example ruleset below. The macros available for the string fields are;
- ***************
- *** 208,216 ****
- --- 219,236 ----
- .zf
- %t current hour and minute in HH:MM format
- %y year (last two digits)
- + %& the string that matched the last regular expression
- + %1-%9 the i:th subexpression in the last regular expression that matched
- .TE
- .ft 1
- .sp
- + If a message has a subject of \f2This is a test\f1, and the rule is
- + .sp
- + if (subject matches /([a-z]+) a ([a-z]+)/) then "echo %& %1 %2"
- + .sp
- + then %& expands to \f2is a test\f1, %1 expands to \f2is\f1 and %2 expands to
- + \f2test\f1.
- + .sp
- Foldernames may contain a leading '~/' which will be expanded to be
- your home directory.
- .sp
- ***************
- *** 586,599 ****
- .in .5i
-
- .ti -\n(TWu
- ! 1. The ability to use regular expressions in the patterns.
- ! This would be a \f2very\f1 nice feature!
- !
- ! .ti -\n(TWu
- ! 2. Perhaps more \f2actions\f1 available (but what?)
-
- .ti -\n(TWu
- ! 3. Certainly the ability to filter based on any field or combination of
- fields.
- .in 0
- .ne 5
- --- 606,615 ----
- .in .5i
-
- .ti -\n(TWu
- ! 1. Perhaps more \f2actions\f1 available (but what?)
-
- .ti -\n(TWu
- ! 2. Certainly the ability to filter based on any field or combination of
- fields.
- .in 0
- .ne 5
-
- Index: doc/filter.1
- *** ../elm2.4/doc/filter.1 Mon Oct 19 13:04:04 1992
- --- doc/filter.1 Sat Nov 14 20:48:08 1992
- ***************
- *** 58,63 ****
- --- 58,64 ----
- \fBsave \fIfoldername\fR
- \fBsavecopy \fIfoldername\fR
- \fBexecute \fIcommand\fR
- + \fBexecutec \fIcommand\fR
- \fBforward \fIaddress\fR
- \fBleave\fR
-
-
- Index: filter/regexp.c
- *** /dev/null Mon Nov 16 22:43:59 1992
- --- filter/regexp.c Mon Nov 16 23:10:02 1992
- ***************
- *** 0 ****
- --- 1,1214 ----
- +
- + /* $Id: regexp.c,v 5.4 1992/11/17 18:25:42 syd Exp $ */
- +
- + /*******************************************************************************
- + * The Elm Mail System - $Revision: 5.4 $ $State: Exp $
- + *
- + * Copyright (c) 1992 USENET Community Trust
- + *******************************************************************************
- + * Bug reports, patches, comments, suggestions should be sent to:
- + *
- + * Syd Weinstein, Elm Coordinator
- + * elm@DSI.COM dsinc!elm
- + *
- + *******************************************************************************
- + * $Log: regexp.c,v $
- + * Revision 5.4 1992/11/17 18:25:42 syd
- + * change to use index instead of strchr
- + * From: Syd
- + *
- + * Revision 5.3 1992/11/17 04:10:01 syd
- + * The changes to filter/regexp.c are to correct compiler warnings about
- + * unreachable statements.
- + *
- + * The changes to filter/rules.c are to correct the fact that we are passing
- + * a pointer to a condition_rec structore to a function expecting a pointer to
- + * a character string.
- + * From: Tom Moore <tmoore@fievel.DaytonOH.NCR.COM>
- + *
- + * Revision 5.2 1992/11/15 01:39:31 syd
- + * add proper headers
- + *
- + *
- + ******************************************************************************/
- +
- + /*
- + * regcomp and regexec -- regsub and regerror are elsewhere
- + *
- + * Copyright (c) 1986 by University of Toronto.
- + * Written by Henry Spencer. Not derived from licensed software.
- + *
- + * 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. The author is not responsible for the consequences of use of
- + * this software, no matter how awful, even if they arise
- + * from defects in it.
- + *
- + * 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.
- + *
- + * Beware that some of this code is subtly aware of the way operator
- + * precedence is structured in regular expressions. Serious changes in
- + * regular-expression syntax might require a total rethink.
- + */
- +
- + /*
- + * Altered by Jan D. (Jan.Djarv@sa.erisoft.se) for use in elm:s filter
- + */
- + #include "defs.h"
- + #include "regexp.h"
- + #include <stdio.h>
- +
- + /* #include "regmagic.h" -- Inlined here (next 5 lines) */
- + /*
- + * The first byte of the regexp internal "program" is actually this magic
- + * number; the start node begins in the second byte.
- + */
- + #define MAGIC 0234
- +
- + /*
- + * The "internal use only" fields in regexp.h are present to pass info from
- + * compile to execute that permits the execute phase to run lots faster on
- + * simple cases. They are:
- + *
- + * regstart char that must begin a match; '\0' if none obvious
- + * reganch is the match anchored (at beginning-of-line only)?
- + * regmust string (pointer into program) that match must include, or NULL
- + * regmlen length of regmust string
- + *
- + * Regstart and reganch permit very fast decisions on suitable starting points
- + * for a match, cutting down the work a lot. Regmust permits fast rejection
- + * of lines that cannot possibly match. The regmust tests are costly enough
- + * that regcomp() supplies a regmust only if the r.e. contains something
- + * potentially expensive (at present, the only such thing detected is * or +
- + * at the start of the r.e., which can involve a lot of backup). Regmlen is
- + * supplied because the test in regexec() needs it and regcomp() is computing
- + * it anyway.
- + */
- +
- + /*
- + * Structure for regexp "program". This is essentially a linear encoding
- + * of a nondeterministic finite-state machine (aka syntax charts or
- + * "railroad normal form" in parsing technology). Each node is an opcode
- + * plus a "next" pointer, possibly plus an operand. "Next" pointers of
- + * all nodes except BRANCH implement concatenation; a "next" pointer with
- + * a BRANCH on both ends of it is connecting two alternatives. (Here we
- + * have one of the subtle syntax dependencies: an individual BRANCH (as
- + * opposed to a collection of them) is never concatenated with anything
- + * because of operator precedence.) The operand of some types of node is
- + * a literal string; for others, it is a node leading into a sub-FSM. In
- + * particular, the operand of a BRANCH node is the first node of the branch.
- + * (NB this is *not* a tree structure: the tail of the branch connects
- + * to the thing following the set of BRANCHes.) The opcodes are:
- + */
- +
- + /* definition number opnd? meaning */
- + #define END 0 /* no End of program. */
- + #define BOL 1 /* no Match "" at beginning of line. */
- + #define EOL 2 /* no Match "" at end of line. */
- + #define ANY 3 /* no Match any one character. */
- + #define ANYOF 4 /* str Match any character in this string. */
- + #define ANYBUT 5 /* str Match any character not in this string. */
- + #define BRANCH 6 /* node Match this alternative, or the next... */
- + #define BACK 7 /* no Match "", "next" ptr points backward. */
- + #define EXACTLY 8 /* str Match this string. */
- + #define NOTHING 9 /* no Match empty string. */
- + #define STAR 10 /* node Match this (simple) thing 0 or more times. */
- + #define PLUS 11 /* node Match this (simple) thing 1 or more times. */
- + #define OPEN 20 /* no Mark this point in input as start of #n. */
- + /* OPEN+1 is number 1, etc. */
- + #define CLOSE 30 /* no Analogous to OPEN. */
- +
- + /*
- + * Opcode notes:
- + *
- + * BRANCH The set of branches constituting a single choice are hooked
- + * together with their "next" pointers, since precedence prevents
- + * anything being concatenated to any individual branch. The
- + * "next" pointer of the last BRANCH in a choice points to the
- + * thing following the whole choice. This is also where the
- + * final "next" pointer of each individual branch points; each
- + * branch starts with the operand node of a BRANCH node.
- + *
- + * BACK Normal "next" pointers all implicitly point forward; BACK
- + * exists to make loop structures possible.
- + *
- + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
- + * BRANCH structures using BACK. Simple cases (one character
- + * per match) are implemented with STAR and PLUS for speed
- + * and to minimize recursive plunges.
- + *
- + * OPEN,CLOSE ...are numbered at compile time.
- + */
- +
- + /*
- + * A node is one char of opcode followed by two chars of "next" pointer.
- + * "Next" pointers are stored as two 8-bit pieces, high order first. The
- + * value is a positive offset from the opcode of the node containing it.
- + * An operand, if any, simply follows the node. (Note that much of the
- + * code generation knows about this implicit relationship.)
- + *
- + * Using two bytes for the "next" pointer is vast overkill for most things,
- + * but allows patterns to get big without disasters.
- + */
- + #define OP(p) (*(p))
- + #define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
- + #define OPERAND(p) ((p) + 3)
- +
- + /*
- + * See regmagic.h for one further detail of program structure.
- + */
- +
- +
- + /*
- + * Utility definitions.
- + */
- + #ifndef CHARBITS
- + #define UCHARAT(p) ((int)*(unsigned char *)(p))
- + #else
- + #define UCHARAT(p) ((int)*(p)&CHARBITS)
- + #endif
- +
- + #define FAIL(m) { regerror(m); return(NULL); }
- + #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
- + #define META "^$.[()|?+*\\"
- +
- + /*
- + * Flags to be passed up and down.
- + */
- + #define HASWIDTH 01 /* Known never to match null string. */
- + #define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
- + #define SPSTART 04 /* Starts with * or +. */
- + #define WORST 0 /* Worst case. */
- +
- + /*
- + * Global work variables for regcomp().
- + */
- + static char *regparse; /* Input-scan pointer. */
- + static int regnpar; /* () count. */
- + static char regdummy;
- + static char *regcode; /* Code-emit pointer; ®dummy = don't. */
- + static long regsize; /* Code size. */
- +
- + /*
- + * Forward declarations for regcomp()'s friends.
- + */
- + #ifndef STATIC
- + #define STATIC static
- + #endif
- + STATIC char *reg();
- + STATIC char *regbranch();
- + STATIC char *regpiece();
- + STATIC char *regatom();
- + STATIC char *regnode();
- + STATIC char *regnext();
- + STATIC void regc();
- + STATIC void reginsert();
- + STATIC void regtail();
- + STATIC void regoptail();
- +
- + /*
- + - regcomp - compile a regular expression into internal code
- + *
- + * We can't allocate space until we know how big the compiled form will be,
- + * but we can't compile it (and thus know how big it is) until we've got a
- + * place to put the code. So we cheat: we compile it twice, once with code
- + * generation turned off and size counting turned on, and once "for real".
- + * This also means that we don't allocate space until we are sure that the
- + * thing really will compile successfully, and we never have to move the
- + * code and thus invalidate pointers into it. (Note that it has to be in
- + * one piece because free() must be able to free it all.)
- + *
- + * Beware that the optimization-preparation code in here knows about some
- + * of the structure of the compiled regexp.
- + */
- + regexp *
- + regcomp(exp)
- + char *exp;
- + {
- + register regexp *r;
- + register char *scan;
- + register char *longest;
- + register int len;
- + int flags;
- +
- + if (exp == NULL)
- + FAIL("NULL argument");
- +
- + /* First pass: determine size, legality. */
- + regparse = exp;
- + regnpar = 1;
- + regsize = 0L;
- + regcode = ®dummy;
- + regc(MAGIC);
- + if (reg(0, &flags) == NULL)
- + return(NULL);
- +
- + /* Small enough for pointer-storage convention? */
- + if (regsize >= 32767L) /* Probably could be 65535L. */
- + FAIL("regexp too big");
- +
- + /* Allocate space. */
- + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
- + if (r == NULL)
- + FAIL("out of space");
- +
- + /* Second pass: emit code. */
- + regparse = exp;
- + regnpar = 1;
- + regcode = r->program;
- + regc(MAGIC);
- + if (reg(0, &flags) == NULL)
- + return(NULL);
- +
- + /* Dig out information for optimizations. */
- + r->regstart = '\0'; /* Worst-case defaults. */
- + r->reganch = 0;
- + r->regmust = NULL;
- + r->regmlen = 0;
- + scan = r->program+1; /* First BRANCH. */
- + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
- + scan = OPERAND(scan);
- +
- + /* Starting-point info. */
- + if (OP(scan) == EXACTLY)
- + r->regstart = *OPERAND(scan);
- + else if (OP(scan) == BOL)
- + r->reganch++;
- +
- + /*
- + * If there's something expensive in the r.e., find the
- + * longest literal string that must appear and make it the
- + * regmust. Resolve ties in favor of later strings, since
- + * the regstart check works with the beginning of the r.e.
- + * and avoiding duplication strengthens checking. Not a
- + * strong reason, but sufficient in the absence of others.
- + */
- + if (flags&SPSTART) {
- + longest = NULL;
- + len = 0;
- + for (; scan != NULL; scan = regnext(scan))
- + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
- + longest = OPERAND(scan);
- + len = strlen(OPERAND(scan));
- + }
- + r->regmust = longest;
- + r->regmlen = len;
- + }
- + }
- +
- + return(r);
- + }
- +
- + /*
- + - reg - regular expression, i.e. main body or parenthesized thing
- + *
- + * Caller must absorb opening parenthesis.
- + *
- + * Combining parenthesis handling with the base level of regular expression
- + * is a trifle forced, but the need to tie the tails of the branches to what
- + * follows makes it hard to avoid.
- + */
- + static char *
- + reg(paren, flagp)
- + int paren; /* Parenthesized? */
- + int *flagp;
- + {
- + register char *ret;
- + register char *br;
- + register char *ender;
- + register int parno;
- + int flags;
- +
- + *flagp = HASWIDTH; /* Tentatively. */
- +
- + /* Make an OPEN node, if parenthesized. */
- + if (paren) {
- + if (regnpar >= NSUBEXP)
- + FAIL("too many ()");
- + parno = regnpar;
- + regnpar++;
- + ret = regnode(OPEN+parno);
- + } else
- + ret = NULL;
- +
- + /* Pick up the branches, linking them together. */
- + br = regbranch(&flags);
- + if (br == NULL)
- + return(NULL);
- + if (ret != NULL)
- + regtail(ret, br); /* OPEN -> first. */
- + else
- + ret = br;
- + if (!(flags&HASWIDTH))
- + *flagp &= ~HASWIDTH;
- + *flagp |= flags&SPSTART;
- + while (*regparse == '|') {
- + regparse++;
- + br = regbranch(&flags);
- + if (br == NULL)
- + return(NULL);
- + regtail(ret, br); /* BRANCH -> BRANCH. */
- + if (!(flags&HASWIDTH))
- + *flagp &= ~HASWIDTH;
- + *flagp |= flags&SPSTART;
- + }
- +
- + /* Make a closing node, and hook it on the end. */
- + ender = regnode((paren) ? CLOSE+parno : END);
- + regtail(ret, ender);
- +
- + /* Hook the tails of the branches to the closing node. */
- + for (br = ret; br != NULL; br = regnext(br))
- + regoptail(br, ender);
- +
- + /* Check for proper termination. */
- + if (paren && *regparse++ != ')') {
- + FAIL("unmatched ()");
- + } else if (!paren && *regparse != '\0') {
- + if (*regparse == ')') {
- + FAIL("unmatched ()");
- + } else
- + FAIL("junk on end"); /* "Can't happen". */
- + /* NOTREACHED */
- + }
- +
- + return(ret);
- + }
- +
- + /*
- + - regbranch - one alternative of an | operator
- + *
- + * Implements the concatenation operator.
- + */
- + static char *
- + regbranch(flagp)
- + int *flagp;
- + {
- + register char *ret;
- + register char *chain;
- + register char *latest;
- + int flags;
- +
- + *flagp = WORST; /* Tentatively. */
- +
- + ret = regnode(BRANCH);
- + chain = NULL;
- + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
- + latest = regpiece(&flags);
- + if (latest == NULL)
- + return(NULL);
- + *flagp |= flags&HASWIDTH;
- + if (chain == NULL) /* First piece. */
- + *flagp |= flags&SPSTART;
- + else
- + regtail(chain, latest);
- + chain = latest;
- + }
- + if (chain == NULL) /* Loop ran zero times. */
- + (void) regnode(NOTHING);
- +
- + return(ret);
- + }
- +
- + /*
- + - regpiece - something followed by possible [*+?]
- + *
- + * Note that the branching code sequences used for ? and the general cases
- + * of * and + are somewhat optimized: they use the same NOTHING node as
- + * both the endmarker for their branch list and the body of the last branch.
- + * It might seem that this node could be dispensed with entirely, but the
- + * endmarker role is not redundant.
- + */
- + static char *
- + regpiece(flagp)
- + int *flagp;
- + {
- + register char *ret;
- + register char op;
- + register char *next;
- + int flags;
- +
- + ret = regatom(&flags);
- + if (ret == NULL)
- + return(NULL);
- +
- + op = *regparse;
- + if (!ISMULT(op)) {
- + *flagp = flags;
- + return(ret);
- + }
- +
- + if (!(flags&HASWIDTH) && op != '?')
- + FAIL("*+ operand could be empty");
- + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
- +
- + if (op == '*' && (flags&SIMPLE))
- + reginsert(STAR, ret);
- + else if (op == '*') {
- + /* Emit x* as (x&|), where & means "self". */
- + reginsert(BRANCH, ret); /* Either x */
- + regoptail(ret, regnode(BACK)); /* and loop */
- + regoptail(ret, ret); /* back */
- + regtail(ret, regnode(BRANCH)); /* or */
- + regtail(ret, regnode(NOTHING)); /* null. */
- + } else if (op == '+' && (flags&SIMPLE))
- + reginsert(PLUS, ret);
- + else if (op == '+') {
- + /* Emit x+ as x(&|), where & means "self". */
- + next = regnode(BRANCH); /* Either */
- + regtail(ret, next);
- + regtail(regnode(BACK), ret); /* loop back */
- + regtail(next, regnode(BRANCH)); /* or */
- + regtail(ret, regnode(NOTHING)); /* null. */
- + } else if (op == '?') {
- + /* Emit x? as (x|) */
- + reginsert(BRANCH, ret); /* Either x */
- + regtail(ret, regnode(BRANCH)); /* or */
- + next = regnode(NOTHING); /* null. */
- + regtail(ret, next);
- + regoptail(ret, next);
- + }
- + regparse++;
- + if (ISMULT(*regparse))
- + FAIL("nested *?+");
- +
- + return(ret);
- + }
- +
- + /*
- + - regatom - the lowest level
- + *
- + * Optimization: gobbles an entire sequence of ordinary characters so that
- + * it can turn them into a single node, which is smaller to store and
- + * faster to run. Backslashed characters are exceptions, each becoming a
- + * separate node; the code is simpler that way and it's not worth fixing.
- + */
- + static char *
- + regatom(flagp)
- + int *flagp;
- + {
- + register char *ret;
- + int flags;
- +
- + *flagp = WORST; /* Tentatively. */
- +
- + switch (*regparse++) {
- + case '^':
- + ret = regnode(BOL);
- + break;
- + case '$':
- + ret = regnode(EOL);
- + break;
- + case '.':
- + ret = regnode(ANY);
- + *flagp |= HASWIDTH|SIMPLE;
- + break;
- + case '[': {
- + register int class;
- + register int classend;
- +
- + if (*regparse == '^') { /* Complement of range. */
- + ret = regnode(ANYBUT);
- + regparse++;
- + } else
- + ret = regnode(ANYOF);
- + if (*regparse == ']' || *regparse == '-')
- + regc(*regparse++);
- + while (*regparse != '\0' && *regparse != ']') {
- + if (*regparse == '-') {
- + regparse++;
- + if (*regparse == ']' || *regparse == '\0')
- + regc('-');
- + else {
- + class = UCHARAT(regparse-2)+1;
- + classend = UCHARAT(regparse);
- + if (class > classend+1)
- + FAIL("invalid [] range");
- + for (; class <= classend; class++)
- + regc(class);
- + regparse++;
- + }
- + } else
- + regc(*regparse++);
- + }
- + regc('\0');
- + if (*regparse != ']')
- + FAIL("unmatched []");
- + regparse++;
- + *flagp |= HASWIDTH|SIMPLE;
- + }
- + break;
- + case '(':
- + ret = reg(1, &flags);
- + if (ret == NULL)
- + return(NULL);
- + *flagp |= flags&(HASWIDTH|SPSTART);
- + break;
- + case '\0':
- + case '|':
- + case ')':
- + FAIL("internal urp"); /* Supposed to be caught earlier. */
- + case '?':
- + case '+':
- + case '*':
- + FAIL("?+* follows nothing");
- + case '\\':
- + if (*regparse == '\0')
- + FAIL("trailing \\");
- + ret = regnode(EXACTLY);
- + regc(*regparse++);
- + regc('\0');
- + *flagp |= HASWIDTH|SIMPLE;
- + break;
- + default: {
- + register int len;
- + register char ender;
- +
- + regparse--;
- + len = strcspn(regparse, META);
- + if (len <= 0)
- + FAIL("internal disaster");
- + ender = *(regparse+len);
- + if (len > 1 && ISMULT(ender))
- + len--; /* Back off clear of ?+* operand. */
- + *flagp |= HASWIDTH;
- + if (len == 1)
- + *flagp |= SIMPLE;
- + ret = regnode(EXACTLY);
- + while (len > 0) {
- + regc(*regparse++);
- + len--;
- + }
- + regc('\0');
- + }
- + break;
- + }
- +
- + return(ret);
- + }
- +
- + /*
- + - regnode - emit a node
- + */
- + static char * /* Location. */
- + regnode(op)
- + char op;
- + {
- + register char *ret;
- + register char *ptr;
- +
- + ret = regcode;
- + if (ret == ®dummy) {
- + regsize += 3;
- + return(ret);
- + }
- +
- + ptr = ret;
- + *ptr++ = op;
- + *ptr++ = '\0'; /* Null "next" pointer. */
- + *ptr++ = '\0';
- + regcode = ptr;
- +
- + return(ret);
- + }
- +
- + /*
- + - regc - emit (if appropriate) a byte of code
- + */
- + static void
- + regc(b)
- + char b;
- + {
- + if (regcode != ®dummy)
- + *regcode++ = b;
- + else
- + regsize++;
- + }
- +
- + /*
- + - reginsert - insert an operator in front of already-emitted operand
- + *
- + * Means relocating the operand.
- + */
- + static void
- + reginsert(op, opnd)
- + char op;
- + char *opnd;
- + {
- + register char *src;
- + register char *dst;
- + register char *place;
- +
- + if (regcode == ®dummy) {
- + regsize += 3;
- + return;
- + }
- +
- + src = regcode;
- + regcode += 3;
- + dst = regcode;
- + while (src > opnd)
- + *--dst = *--src;
- +
- + place = opnd; /* Op node, where operand used to be. */
- + *place++ = op;
- + *place++ = '\0';
- + *place++ = '\0';
- + }
- +
- + /*
- + - regtail - set the next-pointer at the end of a node chain
- + */
- + static void
- + regtail(p, val)
- + char *p;
- + char *val;
- + {
- + register char *scan;
- + register char *temp;
- + register int offset;
- +
- + if (p == ®dummy)
- + return;
- +
- + /* Find last node. */
- + scan = p;
- + for (;;) {
- + temp = regnext(scan);
- + if (temp == NULL)
- + break;
- + scan = temp;
- + }
- +
- + if (OP(scan) == BACK)
- + offset = scan - val;
- + else
- + offset = val - scan;
- + *(scan+1) = (offset>>8)&0377;
- + *(scan+2) = offset&0377;
- + }
- +
- + /*
- + - regoptail - regtail on operand of first argument; nop if operandless
- + */
- + static void
- + regoptail(p, val)
- + char *p;
- + char *val;
- + {
- + /* "Operandless" and "op != BRANCH" are synonymous in practice. */
- + if (p == NULL || p == ®dummy || OP(p) != BRANCH)
- + return;
- + regtail(OPERAND(p), val);
- + }
- +
- + /*
- + * regexec and friends
- + */
- +
- + /*
- + * Global work variables for regexec().
- + */
- + static char *reginput; /* String-input pointer. */
- + static char *regbol; /* Beginning of input, for ^ check. */
- + static char **regstartp; /* Pointer to startp array. */
- + static char **regendp; /* Ditto for endp. */
- +
- + /*
- + * Forwards.
- + */
- + STATIC int regtry();
- + STATIC int regmatch();
- + STATIC int regrepeat();
- +
- + #ifdef DEBUG
- + int regnarrate = 0;
- + void regdump();
- + STATIC char *regprop();
- + #endif
- +
- + /*
- + - regexec - match a regexp against a string
- + */
- + int
- + regexec(prog, string)
- + register regexp *prog;
- + register char *string;
- + {
- + register char *s;
- +
- + /* Be paranoid... */
- + if (prog == NULL || string == NULL) {
- + regerror("NULL parameter");
- + return(0);
- + }
- +
- + /* Check validity of program. */
- + if (UCHARAT(prog->program) != MAGIC) {
- + regerror("corrupted program");
- + return(0);
- + }
- +
- + /* If there is a "must appear" string, look for it. */
- + if (prog->regmust != NULL) {
- + s = string;
- + while ((s = index(s, prog->regmust[0])) != NULL) {
- + if (strncmp(s, prog->regmust, prog->regmlen) == 0)
- + break; /* Found it. */
- + s++;
- + }
- + if (s == NULL) /* Not present. */
- + return(0);
- + }
- +
- + /* Mark beginning of line for ^ . */
- + regbol = string;
- +
- + /* Simplest case: anchored match need be tried only once. */
- + if (prog->reganch)
- + return(regtry(prog, string));
- +
- + /* Messy cases: unanchored match. */
- + s = string;
- + if (prog->regstart != '\0')
- + /* We know what char it must start with. */
- + while ((s = index(s, prog->regstart)) != NULL) {
- + if (regtry(prog, s))
- + return(1);
- + s++;
- + }
- + else
- + /* We don't -- general case. */
- + do {
- + if (regtry(prog, s))
- + return(1);
- + } while (*s++ != '\0');
- +
- + /* Failure. */
- + return(0);
- + }
- +
- + /*
- + - regtry - try match at specific point
- + */
- + static int /* 0 failure, 1 success */
- + regtry(prog, string)
- + regexp *prog;
- + char *string;
- + {
- + register int i;
- + register char **sp;
- + register char **ep;
- +
- + reginput = string;
- + regstartp = prog->startp;
- + regendp = prog->endp;
- +
- + sp = prog->startp;
- + ep = prog->endp;
- + for (i = NSUBEXP; i > 0; i--) {
- + *sp++ = NULL;
- + *ep++ = NULL;
- + }
- + if (regmatch(prog->program + 1)) {
- + prog->startp[0] = string;
- + prog->endp[0] = reginput;
- + return(1);
- + } else
- + return(0);
- + }
- +
- + /*
- + - regmatch - main matching routine
- + *
- + * Conceptually the strategy is simple: check to see whether the current
- + * node matches, call self recursively to see whether the rest matches,
- + * and then act accordingly. In practice we make some effort to avoid
- + * recursion, in particular by going through "ordinary" nodes (that don't
- + * need to know whether the rest of the match failed) by a loop instead of
- + * by recursion.
- + */
- + static int /* 0 failure, 1 success */
- + regmatch(prog)
- + char *prog;
- + {
- + register char *scan; /* Current node. */
- + char *next; /* Next node. */
- +
- + scan = prog;
- + #ifdef DEBUG
- + if (scan != NULL && regnarrate)
- + fprintf(stderr, "%s(\n", regprop(scan));
- + #endif
- + while (scan != NULL) {
- + #ifdef DEBUG
- + if (regnarrate)
- + fprintf(stderr, "%s...\n", regprop(scan));
- + #endif
- + next = regnext(scan);
- +
- + switch (OP(scan)) {
- + case BOL:
- + if (reginput != regbol)
- + return(0);
- + break;
- + case EOL:
- + if (*reginput != '\0')
- + return(0);
- + break;
- + case ANY:
- + if (*reginput == '\0')
- + return(0);
- + reginput++;
- + break;
- + case EXACTLY: {
- + register int len;
- + register char *opnd;
- +
- + opnd = OPERAND(scan);
- + /* Inline the first character, for speed. */
- + if (*opnd != *reginput)
- + return(0);
- + len = strlen(opnd);
- + if (len > 1 && strncmp(opnd, reginput, len) != 0)
- + return(0);
- + reginput += len;
- + }
- + break;
- + case ANYOF:
- + if (*reginput == '\0' || index(OPERAND(scan), *reginput) == NULL)
- + return(0);
- + reginput++;
- + break;
- + case ANYBUT:
- + if (*reginput == '\0' || index(OPERAND(scan), *reginput) != NULL)
- + return(0);
- + reginput++;
- + break;
- + case NOTHING:
- + break;
- + case BACK:
- + break;
- + case OPEN+1:
- + case OPEN+2:
- + case OPEN+3:
- + case OPEN+4:
- + case OPEN+5:
- + case OPEN+6:
- + case OPEN+7:
- + case OPEN+8:
- + case OPEN+9: {
- + register int no;
- + register char *save;
- +
- + no = OP(scan) - OPEN;
- + save = reginput;
- +
- + if (regmatch(next)) {
- + /*
- + * Don't set startp if some later
- + * invocation of the same parentheses
- + * already has.
- + */
- + if (regstartp[no] == NULL)
- + regstartp[no] = save;
- + return(1);
- + } else
- + return(0);
- + }
- + break;
- + case CLOSE+1:
- + case CLOSE+2:
- + case CLOSE+3:
- + case CLOSE+4:
- + case CLOSE+5:
- + case CLOSE+6:
- + case CLOSE+7:
- + case CLOSE+8:
- + case CLOSE+9: {
- + register int no;
- + register char *save;
- +
- + no = OP(scan) - CLOSE;
- + save = reginput;
- +
- + if (regmatch(next)) {
- + /*
- + * Don't set endp if some later
- + * invocation of the same parentheses
- + * already has.
- + */
- + if (regendp[no] == NULL)
- + regendp[no] = save;
- + return(1);
- + } else
- + return(0);
- + }
- + break;
- + case BRANCH: {
- + register char *save;
- +
- + if (OP(next) != BRANCH) /* No choice. */
- + next = OPERAND(scan); /* Avoid recursion. */
- + else {
- + do {
- + save = reginput;
- + if (regmatch(OPERAND(scan)))
- + return(1);
- + reginput = save;
- + scan = regnext(scan);
- + } while (scan != NULL && OP(scan) == BRANCH);
- + return(0);
- + /* NOTREACHED */
- + }
- + }
- + break;
- + case STAR:
- + case PLUS: {
- + register char nextch;
- + register int no;
- + register char *save;
- + register int mmin;
- +
- + /*
- + * Lookahead to avoid useless match attempts
- + * when we know what character comes next.
- + */
- + nextch = '\0';
- + if (OP(next) == EXACTLY)
- + nextch = *OPERAND(next);
- + mmin = (OP(scan) == STAR) ? 0 : 1;
- + save = reginput;
- + no = regrepeat(OPERAND(scan));
- + while (no >= mmin) {
- + /* If it could work, try it. */
- + if (nextch == '\0' || *reginput == nextch)
- + if (regmatch(next))
- + return(1);
- + /* Couldn't or didn't -- back up. */
- + no--;
- + reginput = save + no;
- + }
- + return(0);
- + }
- + case END:
- + return(1); /* Success! */
- + default:
- + regerror("memory corruption");
- + return(0);
- + }
- +
- + scan = next;
- + }
- +
- + /*
- + * We get here only if there's trouble -- normally "case END" is
- + * the terminating point.
- + */
- + regerror("corrupted pointers");
- + return(0);
- + }
- +
- + /*
- + - regrepeat - repeatedly match something simple, report how many
- + */
- + static int
- + regrepeat(p)
- + char *p;
- + {
- + register int count = 0;
- + register char *scan;
- + register char *opnd;
- +
- + scan = reginput;
- + opnd = OPERAND(p);
- + switch (OP(p)) {
- + case ANY:
- + count = strlen(scan);
- + scan += count;
- + break;
- + case EXACTLY:
- + while (*opnd == *scan) {
- + count++;
- + scan++;
- + }
- + break;
- + case ANYOF:
- + while (*scan != '\0' && index(opnd, *scan) != NULL) {
- + count++;
- + scan++;
- + }
- + break;
- + case ANYBUT:
- + while (*scan != '\0' && index(opnd, *scan) == NULL) {
- + count++;
- + scan++;
- + }
- + break;
- + default: /* Oh dear. Called inappropriately. */
- + regerror("internal foulup");
- + count = 0; /* Best compromise. */
- + break;
- + }
- + reginput = scan;
- +
- + return(count);
- + }
- +
- + /*
- + - regnext - dig the "next" pointer out of a node
- + */
- + static char *
- + regnext(p)
- + register char *p;
- + {
- + register int offset;
- +
- + if (p == ®dummy)
- + return(NULL);
- +
- + offset = NEXT(p);
- + if (offset == 0)
- + return(NULL);
- +
- + if (OP(p) == BACK)
- + return(p-offset);
- + else
- + return(p+offset);
- + }
- +
- + #ifdef DEBUG
- +
- + STATIC char *regprop();
- +
- + /*
- + - regdump - dump a regexp onto stdout in vaguely comprehensible form
- + */
- + void
- + regdump(r)
- + regexp *r;
- + {
- + register char *s;
- + register char op = EXACTLY; /* Arbitrary non-END op. */
- + register char *next;
- +
- +
- + s = r->program + 1;
- + while (op != END) { /* While that wasn't END last time... */
- + op = OP(s);
- + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
- + next = regnext(s);
- + if (next == NULL) /* Next ptr. */
- + printf("(0)");
- + else
- + printf("(%d)", (s-r->program)+(next-s));
- + s += 3;
- + if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
- + /* Literal string, where present. */
- + while (*s != '\0') {
- + putchar(*s);
- + s++;
- + }
- + s++;
- + }
- + putchar('\n');
- + }
- +
- + /* Header fields of interest. */
- + if (r->regstart != '\0')
- + printf("start `%c' ", r->regstart);
- + if (r->reganch)
- + printf("anchored ");
- + if (r->regmust != NULL)
- + printf("must have \"%s\"", r->regmust);
- + printf("\n");
- + }
- +
- + /*
- + - regprop - printable representation of opcode
- + */
- + static char *
- + regprop(op)
- + char *op;
- + {
- + register char *p;
- + static char buf[50];
- +
- + (void) strcpy(buf, ":");
- +
- + switch (OP(op)) {
- + case BOL:
- + p = "BOL";
- + break;
- + case EOL:
- + p = "EOL";
- + break;
- + case ANY:
- + p = "ANY";
- + break;
- + case ANYOF:
- + p = "ANYOF";
- + break;
- + case ANYBUT:
- + p = "ANYBUT";
- + break;
- + case BRANCH:
- + p = "BRANCH";
- + break;
- + case EXACTLY:
- + p = "EXACTLY";
- + break;
- + case NOTHING:
- + p = "NOTHING";
- + break;
- + case BACK:
- + p = "BACK";
- + break;
- + case END:
- + p = "END";
- + break;
- + case OPEN+1:
- + case OPEN+2:
- + case OPEN+3:
- + case OPEN+4:
- + case OPEN+5:
- + case OPEN+6:
- + case OPEN+7:
- + case OPEN+8:
- + case OPEN+9:
- + sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
- + p = NULL;
- + break;
- + case CLOSE+1:
- + case CLOSE+2:
- + case CLOSE+3:
- + case CLOSE+4:
- + case CLOSE+5:
- + case CLOSE+6:
- + case CLOSE+7:
- + case CLOSE+8:
- + case CLOSE+9:
- + sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- + p = NULL;
- + break;
- + case STAR:
- + p = "STAR";
- + break;
- + case PLUS:
- + p = "PLUS";
- + break;
- + default:
- + regerror("corrupted opcode");
- + break;
- + }
- + if (p != NULL)
- + (void) strcat(buf, p);
- + return(buf);
- + }
- + #endif
-
- Index: src/date.c
- Prereq: 5.1
- *** ../elm2.4/src/date.c Sat Oct 3 18:58:48 1992
- --- src/date.c Sat Nov 14 21:10:21 1992
- ***************
- *** 1,8 ****
-
- ! static char rcsid[] = "@(#)$Id: date.c,v 5.1 1992/10/03 22:58:40 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.1 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- --- 1,8 ----
-
- ! static char rcsid[] = "@(#)$Id: date.c,v 5.2 1992/11/15 02:10:11 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.2 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- ***************
- *** 14,19 ****
- --- 14,23 ----
- *
- *******************************************************************************
- * $Log: date.c,v $
- + * Revision 5.2 1992/11/15 02:10:11 syd
- + * remove no longer used tzname
- + * From: Syd
- + *
- * Revision 5.1 1992/10/03 22:58:40 syd
- * Initial checkin as of 2.4 Release at PL0
- *
- ***************
- *** 65,76 ****
-
- int days_in_month[] = { 31, 28, 31, 30, 31, 30,
- 31, 31, 30, 31, 30, 31, -1};
- -
- - #ifdef BSD
- - char *timezone();
- - #else
- - extern char *tzname[];
- - #endif
-
- days_ahead(days, buffer)
- int days;
- --- 69,74 ----
-
- Index: lib/getarpdate.c
- Prereq: 5.2
- *** ../elm2.4/lib/getarpdate.c Tue Nov 10 15:20:24 1992
- --- lib/getarpdate.c Sat Nov 14 21:18:27 1992
- ***************
- *** 1,7 ****
- ! static char rcsid[] = "@(#)$Id: getarpdate.c,v 5.2 1992/11/07 19:27:30 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.2 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- --- 1,7 ----
- ! static char rcsid[] = "@(#)$Id: getarpdate.c,v 5.4 1992/11/15 02:18:15 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.4 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- ***************
- *** 13,18 ****
- --- 13,27 ----
- *
- *******************************************************************************
- * $Log: getarpdate.c,v $
- + * Revision 5.4 1992/11/15 02:18:15 syd
- + * Change most of the rest of the BSDs to TZNAME
- + * From: Syd
- + *
- + * Revision 5.3 1992/11/15 02:10:58 syd
- + * change tzname ifdef from ndefBSD to ifdef TZNAME on its own
- + * configure variable
- + * From: Syd
- + *
- * Revision 5.2 1992/11/07 19:27:30 syd
- * Symbol change for AIX370
- * From: uri@watson.ibm.com
- ***************
- *** 54,63 ****
- static char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
-
- ! #if defined(BSD) && !defined(_POSIX_SOURCE)
- ! char *timezone();
- ! #else
- extern char *tzname[];
- #endif
-
- #ifdef _AIX370
- --- 63,72 ----
- static char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
-
- ! #ifdef TZNAME
- extern char *tzname[];
- + #else
- + char *timezone();
- #endif
-
- #ifdef _AIX370
- ***************
- *** 80,86 ****
- long tzmin; /* number of minutes off gmt */
- char *tzsign; /* + or - gmt */
-
- ! #ifdef BSD
- # ifndef TZ_MINUTESWEST
- struct timeb loc_time;
-
- --- 89,95 ----
- long tzmin; /* number of minutes off gmt */
- char *tzsign; /* + or - gmt */
-
- ! #ifndef TZNAME
- # ifndef TZ_MINUTESWEST
- struct timeb loc_time;
-
- ***************
- *** 94,100 ****
- junk = time_val.tv_sec;
- # endif /* TZ_MINUTESWEST */
-
- ! #else /* BSD */
- extern time_t timezone;
- # ifdef ALTCHECK
- extern time_t altzone;
- --- 103,109 ----
- junk = time_val.tv_sec;
- # endif /* TZ_MINUTESWEST */
-
- ! #else /* TZNAME */
- extern time_t timezone;
- # ifdef ALTCHECK
- extern time_t altzone;
- ***************
- *** 101,112 ****
- # endif
-
- junk = time((time_t *) 0); /* this must be here for it to work! */
- ! #endif /* BSD */
-
- the_time = localtime(&junk);
- if (the_time->tm_year < 100)
- the_time->tm_year += 1900;
- ! #ifdef BSD
- # ifdef TZ_MINUTESWEST
- if (the_time->tm_isdst && time_zone.tz_dsttime != DST_NONE)
- tzmin = - (time_zone.tz_minuteswest - 60);
- --- 110,121 ----
- # endif
-
- junk = time((time_t *) 0); /* this must be here for it to work! */
- ! #endif /* TZNAME */
-
- the_time = localtime(&junk);
- if (the_time->tm_year < 100)
- the_time->tm_year += 1900;
- ! #ifndef TZNAME
- # ifdef TZ_MINUTESWEST
- if (the_time->tm_isdst && time_zone.tz_dsttime != DST_NONE)
- tzmin = - (time_zone.tz_minuteswest - 60);
- ***************
- *** 115,121 ****
- # else /* TZ_MINUTESWEST */
- tzmin = the_time->tm_gmtoff / 60;
- # endif /* TZ_MINUTESWEST */
- ! #else /* BSD */
- # ifdef ALTCHECK
- if (the_time->tm_isdst)
- tzmin = - (altzone / 60);
- --- 124,130 ----
- # else /* TZ_MINUTESWEST */
- tzmin = the_time->tm_gmtoff / 60;
- # endif /* TZ_MINUTESWEST */
- ! #else /* TZNAME */
- # ifdef ALTCHECK
- if (the_time->tm_isdst)
- tzmin = - (altzone / 60);
- ***************
- *** 124,130 ****
- # else /* ALTCHECK */
- tzmin = - (timezone / 60);
- # endif /* ALTCHECK */
- ! #endif /* BSD */
-
- if (tzmin >= 0)
- tzsign = "+";
- --- 133,139 ----
- # else /* ALTCHECK */
- tzmin = - (timezone / 60);
- # endif /* ALTCHECK */
- ! #endif /* TZNAME */
-
- if (tzmin >= 0)
- tzsign = "+";
- ***************
- *** 139,145 ****
- arpa_monname[the_time->tm_mon], the_time->tm_year,
- the_time->tm_hour, the_time->tm_min, the_time->tm_sec,
- tzsign, tzmin / 60, tzmin % 60,
- ! #ifdef BSD
- #ifdef TZ_MINUTESWEST
- # ifdef GOULD_NP1
- the_time->tm_zone);
- --- 148,154 ----
- arpa_monname[the_time->tm_mon], the_time->tm_year,
- the_time->tm_hour, the_time->tm_min, the_time->tm_sec,
- tzsign, tzmin / 60, tzmin % 60,
- ! #ifndef TZNAME
- #ifdef TZ_MINUTESWEST
- # ifdef GOULD_NP1
- the_time->tm_zone);
-
- Index: src/editmsg.c
- Prereq: 5.2
- *** ../elm2.4/src/editmsg.c Mon Oct 19 13:04:08 1992
- --- src/editmsg.c Mon Nov 16 23:05:25 1992
- ***************
- *** 1,8 ****
-
- ! static char rcsid[] = "@(#)$Id: editmsg.c,v 5.2 1992/10/17 22:22:33 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.2 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- --- 1,8 ----
-
- ! static char rcsid[] = "@(#)$Id: editmsg.c,v 5.3 1992/11/17 04:05:24 syd Exp $";
-
- /*******************************************************************************
- ! * The Elm Mail System - $Revision: 5.3 $ $State: Exp $
- *
- * Copyright (c) 1988-1992 USENET Community Trust
- * Copyright (c) 1986,1987 Dave Taylor
- ***************
- *** 14,19 ****
- --- 14,23 ----
- *
- *******************************************************************************
- * $Log: editmsg.c,v $
- + * Revision 5.3 1992/11/17 04:05:24 syd
- + * Fix for editing interrupt broken by posix_signal().
- + * From cs.utexas.edu!chinacat!chip Mon Nov 16 09:03:04 1992
- + *
- * Revision 5.2 1992/10/17 22:22:33 syd
- * Fix warnings from my ANSI C compiler because the declaration of
- * edit_interrupt did not match the prototype for the second argument of
- ***************
- *** 38,43 ****
- --- 42,53 ----
- #include <setjmp.h>
- #endif /* BSD */
- #include <ctype.h>
- +
- + #ifdef POSIX_SIGNALS
- + #define jmp_buf sigjmp_buf
- + #define setjmp(env) sigsetjmp((env), 1)
- + #define longjmp(env,val) siglongjmp((env), (val))
- + #endif
-
- #ifdef BSD
- #undef tolower
-
- --
- ========================================================================
- Sydney S. Weinstein, CDP, CCP Elm Coordinator - Current 2.4PL08
- Datacomp Systems, Inc. Projected 3.0 Release: ??? ?,1994
- syd@DSI.COM or dsinc!syd Voice: (215) 947-9900, FAX: (215) 938-0235
-