home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / sortmail / part01 next >
Text File  |  1994-08-18  |  85KB  |  3,118 lines

  1. Newsgroups: comp.sources.unix
  2. From: Ed.Falk@Eng.Sun.COM (Ed Falk)
  3. Subject: v28i114: sortmail - kill files and more for your mail, Part01/01
  4. Message-id: <1.777230853.7352@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: Ed.Falk@Eng.Sun.COM (Ed Falk)
  9. Posting-Number: Volume 28, Issue 114
  10. Archive-Name: sortmail/part01
  11.  
  12. Hi; I post this program because I believe it is the best one I've
  13. seen (or I wouldn't have written it.)  It's written in C rather than
  14. shell scripts, and runs quite fast.
  15.  
  16. Overview: sortmail(1) examines incoming mail and sorts it for you based
  17. on all or part of the header, or even the entire message.
  18.  
  19. Messages can be filed to your mailbox, to a specific mail folder,
  20. junked, forwarded to another address or piped through sh(1).
  21.  
  22. The format of the $HOME/.sortmailrc file is similar to an rn KILL file:
  23.  
  24.           set default=+other
  25.           /MAILER-DAEMON/f:+bounces
  26.           /falk/t:m
  27.           /scuba/s:+scuba
  28.           /marko/f:j
  29.           /^Precedence: junk/h:+other
  30.  
  31. #! /bin/sh
  32. # this is a shell archive, meaning:
  33. # 1. Remove everything above the #! /bin/sh line
  34. # 2. Save the resulting text in a file.
  35. # 3. Execute the file with /bin/sh to create the files:
  36. #    sortmail.1
  37. #    sample.forward
  38. #    sample.sortmailrc
  39. #    Makefile
  40. #    sortmail.h
  41. #    regex.h
  42. #    sortmail.c
  43. #    parse.c
  44. #    regex.c
  45. # This archive created: Wed Aug 17 13:42:30 PDT 1994 by falk
  46. #
  47. #
  48. export PATH; PATH=/bin:$PATH
  49. #
  50.  
  51. if test -f sortmail.1
  52. then
  53. echo shar: will not over-write existing file sortmail.1
  54. else
  55. echo shar: extracting 'sortmail.1',     7787 characters
  56. sed 's/^X//' > sortmail.1 <<'SHAR_EOF'
  57. X.\" %Z%%M% %I% %E%; Copyright (c) 1990 - Sun Microsystems
  58. X.\"
  59. X.TH SORTMAIL 1 "21 Apr 1991"
  60. X.SH NAME
  61. Xsortmail \- classify incoming mail
  62. X.SH SYNOPSIS
  63. X.B sortmail
  64. X[
  65. X.B \-v
  66. X] [
  67. X.B \-home
  68. X.I path
  69. X] [
  70. X.B \-mailbox
  71. X.I path
  72. X] [
  73. X.B \-mailrc
  74. X.I initfile
  75. X] [
  76. X.B \-sortmailrc
  77. X.I initfile
  78. X]
  79. X.I username
  80. X.SH DESCRIPTION
  81. XCreate this \fB.forward\fP file in your home directory:
  82. X
  83. X    "| /\fIpath\fP/sortmail \fIuser\fP"
  84. X
  85. XWhere "/\fIpath\fP/sortmail" is the full path where you installed
  86. Xsortmail, and \fIuser\fP is your own userid.  The userid must be
  87. Xspecified because when mail arrives \fBsortmail\fP could be run as
  88. Xroot, daemon, or any number of other id's.
  89. X
  90. XOnce your \fB.forward\fP file is set up,
  91. X.B sortmail
  92. Xwill classify incoming mail according to the patterns in $HOME/.sortmailrc.
  93. XYour \fB.sortmailrc\fP file is similar to a news KILL file, but somewhat
  94. Xmore powerful.  You can discard mail, have it delivered to your mailbox,
  95. Xhave it filed into a folder, forward it to another address
  96. Xor even pipe it through a shell command.
  97. X
  98. XWhen \fBsortmail\fP starts up, it first reads your \fB.mailrc\fP file to
  99. Xfind the value of mail(1) variables that are also used by \fBsortmail\fP.
  100. XIt then reads your \fB.sortmailrc\fP file for additional variable settings,
  101. Xif any, and for search patterns.  (See below.)
  102. X
  103. X.SH OPTIONS
  104. X.TP 15
  105. X.B \-v
  106. XVerbose.  A message is printed on /dev/console for every mail message.  A
  107. Xsecond
  108. X.B \-v
  109. Xcauses a lot more information to be printed.
  110. X.TP 15
  111. X\fB\-home\fP \fIpath\fP
  112. XSet user's home directory, overriding the default taken from the user's
  113. Xpasswd entry.
  114. X.TP 15
  115. X\fB\-mailbox\fP \fIpath\fP
  116. XSet the user's system mailbox, overriding the default of
  117. X\fB/usr/spool/mail/\fP\fIuser\fP.
  118. X.TP 15
  119. X\fB\-mailrc\fP \fIpath\fP
  120. XSet the user's .mailrc file, overriding the default of
  121. X\fI~user/\fP\fB.mailrc\fP.
  122. X.TP 15
  123. X\fB\-sortmailrc\fP \fIpath\fP
  124. XSet the user's .sortmailrc file, overriding the default of
  125. X\fI~user/\fP\fB.sortmailrc\fP.
  126. X
  127. X.SH SORTMAILRC FORMAT
  128. X
  129. XYour .sortmailrc file is a series of lines in the form
  130. X
  131. X    \fBset\fP \fIvariable=value\fP
  132. X
  133. Xand search patterns take the form
  134. X
  135. X    /\fIregular-expression\fP/\fImodifier\fP:\fIcommand\fP
  136. X
  137. Xwhere \fIregular-expression\fP is any \fBed(1)\fP-style regular
  138. Xexpression, \fImodifier\fP is one of \fBt, f, s, h, a\fP, and
  139. X\fIcommand\fP is one of \fBm, j, v, f\fP\ \fIfile\fP, \fB+\fP\fIfile\fP,
  140. Xor \fB|\fP\ \fIcommand\fP.
  141. X
  142. X.SH MODIFIERS
  143. X.LP
  144. XThese modifiers affect how the regular expression is applied to the
  145. Xincoming mail.  The default is 's'.
  146. X.TP 6
  147. X.B s
  148. XTest the "Subject:\ " line of the incoming mail against the regular expression.
  149. X.TP 6
  150. X.B t
  151. XTest the "To:\ ", "Cc:\ " and "Apparently-To:\ " lines of the incoming
  152. Xmail against the regular expression.
  153. X.TP 6
  154. X.B f
  155. XTest the "From:\ " line of the incoming mail against the regular expression.
  156. X.TP 6
  157. X.B h
  158. XTest the entire header of the incoming mail against the regular expression.
  159. X.TP 6
  160. X.B a
  161. XTest the entire incoming mail message against the regular expression.
  162. X
  163. X.SH COMMANDS
  164. X.TP 10
  165. X.B m
  166. XSend the message to the user's mailbox.
  167. X.TP
  168. X\fBm\fP \fIaddress\fP
  169. XForward the mail to the specified address.
  170. X.TP 10
  171. X.B j
  172. XDelete the message ("junk" it.)
  173. X.TP 10
  174. X\fBf\fP \fIfolder\fP
  175. XSave the message in the given mail folder.  \fIfolder\fP may be in
  176. Xthe formats ~/\fIpath\fP, /\fIabspath\fP, ~\fIuser/path\fP, or
  177. X+\fIname\fP.  The latter form expands to ~/\fIfolder/name\fP where
  178. X\fIfolder\fP is the value specified for the \fBfolder\fP variable
  179. X(default is "\fBfolders\fP".)
  180. X.TP 10
  181. X\fB+\fP\fIfolder\fP
  182. XShorthand for "\fBf +\fP\fIfolder\fP".
  183. X.TP 10
  184. X\fB|\fP \fIcommand\fP
  185. XPipe the mail message through the given \fIshell-command\fP.
  186. Xsh(1) is used.
  187. X
  188. X.SH VARIABLES
  189. X.LP
  190. X\fBsortmail\fP uses the following variables, which may be changed in
  191. Xyour \fB.mailrc\fP or \fB.sortmailrc\fP files.  Some variables may also
  192. Xbe set on the command line.
  193. X.TP 10
  194. X.B user
  195. XThe user on behalf of whom \fBsortmail\fP is running.  This value must
  196. Xbe specified on the command line, but may be changed later.  It is used
  197. Xto determine the user's home directory, among other things.
  198. X.TP 10
  199. X.B home
  200. XThe user's home directory.  Used to find intialization files and the
  201. Xuser's \fIfolders\fP directory.  Default is ~\fIuser\fP.
  202. X.TP 10
  203. X.B mailbox
  204. XThe user's mail box.  Default is \fB/usr/spool/mail/\fP\fIuser\fP.
  205. X.TP 10
  206. X.B mailrc
  207. XFull path of the user's \fB.mailrc\fP file.  There's no real point in
  208. Xchanging this.
  209. X.TP 10
  210. X.B sortmailrc
  211. XFull path of the user's \fB.sortmailrc\fP file.  There's no real point in
  212. Xchanging this.
  213. X.TP 10
  214. X.B mbox
  215. XFull path of the user's \fBmbox\fP file.  Not currently used by \fBsortmail\fP.
  216. X.TP 10
  217. X.B folder
  218. XThe user's \fImail folders\fP directory.  Mail folders are identified by the
  219. Xleading '+' in their name, and are stored in ~\fIuser/folder\fP/.
  220. XDefault is "\fBfolders\fP".
  221. X.TP 10
  222. X.B default
  223. XName of the file into which unclassifiable mail is sent.  The default
  224. Xis \fImailbox\fP.  Another reasonable value might be "\fB+other\fP".
  225. X.TP 10
  226. X.B vacation
  227. XIf set, mail to \fIuser\fP will also be piped through /usr/ucb/vacation.
  228. X.TP 10
  229. X.B logfilename
  230. XMessages printed with -v are sent to the specified log file.  Default is
  231. X/dev/console, or (if /dev/console cannot be opened) stderr.
  232. X
  233. X.SH EXAMPLES
  234. X.LP
  235. XHere is a sample \fB.sortmailrc\fP file:
  236. X.LP
  237. X.RS
  238. X.nf
  239. X.ft B
  240. Xset default=+other
  241. X/MAILER-DAEMON/f:+bounces
  242. X/falk/t:m
  243. X/bldg8/t:m
  244. X/joe/f:m
  245. X/scuba@sun/t:+scuba
  246. X/scuba/s:+scuba
  247. X/mwicks/f:j
  248. X/homework/t:m falk@kestrel
  249. X/jim@apple/f:| /home/falk/bin/fixjim
  250. X/^Precedence: junk/h:+other
  251. X.ft
  252. X.fi
  253. X.RE
  254. X.LP
  255. XIn this example, the folder directory and other variables have whatever
  256. Xvalues were specified in \fB.mailrc\fP.  Unclassifiable mail is sent to
  257. Xthe folder "+other".  Mail from "MAILER-DAEMON" is sent to the folder
  258. X"+bounces".  Mail to "falk" or "bldg8" or from my friend joe is sent
  259. Xdirectly to my mailbox.  Mail to the scuba club or with "scuba" in the
  260. Xsubject line is sent to the "+scuba" folder.  Mail from mwicks is
  261. Xthrown away without my ever seeing it.  Mail to the "homework" alias
  262. Xis forwarded to my account on another machine.
  263. XMail from my friend jim, who
  264. Xformats his mail in a funny way is passed through a shell script which
  265. Xcleans up his messages and appends them to my mailbox.  Mail messages
  266. Xwith "^Precedence:\ junk" anywhere in the header is filed in +other.
  267. X
  268. XNote that the patterns are applied in the order given; it is important,
  269. Xfor example, that the "MAILER-DAEMON" pattern precede the "falk" pattern
  270. Xso that mail from MAILER-DAEMON is filed in +bounces even if directed
  271. Xto me personally.  On the other hand, mail from mwicks will be placed
  272. Xin my mailbox if addressed to me personally, otherwise it will
  273. Xbe junked.
  274. X
  275. X.SH NOTES
  276. XRemember that sortmail can be executed under any userid, depending on
  277. Xwho sent the mail, and whether or not it came from the local machine.
  278. XBecause of this, you cannot depend on any user environment to be available,
  279. Xespecially environment variables and path.  All filenames and program
  280. Xnames should be specified as full paths, except that "~", "~user" and
  281. X"+folder" forms are understood.  The permissions of sortmail and every
  282. Xdirectory along its path should be such that any user can run it.
  283. X
  284. XIf you pipe incoming mail through a program, that program should not
  285. Xgenerate any output to stdout or stderr whatsoever.  If it does, that
  286. Xoutput will be sent back to the originator of the mail as if the mail
  287. Xhad bounced.
  288. X
  289. X.SH SEE ALSO
  290. Xed(1), mail(1)
  291. X.SH COPYRIGHT
  292. X Copyright (c) 1990 by Sun Microsystems, Inc.
  293. X Edward A. Falk (falk@sun.com)
  294. X
  295. XPermission to use, copy, modify, and distribute this software and its
  296. Xdocumentation for any purpose and without fee is hereby granted,
  297. Xprovided that the above copyright notice appear in all copies and that
  298. Xboth that copyright notice and this permission notice appear in
  299. Xsupporting documentation.
  300. X
  301. Xregex.[ch] is covered by the GNU copyleft.
  302. X
  303. SHAR_EOF
  304. len=`wc -c < sortmail.1`
  305. if test $len !=     7787 ; then
  306. echo error: sortmail.1 was $len bytes long, should have been     7787
  307. fi
  308. fi # end of overwriting check
  309.  
  310. if test -f sample.forward
  311. then
  312. echo shar: will not over-write existing file sample.forward
  313. else
  314. echo shar: extracting 'sample.forward',       41 characters
  315. sed 's/^X//' > sample.forward <<'SHAR_EOF'
  316. X"| /home/joeshmoe/bin/sortmail joeshmoe"
  317. SHAR_EOF
  318. len=`wc -c < sample.forward`
  319. if test $len !=       41 ; then
  320. echo error: sample.forward was $len bytes long, should have been       41
  321. fi
  322. fi # end of overwriting check
  323.  
  324. if test -f sample.sortmailrc
  325. then
  326. echo shar: will not over-write existing file sample.sortmailrc
  327. else
  328. echo shar: extracting 'sample.sortmailrc',     1067 characters
  329. sed 's/^X//' > sample.sortmailrc <<'SHAR_EOF'
  330. X# This is a sample .sortmailrc file.
  331. X#
  332. X# The destination for unclassifiable mail is the +other folder.
  333. X# The directory containg the folders is Mail
  334. X# vacation mode is not currently enabled
  335. X#
  336. X# all mail from Mailer-Daemon goes to the +bounces folder, otherwise
  337. X# all mail to me (joeshmoe) or to anybody in mail building, or from
  338. X# my boss fred goes directly to me.
  339. X# all mail from mwicks gets ignored.
  340. X# all mail from my friend jim who never formats his mail goes through
  341. X# my "fixjim" filter.
  342. X# all mail to the scuba club or with "scuba" in the subject goes into
  343. X# my +scuba folder.
  344. X# all mail to the testing alias is forwarded to my my account on another machine
  345. X# all mail with "Precedence: junk" in the header goes to +other.
  346. X# all unclassified mail goes to +other.
  347. X#
  348. Xset default=+other
  349. Xset folder='Mail'
  350. X#set vacation
  351. X/Mailer-Daemon/f:+bounces
  352. X/MAILER-DAEMON/f:+bounces
  353. X/joeshmoe/t:m
  354. X/Joeshmoe/t:m
  355. X/bldg18/t:m
  356. X/fred/f:m
  357. X/mwicks/f:j
  358. X/jim@apple/f:| /home/joeshmoe/bin/fixjim
  359. X/scuba@sun/t:+scuba
  360. X/scuba/s:+scuba
  361. X/testing/t:m joeshmoe@lab
  362. X/^Precedence: junk/h:+other
  363. SHAR_EOF
  364. len=`wc -c < sample.sortmailrc`
  365. if test $len !=     1067 ; then
  366. echo error: sample.sortmailrc was $len bytes long, should have been     1067
  367. fi
  368. fi # end of overwriting check
  369.  
  370. if test -f Makefile
  371. then
  372. echo shar: will not over-write existing file Makefile
  373. else
  374. echo shar: extracting 'Makefile',      460 characters
  375. sed 's/^X//' > Makefile <<'SHAR_EOF'
  376. X
  377. X#DBG = -g -DDEBUG
  378. XDBG = -O
  379. X
  380. X# SunOS 4.x
  381. X#CFLAGS = ${DBG}
  382. X#LDFLAGS = -n -Bdynamic -s
  383. X
  384. X# SunOS 5.x
  385. XCFLAGS = ${DBG} -DSVr4
  386. XLDFLAGS =
  387. X
  388. X#CC = gcc
  389. X
  390. XSRCS = sortmail.c parse.c regex.c
  391. X
  392. XHDRS = sortmail.h regex.h
  393. X
  394. XOBJS = $(SRCS:.c=.o)
  395. X
  396. XDOC = sortmail.1 sample.forward sample.sortmailrc
  397. X
  398. Xsortmail: $(OBJS)
  399. X    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIB)
  400. X
  401. Xarchive: Makefile $(HDRS) $(SRCS) $(DOC)
  402. X    shar $(DOC) Makefile $(HDRS) $(SRCS) > archive
  403. X
  404. Xclean:
  405. X    -rm *.o archive
  406. SHAR_EOF
  407. len=`wc -c < Makefile`
  408. if test $len !=      460 ; then
  409. echo error: Makefile was $len bytes long, should have been      460
  410. fi
  411. fi # end of overwriting check
  412.  
  413. if test -f sortmail.h
  414. then
  415. echo shar: will not over-write existing file sortmail.h
  416. else
  417. echo shar: extracting 'sortmail.h',     1038 characters
  418. sed 's/^X//' > sortmail.h <<'SHAR_EOF'
  419. X
  420. X
  421. X    /* sortmail variables */
  422. X
  423. Xextern    char    *user ;        /* userid */
  424. Xextern    char    *home ;        /* user's $HOME */
  425. Xextern    char    *mailbox ;    /* $MAIL, default = /var/spool/mail/$USER */
  426. Xextern    char    *mailrc ;    /* $MAILRC, default = $HOME/.mailrc */
  427. Xextern    char    *sortmailrc ;    /* initfile, default = $HOME/.sortmailrc */
  428. Xextern    char    *mbox ;        /* MBOX, default = $HOME/mbox */
  429. Xextern    char    *deflt ;    /* where unclasifiable mail goes */
  430. Xextern    char    *folder ;    /* folder, default = $HOME/folders */
  431. Xextern    char    *vacation ;    /* pipe through vacation(1) */
  432. Xextern    int    verbose ;
  433. Xextern    char    *logfilename ;
  434. Xextern    FILE    *logfile ;
  435. X
  436. X#define    SPOOLDIR    "/usr/spool/mail/"
  437. X#define    MBOX        "mbox"
  438. X#define    FOLDER        "folders"
  439. X
  440. Xtypedef    struct patinfo {
  441. X      struct patinfo *next ;
  442. X      char    *pattern ;    /* pattern to match */
  443. X      enum {P_SUBJECT, P_TO, P_FROM, P_HEADER, P_ALL} flags ;
  444. X      enum {C_MAIL, C_FILE, C_PIPE, C_JUNK} command ;
  445. X      char    *dest ;        /* destination, if any */
  446. X    } PatInfo ;
  447. X
  448. Xextern    PatInfo    *patterns, *lastpat ;
  449. X
  450. X
  451. X#define    strmatch(a,b)    (!strncmp((a),(b),sizeof(b)-1))
  452. X
  453. SHAR_EOF
  454. len=`wc -c < sortmail.h`
  455. if test $len !=     1038 ; then
  456. echo error: sortmail.h was $len bytes long, should have been     1038
  457. fi
  458. fi # end of overwriting check
  459.  
  460. if test -f regex.h
  461. then
  462. echo shar: will not over-write existing file regex.h
  463. else
  464. echo shar: extracting 'regex.h',     8080 characters
  465. sed 's/^X//' > regex.h <<'SHAR_EOF'
  466. X/* Definitions for data structures callers pass the regex library.
  467. X   Copyright (C) 1985 Free Software Foundation, Inc.
  468. X
  469. X    This program is free software; you can redistribute it and/or modify
  470. X    it under the terms of the GNU General Public License as published by
  471. X    the Free Software Foundation; either version 1, or (at your option)
  472. X    any later version.
  473. X
  474. X    This program is distributed in the hope that it will be useful,
  475. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  476. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  477. X    GNU General Public License for more details.
  478. X
  479. X    You should have received a copy of the GNU General Public License
  480. X    along with this program; if not, write to the Free Software
  481. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  482. X
  483. XIn other words, you are welcome to use, share and improve this program.
  484. XYou are forbidden to forbid anyone else to use, share and improve
  485. Xwhat you give them.   Help stamp out software-hoarding!  */
  486. X
  487. X
  488. X/* Define number of parens for which we record the beginnings and ends.
  489. X   This affects how much space the `struct re_registers' type takes up.  */
  490. X#ifndef RE_NREGS
  491. X#define RE_NREGS 10
  492. X#endif
  493. X
  494. X/* These bits are used in the obscure_syntax variable to choose among
  495. X   alternative regexp syntaxes.  */
  496. X
  497. X/* 1 means plain parentheses serve as grouping, and backslash
  498. X     parentheses are needed for literal searching.
  499. X   0 means backslash-parentheses are grouping, and plain parentheses
  500. X     are for literal searching.  */
  501. X#define RE_NO_BK_PARENS 1
  502. X
  503. X/* 1 means plain | serves as the "or"-operator, and \| is a literal.
  504. X   0 means \| serves as the "or"-operator, and | is a literal.  */
  505. X#define RE_NO_BK_VBAR 2
  506. X
  507. X/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
  508. X   1 means \+, \? are operators and plain +, ? are literals.  */
  509. X#define RE_BK_PLUS_QM 4
  510. X
  511. X/* 1 means | binds tighter than ^ or $.
  512. X   0 means the contrary.  */
  513. X#define RE_TIGHT_VBAR 8
  514. X
  515. X/* 1 means treat \n as an _OR operator
  516. X   0 means treat it as a normal character */
  517. X#define RE_NEWLINE_OR 16
  518. X
  519. X/* 0 means that a special characters (such as *, ^, and $) always have
  520. X     their special meaning regardless of the surrounding context.
  521. X   1 means that special characters may act as normal characters in some
  522. X     contexts.  Specifically, this applies to:
  523. X    ^ - only special at the beginning, or after ( or |
  524. X    $ - only special at the end, or before ) or |
  525. X    *, +, ? - only special when not after the beginning, (, or | */
  526. X#define RE_CONTEXT_INDEP_OPS 32
  527. X
  528. X/* Now define combinations of bits for the standard possibilities.  */
  529. X#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
  530. X#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR)
  531. X#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR)
  532. X#define RE_SYNTAX_EMACS 0
  533. X
  534. X/* This data structure is used to represent a compiled pattern. */
  535. X
  536. Xstruct re_pattern_buffer
  537. X  {
  538. X    char *buffer;    /* Space holding the compiled pattern commands. */
  539. X    int allocated;    /* Size of space that  buffer  points to */
  540. X    int used;        /* Length of portion of buffer actually occupied */
  541. X    char *fastmap;    /* Pointer to fastmap, if any, or zero if none. */
  542. X            /* re_search uses the fastmap, if there is one,
  543. X               to skip quickly over totally implausible characters */
  544. X    char *translate;    /* Translate table to apply to all characters before comparing.
  545. X               Or zero for no translation.
  546. X               The translation is applied to a pattern when it is compiled
  547. X               and to data when it is matched. */
  548. X    char fastmap_accurate;
  549. X            /* Set to zero when a new pattern is stored,
  550. X               set to one when the fastmap is updated from it. */
  551. X    char can_be_null;   /* Set to one by compiling fastmap
  552. X               if this pattern might match the null string.
  553. X               It does not necessarily match the null string
  554. X               in that case, but if this is zero, it cannot.
  555. X               2 as value means can match null string
  556. X               but at end of range or before a character
  557. X               listed in the fastmap.  */
  558. X  };
  559. X
  560. X/* Structure to store "register" contents data in.
  561. X
  562. X   Pass the address of such a structure as an argument to re_match, etc.,
  563. X   if you want this information back.
  564. X
  565. X   start[i] and end[i] record the string matched by \( ... \) grouping i,
  566. X   for i from 1 to RE_NREGS - 1.
  567. X   start[0] and end[0] record the entire string matched. */
  568. X
  569. Xstruct re_registers
  570. X  {
  571. X    int start[RE_NREGS];
  572. X    int end[RE_NREGS];
  573. X  };
  574. X
  575. X/* These are the command codes that appear in compiled regular expressions, one per byte.
  576. X  Some command codes are followed by argument bytes.
  577. X  A command code can specify any interpretation whatever for its arguments.
  578. X  Zero-bytes may appear in the compiled regular expression. */
  579. X
  580. Xenum regexpcode
  581. X  {
  582. X    unused,
  583. X    exactn,    /* followed by one byte giving n, and then by n literal bytes */
  584. X    begline,   /* fails unless at beginning of line */
  585. X    endline,   /* fails unless at end of line */
  586. X    jump,     /* followed by two bytes giving relative address to jump to */
  587. X    on_failure_jump,     /* followed by two bytes giving relative address of place
  588. X                    to resume at in case of failure. */
  589. X    finalize_jump,     /* Throw away latest failure point and then jump to address. */
  590. X    maybe_finalize_jump, /* Like jump but finalize if safe to do so.
  591. X                This is used to jump back to the beginning
  592. X                of a repeat.  If the command that follows
  593. X                this jump is clearly incompatible with the
  594. X                one at the beginning of the repeat, such that
  595. X                we can be sure that there is no use backtracking
  596. X                out of repetitions already completed,
  597. X                then we finalize. */
  598. X    dummy_failure_jump,  /* jump, and push a dummy failure point.
  599. X                This failure point will be thrown away
  600. X                if an attempt is made to use it for a failure.
  601. X                A + construct makes this before the first repeat.  */
  602. X    anychar,     /* matches any one character */
  603. X    charset,     /* matches any one char belonging to specified set.
  604. X            First following byte is # bitmap bytes.
  605. X            Then come bytes for a bit-map saying which chars are in.
  606. X            Bits in each byte are ordered low-bit-first.
  607. X            A character is in the set if its bit is 1.
  608. X            A character too large to have a bit in the map
  609. X            is automatically not in the set */
  610. X    charset_not, /* similar but match any character that is NOT one of those specified */
  611. X    start_memory, /* starts remembering the text that is matched
  612. X            and stores it in a memory register.
  613. X            followed by one byte containing the register number.
  614. X            Register numbers must be in the range 0 through NREGS. */
  615. X    stop_memory, /* stops remembering the text that is matched
  616. X            and stores it in a memory register.
  617. X            followed by one byte containing the register number.
  618. X            Register numbers must be in the range 0 through NREGS. */
  619. X    duplicate,    /* match a duplicate of something remembered.
  620. X            Followed by one byte containing the index of the memory register. */
  621. X    before_dot,     /* Succeeds if before dot */
  622. X    at_dot,     /* Succeeds if at dot */
  623. X    after_dot,     /* Succeeds if after dot */
  624. X    begbuf,      /* Succeeds if at beginning of buffer */
  625. X    endbuf,      /* Succeeds if at end of buffer */
  626. X    wordchar,    /* Matches any word-constituent character */
  627. X    notwordchar, /* Matches any char that is not a word-constituent */
  628. X    wordbeg,     /* Succeeds if at word beginning */
  629. X    wordend,     /* Succeeds if at word end */
  630. X    wordbound,   /* Succeeds if at a word boundary */
  631. X    notwordbound, /* Succeeds if not at a word boundary */
  632. X    syntaxspec,  /* Matches any character whose syntax is specified.
  633. X            followed by a byte which contains a syntax code, Sword or such like */
  634. X    notsyntaxspec /* Matches any character whose syntax differs from the specified. */
  635. X  };
  636. X
  637. Xextern char *re_compile_pattern ();
  638. X/* Is this really advertised? */
  639. Xextern void re_compile_fastmap ();
  640. Xextern int re_search (), re_search_2 ();
  641. Xextern int re_match (), re_match_2 ();
  642. X
  643. X/* 4.2 bsd compatibility (yuck) */
  644. Xextern char *re_comp ();
  645. Xextern int re_exec ();
  646. X
  647. X#ifdef SYNTAX_TABLE
  648. Xextern char *re_syntax_table;
  649. X#endif
  650. SHAR_EOF
  651. len=`wc -c < regex.h`
  652. if test $len !=     8080 ; then
  653. echo error: regex.h was $len bytes long, should have been     8080
  654. fi
  655. fi # end of overwriting check
  656.  
  657. if test -f sortmail.c
  658. then
  659. echo shar: will not over-write existing file sortmail.c
  660. else
  661. echo shar: extracting 'sortmail.c',     6369 characters
  662. sed 's/^X//' > sortmail.c <<'SHAR_EOF'
  663. X
  664. X
  665. X#include <stdio.h>
  666. X#include <varargs.h>
  667. X#include <errno.h>
  668. X#include <alloca.h>
  669. X#include <sys/param.h>        /* defines MAXPATHLEN */
  670. X
  671. X#include "sortmail.h"
  672. X#include "regex.h"    /* use gnu regex */
  673. X
  674. X    FILE    *logfile ;
  675. X
  676. Xstatic    int
  677. XReCompile(pat)
  678. X  char *pat ;
  679. X{
  680. X  char *err ;
  681. X  if( (err = re_comp(pat)) != NULL ) {
  682. X    fprintf(logfile, "sortmail: pattern %s: %s\n", pat, err) ;
  683. X    return 1 ;
  684. X  }
  685. X  return 0 ;
  686. X}
  687. X
  688. Xextern    int    sys_nerr ;
  689. Xextern    char    *sys_errlist[] ;
  690. X
  691. X
  692. X
  693. X    char    *user = NULL ;
  694. X    char    *home = NULL ;
  695. X    char    *mailbox = NULL ;
  696. X    char    *mailrc = NULL ;
  697. X    char    *sortmailrc = NULL ;
  698. X    char    *mbox = NULL ;
  699. X    char    *deflt = NULL ;
  700. X    char    *vacation = NULL ;
  701. X    char    *folder = NULL ;
  702. X    char    *logfilename = NULL ;
  703. X    int    verbose = 0 ;
  704. X
  705. X    PatInfo    *patterns = NULL, *lastpat = NULL ;
  706. X
  707. Xstatic    char    tmpfilename[256] ;
  708. X
  709. Xstatic    void    dispose() ;
  710. Xstatic    void    append() ;
  711. Xstatic    void    put_pipe() ;
  712. Xstatic    void    forward() ;
  713. X
  714. Xstatic int
  715. Xargcheck(str, argv, nargs, argc)
  716. X    char    *str, *argv ;
  717. X    int    nargs ;
  718. X    int    *argc ;
  719. X{
  720. X    if( strcmp(str, argv) != 0 )
  721. X      return 0 ;
  722. X    if( (*argc -= nargs) <= 0 )
  723. X      die("sortmail: %s option requires %d arguments\n", str, nargs) ;
  724. X    return 1 ;
  725. X}
  726. X
  727. X
  728. X
  729. Xmain(argc,argv)
  730. X    int    argc ;
  731. X    char    **argv ;
  732. X{
  733. X    FILE    *tmpfile ;
  734. X    char    line[1024] ;
  735. X    int    n ;
  736. X    int    header ;
  737. X    PatInfo    *pat ;
  738. X    char    *err ;
  739. X    int    firstline ;
  740. X    int    cont = 0 ;
  741. X    int    foundit = 0 ;
  742. X
  743. X    logfile = fopen("/dev/console","w") ;
  744. X    if( logfile == NULL )
  745. X      logfile = stderr ;
  746. X
  747. X    while( --argc > 0 )
  748. X    {
  749. X      ++argv ;
  750. X      if( argcheck("-v", *argv, 0, &argc) )
  751. X        ++verbose ;
  752. X      else if( argcheck("-home", *argv, 1, &argc) )
  753. X        home = *++argv ;
  754. X      else if( argcheck("-mailbox", *argv, 1, &argc) )
  755. X        mailbox = *++argv ;
  756. X      else if( argcheck("-mailrc", *argv, 1, &argc) )
  757. X        mailrc = *++argv ;
  758. X      else if( argcheck("-sortmailrc", *argv, 1, &argc) )
  759. X        sortmailrc = *++argv ;
  760. X      else
  761. X        user = *argv ;
  762. X    }
  763. X
  764. X#ifdef    DEBUG
  765. X    verbose = 1 ;
  766. X#endif    /* DEBUG */
  767. X
  768. X    read_initfiles() ;
  769. X
  770. X    sprintf(tmpfilename, "/tmp/sortmail%d", getpid()) ;
  771. X    if( (tmpfile = fopen(tmpfilename, "w+")) == NULL )
  772. X    {
  773. X      fprintf(stderr, "sortmail: can't open %s, mail to %s may be lost\n",
  774. X        tmpfile, user) ;
  775. X      fprintf(logfile, "sortmail: can't open %s, %s\n",
  776. X        tmpfile, sys_errlist[errno]) ;
  777. X      append(stdin, mailbox) ;        /* try to rescue situtation */
  778. X      exit(1) ;
  779. X    }
  780. X
  781. X    firstline = 1 ;
  782. X    while( fgets(line, sizeof(line), stdin) != NULL ) {
  783. X      if( !firstline && strmatch(line, "From ") )
  784. X        putc('>', tmpfile) ;
  785. X      fputs(line, tmpfile) ;
  786. X      firstline = 0 ;
  787. X    }
  788. X#ifdef    DEBUG
  789. X    fprintf(logfile, "got a message in %s\n", tmpfilename) ;
  790. X#endif    /* DEBUG */
  791. X
  792. X    for( pat = patterns; pat != NULL && !foundit ; pat = pat->next )
  793. X    {
  794. X      if( !ReCompile(pat->pattern) )
  795. X      {
  796. X        rewind(tmpfile) ;
  797. X        while( fgets(line, sizeof(line), tmpfile) != NULL ) {
  798. X          if( line[0] == '\n'  &&  pat->flags != P_ALL )
  799. X        break ;
  800. X          if( pat->flags == P_HEADER  ||
  801. X          pat->flags == P_SUBJECT && strmatch(line, "Subject: ") ||
  802. X          pat->flags == P_FROM && strmatch(line, "From: ") ||
  803. X          pat->flags == P_TO &&
  804. X            (strmatch(line, "To: ") || strmatch(line, "Cc: ") ||
  805. X            strmatch(line, "Apparently-To: ") ) ||
  806. X          isspace(line[0]) && cont ||
  807. X          pat->flags == P_ALL )
  808. X          {
  809. X        if( re_exec(line) )
  810. X        {
  811. X          dispose(pat,tmpfile) ;
  812. X          foundit = 1 ;
  813. X          break ;
  814. X        }
  815. X        else
  816. X          /* if next line is a continuation line, test it too */
  817. X          cont = 1 ;
  818. X          }
  819. X          else
  820. X        cont = 0 ;
  821. X        }
  822. X      }
  823. X    }
  824. X
  825. X    if( vacation != NULL )
  826. X    {
  827. X      rewind(tmpfile) ;
  828. X      if( !ReCompile(user) )
  829. X      {
  830. X        while( fgets(line, sizeof(line), tmpfile) != NULL ) {
  831. X          if( line[0] == '\n' )
  832. X        break ;
  833. X          if( strmatch(line, "To: ") || strmatch(line, "Cc: ") ||
  834. X            strmatch(line, "Apparently-To: ") )
  835. X          {
  836. X        if( re_exec(line) )
  837. X        {
  838. X          sprintf(line, "/usr/ucb/vacation %s", user) ;
  839. X          put_pipe(tmpfile, line) ;
  840. X          if( verbose )
  841. X            fprintf(logfile, "message piped through %s\n", line) ;
  842. X          break ;
  843. X        }
  844. X          }
  845. X        }
  846. X      }
  847. X    }
  848. X
  849. X    unlink(tmpfilename) ;
  850. X
  851. X    if( !foundit )
  852. X      append(tmpfile, deflt != NULL ? deflt : mailbox) ;
  853. X    exit(0) ;
  854. X}
  855. X
  856. X
  857. X/*VARARGS0*/
  858. Xdie(va_alist)
  859. X    va_dcl
  860. X{
  861. X    va_list    args ;
  862. X    char    *fmt ;
  863. X
  864. X    va_start(args) ;
  865. X    fprintf(logfile, "sortmail: ") ;
  866. X    fmt = va_arg(args, char *);
  867. X    vfprintf(logfile, fmt, args);
  868. X    va_end(args) ;
  869. X    exit(1) ;
  870. X}
  871. X
  872. X
  873. X    /* This function deals with the file described by 'file' in
  874. X     * the manner described by "pat".
  875. X     */
  876. X
  877. Xstatic    void
  878. Xdispose(pat, file)
  879. Xregister PatInfo *pat ;
  880. Xregister FILE    *file ;
  881. X{
  882. X    char    outfile[MAXPATHLEN] ;
  883. X    char    *ptr ;
  884. X    struct passwd    *passwd ;
  885. X
  886. X    switch( pat->command ) {
  887. X      case C_MAIL:        /* append to user's mail file */
  888. X        if( pat->dest == NULL || pat->dest[0] == '\0' )
  889. X          append(file, mailbox) ;
  890. X        else
  891. X          forward(file, pat->dest) ;
  892. X        break ;
  893. X
  894. X      case C_FILE:        /* append to named file. */
  895. X        append(file, pat->dest) ;
  896. X        break ;
  897. X
  898. X      case C_PIPE:        /* pipe through named command */
  899. X        put_pipe(file, pat->dest) ;
  900. X        if( verbose )
  901. X          fprintf(logfile, "message piped through %s\n", pat->dest) ;
  902. X        break ;
  903. X
  904. X      case C_JUNK:        /* throw it away */
  905. X        if( verbose )
  906. X          fprintf(logfile, "message deleted\n") ;
  907. X        break ;
  908. X    }
  909. X}
  910. X
  911. X
  912. Xstatic    void
  913. Xappend(file, outfile)
  914. X    FILE    *file ;
  915. X    char    *outfile ;
  916. X{
  917. X    FILE    *ofile ;
  918. X    char    line[1024] ;
  919. X    int    i ;
  920. X
  921. X    filename_expand(line, outfile) ;
  922. X    if( verbose )
  923. X      fprintf(logfile, "message filed to %s\n", line) ;
  924. X
  925. X    rewind(file) ;
  926. X
  927. X    if( (ofile = fopen(line, "a")) == NULL )
  928. X    {
  929. X      fprintf(logfile, "sortmail: can't open %s, %s\n",
  930. X        line,sys_errlist[errno]);
  931. X      if( strcmp(outfile, mailbox) == 0 )
  932. X        fprintf(stderr,
  933. X          "sortmail: Cannot open %s, %s.  Mail to %s may be lost\n",
  934. X        mailbox, sys_errlist[errno], user) ;
  935. X      else
  936. X        append(file, mailbox) ;
  937. X    }
  938. X    else
  939. X    {
  940. X      while( fgets(line, sizeof(line), file) != NULL )
  941. X        fputs(line, ofile) ;
  942. X      fputs("\n", ofile) ;
  943. X      fclose(ofile) ;
  944. X    }
  945. X}
  946. X
  947. X
  948. Xstatic    void
  949. Xput_pipe(file, dest)
  950. X    FILE    *file ;
  951. X    char    *dest ;
  952. X{
  953. X    FILE    *ofile ;
  954. X    char    line[1024] ;
  955. X
  956. X    if( (ofile = popen(dest, "w")) == NULL )
  957. X    {
  958. X      fprintf(logfile, "sortmail: cannot open pipe to command %s\n",
  959. X        dest ) ;
  960. X      append(file, mailbox) ;
  961. X    }
  962. X    else
  963. X    {
  964. X      rewind(file) ;
  965. X      while( fgets(line, sizeof(line), file) != NULL )
  966. X        fputs(line, ofile) ;
  967. X      pclose(ofile) ;
  968. X    }
  969. X}
  970. X
  971. X
  972. Xstatic    void
  973. Xforward(file, dest)
  974. X    FILE    *file ;
  975. X    char    *dest ;
  976. X{
  977. X    char    cmd[1024] ;
  978. X
  979. X    sprintf(cmd, "/usr/lib/sendmail %s", dest) ;
  980. X    put_pipe(file, cmd) ;
  981. X    if( verbose )
  982. X      fprintf(logfile, "message mailed to %s\n", dest) ;
  983. X}
  984. SHAR_EOF
  985. len=`wc -c < sortmail.c`
  986. if test $len !=     6369 ; then
  987. echo error: sortmail.c was $len bytes long, should have been     6369
  988. fi
  989. fi # end of overwriting check
  990.  
  991. if test -f parse.c
  992. then
  993. echo shar: will not over-write existing file parse.c
  994. else
  995. echo shar: extracting 'parse.c',     7864 characters
  996. sed 's/^X//' > parse.c <<'SHAR_EOF'
  997. X
  998. X
  999. X#include <stdio.h>
  1000. X#include <stdlib.h>    /* defines getenv(3) */
  1001. X#include <pwd.h>
  1002. X#include <ctype.h>
  1003. X#include <string.h>
  1004. X#include <sys/param.h>
  1005. X
  1006. X#include "sortmail.h"
  1007. X
  1008. X#define    MAXLINE    256
  1009. X
  1010. X#ifdef    DEBUG
  1011. X#define    register
  1012. X#endif
  1013. X
  1014. Xstatic    char    spooldir[] = SPOOLDIR ;
  1015. X
  1016. Xstatic    void    read_initfile() ;
  1017. Xstatic    void    parse_var() ;
  1018. Xstatic    void    set_var() ;
  1019. Xstatic    void    add_pat() ;
  1020. Xstatic    void    get_dest() ;
  1021. X
  1022. X#define    NN(str)    ((str)==NULL ? "-none-" : (str))
  1023. X
  1024. Xread_initfiles()
  1025. X{
  1026. X    struct passwd    *passwd ;
  1027. X
  1028. X    /* first, try to set up some of the defaults */
  1029. X
  1030. X    if( user == NULL ) {
  1031. X      if( (user = (char *) malloc(L_cuserid)) == NULL )
  1032. X        die("out of memory") ;
  1033. X      if( cuserid(user) == NULL )
  1034. X        die("can't determine username") ;
  1035. X    }
  1036. X
  1037. X    if( home == NULL ) {
  1038. X      if( (passwd = getpwnam(user)) != NULL )
  1039. X        home = strdup(passwd->pw_dir) ;
  1040. X      else if( (home = getenv("HOME")) == NULL )
  1041. X        die("can't determine %s's directory",user) ;
  1042. X    }
  1043. X
  1044. X    if( mailbox == NULL ) {
  1045. X      mailbox = (char *) malloc(sizeof(spooldir) + strlen(user)) ;
  1046. X      strcpy(mailbox, spooldir) ;
  1047. X      strcat(mailbox, user) ;
  1048. X    }
  1049. X
  1050. X    if( mailrc == NULL ) {
  1051. X      mailrc = (char *) malloc(strlen(home) + sizeof("/.mailrc") ) ;
  1052. X      strcpy(mailrc, home) ;
  1053. X      strcat(mailrc, "/.mailrc") ;
  1054. X    }
  1055. X
  1056. X    if( sortmailrc == NULL ) {
  1057. X      sortmailrc = (char *) malloc(strlen(home) + sizeof("/.sortmailrc") ) ;
  1058. X      strcpy(sortmailrc, home) ;
  1059. X      strcat(sortmailrc, "/.sortmailrc") ;
  1060. X    }
  1061. X
  1062. X    if( mbox == NULL )
  1063. X      mbox = MBOX ;
  1064. X
  1065. X    if( folder == NULL )
  1066. X      folder = FOLDER ;
  1067. X
  1068. X    read_initfile(mailrc) ;
  1069. X    read_initfile(sortmailrc) ;
  1070. X    if( verbose >= 2 ) {
  1071. X      fprintf(logfile,"$USER = %s\n", NN(user)) ;
  1072. X      fprintf(logfile,"$HOME = %s\n", NN(home)) ;
  1073. X      fprintf(logfile,"mailbox = %s\n", NN(mailbox)) ;
  1074. X      fprintf(logfile,"mailrc = %s\n", NN(mailrc)) ;
  1075. X      fprintf(logfile,"sortmailrc = %s\n", NN(sortmailrc)) ;
  1076. X      fprintf(logfile,"mbox = %s\n", NN(mbox)) ;
  1077. X      fprintf(logfile,"deflt = %s\n", NN(deflt)) ;
  1078. X      fprintf(logfile,"vacation = %s\n", NN(vacation)) ;
  1079. X      fprintf(logfile,"folder = %s\n", NN(folder)) ;
  1080. X    }
  1081. X}
  1082. X
  1083. X
  1084. Xstatic    void
  1085. Xread_initfile(file)
  1086. X    char    *file ;
  1087. X{
  1088. Xregister FILE    *ifile ;
  1089. X    char    line[MAXLINE] ;
  1090. Xregister char    *ptr ;
  1091. X
  1092. X    if( (ifile = fopen(file, "r")) != NULL ) {
  1093. X      while( fgets(line, MAXLINE, ifile) != NULL ) {
  1094. X        if( line[0] != '#' )
  1095. X        {
  1096. X          for( ptr = line; isspace(*ptr); ++ptr );
  1097. X
  1098. X          if( strmatch(ptr,"set") )    /* variable */
  1099. X        parse_var(ptr) ;
  1100. X          else if( *ptr == '/' )    /* pattern */
  1101. X        add_pat(ptr) ;
  1102. X          /* else ignore it */
  1103. X        }
  1104. X      }
  1105. X      fclose(ifile) ;
  1106. X    }
  1107. X}
  1108. X
  1109. X
  1110. Xstatic    void
  1111. Xparse_var(ptr)
  1112. Xregister char    *ptr ;
  1113. X{
  1114. X    ptr += 3 ;    /* skip "set" */
  1115. X    if( !isspace(*ptr) )
  1116. X      return ;        /* something was wrong */
  1117. X    
  1118. X    for(; isspace(*ptr); ++ptr );
  1119. X
  1120. X    if( strmatch(ptr,"user") )
  1121. X      set_var(&user, ptr+4) ;
  1122. X    else if( strmatch(ptr,"home") )
  1123. X      set_var(&home, ptr+4) ;
  1124. X    else if( strmatch(ptr,"mailbox") )
  1125. X      set_var(&mailbox, ptr+7) ;
  1126. X    else if( strmatch(ptr,"mailrc") )
  1127. X      set_var(&mailrc, ptr+6) ;
  1128. X    else if( strmatch(ptr,"sortmailrc") )
  1129. X      set_var(&sortmailrc, ptr+10) ;
  1130. X    else if( strmatch(ptr,"mbox") )
  1131. X      set_var(&mbox, ptr+4) ;
  1132. X    else if( strmatch(ptr,"folder") )
  1133. X      set_var(&folder, ptr+6) ;
  1134. X    else if( strmatch(ptr,"default") )
  1135. X      set_var(&deflt, ptr+7) ;
  1136. X    else if( strmatch(ptr,"vacation") )
  1137. X      set_var(&vacation, ptr+8) ;
  1138. X    else if( strmatch(ptr,"logfile") ) {
  1139. X      set_var(&logfilename, ptr+7) ;
  1140. X      if( (logfile = fopen(logfilename, "a")) == NULL )
  1141. X        logfile = stderr ;
  1142. X    }
  1143. X    /* else ignore it */
  1144. X}
  1145. X
  1146. Xstatic    void
  1147. Xset_var(var, ptr)
  1148. Xregister char    **var ;
  1149. Xregister char    *ptr ;
  1150. X{
  1151. X    for(; isspace(*ptr); ++ptr );    /* consume blanks before '=' */
  1152. X
  1153. X    if( *ptr != '=' )
  1154. X    {
  1155. X      *var = "" ;
  1156. X      return ;
  1157. X    }
  1158. X
  1159. X    for(++ptr; isspace(*ptr); ++ptr ); /* consume blanks after '=' */
  1160. X
  1161. X    if( *ptr == '\'' ) {
  1162. X      ++ptr ;
  1163. X      *var = strdup(ptr) ;
  1164. X      for(ptr=*var; *ptr != '\'' && *ptr != '\n' && *ptr != '\0'; ++ptr);
  1165. X      *ptr = '\0' ;
  1166. X    }
  1167. X
  1168. X    else if( *ptr == '"' ) {
  1169. X      ++ptr ;
  1170. X      *var = strdup(ptr) ;
  1171. X      for(ptr=*var; *ptr != '"' && *ptr != '\n' && *ptr != '\0'; ++ptr);
  1172. X      *ptr = '\0' ;
  1173. X    }
  1174. X
  1175. X    else {
  1176. X      *var = strdup(ptr) ;
  1177. X      for(ptr=*var; *ptr != '\n' && *ptr != '\0'; ++ptr);
  1178. X      *ptr = '\0' ;
  1179. X    }
  1180. X}
  1181. X
  1182. X
  1183. X
  1184. X    /* try to make sense out of patterns in the form
  1185. X        /regular expression/modifs:command
  1186. X    */
  1187. X
  1188. Xstatic    void
  1189. Xadd_pat(ptr)
  1190. Xregister char    *ptr ;
  1191. X{
  1192. X    char    buffer[1024] ;        /* KLUDGE! should be unlimited */
  1193. Xregister char    *optr = buffer ;
  1194. Xregister PatInfo *pat ;
  1195. Xregister int    done, done2 ;
  1196. X
  1197. X    ++ptr ;                /* skip leading '/' */
  1198. X
  1199. X    for(done=0;!done;)
  1200. X      switch( *ptr ) {
  1201. X        case '\0':
  1202. X          fprintf(logfile, "sortmail: missing '/' in pattern\n") ;
  1203. X          return ;
  1204. X        case '\\':            /* '\' quotes anything */
  1205. X          *optr++ = *ptr++ ;
  1206. X          *optr++ = *ptr++ ;
  1207. X          break ;
  1208. X        case '/':            /* '/' terminates */
  1209. X          ++ptr ;
  1210. X          done = 1 ;
  1211. X          break ;
  1212. X        case '[':            /* '[' starts a set */
  1213. X          *optr++ = *ptr++ ;
  1214. X          for(done2=0; !done2;)
  1215. X        switch(*ptr) {
  1216. X          case '\0':        /* premature EOS, reject */
  1217. X            fprintf(logfile, "sortmail: missing ']' in pattern\n") ;
  1218. X            return ;
  1219. X          case ']':        /* ']' terminates a set */
  1220. X            done2=1 ;
  1221. X            *optr++ = *ptr++ ;
  1222. X            break ;
  1223. X          default:
  1224. X            *optr++ = *ptr++ ;
  1225. X            break ;
  1226. X        }
  1227. X          break ;
  1228. X        default:
  1229. X          *optr++ = *ptr++ ;
  1230. X      }
  1231. X    *optr++ = '\0' ;
  1232. X
  1233. X    pat = (PatInfo *) malloc(sizeof(PatInfo)) ;
  1234. X    pat->next = NULL ;
  1235. X    if( patterns == NULL )
  1236. X      patterns = pat ;
  1237. X    else
  1238. X      lastpat->next = pat ;
  1239. X    lastpat = pat ;
  1240. X
  1241. X    pat->pattern = strdup(buffer) ;
  1242. X    pat->flags = P_SUBJECT ;
  1243. X    pat->command = C_MAIL ;
  1244. X    pat->dest = NULL ;
  1245. X
  1246. X    /* parse modifiers part */
  1247. X
  1248. X    for(done=0;!done;)
  1249. X      switch( *ptr ) {
  1250. X        case '\0': done = 1 ; break ;
  1251. X        case ':': ++ptr ; done = 1 ; break ;
  1252. X        case 't': pat->flags = P_TO ; ++ptr ; break ;
  1253. X        case 'f': pat->flags = P_FROM ; ++ptr ; break ;
  1254. X        case 's': pat->flags = P_SUBJECT ; ++ptr ; break ;
  1255. X        case 'h': pat->flags = P_HEADER ; ++ptr ; break ;
  1256. X        case 'a': pat->flags = P_ALL ; ++ptr ; break ;
  1257. X        default: ++ptr ; break ;
  1258. X      }
  1259. X
  1260. X    while( isspace(*ptr) )
  1261. X      ++ptr ;
  1262. X
  1263. X    /* parse command part */
  1264. X
  1265. X    switch( *ptr ) {
  1266. X      case '\0': break ;
  1267. X      case 'm':
  1268. X        pat->command = C_MAIL ;
  1269. X        get_dest(pat, ++ptr) ;
  1270. X        break ;
  1271. X      case 'j': pat->command = C_JUNK ; ++ptr ; break ;
  1272. X      case 'f':
  1273. X        pat->command = C_FILE ;
  1274. X        get_dest(pat, ++ptr) ;
  1275. X        break ;
  1276. X      case '+':
  1277. X        pat->command = C_FILE ;
  1278. X        get_dest(pat, ptr) ;
  1279. X        break ;
  1280. X      case '|':
  1281. X        pat->command = C_PIPE ;
  1282. X        get_dest(pat, ++ptr) ;
  1283. X        break ;
  1284. X      default: ++ptr ; break ;
  1285. X    }
  1286. X}
  1287. X
  1288. X
  1289. Xstatic    void
  1290. Xget_dest(pat,ptr)
  1291. Xregister PatInfo *pat ;
  1292. Xregister char    *ptr ;
  1293. X{
  1294. X    for(; isspace(*ptr); ++ptr);
  1295. X
  1296. X    pat->dest = strdup(ptr) ;
  1297. X    if( (ptr = strchr(pat->dest, '\n')) != NULL )
  1298. X      *ptr = '\0' ;
  1299. X}
  1300. X
  1301. X
  1302. X
  1303. X
  1304. Xint
  1305. Xfilename_expand(dest, src)
  1306. X    char    *dest ;
  1307. X    char    *src ;        /* file to match */
  1308. X{
  1309. X    char        *lastsl ;    /* last '/' in template */
  1310. X    char        *dirstr ;
  1311. X    struct passwd    *passent ;
  1312. X
  1313. X    if( src[0] == '/' ) {        /* absolute */
  1314. X      strcpy(dest, src) ;        /* that was easy */
  1315. X      return 0 ;
  1316. X    }
  1317. X
  1318. X    if( src[0] == '+' ) {        /* folder name */
  1319. X      strcpy(dest, home) ;
  1320. X      strcat(dest, "/") ;
  1321. X      strcat(dest, folder) ;
  1322. X      strcat(dest, "/") ;
  1323. X      strcat(dest, src+1) ;
  1324. X      return 0 ;
  1325. X    }
  1326. X
  1327. X    if( strmatch(src, "$HOME/") )
  1328. X    {
  1329. X      strcpy(dest, home) ;
  1330. X      strcat(dest, src+5) ;
  1331. X      return 0 ;
  1332. X    }
  1333. X
  1334. X    if( src[0] != '~' ) {        /* relative path, assume relative */
  1335. X      strcpy(dest, home) ;        /* to $HOME    */
  1336. X      strcat(dest, "/") ;
  1337. X      strcat(dest, src) ;
  1338. X      return 0 ;
  1339. X    }
  1340. X
  1341. X
  1342. X
  1343. X    /* cases:
  1344. X     *  "~"        fail
  1345. X     *  "~/        get home directory
  1346. X     *  "~xx    username matching
  1347. X     */
  1348. X
  1349. X    if( src[1] == '/' )
  1350. X    {
  1351. X      strcpy(dest, home) ;
  1352. X      strcat(dest, src+1) ;
  1353. X    }
  1354. X    else
  1355. X    {
  1356. X      dirstr = strchr(src, '/') ;
  1357. X      if( dirstr != NULL )
  1358. X        *dirstr = '\0' ;
  1359. X      passent = getpwnam(src+1) ;
  1360. X      if( dirstr != NULL )
  1361. X        *dirstr = '/' ;
  1362. X      if( passent == NULL )
  1363. X        return -1 ;
  1364. X
  1365. X      strcpy(dest, passent->pw_dir) ;
  1366. X      if( dirstr != NULL )
  1367. X        strcat(dest, dirstr) ;
  1368. X      strcpy(src,dest) ;
  1369. X    }
  1370. X    return 0 ;
  1371. X}
  1372. SHAR_EOF
  1373. len=`wc -c < parse.c`
  1374. if test $len !=     7864 ; then
  1375. echo error: parse.c was $len bytes long, should have been     7864
  1376. fi
  1377. fi # end of overwriting check
  1378.  
  1379. if test -f regex.c
  1380. then
  1381. echo shar: will not over-write existing file regex.c
  1382. else
  1383. echo shar: extracting 'regex.c',    44540 characters
  1384. sed 's/^X//' > regex.c <<'SHAR_EOF'
  1385. X/* Extended regular expression matching and search.
  1386. X   Copyright (C) 1985 Free Software Foundation, Inc.
  1387. X
  1388. X    This program is free software; you can redistribute it and/or modify
  1389. X    it under the terms of the GNU General Public License as published by
  1390. X    the Free Software Foundation; either version 1, or (at your option)
  1391. X    any later version.
  1392. X
  1393. X    This program is distributed in the hope that it will be useful,
  1394. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1395. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1396. X    GNU General Public License for more details.
  1397. X
  1398. X    You should have received a copy of the GNU General Public License
  1399. X    along with this program; if not, write to the Free Software
  1400. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1401. X
  1402. XIn other words, you are welcome to use, share and improve this program.
  1403. XYou are forbidden to forbid anyone else to use, share and improve
  1404. Xwhat you give them.   Help stamp out software-hoarding!  */
  1405. X
  1406. X
  1407. X/* To test, compile with -Dtest.
  1408. X This Dtestable feature turns this into a self-contained program
  1409. X which reads a pattern, describes how it compiles,
  1410. X then reads a string and searches for it.  */
  1411. X
  1412. X
  1413. X#ifdef    SVr4
  1414. X#define    bcopy(s,d,n)    memmove(d,s,n)
  1415. X#define    bzero(d,n)    memset(d,0,n)
  1416. X#define    bcmp        memcmp
  1417. X#endif
  1418. X
  1419. X#ifdef emacs
  1420. X
  1421. X/* The `emacs' switch turns on certain special matching commands
  1422. X that make sense only in emacs. */
  1423. X
  1424. X#include "config.h"
  1425. X#include "lisp.h"
  1426. X#include "buffer.h"
  1427. X#include "syntax.h"
  1428. X
  1429. X#else  /* not emacs */
  1430. X
  1431. X/*
  1432. X * Define the syntax stuff, so we can do the \<...\> things.
  1433. X */
  1434. X
  1435. X#ifndef Sword /* must be non-zero in some of the tests below... */
  1436. X#define Sword 1
  1437. X#endif
  1438. X
  1439. X#define SYNTAX(c) re_syntax_table[c]
  1440. X
  1441. X#ifdef SYNTAX_TABLE
  1442. X
  1443. Xchar *re_syntax_table;
  1444. X
  1445. X#else
  1446. X
  1447. Xstatic char re_syntax_table[256];
  1448. X
  1449. Xstatic void
  1450. Xinit_syntax_once ()
  1451. X{
  1452. X   register int c;
  1453. X   static int done = 0;
  1454. X
  1455. X   if (done)
  1456. X     return;
  1457. X
  1458. X   bzero (re_syntax_table, sizeof re_syntax_table);
  1459. X
  1460. X   for (c = 'a'; c <= 'z'; c++)
  1461. X     re_syntax_table[c] = Sword;
  1462. X
  1463. X   for (c = 'A'; c <= 'Z'; c++)
  1464. X     re_syntax_table[c] = Sword;
  1465. X
  1466. X   for (c = '0'; c <= '9'; c++)
  1467. X     re_syntax_table[c] = Sword;
  1468. X
  1469. X   done = 1;
  1470. X}
  1471. X
  1472. X#endif /* SYNTAX_TABLE */
  1473. X#endif /* not emacs */
  1474. X
  1475. X#include <alloca.h>
  1476. X#include "regex.h"
  1477. X
  1478. X/* Number of failure points to allocate space for initially,
  1479. X when matching.  If this number is exceeded, more space is allocated,
  1480. X so it is not a hard limit.  */
  1481. X
  1482. X#ifndef NFAILURES
  1483. X#define NFAILURES 80
  1484. X#endif NFAILURES
  1485. X
  1486. X/* width of a byte in bits */
  1487. X
  1488. X#define BYTEWIDTH 8
  1489. X
  1490. X#ifndef SIGN_EXTEND_CHAR
  1491. X#define SIGN_EXTEND_CHAR(x) (x)
  1492. X#endif
  1493. X
  1494. Xstatic int obscure_syntax = 0;
  1495. X
  1496. X/* Specify the precise syntax of regexp for compilation.
  1497. X   This provides for compatibility for various utilities
  1498. X   which historically have different, incompatible syntaxes.
  1499. X
  1500. X   The argument SYNTAX is a bit-mask containing the two bits
  1501. X   RE_NO_BK_PARENS and RE_NO_BK_VBAR.  */
  1502. X
  1503. Xint
  1504. Xre_set_syntax (syntax)
  1505. X{
  1506. X  int ret;
  1507. X
  1508. X  ret = obscure_syntax;
  1509. X  obscure_syntax = syntax;
  1510. X  return ret;
  1511. X}
  1512. X
  1513. X/* re_compile_pattern takes a regular-expression string
  1514. X   and converts it into a buffer full of byte commands for matching.
  1515. X
  1516. X  PATTERN   is the address of the pattern string
  1517. X  SIZE      is the length of it.
  1518. X  BUFP        is a  struct re_pattern_buffer *  which points to the info
  1519. X        on where to store the byte commands.
  1520. X        This structure contains a  char *  which points to the
  1521. X        actual space, which should have been obtained with malloc.
  1522. X        re_compile_pattern may use  realloc  to grow the buffer space.
  1523. X
  1524. X  The number of bytes of commands can be found out by looking in
  1525. X  the  struct re_pattern_buffer  that bufp pointed to,
  1526. X  after re_compile_pattern returns.
  1527. X*/
  1528. X
  1529. X#define PATPUSH(ch) (*b++ = (char) (ch))
  1530. X
  1531. X#define PATFETCH(c) \
  1532. X {if (p == pend) goto end_of_pattern; \
  1533. X  c = * (unsigned char *) p++; \
  1534. X  if (translate) c = translate[c]; }
  1535. X
  1536. X#define PATFETCH_RAW(c) \
  1537. X {if (p == pend) goto end_of_pattern; \
  1538. X  c = * (unsigned char *) p++; }
  1539. X
  1540. X#define PATUNFETCH p--
  1541. X
  1542. X#define EXTEND_BUFFER \
  1543. X  { char *old_buffer = bufp->buffer; \
  1544. X    if (bufp->allocated == (1<<16)) goto too_big; \
  1545. X    bufp->allocated *= 2; \
  1546. X    if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \
  1547. X    if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
  1548. X      goto memory_exhausted; \
  1549. X    c = bufp->buffer - old_buffer; \
  1550. X    b += c; \
  1551. X    if (fixup_jump) \
  1552. X      fixup_jump += c; \
  1553. X    if (laststart) \
  1554. X      laststart += c; \
  1555. X    begalt += c; \
  1556. X    if (pending_exact) \
  1557. X      pending_exact += c; \
  1558. X  }
  1559. X
  1560. Xstatic int store_jump (), insert_jump ();
  1561. X
  1562. Xchar *
  1563. Xre_compile_pattern (pattern, size, bufp)
  1564. X     char *pattern;
  1565. X     int size;
  1566. X     struct re_pattern_buffer *bufp;
  1567. X{
  1568. X  register char *b = bufp->buffer;
  1569. X  register char *p = pattern;
  1570. X  char *pend = pattern + size;
  1571. X  register unsigned c, c1;
  1572. X  char *p1;
  1573. X  unsigned char *translate = (unsigned char *) bufp->translate;
  1574. X
  1575. X  /* address of the count-byte of the most recently inserted "exactn" command.
  1576. X    This makes it possible to tell whether a new exact-match character
  1577. X    can be added to that command or requires a new "exactn" command. */
  1578. X     
  1579. X  char *pending_exact = 0;
  1580. X
  1581. X  /* address of the place where a forward-jump should go
  1582. X    to the end of the containing expression.
  1583. X    Each alternative of an "or", except the last, ends with a forward-jump
  1584. X    of this sort. */
  1585. X
  1586. X  char *fixup_jump = 0;
  1587. X
  1588. X  /* address of start of the most recently finished expression.
  1589. X    This tells postfix * where to find the start of its operand. */
  1590. X
  1591. X  char *laststart = 0;
  1592. X
  1593. X  /* In processing a repeat, 1 means zero matches is allowed */
  1594. X
  1595. X  char zero_times_ok;
  1596. X
  1597. X  /* In processing a repeat, 1 means many matches is allowed */
  1598. X
  1599. X  char many_times_ok;
  1600. X
  1601. X  /* address of beginning of regexp, or inside of last \( */
  1602. X
  1603. X  char *begalt = b;
  1604. X
  1605. X  /* Stack of information saved by \( and restored by \).
  1606. X     Four stack elements are pushed by each \(:
  1607. X       First, the value of b.
  1608. X       Second, the value of fixup_jump.
  1609. X       Third, the value of regnum.
  1610. X       Fourth, the value of begalt.  */
  1611. X
  1612. X  int stackb[40];
  1613. X  int *stackp = stackb;
  1614. X  int *stacke = stackb + 40;
  1615. X  int *stackt;
  1616. X
  1617. X  /* Counts \('s as they are encountered.  Remembered for the matching \),
  1618. X     where it becomes the "register number" to put in the stop_memory command */
  1619. X
  1620. X  int regnum = 1;
  1621. X
  1622. X  bufp->fastmap_accurate = 0;
  1623. X
  1624. X#ifndef emacs
  1625. X#ifndef SYNTAX_TABLE
  1626. X  /*
  1627. X   * Initialize the syntax table.
  1628. X   */
  1629. X   init_syntax_once();
  1630. X#endif
  1631. X#endif
  1632. X
  1633. X  if (bufp->allocated == 0)
  1634. X    {
  1635. X      bufp->allocated = 28;
  1636. X      if (bufp->buffer)
  1637. X    /* EXTEND_BUFFER loses when bufp->allocated is 0 */
  1638. X    bufp->buffer = (char *) realloc (bufp->buffer, 28);
  1639. X      else
  1640. X    /* Caller did not allocate a buffer.  Do it for him */
  1641. X    bufp->buffer = (char *) malloc (28);
  1642. X      if (!bufp->buffer) goto memory_exhausted;
  1643. X      begalt = b = bufp->buffer;
  1644. X    }
  1645. X
  1646. X  while (p != pend)
  1647. X    {
  1648. X      if (b - bufp->buffer > bufp->allocated - 10)
  1649. X    /* Note that EXTEND_BUFFER clobbers c */
  1650. X    EXTEND_BUFFER;
  1651. X
  1652. X      PATFETCH (c);
  1653. X
  1654. X      switch (c)
  1655. X    {
  1656. X    case '$':
  1657. X      if (obscure_syntax & RE_TIGHT_VBAR)
  1658. X        {
  1659. X          if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
  1660. X        goto normal_char;
  1661. X          /* Make operand of last vbar end before this `$'.  */
  1662. X          if (fixup_jump)
  1663. X        store_jump (fixup_jump, jump, b);
  1664. X          fixup_jump = 0;
  1665. X          PATPUSH (endline);
  1666. X          break;
  1667. X        }
  1668. X
  1669. X      /* $ means succeed if at end of line, but only in special contexts.
  1670. X        If randomly in the middle of a pattern, it is a normal character. */
  1671. X      if (p == pend || *p == '\n'
  1672. X          || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
  1673. X          || (obscure_syntax & RE_NO_BK_PARENS
  1674. X          ? *p == ')'
  1675. X          : *p == '\\' && p[1] == ')')
  1676. X          || (obscure_syntax & RE_NO_BK_VBAR
  1677. X          ? *p == '|'
  1678. X          : *p == '\\' && p[1] == '|'))
  1679. X        {
  1680. X          PATPUSH (endline);
  1681. X          break;
  1682. X        }
  1683. X      goto normal_char;
  1684. X
  1685. X    case '^':
  1686. X      /* ^ means succeed if at beg of line, but only if no preceding pattern. */
  1687. X
  1688. X      if (laststart && p[-2] != '\n'
  1689. X          && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
  1690. X        goto normal_char;
  1691. X      if (obscure_syntax & RE_TIGHT_VBAR)
  1692. X        {
  1693. X          if (p != pattern + 1
  1694. X          && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
  1695. X        goto normal_char;
  1696. X          PATPUSH (begline);
  1697. X          begalt = b;
  1698. X        }
  1699. X      else
  1700. X        PATPUSH (begline);
  1701. X      break;
  1702. X
  1703. X    case '+':
  1704. X    case '?':
  1705. X      if (obscure_syntax & RE_BK_PLUS_QM)
  1706. X        goto normal_char;
  1707. X    handle_plus:
  1708. X    case '*':
  1709. X      /* If there is no previous pattern, char not special. */
  1710. X      if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
  1711. X        goto normal_char;
  1712. X      /* If there is a sequence of repetition chars,
  1713. X         collapse it down to equivalent to just one.  */
  1714. X      zero_times_ok = 0;
  1715. X      many_times_ok = 0;
  1716. X      while (1)
  1717. X        {
  1718. X          zero_times_ok |= c != '+';
  1719. X          many_times_ok |= c != '?';
  1720. X          if (p == pend)
  1721. X        break;
  1722. X          PATFETCH (c);
  1723. X          if (c == '*')
  1724. X        ;
  1725. X          else if (!(obscure_syntax & RE_BK_PLUS_QM)
  1726. X               && (c == '+' || c == '?'))
  1727. X        ;
  1728. X          else if ((obscure_syntax & RE_BK_PLUS_QM)
  1729. X               && c == '\\')
  1730. X        {
  1731. X          int c1;
  1732. X          PATFETCH (c1);
  1733. X          if (!(c1 == '+' || c1 == '?'))
  1734. X            {
  1735. X              PATUNFETCH;
  1736. X              PATUNFETCH;
  1737. X              break;
  1738. X            }
  1739. X          c = c1;
  1740. X        }
  1741. X          else
  1742. X        {
  1743. X          PATUNFETCH;
  1744. X          break;
  1745. X        }
  1746. X        }
  1747. X
  1748. X      /* Star, etc. applied to an empty pattern is equivalent
  1749. X         to an empty pattern.  */
  1750. X      if (!laststart)
  1751. X        break;
  1752. X
  1753. X      /* Now we know whether 0 matches is allowed,
  1754. X         and whether 2 or more matches is allowed.  */
  1755. X      if (many_times_ok)
  1756. X        {
  1757. X          /* If more than one repetition is allowed,
  1758. X         put in a backward jump at the end.  */
  1759. X          store_jump (b, maybe_finalize_jump, laststart - 3);
  1760. X          b += 3;
  1761. X        }
  1762. X      insert_jump (on_failure_jump, laststart, b + 3, b);
  1763. X      pending_exact = 0;
  1764. X      b += 3;
  1765. X      if (!zero_times_ok)
  1766. X        {
  1767. X          /* At least one repetition required: insert before the loop
  1768. X         a skip over the initial on-failure-jump instruction */
  1769. X          insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
  1770. X          b += 3;
  1771. X        }
  1772. X      break;
  1773. X
  1774. X    case '.':
  1775. X      laststart = b;
  1776. X      PATPUSH (anychar);
  1777. X      break;
  1778. X
  1779. X    case '[':
  1780. X      while (b - bufp->buffer
  1781. X         > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
  1782. X        /* Note that EXTEND_BUFFER clobbers c */
  1783. X        EXTEND_BUFFER;
  1784. X
  1785. X      laststart = b;
  1786. X      if (*p == '^')
  1787. X        PATPUSH (charset_not), p++;
  1788. X      else
  1789. X        PATPUSH (charset);
  1790. X      p1 = p;
  1791. X
  1792. X      PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
  1793. X      /* Clear the whole map */
  1794. X      bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
  1795. X      /* Read in characters and ranges, setting map bits */
  1796. X      while (1)
  1797. X        {
  1798. X          PATFETCH (c);
  1799. X          if (c == ']' && p != p1 + 1) break;
  1800. X          if (*p == '-' && p[1] != ']')
  1801. X        {
  1802. X          PATFETCH (c1);
  1803. X          PATFETCH (c1);
  1804. X          while (c <= c1)
  1805. X            b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
  1806. X        }
  1807. X          else
  1808. X        {
  1809. X          b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
  1810. X        }
  1811. X        }
  1812. X      /* Discard any bitmap bytes that are all 0 at the end of the map.
  1813. X         Decrement the map-length byte too. */
  1814. X      while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
  1815. X        b[-1]--;
  1816. X      b += b[-1];
  1817. X      break;
  1818. X
  1819. X    case '(':
  1820. X      if (! (obscure_syntax & RE_NO_BK_PARENS))
  1821. X        goto normal_char;
  1822. X      else
  1823. X        goto handle_open;
  1824. X
  1825. X    case ')':
  1826. X      if (! (obscure_syntax & RE_NO_BK_PARENS))
  1827. X        goto normal_char;
  1828. X      else
  1829. X        goto handle_close;
  1830. X
  1831. X    case '\n':
  1832. X      if (! (obscure_syntax & RE_NEWLINE_OR))
  1833. X        goto normal_char;
  1834. X      else
  1835. X        goto handle_bar;
  1836. X
  1837. X    case '|':
  1838. X      if (! (obscure_syntax & RE_NO_BK_VBAR))
  1839. X        goto normal_char;
  1840. X      else
  1841. X        goto handle_bar;
  1842. X
  1843. X        case '\\':
  1844. X      if (p == pend) goto invalid_pattern;
  1845. X      PATFETCH_RAW (c);
  1846. X      switch (c)
  1847. X        {
  1848. X        case '(':
  1849. X          if (obscure_syntax & RE_NO_BK_PARENS)
  1850. X        goto normal_backsl;
  1851. X        handle_open:
  1852. X          if (stackp == stacke) goto nesting_too_deep;
  1853. X          if (regnum < RE_NREGS)
  1854. X            {
  1855. X          PATPUSH (start_memory);
  1856. X          PATPUSH (regnum);
  1857. X            }
  1858. X          *stackp++ = b - bufp->buffer;
  1859. X          *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0;
  1860. X          *stackp++ = regnum++;
  1861. X          *stackp++ = begalt - bufp->buffer;
  1862. X          fixup_jump = 0;
  1863. X          laststart = 0;
  1864. X          begalt = b;
  1865. X          break;
  1866. X
  1867. X        case ')':
  1868. X          if (obscure_syntax & RE_NO_BK_PARENS)
  1869. X        goto normal_backsl;
  1870. X        handle_close:
  1871. X          if (stackp == stackb) goto unmatched_close;
  1872. X          begalt = *--stackp + bufp->buffer;
  1873. X          if (fixup_jump)
  1874. X        store_jump (fixup_jump, jump, b);
  1875. X          if (stackp[-1] < RE_NREGS)
  1876. X        {
  1877. X          PATPUSH (stop_memory);
  1878. X          PATPUSH (stackp[-1]);
  1879. X        }
  1880. X          stackp -= 2;
  1881. X          fixup_jump = 0;
  1882. X          if (*stackp)
  1883. X        fixup_jump = *stackp + bufp->buffer - 1;
  1884. X          laststart = *--stackp + bufp->buffer;
  1885. X          break;
  1886. X
  1887. X        case '|':
  1888. X          if (obscure_syntax & RE_NO_BK_VBAR)
  1889. X        goto normal_backsl;
  1890. X        handle_bar:
  1891. X          insert_jump (on_failure_jump, begalt, b + 6, b);
  1892. X          pending_exact = 0;
  1893. X          b += 3;
  1894. X          if (fixup_jump)
  1895. X        store_jump (fixup_jump, jump, b);
  1896. X          fixup_jump = b;
  1897. X          b += 3;
  1898. X          laststart = 0;
  1899. X          begalt = b;
  1900. X          break;
  1901. X
  1902. X#ifdef emacs
  1903. X        case '=':
  1904. X          PATPUSH (at_dot);
  1905. X          break;
  1906. X
  1907. X        case 's':    
  1908. X          laststart = b;
  1909. X          PATPUSH (syntaxspec);
  1910. X          PATFETCH (c);
  1911. X          PATPUSH (syntax_spec_code[c]);
  1912. X          break;
  1913. X
  1914. X        case 'S':
  1915. X          laststart = b;
  1916. X          PATPUSH (notsyntaxspec);
  1917. X          PATFETCH (c);
  1918. X          PATPUSH (syntax_spec_code[c]);
  1919. X          break;
  1920. X#endif emacs
  1921. X
  1922. X        case 'w':
  1923. X          laststart = b;
  1924. X          PATPUSH (wordchar);
  1925. X          break;
  1926. X
  1927. X        case 'W':
  1928. X          laststart = b;
  1929. X          PATPUSH (notwordchar);
  1930. X          break;
  1931. X
  1932. X        case '<':
  1933. X          PATPUSH (wordbeg);
  1934. X          break;
  1935. X
  1936. X        case '>':
  1937. X          PATPUSH (wordend);
  1938. X          break;
  1939. X
  1940. X        case 'b':
  1941. X          PATPUSH (wordbound);
  1942. X          break;
  1943. X
  1944. X        case 'B':
  1945. X          PATPUSH (notwordbound);
  1946. X          break;
  1947. X
  1948. X        case '`':
  1949. X          PATPUSH (begbuf);
  1950. X          break;
  1951. X
  1952. X        case '\'':
  1953. X          PATPUSH (endbuf);
  1954. X          break;
  1955. X
  1956. X        case '1':
  1957. X        case '2':
  1958. X        case '3':
  1959. X        case '4':
  1960. X        case '5':
  1961. X        case '6':
  1962. X        case '7':
  1963. X        case '8':
  1964. X        case '9':
  1965. X          c1 = c - '0';
  1966. X          if (c1 >= regnum)
  1967. X        goto normal_char;
  1968. X          for (stackt = stackp - 2;  stackt > stackb;  stackt -= 4)
  1969. X         if (*stackt == c1)
  1970. X          goto normal_char;
  1971. X          laststart = b;
  1972. X          PATPUSH (duplicate);
  1973. X          PATPUSH (c1);
  1974. X          break;
  1975. X
  1976. X        case '+':
  1977. X        case '?':
  1978. X          if (obscure_syntax & RE_BK_PLUS_QM)
  1979. X        goto handle_plus;
  1980. X
  1981. X        default:
  1982. X        normal_backsl:
  1983. X          /* You might think it would be useful for \ to mean
  1984. X         not to translate; but if we don't translate it
  1985. X         it will never match anything.  */
  1986. X          if (translate) c = translate[c];
  1987. X          goto normal_char;
  1988. X        }
  1989. X      break;
  1990. X
  1991. X    default:
  1992. X    normal_char:
  1993. X      if (!pending_exact || pending_exact + *pending_exact + 1 != b
  1994. X          || *pending_exact == 0177 || *p == '*' || *p == '^'
  1995. X          || ((obscure_syntax & RE_BK_PLUS_QM)
  1996. X          ? *p == '\\' && (p[1] == '+' || p[1] == '?')
  1997. X          : (*p == '+' || *p == '?')))
  1998. X        {
  1999. X          laststart = b;
  2000. X          PATPUSH (exactn);
  2001. X          pending_exact = b;
  2002. X          PATPUSH (0);
  2003. X        }
  2004. X      PATPUSH (c);
  2005. X      (*pending_exact)++;
  2006. X    }
  2007. X    }
  2008. X
  2009. X  if (fixup_jump)
  2010. X    store_jump (fixup_jump, jump, b);
  2011. X
  2012. X  if (stackp != stackb) goto unmatched_open;
  2013. X
  2014. X  bufp->used = b - bufp->buffer;
  2015. X  return 0;
  2016. X
  2017. X invalid_pattern:
  2018. X  return "Invalid regular expression";
  2019. X
  2020. X unmatched_open:
  2021. X  return "Unmatched \\(";
  2022. X
  2023. X unmatched_close:
  2024. X  return "Unmatched \\)";
  2025. X
  2026. X end_of_pattern:
  2027. X  return "Premature end of regular expression";
  2028. X
  2029. X nesting_too_deep:
  2030. X  return "Nesting too deep";
  2031. X
  2032. X too_big:
  2033. X  return "Regular expression too big";
  2034. X
  2035. X memory_exhausted:
  2036. X  return "Memory exhausted";
  2037. X}
  2038. X
  2039. X/* Store where `from' points a jump operation to jump to where `to' points.
  2040. X  `opcode' is the opcode to store. */
  2041. X
  2042. Xstatic int
  2043. Xstore_jump (from, opcode, to)
  2044. X     char *from, *to;
  2045. X     char opcode;
  2046. X{
  2047. X  from[0] = opcode;
  2048. X  from[1] = (to - (from + 3)) & 0377;
  2049. X  from[2] = (to - (from + 3)) >> 8;
  2050. X}
  2051. X
  2052. X/* Open up space at char FROM, and insert there a jump to TO.
  2053. X   CURRENT_END gives te end of the storage no in use,
  2054. X   so we know how much data to copy up.
  2055. X   OP is the opcode of the jump to insert.
  2056. X
  2057. X   If you call this function, you must zero out pending_exact.  */
  2058. X
  2059. Xstatic int
  2060. Xinsert_jump (op, from, to, current_end)
  2061. X     char op;
  2062. X     char *from, *to, *current_end;
  2063. X{
  2064. X  register char *pto = current_end + 3;
  2065. X  register char *pfrom = current_end;
  2066. X  while (pfrom != from)
  2067. X    *--pto = *--pfrom;
  2068. X  store_jump (from, op, to);
  2069. X}
  2070. X
  2071. X/* Given a pattern, compute a fastmap from it.
  2072. X The fastmap records which of the (1 << BYTEWIDTH) possible characters
  2073. X can start a string that matches the pattern.
  2074. X This fastmap is used by re_search to skip quickly over totally implausible text.
  2075. X
  2076. X The caller must supply the address of a (1 << BYTEWIDTH)-byte data area
  2077. X as bufp->fastmap.
  2078. X The other components of bufp describe the pattern to be used.  */
  2079. X
  2080. Xvoid
  2081. Xre_compile_fastmap (bufp)
  2082. X     struct re_pattern_buffer *bufp;
  2083. X{
  2084. X  unsigned char *pattern = (unsigned char *) bufp->buffer;
  2085. X  int size = bufp->used;
  2086. X  register char *fastmap = bufp->fastmap;
  2087. X  register unsigned char *p = pattern;
  2088. X  register unsigned char *pend = pattern + size;
  2089. X  register int j, k;
  2090. X  unsigned char *translate = (unsigned char *) bufp->translate;
  2091. X
  2092. X  unsigned char *stackb[NFAILURES];
  2093. X  unsigned char **stackp = stackb;
  2094. X
  2095. X  bzero (fastmap, (1 << BYTEWIDTH));
  2096. X  bufp->fastmap_accurate = 1;
  2097. X  bufp->can_be_null = 0;
  2098. X      
  2099. X  while (p)
  2100. X    {
  2101. X      if (p == pend)
  2102. X    {
  2103. X      bufp->can_be_null = 1;
  2104. X      break;
  2105. X    }
  2106. X#ifdef SWITCH_ENUM_BUG
  2107. X      switch ((int) ((enum regexpcode) *p++))
  2108. X#else
  2109. X      switch ((enum regexpcode) *p++)
  2110. X#endif
  2111. X    {
  2112. X    case exactn:
  2113. X      if (translate)
  2114. X        fastmap[translate[p[1]]] = 1;
  2115. X      else
  2116. X        fastmap[p[1]] = 1;
  2117. X      break;
  2118. X
  2119. X        case begline:
  2120. X        case before_dot:
  2121. X    case at_dot:
  2122. X    case after_dot:
  2123. X    case begbuf:
  2124. X    case endbuf:
  2125. X    case wordbound:
  2126. X    case notwordbound:
  2127. X    case wordbeg:
  2128. X    case wordend:
  2129. X      continue;
  2130. X
  2131. X    case endline:
  2132. X      if (translate)
  2133. X        fastmap[translate['\n']] = 1;
  2134. X      else
  2135. X        fastmap['\n'] = 1;
  2136. X      if (bufp->can_be_null != 1)
  2137. X        bufp->can_be_null = 2;
  2138. X      break;
  2139. X
  2140. X    case finalize_jump:
  2141. X    case maybe_finalize_jump:
  2142. X    case jump:
  2143. X    case dummy_failure_jump:
  2144. X      bufp->can_be_null = 1;
  2145. X      j = *p++ & 0377;
  2146. X      j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2147. X      p += j + 1;        /* The 1 compensates for missing ++ above */
  2148. X      if (j > 0)
  2149. X        continue;
  2150. X      /* Jump backward reached implies we just went through
  2151. X         the body of a loop and matched nothing.
  2152. X         Opcode jumped to should be an on_failure_jump.
  2153. X         Just treat it like an ordinary jump.
  2154. X         For a * loop, it has pushed its failure point already;
  2155. X         if so, discard that as redundant.  */
  2156. X      if ((enum regexpcode) *p != on_failure_jump)
  2157. X        continue;
  2158. X      p++;
  2159. X      j = *p++ & 0377;
  2160. X      j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2161. X      p += j + 1;        /* The 1 compensates for missing ++ above */
  2162. X      if (stackp != stackb && *stackp == p)
  2163. X        stackp--;
  2164. X      continue;
  2165. X      
  2166. X    case on_failure_jump:
  2167. X      j = *p++ & 0377;
  2168. X      j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2169. X      p++;
  2170. X      *++stackp = p + j;
  2171. X      continue;
  2172. X
  2173. X    case start_memory:
  2174. X    case stop_memory:
  2175. X      p++;
  2176. X      continue;
  2177. X
  2178. X    case duplicate:
  2179. X      bufp->can_be_null = 1;
  2180. X      fastmap['\n'] = 1;
  2181. X    case anychar:
  2182. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  2183. X        if (j != '\n')
  2184. X          fastmap[j] = 1;
  2185. X      if (bufp->can_be_null)
  2186. X        return;
  2187. X      /* Don't return; check the alternative paths
  2188. X         so we can set can_be_null if appropriate.  */
  2189. X      break;
  2190. X
  2191. X    case wordchar:
  2192. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  2193. X        if (SYNTAX (j) == Sword)
  2194. X          fastmap[j] = 1;
  2195. X      break;
  2196. X
  2197. X    case notwordchar:
  2198. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  2199. X        if (SYNTAX (j) != Sword)
  2200. X          fastmap[j] = 1;
  2201. X      break;
  2202. X
  2203. X#ifdef emacs
  2204. X    case syntaxspec:
  2205. X      k = *p++;
  2206. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  2207. X        if (SYNTAX (j) == (enum syntaxcode) k)
  2208. X          fastmap[j] = 1;
  2209. X      break;
  2210. X
  2211. X    case notsyntaxspec:
  2212. X      k = *p++;
  2213. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  2214. X        if (SYNTAX (j) != (enum syntaxcode) k)
  2215. X          fastmap[j] = 1;
  2216. X      break;
  2217. X#endif emacs
  2218. X
  2219. X    case charset:
  2220. X      for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
  2221. X        if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
  2222. X          {
  2223. X        if (translate)
  2224. X          fastmap[translate[j]] = 1;
  2225. X        else
  2226. X          fastmap[j] = 1;
  2227. X          }
  2228. X      break;
  2229. X
  2230. X    case charset_not:
  2231. X      /* Chars beyond end of map must be allowed */
  2232. X      for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
  2233. X        if (translate)
  2234. X          fastmap[translate[j]] = 1;
  2235. X        else
  2236. X          fastmap[j] = 1;
  2237. X
  2238. X      for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
  2239. X        if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
  2240. X          {
  2241. X        if (translate)
  2242. X          fastmap[translate[j]] = 1;
  2243. X        else
  2244. X          fastmap[j] = 1;
  2245. X          }
  2246. X      break;
  2247. X    }
  2248. X
  2249. X      /* Get here means we have successfully found the possible starting characters
  2250. X     of one path of the pattern.  We need not follow this path any farther.
  2251. X     Instead, look at the next alternative remembered in the stack. */
  2252. X      if (stackp != stackb)
  2253. X    p = *stackp--;
  2254. X      else
  2255. X    break;
  2256. X    }
  2257. X}
  2258. X
  2259. X/* Like re_search_2, below, but only one string is specified. */
  2260. X
  2261. Xint
  2262. Xre_search (pbufp, string, size, startpos, range, regs)
  2263. X     struct re_pattern_buffer *pbufp;
  2264. X     char *string;
  2265. X     int size, startpos, range;
  2266. X     struct re_registers *regs;
  2267. X{
  2268. X  return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size);
  2269. X}
  2270. X
  2271. X/* Like re_match_2 but tries first a match starting at index STARTPOS,
  2272. X   then at STARTPOS + 1, and so on.
  2273. X   RANGE is the number of places to try before giving up.
  2274. X   If RANGE is negative, the starting positions tried are
  2275. X    STARTPOS, STARTPOS - 1, etc.
  2276. X   It is up to the caller to make sure that range is not so large
  2277. X   as to take the starting position outside of the input strings.
  2278. X
  2279. XThe value returned is the position at which the match was found,
  2280. X or -1 if no match was found,
  2281. X or -2 if error (such as failure stack overflow).  */
  2282. X
  2283. Xint
  2284. Xre_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop)
  2285. X     struct re_pattern_buffer *pbufp;
  2286. X     char *string1, *string2;
  2287. X     int size1, size2;
  2288. X     int startpos;
  2289. X     register int range;
  2290. X     struct re_registers *regs;
  2291. X     int mstop;
  2292. X{
  2293. X  register char *fastmap = pbufp->fastmap;
  2294. X  register unsigned char *translate = (unsigned char *) pbufp->translate;
  2295. X  int total = size1 + size2;
  2296. X  int val;
  2297. X
  2298. X  /* Update the fastmap now if not correct already */
  2299. X  if (fastmap && !pbufp->fastmap_accurate)
  2300. X    re_compile_fastmap (pbufp);
  2301. X  
  2302. X  /* Don't waste time in a long search for a pattern
  2303. X     that says it is anchored.  */
  2304. X  if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
  2305. X      && range > 0)
  2306. X    {
  2307. X      if (startpos > 0)
  2308. X    return -1;
  2309. X      else
  2310. X    range = 1;
  2311. X    }
  2312. X
  2313. X  while (1)
  2314. X    {
  2315. X      /* If a fastmap is supplied, skip quickly over characters
  2316. X     that cannot possibly be the start of a match.
  2317. X     Note, however, that if the pattern can possibly match
  2318. X     the null string, we must test it at each starting point
  2319. X     so that we take the first null string we get.  */
  2320. X
  2321. X      if (fastmap && startpos < total && pbufp->can_be_null != 1)
  2322. X    {
  2323. X      if (range > 0)
  2324. X        {
  2325. X          register int lim = 0;
  2326. X          register unsigned char *p;
  2327. X          int irange = range;
  2328. X          if (startpos < size1 && startpos + range >= size1)
  2329. X        lim = range - (size1 - startpos);
  2330. X
  2331. X          p = ((unsigned char *)
  2332. X           &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
  2333. X
  2334. X          if (translate)
  2335. X        {
  2336. X          while (range > lim && !fastmap[translate[*p++]])
  2337. X            range--;
  2338. X        }
  2339. X          else
  2340. X        {
  2341. X          while (range > lim && !fastmap[*p++])
  2342. X            range--;
  2343. X        }
  2344. X          startpos += irange - range;
  2345. X        }
  2346. X      else
  2347. X        {
  2348. X          register unsigned char c;
  2349. X          if (startpos >= size1)
  2350. X        c = string2[startpos - size1];
  2351. X          else
  2352. X        c = string1[startpos];
  2353. X          c &= 0xff;
  2354. X          if (translate ? !fastmap[translate[c]] : !fastmap[c])
  2355. X        goto advance;
  2356. X        }
  2357. X    }
  2358. X
  2359. X      if (range >= 0 && startpos == total
  2360. X      && fastmap && pbufp->can_be_null == 0)
  2361. X    return -1;
  2362. X
  2363. X      val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs,
  2364. X            mstop);
  2365. X      /* Propagate error indication if worse than mere failure.  */
  2366. X      if (val == -2)
  2367. X    return -2;
  2368. X      /* Return position on success.  */
  2369. X      if (0 <= val)
  2370. X    return startpos;
  2371. X
  2372. X#ifdef C_ALLOCA
  2373. X      alloca (0);
  2374. X#endif /* C_ALLOCA */
  2375. X
  2376. X    advance:
  2377. X      if (!range) break;
  2378. X      if (range > 0) range--, startpos++; else range++, startpos--;
  2379. X    }
  2380. X  return -1;
  2381. X}
  2382. X
  2383. X#ifndef emacs   /* emacs never uses this */
  2384. Xint
  2385. Xre_match (pbufp, string, size, pos, regs)
  2386. X     struct re_pattern_buffer *pbufp;
  2387. X     char *string;
  2388. X     int size, pos;
  2389. X     struct re_registers *regs;
  2390. X{
  2391. X  return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size);
  2392. X}
  2393. X#endif /* emacs */
  2394. X
  2395. X/* Maximum size of failure stack.  Beyond this, overflow is an error.  */
  2396. X
  2397. Xint re_max_failures = 2000;
  2398. X
  2399. Xstatic int bcmp_translate();
  2400. X/* Match the pattern described by PBUFP
  2401. X   against data which is the virtual concatenation of STRING1 and STRING2.
  2402. X   SIZE1 and SIZE2 are the sizes of the two data strings.
  2403. X   Start the match at position POS.
  2404. X   Do not consider matching past the position MSTOP.
  2405. X
  2406. X   If pbufp->fastmap is nonzero, then it had better be up to date.
  2407. X
  2408. X   The reason that the data to match are specified as two components
  2409. X   which are to be regarded as concatenated
  2410. X   is so this function can be used directly on the contents of an Emacs buffer.
  2411. X
  2412. X   -1 is returned if there is no match.  -2 is returned if there is
  2413. X   an error (such as match stack overflow).  Otherwise the value is the length
  2414. X   of the substring which was matched.  */
  2415. X
  2416. Xint
  2417. Xre_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop)
  2418. X     struct re_pattern_buffer *pbufp;
  2419. X     unsigned char *string1, *string2;
  2420. X     int size1, size2;
  2421. X     int pos;
  2422. X     struct re_registers *regs;
  2423. X     int mstop;
  2424. X{
  2425. X  register unsigned char *p = (unsigned char *) pbufp->buffer;
  2426. X  register unsigned char *pend = p + pbufp->used;
  2427. X  /* End of first string */
  2428. X  unsigned char *end1;
  2429. X  /* End of second string */
  2430. X  unsigned char *end2;
  2431. X  /* Pointer just past last char to consider matching */
  2432. X  unsigned char *end_match_1, *end_match_2;
  2433. X  register unsigned char *d, *dend;
  2434. X  register int mcnt;
  2435. X  unsigned char *translate = (unsigned char *) pbufp->translate;
  2436. X
  2437. X /* Failure point stack.  Each place that can handle a failure further down the line
  2438. X    pushes a failure point on this stack.  It consists of two char *'s.
  2439. X    The first one pushed is where to resume scanning the pattern;
  2440. X    the second pushed is where to resume scanning the strings.
  2441. X    If the latter is zero, the failure point is a "dummy".
  2442. X    If a failure happens and the innermost failure point is dormant,
  2443. X    it discards that failure point and tries the next one. */
  2444. X
  2445. X  unsigned char *initial_stack[2 * NFAILURES];
  2446. X  unsigned char **stackb = initial_stack;
  2447. X  unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
  2448. X
  2449. X  /* Information on the "contents" of registers.
  2450. X     These are pointers into the input strings; they record
  2451. X     just what was matched (on this attempt) by some part of the pattern.
  2452. X     The start_memory command stores the start of a register's contents
  2453. X     and the stop_memory command stores the end.
  2454. X
  2455. X     At that point, regstart[regnum] points to the first character in the register,
  2456. X     regend[regnum] points to the first character beyond the end of the register,
  2457. X     regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
  2458. X     and regend_seg1[regnum] is true iff regend[regnum] points into string1.  */
  2459. X
  2460. X  unsigned char *regstart[RE_NREGS];
  2461. X  unsigned char *regend[RE_NREGS];
  2462. X  unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
  2463. X
  2464. X  /* Set up pointers to ends of strings.
  2465. X     Don't allow the second string to be empty unless both are empty.  */
  2466. X  if (!size2)
  2467. X    {
  2468. X      string2 = string1;
  2469. X      size2 = size1;
  2470. X      string1 = 0;
  2471. X      size1 = 0;
  2472. X    }
  2473. X  end1 = string1 + size1;
  2474. X  end2 = string2 + size2;
  2475. X
  2476. X  /* Compute where to stop matching, within the two strings */
  2477. X  if (mstop <= size1)
  2478. X    {
  2479. X      end_match_1 = string1 + mstop;
  2480. X      end_match_2 = string2;
  2481. X    }
  2482. X  else
  2483. X    {
  2484. X      end_match_1 = end1;
  2485. X      end_match_2 = string2 + mstop - size1;
  2486. X    }
  2487. X
  2488. X  /* Initialize \) text positions to -1
  2489. X     to mark ones that no \( or \) has been seen for.  */
  2490. X
  2491. X  for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
  2492. X    regend[mcnt] = (unsigned char *) -1;
  2493. X
  2494. X  /* `p' scans through the pattern as `d' scans through the data.
  2495. X     `dend' is the end of the input string that `d' points within.
  2496. X     `d' is advanced into the following input string whenever necessary,
  2497. X     but this happens before fetching;
  2498. X     therefore, at the beginning of the loop,
  2499. X     `d' can be pointing at the end of a string,
  2500. X     but it cannot equal string2.  */
  2501. X
  2502. X  if (pos <= size1)
  2503. X    d = string1 + pos, dend = end_match_1;
  2504. X  else
  2505. X    d = string2 + pos - size1, dend = end_match_2;
  2506. X
  2507. X/* Write PREFETCH; just before fetching a character with *d.  */
  2508. X#define PREFETCH \
  2509. X while (d == dend)                            \
  2510. X  { if (dend == end_match_2) goto fail;  /* end of string2 => failure */   \
  2511. X    d = string2;  /* end of string1 => advance to string2. */       \
  2512. X    dend = end_match_2; }
  2513. X
  2514. X  /* This loop loops over pattern commands.
  2515. X     It exits by returning from the function if match is complete,
  2516. X     or it drops through if match fails at this starting point in the input data. */
  2517. X
  2518. X  while (1)
  2519. X    {
  2520. X      if (p == pend)
  2521. X    /* End of pattern means we have succeeded! */
  2522. X    {
  2523. X      /* If caller wants register contents data back, convert it to indices */
  2524. X      if (regs)
  2525. X        {
  2526. X           regs->start[0] = pos;
  2527. X           if (dend == end_match_1)
  2528. X         regs->end[0] = d - string1;
  2529. X           else
  2530. X         regs->end[0] = d - string2 + size1;
  2531. X           for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
  2532. X        {
  2533. X          if (regend[mcnt] == (unsigned char *) -1)
  2534. X            {
  2535. X              regs->start[mcnt] = -1;
  2536. X              regs->end[mcnt] = -1;
  2537. X              continue;
  2538. X            }
  2539. X           if (regstart_seg1[mcnt])
  2540. X            regs->start[mcnt] = regstart[mcnt] - string1;
  2541. X          else
  2542. X            regs->start[mcnt] = regstart[mcnt] - string2 + size1;
  2543. X           if (regend_seg1[mcnt])
  2544. X            regs->end[mcnt] = regend[mcnt] - string1;
  2545. X          else
  2546. X            regs->end[mcnt] = regend[mcnt] - string2 + size1;
  2547. X        }
  2548. X        }
  2549. X       if (dend == end_match_1)
  2550. X        return (d - string1 - pos);
  2551. X      else
  2552. X        return d - string2 + size1 - pos;
  2553. X    }
  2554. X
  2555. X      /* Otherwise match next pattern command */
  2556. X#ifdef SWITCH_ENUM_BUG
  2557. X      switch ((int) ((enum regexpcode) *p++))
  2558. X#else
  2559. X      switch ((enum regexpcode) *p++)
  2560. X#endif
  2561. X    {
  2562. X
  2563. X    /* \( is represented by a start_memory, \) by a stop_memory.
  2564. X        Both of those commands contain a "register number" argument.
  2565. X        The text matched within the \( and \) is recorded under that number.
  2566. X        Then, \<digit> turns into a `duplicate' command which
  2567. X        is followed by the numeric value of <digit> as the register number. */
  2568. X
  2569. X    case start_memory:
  2570. X      regstart[*p] = d;
  2571. X       regstart_seg1[*p++] = (dend == end_match_1);
  2572. X      break;
  2573. X
  2574. X    case stop_memory:
  2575. X      regend[*p] = d;
  2576. X       regend_seg1[*p++] = (dend == end_match_1);
  2577. X      break;
  2578. X
  2579. X    case duplicate:
  2580. X      {
  2581. X        int regno = *p++;   /* Get which register to match against */
  2582. X        register unsigned char *d2, *dend2;
  2583. X
  2584. X        /* Don't allow matching a register that hasn't been used.
  2585. X           This isn't fully reliable in the current version,
  2586. X           but it is better than crashing.  */
  2587. X        if ((int) regend[regno] <= -1)
  2588. X          goto fail;
  2589. X
  2590. X        d2 = regstart[regno];
  2591. X         dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
  2592. X             ? regend[regno] : end_match_1);
  2593. X        while (1)
  2594. X          {
  2595. X        /* Advance to next segment in register contents, if necessary */
  2596. X        while (d2 == dend2)
  2597. X          {
  2598. X            if (dend2 == end_match_2) break;
  2599. X            if (dend2 == regend[regno]) break;
  2600. X            d2 = string2, dend2 = regend[regno];  /* end of string1 => advance to string2. */
  2601. X          }
  2602. X        /* At end of register contents => success */
  2603. X        if (d2 == dend2) break;
  2604. X
  2605. X        /* Advance to next segment in data being matched, if necessary */
  2606. X        PREFETCH;
  2607. X
  2608. X        /* mcnt gets # consecutive chars to compare */
  2609. X        mcnt = dend - d;
  2610. X        if (mcnt > dend2 - d2)
  2611. X          mcnt = dend2 - d2;
  2612. X        /* Compare that many; failure if mismatch, else skip them. */
  2613. X        if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt))
  2614. X          goto fail;
  2615. X        d += mcnt, d2 += mcnt;
  2616. X          }
  2617. X      }
  2618. X      break;
  2619. X
  2620. X    case anychar:
  2621. X      /* fetch a data character */
  2622. X      PREFETCH;
  2623. X      /* Match anything but a newline.  */
  2624. X      if ((translate ? translate[*d++] : *d++) == '\n')
  2625. X        goto fail;
  2626. X      break;
  2627. X
  2628. X    case charset:
  2629. X    case charset_not:
  2630. X      {
  2631. X        /* Nonzero for charset_not */
  2632. X        int not = 0;
  2633. X        register int c;
  2634. X        if (*(p - 1) == (unsigned char) charset_not)
  2635. X          not = 1;
  2636. X
  2637. X        /* fetch a data character */
  2638. X        PREFETCH;
  2639. X
  2640. X        if (translate)
  2641. X          c = translate [*d];
  2642. X        else
  2643. X          c = *d;
  2644. X
  2645. X        if (c < *p * BYTEWIDTH
  2646. X        && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  2647. X          not = !not;
  2648. X
  2649. X        p += 1 + *p;
  2650. X
  2651. X        if (!not) goto fail;
  2652. X        d++;
  2653. X        break;
  2654. X      }
  2655. X
  2656. X    case begline:
  2657. X      if (d == string1 || d[-1] == '\n')
  2658. X        break;
  2659. X      goto fail;
  2660. X
  2661. X    case endline:
  2662. X      if (d == end2
  2663. X          || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
  2664. X        break;
  2665. X      goto fail;
  2666. X
  2667. X    /* "or" constructs ("|") are handled by starting each alternative
  2668. X        with an on_failure_jump that points to the start of the next alternative.
  2669. X        Each alternative except the last ends with a jump to the joining point.
  2670. X        (Actually, each jump except for the last one really jumps
  2671. X         to the following jump, because tensioning the jumps is a hassle.) */
  2672. X
  2673. X    /* The start of a stupid repeat has an on_failure_jump that points
  2674. X       past the end of the repeat text.
  2675. X       This makes a failure point so that, on failure to match a repetition,
  2676. X       matching restarts past as many repetitions have been found
  2677. X       with no way to fail and look for another one.  */
  2678. X
  2679. X    /* A smart repeat is similar but loops back to the on_failure_jump
  2680. X       so that each repetition makes another failure point. */
  2681. X
  2682. X    case on_failure_jump:
  2683. X      if (stackp == stacke)
  2684. X        {
  2685. X          unsigned char **stackx;
  2686. X          if (stacke - stackb > re_max_failures)
  2687. X        return -2;
  2688. X          stackx = (unsigned char **) alloca (2 * (stacke - stackb)
  2689. X                     * sizeof (char *));
  2690. X          bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
  2691. X          stackp = stackx + (stackp - stackb);
  2692. X          stacke = stackx + 2 * (stacke - stackb);
  2693. X          stackb = stackx;
  2694. X        }
  2695. X      mcnt = *p++ & 0377;
  2696. X      mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2697. X      p++;
  2698. X      *stackp++ = mcnt + p;
  2699. X      *stackp++ = d;
  2700. X      break;
  2701. X
  2702. X    /* The end of a smart repeat has an maybe_finalize_jump back.
  2703. X       Change it either to a finalize_jump or an ordinary jump. */
  2704. X
  2705. X    case maybe_finalize_jump:
  2706. X      mcnt = *p++ & 0377;
  2707. X      mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2708. X      p++;
  2709. X      /* Compare what follows with the begining of the repeat.
  2710. X         If we can establish that there is nothing that they would
  2711. X         both match, we can change to finalize_jump */
  2712. X      if (p == pend)
  2713. X        p[-3] = (unsigned char) finalize_jump;
  2714. X      else if (*p == (unsigned char) exactn
  2715. X           || *p == (unsigned char) endline)
  2716. X        {
  2717. X          register int c = *p == (unsigned char) endline ? '\n' : p[2];
  2718. X          register unsigned char *p1 = p + mcnt;
  2719. X          /* p1[0] ... p1[2] are an on_failure_jump.
  2720. X         Examine what follows that */
  2721. X          if (p1[3] == (unsigned char) exactn && p1[5] != c)
  2722. X        p[-3] = (unsigned char) finalize_jump;
  2723. X          else if (p1[3] == (unsigned char) charset
  2724. X               || p1[3] == (unsigned char) charset_not)
  2725. X        {
  2726. X          int not = p1[3] == (unsigned char) charset_not;
  2727. X          if (c < p1[4] * BYTEWIDTH
  2728. X              && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  2729. X            not = !not;
  2730. X          /* not is 1 if c would match */
  2731. X          /* That means it is not safe to finalize */
  2732. X          if (!not)
  2733. X            p[-3] = (unsigned char) finalize_jump;
  2734. X        }
  2735. X        }
  2736. X      p -= 2;
  2737. X      if (p[-1] != (unsigned char) finalize_jump)
  2738. X        {
  2739. X          p[-1] = (unsigned char) jump;
  2740. X          goto nofinalize;
  2741. X        }
  2742. X
  2743. X    /* The end of a stupid repeat has a finalize-jump
  2744. X       back to the start, where another failure point will be made
  2745. X       which will point after all the repetitions found so far. */
  2746. X
  2747. X    case finalize_jump:
  2748. X      stackp -= 2;
  2749. X
  2750. X    case jump:
  2751. X    nofinalize:
  2752. X      mcnt = *p++ & 0377;
  2753. X      mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
  2754. X      p += mcnt + 1;    /* The 1 compensates for missing ++ above */
  2755. X      break;
  2756. X
  2757. X    case dummy_failure_jump:
  2758. X      if (stackp == stacke)
  2759. X        {
  2760. X          unsigned char **stackx
  2761. X        = (unsigned char **) alloca (2 * (stacke - stackb)
  2762. X                         * sizeof (char *));
  2763. X          bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
  2764. X          stackp = stackx + (stackp - stackb);
  2765. X          stacke = stackx + 2 * (stacke - stackb);
  2766. X          stackb = stackx;
  2767. X        }
  2768. X      *stackp++ = 0;
  2769. X      *stackp++ = 0;
  2770. X      goto nofinalize;
  2771. X
  2772. X    case wordbound:
  2773. X      if (d == string1  /* Points to first char */
  2774. X          || d == end2  /* Points to end */
  2775. X          || (d == end1 && size2 == 0)) /* Points to end */
  2776. X        break;
  2777. X      if ((SYNTAX (d[-1]) == Sword)
  2778. X          != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
  2779. X        break;
  2780. X      goto fail;
  2781. X
  2782. X    case notwordbound:
  2783. X      if (d == string1  /* Points to first char */
  2784. X          || d == end2  /* Points to end */
  2785. X          || (d == end1 && size2 == 0)) /* Points to end */
  2786. X        goto fail;
  2787. X      if ((SYNTAX (d[-1]) == Sword)
  2788. X          != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
  2789. X        goto fail;
  2790. X      break;
  2791. X
  2792. X    case wordbeg:
  2793. X      if (d == end2  /* Points to end */
  2794. X          || (d == end1 && size2 == 0) /* Points to end */
  2795. X          || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
  2796. X        goto fail;
  2797. X      if (d == string1  /* Points to first char */
  2798. X          || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
  2799. X        break;
  2800. X      goto fail;
  2801. X
  2802. X    case wordend:
  2803. X      if (d == string1  /* Points to first char */
  2804. X          || SYNTAX (d[-1]) != Sword)  /* prev char not letter */
  2805. X        goto fail;
  2806. X      if (d == end2  /* Points to end */
  2807. X          || (d == end1 && size2 == 0) /* Points to end */
  2808. X          || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
  2809. X        break;
  2810. X      goto fail;
  2811. X
  2812. X#ifdef emacs
  2813. X    case before_dot:
  2814. X      if (PTR_CHAR_POS (d) + 1 >= point)
  2815. X        goto fail;
  2816. X      break;
  2817. X
  2818. X    case at_dot:
  2819. X      if (PTR_CHAR_POS (d) + 1 != point)
  2820. X        goto fail;
  2821. X      break;
  2822. X
  2823. X    case after_dot:
  2824. X      if (PTR_CHAR_POS (d) + 1 <= point)
  2825. X        goto fail;
  2826. X      break;
  2827. X
  2828. X    case wordchar:
  2829. X      mcnt = (int) Sword;
  2830. X      goto matchsyntax;
  2831. X
  2832. X    case syntaxspec:
  2833. X      mcnt = *p++;
  2834. X    matchsyntax:
  2835. X      PREFETCH;
  2836. X      if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
  2837. X      break;
  2838. X      
  2839. X    case notwordchar:
  2840. X      mcnt = (int) Sword;
  2841. X      goto matchnotsyntax;
  2842. X
  2843. X    case notsyntaxspec:
  2844. X      mcnt = *p++;
  2845. X    matchnotsyntax:
  2846. X      PREFETCH;
  2847. X      if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
  2848. X      break;
  2849. X#else
  2850. X    case wordchar:
  2851. X      PREFETCH;
  2852. X      if (SYNTAX (*d++) == 0) goto fail;
  2853. X      break;
  2854. X      
  2855. X    case notwordchar:
  2856. X      PREFETCH;
  2857. X      if (SYNTAX (*d++) != 0) goto fail;
  2858. X      break;
  2859. X#endif not emacs
  2860. X
  2861. X    case begbuf:
  2862. X      if (d == string1)    /* Note, d cannot equal string2 */
  2863. X        break;        /* unless string1 == string2.  */
  2864. X      goto fail;
  2865. X
  2866. X    case endbuf:
  2867. X      if (d == end2 || (d == end1 && size2 == 0))
  2868. X        break;
  2869. X      goto fail;
  2870. X
  2871. X    case exactn:
  2872. X      /* Match the next few pattern characters exactly.
  2873. X         mcnt is how many characters to match. */
  2874. X      mcnt = *p++;
  2875. X      if (translate)
  2876. X        {
  2877. X          do
  2878. X        {
  2879. X          PREFETCH;
  2880. X          if (translate[*d++] != *p++) goto fail;
  2881. X        }
  2882. X          while (--mcnt);
  2883. X        }
  2884. X      else
  2885. X        {
  2886. X          do
  2887. X        {
  2888. X          PREFETCH;
  2889. X          if (*d++ != *p++) goto fail;
  2890. X        }
  2891. X          while (--mcnt);
  2892. X        }
  2893. X      break;
  2894. X    }
  2895. X      continue;    /* Successfully matched one pattern command; keep matching */
  2896. X
  2897. X      /* Jump here if any matching operation fails. */
  2898. X    fail:
  2899. X      if (stackp != stackb)
  2900. X    /* A restart point is known.  Restart there and pop it. */
  2901. X    {
  2902. X      if (!stackp[-2])
  2903. X        {   /* If innermost failure point is dormant, flush it and keep looking */
  2904. X          stackp -= 2;
  2905. X          goto fail;
  2906. X        }
  2907. X      d = *--stackp;
  2908. X      p = *--stackp;
  2909. X      if (d >= string1 && d <= end1)
  2910. X        dend = end_match_1;
  2911. X    }
  2912. X      else break;   /* Matching at this starting point really fails! */
  2913. X    }
  2914. X  return -1;         /* Failure to match */
  2915. X}
  2916. X
  2917. Xstatic int
  2918. Xbcmp_translate (s1, s2, len, translate)
  2919. X     unsigned char *s1, *s2;
  2920. X     register int len;
  2921. X     unsigned char *translate;
  2922. X{
  2923. X  register unsigned char *p1 = s1, *p2 = s2;
  2924. X  while (len)
  2925. X    {
  2926. X      if (translate [*p1++] != translate [*p2++]) return 1;
  2927. X      len--;
  2928. X    }
  2929. X  return 0;
  2930. X}
  2931. X
  2932. X/* Entry points compatible with bsd4.2 regex library */
  2933. X
  2934. X#ifndef emacs
  2935. X
  2936. Xstatic struct re_pattern_buffer re_comp_buf;
  2937. X
  2938. Xchar *
  2939. Xre_comp (s)
  2940. X     char *s;
  2941. X{
  2942. X  if (!s)
  2943. X    {
  2944. X      if (!re_comp_buf.buffer)
  2945. X    return "No previous regular expression";
  2946. X      return 0;
  2947. X    }
  2948. X
  2949. X  if (!re_comp_buf.buffer)
  2950. X    {
  2951. X      if (!(re_comp_buf.buffer = (char *) malloc (200)))
  2952. X    return "Memory exhausted";
  2953. X      re_comp_buf.allocated = 200;
  2954. X      if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
  2955. X    return "Memory exhausted";
  2956. X    }
  2957. X  return re_compile_pattern (s, strlen (s), &re_comp_buf);
  2958. X}
  2959. X
  2960. Xint
  2961. Xre_exec (s)
  2962. X     char *s;
  2963. X{
  2964. X  int len = strlen (s);
  2965. X  return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0);
  2966. X}
  2967. X
  2968. X#endif /* emacs */
  2969. X
  2970. X#ifdef test
  2971. X
  2972. X#include <stdio.h>
  2973. X
  2974. X/* Indexed by a character, gives the upper case equivalent of the character */
  2975. X
  2976. Xstatic char upcase[0400] = 
  2977. X  { 000, 001, 002, 003, 004, 005, 006, 007,
  2978. X    010, 011, 012, 013, 014, 015, 016, 017,
  2979. X    020, 021, 022, 023, 024, 025, 026, 027,
  2980. X    030, 031, 032, 033, 034, 035, 036, 037,
  2981. X    040, 041, 042, 043, 044, 045, 046, 047,
  2982. X    050, 051, 052, 053, 054, 055, 056, 057,
  2983. X    060, 061, 062, 063, 064, 065, 066, 067,
  2984. X    070, 071, 072, 073, 074, 075, 076, 077,
  2985. X    0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  2986. X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  2987. X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  2988. X    0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
  2989. X    0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  2990. X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  2991. X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  2992. X    0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
  2993. X    0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  2994. X    0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
  2995. X    0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
  2996. X    0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
  2997. X    0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
  2998. X    0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  2999. X    0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  3000. X    0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  3001. X    0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  3002. X    0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
  3003. X    0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
  3004. X    0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  3005. X    0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  3006. X    0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
  3007. X    0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  3008. X    0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
  3009. X  };
  3010. X
  3011. Xmain (argc, argv)
  3012. X     int argc;
  3013. X     char **argv;
  3014. X{
  3015. X  char pat[80];
  3016. X  struct re_pattern_buffer buf;
  3017. X  int i;
  3018. X  char c;
  3019. X  char fastmap[(1 << BYTEWIDTH)];
  3020. X
  3021. X  /* Allow a command argument to specify the style of syntax.  */
  3022. X  if (argc > 1)
  3023. X    obscure_syntax = atoi (argv[1]);
  3024. X
  3025. X  buf.allocated = 40;
  3026. X  buf.buffer = (char *) malloc (buf.allocated);
  3027. X  buf.fastmap = fastmap;
  3028. X  buf.translate = upcase;
  3029. X
  3030. X  while (1)
  3031. X    {
  3032. X      gets (pat);
  3033. X
  3034. X      if (*pat)
  3035. X    {
  3036. X          re_compile_pattern (pat, strlen(pat), &buf);
  3037. X
  3038. X      for (i = 0; i < buf.used; i++)
  3039. X        printchar (buf.buffer[i]);
  3040. X
  3041. X      putchar ('\n');
  3042. X
  3043. X      printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
  3044. X
  3045. X      re_compile_fastmap (&buf);
  3046. X      printf ("Allowed by fastmap: ");
  3047. X      for (i = 0; i < (1 << BYTEWIDTH); i++)
  3048. X        if (fastmap[i]) printchar (i);
  3049. X      putchar ('\n');
  3050. X    }
  3051. X
  3052. X      gets (pat);    /* Now read the string to match against */
  3053. X
  3054. X      i = re_match (&buf, pat, strlen (pat), 0, 0);
  3055. X      printf ("Match value %d.\n", i);
  3056. X    }
  3057. X}
  3058. X
  3059. X#ifdef NOTDEF
  3060. Xprint_buf (bufp)
  3061. X     struct re_pattern_buffer *bufp;
  3062. X{
  3063. X  int i;
  3064. X
  3065. X  printf ("buf is :\n----------------\n");
  3066. X  for (i = 0; i < bufp->used; i++)
  3067. X    printchar (bufp->buffer[i]);
  3068. X  
  3069. X  printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
  3070. X  
  3071. X  printf ("Allowed by fastmap: ");
  3072. X  for (i = 0; i < (1 << BYTEWIDTH); i++)
  3073. X    if (bufp->fastmap[i])
  3074. X      printchar (i);
  3075. X  printf ("\nAllowed by translate: ");
  3076. X  if (bufp->translate)
  3077. X    for (i = 0; i < (1 << BYTEWIDTH); i++)
  3078. X      if (bufp->translate[i])
  3079. X    printchar (i);
  3080. X  printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
  3081. X  printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
  3082. X}
  3083. X#endif
  3084. X
  3085. Xprintchar (c)
  3086. X     char c;
  3087. X{
  3088. X  if (c < 041 || c >= 0177)
  3089. X    {
  3090. X      putchar ('\\');
  3091. X      putchar (((c >> 6) & 3) + '0');
  3092. X      putchar (((c >> 3) & 7) + '0');
  3093. X      putchar ((c & 7) + '0');
  3094. X    }
  3095. X  else
  3096. X    putchar (c);
  3097. X}
  3098. X
  3099. Xerror (string)
  3100. X     char *string;
  3101. X{
  3102. X  puts (string);
  3103. X  exit (1);
  3104. X}
  3105. X
  3106. X#endif test
  3107. SHAR_EOF
  3108. len=`wc -c < regex.c`
  3109. if test $len !=    44540 ; then
  3110. echo error: regex.c was $len bytes long, should have been    44540
  3111. fi
  3112. fi # end of overwriting check
  3113. exit 0
  3114. -- 
  3115.         -ed falk, sun microsystems
  3116.          sun!falk, falk@sun.com
  3117.       He who dies with the most friends, wins.
  3118.