home *** CD-ROM | disk | FTP | other *** search
- From: guido@cwi.nl (Guido van Rossum)
- Newsgroups: alt.sources
- Subject: STDWIN 0.9.5, Part 01/19
- Message-ID: <3065@charon.cwi.nl>
- Date: 4 Mar 91 11:51:19 GMT
-
- Archive-name: stdwin/part01
-
- This is STDWIN version 0.9.5. (The last digit of the version number is
- also the patchlevel, in case you're collecting patches.)
-
- I am posting this mainly because it is needed to support the Python
- distribution that I recently put on alt.sources, not because it is a
- new product. After being flamed for posting 21 parts of Python I
- hesitated to post STDWIN, but fan mail has convinced me to go ahead
- (it's still peanuts compared to alt.sex.pictures :-) ).
-
- STDWIN is a simple windowing interface which makes (the windowing part
- of) your program portable between multiple platforms without requiring
- changes to your code -- just link with a different library and you are
- done. Major platforms supported are the Mac and X11. STDWIN programs
- can also run on alphanumeric terminals, under UNIX using termcap, and
- on MS-DOS using the alphanumeric screen. It used to work on the Atari
- ST but I can't do any maintenance on that version.
-
- STDWIN applications are event-based. STDWIN supports multiple
- windows, dynamic menus with shortcuts, mouse and keyboard input,
- time-outs, automatic scroll bars, and a number of drawing primitives
- such as text (multiple fonts, variable-width), lines, circles and
- ellipses, arcs, shading and boxes. A number of standard dialogs are
- also available: message, yes/no question, ask for string, ask for file
- name.
-
- STDWIN is copyrighted, but can be freely copied and used as long as
- the copyright notice remains in place.
-
- STDWIN is not supported, I can only do my best. Most of it was
- created over three years ago, although support for X11 R4 is more
- recent, and I have polished it a little bit recently (added clipping
- and X11 selection support for instance).
-
- If you want to port STDWIN to a new platform (Suntools, MS Windows and
- Motif are most wanted), contact me, I can give you some hints on how
- to start. Beware: although porting a STDWIN-based application to
- another platform supported by STDWIN is a piece of cake, porting
- STDWIN itself to a new window system is a major undertaking. You need
- a thorough understanding both of the underlying window system and of
- the STDWIN model.
-
- Documentation (in troff -ms format) is provided -- some of the new
- features are undocumented except through the source and example
- applications though.
-
- To get to know more, extract the files and read the README file.
-
- I regularly put the latest STDWIN distribution on two anonymous ftp
- sites. As the filename shows, to unpack this you need the programs
- uncompress and tar.
-
- site hp4nl.nluug.nl (IP address 192.16.202.2)
- directory pub/windows
- file stdwin*.tar.Z (the * is the version, e.g. 0.9.5)
-
- site wuarchive.wustl.edu (IP address 128.252.135.4)
- directory pub
- file stdwin*.tar.Z (the * is the version, e.g. 0.9.5)
-
- Don't forget to specify binary file transfer mode! ("type binary")
-
- --Guido van Rossum <guido@cwi.nl>
-
- CWI, dept. CST
- Kruislaan 413
- 1098 SJ Amsterdam
- The Netherlands
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 19)."
- # Contents: README MANIFEST Appls Appls/bed Appls/dpv Appls/klok
- # Appls/miniedit Appls/miniedit/regexp.c Appls/repeat Appls/test
- # Appls/test/test3.c Appls/tetris Conf Doc Doc/man Gen H Packs
- # Packs/textedit Packs/vt Ports Ports/alfa Ports/mac Ports/mac_mpw
- # Ports/msdos Ports/vtrm Ports/vtrm/DIST Ports/x11 Tools
- # Wrapped by guido@voorn.cwi.nl on Mon Mar 4 12:37:22 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(5626 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XSTDWIN INSTALLATION GUIDE
- X-------------------------
- X
- X[last edit: 4 March 1991]
- X
- X
- XWhat Is STDWIN
- X==============
- X
- XSTDWIN (STanDard Window INterface) is a simple windowing interface for
- Xwhich multiple implementations exist; currently, programs using STDWIN
- Xcan be made to run on Unix (using either alphanumeric terminals or the
- XX11 Window System), on the Apple Macintosh (using THINK C or MPW), or
- Xon MS-DOS with a dumb display (using Microsoft C). If you insist, I
- Xalso have two versions for the Atari ST that need some dusting off.
- X
- XFor a longer introduction, read the (slightly outdated) file Doc/ABOUT.
- XFor more information on the Macintosh version, read Ports/mac/README,
- Xfor MS-DOS, read Ports/msdos/README.
- X
- XThis is version 0.9.5. It is still a beta test version.
- X
- X
- XWhere To Get STDWIN
- X===================
- X
- XI regularly put the latest STDWIN distribution on two anonymous ftp
- Xsites. As the filename shows, to unpack this you need the programs
- Xuncompress and tar.
- X
- X site hp4nl.nluug.nl (IP address 192.16.202.2)
- X directory pub/windows
- X file stdwin*.tar.Z (the * is the version, e.g. 0.9.5)
- X
- X site wuarchive.wustl.edu (IP address 128.252.135.4)
- X directory pub
- X file stdwin*.tar.Z (the * is the version, e.g. 0.9.5)
- X
- XDon't forget to specify binary file transfer mode! ("type binary")
- X
- XI can also e-mail you a voluminous bunch of shar files but please try
- Xfinding a friend with ftp access first -- it's much more convenient
- Xfor all concerned.
- X
- X
- XGetting Started Right Now
- X=========================
- X
- XFor some common systems, the system knows how to configure itself
- Xautomatically. This works for:
- X
- X Hardware Operating System
- X
- X DEC VAX, DECstation Ultrix 2.2 or 3.0
- X Sun3, Sun4 SunOS 4.0 or 4.1
- X Silicon Graphics Personal IRIS IRIX 3.2 or 3.3
- X Harris HCX-7 (tahoe) BSD 4.3
- X
- X(For other OS versions on these or similar machines, give it a try
- Xanyway, it may work as well, especially if there is a program called
- X"arch" or "machine" that prints the machine type.) To build STDWIN
- Xfor X11 on such systems:
- X
- X cd Conf
- X ./mkmf # answer all questions with yes
- X cd ..
- X cd Build/<arch>/x11/lib # <arch> is `machine` or `arch`
- X make
- X
- XThis creates the STDWIN library for X11 on a file named "lib.a".
- XTo build the standard test/demo application, "miniedit" (first chdir
- Xback to the top of the STDWIN source tree):
- X
- X cd Conf
- X ./mkmf miniedit
- X cd ..
- X cd Build/<arch>/x11/miniedit
- X make
- X
- XTo try it out, use it to have a look at the Makefile:
- X
- X miniedit Makefile
- X
- X
- XIf It Doesn't Work Right Away
- X=============================
- X
- XYou may have to create new Makefile prototypes in subdirectory Conf, or
- Xfix the mkmf script there.
- X
- XThe configuration system works as follows. Sources and objects live in
- Xseparate directories. There are no tools like "imake" nor nonstandard
- Xmake features like "VPATH" used. Instead, all Makefiles are generated
- Xby simple, easy-to-understand shell scripts living in Conf. It is
- Xpossible to say "make" in any leaf subdirectory of Build.
- X
- XRead Conf/README for more information.
- X
- X
- XThe STDWIN source tree
- X======================
- X
- XThe STDWIN tree is organized as follows. Starting from the top of the
- Xtree (where this README file lives), we have:
- X
- X . Top-level directory.
- X
- X README The file you are now reading.
- X
- X H/ Public header files of STDWIN ports and
- X packages. Stdwin applications should pass this
- X directory to the compiler in a "-I" option.
- X
- X Tools/ Subroutines used by various ports and
- X applications; not STDWIN-specific.
- X (This has now been truncated to the bare
- X minimum.)
- X
- X Gen/ (Almost) generic versions of some STDWIN
- X functions, used by more than one port. (Some
- X are dummies that ignore the request or always
- X fail.)
- X
- X Ports/ Source for various ports.
- X Note: not all subdirectories are distributed!
- X
- X Ports/x11/ Port to X11 R4; uses Xlib only.
- X Ports/alfa/ Port for alphanumeric displays using termcap/terminfo.
- X Ports/vtrm/ VTRM (virtual terminal) package used by Ports/alfa.
- X Ports/atrm/ Amoeba support or verion for VTRM (old).
- X Ports/proto/ Dummy routines to start a new port (ancient).
- X Ports/stubs/ RPC-style stubs (ancient).
- X Ports/mg1/ Obsolete Whitechapel MG-1 port.
- X Ports/atari/ Atari ST port, for Mark Williams C compiler.
- X Ports/atari_turbo/ (Newer) Atari ST port, for TurboC.
- X Ports/mac/ Apple Macintosh port (both MPW and THINK C).
- X Ports/msdos/ MS-DOS port (uses the alfa port mostly).
- X (etc)
- X
- X Packs/ Source for packages (libraries) on top of STDWIN.
- X
- X Packs/textedit/ Standard text-editing package.
- X Packs/vt/ Virtual terminal package (needs some work).
- X packs/buttons/ Probably not useful, and broken.
- X
- X Appls/ Source for test programs and real applications.
- X
- X Appls/README Read this for more information.
- X
- X Doc/ Documentation for STDWIN and packages.
- X Unfortunately this is terribly out of date.
- X
- X Doc/ABOUT Blurb to be sent to prospective users.
- X Doc/paper.ms The original paper (CWI report CS-R8817) (*troff -ms).
- X (etc)
- X
- X Conf/ Configuration scripts and prototype Makefiles.
- X
- X Conf/README Read this before twiddling the configuration.
- X Conf/mkmf Script to build Makefiles.
- X Conf/mkall Script to build Makefiles for allo applications.
- X Conf/proto.* Makefile fragments used by mkmf.
- X Conf/* Scripts used by mkmf.
- X
- X Build/ Contains subdirectories where the various
- X ports are built for various architectures.
- X
- X Build/sun3/ Sun3 (680x0) under SunOS 4.1
- X Build/sun4/ Sun4 (SPARC) under SunOS 4.1
- X Build/sgi/ Silicon Graphics under IRIX 3.2
- X Build/mips/ DEC RISC architecture under Ultrix 3.0
- X Build/vax/ DEC VAX under Ultrix 2.2
- X (etc)
- X
- X
- X--
- XGuido van Rossum, CWI, Amsterdam <guido@cwi.nl>
- X"The life of a Repo Man is always intense"
- END_OF_FILE
- if test 5626 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(7822 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X README 1
- X MANIFEST 1
- X Appls 1
- X Appls/bed 1
- X Appls/bed/2x2 3
- X Appls/bed/Dada 14
- X Appls/bed/Make.proto 19
- X Appls/bed/Woman 14
- X Appls/bed/bed.c 13
- X Appls/bed/bed.h 19
- X Appls/bed/file.c 16
- X Appls/bed/fmenu.c 16
- X Appls/bed/menu.h 19
- X Appls/bed/mmenu.c 17
- X Appls/bed/mouse.c 11
- X Appls/bed/opmenu.c 12
- X Appls/dpv 1
- X Appls/dpv/Make.proto 19
- X Appls/dpv/README 17
- X Appls/dpv/To.do 19
- X Appls/dpv/choose.c 10
- X Appls/dpv/dpv.c 17
- X Appls/dpv/dpv.h 19
- X Appls/dpv/dpvcontrol.c 13
- X Appls/dpv/dpvdoc.h 16
- X Appls/dpv/dpvfonts.c 8
- X Appls/dpv/dpvfunny.c 14
- X Appls/dpv/dpvmachine.c 16
- X Appls/dpv/dpvmachine.h 16
- X Appls/dpv/dpvoutput.c 6
- X Appls/dpv/dpvoutput.h 18
- X Appls/dpv/dpvparse.c 14
- X Appls/dpv/dpvrestart.c 14
- X Appls/dpv/figtest 15
- X Appls/dpv/funnyproto 19
- X Appls/dpv/funnytab 17
- X Appls/dpv/makefunny 19
- X Appls/dpv/r3symbol 18
- X Appls/dpv/symbol 19
- X Appls/dpv/symbola 19
- X Appls/dpv/trans 17
- X Appls/klok 1
- X Appls/klok/Make.proto 19
- X Appls/klok/amsetdate.c 19
- X Appls/klok/bsdsetdate.c 17
- X Appls/klok/klok.c 5
- X Appls/miniedit 1
- X Appls/miniedit/Make.proto 19
- X Appls/miniedit/miniedit.c 12
- X Appls/miniedit/regexp.c 1
- X Appls/miniedit/regexp.h 19
- X Appls/miniedit/regmagic.h 19
- X Appls/miniedit/regsub.c 17
- X Appls/repeat 1
- X Appls/repeat/Make.proto 19
- X Appls/repeat/repeat.c 12
- X Appls/test 1
- X Appls/test/README 19
- X Appls/test/bike.c 16
- X Appls/test/bits.c 16
- X Appls/test/charset.c 16
- X Appls/test/dklok.c 16
- X Appls/test/faced.c 12
- X Appls/test/hello.c 18
- X Appls/test/kuifje 18
- X Appls/test/magic.c 14
- X Appls/test/multiwin.c 17
- X Appls/test/sevenseg.h 14
- X Appls/test/test0.c 19
- X Appls/test/test1.c 4
- X Appls/test/test2.c 19
- X Appls/test/test3.c 1
- X Appls/test/test4.c 18
- X Appls/test/test5.c 18
- X Appls/test/testlocalmenus.c 18
- X Appls/test/testpollevent.c 18
- X Appls/test/thand.c 18
- X Appls/test/vtdemo.c 18
- X Appls/tetris 1
- X Appls/tetris/Make.proto 19
- X Appls/tetris/tetris.c 3
- X Conf 1
- X Conf/README 10
- X Conf/fastmkdep 19
- X Conf/makemakefile 17
- X Conf/mkall 19
- X Conf/mkmf 17
- X Conf/proto.arch.68000 18
- X Conf/proto.arch.mips 19
- X Conf/proto.arch.sgi 19
- X Conf/proto.arch.sun3 19
- X Conf/proto.arch.sun4 19
- X Conf/proto.arch.tahoe 19
- X Conf/proto.arch.vax 19
- X Conf/proto.arch.xxx 18
- X Conf/proto.conf 17
- X Conf/proto.os.amoeba 13
- X Conf/proto.os.bsd 5
- X Conf/proto.os.sony 18
- X Conf/proto.os.sunos 19
- X Conf/proto.os.sysv 18
- X Conf/proto.os.ultrix 19
- X Conf/proto.os.xxx 18
- X Conf/proto.port.alfa 19
- X Conf/proto.port.x11 19
- X Conf/proto.port.xxx 18
- X Conf/putlibmf 19
- X Conf/putobjs 19
- X Conf/putprogmf 19
- X Conf/puttargets 19
- X Conf/slowmkdep 19
- X Doc 1
- X Doc/ABOUT 6
- X Doc/README 19
- X Doc/macros.ms 18
- X Doc/man 1
- X Doc/man/dpv.man 15
- X Doc/man/editwin.man 10
- X Doc/man/textedit.man 12
- X Doc/man/vt.man 12
- X Doc/man/x11stdwin.man 11
- X Doc/paper.ms 2
- X Doc/seldoc.ms 8
- X Doc/vtrmdoc.ms 7
- X Gen 1
- X Gen/waskfile.c 18
- X Gen/waskync.c 19
- X Gen/wdrawpar.c 17
- X Gen/wperror.c 19
- X Gen/wsetclip.c 19
- X Gen/wsetcutbuffer.c 19
- X Gen/wsetselection.c 19
- X Gen/wstyle.c 19
- X Gen/wtextbreak.c 17
- X H 1
- X H/_ARGS.h 18
- X H/editwin.h 18
- X H/endian.h 19
- X H/filedefs.h 19
- X H/lists.h 16
- X H/patchlevel.h 16
- X H/sigtype.h 19
- X H/stdwconf.h 19
- X H/stdwin.h 11
- X H/stdwtext.h 17
- X H/style.h 19
- X H/tilist.h 19
- X H/tools.h 15
- X H/vt.h 14
- X H/vtrm.h 18
- X H/vtserial.h 19
- X H/winreq.h 16
- X Packs 1
- X Packs/textedit 1
- X Packs/textedit/editwin.c 11
- X Packs/textedit/text.h 15
- X Packs/textedit/textdbg.c 17
- X Packs/textedit/textedit.c 6
- X Packs/textedit/textlow.c 8
- X Packs/textedit/wprintf.c 18
- X Packs/vt 1
- X Packs/vt/To.do 19
- X Packs/vt/vt.c 4
- X Packs/vt/vtansi.c 9
- X Packs/vt/vtfunc.c 14
- X Packs/vt/vtimpl.h 18
- X Packs/vt/vtpanic.c 19
- X Packs/vt/vtputs.c 18
- X Packs/vt/vtresize.c 16
- X Packs/vt/vtselect.c 10
- X Packs/vt/vtsend.c 19
- X Packs/vt/vtusesend.c 19
- X Packs/vt/vtvtrm.c 16
- X Ports 1
- X Ports/alfa 1
- X Ports/alfa/BUGS 19
- X Ports/alfa/Make.proto 19
- X Ports/alfa/To.do 17
- X Ports/alfa/alfa.h 15
- X Ports/alfa/bind.c 12
- X Ports/alfa/draw.c 10
- X Ports/alfa/event.c 13
- X Ports/alfa/keymap.c 15
- X Ports/alfa/measure.c 18
- X Ports/alfa/menu.c 5
- X Ports/alfa/menu.h 19
- X Ports/alfa/scroll.c 18
- X Ports/alfa/stdwin.c 9
- X Ports/alfa/syswin.c 13
- X Ports/alfa/timer.c 14
- X Ports/mac 1
- X Ports/mac/about.c 11
- X Ports/mac/argcargv.c 18
- X Ports/mac/caret.c 16
- X Ports/mac/cursor.c 15
- X Ports/mac/dialog.c 11
- X Ports/mac/dprintf.c 17
- X Ports/mac/draw.c 9
- X Ports/mac/event.c 8
- X Ports/mac/fullpath.c 18
- X Ports/mac/macwin.h 13
- X Ports/mac/menu.c 15
- X Ports/mac/menu.h 8
- X Ports/mac/pstring.c 2
- X Ports/mac/scrap.c 17
- X Ports/mac/scroll.c 7
- X Ports/mac/stdwin.c 13
- X Ports/mac/timer.c 17
- X Ports/mac_mpw 1
- X Ports/mac_mpw/Makefile 18
- X Ports/mac_mpw/README 19
- X Ports/mac_mpw/intercept.h 18
- X Ports/mac_mpw/set_open_hook.c 15
- X Ports/msdos 1
- X Ports/msdos/README 19
- X Ports/msdos/dir.c 15
- X Ports/msdos/dir.h 19
- X Ports/msdos/lib. 19
- X Ports/msdos/ptrm.c 5
- X Ports/vtrm 1
- X Ports/vtrm/DIST 1
- X Ports/vtrm/DIST/README 17
- X Ports/vtrm/DIST/pag.c 16
- X Ports/vtrm/uxtty.c 14
- X Ports/vtrm/vtrm.c 3
- X Ports/vtrm/vtrm.h 18
- X Ports/x11 1
- X Ports/x11/Make.proto 19
- X Ports/x11/amtimer.c 15
- X Ports/x11/caret.c 18
- X Ports/x11/cursor.c 13
- X Ports/x11/cutbuffer.c 18
- X Ports/x11/dialog.c 6
- X Ports/x11/draw.c 11
- X Ports/x11/error.c 17
- X Ports/x11/event.c 13
- X Ports/x11/font.c 15
- X Ports/x11/general.c 7
- X Ports/x11/llevent.c 7
- X Ports/x11/llevent.h 18
- X Ports/x11/menu.c 9
- X Ports/x11/scroll.c 16
- X Ports/x11/selection.c 10
- X Ports/x11/timer.c 9
- X Ports/x11/window.c 4
- X Ports/x11/x11.h 15
- X Tools 1
- X Tools/getopt.c 17
- X Tools/strdup.c 18
- END_OF_FILE
- if test 7822 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test ! -d 'Appls' ; then
- echo shar: Creating directory \"'Appls'\"
- mkdir 'Appls'
- fi
- if test ! -d 'Appls/bed' ; then
- echo shar: Creating directory \"'Appls/bed'\"
- mkdir 'Appls/bed'
- fi
- if test ! -d 'Appls/dpv' ; then
- echo shar: Creating directory \"'Appls/dpv'\"
- mkdir 'Appls/dpv'
- fi
- if test ! -d 'Appls/klok' ; then
- echo shar: Creating directory \"'Appls/klok'\"
- mkdir 'Appls/klok'
- fi
- if test ! -d 'Appls/miniedit' ; then
- echo shar: Creating directory \"'Appls/miniedit'\"
- mkdir 'Appls/miniedit'
- fi
- if test -f 'Appls/miniedit/regexp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Appls/miniedit/regexp.c'\"
- else
- echo shar: Extracting \"'Appls/miniedit/regexp.c'\" \(31000 characters\)
- sed "s/^X//" >'Appls/miniedit/regexp.c' <<'END_OF_FILE'
- X/*
- X * regcomp and regexec -- regsub and regerror are elsewhere
- X *
- X * Copyright (c) 1986 by University of Toronto.
- X * Written by Henry Spencer. Not derived from licensed software.
- X#ifdef MULTILINE
- X * Changed by Guido van Rossum, CWI, Amsterdam
- X * for multi-line support.
- X#endif
- X *
- X * Permission is granted to anyone to use this software for any
- X * purpose on any computer system, and to redistribute it freely,
- X * subject to the following restrictions:
- X *
- X * 1. The author is not responsible for the consequences of use of
- X * this software, no matter how awful, even if they arise
- X * from defects in it.
- X *
- X * 2. The origin of this software must not be misrepresented, either
- X * by explicit claim or by omission.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not
- X * be misrepresented as being the original software.
- X *
- X * Beware that some of this code is subtly aware of the way operator
- X * precedence is structured in regular expressions. Serious changes in
- X * regular-expression syntax might require a total rethink.
- X */
- X#include <stdio.h>
- X#include "regexp.h"
- X#include "regmagic.h"
- X
- X#ifdef MULTILINE
- X/*
- X * Defining MULTILINE turns on the following changes in the semantics:
- X * 1. The '.' operator matches all characters except a newline.
- X * 2. The '^' operator matches at the beginning of the string or after
- X * a newline. (Anchored matches are retried after each newline.)
- X * 3. The '$' operator matches at the end of the string or before
- X * a newline.
- X * 4. A '\' followed by an 'n' matches a newline. (This is an
- X * unfortunate exception to the rule that '\' followed by a
- X * character matches that character...)
- X *
- X * Also, there is a new function reglexec(prog, string, offset)
- X * which searches for a match starting at 'string+offset';
- X * it differs from regexec(prog, string+offset) in assuming
- X * that the line begins at 'string'.
- X */
- X#endif
- X
- X/*
- X * The "internal use only" fields in regexp.h are present to pass info from
- X * compile to execute that permits the execute phase to run lots faster on
- X * simple cases. They are:
- X *
- X * regstart char that must begin a match; '\0' if none obvious
- X * reganch is the match anchored (at beginning-of-line only)?
- X * regmust string (pointer into program) that match must include, or NULL
- X * regmlen length of regmust string
- X *
- X * Regstart and reganch permit very fast decisions on suitable starting points
- X * for a match, cutting down the work a lot. Regmust permits fast rejection
- X * of lines that cannot possibly match. The regmust tests are costly enough
- X * that regcomp() supplies a regmust only if the r.e. contains something
- X * potentially expensive (at present, the only such thing detected is * or +
- X * at the start of the r.e., which can involve a lot of backup). Regmlen is
- X * supplied because the test in regexec() needs it and regcomp() is computing
- X * it anyway.
- X */
- X
- X/*
- X * Structure for regexp "program". This is essentially a linear encoding
- X * of a nondeterministic finite-state machine (aka syntax charts or
- X * "railroad normal form" in parsing technology). Each node is an opcode
- X * plus a "next" pointer, possibly plus an operand. "Next" pointers of
- X * all nodes except BRANCH implement concatenation; a "next" pointer with
- X * a BRANCH on both ends of it is connecting two alternatives. (Here we
- X * have one of the subtle syntax dependencies: an individual BRANCH (as
- X * opposed to a collection of them) is never concatenated with anything
- X * because of operator precedence.) The operand of some types of node is
- X * a literal string; for others, it is a node leading into a sub-FSM. In
- X * particular, the operand of a BRANCH node is the first node of the branch.
- X * (NB this is *not* a tree structure: the tail of the branch connects
- X * to the thing following the set of BRANCHes.) The opcodes are:
- X */
- X
- X/* definition number opnd? meaning */
- X#define END 0 /* no End of program. */
- X#define BOL 1 /* no Match "" at beginning of line. */
- X#define EOL 2 /* no Match "" at end of line. */
- X#define ANY 3 /* no Match any one character. */
- X#define ANYOF 4 /* str Match any character in this string. */
- X#define ANYBUT 5 /* str Match any character not in this string. */
- X#define BRANCH 6 /* node Match this alternative, or the next... */
- X#define BACK 7 /* no Match "", "next" ptr points backward. */
- X#define EXACTLY 8 /* str Match this string. */
- X#define NOTHING 9 /* no Match empty string. */
- X#define STAR 10 /* node Match this (simple) thing 0 or more times. */
- X#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
- X#define OPEN 20 /* no Mark this point in input as start of #n. */
- X /* OPEN+1 is number 1, etc. */
- X#define CLOSE 30 /* no Analogous to OPEN. */
- X
- X/*
- X * Opcode notes:
- X *
- X * BRANCH The set of branches constituting a single choice are hooked
- X * together with their "next" pointers, since precedence prevents
- X * anything being concatenated to any individual branch. The
- X * "next" pointer of the last BRANCH in a choice points to the
- X * thing following the whole choice. This is also where the
- X * final "next" pointer of each individual branch points; each
- X * branch starts with the operand node of a BRANCH node.
- X *
- X * BACK Normal "next" pointers all implicitly point forward; BACK
- X * exists to make loop structures possible.
- X *
- X * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
- X * BRANCH structures using BACK. Simple cases (one character
- X * per match) are implemented with STAR and PLUS for speed
- X * and to minimize recursive plunges.
- X *
- X * OPEN,CLOSE ...are numbered at compile time.
- X */
- X
- X/*
- X * A node is one char of opcode followed by two chars of "next" pointer.
- X * "Next" pointers are stored as two 8-bit pieces, high order first. The
- X * value is a positive offset from the opcode of the node containing it.
- X * An operand, if any, simply follows the node. (Note that much of the
- X * code generation knows about this implicit relationship.)
- X *
- X * Using two bytes for the "next" pointer is vast overkill for most things,
- X * but allows patterns to get big without disasters.
- X */
- X#define OP(p) (*(p))
- X#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
- X#define OPERAND(p) ((p) + 3)
- X
- X/*
- X * See regmagic.h for one further detail of program structure.
- X */
- X
- X
- X/*
- X * Utility definitions.
- X */
- X#ifndef CHARBITS
- X#define UCHARAT(p) ((int)*(unsigned char *)(p))
- X#else
- X#define UCHARAT(p) ((int)*(p)&CHARBITS)
- X#endif
- X
- X#define FAIL(m) { regerror(m); return(NULL); }
- X#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
- X#define META "^$.[()|?+*\\"
- X
- X/*
- X * Flags to be passed up and down.
- X */
- X#define HASWIDTH 01 /* Known never to match null string. */
- X#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
- X#define SPSTART 04 /* Starts with * or +. */
- X#define WORST 0 /* Worst case. */
- X
- X/*
- X * Global work variables for regcomp().
- X */
- Xstatic char *regparse; /* Input-scan pointer. */
- Xstatic int regnpar; /* () count. */
- Xstatic char regdummy;
- Xstatic char *regcode; /* Code-emit pointer; ®dummy = don't. */
- Xstatic long regsize; /* Code size. */
- X#ifdef MULTILINE
- Xstatic int regnl; /* '\n' detected. */
- X#endif
- X
- X/*
- X * Forward declarations for regcomp()'s friends.
- X */
- X#ifndef STATIC
- X#define STATIC static
- X#endif
- XSTATIC char *reg();
- XSTATIC char *regbranch();
- XSTATIC char *regpiece();
- XSTATIC char *regatom();
- XSTATIC char *regnode();
- XSTATIC char *regnext();
- XSTATIC void regc();
- XSTATIC void reginsert();
- XSTATIC void regtail();
- XSTATIC void regoptail();
- X#ifdef STRCSPN
- XSTATIC int strcspn();
- X#endif
- X
- X/*
- X - regcomp - compile a regular expression into internal code
- X *
- X * We can't allocate space until we know how big the compiled form will be,
- X * but we can't compile it (and thus know how big it is) until we've got a
- X * place to put the code. So we cheat: we compile it twice, once with code
- X * generation turned off and size counting turned on, and once "for real".
- X * This also means that we don't allocate space until we are sure that the
- X * thing really will compile successfully, and we never have to move the
- X * code and thus invalidate pointers into it. (Note that it has to be in
- X * one piece because free() must be able to free it all.)
- X *
- X * Beware that the optimization-preparation code in here knows about some
- X * of the structure of the compiled regexp.
- X */
- Xregexp *
- Xregcomp(exp)
- Xchar *exp;
- X{
- X register regexp *r;
- X register char *scan;
- X register char *longest;
- X register int len;
- X int flags;
- X extern char *malloc();
- X
- X if (exp == NULL)
- X FAIL("NULL argument");
- X
- X /* First pass: determine size, legality. */
- X regparse = exp;
- X regnpar = 1;
- X regsize = 0L;
- X regcode = ®dummy;
- X#ifdef MULTILINE
- X regnl = 0;
- X#endif
- X regc(MAGIC);
- X if (reg(0, &flags) == NULL)
- X return(NULL);
- X
- X /* Small enough for pointer-storage convention? */
- X if (regsize >= 32767L) /* Probably could be 65535L. */
- X FAIL("regexp too big");
- X
- X /* Allocate space. */
- X r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
- X if (r == NULL)
- X FAIL("out of space");
- X
- X /* Second pass: emit code. */
- X regparse = exp;
- X regnpar = 1;
- X regcode = r->program;
- X regc(MAGIC);
- X if (reg(0, &flags) == NULL)
- X return(NULL);
- X
- X /* Dig out information for optimizations. */
- X r->regstart = '\0'; /* Worst-case defaults. */
- X r->reganch = 0;
- X r->regmust = NULL;
- X r->regmlen = 0;
- X scan = r->program+1; /* First BRANCH. */
- X if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
- X scan = OPERAND(scan);
- X
- X /* Starting-point info. */
- X if (OP(scan) == EXACTLY)
- X r->regstart = *OPERAND(scan);
- X else if (OP(scan) == BOL)
- X r->reganch++;
- X
- X /*
- X * If there's something expensive in the r.e., find the
- X * longest literal string that must appear and make it the
- X * regmust. Resolve ties in favor of later strings, since
- X * the regstart check works with the beginning of the r.e.
- X * and avoiding duplication strengthens checking. Not a
- X * strong reason, but sufficient in the absence of others.
- X */
- X#ifdef MULTILINE
- X if ((flags&SPSTART) && !regnl) {
- X#else
- X if (flags&SPSTART) {
- X#endif
- X longest = NULL;
- X len = 0;
- X for (; scan != NULL; scan = regnext(scan))
- X if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
- X longest = OPERAND(scan);
- X len = strlen(OPERAND(scan));
- X }
- X r->regmust = longest;
- X r->regmlen = len;
- X }
- X }
- X
- X return(r);
- X}
- X
- X/*
- X - reg - regular expression, i.e. main body or parenthesized thing
- X *
- X * Caller must absorb opening parenthesis.
- X *
- X * Combining parenthesis handling with the base level of regular expression
- X * is a trifle forced, but the need to tie the tails of the branches to what
- X * follows makes it hard to avoid.
- X */
- Xstatic char *
- Xreg(paren, flagp)
- Xint paren; /* Parenthesized? */
- Xint *flagp;
- X{
- X register char *ret;
- X register char *br;
- X register char *ender;
- X register int parno;
- X int flags;
- X
- X *flagp = HASWIDTH; /* Tentatively. */
- X
- X /* Make an OPEN node, if parenthesized. */
- X if (paren) {
- X if (regnpar >= NSUBEXP)
- X FAIL("too many ()");
- X parno = regnpar;
- X regnpar++;
- X ret = regnode(OPEN+parno);
- X } else
- X ret = NULL;
- X
- X /* Pick up the branches, linking them together. */
- X br = regbranch(&flags);
- X if (br == NULL)
- X return(NULL);
- X if (ret != NULL)
- X regtail(ret, br); /* OPEN -> first. */
- X else
- X ret = br;
- X if (!(flags&HASWIDTH))
- X *flagp &= ~HASWIDTH;
- X *flagp |= flags&SPSTART;
- X while (*regparse == '|') {
- X regparse++;
- X br = regbranch(&flags);
- X if (br == NULL)
- X return(NULL);
- X regtail(ret, br); /* BRANCH -> BRANCH. */
- X if (!(flags&HASWIDTH))
- X *flagp &= ~HASWIDTH;
- X *flagp |= flags&SPSTART;
- X }
- X
- X /* Make a closing node, and hook it on the end. */
- X ender = regnode((paren) ? CLOSE+parno : END);
- X regtail(ret, ender);
- X
- X /* Hook the tails of the branches to the closing node. */
- X for (br = ret; br != NULL; br = regnext(br))
- X regoptail(br, ender);
- X
- X /* Check for proper termination. */
- X if (paren && *regparse++ != ')') {
- X FAIL("unmatched ()");
- X } else if (!paren && *regparse != '\0') {
- X if (*regparse == ')') {
- X FAIL("unmatched ()");
- X } else
- X FAIL("junk on end"); /* "Can't happen". */
- X /* NOTREACHED */
- X }
- X
- X return(ret);
- X}
- X
- X/*
- X - regbranch - one alternative of an | operator
- X *
- X * Implements the concatenation operator.
- X */
- Xstatic char *
- Xregbranch(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X register char *chain;
- X register char *latest;
- X int flags;
- X
- X *flagp = WORST; /* Tentatively. */
- X
- X ret = regnode(BRANCH);
- X chain = NULL;
- X while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
- X latest = regpiece(&flags);
- X if (latest == NULL)
- X return(NULL);
- X *flagp |= flags&HASWIDTH;
- X if (chain == NULL) /* First piece. */
- X *flagp |= flags&SPSTART;
- X else
- X regtail(chain, latest);
- X chain = latest;
- X }
- X if (chain == NULL) /* Loop ran zero times. */
- X (void) regnode(NOTHING);
- X
- X return(ret);
- X}
- X
- X/*
- X - regpiece - something followed by possible [*+?]
- X *
- X * Note that the branching code sequences used for ? and the general cases
- X * of * and + are somewhat optimized: they use the same NOTHING node as
- X * both the endmarker for their branch list and the body of the last branch.
- X * It might seem that this node could be dispensed with entirely, but the
- X * endmarker role is not redundant.
- X */
- Xstatic char *
- Xregpiece(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X register char op;
- X register char *next;
- X int flags;
- X
- X ret = regatom(&flags);
- X if (ret == NULL)
- X return(NULL);
- X
- X op = *regparse;
- X if (!ISMULT(op)) {
- X *flagp = flags;
- X return(ret);
- X }
- X
- X if (!(flags&HASWIDTH) && op != '?')
- X FAIL("*+ operand could be empty");
- X *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
- X
- X if (op == '*' && (flags&SIMPLE))
- X reginsert(STAR, ret);
- X else if (op == '*') {
- X /* Emit x* as (x&|), where & means "self". */
- X reginsert(BRANCH, ret); /* Either x */
- X regoptail(ret, regnode(BACK)); /* and loop */
- X regoptail(ret, ret); /* back */
- X regtail(ret, regnode(BRANCH)); /* or */
- X regtail(ret, regnode(NOTHING)); /* null. */
- X } else if (op == '+' && (flags&SIMPLE))
- X reginsert(PLUS, ret);
- X else if (op == '+') {
- X /* Emit x+ as x(&|), where & means "self". */
- X next = regnode(BRANCH); /* Either */
- X regtail(ret, next);
- X regtail(regnode(BACK), ret); /* loop back */
- X regtail(next, regnode(BRANCH)); /* or */
- X regtail(ret, regnode(NOTHING)); /* null. */
- X } else if (op == '?') {
- X /* Emit x? as (x|) */
- X reginsert(BRANCH, ret); /* Either x */
- X regtail(ret, regnode(BRANCH)); /* or */
- X next = regnode(NOTHING); /* null. */
- X regtail(ret, next);
- X regoptail(ret, next);
- X }
- X regparse++;
- X if (ISMULT(*regparse))
- X FAIL("nested *?+");
- X
- X return(ret);
- X}
- X
- X/*
- X - regatom - the lowest level
- X *
- X * Optimization: gobbles an entire sequence of ordinary characters so that
- X * it can turn them into a single node, which is smaller to store and
- X * faster to run. Backslashed characters are exceptions, each becoming a
- X * separate node; the code is simpler that way and it's not worth fixing.
- X */
- Xstatic char *
- Xregatom(flagp)
- Xint *flagp;
- X{
- X register char *ret;
- X int flags;
- X
- X *flagp = WORST; /* Tentatively. */
- X
- X switch (*regparse++) {
- X case '^':
- X ret = regnode(BOL);
- X break;
- X case '$':
- X ret = regnode(EOL);
- X break;
- X case '.':
- X ret = regnode(ANY);
- X *flagp |= HASWIDTH|SIMPLE;
- X break;
- X case '[': {
- X register int class;
- X register int classend;
- X
- X if (*regparse == '^') { /* Complement of range. */
- X ret = regnode(ANYBUT);
- X regparse++;
- X } else
- X ret = regnode(ANYOF);
- X if (*regparse == ']' || *regparse == '-')
- X regc(*regparse++);
- X while (*regparse != '\0' && *regparse != ']') {
- X if (*regparse == '-') {
- X regparse++;
- X if (*regparse == ']' || *regparse == '\0')
- X regc('-');
- X else {
- X class = UCHARAT(regparse-2)+1;
- X classend = UCHARAT(regparse);
- X if (class > classend+1)
- X FAIL("invalid [] range");
- X for (; class <= classend; class++)
- X regc(class);
- X regparse++;
- X }
- X } else
- X regc(*regparse++);
- X }
- X regc('\0');
- X if (*regparse != ']')
- X FAIL("unmatched []");
- X regparse++;
- X *flagp |= HASWIDTH|SIMPLE;
- X }
- X break;
- X case '(':
- X ret = reg(1, &flags);
- X if (ret == NULL)
- X return(NULL);
- X *flagp |= flags&(HASWIDTH|SPSTART);
- X break;
- X case '\0':
- X case '|':
- X case ')':
- X FAIL("internal urp"); /* Supposed to be caught earlier. */
- X break;
- X case '?':
- X case '+':
- X case '*':
- X FAIL("?+* follows nothing");
- X break;
- X case '\\':
- X if (*regparse == '\0')
- X FAIL("trailing \\");
- X ret = regnode(EXACTLY);
- X#ifdef MULTILINE
- X if (*regparse == 'n') {
- X regc('\n');
- X regparse++;
- X regnl++;
- X }
- X else
- X#endif
- X regc(*regparse++);
- X regc('\0');
- X *flagp |= HASWIDTH|SIMPLE;
- X break;
- X default: {
- X register int len;
- X register char ender;
- X
- X regparse--;
- X len = strcspn(regparse, META);
- X if (len <= 0)
- X FAIL("internal disaster");
- X ender = *(regparse+len);
- X if (len > 1 && ISMULT(ender))
- X len--; /* Back off clear of ?+* operand. */
- X *flagp |= HASWIDTH;
- X if (len == 1)
- X *flagp |= SIMPLE;
- X ret = regnode(EXACTLY);
- X while (len > 0) {
- X#ifdef MULTILINE
- X if (*regparse == '\n')
- X regnl++;
- X#endif
- X regc(*regparse++);
- X len--;
- X }
- X regc('\0');
- X }
- X break;
- X }
- X
- X return(ret);
- X}
- X
- X/*
- X - regnode - emit a node
- X */
- Xstatic char * /* Location. */
- Xregnode(op)
- Xchar op;
- X{
- X register char *ret;
- X register char *ptr;
- X
- X ret = regcode;
- X if (ret == ®dummy) {
- X regsize += 3;
- X return(ret);
- X }
- X
- X ptr = ret;
- X *ptr++ = op;
- X *ptr++ = '\0'; /* Null "next" pointer. */
- X *ptr++ = '\0';
- X regcode = ptr;
- X
- X return(ret);
- X}
- X
- X/*
- X - regc - emit (if appropriate) a byte of code
- X */
- Xstatic void
- Xregc(b)
- Xchar b;
- X{
- X if (regcode != ®dummy)
- X *regcode++ = b;
- X else
- X regsize++;
- X}
- X
- X/*
- X - reginsert - insert an operator in front of already-emitted operand
- X *
- X * Means relocating the operand.
- X */
- Xstatic void
- Xreginsert(op, opnd)
- Xchar op;
- Xchar *opnd;
- X{
- X register char *src;
- X register char *dst;
- X register char *place;
- X
- X if (regcode == ®dummy) {
- X regsize += 3;
- X return;
- X }
- X
- X src = regcode;
- X regcode += 3;
- X dst = regcode;
- X while (src > opnd)
- X *--dst = *--src;
- X
- X place = opnd; /* Op node, where operand used to be. */
- X *place++ = op;
- X *place++ = '\0';
- X *place++ = '\0';
- X}
- X
- X/*
- X - regtail - set the next-pointer at the end of a node chain
- X */
- Xstatic void
- Xregtail(p, val)
- Xchar *p;
- Xchar *val;
- X{
- X register char *scan;
- X register char *temp;
- X register int offset;
- X
- X if (p == ®dummy)
- X return;
- X
- X /* Find last node. */
- X scan = p;
- X for (;;) {
- X temp = regnext(scan);
- X if (temp == NULL)
- X break;
- X scan = temp;
- X }
- X
- X if (OP(scan) == BACK)
- X offset = scan - val;
- X else
- X offset = val - scan;
- X *(scan+1) = (offset>>8)&0377;
- X *(scan+2) = offset&0377;
- X}
- X
- X/*
- X - regoptail - regtail on operand of first argument; nop if operandless
- X */
- Xstatic void
- Xregoptail(p, val)
- Xchar *p;
- Xchar *val;
- X{
- X /* "Operandless" and "op != BRANCH" are synonymous in practice. */
- X if (p == NULL || p == ®dummy || OP(p) != BRANCH)
- X return;
- X regtail(OPERAND(p), val);
- X}
- X
- X/*
- X * regexec and friends
- X */
- X
- X/*
- X * Global work variables for regexec().
- X */
- Xstatic char *reginput; /* String-input pointer. */
- Xstatic char *regbol; /* Beginning of input, for ^ check. */
- Xstatic char **regstartp; /* Pointer to startp array. */
- Xstatic char **regendp; /* Ditto for endp. */
- X
- X/*
- X * Forwards.
- X */
- XSTATIC int regtry();
- XSTATIC int regmatch();
- XSTATIC int regrepeat();
- X
- X#ifdef DEBUG
- Xint regnarrate = 0;
- Xvoid regdump();
- XSTATIC char *regprop();
- X#endif
- X
- X/*
- X - regexec - match a regexp against a string
- X */
- Xint
- Xregexec(prog, string)
- Xregister regexp *prog;
- Xregister char *string;
- X{
- X register char *s;
- X extern char *strchr();
- X
- X /* Be paranoid... */
- X if (prog == NULL || string == NULL) {
- X regerror("NULL parameter");
- X return(0);
- X }
- X
- X#ifdef MULTILINE
- X /* Check for \n in string, and if so, call the more general routine. */
- X if (strchr(string, '\n') != NULL)
- X return reglexec(prog, string, 0);
- X#endif
- X
- X /* Check validity of program. */
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("corrupted program");
- X return(0);
- X }
- X
- X /* If there is a "must appear" string, look for it. */
- X if (prog->regmust != NULL) {
- X s = string;
- X while ((s = strchr(s, prog->regmust[0])) != NULL) {
- X if (strncmp(s, prog->regmust, prog->regmlen) == 0)
- X break; /* Found it. */
- X s++;
- X }
- X if (s == NULL) /* Not present. */
- X return(0);
- X }
- X
- X /* Mark beginning of line for ^ . */
- X regbol = string;
- X
- X /* Simplest case: anchored match need be tried only once. */
- X if (prog->reganch)
- X return(regtry(prog, string));
- X
- X /* Messy cases: unanchored match. */
- X s = string;
- X if (prog->regstart != '\0')
- X /* We know what char it must start with. */
- X while ((s = strchr(s, prog->regstart)) != NULL) {
- X if (regtry(prog, s))
- X return(1);
- X s++;
- X }
- X else
- X /* We don't -- general case. */
- X do {
- X if (regtry(prog, s))
- X return(1);
- X } while (*s++ != '\0');
- X
- X /* Failure. */
- X return(0);
- X}
- X
- X#ifdef MULTILINE
- X/*
- X - reglexec - match a regexp against a long string buffer, starting at offset
- X */
- Xint
- Xreglexec(prog, string, offset)
- Xregister regexp *prog;
- Xregister char *string;
- X{
- X register char *s;
- X extern char *strchr();
- X
- X /* Be paranoid... */
- X if (prog == NULL || string == NULL) {
- X regerror("NULL parameter");
- X return(0);
- X }
- X
- X /* Check validity of program. */
- X if (UCHARAT(prog->program) != MAGIC) {
- X regerror("corrupted program");
- X return(0);
- X }
- X
- X /* (Don't look for "must appear" string -- string can be long.) */
- X
- X /* Mark beginning of line for ^ . */
- X regbol = string;
- X
- X /* Apply offset.
- X Assume 0 <= offset <= strlen(string), but don't check,
- X as string can be long. */
- X s= string + offset;
- X
- X /* Anchored match need be tried only at line starts. */
- X if (prog->reganch) {
- X while (!regtry(prog, s)) {
- X s = strchr(s, '\n');
- X if (s == NULL)
- X return(0);
- X s++;
- X }
- X return(1);
- X }
- X
- X /* Messy cases: unanchored match. */
- X if (prog->regstart != '\0')
- X /* We know what char it must start with. */
- X while ((s = strchr(s, prog->regstart)) != NULL) {
- X if (regtry(prog, s))
- X return(1);
- X s++;
- X }
- X else
- X /* We don't -- general case. */
- X do {
- X if (regtry(prog, s))
- X return(1);
- X } while (*s++ != '\0');
- X
- X /* Failure. */
- X return(0);
- X}
- X#endif
- X
- X/*
- X - regtry - try match at specific point
- X */
- Xstatic int /* 0 failure, 1 success */
- Xregtry(prog, string)
- Xregexp *prog;
- Xchar *string;
- X{
- X register int i;
- X register char **sp;
- X register char **ep;
- X
- X reginput = string;
- X regstartp = prog->startp;
- X regendp = prog->endp;
- X
- X sp = prog->startp;
- X ep = prog->endp;
- X for (i = NSUBEXP; i > 0; i--) {
- X *sp++ = NULL;
- X *ep++ = NULL;
- X }
- X if (regmatch(prog->program + 1)) {
- X prog->startp[0] = string;
- X prog->endp[0] = reginput;
- X return(1);
- X } else
- X return(0);
- X}
- X
- X/*
- X - regmatch - main matching routine
- X *
- X * Conceptually the strategy is simple: check to see whether the current
- X * node matches, call self recursively to see whether the rest matches,
- X * and then act accordingly. In practice we make some effort to avoid
- X * recursion, in particular by going through "ordinary" nodes (that don't
- X * need to know whether the rest of the match failed) by a loop instead of
- X * by recursion.
- X */
- Xstatic int /* 0 failure, 1 success */
- Xregmatch(prog)
- Xchar *prog;
- X{
- X register char *scan; /* Current node. */
- X char *next; /* Next node. */
- X extern char *strchr();
- X
- X scan = prog;
- X#ifdef DEBUG
- X if (scan != NULL && regnarrate)
- X fprintf(stderr, "%s(\n", regprop(scan));
- X#endif
- X while (scan != NULL) {
- X#ifdef DEBUG
- X if (regnarrate)
- X fprintf(stderr, "%s...\n", regprop(scan));
- X#endif
- X next = regnext(scan);
- X
- X switch (OP(scan)) {
- X case BOL:
- X#ifdef MULTILINE
- X if (!(reginput == regbol ||
- X reginput > regbol && *(reginput-1) == '\n'))
- X#else
- X if (reginput != regbol)
- X#endif
- X return(0);
- X break;
- X case EOL:
- X#ifdef MULTILINE
- X if (*reginput != '\0' && *reginput != '\n')
- X#else
- X if (*reginput != '\0')
- X#endif
- X return(0);
- X break;
- X case ANY:
- X#ifdef MULTILINE
- X if (*reginput == '\0' || *reginput == '\n')
- X#else
- X if (*reginput == '\0')
- X#endif
- X return(0);
- X reginput++;
- X break;
- X case EXACTLY: {
- X register int len;
- X register char *opnd;
- X
- X opnd = OPERAND(scan);
- X /* Inline the first character, for speed. */
- X if (*opnd != *reginput)
- X return(0);
- X len = strlen(opnd);
- X if (len > 1 && strncmp(opnd, reginput, len) != 0)
- X return(0);
- X reginput += len;
- X }
- X break;
- X case ANYOF:
- X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
- X return(0);
- X reginput++;
- X break;
- X case ANYBUT:
- X#ifdef MULTILINE
- X if (*reginput == '\0' || *reginput == '\n' ||
- X strchr(OPERAND(scan), *reginput) != NULL)
- X#else
- X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
- X#endif
- X return(0);
- X reginput++;
- X break;
- X case NOTHING:
- X break;
- X case BACK:
- X break;
- X case OPEN+1:
- X case OPEN+2:
- X case OPEN+3:
- X case OPEN+4:
- X case OPEN+5:
- X case OPEN+6:
- X case OPEN+7:
- X case OPEN+8:
- X case OPEN+9: {
- X register int no;
- X register char *save;
- X
- X no = OP(scan) - OPEN;
- X save = reginput;
- X
- X if (regmatch(next)) {
- X /*
- X * Don't set startp if some later
- X * invocation of the same parentheses
- X * already has.
- X */
- X if (regstartp[no] == NULL)
- X regstartp[no] = save;
- X return(1);
- X } else
- X return(0);
- X }
- X break;
- X case CLOSE+1:
- X case CLOSE+2:
- X case CLOSE+3:
- X case CLOSE+4:
- X case CLOSE+5:
- X case CLOSE+6:
- X case CLOSE+7:
- X case CLOSE+8:
- X case CLOSE+9: {
- X register int no;
- X register char *save;
- X
- X no = OP(scan) - CLOSE;
- X save = reginput;
- X
- X if (regmatch(next)) {
- X /*
- X * Don't set endp if some later
- X * invocation of the same parentheses
- X * already has.
- X */
- X if (regendp[no] == NULL)
- X regendp[no] = save;
- X return(1);
- X } else
- X return(0);
- X }
- X break;
- X case BRANCH: {
- X register char *save;
- X
- X if (OP(next) != BRANCH) /* No choice. */
- X next = OPERAND(scan); /* Avoid recursion. */
- X else {
- X do {
- X save = reginput;
- X if (regmatch(OPERAND(scan)))
- X return(1);
- X reginput = save;
- X scan = regnext(scan);
- X } while (scan != NULL && OP(scan) == BRANCH);
- X return(0);
- X /* NOTREACHED */
- X }
- X }
- X break;
- X case STAR:
- X case PLUS: {
- X register char nextch;
- X register int no;
- X register char *save;
- X register int min;
- X
- X /*
- X * Lookahead to avoid useless match attempts
- X * when we know what character comes next.
- X */
- X nextch = '\0';
- X if (OP(next) == EXACTLY)
- X nextch = *OPERAND(next);
- X min = (OP(scan) == STAR) ? 0 : 1;
- X save = reginput;
- X no = regrepeat(OPERAND(scan));
- X while (no >= min) {
- X /* If it could work, try it. */
- X if (nextch == '\0' || *reginput == nextch)
- X if (regmatch(next))
- X return(1);
- X /* Couldn't or didn't -- back up. */
- X no--;
- X reginput = save + no;
- X }
- X return(0);
- X }
- X break;
- X case END:
- X return(1); /* Success! */
- X break;
- X default:
- X regerror("memory corruption");
- X return(0);
- X break;
- X }
- X
- X scan = next;
- X }
- X
- X /*
- X * We get here only if there's trouble -- normally "case END" is
- X * the terminating point.
- X */
- X regerror("corrupted pointers");
- X return(0);
- X}
- X
- X/*
- X - regrepeat - repeatedly match something simple, report how many
- X */
- Xstatic int
- Xregrepeat(p)
- Xchar *p;
- X{
- X register int count = 0;
- X register char *scan;
- X register char *opnd;
- X#ifdef MULTILINE
- X register char *eol;
- X#endif
- X
- X scan = reginput;
- X opnd = OPERAND(p);
- X switch (OP(p)) {
- X case ANY:
- X#ifdef MULTILINE
- X if ((eol = strchr(scan, '\n')) != NULL) {
- X count += eol - scan;
- X scan = eol;
- X break;
- X }
- X#endif
- X count = strlen(scan);
- X scan += count;
- X break;
- X case EXACTLY:
- X while (*opnd == *scan) {
- X count++;
- X scan++;
- X }
- X break;
- X case ANYOF:
- X while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
- X count++;
- X scan++;
- X }
- X break;
- X case ANYBUT:
- X#ifdef MULTILINE
- X while (*scan != '\0' && *scan != '\n' &&
- X strchr(opnd, *scan) == NULL) {
- X#else
- X while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
- X#endif
- X count++;
- X scan++;
- X }
- X break;
- X default: /* Oh dear. Called inappropriately. */
- X regerror("internal foulup");
- X count = 0; /* Best compromise. */
- X break;
- X }
- X reginput = scan;
- X
- X return(count);
- X}
- X
- X/*
- X - regnext - dig the "next" pointer out of a node
- X */
- Xstatic char *
- Xregnext(p)
- Xregister char *p;
- X{
- X register int offset;
- X
- X if (p == ®dummy)
- X return(NULL);
- X
- X offset = NEXT(p);
- X if (offset == 0)
- X return(NULL);
- X
- X if (OP(p) == BACK)
- X return(p-offset);
- X else
- X return(p+offset);
- X}
- X
- X#ifdef DEBUG
- X
- XSTATIC char *regprop();
- X
- X/*
- X - regdump - dump a regexp onto stdout in vaguely comprehensible form
- X */
- Xvoid
- Xregdump(r)
- Xregexp *r;
- X{
- X register char *s;
- X register char op = EXACTLY; /* Arbitrary non-END op. */
- X register char *next;
- X extern char *strchr();
- X
- X
- X s = r->program + 1;
- X while (op != END) { /* While that wasn't END last time... */
- X op = OP(s);
- X printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
- X next = regnext(s);
- X if (next == NULL) /* Next ptr. */
- X printf("(0)");
- X else
- X printf("(%d)", (s-r->program)+(next-s));
- X s += 3;
- X if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
- X /* Literal string, where present. */
- X while (*s != '\0') {
- X#ifdef MULTILINE
- X if (*s == '\n')
- X printf("\\n");
- X else
- X#endif
- X putchar(*s);
- X s++;
- X }
- X s++;
- X }
- X putchar('\n');
- X }
- X
- X /* Header fields of interest. */
- X if (r->regstart != '\0')
- X printf("start `%c' ", r->regstart);
- X if (r->reganch)
- X printf("anchored ");
- X if (r->regmust != NULL)
- X printf("must have \"%s\"", r->regmust);
- X printf("\n");
- X}
- X
- X/*
- X - regprop - printable representation of opcode
- X */
- Xstatic char *
- Xregprop(op)
- Xchar *op;
- X{
- X register char *p;
- X static char buf[50];
- X
- X (void) strcpy(buf, ":");
- X
- X switch (OP(op)) {
- X case BOL:
- X p = "BOL";
- X break;
- X case EOL:
- X p = "EOL";
- X break;
- X case ANY:
- X p = "ANY";
- X break;
- X case ANYOF:
- X p = "ANYOF";
- X break;
- X case ANYBUT:
- X p = "ANYBUT";
- X break;
- X case BRANCH:
- X p = "BRANCH";
- X break;
- X case EXACTLY:
- X p = "EXACTLY";
- X break;
- X case NOTHING:
- X p = "NOTHING";
- X break;
- X case BACK:
- X p = "BACK";
- X break;
- X case END:
- X p = "END";
- X break;
- X case OPEN+1:
- X case OPEN+2:
- X case OPEN+3:
- X case OPEN+4:
- X case OPEN+5:
- X case OPEN+6:
- X case OPEN+7:
- X case OPEN+8:
- X case OPEN+9:
- X sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
- X p = NULL;
- X break;
- X case CLOSE+1:
- X case CLOSE+2:
- X case CLOSE+3:
- X case CLOSE+4:
- X case CLOSE+5:
- X case CLOSE+6:
- X case CLOSE+7:
- X case CLOSE+8:
- X case CLOSE+9:
- X sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- X p = NULL;
- X break;
- X case STAR:
- X p = "STAR";
- X break;
- X case PLUS:
- X p = "PLUS";
- X break;
- X default:
- X regerror("corrupted opcode");
- X break;
- X }
- X if (p != NULL)
- X (void) strcat(buf, p);
- X return(buf);
- X}
- X#endif
- X
- X/*
- X * The following is provided for those people who do not have strcspn() in
- X * their C libraries. They should get off their butts and do something
- X * about it; at least one public-domain implementation of those (highly
- X * useful) string routines has been published on Usenet.
- X */
- X#ifdef STRCSPN
- X/*
- X * strcspn - find length of initial segment of s1 consisting entirely
- X * of characters not from s2
- X */
- X
- Xstatic int
- Xstrcspn(s1, s2)
- Xchar *s1;
- Xchar *s2;
- X{
- X register char *scan1;
- X register char *scan2;
- X register int count;
- X
- X count = 0;
- X for (scan1 = s1; *scan1 != '\0'; scan1++) {
- X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
- X if (*scan1 == *scan2++)
- X return(count);
- X count++;
- X }
- X return(count);
- X}
- X#endif
- END_OF_FILE
- if test 31000 -ne `wc -c <'Appls/miniedit/regexp.c'`; then
- echo shar: \"'Appls/miniedit/regexp.c'\" unpacked with wrong size!
- fi
- # end of 'Appls/miniedit/regexp.c'
- fi
- if test ! -d 'Appls/repeat' ; then
- echo shar: Creating directory \"'Appls/repeat'\"
- mkdir 'Appls/repeat'
- fi
- if test ! -d 'Appls/test' ; then
- echo shar: Creating directory \"'Appls/test'\"
- mkdir 'Appls/test'
- fi
- if test -f 'Appls/test/test3.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Appls/test/test3.c'\"
- else
- echo shar: Extracting \"'Appls/test/test3.c'\" \(769 characters\)
- sed "s/^X//" >'Appls/test/test3.c' <<'END_OF_FILE'
- X/* Text-edit test -- a text-edit window. */
- X
- X#include "stdwin.h"
- X
- XTEXTEDIT *tb;
- X
- Xvoid
- Xdrawproc(win, l, t, r, b)
- X WINDOW *win;
- X{
- X tedraw(tb);
- X}
- X
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X WINDOW *win;
- X int width, height;
- X
- X winitargs(&argc, &argv);
- X if (argc >= 3) {
- X int h= atoi(argv[1]), v= atoi(argv[2]);
- X wsetdefwinpos(h, v);
- X }
- X
- X win= wopen("Textedit", drawproc);
- X wgetwinsize(win, &width, &height);
- X wsetdocsize(win, width, height);
- X
- X tb= tealloc(win, 0, 0, width);
- X tereplace(tb, "Hello, world\n--Guido van Rossum");
- X
- X for (;;) {
- X EVENT e;
- X wgetevent(&e);
- X if (e.type == WE_CLOSE || e.type == WE_COMMAND &&
- X (e.u.command == WC_CLOSE || e.u.command == WC_CANCEL))
- X break;
- X (void) teevent(tb, &e);
- X }
- X tefree(tb);
- X wclose(win);
- X wdone();
- X exit(0);
- X}
- END_OF_FILE
- if test 769 -ne `wc -c <'Appls/test/test3.c'`; then
- echo shar: \"'Appls/test/test3.c'\" unpacked with wrong size!
- fi
- # end of 'Appls/test/test3.c'
- fi
- if test ! -d 'Appls/tetris' ; then
- echo shar: Creating directory \"'Appls/tetris'\"
- mkdir 'Appls/tetris'
- fi
- if test ! -d 'Conf' ; then
- echo shar: Creating directory \"'Conf'\"
- mkdir 'Conf'
- fi
- if test ! -d 'Doc' ; then
- echo shar: Creating directory \"'Doc'\"
- mkdir 'Doc'
- fi
- if test ! -d 'Doc/man' ; then
- echo shar: Creating directory \"'Doc/man'\"
- mkdir 'Doc/man'
- fi
- if test ! -d 'Gen' ; then
- echo shar: Creating directory \"'Gen'\"
- mkdir 'Gen'
- fi
- if test ! -d 'H' ; then
- echo shar: Creating directory \"'H'\"
- mkdir 'H'
- fi
- if test ! -d 'Packs' ; then
- echo shar: Creating directory \"'Packs'\"
- mkdir 'Packs'
- fi
- if test ! -d 'Packs/textedit' ; then
- echo shar: Creating directory \"'Packs/textedit'\"
- mkdir 'Packs/textedit'
- fi
- if test ! -d 'Packs/vt' ; then
- echo shar: Creating directory \"'Packs/vt'\"
- mkdir 'Packs/vt'
- fi
- if test ! -d 'Ports' ; then
- echo shar: Creating directory \"'Ports'\"
- mkdir 'Ports'
- fi
- if test ! -d 'Ports/alfa' ; then
- echo shar: Creating directory \"'Ports/alfa'\"
- mkdir 'Ports/alfa'
- fi
- if test ! -d 'Ports/mac' ; then
- echo shar: Creating directory \"'Ports/mac'\"
- mkdir 'Ports/mac'
- fi
- if test ! -d 'Ports/mac_mpw' ; then
- echo shar: Creating directory \"'Ports/mac_mpw'\"
- mkdir 'Ports/mac_mpw'
- fi
- if test ! -d 'Ports/msdos' ; then
- echo shar: Creating directory \"'Ports/msdos'\"
- mkdir 'Ports/msdos'
- fi
- if test ! -d 'Ports/vtrm' ; then
- echo shar: Creating directory \"'Ports/vtrm'\"
- mkdir 'Ports/vtrm'
- fi
- if test ! -d 'Ports/vtrm/DIST' ; then
- echo shar: Creating directory \"'Ports/vtrm/DIST'\"
- mkdir 'Ports/vtrm/DIST'
- fi
- if test ! -d 'Ports/x11' ; then
- echo shar: Creating directory \"'Ports/x11'\"
- mkdir 'Ports/x11'
- fi
- if test ! -d 'Tools' ; then
- echo shar: Creating directory \"'Tools'\"
- mkdir 'Tools'
- fi
- echo shar: End of archive 1 \(of 19\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-