heirloom-ed

changeset 0:1493bea5ac22 0.1

Initial version of the standalone heirloom-ed
author markus schnalke <meillo@marmaro.de>
date Mon, 05 Sep 2011 16:31:35 +0200
parents
children db609ba8ab93
files LICENSE README ed.1 ed.c makefile regexp.h regexpr.c regexpr.h sigrelse.c sigset.c sigset.h
diffstat 11 files changed, 5368 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LICENSE	Mon Sep 05 16:31:35 2011 +0200
     1.3 @@ -0,0 +1,1 @@
     1.4 +Look into the source files directly.
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/README	Mon Sep 05 16:31:35 2011 +0200
     2.3 @@ -0,0 +1,22 @@
     2.4 +Ed -- The Standard Text Editor
     2.5 +==============================
     2.6 +
     2.7 +This version of ed had been cut out of Gunnar Ritter's Heirloom Toolchest.
     2.8 +The reason for doing so is to have Heirloom ed quickly at hand when I am
     2.9 +annoyed again by GNU ed. Having to configure and install the complete
    2.10 +Heirloom Toolchest is more than I usually want. This ed is slightly
    2.11 +stripped down as only the traditional variant gets created. Any references
    2.12 +to the other variants and features only in them are removed from the man
    2.13 +page. Parts of libcommon had been ripped out and included directly. Thus
    2.14 +the makefile had been reworked.
    2.15 +
    2.16 +To install do:
    2.17 +
    2.18 +	vi makefile
    2.19 +	make
    2.20 +	make install
    2.21 +
    2.22 +
    2.23 +2011-09-05
    2.24 +markus schnalke <meillo@marmaro.de>
    2.25 +http://hg.marmaro.de/heirloom-ed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ed.1	Mon Sep 05 16:31:35 2011 +0200
     3.3 @@ -0,0 +1,914 @@
     3.4 +'\" t
     3.5 +.\" Sccsid @(#)ed.1	1.48 (gritter) 6/22/05
     3.6 +.\" Parts taken from ed(1), Unix 7th edition:
     3.7 +.\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
     3.8 +.\"
     3.9 +.\" Redistribution and use in source and binary forms, with or without
    3.10 +.\" modification, are permitted provided that the following conditions
    3.11 +.\" are met:
    3.12 +.\"   Redistributions of source code and documentation must retain the
    3.13 +.\"    above copyright notice, this list of conditions and the following
    3.14 +.\"    disclaimer.
    3.15 +.\"   Redistributions in binary form must reproduce the above copyright
    3.16 +.\"    notice, this list of conditions and the following disclaimer in the
    3.17 +.\"    documentation and/or other materials provided with the distribution.
    3.18 +.\"   All advertising materials mentioning features or use of this software
    3.19 +.\"    must display the following acknowledgement:
    3.20 +.\"      This product includes software developed or owned by Caldera
    3.21 +.\"      International, Inc.
    3.22 +.\"   Neither the name of Caldera International, Inc. nor the names of
    3.23 +.\"    other contributors may be used to endorse or promote products
    3.24 +.\"    derived from this software without specific prior written permission.
    3.25 +.\"
    3.26 +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    3.27 +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    3.28 +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    3.29 +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    3.30 +.\" ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    3.31 +.\" LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    3.32 +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    3.33 +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    3.34 +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    3.35 +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    3.36 +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    3.37 +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    3.38 +.TH ED 1 "6/22/05" "Heirloom Toolchest" "User Commands"
    3.39 +.if t .ds q \(aa
    3.40 +.if n .ds q '
    3.41 +.SH NAME
    3.42 +ed \- text editor
    3.43 +.SH SYNOPSIS
    3.44 +\fBed\fR [\fB\-\fR\ |\ \fB\-s\fR] [\fB\-p\fI\ prompt\fR] [\fIname\fR]
    3.45 +.SH DESCRIPTION
    3.46 +.I Ed
    3.47 +is the standard text editor.
    3.48 +.PP
    3.49 +If a
    3.50 +.I name
    3.51 +argument is given,
    3.52 +.I ed
    3.53 +simulates an
    3.54 +.I e
    3.55 +command (see below)\| on the named file; that is to say,
    3.56 +the file is read into
    3.57 +.IR ed 's
    3.58 +buffer so that it can be edited.
    3.59 +The optional
    3.60 +.B \-
    3.61 +or
    3.62 +.B \-s
    3.63 +suppresses the printing
    3.64 +of character counts by
    3.65 +.IR e ,
    3.66 +.IR r ,
    3.67 +and
    3.68 +.I w
    3.69 +commands,
    3.70 +and of the `!' after completion of a shell command.
    3.71 +.PP
    3.72 +With the
    3.73 +.B \-p
    3.74 +option,
    3.75 +the given
    3.76 +.I prompt
    3.77 +string is printed before each command is read.
    3.78 +.PP
    3.79 +.I Ed
    3.80 +operates on a copy of any file it is editing; changes made
    3.81 +in the copy have no effect on the file until a
    3.82 +.IR w ""
    3.83 +(write)\|
    3.84 +command is given.
    3.85 +The copy of the text being edited resides
    3.86 +in a temporary file called the 
    3.87 +.IR buffer .
    3.88 +.PP
    3.89 +The editor supports format specifications as defined in
    3.90 +.IR fspec (5).
    3.91 +If the terminal is configured to expand tabulators
    3.92 +(as enabled with
    3.93 +.I stty tab3
    3.94 +or
    3.95 +.IR "stty \-tabs"),
    3.96 +and the first line of the file being edited
    3.97 +contains a format specification,
    3.98 +the
    3.99 +.I t
   3.100 +and
   3.101 +.I s
   3.102 +are interpreted,
   3.103 +that is, tabulators are expanded and lines are truncated
   3.104 +when printing to the terminal. For example,
   3.105 +.RS
   3.106 +<:t\-f s72:>
   3.107 +.sp
   3.108 +.RE
   3.109 +selects FORTRAN format and truncates lines at 72 characters.
   3.110 +No expansion or truncation is performed by
   3.111 +.I ed
   3.112 +when input is typed to the terminal.
   3.113 +.PP
   3.114 +Commands to
   3.115 +.I ed
   3.116 +have a simple and regular structure: zero or
   3.117 +more
   3.118 +.I addresses
   3.119 +followed by a single character
   3.120 +.I command,
   3.121 +possibly
   3.122 +followed by parameters to the command.
   3.123 +These addresses specify one or more lines in the buffer.
   3.124 +Missing addresses are supplied by default.
   3.125 +.PP
   3.126 +In general, only one command may appear on a line.
   3.127 +Certain commands allow the 
   3.128 +addition of text to the buffer.
   3.129 +While
   3.130 +.I ed
   3.131 +is accepting text, it is said
   3.132 +to be in
   3.133 +.I  "input mode."
   3.134 +In this mode, no commands are recognized;
   3.135 +all input is merely collected.
   3.136 +Input mode is left by typing a period `\fB.\fR' alone at the
   3.137 +beginning of a line.
   3.138 +.PP
   3.139 +.I Ed
   3.140 +supports a limited form of
   3.141 +.I "regular expression"
   3.142 +notation.
   3.143 +A regular expression specifies
   3.144 +a set of strings of characters.
   3.145 +A member of this set of strings is said to be
   3.146 +.I matched
   3.147 +by the regular expression.
   3.148 +In the following specification for regular expressions
   3.149 +the word `character' means any character but newline.
   3.150 +.B ed
   3.151 +uses simple regular expressions.
   3.152 +.SS "Simple Regular Expressions"
   3.153 +.IP 1.
   3.154 +Any character except a special character
   3.155 +matches itself.
   3.156 +Special characters are
   3.157 +the regular expression delimiter plus
   3.158 +.RB \e\|[\| .
   3.159 +and sometimes ^\|*\|$.
   3.160 +.IP 2.
   3.161 +A
   3.162 +.B .\&
   3.163 +matches any character.
   3.164 +.IP 3.
   3.165 +A \fB\e\fR followed by any character except a digit
   3.166 +or (\|) {\|} <\|> matches that character.
   3.167 +.IP 4.
   3.168 +A nonempty string
   3.169 +.I s
   3.170 +bracketed
   3.171 +\fB[\fI\|s\|\fB]\fR
   3.172 +(or
   3.173 +\fB[^\fIs\|\fB]\fR)
   3.174 +forms a \fIbracket expression\fR that
   3.175 +matches any character in (or not in)
   3.176 +.I s.
   3.177 +In 
   3.178 +.I s,
   3.179 +\e has no special meaning, and ] may only appear as
   3.180 +the first letter.
   3.181 +A substring 
   3.182 +\fIa\fB\-\fIb\fR,
   3.183 +with
   3.184 +.I a
   3.185 +and
   3.186 +.I b
   3.187 +in ascending ASCII order, stands for the inclusive
   3.188 +range of ASCII characters.
   3.189 +.IP 5.
   3.190 +A regular expression of form 1-4 followed by \fB*\fR matches a sequence of
   3.191 +0 or more matches of the regular expression.
   3.192 +.IP 6.
   3.193 +A regular expression of form 1-4
   3.194 +followed by \fB\e{\fIm\fB,\fIn\fB\e}\fR
   3.195 +forms an \fIinterval expression\fR that
   3.196 +matches a sequence of \fIm\fR through \fIn\fR matches, inclusive,
   3.197 +of the regular expression.
   3.198 +The values of \fIm\fR and \fIn\fR must be non-negative
   3.199 +and smaller than 256.
   3.200 +The form \fB\e{\fIm\fB\e}\fR matches exactly \fIm\fR occurrences,
   3.201 +\fB\e{\fIm\fB,\e}\fR matches at least \fIm\fR occurrences.
   3.202 +.IP 7.
   3.203 +The sequence \fB\e<\fR forces the match
   3.204 +to occur only at the beginning of a ``variable'' or ``word'';
   3.205 +that is, either at the beginning of a line,
   3.206 +or just before a letter, digit or underline
   3.207 +and after a character not one of these.
   3.208 +.IP 8.
   3.209 +The sequence \fB\e>\fR matches the end
   3.210 +of a ``variable'' or ``word'',
   3.211 +i.\|e. either the end of the line
   3.212 +or before character which is neither a letter,
   3.213 +nor a digit, nor the underline character.
   3.214 +.IP 9.
   3.215 +A regular expression,
   3.216 +.I x,
   3.217 +of form 1-11, parenthesized
   3.218 +\fB\e(\fI\|x\|\fB\e)\fR
   3.219 +is called a \fIsubexpression\fR and
   3.220 +matches what
   3.221 +.I x
   3.222 +matches.
   3.223 +.IP 10.
   3.224 +A \fB\e\fR followed by a digit 
   3.225 +.I n
   3.226 +forms a \fIbackreference\fR and
   3.227 +matches a copy of the string that the
   3.228 +parenthesized regular expression beginning with the
   3.229 +.IR n th
   3.230 +\e( matched.
   3.231 +.IP 11.
   3.232 +A regular expression of form 1-11,
   3.233 +.I x,
   3.234 +followed by a regular expression of form 1-10,
   3.235 +.I y
   3.236 +matches a match for
   3.237 +.I x
   3.238 +followed by a match for
   3.239 +.I y,
   3.240 +with the
   3.241 +.I x
   3.242 +match being as long as possible while still permitting a
   3.243 +.I y
   3.244 +match.
   3.245 +.IP 12.
   3.246 +A regular expression of form 1-11 preceded by \fB^\fR
   3.247 +(or followed by \fB$\fR), is constrained to matches that
   3.248 +begin at the left (or end at the right) end of a line
   3.249 +(\fIanchoring\fR).
   3.250 +.IP 13.
   3.251 +A regular expression of form 1-12 picks out the
   3.252 +longest among the leftmost matches in a line.
   3.253 +.IP 14.
   3.254 +An empty regular expression stands for a copy of the
   3.255 +last regular expression encountered.
   3.256 +.PP
   3.257 +Regular expressions are used in addresses to specify
   3.258 +lines and in one command
   3.259 +(see
   3.260 +.I s
   3.261 +below)\|
   3.262 +to specify a portion of a line which is to be replaced.
   3.263 +If it is desired to use one of
   3.264 +the regular expression metacharacters as an ordinary
   3.265 +character, that character may be preceded by `\e'.
   3.266 +This also applies to the character bounding the regular
   3.267 +expression (often `/')\| and to `\e' itself.
   3.268 +.PP
   3.269 +To understand addressing in
   3.270 +.I ed
   3.271 +it is necessary to know that at any time there is a
   3.272 +.I  "current line."
   3.273 +Generally speaking, the current line is
   3.274 +the last line affected by a command; however,
   3.275 +the exact effect on the current line
   3.276 +is discussed under the description of
   3.277 +the command.
   3.278 +Addresses are constructed as follows.
   3.279 +.TP
   3.280 +1.
   3.281 +The character `\fB.\fR' addresses the current line.
   3.282 +.TP
   3.283 +2.
   3.284 +The character `\fB$\fR' addresses the last line of the buffer.
   3.285 +.TP
   3.286 +3.
   3.287 +A decimal number
   3.288 +.I n
   3.289 +addresses the
   3.290 +.IR n -th
   3.291 +line of the buffer.
   3.292 +.TP
   3.293 +4.
   3.294 +`\fB\(fm\fIx\fR' addresses the line marked with the name
   3.295 +.IR x ,
   3.296 +which must be a lower-case letter.
   3.297 +Lines are marked with the
   3.298 +.I k
   3.299 +command described below.
   3.300 +.TP
   3.301 +5.
   3.302 +A regular expression enclosed in slashes `\fB/\fR' addresses
   3.303 +the line found by searching forward from the current line
   3.304 +and stopping at the first line containing a
   3.305 +string that matches the regular expression.
   3.306 +If necessary the search wraps around to the beginning of the
   3.307 +buffer.
   3.308 +.TP
   3.309 +6.
   3.310 +A regular expression enclosed in queries `\fB?\fR' addresses
   3.311 +the line found by searching backward from the current line
   3.312 +and stopping at the first line containing
   3.313 +a string that matches the regular expression.
   3.314 +If necessary
   3.315 +the search wraps around to the end of the buffer.
   3.316 +.TP
   3.317 +7.
   3.318 +An address followed by a plus sign `\fB+\fR'
   3.319 +or a minus sign `\fB\-\fR' followed by a decimal number
   3.320 +specifies that address plus
   3.321 +(resp. minus)\| the indicated number of lines.
   3.322 +The plus sign may be omitted.
   3.323 +.TP
   3.324 +8.
   3.325 +If an address begins with `\fB+\fR' or `\fB\-\fR'
   3.326 +the addition or subtraction is taken with respect to the current line;
   3.327 +e.g. `\-5' is understood to mean `\fB.\fR\-5'.
   3.328 +.TP
   3.329 +9.
   3.330 +If an address ends with `\fB+\fR' or `\fB\-\fR',
   3.331 +then 1 is added (resp. subtracted).
   3.332 +As a consequence of this rule and rule 8,
   3.333 +the address `\-' refers to the line before the current line.
   3.334 +Moreover,
   3.335 +trailing
   3.336 +`+' and `\-' characters
   3.337 +have cumulative effect, so `\-\-' refers to the current
   3.338 +line less 2.
   3.339 +.TP
   3.340 +10.
   3.341 +To maintain compatibility with earlier versions of the editor,
   3.342 +the character `\fB^\fR' in addresses is 
   3.343 +equivalent to `\-'.
   3.344 +.PP
   3.345 +Commands may require zero, one, or two addresses.
   3.346 +Commands which require no addresses regard the presence
   3.347 +of an address as an error.
   3.348 +Commands which accept one or two addresses
   3.349 +assume default addresses when insufficient are given.
   3.350 +If more addresses are given than such a command requires,
   3.351 +the last one or two (depending on what is accepted)\| are used.
   3.352 +.PP
   3.353 +Addresses are separated from each other typically by a comma
   3.354 +`\fB,\fR'.
   3.355 +They may also be separated by a semicolon
   3.356 +`\fB;\fR'.
   3.357 +In this case the current line `\fB.\fR' is set to
   3.358 +the previous address before the next address is interpreted.
   3.359 +This feature can be used to determine the starting
   3.360 +line for forward and backward searches (`/', `?')\|.
   3.361 +The second address of any two-address sequence
   3.362 +must correspond to a line following the line corresponding to the first address.
   3.363 +.PP
   3.364 +Omission of the first address causes
   3.365 +the first line to be used with `,',
   3.366 +or the current line with `;', respectively;
   3.367 +if the second address is also omitted,
   3.368 +the last line of the buffer is used.
   3.369 +Thus a single `,' specifies the entire contents of the buffer,
   3.370 +and a single `;' specifies the contents
   3.371 +ranging from the current line to the last one.
   3.372 +.PP
   3.373 +In the following list of
   3.374 +.I ed
   3.375 +commands, the default addresses
   3.376 +are shown in parentheses.
   3.377 +The parentheses are not part of
   3.378 +the address, but are used to show that the given addresses are
   3.379 +the default.
   3.380 +.PP
   3.381 +As mentioned, it is generally illegal for more than one
   3.382 +command to appear on a line.
   3.383 +However, most commands may be suffixed by `p', `l', or `n',
   3.384 +in which case
   3.385 +the current line is either
   3.386 +printed, listed, or numbered respectively
   3.387 +in the way discussed below.
   3.388 +.TP 5
   3.389 +\fR(\|\fI.\|\fR)\fB\|a\fR
   3.390 +.br
   3.391 +.ns
   3.392 +.TP 5
   3.393 +<text>
   3.394 +.br
   3.395 +.ns
   3.396 +.TP 5
   3.397 +.B .
   3.398 +.br
   3.399 +The append command reads the given text
   3.400 +and appends it after the addressed line.
   3.401 +`\fB.\fR' is left
   3.402 +on the last line input, if there
   3.403 +were any, otherwise at the addressed line.
   3.404 +Address `0' is legal for this command; text is placed
   3.405 +at the beginning of the buffer.
   3.406 +.TP 5
   3.407 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBc\fR
   3.408 +.br
   3.409 +.ns
   3.410 +.TP 5
   3.411 +<text>
   3.412 +.br
   3.413 +.ns
   3.414 +.TP 5
   3.415 +.B .
   3.416 +.br
   3.417 +The change
   3.418 +command deletes the addressed lines, then accepts input
   3.419 +text which replaces these lines.
   3.420 +`\fB.\fR' is left at the last line input; if there were none,
   3.421 +it is left at the line preceding the deleted lines.
   3.422 +.TP 5
   3.423 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBd\fR
   3.424 +The delete command deletes the addressed lines from the buffer.
   3.425 +The line originally after the last line deleted becomes the current line;
   3.426 +if the lines deleted were originally at the end,
   3.427 +the new last line becomes the current line.
   3.428 +.TP 5
   3.429 +\fBe\ \fIfilename\fR
   3.430 +The edit
   3.431 +command causes the entire contents of the buffer to be deleted,
   3.432 +and then the named file to be read in.
   3.433 +`\fB.\fR' is set to the last line of the buffer.
   3.434 +The number of characters read is typed.
   3.435 +`\fIfilename\fR' is remembered for possible use as a default file name
   3.436 +in a subsequent
   3.437 +.I r
   3.438 +or
   3.439 +.I w
   3.440 +command.
   3.441 +If `\fIfilename\fR' is missing, the remembered name is used.
   3.442 +A `\fIfilename\fR' starting with a `\fB!\fR'
   3.443 +causes the output of the shell command following this character
   3.444 +to be read in.
   3.445 +.TP 5
   3.446 +\fBE\ \fIfilename\fR
   3.447 +This command is the same as
   3.448 +.IR e ,
   3.449 +except that no diagnostic results when no
   3.450 +.I w
   3.451 +has been given since the last buffer alteration.
   3.452 +.TP 5
   3.453 +\fBf\ \fIfilename\fR
   3.454 +The filename command prints the currently remembered file name.
   3.455 +If `\fIfilename\fR' is given,
   3.456 +the currently remembered file name is changed to `\fIfilename\fR'.
   3.457 +.TP 5
   3.458 +\fR(\fI1\fB,\fI$\fR)\|\fBg/\fIregular expression\fB/\fIcommand list\fR
   3.459 +In the global
   3.460 +command, the first step is to mark every line which matches
   3.461 +the given \fIregular expression\fR.
   3.462 +Then for every such line, the
   3.463 +given \fIcommand list\fR is executed
   3.464 +with `\fB.\fR' initially set to that line.
   3.465 +A single command or the first of multiple commands
   3.466 +appears on the same line with the global command.
   3.467 +All lines of a multi-line list except the last line must be ended with `\e'.
   3.468 +.I A,
   3.469 +.I i,
   3.470 +and
   3.471 +.I c
   3.472 +commands and associated input are permitted;
   3.473 +the `\fB.\fR' terminating input mode may be omitted if it would be on the
   3.474 +last line of the command list.
   3.475 +The commands
   3.476 +.I g
   3.477 +and
   3.478 +.I v
   3.479 +are not permitted in the command list.
   3.480 +.TP 5
   3.481 +\fR(\fI1\fB,\fI$\fR)\|\fBG/\fIregular expression\fB/\fR
   3.482 +The interactive global command
   3.483 +first marks every line matching the given \fIregular expression\fR.
   3.484 +Then each line is printed
   3.485 +and a command is read and executed for this line.
   3.486 +A single newline character causes the line to remain unchanged,
   3.487 +an isolated `\fB&\fR' repeats the command given for the previous line.
   3.488 +The command can be terminated by an interrupt signal.
   3.489 +.TP 5
   3.490 +.B h
   3.491 +This command prints a verbose description for the
   3.492 +last error encountered.
   3.493 +.TP
   3.494 +.B H
   3.495 +This command acts like the
   3.496 +.I h
   3.497 +command,
   3.498 +but also causes verbose descriptions to be printed
   3.499 +on all following error conditions.
   3.500 +Another
   3.501 +.I H
   3.502 +turns verbose mode off.
   3.503 +.TP 5
   3.504 +\fR(\|\fI.\|\fR)\|\fBi\fR
   3.505 +.br
   3.506 +.ns
   3.507 +.TP 5
   3.508 +<text>
   3.509 +.br
   3.510 +.ns
   3.511 +.TP 5
   3.512 +.B .
   3.513 +.br
   3.514 +This command inserts the given text before the addressed line.
   3.515 +`\fB.\fR' is left at the last line input, or, if there were none,
   3.516 +at the line before the addressed line.
   3.517 +This command differs from the
   3.518 +.I a
   3.519 +command only in the placement of the
   3.520 +text.
   3.521 +.TP 5
   3.522 +\fR(\|\fI.\|\fB,\|\fI.+1\fR)\|\fBj\fR
   3.523 +This command joins the addressed lines into a single line;
   3.524 +intermediate newlines simply disappear.
   3.525 +`\fB.\fR' is left at the resulting line.
   3.526 +.TP 5
   3.527 +\fR(\fI.\fR)\|\fBk\fIx\fR
   3.528 +The mark command marks the addressed line with
   3.529 +name
   3.530 +.IR x ,
   3.531 +which must be a lower-case letter.
   3.532 +The address form `\(fm\fIx\fR' then addresses this line.
   3.533 +.ne 2.5
   3.534 +.TP 5
   3.535 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBl\fR
   3.536 +The list command
   3.537 +prints the addressed lines in an unambiguous way:
   3.538 +non-graphic control characters are printed in three-digit octal;
   3.539 +Long lines are folded.
   3.540 +The
   3.541 +.I l
   3.542 +command may be placed on the same line after any non-i/o
   3.543 +command.
   3.544 +.TP 5
   3.545 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBm\fIa\fR
   3.546 +The move command repositions the addressed lines after the line
   3.547 +addressed by
   3.548 +.IR a .
   3.549 +The last of the moved lines becomes the current line.
   3.550 +.TP 5
   3.551 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBn\fR
   3.552 +This command prints lines preceded by their line numbers.
   3.553 +It otherwise acts like the
   3.554 +.I p
   3.555 +command described below.
   3.556 +.TP 5
   3.557 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBp\fR
   3.558 +The print command prints the addressed lines.
   3.559 +`\fB.\fR'
   3.560 +is left at the last line printed.
   3.561 +The
   3.562 +.I p
   3.563 +command
   3.564 +may
   3.565 +be placed on the same line after any non-i/o command.
   3.566 +.TP
   3.567 +.B P
   3.568 +This command causes a prompt to be printed
   3.569 +before following commands are read.
   3.570 +The default prompt is a `*' character,
   3.571 +but can be set with the
   3.572 +.I \-p
   3.573 +command line option (which also enables the prompt).
   3.574 +Another 
   3.575 +.I P
   3.576 +disables the prompt.
   3.577 +.TP 5
   3.578 +.B q
   3.579 +The quit command causes
   3.580 +.I ed
   3.581 +to exit.
   3.582 +No automatic write
   3.583 +of a file is done.
   3.584 +.TP 5
   3.585 +.B Q
   3.586 +This command is the same as
   3.587 +.I q,
   3.588 +except that no diagnostic results when no
   3.589 +.I w
   3.590 +has been given since the last buffer alteration.
   3.591 +.TP 5
   3.592 +\fR(\fI$\fR)\|\fBr\ \fIfilename\fR
   3.593 +The read command
   3.594 +reads in the given file after the addressed line.
   3.595 +If no file name is given,
   3.596 +the remembered file name, if any, is used
   3.597 +(see
   3.598 +.I e
   3.599 +and
   3.600 +.I f
   3.601 +commands)\|.
   3.602 +The file name is remembered if there was no
   3.603 +remembered file name already.
   3.604 +Address `0' is legal for
   3.605 +.I r
   3.606 +and causes the
   3.607 +file to be read at the beginning of the buffer.
   3.608 +If the read is successful, the number of characters
   3.609 +read is typed.
   3.610 +`\fB.\fR' is left at the last line read in from the file.
   3.611 +A `filename' starting with a `\fB!\fR'
   3.612 +causes the output of the shell command following this character
   3.613 +to be read in.
   3.614 +.TP 5
   3.615 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/\fR       or,
   3.616 +.br
   3.617 +.ns
   3.618 +.TP 5
   3.619 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/g\fR      or,
   3.620 +.br
   3.621 +.ns
   3.622 +.TP 5
   3.623 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/\fInumber\fR
   3.624 +The substitute command searches each addressed
   3.625 +line for an occurrence of the specified regular expression.
   3.626 +On each line in which a match is found,
   3.627 +all matched strings are replaced by the replacement specified,
   3.628 +if the global replacement indicator
   3.629 +.RB ` g '
   3.630 +appears after the command.
   3.631 +If the global indicator does not appear, only the first occurrence
   3.632 +of the matched string is replaced;
   3.633 +if the \fInumber\fR indicator is given,
   3.634 +the numbered occurrence is replaced.
   3.635 +It is an error for the substitution to fail on all addressed lines.
   3.636 +Any character other than space or new-line
   3.637 +may be used instead of `/' to delimit the regular expression
   3.638 +and the replacement.
   3.639 +`\fB.\fR' is left at the last line substituted.
   3.640 +.IP
   3.641 +An ampersand
   3.642 +.RB ` & '
   3.643 +appearing in the replacement
   3.644 +is replaced by the string matching the regular expression.
   3.645 +The special meaning of `&' in this context may be
   3.646 +suppressed by preceding it by
   3.647 +.RB ` \e '.
   3.648 +The characters `\|\fB\e\fIn\fR'
   3.649 +where
   3.650 +.I n
   3.651 +is a digit,
   3.652 +are replaced by the text matched by the
   3.653 +.IR n -th
   3.654 +regular subexpression
   3.655 +enclosed between `\e(' and `\e)'.
   3.656 +When
   3.657 +nested, parenthesized subexpressions
   3.658 +are present,
   3.659 +.I n
   3.660 +is determined by counting occurrences of `\e(' starting from the left.
   3.661 +.IP
   3.662 +A substitution string consisting of a single
   3.663 +.RB ` % '
   3.664 +causes the string given on the previous substitution to be re-used.
   3.665 +.IP
   3.666 +Lines may be split by substituting new-line characters into them.
   3.667 +The new-line in the
   3.668 +replacement string
   3.669 +must be escaped by preceding it by
   3.670 +.RB ` \e '.
   3.671 +.TP 5
   3.672 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBt\|\fIa\fR
   3.673 +This command acts just like the
   3.674 +.I m
   3.675 +command, except that a copy of the addressed lines is placed
   3.676 +after address
   3.677 +.I a
   3.678 +(which may be 0).
   3.679 +`\fB.\fR' is left on the last line of the copy.
   3.680 +.TP 5
   3.681 +.B u
   3.682 +The undo command restores
   3.683 +the contents of the buffer
   3.684 +before the last command was executed.
   3.685 +If the undo command is given twice,
   3.686 +the current state is restored.
   3.687 +.TP 5
   3.688 +\fR(\fI1\fB,\fI$\fR)\|\fBv/\fIregular expression\fB/\fIcommand list\fR
   3.689 +This command is the same as the global command
   3.690 +.I g
   3.691 +except that the command list is executed
   3.692 +.I g
   3.693 +with `\fB.\fR' initially set to every line
   3.694 +.I except
   3.695 +those
   3.696 +matching the regular expression.
   3.697 +.TP 5
   3.698 +\fR(\fI1\fB,\fI$\fR)\|\fBV/\fIregular expression\fB/\fR
   3.699 +This command is the same as the interactive global command
   3.700 +.I G
   3.701 +except that the commands are read
   3.702 +.I g
   3.703 +with `\fB.\fR' initially set to every line
   3.704 +.I except
   3.705 +those
   3.706 +matching the regular expression.
   3.707 +.TP 5
   3.708 +\fR(\fI1\fB,\fI$\fR)\|\fBw\ \fIfilename\fR
   3.709 +.br
   3.710 +The write command writes the addressed lines onto
   3.711 +the given file.
   3.712 +If the file does not exist,
   3.713 +it is created mode 666 (readable and writable by everyone)\|.
   3.714 +The file name is remembered if there was no 
   3.715 +remembered file name already.
   3.716 +If no file name is given,
   3.717 +the remembered file name, if any, is used
   3.718 +(see
   3.719 +.I e
   3.720 +and
   3.721 +.I f
   3.722 +commands)\|.
   3.723 +`\fB.\fR' is unchanged.
   3.724 +If the command is successful, the number of characters written is
   3.725 +printed.
   3.726 +A `filename' starting with a `\fB!\fR'
   3.727 +causes the string following this character
   3.728 +to be executed as a shell command
   3.729 +with the addressed lines as standard input.
   3.730 +.TP
   3.731 +\fR(\fI1\fB,\fI$\fR)\fBW\ \fIfilename\fR
   3.732 +This command is the same as
   3.733 +.I w,
   3.734 +except that the addressed lines are appended to the file.
   3.735 +.TP 5
   3.736 +\fR(\fI$\fR)\|\fB=\fR
   3.737 +The line number of the addressed line is typed.
   3.738 +`\fB.\fR' is unchanged by this command.
   3.739 +.TP 5
   3.740 +\fB!\fR<shell command>
   3.741 +The remainder of the line after the `!' is sent
   3.742 +to
   3.743 +.IR sh (1)
   3.744 +to be interpreted as a command.
   3.745 +.RB ` . '
   3.746 +is unchanged.
   3.747 +If the command starts with a
   3.748 +.RB ` ! ',
   3.749 +the previous command is inserted.
   3.750 +A
   3.751 +.RB ` % '
   3.752 +causes the current file name to be inserted.
   3.753 +.TP 5
   3.754 +\fR(\|\fI.+1\fR)\|<newline>
   3.755 +An address alone on a line causes the addressed line to be printed.
   3.756 +A blank line alone is equivalent to `.+1p'; it is useful
   3.757 +for stepping through text.
   3.758 +.PP
   3.759 +The following commands are extensions:
   3.760 +.TP 5
   3.761 +\fR(\|\fI.\|\fR)\fB\|b\fR[\fIcount\fR]
   3.762 +Prints a screenful of lines,
   3.763 +starting at the addressed one,
   3.764 +and browses forward in the buffer by this amount.
   3.765 +With the optional
   3.766 +.I count
   3.767 +argument, the screen size for this and following
   3.768 +.I b
   3.769 +commands is set to the given number of lines.
   3.770 +.TP 5
   3.771 +.B help
   3.772 +Causes a summary of
   3.773 +.I ed
   3.774 +commands along with short descriptions
   3.775 +to be printed on the terminal.
   3.776 +.TP 5
   3.777 +.B N
   3.778 +Makes the
   3.779 +.I p
   3.780 +command behave like the
   3.781 +.I n
   3.782 +command and vice-versa.
   3.783 +If given a second time,
   3.784 +the original semantics are restored.
   3.785 +.TP 5
   3.786 +\fR(\|\fI.\|\fR)\fB\|o\fR[\fIcount\fR]
   3.787 +Prints a screenful of lines centered around the addressed one.
   3.788 +The current line is not changed.
   3.789 +With the optional
   3.790 +.I count
   3.791 +argument, the amount of lines printed above and below
   3.792 +for this and following
   3.793 +.I o
   3.794 +commands is set to the given number.
   3.795 +.TP 5
   3.796 +.B z
   3.797 +Performs the same actions as a
   3.798 +.I w
   3.799 +command followed by a
   3.800 +.I q
   3.801 +command.
   3.802 +.PP
   3.803 +If an interrupt signal is sent,
   3.804 +.I ed
   3.805 +prints a `?' and returns to its command level.
   3.806 +.PP
   3.807 +An input line that consists exactly of the two characters `\e.'
   3.808 +causes a period `.' to be inserted with the
   3.809 +.IR a ,
   3.810 +.IR c ,
   3.811 +and
   3.812 +.IR i
   3.813 +commands.
   3.814 +.PP
   3.815 +Some size limitations:
   3.816 +The maximum number of bytes in the buffer
   3.817 +corresponds to the address size;
   3.818 +on machines with 32-bit addressing,
   3.819 +it is 2\ G bytes,
   3.820 +with 64-bit addressing,
   3.821 +it is 9\ E bytes.
   3.822 +The limit on the number of lines depends on the amount of core:
   3.823 +each line takes 2 words.
   3.824 +.PP
   3.825 +If a line contains a NUL character,
   3.826 +regular expressions cannot match beyond this character.
   3.827 +A substitute command deletes a NUL
   3.828 +and all following characters on the line.
   3.829 +NUL characters in command input are discarded.
   3.830 +If an input file does not end with a newline,
   3.831 +.I ed
   3.832 +prints a message and appends one.
   3.833 +.PP
   3.834 +Omission of the `/' character
   3.835 +following the regular expression or the replacement string
   3.836 +to the global and substitute commands
   3.837 +causes the affected lines to be printed.
   3.838 +Thus the following commands have the same effect:
   3.839 +.RS
   3.840 +g/pattern	g/pattern/p
   3.841 +.br
   3.842 +s/pattern/repl	s/pattern/repl/p
   3.843 +.br
   3.844 +s/pattern/	s/pattern//p
   3.845 +.RE
   3.846 +.SH "ENVIRONMENT VARIABLES"
   3.847 +.TP
   3.848 +.BR LANG ", " LC_ALL
   3.849 +See
   3.850 +.IR locale (7).
   3.851 +.TP
   3.852 +.B LC_CTYPE
   3.853 +Determines the mapping of bytes to characters
   3.854 +and the set of printable characters for the
   3.855 +.I l
   3.856 +command.
   3.857 +.TP
   3.858 +.B TMPDIR
   3.859 +Determines the location of the temporary file
   3.860 +if it contains the name of an accessible directory.
   3.861 +.SH FILES
   3.862 +/var/tmp/e*
   3.863 +.br
   3.864 +/tmp/e*
   3.865 +.br
   3.866 +ed.hup: work is saved here if terminal hangs up
   3.867 +.SH "SEE ALSO"
   3.868 +B. W. Kernighan,
   3.869 +.I
   3.870 +A Tutorial Introduction to the ED Text Editor
   3.871 +.br
   3.872 +B. W. Kernighan,
   3.873 +.I Advanced editing on UNIX
   3.874 +.br
   3.875 +bfs(1),
   3.876 +grep(1),
   3.877 +sed(1),
   3.878 +sh(1)
   3.879 +.SH DIAGNOSTICS
   3.880 +`?name' for inaccessible file;
   3.881 +`?' for
   3.882 +errors in commands,
   3.883 +possibly followed by a verbose description
   3.884 +(see the description for the
   3.885 +.I h
   3.886 +and
   3.887 +.I H
   3.888 +commands above).
   3.889 +.PP
   3.890 +To protect against throwing away valuable work,
   3.891 +a
   3.892 +.I q
   3.893 +or
   3.894 +.I e
   3.895 +command is considered to be in error, unless a
   3.896 +.I w
   3.897 +has occurred since the last buffer change.
   3.898 +A second
   3.899 +.I q
   3.900 +or
   3.901 +.I e
   3.902 +will be obeyed regardless.
   3.903 +.SH NOTES
   3.904 +A
   3.905 +.I !\&
   3.906 +command cannot be subject to a
   3.907 +.I g
   3.908 +command.
   3.909 +.PP
   3.910 +The LC_COLLATE variable has currently no effect.
   3.911 +Ranges in bracket expressions are ordered
   3.912 +as byte values in single-byte locales
   3.913 +and as wide character values in multibyte locales.
   3.914 +.PP
   3.915 +For portable programs, restrict textual data
   3.916 +to the US-ASCII character set and
   3.917 +set the LC_CTYPE and LC_COLLATE variables to `C' or `POSIX'.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/ed.c	Mon Sep 05 16:31:35 2011 +0200
     4.3 @@ -0,0 +1,2822 @@
     4.4 +/*
     4.5 + * Editor
     4.6 + */
     4.7 +
     4.8 +/*
     4.9 + * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003.
    4.10 + */
    4.11 +/*	from Unix 32V /usr/src/cmd/ed.c	*/
    4.12 +/*
    4.13 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
    4.14 + *
    4.15 + * Redistribution and use in source and binary forms, with or without
    4.16 + * modification, are permitted provided that the following conditions
    4.17 + * are met:
    4.18 + *   Redistributions of source code and documentation must retain the
    4.19 + *    above copyright notice, this list of conditions and the following
    4.20 + *    disclaimer.
    4.21 + *   Redistributions in binary form must reproduce the above copyright
    4.22 + *    notice, this list of conditions and the following disclaimer in the
    4.23 + *    documentation and/or other materials provided with the distribution.
    4.24 + *   All advertising materials mentioning features or use of this software
    4.25 + *    must display the following acknowledgement:
    4.26 + *      This product includes software developed or owned by Caldera
    4.27 + *      International, Inc.
    4.28 + *   Neither the name of Caldera International, Inc. nor the names of
    4.29 + *    other contributors may be used to endorse or promote products
    4.30 + *    derived from this software without specific prior written permission.
    4.31 + *
    4.32 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    4.33 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    4.34 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    4.35 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.36 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    4.37 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.38 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.39 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    4.40 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    4.41 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    4.42 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    4.43 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    4.44 + */
    4.45 +
    4.46 +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
    4.47 +#define	USED	__attribute__ ((used))
    4.48 +#elif defined __GNUC__
    4.49 +#define	USED	__attribute__ ((unused))
    4.50 +#else
    4.51 +#define	USED
    4.52 +#endif
    4.53 +#if defined (SU3)
    4.54 +static const char sccsid[] USED = "@(#)ed_su3.sl	1.99 (gritter) 7/27/06";
    4.55 +#elif defined (SUS)
    4.56 +static const char sccsid[] USED = "@(#)ed_sus.sl	1.99 (gritter) 7/27/06";
    4.57 +#elif defined (S42)
    4.58 +static const char sccsid[] USED = "@(#)ed_s42.sl	1.99 (gritter) 7/27/06";
    4.59 +#else	/* !SU3, !SUS, !S42 */
    4.60 +static const char sccsid[] USED = "@(#)ed.sl	1.99 (gritter) 7/27/06";
    4.61 +#endif	/* !SU3, !SUS, !S42 */
    4.62 +
    4.63 +#include <sys/types.h>
    4.64 +#include <sys/stat.h>
    4.65 +#include <sys/wait.h>
    4.66 +#include <sys/stat.h>
    4.67 +#include <fcntl.h>
    4.68 +#include <unistd.h>
    4.69 +#include <time.h>
    4.70 +#include <string.h>
    4.71 +#include <stdlib.h>
    4.72 +#include <signal.h>
    4.73 +#include "sigset.h"
    4.74 +#include <termios.h>
    4.75 +#include <setjmp.h>
    4.76 +#include <libgen.h>
    4.77 +#include <inttypes.h>
    4.78 +#include <locale.h>
    4.79 +#include <wchar.h>
    4.80 +#include <ctype.h>
    4.81 +#include <wctype.h>
    4.82 +#include <limits.h>
    4.83 +#include <termios.h>
    4.84 +static int	FNSIZE;
    4.85 +static int	LBSIZE;
    4.86 +static int	RHSIZE;
    4.87 +#define	ESIZE	2048
    4.88 +static int	GBSIZE;
    4.89 +#undef	EOF
    4.90 +#define	EOF	-1
    4.91 +#define	puts(s)		xxputs(s)
    4.92 +#define	getline(t, n)	xxgetline(t, n)
    4.93 +
    4.94 +#if (LONG_MAX > 017777777777L)
    4.95 +#define	MAXCNT	0777777777777777777777L		/* 2^63-1 */
    4.96 +#else
    4.97 +#define	MAXCNT	017777777777L			/* 2^31-1 */
    4.98 +#endif
    4.99 +#define	BLKMSK	(MAXCNT>>8)			/* was 0377 */
   4.100 +
   4.101 +#define	READ	0
   4.102 +#define	WRITE	1
   4.103 +#define	EXIST	2
   4.104 +
   4.105 +struct	tabulator {
   4.106 +	struct tabulator	*t_nxt;	/* next list element */
   4.107 +	const char	*t_str;		/* tabulator string */
   4.108 +	int	t_tab;			/* tab stop position */
   4.109 +	int	t_rep;			/* repetitive tab count */
   4.110 +};
   4.111 +
   4.112 +static int	peekc;
   4.113 +static int	lastc;
   4.114 +static char	*savedfile;
   4.115 +static char	*file;
   4.116 +static struct stat	fstbuf;
   4.117 +static char	*linebuf;
   4.118 +static char	*rhsbuf;
   4.119 +static char	expbuf[ESIZE + 4];
   4.120 +static long	*zero;
   4.121 +static long	*undzero;
   4.122 +static long	*dot;
   4.123 +static long	*unddot;
   4.124 +static long	*dol;
   4.125 +static long	*unddol;
   4.126 +static long	*addr1;
   4.127 +static long	*addr2;
   4.128 +static char	*genbuf;
   4.129 +static long	count;
   4.130 +static char	*linebp;
   4.131 +static int	ninbuf;
   4.132 +static int	io;
   4.133 +static int	ioeof;
   4.134 +static int	pflag;
   4.135 +static char	*wrtemp;
   4.136 +static uid_t	myuid;
   4.137 +static void	(*oldhup)(int);
   4.138 +static void	(*oldquit)(int);
   4.139 +static void	(*oldpipe)(int);
   4.140 +static int	vflag	= 1;
   4.141 +static int	listf;
   4.142 +static int	numbf;
   4.143 +static char	*globp;
   4.144 +static int	tfile	= -1;
   4.145 +static long	tline;
   4.146 +static char	tfname[64];
   4.147 +static char	ibuff[512];
   4.148 +static int	iblock	= -1;
   4.149 +static char	obuff[512];
   4.150 +static int	oblock	= -1;
   4.151 +static int	ichanged;
   4.152 +static int	nleft;
   4.153 +static long	*names;
   4.154 +static long	*undnames;
   4.155 +static int	anymarks;
   4.156 +static int	subnewa;
   4.157 +static int	fchange;
   4.158 +static int	wrapp;
   4.159 +static unsigned nlall = 128;
   4.160 +static const char	*progname;
   4.161 +static const char	*prompt = "*";
   4.162 +static int	Pflag;
   4.163 +static int	prhelp;
   4.164 +static const char	*prvmsg;
   4.165 +static int	lastsig;
   4.166 +static int	pipid = -1;
   4.167 +static int	readop;
   4.168 +static int	status;
   4.169 +static int	mb_cur_max;
   4.170 +static int	needsub;
   4.171 +static int	insub;
   4.172 +static struct tabulator	*tabstops;
   4.173 +static int	maxlength;
   4.174 +static int	rspec;
   4.175 +static int	Nflag;
   4.176 +static int	bcount = 22;
   4.177 +static int	ocount = 11;
   4.178 +
   4.179 +static jmp_buf	savej;
   4.180 +
   4.181 +static void	usage(char, int);
   4.182 +static void	commands(void);
   4.183 +static long	*address(void);
   4.184 +static void	setdot(void);
   4.185 +static void	setall(void);
   4.186 +static void	setnoaddr(void);
   4.187 +static void	nonzero(void);
   4.188 +static void	newline(void);
   4.189 +static void	filename(int);
   4.190 +static void	exfile(void);
   4.191 +static void	onintr(int);
   4.192 +static void	onhup(int);
   4.193 +static void	onpipe(int);
   4.194 +static void	error(const char *);
   4.195 +static void	error2(const char *, const char *);
   4.196 +static void	errput(const char *, const char *);
   4.197 +static int	getchr(void);
   4.198 +static int	gettty(void);
   4.199 +static long	getnum(void);
   4.200 +static int	getfile(void);
   4.201 +static void	putfile(void);
   4.202 +static int	append(int (*)(void), long *);
   4.203 +static void	callunix(void);
   4.204 +static char	*readcmd(void);
   4.205 +static void	quit(int);
   4.206 +static void	delete(void);
   4.207 +static void	rdelete(long *, long *);
   4.208 +static void	gdelete(void);
   4.209 +static char	*getline(long, int);
   4.210 +static int	putline(void);
   4.211 +static char	*getblock(long, long);
   4.212 +static void	blkio(long, char *, int);
   4.213 +static void	init(void);
   4.214 +static void	global(int, int);
   4.215 +static void	globrd(char **, int);
   4.216 +static void	join(void);
   4.217 +static void	substitute(int);
   4.218 +static int	compsub(void);
   4.219 +static int	getsub(void);
   4.220 +static int	dosub(int);
   4.221 +static int	place(int, const char *, const char *);
   4.222 +static void	move(int);
   4.223 +static void	reverse(long *, long *);
   4.224 +static int	getcopy(void);
   4.225 +static int	execute(int, long *, int);
   4.226 +static void	cmplerr(int);
   4.227 +static void	doprnt(long *, long *);
   4.228 +static void	putd(long);
   4.229 +static void	puts(const char *);
   4.230 +static void	nlputs(const char *);
   4.231 +static void	list(const char *);
   4.232 +static int	lstchr(int);
   4.233 +static void	putstr(const char *);
   4.234 +static void	putchr(int);
   4.235 +static void	checkpoint(void);
   4.236 +static void	undo(void);
   4.237 +static int	maketf(int);
   4.238 +static int	creatf(const char *);
   4.239 +static int	sopen(const char *, int);
   4.240 +static void	sclose(int);
   4.241 +static void	fspec(const char *);
   4.242 +static const char	*ftok(const char **);
   4.243 +static struct tabulator	*tabstring(const char *);
   4.244 +static void	freetabs(void);
   4.245 +static void	expand(const char *);
   4.246 +static void	growlb(const char *);
   4.247 +static void	growrhs(const char *);
   4.248 +static void	growfn(const char *);
   4.249 +static void	help(void);
   4.250 +
   4.251 +#define	INIT
   4.252 +#define	GETC()		getchr()
   4.253 +#define	UNGETC(c)	(peekc = c)
   4.254 +#define	PEEKC()		(peekc = getchr())
   4.255 +#define	RETURN(c)	return c
   4.256 +#define	ERROR(c)	cmplerr(c)
   4.257 +static wint_t	GETWC(char *);
   4.258 +
   4.259 +#if defined (SUS) || defined (S42) || defined (SU3)
   4.260 +
   4.261 +#include <regex.h>
   4.262 +
   4.263 +#define	NBRA	9
   4.264 +
   4.265 +static char	*braslist[NBRA];
   4.266 +static char	*braelist[NBRA];
   4.267 +static char	*loc1, *loc2, *locs;
   4.268 +static int	nbra;
   4.269 +static int	circf;
   4.270 +static int	nodelim;
   4.271 +
   4.272 +static char	*compile(char *, char *, const char *, int);
   4.273 +static int	step(const char *, const char *);
   4.274 +
   4.275 +#else	/* !SUS, !S42, !SU3 */
   4.276 +
   4.277 +#include <regexp.h>
   4.278 +
   4.279 +#endif	/* !SUS, !S42, !SU3 */
   4.280 +
   4.281 +int
   4.282 +main(int argc, char **argv)
   4.283 +{
   4.284 +	register int i;
   4.285 +	void (*oldintr)(int);
   4.286 +
   4.287 +	progname = basename(argv[0]);
   4.288 +#if defined (SUS) || defined (S42) || defined (SU3)
   4.289 +	setlocale(LC_COLLATE, "");
   4.290 +#endif
   4.291 +	setlocale(LC_CTYPE, "");
   4.292 +	mb_cur_max = MB_CUR_MAX;
   4.293 +	myuid = getuid();
   4.294 +	oldquit = sigset(SIGQUIT, SIG_IGN);
   4.295 +	oldhup = sigset(SIGHUP, SIG_IGN);
   4.296 +	oldintr = sigset(SIGINT, SIG_IGN);
   4.297 +	if (sigset(SIGTERM, SIG_IGN) != SIG_IGN)
   4.298 +		sigset(SIGTERM, quit);
   4.299 +	oldpipe = sigset(SIGPIPE, onpipe);
   4.300 +	argv++;
   4.301 +	while (argc > 1 && **argv=='-') {
   4.302 +		if ((*argv)[1] == '\0') {
   4.303 +			vflag = 0;
   4.304 +			goto next;
   4.305 +		} else if ((*argv)[1] == '-' && (*argv)[2] == '\0') {
   4.306 +			argv++;
   4.307 +			argc--;
   4.308 +			break;
   4.309 +		}
   4.310 +	letter:	switch((*argv)[1]) {
   4.311 +
   4.312 +		case 's':
   4.313 +			vflag = 0;
   4.314 +			break;
   4.315 +
   4.316 +		case 'q':
   4.317 +			sigset(SIGQUIT, SIG_DFL);
   4.318 +			vflag = 1;
   4.319 +			break;
   4.320 +
   4.321 +		case 'p':
   4.322 +			if ((*argv)[2])
   4.323 +				prompt = &(*argv)[2];
   4.324 +			else if (argv[1]) {
   4.325 +				prompt = argv[1];
   4.326 +				argv++;
   4.327 +				argc--;
   4.328 +			} else
   4.329 +				usage((*argv)[1], 1);
   4.330 +			Pflag = 1;
   4.331 +			goto next;
   4.332 +
   4.333 +		default:
   4.334 +			usage((*argv)[1], 0);
   4.335 +		}
   4.336 +		if ((*argv)[2]) {
   4.337 +			(*argv)++;
   4.338 +			goto letter;
   4.339 +		}
   4.340 +	next:	argv++;
   4.341 +		argc--;
   4.342 +	}
   4.343 +
   4.344 +	growfn("no space");
   4.345 +	if (argc>1) {
   4.346 +		i = -1;
   4.347 +		do
   4.348 +			if (++i >= FNSIZE)
   4.349 +				growfn("maximum of characters in "
   4.350 +						"file names reached");
   4.351 +		while (savedfile[i] = (*argv)[i]);
   4.352 +		globp = "e";
   4.353 +	}
   4.354 +	names = malloc(26*sizeof *names);
   4.355 +	undnames = malloc(26*sizeof *undnames);
   4.356 +	zero = malloc(nlall*sizeof *zero);
   4.357 +	if ((undzero = malloc(nlall*sizeof *undzero)) == NULL)
   4.358 +		puts("no memory for undo");
   4.359 +	growlb("no space");
   4.360 +	growrhs("no space");
   4.361 +	init();
   4.362 +	if (oldintr != SIG_IGN)
   4.363 +		sigset(SIGINT, onintr);
   4.364 +	if (oldhup != SIG_IGN)
   4.365 +		sigset(SIGHUP, onhup);
   4.366 +	setjmp(savej);
   4.367 +	if (lastsig) {
   4.368 +		sigrelse(lastsig);
   4.369 +		lastsig = 0;
   4.370 +	}
   4.371 +	commands();
   4.372 +	quit(0);
   4.373 +	/*NOTREACHED*/
   4.374 +	return 0;
   4.375 +}
   4.376 +
   4.377 +static void
   4.378 +usage(char c, int misarg)
   4.379 +{
   4.380 +	if (c) {
   4.381 +		write(2, progname, strlen(progname));
   4.382 +		if (misarg)
   4.383 +			write(2, ": option requires an argument -- ", 33);
   4.384 +		else
   4.385 +			write(2, ": illegal option -- ", 20);
   4.386 +		write(2, &c, 1);
   4.387 +		write(2, "\n", 1);
   4.388 +	}
   4.389 +	write(2, "usage: ", 7);
   4.390 +	write(2, progname, strlen(progname));
   4.391 +	write(2, " [- | -s] [-p string] [file]\n", 29);
   4.392 +	exit(2);
   4.393 +}
   4.394 +
   4.395 +static void
   4.396 +commands(void)
   4.397 +{
   4.398 +	register long *a1;
   4.399 +	register int c;
   4.400 +	int	n;
   4.401 +
   4.402 +	for (;;) {
   4.403 +	if (pflag) {
   4.404 +		pflag = 0;
   4.405 +		addr1 = addr2 = dot;
   4.406 +		goto print;
   4.407 +	}
   4.408 +	if (Pflag && globp == NULL)
   4.409 +		write(1, prompt, strlen(prompt));
   4.410 +	addr1 = 0;
   4.411 +	addr2 = 0;
   4.412 +	switch (c = getchr()) {
   4.413 +	case ',':
   4.414 +	case ';':
   4.415 +		addr2 = c == ',' ? zero+1 : dot;
   4.416 +		if (((peekc = getchr()) < '0' || peekc > '9') &&
   4.417 +				peekc != ' ' && peekc != '\t' &&
   4.418 +				peekc != '+' && peekc != '-' &&
   4.419 +				peekc != '^' && peekc != '?' &&
   4.420 +				peekc != '/' && peekc != '$' &&
   4.421 +				peekc != '.' && peekc != '\'') {
   4.422 +			addr1 = addr2;
   4.423 +			a1 = dol;
   4.424 +			goto loop;
   4.425 +		}
   4.426 +		break;
   4.427 +	default:
   4.428 +		peekc = c;
   4.429 +	}
   4.430 +	do {
   4.431 +		addr1 = addr2;
   4.432 +		if ((a1 = address())==0) {
   4.433 +			c = getchr();
   4.434 +			break;
   4.435 +		}
   4.436 +	loop:	addr2 = a1;
   4.437 +		if ((c=getchr()) == ';') {
   4.438 +			c = ',';
   4.439 +			dot = a1;
   4.440 +		}
   4.441 +	} while (c==',');
   4.442 +	if (addr1==0)
   4.443 +		addr1 = addr2;
   4.444 +	switch(c) {
   4.445 +
   4.446 +	case 'a':
   4.447 +		setdot();
   4.448 +		newline();
   4.449 +		checkpoint();
   4.450 +		append(gettty, addr2);
   4.451 +		continue;
   4.452 +
   4.453 +	case 'c':
   4.454 +#if defined (SU3)
   4.455 +		if (addr1 == zero && addr1+1 <= dol) {
   4.456 +			if (addr1 == addr2)
   4.457 +				addr2++;
   4.458 +			addr1++;
   4.459 +		}
   4.460 +#endif	/* SU3 */
   4.461 +		delete();
   4.462 +		append(gettty, addr1-1);
   4.463 +#if defined (SUS) || defined (SU3)
   4.464 +		if (dot == addr1-1 && addr1 <= dol)
   4.465 +			dot = addr1;
   4.466 +#endif	/* SUS || SU3 */
   4.467 +		continue;
   4.468 +
   4.469 +	case 'd':
   4.470 +		delete();
   4.471 +		continue;
   4.472 +
   4.473 +	case 'E':
   4.474 +		fchange = 0;
   4.475 +		c = 'e';
   4.476 +	case 'e':
   4.477 +		setnoaddr();
   4.478 +		if (vflag && fchange) {
   4.479 +			fchange = 0;
   4.480 +			error("warning: expecting `w'");
   4.481 +		}
   4.482 +		filename(c);
   4.483 +		init();
   4.484 +		addr2 = zero;
   4.485 +		goto caseread;
   4.486 +
   4.487 +	case 'f':
   4.488 +		setnoaddr();
   4.489 +		filename(c);
   4.490 +		puts(savedfile);
   4.491 +		continue;
   4.492 +
   4.493 +	case 'g':
   4.494 +		global(1, 0);
   4.495 +		continue;
   4.496 +
   4.497 +	case 'G':
   4.498 +		global(1, 1);
   4.499 +		continue;
   4.500 +
   4.501 +	case 'H':
   4.502 +		prhelp = !prhelp;
   4.503 +		/*FALLTHRU*/
   4.504 +
   4.505 +	case 'h':
   4.506 +		if ((peekc = getchr()) == 'e') {
   4.507 +			peekc = 0;
   4.508 +			if (getchr() != 'l' || getchr() != 'p' ||
   4.509 +					getchr() != '\n')
   4.510 +				error("illegal suffix");
   4.511 +			setnoaddr();
   4.512 +			help();
   4.513 +			continue;
   4.514 +		}
   4.515 +		newline();
   4.516 +		setnoaddr();
   4.517 +		if (prvmsg)
   4.518 +			puts(prvmsg);
   4.519 +		continue;
   4.520 +
   4.521 +	case 'i':
   4.522 +		setdot();
   4.523 +#if defined (SU3)
   4.524 +		if (addr1 == zero) {
   4.525 +			if (addr1 == addr2)
   4.526 +				addr2++;
   4.527 +			addr1++;
   4.528 +			if (dol != zero)
   4.529 +				nonzero();
   4.530 +		} else
   4.531 +#endif	/* SU3 */
   4.532 +			nonzero();
   4.533 +		newline();
   4.534 +		checkpoint();
   4.535 +		append(gettty, addr2-1);
   4.536 +		if (dot == addr2-1)
   4.537 +			dot++;
   4.538 +		continue;
   4.539 +
   4.540 +
   4.541 +	case 'j':
   4.542 +		if (addr2==0) {
   4.543 +			addr1 = dot;
   4.544 +			addr2 = dot+1;
   4.545 +		}
   4.546 +		setdot();
   4.547 +		newline();
   4.548 +		nonzero();
   4.549 +		checkpoint();
   4.550 +		if (addr1 != addr2)
   4.551 +			join();
   4.552 +		continue;
   4.553 +
   4.554 +	case 'k':
   4.555 +		if ((c = getchr()) < 'a' || c > 'z')
   4.556 +			error("mark not lower case");
   4.557 +		newline();
   4.558 +		setdot();
   4.559 +		nonzero();
   4.560 +		names[c-'a'] = *addr2 & ~01;
   4.561 +		anymarks |= 01;
   4.562 +		continue;
   4.563 +
   4.564 +	case 'm':
   4.565 +		move(0);
   4.566 +		continue;
   4.567 +
   4.568 +	case '\n':
   4.569 +		if (addr2==0)
   4.570 +			addr2 = dot+1;
   4.571 +		addr1 = addr2;
   4.572 +		goto print;
   4.573 +
   4.574 +	case 'n':
   4.575 +		numbf = 1;
   4.576 +		newline();
   4.577 +		goto print;
   4.578 +
   4.579 +	case 'N':
   4.580 +		newline();
   4.581 +		setnoaddr();
   4.582 +		Nflag = !Nflag;
   4.583 +		continue;
   4.584 +
   4.585 +	case 'b':
   4.586 +	case 'o':
   4.587 +		n = getnum();
   4.588 +		newline();
   4.589 +		setdot();
   4.590 +		nonzero();
   4.591 +		if (n >= 0) {
   4.592 +			if (c == 'b')
   4.593 +				bcount = n;
   4.594 +			else
   4.595 +				ocount = n;
   4.596 +		}
   4.597 +		if (c == 'b') {
   4.598 +			a1 = addr2+bcount > dol ? dol : addr2 + bcount;
   4.599 +			doprnt(addr1, a1);
   4.600 +			dot = a1;
   4.601 +		} else {
   4.602 +			a1 = addr2+ocount > dol ? dol : addr2 + ocount;
   4.603 +			doprnt(addr2-ocount<zero+1?zero+1:addr2-ocount, a1);
   4.604 +			dot = addr2;
   4.605 +		}
   4.606 +		continue;
   4.607 +
   4.608 +	case 'l':
   4.609 +		listf++;
   4.610 +	case 'p':
   4.611 +		newline();
   4.612 +	print:
   4.613 +		setdot();
   4.614 +		nonzero();
   4.615 +		doprnt(addr1, addr2);
   4.616 +		dot = addr2;
   4.617 +		continue;
   4.618 +
   4.619 +	case 'P':
   4.620 +		setnoaddr();
   4.621 +		newline();
   4.622 +		Pflag = !Pflag;
   4.623 +		continue;
   4.624 +
   4.625 +	case 'Q':
   4.626 +		fchange = 0;
   4.627 +	case 'q':
   4.628 +		setnoaddr();
   4.629 +		newline();
   4.630 +		quit(0);
   4.631 +
   4.632 +	case 'r':
   4.633 +		filename(c);
   4.634 +	caseread:
   4.635 +		if ((io = sopen(file, READ)) < 0) {
   4.636 +			lastc = '\n';
   4.637 +			error2("cannot open input file", file);
   4.638 +		}
   4.639 +		ioeof = 0;
   4.640 +		setall();
   4.641 +		ninbuf = 0;
   4.642 +		if (c == 'r')
   4.643 +			checkpoint();
   4.644 +		n = zero != dol;
   4.645 +		rspec = (c == 'e' || !n) && file[0] != '!';
   4.646 +		append(getfile, addr2);
   4.647 +		rspec = 0;
   4.648 +		exfile();
   4.649 +		fchange = n;
   4.650 +		continue;
   4.651 +
   4.652 +	case 's':
   4.653 +		setdot();
   4.654 +		nonzero();
   4.655 +		substitute(globp!=0);
   4.656 +		continue;
   4.657 +
   4.658 +	case 't':
   4.659 +		move(1);
   4.660 +		continue;
   4.661 +
   4.662 +	case 'u':
   4.663 +		setdot();
   4.664 +		newline();
   4.665 +		if (unddot == NULL)
   4.666 +			error("nothing to undo");
   4.667 +		undo();
   4.668 +		continue;
   4.669 +
   4.670 +	case 'v':
   4.671 +		global(0, 0);
   4.672 +		continue;
   4.673 +
   4.674 +	case 'V':
   4.675 +		global(0, 1);
   4.676 +		continue;
   4.677 +
   4.678 +	case 'W':
   4.679 +		wrapp++;
   4.680 +	case 'w':
   4.681 +	write:
   4.682 +		setall();
   4.683 +		if (zero != dol)
   4.684 +			nonzero();
   4.685 +		filename(c);
   4.686 +		if(!wrapp ||
   4.687 +		  ((io = open(file,O_WRONLY|O_APPEND)) == -1) ||
   4.688 +		  ((lseek(io, 0, SEEK_END)) == -1)) {
   4.689 +			struct stat	st;
   4.690 +			if (lstat(file, &st) == 0 &&
   4.691 +					(st.st_mode&S_IFMT) == S_IFREG &&
   4.692 +					st.st_nlink == 1 &&
   4.693 +					(myuid==0 || myuid==st.st_uid)) {
   4.694 +				char	*cp, *tp;
   4.695 +				int	nio;
   4.696 +				if ((io = sopen(file, EXIST)) < 0)
   4.697 +					error("cannot create output file");
   4.698 +				if ((wrtemp = malloc(strlen(file)+8)) == NULL)
   4.699 +					error("out of memory");
   4.700 +				for (cp = file, tp = wrtemp; *cp; cp++)
   4.701 +					*tp++ = *cp;
   4.702 +				while (tp > wrtemp && tp[-1] != '/')
   4.703 +					tp--;
   4.704 +				for (cp = "\7XXXXXX"; *cp; cp++)
   4.705 +					*tp++ = *cp;
   4.706 +				*tp = '\0';
   4.707 +				if ((nio = mkstemp(wrtemp)) < 0) {
   4.708 +					free(wrtemp);
   4.709 +					wrtemp = NULL;
   4.710 +					ftruncate(io, 0);
   4.711 +				} else {
   4.712 +					close(io);
   4.713 +					io = nio;
   4.714 +				}
   4.715 +			} else {
   4.716 +				if ((io = sopen(file, WRITE)) < 0)
   4.717 +					error("cannot create output file");
   4.718 +			}
   4.719 +		}
   4.720 +		if (zero != dol) {
   4.721 +			ioeof = 0;
   4.722 +			wrapp = 0;
   4.723 +			putfile();
   4.724 +		}
   4.725 +		exfile();
   4.726 +		if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero)
   4.727 +			fchange = 0;
   4.728 +		if (c == 'z')
   4.729 +			quit(0);
   4.730 +		continue;
   4.731 +
   4.732 +	case 'z':
   4.733 +		if ((peekc=getchr()) != '\n')
   4.734 +			error("illegal suffix");
   4.735 +		setnoaddr();
   4.736 +		goto write;
   4.737 +
   4.738 +	case '=':
   4.739 +		setall();
   4.740 +		newline();
   4.741 +		putd((addr2-zero)&MAXCNT);
   4.742 +		putchr('\n');
   4.743 +		continue;
   4.744 +
   4.745 +	case '!':
   4.746 +		callunix();
   4.747 +		continue;
   4.748 +
   4.749 +	case EOF:
   4.750 +		return;
   4.751 +
   4.752 +	}
   4.753 +	error("unknown command");
   4.754 +	}
   4.755 +}
   4.756 +
   4.757 +static long *
   4.758 +address(void)
   4.759 +{
   4.760 +	register long *a1;
   4.761 +	register int minus, c;
   4.762 +	int n, relerr;
   4.763 +
   4.764 +	minus = 0;
   4.765 +	a1 = 0;
   4.766 +	for (;;) {
   4.767 +		c = getchr();
   4.768 +		if ('0'<=c && c<='9') {
   4.769 +			n = 0;
   4.770 +			do {
   4.771 +				n *= 10;
   4.772 +				n += c - '0';
   4.773 +			} while ((c = getchr())>='0' && c<='9');
   4.774 +			peekc = c;
   4.775 +			if (a1==0)
   4.776 +				a1 = zero;
   4.777 +			if (minus<0)
   4.778 +				n = -n;
   4.779 +			a1 += n;
   4.780 +			minus = 0;
   4.781 +			continue;
   4.782 +		}
   4.783 +		relerr = 0;
   4.784 +		if (a1 || minus)
   4.785 +			relerr++;
   4.786 +		switch(c) {
   4.787 +		case ' ':
   4.788 +		case '\t':
   4.789 +			continue;
   4.790 +	
   4.791 +		case '+':
   4.792 +			minus++;
   4.793 +			if (a1==0)
   4.794 +				a1 = dot;
   4.795 +			continue;
   4.796 +
   4.797 +		case '-':
   4.798 +		case '^':
   4.799 +			minus--;
   4.800 +			if (a1==0)
   4.801 +				a1 = dot;
   4.802 +			continue;
   4.803 +	
   4.804 +		case '?':
   4.805 +		case '/':
   4.806 +			compile(NULL, expbuf, &expbuf[ESIZE], c);
   4.807 +			a1 = dot;
   4.808 +			for (;;) {
   4.809 +				if (c=='/') {
   4.810 +					a1++;
   4.811 +					if (a1 > dol)
   4.812 +						a1 = zero;
   4.813 +				} else {
   4.814 +					a1--;
   4.815 +					if (a1 < zero)
   4.816 +						a1 = dol;
   4.817 +				}
   4.818 +				if (execute(0, a1, 0))
   4.819 +					break;
   4.820 +				if (a1==dot)
   4.821 +					error("search string not found");
   4.822 +			}
   4.823 +			break;
   4.824 +	
   4.825 +		case '$':
   4.826 +			a1 = dol;
   4.827 +			break;
   4.828 +	
   4.829 +		case '.':
   4.830 +			a1 = dot;
   4.831 +			break;
   4.832 +
   4.833 +		case '\'':
   4.834 +			if ((c = getchr()) < 'a' || c > 'z')
   4.835 +				error("mark not lower case");
   4.836 +			for (a1=zero; a1<=dol; a1++)
   4.837 +				if (names[c-'a'] == (*a1 & ~01))
   4.838 +					break;
   4.839 +			break;
   4.840 +	
   4.841 +		default:
   4.842 +			peekc = c;
   4.843 +			if (a1==0)
   4.844 +				return(0);
   4.845 +			a1 += minus;
   4.846 +			if (a1<zero || a1>dol)
   4.847 +				error("line out of range");
   4.848 +			return(a1);
   4.849 +		}
   4.850 +		if (relerr)
   4.851 +			error("bad number");
   4.852 +	}
   4.853 +}
   4.854 +
   4.855 +static void
   4.856 +setdot(void)
   4.857 +{
   4.858 +	if (addr2 == 0)
   4.859 +		addr1 = addr2 = dot;
   4.860 +	if (addr1 > addr2)
   4.861 +		error("bad range");
   4.862 +}
   4.863 +
   4.864 +static void
   4.865 +setall(void)
   4.866 +{
   4.867 +	if (addr2==0) {
   4.868 +		addr1 = zero+1;
   4.869 +		addr2 = dol;
   4.870 +		if (dol==zero)
   4.871 +			addr1 = zero;
   4.872 +	}
   4.873 +	setdot();
   4.874 +}
   4.875 +
   4.876 +static void
   4.877 +setnoaddr(void)
   4.878 +{
   4.879 +	if (addr2)
   4.880 +		error("Illegal address count");
   4.881 +}
   4.882 +
   4.883 +static void
   4.884 +nonzero(void)
   4.885 +{
   4.886 +	if (addr1<=zero || addr2>dol)
   4.887 +		error("line out of range");
   4.888 +}
   4.889 +
   4.890 +static void
   4.891 +newline(void)
   4.892 +{
   4.893 +	register int c;
   4.894 +
   4.895 +	if ((c = getchr()) == '\n')
   4.896 +		return;
   4.897 +	if (c=='p' || c=='l' || c=='n') {
   4.898 +		pflag++;
   4.899 +		if (c=='l')
   4.900 +			listf++;
   4.901 +		else if (c=='n')
   4.902 +			numbf = 1;
   4.903 +		if (getchr() == '\n')
   4.904 +			return;
   4.905 +	}
   4.906 +	error("illegal suffix");
   4.907 +}
   4.908 +
   4.909 +static void
   4.910 +filename(int comm)
   4.911 +{
   4.912 +	register char *p1, *p2;
   4.913 +	register int c, i;
   4.914 +
   4.915 +	count = 0;
   4.916 +	c = getchr();
   4.917 +	if (c=='\n' || c==EOF) {
   4.918 +		p1 = savedfile;
   4.919 +		if (*p1==0 && comm!='f')
   4.920 +			error("illegal or missing filename");
   4.921 +		p2 = file;
   4.922 +		while (*p2++ = *p1++)
   4.923 +			;
   4.924 +		return;
   4.925 +	}
   4.926 +	if (c!=' ')
   4.927 +		error("no space after command");
   4.928 +	while ((c = getchr()) == ' ')
   4.929 +		;
   4.930 +	if (c=='\n')
   4.931 +		error("illegal or missing filename");
   4.932 +	i = 0;
   4.933 +	do {
   4.934 +		if (i >= FNSIZE)
   4.935 +			growfn("maximum of characters in file names reached");
   4.936 +		file[i++] = c;
   4.937 +		if (c==' ' && file[0] != '!' || c==EOF)
   4.938 +			error("illegal or missing filename");
   4.939 +	} while ((c = getchr()) != '\n');
   4.940 +	file[i++] = 0;
   4.941 +	if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') {
   4.942 +		p1 = savedfile;
   4.943 +		p2 = file;
   4.944 +		while (*p1++ = *p2++)
   4.945 +			;
   4.946 +	}
   4.947 +}
   4.948 +
   4.949 +static void
   4.950 +exfile(void)
   4.951 +{
   4.952 +	sclose(io);
   4.953 +	io = -1;
   4.954 +	if (wrtemp) {
   4.955 +		extern int	rename(const char *, const char *);
   4.956 +		if (rename(wrtemp, file) < 0)
   4.957 +			error("cannot create output file");
   4.958 +		if (myuid == 0)
   4.959 +			chown(file, fstbuf.st_uid, fstbuf.st_gid);
   4.960 +		chmod(file, fstbuf.st_mode & 07777);
   4.961 +		free(wrtemp);
   4.962 +		wrtemp = NULL;
   4.963 +	}
   4.964 +	if (vflag) {
   4.965 +		putd(count);
   4.966 +		putchr('\n');
   4.967 +	}
   4.968 +}
   4.969 +
   4.970 +static void
   4.971 +onintr(int signo)
   4.972 +{
   4.973 +	lastsig = signo;
   4.974 +	putchr('\n');
   4.975 +	lastc = '\n';
   4.976 +	if (readop) {
   4.977 +		puts("\007read may be incomplete - beware!\007");
   4.978 +		fchange = 0;
   4.979 +	}
   4.980 +	error("interrupt");
   4.981 +}
   4.982 +
   4.983 +static void
   4.984 +onhup(int signo)
   4.985 +{
   4.986 +	if (dol > zero && fchange) {
   4.987 +		addr1 = zero+1;
   4.988 +		addr2 = dol;
   4.989 +		io = creat("ed.hup", 0666);
   4.990 +		if (io < 0) {
   4.991 +			char	*home = getenv("HOME");
   4.992 +			if (home) {
   4.993 +				char	*fn = malloc(strlen(home) + 10);
   4.994 +				if (fn) {
   4.995 +					strcpy(fn, home);
   4.996 +					strcat(fn, "/ed.hup");
   4.997 +					io = creat(fn, 0666);
   4.998 +				}
   4.999 +			}
  4.1000 +		}
  4.1001 +		if (io >= 0)
  4.1002 +			putfile();
  4.1003 +	}
  4.1004 +	fchange = 0;
  4.1005 +	status = 0200 | signo;
  4.1006 +	quit(0);
  4.1007 +}
  4.1008 +
  4.1009 +static void
  4.1010 +onpipe(int signo)
  4.1011 +{
  4.1012 +	lastsig = signo;
  4.1013 +	error("write or open on pipe failed");
  4.1014 +}
  4.1015 +
  4.1016 +static void
  4.1017 +error(const char *s)
  4.1018 +{
  4.1019 +	error2(s, NULL);
  4.1020 +}
  4.1021 +
  4.1022 +static void
  4.1023 +error2(const char *s, const char *fn)
  4.1024 +{
  4.1025 +	register int c;
  4.1026 +
  4.1027 +	wrapp = 0;
  4.1028 +	listf = 0;
  4.1029 +	numbf = 0;
  4.1030 +	errput(s, fn);
  4.1031 +	count = 0;
  4.1032 +	if (lseek(0, 0, SEEK_END) > 0)
  4.1033 +		status = 2;
  4.1034 +	pflag = 0;
  4.1035 +	if (globp)
  4.1036 +		lastc = '\n';
  4.1037 +	globp = 0;
  4.1038 +	peekc = lastc;
  4.1039 +	if(lastc)
  4.1040 +		while ((c = getchr()) != '\n' && c != EOF)
  4.1041 +			;
  4.1042 +	if (io > 0) {
  4.1043 +		sclose(io);
  4.1044 +		io = -1;
  4.1045 +	}
  4.1046 +	if (wrtemp) {
  4.1047 +		unlink(wrtemp);
  4.1048 +		free(wrtemp);
  4.1049 +		wrtemp = NULL;
  4.1050 +	}
  4.1051 +	longjmp(savej, 1);
  4.1052 +}
  4.1053 +
  4.1054 +static void
  4.1055 +errput(const char *s, const char *fn)
  4.1056 +{
  4.1057 +	prvmsg = s;
  4.1058 +	if (fn) {
  4.1059 +		putchr('?');
  4.1060 +		puts(fn);
  4.1061 +	} else
  4.1062 +		puts("?");
  4.1063 +	if (prhelp)
  4.1064 +		puts(s);
  4.1065 +}
  4.1066 +
  4.1067 +static int
  4.1068 +getchr(void)
  4.1069 +{
  4.1070 +	char c;
  4.1071 +	if (lastc=peekc) {
  4.1072 +		peekc = 0;
  4.1073 +		return(lastc);
  4.1074 +	}
  4.1075 +	if (globp) {
  4.1076 +		if ((lastc = *globp++) != 0)
  4.1077 +			return(lastc);
  4.1078 +		globp = 0;
  4.1079 +		return(EOF);
  4.1080 +	}
  4.1081 +	if (read(0, &c, 1) <= 0)
  4.1082 +		return(lastc = EOF);
  4.1083 +	lastc = c;
  4.1084 +	return(lastc);
  4.1085 +}
  4.1086 +
  4.1087 +static int
  4.1088 +gettty(void)
  4.1089 +{
  4.1090 +	register int c, i;
  4.1091 +	register char *gf;
  4.1092 +
  4.1093 +	i = 0;
  4.1094 +	gf = globp;
  4.1095 +	while ((c = getchr()) != '\n') {
  4.1096 +		if (c==EOF) {
  4.1097 +			if (gf)
  4.1098 +				peekc = c;
  4.1099 +			return(c);
  4.1100 +		}
  4.1101 +		if (c == 0)
  4.1102 +			continue;
  4.1103 +		if (i >= LBSIZE)
  4.1104 +			growlb("line too long");
  4.1105 +		linebuf[i++] = c;
  4.1106 +	}
  4.1107 +	if (i >= LBSIZE-2)
  4.1108 +		growlb("line too long");
  4.1109 +	linebuf[i++] = 0;
  4.1110 +	if (linebuf[0]=='.' && linebuf[1]==0)
  4.1111 +		return(EOF);
  4.1112 +#if !defined (SUS) && !defined (SU3)
  4.1113 +	if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0)
  4.1114 +		linebuf[0]='.', linebuf[1]=0;
  4.1115 +#endif
  4.1116 +	return(0);
  4.1117 +}
  4.1118 +
  4.1119 +static long
  4.1120 +getnum(void)
  4.1121 +{
  4.1122 +	char	scount[20];
  4.1123 +	int	i;
  4.1124 +
  4.1125 +	i = 0;
  4.1126 +	while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) {
  4.1127 +		scount[i++] = peekc;
  4.1128 +		peekc = 0;
  4.1129 +	}
  4.1130 +	scount[i] = '\0';
  4.1131 +	return i ? atol(scount) : -1;
  4.1132 +}
  4.1133 +
  4.1134 +static int
  4.1135 +getfile(void)
  4.1136 +{
  4.1137 +	register int c, i, j;
  4.1138 +	static int	nextj;
  4.1139 +
  4.1140 +	i = 0;
  4.1141 +	j = nextj;
  4.1142 +	do {
  4.1143 +		if (--ninbuf < 0) {
  4.1144 +			if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) {
  4.1145 +				if (ioeof == 0 && ninbuf < -1) {
  4.1146 +					puts("input error");
  4.1147 +					status = 1;
  4.1148 +				}
  4.1149 +				if (i > 0) {
  4.1150 +					puts("'\\n' appended");
  4.1151 +					c = '\n';
  4.1152 +					ioeof = 1;
  4.1153 +					goto wrc;
  4.1154 +				}
  4.1155 +				return(EOF);
  4.1156 +			}
  4.1157 +			j = 0;
  4.1158 +		}
  4.1159 +		c = genbuf[j++]&0377;
  4.1160 +	wrc:	if (i >= LBSIZE) {
  4.1161 +			lastc = '\n';
  4.1162 +			growlb("line too long");
  4.1163 +		}
  4.1164 +		linebuf[i++] = c ? c : '\n';
  4.1165 +		count++;
  4.1166 +	} while (c != '\n');
  4.1167 +	linebuf[--i] = 0;
  4.1168 +	nextj = j;
  4.1169 +	if (rspec && dot == zero)
  4.1170 +		fspec(linebuf);
  4.1171 +	if (maxlength && i > maxlength) {
  4.1172 +		putstr("line too long: lno = ");
  4.1173 +		putd((dot - zero+1)&MAXCNT);
  4.1174 +		putchr('\n');
  4.1175 +	}
  4.1176 +	return(0);
  4.1177 +}
  4.1178 +
  4.1179 +static void
  4.1180 +putfile(void)
  4.1181 +{
  4.1182 +	long *a1;
  4.1183 +	int n;
  4.1184 +	register char *fp, *lp;
  4.1185 +	register int nib;
  4.1186 +
  4.1187 +	nib = 512;
  4.1188 +	fp = genbuf;
  4.1189 +	a1 = addr1;
  4.1190 +	do {
  4.1191 +		lp = getline(*a1++, 0);
  4.1192 +		if (maxlength) {
  4.1193 +			for (n = 0; lp[n]; n++);
  4.1194 +			if (n > maxlength) {
  4.1195 +				putstr("line too long: lno = ");
  4.1196 +				putd((a1-1 - zero)&MAXCNT);
  4.1197 +				putchr('\n');
  4.1198 +			}
  4.1199 +		}
  4.1200 +		for (;;) {
  4.1201 +			if (--nib < 0) {
  4.1202 +				n = fp-genbuf;
  4.1203 +				if(write(io, genbuf, n) != n)
  4.1204 +					error("write error");
  4.1205 +				nib = 511;
  4.1206 +				fp = genbuf;
  4.1207 +			}
  4.1208 +			count++;
  4.1209 +			if ((*fp++ = *lp++) == 0) {
  4.1210 +				fp[-1] = '\n';
  4.1211 +				break;
  4.1212 +			} else if (fp[-1] == '\n')
  4.1213 +				fp[-1] = '\0';
  4.1214 +		}
  4.1215 +	} while (a1 <= addr2);
  4.1216 +	n = fp-genbuf;
  4.1217 +	if(write(io, genbuf, n) != n)
  4.1218 +		error("write error");
  4.1219 +}
  4.1220 +
  4.1221 +static int
  4.1222 +append(int (*f)(void), long *a)
  4.1223 +{
  4.1224 +	register long *a1, *a2, *rdot;
  4.1225 +	int nline, tl;
  4.1226 +
  4.1227 +	nline = 0;
  4.1228 +	dot = a;
  4.1229 +	while ((*f)() == 0) {
  4.1230 +		if ((dol-zero)+1 >= nlall) {
  4.1231 +			long *ozero = zero;
  4.1232 +			nlall += 512;
  4.1233 +			if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) {
  4.1234 +				lastc = '\n';
  4.1235 +				zero = ozero;
  4.1236 +				error("out of memory for append");
  4.1237 +			}
  4.1238 +			dot += zero - ozero;
  4.1239 +			dol += zero - ozero;
  4.1240 +			addr1 += zero - ozero;
  4.1241 +			addr2 += zero - ozero;
  4.1242 +			if (unddot) {
  4.1243 +				unddot += zero - ozero;
  4.1244 +				unddol += zero - ozero;
  4.1245 +			}
  4.1246 +			if (undzero) {
  4.1247 +				ozero = undzero;
  4.1248 +				if ((undzero = realloc(undzero,
  4.1249 +						nlall*sizeof *undzero)) == 0) {
  4.1250 +					puts("no memory for undo");
  4.1251 +					free(ozero);
  4.1252 +				}
  4.1253 +			}
  4.1254 +		}
  4.1255 +		tl = putline();
  4.1256 +		nline++;
  4.1257 +		a1 = ++dol;
  4.1258 +		a2 = a1+1;
  4.1259 +		rdot = ++dot;
  4.1260 +		while (a1 > rdot)
  4.1261 +			*--a2 = *--a1;
  4.1262 +		*rdot = tl;
  4.1263 +	}
  4.1264 +	return(nline);
  4.1265 +}
  4.1266 +
  4.1267 +static void
  4.1268 +callunix(void)
  4.1269 +{
  4.1270 +	char	*line;
  4.1271 +	void (*savint)(int);
  4.1272 +	pid_t pid, rpid;
  4.1273 +	int retcode;
  4.1274 +
  4.1275 +	setnoaddr();
  4.1276 +	line = readcmd();
  4.1277 +	if ((pid = fork()) == 0) {
  4.1278 +		sigset(SIGHUP, oldhup);
  4.1279 +		sigset(SIGQUIT, oldquit);
  4.1280 +		sigset(SIGPIPE, oldpipe);
  4.1281 +		execl(SHELL, "sh", "-c", line, NULL);
  4.1282 +		_exit(0100);
  4.1283 +	} else if (pid < 0)
  4.1284 +		error("fork failed - try again");
  4.1285 +	savint = sigset(SIGINT, SIG_IGN);
  4.1286 +	while ((rpid = wait(&retcode)) != pid && rpid != -1)
  4.1287 +		;
  4.1288 +	sigset(SIGINT, savint);
  4.1289 +	if (vflag)
  4.1290 +		puts("!");
  4.1291 +}
  4.1292 +
  4.1293 +#define	cmadd(c)	((i>=cmsize ? \
  4.1294 +		((line=realloc(line,cmsize+=128)) == 0 ? \
  4.1295 +			(error("line too long"),0) : 0, 0) \
  4.1296 +		: 0), line[i++]=(c))
  4.1297 +
  4.1298 +static char *
  4.1299 +readcmd(void)
  4.1300 +{
  4.1301 +	static char	*line, *prev;
  4.1302 +	static int	cmsize, pvsize;
  4.1303 +	char	*pp;
  4.1304 +	int	c, mod = 0, i;
  4.1305 +
  4.1306 +	i = 0;
  4.1307 +	if ((c = getchr()) == '!') {
  4.1308 +		for (pp = prev; *pp; pp++)
  4.1309 +			line[i++] = *pp;
  4.1310 +		mod = 1;
  4.1311 +		c = getchr();
  4.1312 +	}
  4.1313 +	while (c != '\n' && c != EOF) {
  4.1314 +		if (c == '\\') {
  4.1315 +			c = getchr();
  4.1316 +			if (c != '%')
  4.1317 +				cmadd('\\');
  4.1318 +			cmadd(c);
  4.1319 +		} else if (c == '%') {
  4.1320 +			for (pp = savedfile; *pp; pp++)
  4.1321 +				cmadd(*pp);
  4.1322 +			mod = 1;
  4.1323 +		} else
  4.1324 +			cmadd(c);
  4.1325 +		c = getchr();
  4.1326 +	}
  4.1327 +	cmadd('\0');
  4.1328 +	if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0)
  4.1329 +		error("line too long");
  4.1330 +	strcpy(prev, line);
  4.1331 +	if (mod)
  4.1332 +		nlputs(line);
  4.1333 +	return line;
  4.1334 +}
  4.1335 +
  4.1336 +static void
  4.1337 +quit(int signo)
  4.1338 +{
  4.1339 +	lastsig = signo;
  4.1340 +	if (vflag && fchange) {
  4.1341 +		fchange = 0;
  4.1342 +		error("warning: expecting `w'");
  4.1343 +	}
  4.1344 +	if (wrtemp)
  4.1345 +		unlink(wrtemp);
  4.1346 +	unlink(tfname);
  4.1347 +	exit(status);
  4.1348 +}
  4.1349 +
  4.1350 +static void
  4.1351 +delete(void)
  4.1352 +{
  4.1353 +	setdot();
  4.1354 +	newline();
  4.1355 +	nonzero();
  4.1356 +	checkpoint();
  4.1357 +	rdelete(addr1, addr2);
  4.1358 +}
  4.1359 +
  4.1360 +static void
  4.1361 +rdelete(long *ad1, long *ad2)
  4.1362 +{
  4.1363 +	register long *a1, *a2, *a3;
  4.1364 +
  4.1365 +	a1 = ad1;
  4.1366 +	a2 = ad2+1;
  4.1367 +	a3 = dol;
  4.1368 +	dol -= a2 - a1;
  4.1369 +	do {
  4.1370 +		*a1++ = *a2++;
  4.1371 +	} while (a2 <= a3);
  4.1372 +	a1 = ad1;
  4.1373 +	if (a1 > dol)
  4.1374 +		a1 = dol;
  4.1375 +	dot = a1;
  4.1376 +	fchange = 1;
  4.1377 +}
  4.1378 +
  4.1379 +static void
  4.1380 +gdelete(void)
  4.1381 +{
  4.1382 +	register long *a1, *a2, *a3;
  4.1383 +
  4.1384 +	a3 = dol;
  4.1385 +	for (a1=zero+1; (*a1&01)==0; a1++)
  4.1386 +		if (a1>=a3)
  4.1387 +			return;
  4.1388 +	for (a2=a1+1; a2<=a3;) {
  4.1389 +		if (*a2&01) {
  4.1390 +			a2++;
  4.1391 +			dot = a1;
  4.1392 +		} else
  4.1393 +			*a1++ = *a2++;
  4.1394 +	}
  4.1395 +	dol = a1-1;
  4.1396 +	if (dot>dol)
  4.1397 +		dot = dol;
  4.1398 +	fchange = 1;
  4.1399 +}
  4.1400 +
  4.1401 +static char *
  4.1402 +getline(long tl, int nulterm)
  4.1403 +{
  4.1404 +	register char *bp, *lp;
  4.1405 +	register long nl;
  4.1406 +
  4.1407 +	lp = linebuf;
  4.1408 +	bp = getblock(tl, READ);
  4.1409 +	nl = nleft;
  4.1410 +	tl &= ~0377;
  4.1411 +	while (*lp++ = *bp++) {
  4.1412 +		if (lp[-1] == '\n' && nulterm) {
  4.1413 +			lp[-1] = '\0';
  4.1414 +			break;
  4.1415 +		}
  4.1416 +		if (--nl == 0) {
  4.1417 +			bp = getblock(tl+=0400, READ);
  4.1418 +			nl = nleft;
  4.1419 +		}
  4.1420 +	}
  4.1421 +	return(linebuf);
  4.1422 +}
  4.1423 +
  4.1424 +static int
  4.1425 +putline(void)
  4.1426 +{
  4.1427 +	register char *bp, *lp;
  4.1428 +	register long nl;
  4.1429 +	long tl;
  4.1430 +
  4.1431 +	fchange = 1;
  4.1432 +	lp = linebuf;
  4.1433 +	tl = tline;
  4.1434 +	bp = getblock(tl, WRITE);
  4.1435 +	nl = nleft;
  4.1436 +	tl &= ~0377;
  4.1437 +	while (*bp = *lp++) {
  4.1438 +		if (*bp++ == '\n' && insub) {
  4.1439 +			*--bp = 0;
  4.1440 +			linebp = lp;
  4.1441 +			break;
  4.1442 +		}
  4.1443 +		if (--nl == 0) {
  4.1444 +			bp = getblock(tl+=0400, WRITE);
  4.1445 +			nl = nleft;
  4.1446 +		}
  4.1447 +	}
  4.1448 +	nl = tline;
  4.1449 +	tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1);
  4.1450 +	return(nl);
  4.1451 +}
  4.1452 +
  4.1453 +static char *
  4.1454 +getblock(long atl, long iof)
  4.1455 +{
  4.1456 +	register long bno, off;
  4.1457 +	
  4.1458 +	bno = (atl>>8)&BLKMSK;
  4.1459 +	off = (atl<<1)&0774;
  4.1460 +	if (bno >= BLKMSK) {
  4.1461 +		lastc = '\n';
  4.1462 +		error("temp file too big");
  4.1463 +	}
  4.1464 +	nleft = 512 - off;
  4.1465 +	if (bno==iblock) {
  4.1466 +		ichanged |= iof;
  4.1467 +		return(ibuff+off);
  4.1468 +	}
  4.1469 +	if (bno==oblock)
  4.1470 +		return(obuff+off);
  4.1471 +	if (iof==READ) {
  4.1472 +		if (ichanged)
  4.1473 +			blkio(iblock, ibuff, 1);
  4.1474 +		ichanged = 0;
  4.1475 +		iblock = bno;
  4.1476 +		blkio(bno, ibuff, 0);
  4.1477 +		return(ibuff+off);
  4.1478 +	}
  4.1479 +	if (oblock>=0)
  4.1480 +		blkio(oblock, obuff, 1);
  4.1481 +	oblock = bno;
  4.1482 +	return(obuff+off);
  4.1483 +}
  4.1484 +
  4.1485 +static void
  4.1486 +blkio(long b, char *buf, int wr)
  4.1487 +{
  4.1488 +	lseek(tfile, b<<9, SEEK_SET);
  4.1489 +	if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) {
  4.1490 +		status = 1;
  4.1491 +		error("I/O error on temp file");
  4.1492 +	}
  4.1493 +}
  4.1494 +
  4.1495 +static void
  4.1496 +init(void)
  4.1497 +{
  4.1498 +	register long *markp;
  4.1499 +
  4.1500 +	tline = 2;
  4.1501 +	for (markp = names; markp < &names[26]; markp++)
  4.1502 +		*markp = 0;
  4.1503 +	for (markp = undnames; markp < &undnames[26]; markp++)
  4.1504 +		*markp = 0;
  4.1505 +	subnewa = 0;
  4.1506 +	anymarks = 0;
  4.1507 +	iblock = -1;
  4.1508 +	oblock = -1;
  4.1509 +	ichanged = 0;
  4.1510 +	tfile = maketf(tfile);
  4.1511 +	dot = dol = zero;
  4.1512 +	unddot = NULL;
  4.1513 +}
  4.1514 +
  4.1515 +static void
  4.1516 +global(int k, int ia)
  4.1517 +{
  4.1518 +	register int c;
  4.1519 +	register long *a1;
  4.1520 +	static char *globuf;
  4.1521 +	char	mb[MB_LEN_MAX+1];
  4.1522 +	int	spflag = 0;
  4.1523 +
  4.1524 +	if (globp)
  4.1525 +		error("multiple globals not allowed");
  4.1526 +	setall();
  4.1527 +	nonzero();
  4.1528 +	if ((c=GETWC(mb))=='\n')
  4.1529 +		error("incomplete global expression");
  4.1530 +	compile(NULL, expbuf, &expbuf[ESIZE], c);
  4.1531 +	if (!ia) {
  4.1532 +		globrd(&globuf, EOF);
  4.1533 +		if (globuf[0] == '\n')
  4.1534 +			globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0';
  4.1535 +	} else {
  4.1536 +		newline();
  4.1537 +		spflag = pflag;
  4.1538 +		pflag = 0;
  4.1539 +	}
  4.1540 +	checkpoint();
  4.1541 +	for (a1=zero; a1<=dol; a1++) {
  4.1542 +		*a1 &= ~01;
  4.1543 +		if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k)
  4.1544 +			*a1 |= 01;
  4.1545 +	}
  4.1546 +	/*
  4.1547 +	 * Special case: g/.../d (avoid n^2 algorithm)
  4.1548 +	 */
  4.1549 +	if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
  4.1550 +		gdelete();
  4.1551 +		return;
  4.1552 +	}
  4.1553 +	for (a1=zero; a1<=dol; a1++) {
  4.1554 +		if (*a1 & 01) {
  4.1555 +			*a1 &= ~01;
  4.1556 +			dot = a1;
  4.1557 +			if (ia) {
  4.1558 +				puts(getline(*a1, 0));
  4.1559 +				if ((c = getchr()) == EOF)
  4.1560 +					error("command expected");
  4.1561 +				if (c == 'a' || c == 'c' || c == 'i')
  4.1562 +					error("a, i, or c not allowed in G");
  4.1563 +				else if (c == '&') {
  4.1564 +					if ((c = getchr()) != '\n')
  4.1565 +						error("end of line expected");
  4.1566 +					if (globuf == 0 || *globuf == 0)
  4.1567 +						error("no remembered command");
  4.1568 +				} else if (c == '\n') {
  4.1569 +					a1 = zero;
  4.1570 +					continue;
  4.1571 +				} else
  4.1572 +					globrd(&globuf, c);
  4.1573 +			}
  4.1574 +			globp = globuf;
  4.1575 +			commands();
  4.1576 +			globp = NULL;
  4.1577 +			a1 = zero;
  4.1578 +		}
  4.1579 +	}
  4.1580 +	if (ia)
  4.1581 +		pflag = spflag;
  4.1582 +}
  4.1583 +
  4.1584 +static void
  4.1585 +globrd(char **globuf, register int c)
  4.1586 +{
  4.1587 +	register int i;
  4.1588 +
  4.1589 +	if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0)
  4.1590 +		error("global too long");
  4.1591 +	i = 0;
  4.1592 +	if (c != EOF)
  4.1593 +		(*globuf)[i++] = c;
  4.1594 +	while ((c = getchr()) != '\n') {
  4.1595 +		if (c==EOF)
  4.1596 +			error("incomplete global expression");
  4.1597 +		if (c=='\\') {
  4.1598 +			c = getchr();
  4.1599 +			if (c!='\n')
  4.1600 +				(*globuf)[i++] = '\\';
  4.1601 +		}
  4.1602 +		(*globuf)[i++] = c;
  4.1603 +		if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0)
  4.1604 +			error("global too long");
  4.1605 +	}
  4.1606 +	(*globuf)[i++] = '\n';
  4.1607 +	(*globuf)[i++] = 0;
  4.1608 +}
  4.1609 +
  4.1610 +static void
  4.1611 +join(void)
  4.1612 +{
  4.1613 +	register int i, j;
  4.1614 +	register long *a1;
  4.1615 +
  4.1616 +	j = 0;
  4.1617 +	for (a1=addr1; a1<=addr2; a1++) {
  4.1618 +		i = getline(*a1, 0) - linebuf;
  4.1619 +		while (genbuf[j] = linebuf[i++])
  4.1620 +			if (j++ >= LBSIZE-2)
  4.1621 +				growlb("line too long");
  4.1622 +	}
  4.1623 +	i = 0;
  4.1624 +	j = 0;
  4.1625 +	while (linebuf[i++] = genbuf[j++])
  4.1626 +		;
  4.1627 +	*addr1 = putline();
  4.1628 +	if (addr1<addr2)
  4.1629 +		rdelete(addr1+1, addr2);
  4.1630 +	dot = addr1;
  4.1631 +}
  4.1632 +
  4.1633 +static void
  4.1634 +substitute(int inglob)
  4.1635 +{
  4.1636 +	register long *markp;
  4.1637 +	register long *a1;
  4.1638 +	intptr_t nl;
  4.1639 +	int gsubf;
  4.1640 +
  4.1641 +	checkpoint();
  4.1642 +	gsubf = compsub();
  4.1643 +	insub = 1;
  4.1644 +	for (a1 = addr1; a1 <= addr2; a1++) {
  4.1645 +		long *ozero;
  4.1646 +		if (execute(0, a1, 1)==0)
  4.1647 +			continue;
  4.1648 +		inglob |= dosub(gsubf < 2);
  4.1649 +		if (gsubf) {
  4.1650 +			int	i = 1;
  4.1651 +
  4.1652 +			while (*loc2) {
  4.1653 +				if (execute(1, NULL, 1)==0)
  4.1654 +					break;
  4.1655 +				inglob |= dosub(gsubf == -1 || ++i == gsubf);
  4.1656 +			}
  4.1657 +		}
  4.1658 +		subnewa = putline();
  4.1659 +		*a1 &= ~01;
  4.1660 +		if (anymarks) {
  4.1661 +			for (markp = names; markp < &names[26]; markp++)
  4.1662 +				if (*markp == *a1)
  4.1663 +					*markp = subnewa;
  4.1664 +		}
  4.1665 +		*a1 = subnewa;
  4.1666 +		ozero = zero;
  4.1667 +		nl = append(getsub, a1);
  4.1668 +		nl += zero-ozero;
  4.1669 +		a1 += nl;
  4.1670 +		addr2 += nl;
  4.1671 +	}
  4.1672 +	insub = 0;
  4.1673 +	if (inglob==0)
  4.1674 +		error("no match");
  4.1675 +}
  4.1676 +
  4.1677 +static int
  4.1678 +compsub(void)
  4.1679 +{
  4.1680 +	register int seof, c, i;
  4.1681 +	static char	*oldrhs;
  4.1682 +	static int	orhssz;
  4.1683 +	char	mb[MB_LEN_MAX+1];
  4.1684 +
  4.1685 +	if ((seof = GETWC(mb)) == '\n' || seof == ' ')
  4.1686 +		error("illegal or missing delimiter");
  4.1687 +	nodelim = 0;
  4.1688 +	compile(NULL, expbuf, &expbuf[ESIZE], seof);
  4.1689 +	i = 0;
  4.1690 +	for (;;) {
  4.1691 +		c = GETWC(mb);
  4.1692 +		if (c=='\\') {
  4.1693 +			if (i >= RHSIZE-2)
  4.1694 +				growrhs("replacement string too long");
  4.1695 +			rhsbuf[i++] = c;
  4.1696 +			c = GETWC(mb);
  4.1697 +		} else if (c=='\n') {
  4.1698 +			if (globp && *globp) {
  4.1699 +				if (i >= RHSIZE-2)
  4.1700 +					growrhs("replacement string too long");
  4.1701 +				rhsbuf[i++] = '\\';
  4.1702 +			}
  4.1703 +			else if (nodelim)
  4.1704 +				error("illegal or missing delimiter");
  4.1705 +			else {
  4.1706 +				peekc = c;
  4.1707 +				pflag++;
  4.1708 +				break;
  4.1709 +			}
  4.1710 +		} else if (c==seof)
  4.1711 +			break;
  4.1712 +		for (c = 0; c==0 || mb[c]; c++) {
  4.1713 +			if (i >= RHSIZE-2)
  4.1714 +				growrhs("replacement string too long");
  4.1715 +			rhsbuf[i++] = mb[c];
  4.1716 +		}
  4.1717 +	}
  4.1718 +	rhsbuf[i++] = 0;
  4.1719 +	if (rhsbuf[0] == '%' && rhsbuf[1] == 0) {
  4.1720 +		if (orhssz == 0)
  4.1721 +			error("no remembered replacement string");
  4.1722 +		strcpy(rhsbuf, oldrhs);
  4.1723 +	} else {
  4.1724 +		if (orhssz < RHSIZE &&
  4.1725 +				(oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0)
  4.1726 +			error("replacement string too long");
  4.1727 +		strcpy(oldrhs, rhsbuf);
  4.1728 +	}
  4.1729 +	if ((peekc = getchr()) == 'g') {
  4.1730 +		peekc = 0;
  4.1731 +		newline();
  4.1732 +		return(-1);
  4.1733 +	} else if (peekc >= '0' && peekc <= '9') {
  4.1734 +		c = getnum();
  4.1735 +		if (c < 1 || c > LBSIZE)
  4.1736 +			error("invalid count");
  4.1737 +		newline();
  4.1738 +		return c;
  4.1739 +	}
  4.1740 +	newline();
  4.1741 +	return(0);
  4.1742 +}
  4.1743 +
  4.1744 +static int
  4.1745 +getsub(void)
  4.1746 +{
  4.1747 +	register char *p1, *p2;
  4.1748 +
  4.1749 +	p1 = linebuf;
  4.1750 +	if ((p2 = linebp) == 0)
  4.1751 +		return(EOF);
  4.1752 +	while (*p1++ = *p2++)
  4.1753 +		;
  4.1754 +	linebp = 0;
  4.1755 +	return(0);
  4.1756 +}
  4.1757 +
  4.1758 +static int
  4.1759 +dosub(int really)
  4.1760 +{
  4.1761 +	register char *lp, *sp;
  4.1762 +	register int i, j, k;
  4.1763 +	int c;
  4.1764 +
  4.1765 +	if (!really)
  4.1766 +		goto copy;
  4.1767 +	i = 0;
  4.1768 +	j = 0;
  4.1769 +	k = 0;
  4.1770 +	while (&linebuf[i] < loc1)
  4.1771 +		genbuf[j++] = linebuf[i++];
  4.1772 +	while (c = rhsbuf[k++]&0377) {
  4.1773 +		if (c=='&') {
  4.1774 +			j = place(j, loc1, loc2);
  4.1775 +			continue;
  4.1776 +		} else if (c == '\\') {
  4.1777 +			c = rhsbuf[k++]&0377;
  4.1778 +			if (c >='1' && c < nbra+'1') {
  4.1779 +				j = place(j, braslist[c-'1'], braelist[c-'1']);
  4.1780 +				continue;
  4.1781 +			}
  4.1782 +		}
  4.1783 +		if (j >= LBSIZE)
  4.1784 +			growlb("line too long");
  4.1785 +		genbuf[j++] = c;
  4.1786 +	}
  4.1787 +	i = loc2 - linebuf;
  4.1788 +	loc2 = j + linebuf;
  4.1789 +#if defined (SUS) || defined (SU3) || defined (S42)
  4.1790 +	if (loc1 == &linebuf[i]) {
  4.1791 +		int	n;
  4.1792 +		wchar_t	wc;
  4.1793 +		if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0)
  4.1794 +			loc2 += n;
  4.1795 +		else
  4.1796 +			loc2++;
  4.1797 +	}
  4.1798 +#endif	/* SUS || SU3 || S42 */
  4.1799 +	while (genbuf[j++] = linebuf[i++])
  4.1800 +		if (j >= LBSIZE)
  4.1801 +			growlb("line too long");
  4.1802 +	if (really) {
  4.1803 +		lp = linebuf;
  4.1804 +		sp = genbuf;
  4.1805 +	} else {
  4.1806 +	copy:	sp = linebuf;
  4.1807 +		lp = genbuf;
  4.1808 +	}
  4.1809 +	while (*lp++ = *sp++)
  4.1810 +		;
  4.1811 +	return really;
  4.1812 +}
  4.1813 +
  4.1814 +static int
  4.1815 +place(register int j, register const char *l1, register const char *l2)
  4.1816 +{
  4.1817 +
  4.1818 +	while (l1 < l2) {
  4.1819 +		genbuf[j++] = *l1++;
  4.1820 +		if (j >= LBSIZE)
  4.1821 +			growlb("line too long");
  4.1822 +	}
  4.1823 +	return(j);
  4.1824 +}
  4.1825 +
  4.1826 +static void
  4.1827 +move(int cflag)
  4.1828 +{
  4.1829 +	register long *adt, *ad1, *ad2;
  4.1830 +
  4.1831 +	setdot();
  4.1832 +	nonzero();
  4.1833 +	if ((adt = address())==0)
  4.1834 +		error("illegal move destination");
  4.1835 +	newline();
  4.1836 +	checkpoint();
  4.1837 +	if (cflag) {
  4.1838 +		long *ozero;
  4.1839 +		intptr_t delta;
  4.1840 +		ad1 = dol;
  4.1841 +		ozero = zero;
  4.1842 +		append(getcopy, ad1++);
  4.1843 +		ad2 = dol;
  4.1844 +		delta = zero - ozero;
  4.1845 +		ad1 += delta;
  4.1846 +		adt += delta;
  4.1847 +	} else {
  4.1848 +		ad2 = addr2;
  4.1849 +		for (ad1 = addr1; ad1 <= ad2;)
  4.1850 +			*ad1++ &= ~01;
  4.1851 +		ad1 = addr1;
  4.1852 +	}
  4.1853 +	ad2++;
  4.1854 +	if (adt<ad1) {
  4.1855 +		dot = adt + (ad2-ad1);
  4.1856 +		if ((++adt)==ad1)
  4.1857 +			return;
  4.1858 +		reverse(adt, ad1);
  4.1859 +		reverse(ad1, ad2);
  4.1860 +		reverse(adt, ad2);
  4.1861 +	} else if (adt >= ad2) {
  4.1862 +		dot = adt++;
  4.1863 +		reverse(ad1, ad2);
  4.1864 +		reverse(ad2, adt);
  4.1865 +		reverse(ad1, adt);
  4.1866 +	} else
  4.1867 +		error("illegal move destination");
  4.1868 +	fchange = 1;
  4.1869 +}
  4.1870 +
  4.1871 +static void
  4.1872 +reverse(register long *a1, register long *a2)
  4.1873 +{
  4.1874 +	register int t;
  4.1875 +
  4.1876 +	for (;;) {
  4.1877 +		t = *--a2;
  4.1878 +		if (a2 <= a1)
  4.1879 +			return;
  4.1880 +		*a2 = *a1;
  4.1881 +		*a1++ = t;
  4.1882 +	}
  4.1883 +}
  4.1884 +
  4.1885 +static int
  4.1886 +getcopy(void)
  4.1887 +{
  4.1888 +	if (addr1 > addr2)
  4.1889 +		return(EOF);
  4.1890 +	getline(*addr1++, 0);
  4.1891 +	return(0);
  4.1892 +}
  4.1893 +
  4.1894 +static int
  4.1895 +execute(int gf, long *addr, int subst)
  4.1896 +{
  4.1897 +	register char *p1, *p2, c;
  4.1898 +
  4.1899 +	for (c=0; c<NBRA; c++) {
  4.1900 +		braslist[c&0377] = 0;
  4.1901 +		braelist[c&0377] = 0;
  4.1902 +	}
  4.1903 +	if (gf) {
  4.1904 +		if (circf)
  4.1905 +			return(0);
  4.1906 +		p1 = linebuf;
  4.1907 +		p2 = genbuf;
  4.1908 +		while (*p1++ = *p2++)
  4.1909 +			;
  4.1910 +		locs = p1 = loc2;
  4.1911 +	} else {
  4.1912 +		if (addr==zero)
  4.1913 +			return(0);
  4.1914 +		p1 = getline(*addr, 1);
  4.1915 +		locs = 0;
  4.1916 +	}
  4.1917 +	needsub = subst;
  4.1918 +	return step(p1, expbuf);
  4.1919 +}
  4.1920 +
  4.1921 +static void
  4.1922 +cmplerr(int c)
  4.1923 +{
  4.1924 +	const char	*msg;
  4.1925 +
  4.1926 +#if !defined (SUS) && !defined (S42) && !defined (SU3)
  4.1927 +	expbuf[0] = 0;
  4.1928 +#endif
  4.1929 +	switch (c) {
  4.1930 +	case 11:
  4.1931 +		msg = "Range endpoint too large";
  4.1932 +		break;
  4.1933 +	case 16:
  4.1934 +		msg = "bad number";
  4.1935 +		break;
  4.1936 +	case 25:
  4.1937 +		msg = "`\\digit' out of range";
  4.1938 +		break;
  4.1939 +	case 36:
  4.1940 +		msg = "illegal or missing delimiter";
  4.1941 +		break;
  4.1942 +	case 41:
  4.1943 +		msg = "no remembered search string";
  4.1944 +		break;
  4.1945 +	case 42:
  4.1946 +		msg = "'\\( \\)' imbalance";
  4.1947 +		break;
  4.1948 +	case 43:
  4.1949 +		msg = "Too many `\\(' s";
  4.1950 +		break;
  4.1951 +	case 44:
  4.1952 +		msg = "more than 2 numbers given";
  4.1953 +		break;
  4.1954 +	case 45:
  4.1955 +		msg = "'\\}' expected";
  4.1956 +		break;
  4.1957 +	case 46:
  4.1958 +		msg = "first number exceeds second";
  4.1959 +		break;
  4.1960 +	case 49:
  4.1961 +		msg = "'[ ]' imbalance";
  4.1962 +		break;
  4.1963 +	case 50:
  4.1964 +		msg = "regular expression overflow";
  4.1965 +		break;
  4.1966 +	case 67:
  4.1967 +		msg = "illegal byte sequence";
  4.1968 +		break;
  4.1969 +	default:
  4.1970 +		msg = "regular expression error";
  4.1971 +		break;
  4.1972 +	}
  4.1973 +	error(msg);
  4.1974 +}
  4.1975 +
  4.1976 +static void
  4.1977 +doprnt(long *bot, long *top)
  4.1978 +{
  4.1979 +	long	*a1;
  4.1980 +
  4.1981 +	a1 = bot;
  4.1982 +	do {
  4.1983 +		if (numbf ^ Nflag) {
  4.1984 +			putd(a1-zero);
  4.1985 +			putchr('\t');
  4.1986 +		}
  4.1987 +		nlputs(getline(*a1++, 0));
  4.1988 +	} while (a1 <= top);
  4.1989 +	pflag = 0;
  4.1990 +	listf = 0;
  4.1991 +	numbf = 0;
  4.1992 +}
  4.1993 +
  4.1994 +static void
  4.1995 +putd(long c)
  4.1996 +{
  4.1997 +	register int r;
  4.1998 +
  4.1999 +	r = c%10;
  4.2000 +	c /= 10;
  4.2001 +	if (c)
  4.2002 +		putd(c);
  4.2003 +	putchr(r + '0');
  4.2004 +}
  4.2005 +
  4.2006 +static void
  4.2007 +nlputs(register const char *sp)
  4.2008 +{
  4.2009 +	if (listf)
  4.2010 +		list(sp);
  4.2011 +	else if (tabstops)
  4.2012 +		expand(sp);
  4.2013 +	else
  4.2014 +		puts(sp);
  4.2015 +}
  4.2016 +
  4.2017 +static void
  4.2018 +puts(register const char *sp)
  4.2019 +{
  4.2020 +	while (*sp) {
  4.2021 +		if (*sp != '\n')
  4.2022 +			putchr(*sp++ & 0377);
  4.2023 +		else
  4.2024 +			sp++, putchr('\0');
  4.2025 +	}
  4.2026 +	putchr('\n');
  4.2027 +}
  4.2028 +
  4.2029 +static void
  4.2030 +list(const char *lp)
  4.2031 +{
  4.2032 +	int col, n;
  4.2033 +	wchar_t c;
  4.2034 +
  4.2035 +	col = numbf ^ Nflag ? 8 : 0;
  4.2036 +	while (*lp) {
  4.2037 +		if (mb_cur_max > 1 && *lp&0200)
  4.2038 +			n = mbtowc(&c, lp, mb_cur_max);
  4.2039 +		else {
  4.2040 +			n = 1;
  4.2041 +			c = *lp&0377;
  4.2042 +		}
  4.2043 +		if (col+1 >= 72) {
  4.2044 +			col = 0;
  4.2045 +			putchr('\\');
  4.2046 +			putchr('\n');
  4.2047 +		}
  4.2048 +		if (n<0 ||
  4.2049 +#if defined (SUS) || defined (S42) || defined (SU3)
  4.2050 +				c == '\\' ||
  4.2051 +#endif	/* SUS || S42 || SU3 */
  4.2052 +				!(mb_cur_max>1 ? iswprint(c) : isprint(c))) {
  4.2053 +			if (n<0)
  4.2054 +				n = 1;
  4.2055 +			while (n--)
  4.2056 +				col += lstchr(*lp++&0377);
  4.2057 +		} else if (mb_cur_max>1) {
  4.2058 +			col += wcwidth(c);
  4.2059 +			while (n--)
  4.2060 +				putchr(*lp++&0377);
  4.2061 +		} else {
  4.2062 +			putchr(*lp++&0377);
  4.2063 +			col++;
  4.2064 +		}
  4.2065 +	}
  4.2066 +#if defined (SUS) || defined (S42) || defined (SU3)
  4.2067 +	putchr('$');
  4.2068 +#endif
  4.2069 +	putchr('\n');
  4.2070 +}
  4.2071 +
  4.2072 +static int
  4.2073 +lstchr(int c)
  4.2074 +{
  4.2075 +	int	cad = 1, d;
  4.2076 +
  4.2077 +#if !defined (SUS) && !defined (S42) && !defined (SU3)
  4.2078 +	if (c=='\t') {
  4.2079 +		c = '>';
  4.2080 +		goto esc;
  4.2081 +	}
  4.2082 +	if (c=='\b') {
  4.2083 +		c = '<';
  4.2084 +	esc:
  4.2085 +		putchr('-');
  4.2086 +		putchr('\b');
  4.2087 +		putchr(c);
  4.2088 +	} else if (c == '\n') {
  4.2089 +		putchr('\\');
  4.2090 +		putchr('0');
  4.2091 +		putchr('0');
  4.2092 +		putchr('0');
  4.2093 +		cad = 4;
  4.2094 +#else	/* !SUS, !S42, !SU3 */
  4.2095 +	if (c == '\n')
  4.2096 +		c = '\0';
  4.2097 +	if (c == '\\') {
  4.2098 +		putchr('\\');
  4.2099 +		putchr('\\');
  4.2100 +		cad = 2;
  4.2101 +	} else if (c == '\a') {
  4.2102 +		putchr('\\');
  4.2103 +		putchr('a');
  4.2104 +		cad = 2;
  4.2105 +	} else if (c == '\b') {
  4.2106 +		putchr('\\');
  4.2107 +		putchr('b');
  4.2108 +		cad = 2;
  4.2109 +	} else if (c == '\f') {
  4.2110 +		putchr('\\');
  4.2111 +		putchr('f');
  4.2112 +		cad = 2;
  4.2113 +	} else if (c == '\r') {
  4.2114 +		putchr('\\');
  4.2115 +		putchr('r');
  4.2116 +		cad = 2;
  4.2117 +	} else if (c == '\t') {
  4.2118 +		putchr('\\');
  4.2119 +		putchr('t');
  4.2120 +		cad = 2;
  4.2121 +	} else if (c == '\v') {
  4.2122 +		putchr('\\');
  4.2123 +		putchr('v');
  4.2124 +		cad = 2;
  4.2125 +#endif	/* !SUS, !S42, !SU3 */
  4.2126 +	} else {
  4.2127 +		putchr('\\');
  4.2128 +		putchr(((c&~077)>>6)+'0');
  4.2129 +		c &= 077;
  4.2130 +		d = c & 07;
  4.2131 +		putchr(c > d ? ((c-d)>>3)+'0' : '0');
  4.2132 +		putchr(d+'0');
  4.2133 +		cad = 4;
  4.2134 +	}
  4.2135 +	return cad;
  4.2136 +}
  4.2137 +
  4.2138 +static void
  4.2139 +putstr(const char *s)
  4.2140 +{
  4.2141 +	while (*s)
  4.2142 +		putchr(*s++);
  4.2143 +}
  4.2144 +
  4.2145 +static char	line[70];
  4.2146 +static char	*linp	= line;
  4.2147 +
  4.2148 +static void
  4.2149 +putchr(int ac)
  4.2150 +{
  4.2151 +	register char *lp;
  4.2152 +	register int c;
  4.2153 +
  4.2154 +	lp = linp;
  4.2155 +	c = ac;
  4.2156 +	*lp++ = c;
  4.2157 +	if(c == '\n' || lp >= &line[64]) {
  4.2158 +		linp = line;
  4.2159 +		write(1, line, lp-line);
  4.2160 +		return;
  4.2161 +	}
  4.2162 +	linp = lp;
  4.2163 +}
  4.2164 +
  4.2165 +static void
  4.2166 +checkpoint(void)
  4.2167 +{
  4.2168 +	long	*a1, *a2;
  4.2169 +
  4.2170 +	if (undzero && globp == NULL) {
  4.2171 +		for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++)
  4.2172 +			*a2 = *a1;
  4.2173 +		unddot = &undzero[dot-zero];
  4.2174 +		unddol = &undzero[dol-zero];
  4.2175 +		for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++)
  4.2176 +			*a2 = *a1;
  4.2177 +	}
  4.2178 +}
  4.2179 +
  4.2180 +#define	swap(a, b)	(t = a, a = b, b = t)
  4.2181 +
  4.2182 +static void
  4.2183 +undo(void)
  4.2184 +{
  4.2185 +	long	*t;
  4.2186 +
  4.2187 +	if (undzero == NULL)
  4.2188 +		error("no undo information saved");
  4.2189 +	swap(zero, undzero);
  4.2190 +	swap(dot, unddot);
  4.2191 +	swap(dol, unddol);
  4.2192 +	swap(names, undnames);
  4.2193 +}
  4.2194 +
  4.2195 +static int
  4.2196 +maketf(int fd)
  4.2197 +{
  4.2198 +	char	*tmpdir;
  4.2199 +
  4.2200 +	if (fd == -1) {
  4.2201 +		if ((tmpdir = getenv("TMPDIR")) == NULL ||
  4.2202 +				(fd = creatf(tmpdir)) < 0)
  4.2203 +			if ((fd = creatf("/var/tmp")) < 0 &&
  4.2204 +					(fd = creatf("/tmp")) < 0)
  4.2205 +				error("cannot create temporary file");
  4.2206 +	} else
  4.2207 +		ftruncate(fd, 0);	/* blkio() will seek to 0 anyway */
  4.2208 +	return fd;
  4.2209 +}
  4.2210 +
  4.2211 +static int
  4.2212 +creatf(const char *tmpdir)
  4.2213 +{
  4.2214 +	if (strlen(tmpdir) >= sizeof tfname - 9)
  4.2215 +		return -1;
  4.2216 +	strcpy(tfname, tmpdir);
  4.2217 +	strcat(tfname, "/eXXXXXX");
  4.2218 +	return mkstemp(tfname);
  4.2219 +}
  4.2220 +
  4.2221 +static int
  4.2222 +sopen(const char *fn, int rdwr)
  4.2223 +{
  4.2224 +	int	pf[2], fd = -1;
  4.2225 +
  4.2226 +	if (fn[0] == '!') {
  4.2227 +		fn++;
  4.2228 +		if (pipe(pf) < 0)
  4.2229 +			error("write or open on pipe failed");
  4.2230 +		switch (pipid = fork()) {
  4.2231 +		case 0:
  4.2232 +			if (rdwr == READ)
  4.2233 +				dup2(pf[1], 1);
  4.2234 +			else
  4.2235 +				dup2(pf[0], 0);
  4.2236 +			close(pf[0]);
  4.2237 +			close(pf[1]);
  4.2238 +			sigset(SIGHUP, oldhup);
  4.2239 +			sigset(SIGQUIT, oldquit);
  4.2240 +			sigset(SIGPIPE, oldpipe);
  4.2241 +			execl(SHELL, "sh", "-c", fn, NULL);
  4.2242 +			_exit(0100);
  4.2243 +		default:
  4.2244 +			close(pf[rdwr == READ ? 1 : 0]);
  4.2245 +			fd = pf[rdwr == READ ? 0 : 1];
  4.2246 +			break;
  4.2247 +		case -1:
  4.2248 +			error("fork failed - try again");
  4.2249 +		}
  4.2250 +	} else if (rdwr == READ)
  4.2251 +		fd = open(fn, O_RDONLY);
  4.2252 +	else if (rdwr == EXIST)
  4.2253 +		fd = open(fn, O_WRONLY);
  4.2254 +	else /*if (rdwr == WRITE)*/
  4.2255 +		fd = creat(fn, 0666);
  4.2256 +	if (fd >= 0 && rdwr == READ)
  4.2257 +		readop = 1;
  4.2258 +	if (fd >= 0)
  4.2259 +		fstat(fd, &fstbuf);
  4.2260 +	return fd;
  4.2261 +}
  4.2262 +
  4.2263 +static void
  4.2264 +sclose(int fd)
  4.2265 +{
  4.2266 +	int	status;
  4.2267 +
  4.2268 +	close(fd);
  4.2269 +	if (pipid >= 0) {
  4.2270 +		while (wait(&status) != pipid);
  4.2271 +		pipid = -1;
  4.2272 +	}
  4.2273 +	readop = 0;
  4.2274 +}
  4.2275 +
  4.2276 +static void
  4.2277 +fspec(const char *lp)
  4.2278 +{
  4.2279 +	struct termios	ts;
  4.2280 +	const char	*cp;
  4.2281 +
  4.2282 +	freetabs();
  4.2283 +	maxlength = 0;
  4.2284 +	if (tcgetattr(1, &ts) < 0
  4.2285 +#ifdef	TAB3
  4.2286 +			|| (ts.c_oflag&TAB3) == 0
  4.2287 +#endif
  4.2288 +			)
  4.2289 +		return;
  4.2290 +	while (lp[0]) {
  4.2291 +		if (lp[0] == '<' && lp[1] == ':')
  4.2292 +			break;
  4.2293 +		lp++;
  4.2294 +	}
  4.2295 +	if (lp[0]) {
  4.2296 +		lp += 2;
  4.2297 +		while ((cp = ftok(&lp)) != NULL) {
  4.2298 +			switch (*cp) {
  4.2299 +			case 't':
  4.2300 +				freetabs();
  4.2301 +				if ((tabstops = tabstring(&cp[1])) == NULL)
  4.2302 +					goto err;
  4.2303 +				break;
  4.2304 +			case 's':
  4.2305 +				maxlength = atoi(&cp[1]);
  4.2306 +				break;
  4.2307 +			case 'm':
  4.2308 +			case 'd':
  4.2309 +			case 'e':
  4.2310 +				break;
  4.2311 +			case ':':
  4.2312 +				if (cp[1] == '>') {
  4.2313 +					if (tabstops == NULL)
  4.2314 +						if ((tabstops = tabstring("0"))
  4.2315 +								== NULL)
  4.2316 +							goto err;
  4.2317 +					return;
  4.2318 +				}
  4.2319 +				/*FALLTHRU*/
  4.2320 +			default:
  4.2321 +			err:	freetabs();
  4.2322 +				maxlength = 0;
  4.2323 +				errput("PWB spec problem", NULL);
  4.2324 +				return;
  4.2325 +			}
  4.2326 +		}
  4.2327 +	}
  4.2328 +}
  4.2329 +
  4.2330 +static const char *
  4.2331 +ftok(const char **lp)
  4.2332 +{
  4.2333 +	const char	*cp;
  4.2334 +
  4.2335 +	while (**lp && **lp != ':' && (**lp == ' ' || **lp == '\t'))
  4.2336 +		(*lp)++;
  4.2337 +	cp = *lp;
  4.2338 +	while (**lp && **lp != ':' && **lp != ' ' && **lp != '\t')
  4.2339 +		(*lp)++;
  4.2340 +	return cp;
  4.2341 +}
  4.2342 +
  4.2343 +static struct tabulator *
  4.2344 +repetitive(int repetition)
  4.2345 +{
  4.2346 +	struct tabulator	*tp, *tabspec;
  4.2347 +	int	col, i;
  4.2348 +
  4.2349 +	if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL)
  4.2350 +		return NULL;
  4.2351 +	tp->t_rep = repetition;
  4.2352 +	if (repetition > 0) {
  4.2353 +		 for (col = 1+repetition, i = 0; i < 22; col += repetition) {
  4.2354 +			if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL)
  4.2355 +				return NULL;
  4.2356 +			tp = tp->t_nxt;
  4.2357 +			tp->t_tab = col;
  4.2358 +		}
  4.2359 +	}
  4.2360 +	return tabspec;
  4.2361 +}
  4.2362 +
  4.2363 +#define	blank(c)	((c) == ' ' || (c) == '\t')
  4.2364 +
  4.2365 +static struct tabulator *
  4.2366 +tablist(const char *s)
  4.2367 +{
  4.2368 +	struct tabulator	*tp, *tabspec;
  4.2369 +	char	*x;
  4.2370 +	int	prev = 0, val;
  4.2371 +
  4.2372 +	if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL)
  4.2373 +		return NULL;
  4.2374 +	for (;;) {
  4.2375 +		while (*s == ',')
  4.2376 +			s++;
  4.2377 +		if (*s == '\0' || blank(*s) || *s == ':')
  4.2378 +			break;
  4.2379 +		val = strtol(s, &x, 10);
  4.2380 +		if (*s == '+')
  4.2381 +			val += prev;
  4.2382 +		prev = val;
  4.2383 +		if (*s == '-' || (*x != ',' && !blank(*x) && *x != ':' &&
  4.2384 +					*x != '\0'))
  4.2385 +			return NULL;
  4.2386 +		s = x;
  4.2387 +		if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL)
  4.2388 +			return NULL;
  4.2389 +		tp = tp->t_nxt;
  4.2390 +		tp->t_tab = val;
  4.2391 +	}
  4.2392 +	return tabspec;
  4.2393 +}
  4.2394 +
  4.2395 +static struct tabulator *
  4.2396 +tabstring(const char *s)
  4.2397 +{
  4.2398 +	const struct {
  4.2399 +		const char	*c_nam;
  4.2400 +		const char	*c_str;
  4.2401 +	} canned[] = {
  4.2402 +		{ "a",	"1,10,16,36,72" },
  4.2403 +		{ "a2",	"1,10,16,40,72" },
  4.2404 +		{ "c",	"1,8,12,16,20,55" },
  4.2405 +		{ "c2",	"1,6,10,14,49" },
  4.2406 +		{ "c3",	"1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67" },
  4.2407 +		{ "f",	"1,7,11,15,19,23" },
  4.2408 +		{ "p",	"1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61" },
  4.2409 +		{ "s",	"1,10,55" },
  4.2410 +		{ "u",	"1,12,20,44" },
  4.2411 +		{ 0,	0 }
  4.2412 +	};
  4.2413 +
  4.2414 +	int	i, j;
  4.2415 +
  4.2416 +	if (s[0] == '-') {
  4.2417 +		if (s[1] >= '0' && s[1] <= '9' && ((i = atoi(&s[1])) != 0))
  4.2418 +			return repetitive(i);
  4.2419 +		for (i = 0; canned[i].c_nam; i++) {
  4.2420 +			for (j = 0; canned[i].c_nam[j]; j++)
  4.2421 +				if (s[j+1] != canned[i].c_nam[j])
  4.2422 +					break;
  4.2423 +			if ((s[j+1]=='\0' || s[j+1]==':' || blank(s[j+1])) &&
  4.2424 +					canned[i].c_nam[j] == '\0')
  4.2425 +				return tablist(canned[i].c_str);
  4.2426 +		}
  4.2427 +		return NULL;
  4.2428 +	} else
  4.2429 +		return tablist(s);
  4.2430 +}
  4.2431 +
  4.2432 +static void
  4.2433 +freetabs(void)
  4.2434 +{
  4.2435 +	struct tabulator	*tp;
  4.2436 +
  4.2437 +	tp = tabstops;
  4.2438 +	while (tp) {
  4.2439 +		tabstops = tp->t_nxt;
  4.2440 +		free(tp);
  4.2441 +		tp = tabstops;
  4.2442 +	}
  4.2443 +}
  4.2444 +
  4.2445 +static void
  4.2446 +expand(const char *s)
  4.2447 +{
  4.2448 +	struct tabulator	*tp = tabstops;
  4.2449 +	int	col = 0, n = 1, m, tabcnt = 0, nspc;
  4.2450 +	wchar_t	wc;
  4.2451 +
  4.2452 +	while (*s) {
  4.2453 +		nspc = 0;
  4.2454 +		switch (*s) {
  4.2455 +		case '\n':
  4.2456 +			putchr('\0');
  4.2457 +			s++;
  4.2458 +			continue;
  4.2459 +		case '\t':
  4.2460 +			if (tp) {
  4.2461 +				if (tp->t_rep) {
  4.2462 +					if (col % tp->t_rep == 0) {
  4.2463 +						nspc++;
  4.2464 +						col++;
  4.2465 +					}
  4.2466 +					while (col % tp->t_rep) {
  4.2467 +						nspc++;
  4.2468 +						col++;
  4.2469 +					}
  4.2470 +					break;
  4.2471 +				}
  4.2472 +				while (tp && (col>tp->t_tab || tp->t_tab == 0))
  4.2473 +					tp = tp->t_nxt;
  4.2474 +				if (tp && col == tp->t_tab) {
  4.2475 +					nspc++;
  4.2476 +					col++;
  4.2477 +					tp = tp->t_nxt;
  4.2478 +				}
  4.2479 +				if (tp) {
  4.2480 +					while (col < tp->t_tab) {
  4.2481 +						nspc++;
  4.2482 +						col++;
  4.2483 +					}
  4.2484 +					tp = tp->t_nxt;
  4.2485 +					break;
  4.2486 +				}
  4.2487 +			}
  4.2488 +			tabcnt = 1;
  4.2489 +			nspc++;
  4.2490 +			break;
  4.2491 +		default:
  4.2492 +			if (mb_cur_max>1 && (n=mbtowc(&wc, s, mb_cur_max))>0) {
  4.2493 +				if ((m = wcwidth(wc)) > 0)
  4.2494 +					col += m;
  4.2495 +			} else {
  4.2496 +				col++;
  4.2497 +				n = 1;
  4.2498 +			}
  4.2499 +		}
  4.2500 +		if (maxlength && col > maxlength) {
  4.2501 +			putstr("\ntoo long");
  4.2502 +			break;
  4.2503 +		}
  4.2504 +		if (nspc) {
  4.2505 +			while (nspc--)
  4.2506 +				putchr(' ');
  4.2507 +			s++;
  4.2508 +		} else
  4.2509 +			while (n--)
  4.2510 +				putchr(*s++);
  4.2511 +	}
  4.2512 +	if (tabcnt)
  4.2513 +		putstr("\ntab count");
  4.2514 +	putchr('\n');
  4.2515 +}
  4.2516 +
  4.2517 +static wint_t
  4.2518 +GETWC(char *mb)
  4.2519 +{
  4.2520 +	int	c, n;
  4.2521 +
  4.2522 +	n = 1;
  4.2523 +	mb[0] = c = GETC();
  4.2524 +	mb[1] = '\0';
  4.2525 +	if (mb_cur_max > 1 && c&0200 && c != EOF) {
  4.2526 +		int	m;
  4.2527 +		wchar_t	wc;
  4.2528 +
  4.2529 +		while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n<mb_cur_max) {
  4.2530 +			mb[n++] = c = GETC();
  4.2531 +			mb[n] = '\0';
  4.2532 +			if (c == '\n' || c == EOF)
  4.2533 +				break;
  4.2534 +		}
  4.2535 +		if (m != n)
  4.2536 +			ERROR(67);
  4.2537 +		return wc;
  4.2538 +	} else
  4.2539 +		return c;
  4.2540 +}
  4.2541 +
  4.2542 +static void
  4.2543 +growlb(const char *msg)
  4.2544 +{
  4.2545 +	char	*olb = linebuf;
  4.2546 +	int	i;
  4.2547 +
  4.2548 +	LBSIZE += 512;
  4.2549 +	if ((linebuf = realloc(linebuf, LBSIZE)) == NULL ||
  4.2550 +			(genbuf = realloc(genbuf, LBSIZE)) == NULL)
  4.2551 +		error(msg);
  4.2552 +	if (linebuf != olb) {
  4.2553 +		loc1 += linebuf - olb;
  4.2554 +		loc2 += linebuf - olb;
  4.2555 +		for (i = 0; i < NBRA; i++) {
  4.2556 +			if (braslist[i])
  4.2557 +				braslist[i] += linebuf - olb;
  4.2558 +			if (braelist[i])
  4.2559 +				braelist[i] += linebuf - olb;
  4.2560 +		}
  4.2561 +	}
  4.2562 +}
  4.2563 +
  4.2564 +static void
  4.2565 +growrhs(const char *msg)
  4.2566 +{
  4.2567 +	RHSIZE += 256;
  4.2568 +	if ((rhsbuf = realloc(rhsbuf, RHSIZE)) == NULL)
  4.2569 +		error(msg);
  4.2570 +}
  4.2571 +
  4.2572 +static void
  4.2573 +growfn(const char *msg)
  4.2574 +{
  4.2575 +	FNSIZE += 64;
  4.2576 +	if ((savedfile = realloc(savedfile, FNSIZE)) == NULL ||
  4.2577 +			(file = realloc(file, FNSIZE)) == NULL)
  4.2578 +		error(msg);
  4.2579 +	if (FNSIZE == 64)
  4.2580 +		file[0] = savedfile[0] = 0;
  4.2581 +}
  4.2582 +
  4.2583 +#if defined (SUS) || defined (S42) || defined (SU3)
  4.2584 +union	ptrstore {
  4.2585 +	void	*vp;
  4.2586 +	char	bp[sizeof (void *)];
  4.2587 +};
  4.2588 +
  4.2589 +static void *
  4.2590 +fetchptr(const char *bp)
  4.2591 +{
  4.2592 +	union ptrstore	u;
  4.2593 +	int	i;
  4.2594 +
  4.2595 +	for (i = 0; i < sizeof (void *); i++)
  4.2596 +		u.bp[i] = bp[i];
  4.2597 +	return u.vp;
  4.2598 +}
  4.2599 +
  4.2600 +static void
  4.2601 +storeptr(void *vp, char *bp)
  4.2602 +{
  4.2603 +	union ptrstore	u;
  4.2604 +	int	i;
  4.2605 +
  4.2606 +	u.vp = vp;
  4.2607 +	for (i = 0; i < sizeof (void *); i++)
  4.2608 +		bp[i] = u.bp[i];
  4.2609 +}
  4.2610 +
  4.2611 +#define	add(c)	((i>=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \
  4.2612 +		genbuf[i++] = (c))
  4.2613 +
  4.2614 +#define	copy(s)	{ \
  4.2615 +	int	m; \
  4.2616 +	for (m = 0; m==0 || s[m]; m++) \
  4.2617 +		add(s[m]); \
  4.2618 +}
  4.2619 +
  4.2620 +static char *
  4.2621 +compile(char *unused, char *ep, const char *endbuf, int seof)
  4.2622 +{
  4.2623 +	INIT
  4.2624 +	int	c, d, i;
  4.2625 +	regex_t	*rp;
  4.2626 +	char	*op;
  4.2627 +	char	mb[MB_LEN_MAX+1];
  4.2628 +
  4.2629 +	op = ep;
  4.2630 +	ep += 2;
  4.2631 +	if ((rp = fetchptr(ep)) == NULL) {
  4.2632 +		if ((rp = calloc(1, sizeof *rp)) == NULL)
  4.2633 +			ERROR(50);
  4.2634 +		storeptr(rp, ep);
  4.2635 +	}
  4.2636 +	ep += sizeof (void *);
  4.2637 +	i = 0;
  4.2638 +	nbra = 0;
  4.2639 +	do {
  4.2640 +		if ((c = GETWC(mb)) == seof)
  4.2641 +			add('\0');
  4.2642 +		else if (c == '\\') {
  4.2643 +			copy(mb);
  4.2644 +			c = GETWC(mb);
  4.2645 +			if (c == '(')
  4.2646 +				nbra++;
  4.2647 +			goto normchar;
  4.2648 +		} else if (c == '[') {
  4.2649 +			add(c);
  4.2650 +			d = EOF;
  4.2651 +			do {
  4.2652 +				c = GETWC(mb);
  4.2653 +				if (c == EOF || c == '\n')
  4.2654 +					ERROR(49);
  4.2655 +				copy(mb);
  4.2656 +				if (d=='[' && (c==':' || c=='.' || c=='=')) {
  4.2657 +					d = c;
  4.2658 +					do {
  4.2659 +						c = GETWC(mb);
  4.2660 +						if (c == EOF || c == '\n')
  4.2661 +							ERROR(49);
  4.2662 +						copy(mb);
  4.2663 +					} while (c != d || PEEKC() != ']');
  4.2664 +					c = GETWC(mb);
  4.2665 +					copy(mb);
  4.2666 +					c = EOF;
  4.2667 +				}
  4.2668 +				d = c;
  4.2669 +			} while (c != ']');
  4.2670 +		} else {
  4.2671 +			if (c == EOF || c == '\n') {
  4.2672 +				if (c == '\n')
  4.2673 +					UNGETC(c);
  4.2674 +				mb[0] = c = '\0';
  4.2675 +			}
  4.2676 +			if (c == '\0')
  4.2677 +				nodelim = 1;
  4.2678 +	normchar:	copy(mb);
  4.2679 +		}
  4.2680 +	} while (genbuf[i-1] != '\0');
  4.2681 +	if (genbuf[0]) {
  4.2682 +		int	reflags = 0;
  4.2683 +
  4.2684 +#ifdef	REG_ANGLES
  4.2685 +		reflags |= REG_ANGLES;
  4.2686 +#endif
  4.2687 +#if defined (SU3) && defined (REG_AVOIDNULL)
  4.2688 +		reflags |= REG_AVOIDNULL;
  4.2689 +#endif
  4.2690 +		if (op[0])
  4.2691 +			regfree(rp);
  4.2692 +		op[0] = 0;
  4.2693 +		switch (regcomp(rp, genbuf, reflags)) {
  4.2694 +		case 0:
  4.2695 +			break;
  4.2696 +		case REG_ESUBREG:
  4.2697 +			ERROR(25);
  4.2698 +			/*NOTREACHED*/
  4.2699 +		case REG_EBRACK:
  4.2700 +			ERROR(49);
  4.2701 +			/*NOTREACHED*/
  4.2702 +		case REG_EPAREN:
  4.2703 +			ERROR(42);
  4.2704 +			/*NOTREACHED*/
  4.2705 +		case REG_BADBR:
  4.2706 +		case REG_EBRACE:
  4.2707 +			ERROR(45);
  4.2708 +			/*NOTREACHED*/
  4.2709 +		case REG_ERANGE:
  4.2710 +			ERROR(11);
  4.2711 +			/*NOTREACHED*/
  4.2712 +		case REG_ESPACE:
  4.2713 +			ERROR(50);
  4.2714 +			/*NOTREACHED*/
  4.2715 +		default:
  4.2716 +			ERROR(-1);
  4.2717 +		}
  4.2718 +		op[0] = 1;
  4.2719 +		circf = op[1] = genbuf[0] == '^';
  4.2720 +	} else if (op[0]) {
  4.2721 +		circf = op[1];
  4.2722 +	} else
  4.2723 +		ERROR(41);
  4.2724 +	return ep + sizeof (void *);
  4.2725 +}
  4.2726 +
  4.2727 +static int
  4.2728 +step(const char *lp, const char *ep)
  4.2729 +{
  4.2730 +	regex_t	*rp;
  4.2731 +	regmatch_t	bralist[NBRA+1];
  4.2732 +	int	eflag = 0;
  4.2733 +	int	res;
  4.2734 +	int	i;
  4.2735 +
  4.2736 +	rp = fetchptr(&ep[2]);
  4.2737 +	if (ep[0] == 0)
  4.2738 +		return 0;
  4.2739 +	if (locs)
  4.2740 +		eflag |= REG_NOTBOL;
  4.2741 +	if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 &&
  4.2742 +			needsub) {
  4.2743 +		loc1 = (char *)lp + bralist[0].rm_so;
  4.2744 +		loc2 = (char *)lp + bralist[0].rm_eo;
  4.2745 +		for (i = 1; i <= NBRA; i++) {
  4.2746 +			if (bralist[i].rm_so != -1) {
  4.2747 +				braslist[i-1] = (char *)lp + bralist[i].rm_so;
  4.2748 +				braelist[i-1] = (char *)lp + bralist[i].rm_eo;
  4.2749 +			} else
  4.2750 +				braslist[i-1] = braelist[i-1] = NULL;
  4.2751 +		}
  4.2752 +	}
  4.2753 +	return res == 0;
  4.2754 +}
  4.2755 +#endif	/* SUS || S42 || SU3 */
  4.2756 +
  4.2757 +static void
  4.2758 +help(void)
  4.2759 +{
  4.2760 +	const char	*desc[] = {
  4.2761 +		"(.)a            append up to .",
  4.2762 +		"(.)b[n]         browse n lines",
  4.2763 +		"(.,.)c          change up to .",
  4.2764 +		"(.,.)d          delete lines",
  4.2765 +		"e [file]        edit file",
  4.2766 +		"E [file]        force edit",
  4.2767 +		"f [file]        print or set file",
  4.2768 +		"(1,$)g/RE/cmd   global cmd",
  4.2769 +		"(1,$)G/RE/      interactive global",
  4.2770 +		"h               print last error",
  4.2771 +		"H               toggle error messages",
  4.2772 +		"help            print this screen",
  4.2773 +		"(.)i            insert up to .",
  4.2774 +		"(.,.+1)j        join lines",
  4.2775 +		"(.)kx           mark line with x",
  4.2776 +		"(.,.)l          list lines",
  4.2777 +		"(.,.)ma         move lines to a",
  4.2778 +		"(.,.)n          number lines",
  4.2779 +		"N               revert n and p",
  4.2780 +		"(.)o[n]         show n lines of context",
  4.2781 +		"(.,.)p          print lines",
  4.2782 +		"P               toggle prompt",
  4.2783 +		"q               quit",
  4.2784 +		"Q               force quit",
  4.2785 +		"($)r            read file",
  4.2786 +		"(.,.)s/RE/repl/ search and replace",
  4.2787 +		"(.,.)s/RE/rp/g  replace all occurrences",
  4.2788 +		"(.,.)s/RE/rp/n  replace n-th occurrence",
  4.2789 +		"(.,.)ta         transfer lines to a",
  4.2790 +		"u               undo last change",
  4.2791 +		"(1,$)v/RE/cmd   reverse global",
  4.2792 +		"(1,$)V/RE/      reverse i/a global",
  4.2793 +		"(1,$)w [file]   write file",
  4.2794 +		"(1,$)W [file]   append to file",
  4.2795 +		"z               write buffer and quit",
  4.2796 +		"($)=            print line number",
  4.2797 +		"!command        execute shell command",
  4.2798 +		"(.+1)<newline>  print one line",
  4.2799 +		"/RE             find RE forwards",
  4.2800 +		"?RE             find RE backwards",
  4.2801 +		"1               first line",
  4.2802 +		".               current line",
  4.2803 +		"$               last line",
  4.2804 +		",               1,$",
  4.2805 +		";               .,$",
  4.2806 +		NULL
  4.2807 +	};
  4.2808 +	char	line[100];
  4.2809 +	int	c, half, i, k;
  4.2810 +
  4.2811 +	half = (sizeof desc / sizeof *desc) / 2;
  4.2812 +	for (i = 0; i < half && desc[i]; i++) {
  4.2813 +		c = 0;
  4.2814 +		for (k = 0; desc[i][k]; k++)
  4.2815 +			line[c++] = desc[i][k];
  4.2816 +		if (desc[i+half]) {
  4.2817 +			while (c < 40)
  4.2818 +				line[c++] = ' ';
  4.2819 +			for (k = 0; desc[i+half][k]; k++)
  4.2820 +				line[c++] = desc[i+half][k];
  4.2821 +		}
  4.2822 +		line[c] = 0;
  4.2823 +		puts(line);
  4.2824 +	}
  4.2825 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/makefile	Mon Sep 05 16:31:35 2011 +0200
     5.3 @@ -0,0 +1,121 @@
     5.4 +#
     5.5 +# Root directory. Mainly useful for package building; leave empty for
     5.6 +# normal installation.
     5.7 +#
     5.8 +ROOT = 
     5.9 +
    5.10 +PREFIX = /usr/local
    5.11 +
    5.12 +#
    5.13 +# Location for binaries.
    5.14 +#
    5.15 +BINDIR = $(PREFIX)/bin
    5.16 +
    5.17 +#
    5.18 +# Location for manual pages (with man1, man1b ... man8 below).
    5.19 +#
    5.20 +MANDIR = $(PREFIX)/share/man
    5.21 +
    5.22 +#
    5.23 +# Compiler and linker flags.
    5.24 +#
    5.25 +
    5.26 +#CC = $(HOME)/src/diet gcc
    5.27 +CC = cc
    5.28 +
    5.29 +LD = $(CC)
    5.30 +#LDFLAGS = --static
    5.31 +LDFLAGS = 
    5.32 +
    5.33 +#
    5.34 +# Flags for the C preprocessor.
    5.35 +# On Linux with glibc or uClibc, add -D_GNU_SOURCE.
    5.36 +# On Solaris, -D__EXTENSIONS__ should be added.
    5.37 +# On HP-UX, -D_INCLUDE__STDC_A1_SOURCE must be added.
    5.38 +# On AIX, -D_TPARM_COMPAT must be added.
    5.39 +# On AIX, -D_MTEXTEND_H should be added if mtextend.h is not found.
    5.40 +# On NetBSD, add -DUSE_TERMCAP.
    5.41 +#
    5.42 +CPPFLAGS = -D_GNU_SOURCE
    5.43 +
    5.44 +#
    5.45 +# CFLAGS makes it possible to give special
    5.46 +# compiler flags for objects where speed is critical. There is no other
    5.47 +# purpose with this so setting all to -O will work too.
    5.48 +#
    5.49 +WARN = 
    5.50 +CFLAGS = -O -fomit-frame-pointer $(WARN)
    5.51 +
    5.52 +
    5.53 +#
    5.54 +# Whether to use the supplied widechar emulation library. This should
    5.55 +# only be enabled if the system lacks appropriate widechar support.
    5.56 +# It is currently needed on
    5.57 +# - Linux/diet libc
    5.58 +# - FreeBSD 4
    5.59 +# - NetBSD 1.x, because it lacks wctype_t/wctrans_t etc. in wctype.h.
    5.60 +# - OpenBSD
    5.61 +#
    5.62 +#IWCHAR = -I../libwchar
    5.63 +#LWCHAR = -L../libwchar -lwchar
    5.64 +
    5.65 +
    5.66 +#
    5.67 +# Binaries are stripped with this command after installation.
    5.68 +#
    5.69 +STRIP = strip -s -R .comment -R .note
    5.70 +
    5.71 +#
    5.72 +# This is the shell used for the compilation phase, the execution of most
    5.73 +# installed scripts, and the shell escapes in the traditional command
    5.74 +# versions. It needs not conform to POSIX. The system shell should work
    5.75 +# fine; for maximum compatibility with traditional tools, the Heirloom
    5.76 +# Bourne shell is recommended. It then must obviously be compiled and
    5.77 +# installed first.
    5.78 +#
    5.79 +SHELL = /bin/sh
    5.80 +
    5.81 +#
    5.82 +# Don't change the rest of this file unless you really know what you are
    5.83 +# doing.
    5.84 +#
    5.85 +
    5.86 +########################################################################
    5.87 +########################################################################
    5.88 +########################################################################
    5.89 +########################################################################
    5.90 +########################################################################
    5.91 +
    5.92 +all: ed
    5.93 +
    5.94 +ed: ed.o regexpr.o sigset.o sigrelse.o
    5.95 +	$(LD) $(LDFLAGS) ed.o -o ed
    5.96 +
    5.97 +ed.o: ed.c regexp.h
    5.98 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(IWCHAR) -DSHELL='"$(SHELL)"' -I. -c ed.c
    5.99 +
   5.100 +regexpr.o: regexpr.c regexpr.h regexp.h
   5.101 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(IWCHAR) -I. -c regexpr.c
   5.102 +
   5.103 +sigset.o: sigset.c sigset.h
   5.104 +	$(CC) $(CFLAGS) $(CPPFLAGS) -I. -c sigset.c
   5.105 +
   5.106 +sigrelse.o: sigrelse.c sigset.h
   5.107 +	$(CC) $(CFLAGS) $(CPPFLAGS) -I. -c sigrelse.c
   5.108 +
   5.109 +
   5.110 +install: all
   5.111 +	mkdir -p $(ROOT)$(BINDIR)
   5.112 +	cp ed $(ROOT)$(BINDIR)/ed
   5.113 +	chmod 755 $(ROOT)$(BINDIR)/ed
   5.114 +	$(STRIP) $(ROOT)$(BINDIR)/ed
   5.115 +	mkdir -p $(ROOT)$(MANDIR)/man1
   5.116 +	cp ed.1 $(ROOT)$(MANDIR)/man1/ed.1
   5.117 +	chmod 644 $(ROOT)$(MANDIR)/man1/ed.1
   5.118 +
   5.119 +clean:
   5.120 +	rm -f ed.o regexpr.o sigset.o sigrelse.o core log *~
   5.121 +
   5.122 +mrproper: clean
   5.123 +	rm -f ed
   5.124 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/regexp.h	Mon Sep 05 16:31:35 2011 +0200
     6.3 @@ -0,0 +1,1211 @@
     6.4 +/*
     6.5 + * Simple Regular Expression functions. Derived from Unix 7th Edition,
     6.6 + * /usr/src/cmd/expr.y
     6.7 + *
     6.8 + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, February 2002.
     6.9 + *
    6.10 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
    6.11 + *
    6.12 + * Redistribution and use in source and binary forms, with or without
    6.13 + * modification, are permitted provided that the following conditions
    6.14 + * are met:
    6.15 + *   Redistributions of source code and documentation must retain the
    6.16 + *    above copyright notice, this list of conditions and the following
    6.17 + *    disclaimer.
    6.18 + *   Redistributions in binary form must reproduce the above copyright
    6.19 + *    notice, this list of conditions and the following disclaimer in the
    6.20 + *    documentation and/or other materials provided with the distribution.
    6.21 + *   All advertising materials mentioning features or use of this software
    6.22 + *    must display the following acknowledgement:
    6.23 + *      This product includes software developed or owned by Caldera
    6.24 + *      International, Inc.
    6.25 + *   Neither the name of Caldera International, Inc. nor the names of
    6.26 + *    other contributors may be used to endorse or promote products
    6.27 + *    derived from this software without specific prior written permission.
    6.28 + *
    6.29 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    6.30 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    6.31 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    6.32 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.33 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    6.34 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.35 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.36 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    6.37 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    6.38 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    6.39 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    6.40 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    6.41 + */
    6.42 +
    6.43 +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
    6.44 +#define	REGEXP_H_USED	__attribute__ ((used))
    6.45 +#elif defined __GNUC__
    6.46 +#define	REGEXP_H_USED	__attribute__ ((unused))
    6.47 +#else
    6.48 +#define	REGEXP_H_USED
    6.49 +#endif
    6.50 +static const char regexp_h_sccsid[] REGEXP_H_USED =
    6.51 +	"@(#)regexp.sl	1.56 (gritter) 5/29/05";
    6.52 +
    6.53 +#if !defined (REGEXP_H_USED_FROM_VI) && !defined (__dietlibc__)
    6.54 +#define	REGEXP_H_WCHARS
    6.55 +#endif
    6.56 +
    6.57 +#define	CBRA	2
    6.58 +#define	CCHR	4
    6.59 +#define	CDOT	8
    6.60 +#define	CCL	12
    6.61 +/*	CLNUM	14	used in sed */
    6.62 +/*	CEND	16	used in sed */
    6.63 +#define	CDOL	20
    6.64 +#define	CCEOF	22
    6.65 +#define	CKET	24
    6.66 +#define	CBACK	36
    6.67 +#define	CNCL	40
    6.68 +#define	CBRC	44
    6.69 +#define	CLET	48
    6.70 +#define	CCH1	52
    6.71 +#define	CCH2	56
    6.72 +#define	CCH3	60
    6.73 +
    6.74 +#define	STAR	01
    6.75 +#define RNGE	03
    6.76 +#define	REGEXP_H_LEAST	0100
    6.77 +
    6.78 +#ifdef	REGEXP_H_WCHARS
    6.79 +#define	CMB	0200
    6.80 +#else	/* !REGEXP_H_WCHARS */
    6.81 +#define	CMB	0
    6.82 +#endif	/* !REGEXP_H_WCHARS */
    6.83 +
    6.84 +#define	NBRA	9
    6.85 +
    6.86 +#define PLACE(c)	ep[c >> 3] |= bittab[c & 07]
    6.87 +#define ISTHERE(c)	(ep[c >> 3] & bittab[c & 07])
    6.88 +
    6.89 +#ifdef	REGEXP_H_WCHARS
    6.90 +#define	REGEXP_H_IS_THERE(ep, c)	((ep)[c >> 3] & bittab[c & 07])
    6.91 +#endif
    6.92 +
    6.93 +#include	<ctype.h>
    6.94 +#include	<string.h>
    6.95 +#include	<limits.h>
    6.96 +#ifdef	REGEXP_H_WCHARS
    6.97 +#include	<stdlib.h>
    6.98 +#include	<wchar.h>
    6.99 +#include	<wctype.h>
   6.100 +#endif	/* REGEXP_H_WCHARS */
   6.101 +
   6.102 +#define	regexp_h_uletter(c)	(isalpha(c) || (c) == '_')
   6.103 +#ifdef	REGEXP_H_WCHARS
   6.104 +#define	regexp_h_wuletter(c)	(iswalpha(c) || (c) == L'_')
   6.105 +
   6.106 +/*
   6.107 + * Used to allocate memory for the multibyte star algorithm.
   6.108 + */
   6.109 +#ifndef	regexp_h_malloc
   6.110 +#define	regexp_h_malloc(n)	malloc(n)
   6.111 +#endif
   6.112 +#ifndef	regexp_h_free
   6.113 +#define	regexp_h_free(p)	free(p)
   6.114 +#endif
   6.115 +
   6.116 +/*
   6.117 + * Can be predefined to 'inline' to inline some multibyte functions;
   6.118 + * may improve performance for files that contain many multibyte
   6.119 + * sequences.
   6.120 + */
   6.121 +#ifndef	regexp_h_inline
   6.122 +#define	regexp_h_inline
   6.123 +#endif
   6.124 +
   6.125 +/*
   6.126 + * Mask to determine whether the first byte of a sequence possibly
   6.127 + * starts a multibyte character. Set to 0377 to force mbtowc() for
   6.128 + * any byte sequence (except 0).
   6.129 + */
   6.130 +#ifndef	REGEXP_H_MASK
   6.131 +#define	REGEXP_H_MASK	0200
   6.132 +#endif
   6.133 +#endif	/* REGEXP_H_WCHARS */
   6.134 +
   6.135 +/*
   6.136 + * For regexpr.h.
   6.137 + */
   6.138 +#ifndef	regexp_h_static
   6.139 +#define	regexp_h_static
   6.140 +#endif
   6.141 +#ifndef	REGEXP_H_STEP_INIT
   6.142 +#define	REGEXP_H_STEP_INIT
   6.143 +#endif
   6.144 +#ifndef	REGEXP_H_ADVANCE_INIT
   6.145 +#define	REGEXP_H_ADVANCE_INIT
   6.146 +#endif
   6.147 +
   6.148 +char	*braslist[NBRA];
   6.149 +char	*braelist[NBRA];
   6.150 +int	nbra;
   6.151 +char	*loc1, *loc2, *locs;
   6.152 +int	sed;
   6.153 +int	nodelim;
   6.154 +
   6.155 +regexp_h_static int	circf;
   6.156 +regexp_h_static int	low;
   6.157 +regexp_h_static int	size;
   6.158 +
   6.159 +regexp_h_static unsigned char	bittab[] = {
   6.160 +	1,
   6.161 +	2,
   6.162 +	4,
   6.163 +	8,
   6.164 +	16,
   6.165 +	32,
   6.166 +	64,
   6.167 +	128
   6.168 +};
   6.169 +static int	regexp_h_advance(register const char *lp,
   6.170 +			register const char *ep);
   6.171 +static void	regexp_h_getrnge(register const char *str, int least);
   6.172 +
   6.173 +static const char	*regexp_h_bol;	/* beginning of input line (for \<) */
   6.174 +
   6.175 +#ifdef	REGEXP_H_WCHARS
   6.176 +static int	regexp_h_wchars;
   6.177 +static int	regexp_h_mbcurmax;
   6.178 +
   6.179 +static const char	*regexp_h_firstwc;	/* location of first
   6.180 +						   multibyte character
   6.181 +						   on input line */
   6.182 +
   6.183 +#define	regexp_h_getwc(c)	{ \
   6.184 +	if (regexp_h_wchars) { \
   6.185 +		char mbbuf[MB_LEN_MAX + 1], *mbptr; \
   6.186 +		wchar_t wcbuf; \
   6.187 +		int mb, len; \
   6.188 +		mbptr = mbbuf; \
   6.189 +		do { \
   6.190 +			mb = GETC(); \
   6.191 +			*mbptr++ = mb; \
   6.192 +			*mbptr = '\0'; \
   6.193 +		} while ((len = mbtowc(&wcbuf, mbbuf, regexp_h_mbcurmax)) < 0 \
   6.194 +			&& mb != eof && mbptr < mbbuf + MB_LEN_MAX); \
   6.195 +		if (len == -1) \
   6.196 +			ERROR(67); \
   6.197 +		c = wcbuf; \
   6.198 +	} else { \
   6.199 +		c = GETC(); \
   6.200 +	} \
   6.201 +}
   6.202 +
   6.203 +#define	regexp_h_store(wc, mb, me)	{ \
   6.204 +	int len; \
   6.205 +	if (wc == WEOF) \
   6.206 +		ERROR(67); \
   6.207 +	if ((len = me - mb) <= regexp_h_mbcurmax) { \
   6.208 +		char mt[MB_LEN_MAX]; \
   6.209 +		if (wctomb(mt, wc) >= len) \
   6.210 +			ERROR(50); \
   6.211 +	} \
   6.212 +	switch (len = wctomb(mb, wc)) { \
   6.213 +	case -1: \
   6.214 +		 ERROR(67); \
   6.215 +	case 0: \
   6.216 +		mb++; \
   6.217 +		break; \
   6.218 +	default: \
   6.219 +		mb += len; \
   6.220 +	} \
   6.221 +}
   6.222 +
   6.223 +static regexp_h_inline wint_t
   6.224 +regexp_h_fetchwc(const char **mb, int islp)
   6.225 +{
   6.226 +	wchar_t wc;
   6.227 +	int len;
   6.228 +
   6.229 +	if ((len = mbtowc(&wc, *mb, regexp_h_mbcurmax)) < 0) {
   6.230 +		(*mb)++;
   6.231 +		return WEOF;
   6.232 +	}
   6.233 +	if (islp && regexp_h_firstwc == NULL)
   6.234 +		regexp_h_firstwc = *mb;
   6.235 +	/*if (len == 0) {
   6.236 +		(*mb)++;
   6.237 +		return L'\0';
   6.238 +	} handled in singlebyte code */
   6.239 +	*mb += len;
   6.240 +	return wc;
   6.241 +}
   6.242 +
   6.243 +#define	regexp_h_fetch(mb, islp)	((*(mb) & REGEXP_H_MASK) == 0 ? \
   6.244 +						(*(mb)++&0377): \
   6.245 +						regexp_h_fetchwc(&(mb), islp))
   6.246 +
   6.247 +static regexp_h_inline wint_t
   6.248 +regexp_h_showwc(const char *mb)
   6.249 +{
   6.250 +	wchar_t wc;
   6.251 +
   6.252 +	if (mbtowc(&wc, mb, regexp_h_mbcurmax) < 0)
   6.253 +		return WEOF;
   6.254 +	return wc;
   6.255 +}
   6.256 +
   6.257 +#define	regexp_h_show(mb)	((*(mb) & REGEXP_H_MASK) == 0 ? (*(mb)&0377): \
   6.258 +					regexp_h_showwc(mb))
   6.259 +
   6.260 +/*
   6.261 + * Return the character immediately preceding mb. Since no byte is
   6.262 + * required to be the first byte of a character, the longest multibyte
   6.263 + * character ending at &[mb-1] is searched.
   6.264 + */
   6.265 +static regexp_h_inline wint_t
   6.266 +regexp_h_previous(const char *mb)
   6.267 +{
   6.268 +	const char *p = mb;
   6.269 +	wchar_t wc, lastwc = WEOF;
   6.270 +	int len, max = 0;
   6.271 +
   6.272 +	if (regexp_h_firstwc == NULL || mb <= regexp_h_firstwc)
   6.273 +		return (mb > regexp_h_bol ? (mb[-1] & 0377) : WEOF);
   6.274 +	while (p-- > regexp_h_bol) {
   6.275 +		mbtowc(NULL, NULL, 0);
   6.276 +		if ((len = mbtowc(&wc, p, mb - p)) >= 0) {
   6.277 +			if (len < max || len < mb - p)
   6.278 +				break;
   6.279 +			max = len;
   6.280 +			lastwc = wc;
   6.281 +		} else if (len < 0 && max > 0)
   6.282 +			break;
   6.283 +	}
   6.284 +	return lastwc;
   6.285 +}
   6.286 +
   6.287 +#define	regexp_h_cclass(set, c, af)	\
   6.288 +	((c) == 0 || (c) == WEOF ? 0 : ( \
   6.289 +		((c) > 0177) ? \
   6.290 +			regexp_h_cclass_wc(set, c, af) : ( \
   6.291 +				REGEXP_H_IS_THERE((set)+1, (c)) ? (af) : !(af) \
   6.292 +			) \
   6.293 +		) \
   6.294 +	)
   6.295 +
   6.296 +static regexp_h_inline int
   6.297 +regexp_h_cclass_wc(const char *set, register wint_t c, int af)
   6.298 +{
   6.299 +	register wint_t wc, wl = WEOF;
   6.300 +	const char *end;
   6.301 +
   6.302 +	end = &set[18] + set[0] - 1;
   6.303 +	set += 17;
   6.304 +	while (set < end) {
   6.305 +		wc = regexp_h_fetch(set, 0);
   6.306 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.307 +		if (wc == '\\' && set < end &&
   6.308 +				(*set == ']' || *set == '-' ||
   6.309 +				 *set == '^' || *set == '\\')) {
   6.310 +			wc = regexp_h_fetch(set, 0);
   6.311 +		} else
   6.312 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.313 +		if (wc == '-' && wl != WEOF && set < end) {
   6.314 +			wc = regexp_h_fetch(set, 0);
   6.315 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.316 +			if (wc == '\\' && set < end &&
   6.317 +					(*set == ']' || *set == '-' ||
   6.318 +					 *set == '^' || *set == '\\')) {
   6.319 +				wc = regexp_h_fetch(set, 0);
   6.320 +			}
   6.321 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.322 +			if (c > wl && c < wc)
   6.323 +				return af;
   6.324 +		}
   6.325 +		if (c == wc)
   6.326 +			return af;
   6.327 +		wl = wc;
   6.328 +	}
   6.329 +	return !af;
   6.330 +}
   6.331 +#else	/* !REGEXP_H_WCHARS */
   6.332 +#define	regexp_h_wchars		0
   6.333 +#define	regexp_h_getwc(c)	{ c = GETC(); }
   6.334 +#endif	/* !REGEXP_H_WCHARS */
   6.335 +
   6.336 +regexp_h_static char *
   6.337 +compile(char *instring, char *ep, const char *endbuf, int seof)
   6.338 +{
   6.339 +	INIT	/* Dependent declarations and initializations */
   6.340 +	register int c;
   6.341 +	register int eof = seof;
   6.342 +	char *lastep = instring;
   6.343 +	int cclcnt;
   6.344 +	char bracket[NBRA], *bracketp;
   6.345 +	int closed;
   6.346 +	char neg;
   6.347 +	int lc;
   6.348 +	int i, cflg;
   6.349 +
   6.350 +#ifdef	REGEXP_H_WCHARS
   6.351 +	char *eq;
   6.352 +	regexp_h_mbcurmax = MB_CUR_MAX;
   6.353 +	regexp_h_wchars = regexp_h_mbcurmax > 1 ? CMB : 0;
   6.354 +#endif
   6.355 +	lastep = 0;
   6.356 +	bracketp = bracket;
   6.357 +	if((c = GETC()) == eof || c == '\n') {
   6.358 +		if (c == '\n') {
   6.359 +			UNGETC(c);
   6.360 +			nodelim = 1;
   6.361 +		}
   6.362 +		if(*ep == 0 && !sed)
   6.363 +			ERROR(41);
   6.364 +		if (bracketp > bracket)
   6.365 +			ERROR(42);
   6.366 +		RETURN(ep);
   6.367 +	}
   6.368 +	circf = closed = nbra = 0;
   6.369 +	if (c == '^')
   6.370 +		circf++;
   6.371 +	else
   6.372 +		UNGETC(c);
   6.373 +	for (;;) {
   6.374 +		if (ep >= endbuf)
   6.375 +			ERROR(50);
   6.376 +		regexp_h_getwc(c);
   6.377 +		if(c != '*' && ((c != '\\') || (PEEKC() != '{')))
   6.378 +			lastep = ep;
   6.379 +		if (c == eof) {
   6.380 +			*ep++ = CCEOF;
   6.381 +			if (bracketp > bracket)
   6.382 +				ERROR(42);
   6.383 +			RETURN(ep);
   6.384 +		}
   6.385 +		switch (c) {
   6.386 +
   6.387 +		case '.':
   6.388 +			*ep++ = CDOT|regexp_h_wchars;
   6.389 +			continue;
   6.390 +
   6.391 +		case '\n':
   6.392 +			if (sed == 0) {
   6.393 +				UNGETC(c);
   6.394 +				*ep++ = CCEOF;
   6.395 +				nodelim = 1;
   6.396 +				RETURN(ep);
   6.397 +			}
   6.398 +			ERROR(36);
   6.399 +		case '*':
   6.400 +			if (lastep==0 || *lastep==CBRA || *lastep==CKET ||
   6.401 +					*lastep==(CBRC|regexp_h_wchars) ||
   6.402 +					*lastep==(CLET|regexp_h_wchars))
   6.403 +				goto defchar;
   6.404 +			*lastep |= STAR;
   6.405 +			continue;
   6.406 +
   6.407 +		case '$':
   6.408 +			if(PEEKC() != eof)
   6.409 +				goto defchar;
   6.410 +			*ep++ = CDOL;
   6.411 +			continue;
   6.412 +
   6.413 +		case '[':
   6.414 +#ifdef	REGEXP_H_WCHARS
   6.415 +			if (regexp_h_wchars == 0) {
   6.416 +#endif
   6.417 +				if(&ep[33] >= endbuf)
   6.418 +					ERROR(50);
   6.419 +
   6.420 +				*ep++ = CCL;
   6.421 +				lc = 0;
   6.422 +				for(i = 0; i < 32; i++)
   6.423 +					ep[i] = 0;
   6.424 +
   6.425 +				neg = 0;
   6.426 +				if((c = GETC()) == '^') {
   6.427 +					neg = 1;
   6.428 +					c = GETC();
   6.429 +				}
   6.430 +
   6.431 +				do {
   6.432 +					c &= 0377;
   6.433 +					if(c == '\0' || c == '\n')
   6.434 +						ERROR(49);
   6.435 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.436 +					if(c == '\\' && ((c = PEEKC()) == ']' ||
   6.437 +							c == '-' || c == '^' ||
   6.438 +							c == '\\')) {
   6.439 +						c = GETC();
   6.440 +						c &= 0377;
   6.441 +					} else
   6.442 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.443 +					if(c == '-' && lc != 0) {
   6.444 +						if ((c = GETC()) == ']') {
   6.445 +							PLACE('-');
   6.446 +							break;
   6.447 +						}
   6.448 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.449 +						if(c == '\\' &&
   6.450 +							((c = PEEKC()) == ']' ||
   6.451 +								c == '-' ||
   6.452 +								c == '^' ||
   6.453 +								c == '\\'))
   6.454 +							c = GETC();
   6.455 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.456 +						c &= 0377;
   6.457 +						while(lc < c) {
   6.458 +							PLACE(lc);
   6.459 +							lc++;
   6.460 +						}
   6.461 +					}
   6.462 +					lc = c;
   6.463 +					PLACE(c);
   6.464 +				} while((c = GETC()) != ']');
   6.465 +				if(neg) {
   6.466 +					for(cclcnt = 0; cclcnt < 32; cclcnt++)
   6.467 +						ep[cclcnt] ^= 0377;
   6.468 +					ep[0] &= 0376;
   6.469 +				}
   6.470 +
   6.471 +				ep += 32;
   6.472 +#ifdef	REGEXP_H_WCHARS
   6.473 +			} else {
   6.474 +				if (&ep[18] >= endbuf)
   6.475 +					ERROR(50);
   6.476 +				*ep++ = CCL|CMB;
   6.477 +				*ep++ = 0;
   6.478 +				lc = 0;
   6.479 +				for (i = 0; i < 16; i++)
   6.480 +					ep[i] = 0;
   6.481 +				eq = &ep[16];
   6.482 +				regexp_h_getwc(c);
   6.483 +				if (c == L'^') {
   6.484 +					regexp_h_getwc(c);
   6.485 +					ep[-2] = CNCL|CMB;
   6.486 +				}
   6.487 +				do {
   6.488 +					if (c == '\0' || c == '\n')
   6.489 +						ERROR(49);
   6.490 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.491 +					if(c == '\\' && ((c = PEEKC()) == ']' ||
   6.492 +							c == '-' || c == '^' ||
   6.493 +							c == '\\')) {
   6.494 +						regexp_h_store(c, eq, endbuf);
   6.495 +						regexp_h_getwc(c);
   6.496 +					} else
   6.497 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.498 +					if (c == '-' && lc != 0 && lc <= 0177) {
   6.499 +						regexp_h_store(c, eq, endbuf);
   6.500 +						regexp_h_getwc(c);
   6.501 +						if (c == ']') {
   6.502 +							PLACE('-');
   6.503 +							break;
   6.504 +						}
   6.505 +#ifdef	REGEXP_H_VI_BACKSLASH
   6.506 +						if(c == '\\' &&
   6.507 +							((c = PEEKC()) == ']' ||
   6.508 +								c == '-' ||
   6.509 +								c == '^' ||
   6.510 +								c == '\\')) {
   6.511 +							regexp_h_store(c, eq,
   6.512 +								endbuf);
   6.513 +							regexp_h_getwc(c);
   6.514 +						}
   6.515 +#endif	/* REGEXP_H_VI_BACKSLASH */
   6.516 +						while (lc < (c & 0177)) {
   6.517 +							PLACE(lc);
   6.518 +							lc++;
   6.519 +						}
   6.520 +					}
   6.521 +					lc = c;
   6.522 +					if (c <= 0177)
   6.523 +						PLACE(c);
   6.524 +					regexp_h_store(c, eq, endbuf);
   6.525 +					regexp_h_getwc(c);
   6.526 +				} while (c != L']');
   6.527 +				if ((i = eq - &ep[16]) > 255)
   6.528 +					ERROR(50);
   6.529 +				lastep[1] = i;
   6.530 +				ep = eq;
   6.531 +			}
   6.532 +#endif	/* REGEXP_H_WCHARS */
   6.533 +
   6.534 +			continue;
   6.535 +
   6.536 +		case '\\':
   6.537 +			regexp_h_getwc(c);
   6.538 +			switch(c) {
   6.539 +
   6.540 +			case '(':
   6.541 +				if(nbra >= NBRA)
   6.542 +					ERROR(43);
   6.543 +				*bracketp++ = nbra;
   6.544 +				*ep++ = CBRA;
   6.545 +				*ep++ = nbra++;
   6.546 +				continue;
   6.547 +
   6.548 +			case ')':
   6.549 +				if(bracketp <= bracket)
   6.550 +					ERROR(42);
   6.551 +				*ep++ = CKET;
   6.552 +				*ep++ = *--bracketp;
   6.553 +				closed++;
   6.554 +				continue;
   6.555 +
   6.556 +			case '<':
   6.557 +				*ep++ = CBRC|regexp_h_wchars;
   6.558 +				continue;
   6.559 +
   6.560 +			case '>':
   6.561 +				*ep++ = CLET|regexp_h_wchars;
   6.562 +				continue;
   6.563 +
   6.564 +			case '{':
   6.565 +				if(lastep == (char *) (0))
   6.566 +					goto defchar;
   6.567 +				*lastep |= RNGE;
   6.568 +				cflg = 0;
   6.569 +			nlim:
   6.570 +				c = GETC();
   6.571 +				i = 0;
   6.572 +				do {
   6.573 +					if ('0' <= c && c <= '9')
   6.574 +						i = 10 * i + c - '0';
   6.575 +					else
   6.576 +						ERROR(16);
   6.577 +				} while(((c = GETC()) != '\\') && (c != ','));
   6.578 +				if (i > 255)
   6.579 +					ERROR(11);
   6.580 +				*ep++ = i;
   6.581 +				if (c == ',') {
   6.582 +					if(cflg++)
   6.583 +						ERROR(44);
   6.584 +					if((c = GETC()) == '\\') {
   6.585 +						*ep++ = (char)255;
   6.586 +						*lastep |= REGEXP_H_LEAST;
   6.587 +					} else {
   6.588 +						UNGETC(c);
   6.589 +						goto nlim; /* get 2'nd number */
   6.590 +					}
   6.591 +				}
   6.592 +				if(GETC() != '}')
   6.593 +					ERROR(45);
   6.594 +				if(!cflg)	/* one number */
   6.595 +					*ep++ = i;
   6.596 +				else if((ep[-1] & 0377) < (ep[-2] & 0377))
   6.597 +					ERROR(46);
   6.598 +				continue;
   6.599 +
   6.600 +			case '\n':
   6.601 +				ERROR(36);
   6.602 +
   6.603 +			case 'n':
   6.604 +				c = '\n';
   6.605 +				goto defchar;
   6.606 +
   6.607 +			default:
   6.608 +				if(c >= '1' && c <= '9') {
   6.609 +					if((c -= '1') >= closed)
   6.610 +						ERROR(25);
   6.611 +					*ep++ = CBACK;
   6.612 +					*ep++ = c;
   6.613 +					continue;
   6.614 +				}
   6.615 +			}
   6.616 +			/* Drop through to default to use \ to turn off special chars */
   6.617 +
   6.618 +		defchar:
   6.619 +		default:
   6.620 +			lastep = ep;
   6.621 +#ifdef	REGEXP_H_WCHARS
   6.622 +			if (regexp_h_wchars == 0) {
   6.623 +#endif
   6.624 +				*ep++ = CCHR;
   6.625 +				*ep++ = c;
   6.626 +#ifdef	REGEXP_H_WCHARS
   6.627 +			} else {
   6.628 +				char	mbbuf[MB_LEN_MAX];
   6.629 +
   6.630 +				switch (wctomb(mbbuf, c)) {
   6.631 +				case 1: *ep++ = CCH1;
   6.632 +					break;
   6.633 +				case 2:	*ep++ = CCH2;
   6.634 +					break;
   6.635 +				case 3:	*ep++ = CCH3;
   6.636 +					break;
   6.637 +				default:
   6.638 +					*ep++ = CCHR|CMB;
   6.639 +				}
   6.640 +				regexp_h_store(c, ep, endbuf);
   6.641 +			}
   6.642 +#endif	/* REGEXP_H_WCHARS */
   6.643 +		}
   6.644 +	}
   6.645 +}
   6.646 +
   6.647 +int
   6.648 +step(const char *p1, const char *p2)
   6.649 +{
   6.650 +	register int c;
   6.651 +#ifdef	REGEXP_H_WCHARS
   6.652 +	register int d;
   6.653 +#endif	/* REGEXP_H_WCHARS */
   6.654 +
   6.655 +	REGEXP_H_STEP_INIT	/* get circf */
   6.656 +	regexp_h_bol = p1;
   6.657 +#ifdef	REGEXP_H_WCHARS
   6.658 +	regexp_h_firstwc = NULL;
   6.659 +#endif	/* REGEXP_H_WCHARS */
   6.660 +	if (circf) {
   6.661 +		loc1 = (char *)p1;
   6.662 +		return(regexp_h_advance(p1, p2));
   6.663 +	}
   6.664 +	/* fast check for first character */
   6.665 +	if (*p2==CCHR) {
   6.666 +		c = p2[1] & 0377;
   6.667 +		do {
   6.668 +			if ((*p1 & 0377) != c)
   6.669 +				continue;
   6.670 +			if (regexp_h_advance(p1, p2)) {
   6.671 +				loc1 = (char *)p1;
   6.672 +				return(1);
   6.673 +			}
   6.674 +		} while (*p1++);
   6.675 +		return(0);
   6.676 +	}
   6.677 +#ifdef	REGEXP_H_WCHARS
   6.678 +	else if (*p2==CCH1) {
   6.679 +		do {
   6.680 +			if (p1[0] == p2[1] && regexp_h_advance(p1, p2)) {
   6.681 +				loc1 = (char *)p1;
   6.682 +				return(1);
   6.683 +			}
   6.684 +			c = regexp_h_fetch(p1, 1);
   6.685 +		} while (c);
   6.686 +		return(0);
   6.687 +	} else if (*p2==CCH2) {
   6.688 +		do {
   6.689 +			if (p1[0] == p2[1] && p1[1] == p2[2] &&
   6.690 +					regexp_h_advance(p1, p2)) {
   6.691 +				loc1 = (char *)p1;
   6.692 +				return(1);
   6.693 +			}
   6.694 +			c = regexp_h_fetch(p1, 1);
   6.695 +		} while (c);
   6.696 +		return(0);
   6.697 +	} else if (*p2==CCH3) {
   6.698 +		do {
   6.699 +			if (p1[0] == p2[1] && p1[1] == p2[2] && p1[2] == p2[3]&&
   6.700 +					regexp_h_advance(p1, p2)) {
   6.701 +				loc1 = (char *)p1;
   6.702 +				return(1);
   6.703 +			}
   6.704 +			c = regexp_h_fetch(p1, 1);
   6.705 +		} while (c);
   6.706 +		return(0);
   6.707 +	} else if ((*p2&0377)==(CCHR|CMB)) {
   6.708 +		d = regexp_h_fetch(p2, 0);
   6.709 +		do {
   6.710 +			c = regexp_h_fetch(p1, 1);
   6.711 +			if (c == d && regexp_h_advance(p1, p2)) {
   6.712 +				loc1 = (char *)p1;
   6.713 +				return(1);
   6.714 +			}
   6.715 +		} while(c);
   6.716 +		return(0);
   6.717 +	}
   6.718 +		/* regular algorithm */
   6.719 +	if (regexp_h_wchars)
   6.720 +		do {
   6.721 +			if (regexp_h_advance(p1, p2)) {
   6.722 +				loc1 = (char *)p1;
   6.723 +				return(1);
   6.724 +			}
   6.725 +			c = regexp_h_fetch(p1, 1);
   6.726 +		} while (c);
   6.727 +	else
   6.728 +#endif	/* REGEXP_H_WCHARS */
   6.729 +		do {
   6.730 +			if (regexp_h_advance(p1, p2)) {
   6.731 +				loc1 = (char *)p1;
   6.732 +				return(1);
   6.733 +			}
   6.734 +		} while (*p1++);
   6.735 +	return(0);
   6.736 +}
   6.737 +
   6.738 +#ifdef	REGEXP_H_WCHARS
   6.739 +/*
   6.740 + * It is painfully slow to read character-wise backwards in a
   6.741 + * multibyte string (see regexp_h_previous() above). For the star
   6.742 + * algorithm, we therefore keep track of every character as it is
   6.743 + * read in forward direction.
   6.744 + *
   6.745 + * Don't use alloca() for stack blocks since there is no measurable
   6.746 + * speedup and huge amounts of memory are used up for long input
   6.747 + * lines.
   6.748 + */
   6.749 +#ifndef	REGEXP_H_STAKBLOK
   6.750 +#define	REGEXP_H_STAKBLOK	1000
   6.751 +#endif
   6.752 +
   6.753 +struct	regexp_h_stack {
   6.754 +	struct regexp_h_stack	*s_nxt;
   6.755 +	struct regexp_h_stack	*s_prv;
   6.756 +	const char	*s_ptr[REGEXP_H_STAKBLOK];
   6.757 +};
   6.758 +
   6.759 +#define	regexp_h_push(sb, sp, sc, lp)	(regexp_h_wchars ? \
   6.760 +			regexp_h_pushwc(sb, sp, sc, lp) : (void)0)
   6.761 +
   6.762 +static regexp_h_inline void
   6.763 +regexp_h_pushwc(struct regexp_h_stack **sb,
   6.764 +		struct regexp_h_stack **sp,
   6.765 +		const char ***sc, const char *lp)
   6.766 +{
   6.767 +	if (regexp_h_firstwc == NULL || lp < regexp_h_firstwc)
   6.768 +		return;
   6.769 +	if (*sb == NULL) {
   6.770 +		if ((*sb = regexp_h_malloc(sizeof **sb)) == NULL)
   6.771 +			return;
   6.772 +		(*sb)->s_nxt = (*sb)->s_prv = NULL;
   6.773 +		*sp = *sb;
   6.774 +		*sc = &(*sb)->s_ptr[0];
   6.775 +	} else if (*sc >= &(*sp)->s_ptr[REGEXP_H_STAKBLOK]) {
   6.776 +		if ((*sp)->s_nxt == NULL) {
   6.777 +			struct regexp_h_stack	*bq;
   6.778 +
   6.779 +			if ((bq = regexp_h_malloc(sizeof *bq)) == NULL)
   6.780 +				return;
   6.781 +			bq->s_nxt = NULL;
   6.782 +			bq->s_prv = *sp;
   6.783 +			(*sp)->s_nxt = bq;
   6.784 +			*sp = bq;
   6.785 +		} else
   6.786 +			*sp = (*sp)->s_nxt;
   6.787 +		*sc = &(*sp)->s_ptr[0];
   6.788 +	}
   6.789 +	*(*sc)++ = lp;
   6.790 +}
   6.791 +
   6.792 +static regexp_h_inline const char *
   6.793 +regexp_h_pop(struct regexp_h_stack **sb, struct regexp_h_stack **sp,
   6.794 +		const char ***sc, const char *lp)
   6.795 +{
   6.796 +	if (regexp_h_firstwc == NULL || lp <= regexp_h_firstwc)
   6.797 +		return &lp[-1];
   6.798 +	if (*sp == NULL)
   6.799 +		return regexp_h_firstwc;
   6.800 +	if (*sc == &(*sp)->s_ptr[0]) {
   6.801 +		if ((*sp)->s_prv == NULL) {
   6.802 +			regexp_h_free(*sp);
   6.803 +			*sp = NULL;
   6.804 +			*sb = NULL;
   6.805 +			return regexp_h_firstwc;
   6.806 +		}
   6.807 +		*sp = (*sp)->s_prv;
   6.808 +		regexp_h_free((*sp)->s_nxt);
   6.809 +		(*sp)->s_nxt = NULL ;
   6.810 +		*sc = &(*sp)->s_ptr[REGEXP_H_STAKBLOK];
   6.811 +	}
   6.812 +	return *(--(*sc));
   6.813 +}
   6.814 +
   6.815 +static void
   6.816 +regexp_h_zerostak(struct regexp_h_stack **sb, struct regexp_h_stack **sp)
   6.817 +{
   6.818 +	for (*sp = *sb; *sp && (*sp)->s_nxt; *sp = (*sp)->s_nxt)
   6.819 +		if ((*sp)->s_prv)
   6.820 +			regexp_h_free((*sp)->s_prv);
   6.821 +	if (*sp) {
   6.822 +		if ((*sp)->s_prv)
   6.823 +			regexp_h_free((*sp)->s_prv);
   6.824 +		regexp_h_free(*sp);
   6.825 +	}
   6.826 +	*sp = *sb = NULL;
   6.827 +}
   6.828 +#else	/* !REGEXP_H_WCHARS */
   6.829 +#define	regexp_h_push(sb, sp, sc, lp)
   6.830 +#endif	/* !REGEXP_H_WCHARS */
   6.831 +
   6.832 +static int
   6.833 +regexp_h_advance(const char *lp, const char *ep)
   6.834 +{
   6.835 +	register const char *curlp;
   6.836 +	int c, least;
   6.837 +#ifdef	REGEXP_H_WCHARS
   6.838 +	int d;
   6.839 +	struct regexp_h_stack	*sb = NULL, *sp = NULL;
   6.840 +	const char	**sc;
   6.841 +#endif	/* REGEXP_H_WCHARS */
   6.842 +	char *bbeg;
   6.843 +	int ct;
   6.844 +
   6.845 +	for (;;) switch (least = *ep++ & 0377, least & ~REGEXP_H_LEAST) {
   6.846 +
   6.847 +	case CCHR:
   6.848 +#ifdef	REGEXP_H_WCHARS
   6.849 +	case CCH1:
   6.850 +#endif
   6.851 +		if (*ep++ == *lp++)
   6.852 +			continue;
   6.853 +		return(0);
   6.854 +
   6.855 +#ifdef	REGEXP_H_WCHARS
   6.856 +	case CCHR|CMB:
   6.857 +		if (regexp_h_fetch(ep, 0) == regexp_h_fetch(lp, 1))
   6.858 +			continue;
   6.859 +		return(0);
   6.860 +
   6.861 +	case CCH2:
   6.862 +		if (ep[0] == lp[0] && ep[1] == lp[1]) {
   6.863 +			ep += 2, lp += 2;
   6.864 +			continue;
   6.865 +		}
   6.866 +		return(0);
   6.867 +
   6.868 +	case CCH3:
   6.869 +		if (ep[0] == lp[0] && ep[1] == lp[1] && ep[2] == lp[2]) {
   6.870 +			ep += 3, lp += 3;
   6.871 +			continue;
   6.872 +		}
   6.873 +		return(0);
   6.874 +#endif	/* REGEXP_H_WCHARS */
   6.875 +
   6.876 +	case CDOT:
   6.877 +		if (*lp++)
   6.878 +			continue;
   6.879 +		return(0);
   6.880 +#ifdef	REGEXP_H_WCHARS
   6.881 +	case CDOT|CMB:
   6.882 +		if ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF)
   6.883 +			continue;
   6.884 +		return(0);
   6.885 +#endif	/* REGEXP_H_WCHARS */
   6.886 +
   6.887 +	case CDOL:
   6.888 +		if (*lp==0)
   6.889 +			continue;
   6.890 +		return(0);
   6.891 +
   6.892 +	case CCEOF:
   6.893 +		loc2 = (char *)lp;
   6.894 +		return(1);
   6.895 +
   6.896 +	case CCL:
   6.897 +		c = *lp++ & 0377;
   6.898 +		if(ISTHERE(c)) {
   6.899 +			ep += 32;
   6.900 +			continue;
   6.901 +		}
   6.902 +		return(0);
   6.903 +
   6.904 +#ifdef	REGEXP_H_WCHARS
   6.905 +	case CCL|CMB:
   6.906 +	case CNCL|CMB:
   6.907 +		c = regexp_h_fetch(lp, 1);
   6.908 +		if (regexp_h_cclass(ep, c, (ep[-1] & 0377) == (CCL|CMB))) {
   6.909 +			ep += (*ep & 0377) + 17;
   6.910 +			continue;
   6.911 +		}
   6.912 +		return 0;
   6.913 +#endif	/* REGEXP_H_WCHARS */
   6.914 +
   6.915 +	case CBRA:
   6.916 +		braslist[*ep++ & 0377] = (char *)lp;
   6.917 +		continue;
   6.918 +
   6.919 +	case CKET:
   6.920 +		braelist[*ep++ & 0377] = (char *)lp;
   6.921 +		continue;
   6.922 +
   6.923 +	case CBRC:
   6.924 +		if (lp == regexp_h_bol && locs == NULL)
   6.925 +			continue;
   6.926 +		if ((isdigit(lp[0] & 0377) || regexp_h_uletter(lp[0] & 0377))
   6.927 +				&& !regexp_h_uletter(lp[-1] & 0377)
   6.928 +				&& !isdigit(lp[-1] & 0377))
   6.929 +			continue;
   6.930 +		return(0);
   6.931 +
   6.932 +#ifdef	REGEXP_H_WCHARS
   6.933 +	case CBRC|CMB:
   6.934 +		c = regexp_h_show(lp);
   6.935 +		d = regexp_h_previous(lp);
   6.936 +		if ((iswdigit(c) || regexp_h_wuletter(c))
   6.937 +				&& !regexp_h_wuletter(d)
   6.938 +				&& !iswdigit(d))
   6.939 +			continue;
   6.940 +		return(0);
   6.941 +#endif	/* REGEXP_H_WCHARS */
   6.942 +
   6.943 +	case CLET:
   6.944 +		if (!regexp_h_uletter(lp[0] & 0377) && !isdigit(lp[0] & 0377))
   6.945 +			continue;
   6.946 +		return(0);
   6.947 +
   6.948 +#ifdef	REGEXP_H_WCHARS
   6.949 +	case CLET|CMB:
   6.950 +		c = regexp_h_show(lp);
   6.951 +		if (!regexp_h_wuletter(c) && !iswdigit(c))
   6.952 +			continue;
   6.953 +		return(0);
   6.954 +#endif	/* REGEXP_H_WCHARS */
   6.955 +
   6.956 +	case CCHR|RNGE:
   6.957 +		c = *ep++;
   6.958 +		regexp_h_getrnge(ep, least);
   6.959 +		while(low--)
   6.960 +			if(*lp++ != c)
   6.961 +				return(0);
   6.962 +		curlp = lp;
   6.963 +		while(size--) {
   6.964 +			regexp_h_push(&sb, &sp, &sc, lp);
   6.965 +			if(*lp++ != c)
   6.966 +				break;
   6.967 +		}
   6.968 +		if(size < 0) {
   6.969 +			regexp_h_push(&sb, &sp, &sc, lp);
   6.970 +			lp++;
   6.971 +		}
   6.972 +		ep += 2;
   6.973 +		goto star;
   6.974 +
   6.975 +#ifdef	REGEXP_H_WCHARS
   6.976 +	case CCHR|RNGE|CMB:
   6.977 +	case CCH1|RNGE:
   6.978 +	case CCH2|RNGE:
   6.979 +	case CCH3|RNGE:
   6.980 +		c = regexp_h_fetch(ep, 0);
   6.981 +		regexp_h_getrnge(ep, least);
   6.982 +		while (low--)
   6.983 +			if (regexp_h_fetch(lp, 1) != c)
   6.984 +				return 0;
   6.985 +		curlp = lp;
   6.986 +		while (size--) {
   6.987 +			regexp_h_push(&sb, &sp, &sc, lp);
   6.988 +			if (regexp_h_fetch(lp, 1) != c)
   6.989 +				break;
   6.990 +		}
   6.991 +		if(size < 0) {
   6.992 +			regexp_h_push(&sb, &sp, &sc, lp);
   6.993 +			regexp_h_fetch(lp, 1);
   6.994 +		}
   6.995 +		ep += 2;
   6.996 +		goto star;
   6.997 +#endif	/* REGEXP_H_WCHARS */
   6.998 +
   6.999 +	case CDOT|RNGE:
  6.1000 +		regexp_h_getrnge(ep, least);
  6.1001 +		while(low--)
  6.1002 +			if(*lp++ == '\0')
  6.1003 +				return(0);
  6.1004 +		curlp = lp;
  6.1005 +		while(size--) {
  6.1006 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1007 +			if(*lp++ == '\0')
  6.1008 +				break;
  6.1009 +		}
  6.1010 +		if(size < 0) {
  6.1011 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1012 +			lp++;
  6.1013 +		}
  6.1014 +		ep += 2;
  6.1015 +		goto star;
  6.1016 +
  6.1017 +#ifdef	REGEXP_H_WCHARS
  6.1018 +	case CDOT|RNGE|CMB:
  6.1019 +		regexp_h_getrnge(ep, least);
  6.1020 +		while (low--)
  6.1021 +			if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF)
  6.1022 +				return 0;
  6.1023 +		curlp = lp;
  6.1024 +		while (size--) {
  6.1025 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1026 +			if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF)
  6.1027 +				break;
  6.1028 +		}
  6.1029 +		if (size < 0) {
  6.1030 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1031 +			regexp_h_fetch(lp, 1);
  6.1032 +		}
  6.1033 +		ep += 2;
  6.1034 +		goto star;
  6.1035 +#endif	/* REGEXP_H_WCHARS */
  6.1036 +
  6.1037 +	case CCL|RNGE:
  6.1038 +		regexp_h_getrnge(ep + 32, least);
  6.1039 +		while(low--) {
  6.1040 +			c = *lp++ & 0377;
  6.1041 +			if(!ISTHERE(c))
  6.1042 +				return(0);
  6.1043 +		}
  6.1044 +		curlp = lp;
  6.1045 +		while(size--) {
  6.1046 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1047 +			c = *lp++ & 0377;
  6.1048 +			if(!ISTHERE(c))
  6.1049 +				break;
  6.1050 +		}
  6.1051 +		if(size < 0) {
  6.1052 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1053 +			lp++;
  6.1054 +		}
  6.1055 +		ep += 34;		/* 32 + 2 */
  6.1056 +		goto star;
  6.1057 +
  6.1058 +#ifdef	REGEXP_H_WCHARS
  6.1059 +	case CCL|RNGE|CMB:
  6.1060 +	case CNCL|RNGE|CMB:
  6.1061 +		regexp_h_getrnge(ep + (*ep & 0377) + 17, least);
  6.1062 +		while (low--) {
  6.1063 +			c = regexp_h_fetch(lp, 1);
  6.1064 +			if (!regexp_h_cclass(ep, c,
  6.1065 +					(ep[-1] & 0377 & ~REGEXP_H_LEAST)
  6.1066 +					== (CCL|RNGE|CMB)))
  6.1067 +				return 0;
  6.1068 +		}
  6.1069 +		curlp = lp;
  6.1070 +		while (size--) {
  6.1071 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1072 +			c = regexp_h_fetch(lp, 1);
  6.1073 +			if (!regexp_h_cclass(ep, c,
  6.1074 +					(ep[-1] & 0377 & ~REGEXP_H_LEAST)
  6.1075 +					== (CCL|RNGE|CMB)))
  6.1076 +				break;
  6.1077 +		}
  6.1078 +		if (size < 0) {
  6.1079 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1080 +			regexp_h_fetch(lp, 1);
  6.1081 +		}
  6.1082 +		ep += (*ep & 0377) + 19;
  6.1083 +		goto star;
  6.1084 +#endif	/* REGEXP_H_WCHARS */
  6.1085 +
  6.1086 +	case CBACK:
  6.1087 +		bbeg = braslist[*ep & 0377];
  6.1088 +		ct = braelist[*ep++ & 0377] - bbeg;
  6.1089 +
  6.1090 +		if(strncmp(bbeg, lp, ct) == 0) {
  6.1091 +			lp += ct;
  6.1092 +			continue;
  6.1093 +		}
  6.1094 +		return(0);
  6.1095 +
  6.1096 +	case CBACK|STAR:
  6.1097 +		bbeg = braslist[*ep & 0377];
  6.1098 +		ct = braelist[*ep++ & 0377] - bbeg;
  6.1099 +		curlp = lp;
  6.1100 +		while(strncmp(bbeg, lp, ct) == 0)
  6.1101 +			lp += ct;
  6.1102 +
  6.1103 +		while(lp >= curlp) {
  6.1104 +			if(regexp_h_advance(lp, ep))	return(1);
  6.1105 +			lp -= ct;
  6.1106 +		}
  6.1107 +		return(0);
  6.1108 +
  6.1109 +
  6.1110 +	case CDOT|STAR:
  6.1111 +		curlp = lp;
  6.1112 +		do
  6.1113 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1114 +		while (*lp++);
  6.1115 +		goto star;
  6.1116 +
  6.1117 +#ifdef	REGEXP_H_WCHARS
  6.1118 +	case CDOT|STAR|CMB:
  6.1119 +		curlp = lp;
  6.1120 +		do
  6.1121 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1122 +		while ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF);
  6.1123 +		goto star;
  6.1124 +#endif	/* REGEXP_H_WCHARS */
  6.1125 +
  6.1126 +	case CCHR|STAR:
  6.1127 +		curlp = lp;
  6.1128 +		do
  6.1129 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1130 +		while (*lp++ == *ep);
  6.1131 +		ep++;
  6.1132 +		goto star;
  6.1133 +
  6.1134 +#ifdef	REGEXP_H_WCHARS
  6.1135 +	case CCHR|STAR|CMB:
  6.1136 +	case CCH1|STAR:
  6.1137 +	case CCH2|STAR:
  6.1138 +	case CCH3|STAR:
  6.1139 +		curlp = lp;
  6.1140 +		d = regexp_h_fetch(ep, 0);
  6.1141 +		do
  6.1142 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1143 +		while (regexp_h_fetch(lp, 1) == d);
  6.1144 +		goto star;
  6.1145 +#endif	/* REGEXP_H_WCHARS */
  6.1146 +
  6.1147 +	case CCL|STAR:
  6.1148 +		curlp = lp;
  6.1149 +		do {
  6.1150 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1151 +			c = *lp++ & 0377;
  6.1152 +		} while(ISTHERE(c));
  6.1153 +		ep += 32;
  6.1154 +		goto star;
  6.1155 +
  6.1156 +#ifdef	REGEXP_H_WCHARS
  6.1157 +	case CCL|STAR|CMB:
  6.1158 +	case CNCL|STAR|CMB:
  6.1159 +		curlp = lp;
  6.1160 +		do {
  6.1161 +			regexp_h_push(&sb, &sp, &sc, lp);
  6.1162 +			c = regexp_h_fetch(lp, 1);
  6.1163 +		} while (regexp_h_cclass(ep, c, (ep[-1] & 0377)
  6.1164 +					== (CCL|STAR|CMB)));
  6.1165 +		ep += (*ep & 0377) + 17;
  6.1166 +		goto star;
  6.1167 +#endif	/* REGEXP_H_WCHARS */
  6.1168 +
  6.1169 +	star:
  6.1170 +#ifdef	REGEXP_H_WCHARS
  6.1171 +		if (regexp_h_wchars == 0) {
  6.1172 +#endif
  6.1173 +			do {
  6.1174 +				if(--lp == locs)
  6.1175 +					break;
  6.1176 +				if (regexp_h_advance(lp, ep))
  6.1177 +					return(1);
  6.1178 +			} while (lp > curlp);
  6.1179 +#ifdef	REGEXP_H_WCHARS
  6.1180 +		} else {
  6.1181 +			do {
  6.1182 +				lp = regexp_h_pop(&sb, &sp, &sc, lp);
  6.1183 +				if (lp <= locs)
  6.1184 +					break;
  6.1185 +				if (regexp_h_advance(lp, ep)) {
  6.1186 +					regexp_h_zerostak(&sb, &sp);
  6.1187 +					return(1);
  6.1188 +				}
  6.1189 +			} while (lp > curlp);
  6.1190 +			regexp_h_zerostak(&sb, &sp);
  6.1191 +		}
  6.1192 +#endif	/* REGEXP_H_WCHARS */
  6.1193 +		return(0);
  6.1194 +
  6.1195 +	}
  6.1196 +}
  6.1197 +
  6.1198 +static void
  6.1199 +regexp_h_getrnge(register const char *str, int least)
  6.1200 +{
  6.1201 +	low = *str++ & 0377;
  6.1202 +	size = least & REGEXP_H_LEAST ? /*20000*/INT_MAX : (*str & 0377) - low;
  6.1203 +}
  6.1204 +
  6.1205 +int
  6.1206 +advance(const char *lp, const char *ep)
  6.1207 +{
  6.1208 +	REGEXP_H_ADVANCE_INIT	/* skip past circf */
  6.1209 +	regexp_h_bol = lp;
  6.1210 +#ifdef	REGEXP_H_WCHARS
  6.1211 +	regexp_h_firstwc = NULL;
  6.1212 +#endif	/* REGEXP_H_WCHARS */
  6.1213 +	return regexp_h_advance(lp, ep);
  6.1214 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/regexpr.c	Mon Sep 05 16:31:35 2011 +0200
     7.3 @@ -0,0 +1,90 @@
     7.4 +/*
     7.5 + * Simple Regular Expression functions. Derived from Unix 7th Edition,
     7.6 + * /usr/src/cmd/expr.y
     7.7 + *
     7.8 + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
     7.9 + *
    7.10 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
    7.11 + *
    7.12 + * Redistribution and use in source and binary forms, with or without
    7.13 + * modification, are permitted provided that the following conditions
    7.14 + * are met:
    7.15 + *   Redistributions of source code and documentation must retain the
    7.16 + *    above copyright notice, this list of conditions and the following
    7.17 + *    disclaimer.
    7.18 + *   Redistributions in binary form must reproduce the above copyright
    7.19 + *    notice, this list of conditions and the following disclaimer in the
    7.20 + *    documentation and/or other materials provided with the distribution.
    7.21 + *   All advertising materials mentioning features or use of this software
    7.22 + *    must display the following acknowledgement:
    7.23 + *      This product includes software developed or owned by Caldera
    7.24 + *      International, Inc.
    7.25 + *   Neither the name of Caldera International, Inc. nor the names of
    7.26 + *    other contributors may be used to endorse or promote products
    7.27 + *    derived from this software without specific prior written permission.
    7.28 + *
    7.29 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    7.30 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    7.31 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    7.32 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    7.33 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    7.34 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    7.35 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    7.36 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    7.37 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    7.38 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    7.39 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    7.40 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    7.41 + */
    7.42 +
    7.43 +/*	Sccsid @(#)regexpr.c	1.8 (gritter) 10/13/04	*/
    7.44 +
    7.45 +#include	<stdlib.h>
    7.46 +#include	"regexpr.h"
    7.47 +
    7.48 +int	regerrno, reglength;
    7.49 +static int	circf;
    7.50 +
    7.51 +static char	*regexpr_compile(char *, char *, const char *, int);
    7.52 +
    7.53 +char *
    7.54 +compile(const char *instring, char *ep, char *endbuf)
    7.55 +{
    7.56 +	char	*cp;
    7.57 +	int	sz = 0;
    7.58 +
    7.59 +	if (ep == 0) {
    7.60 +		for (cp = (char *)instring; *cp != '\0'; cp++)
    7.61 +			if (*cp == '[')
    7.62 +				sz += 32;
    7.63 +		sz += 2 * (cp - instring) + 5;
    7.64 +		if ((ep = malloc(sz)) == 0) {
    7.65 +			regerrno = 11;
    7.66 +			return 0;
    7.67 +		}
    7.68 +		endbuf = &ep[sz];
    7.69 +		ep[1] = '\0';
    7.70 +	}
    7.71 +	if ((cp=regexpr_compile((char *)instring, &ep[1], endbuf, '\0')) == 0) {
    7.72 +		if (sz)
    7.73 +			free(ep);
    7.74 +		return 0;
    7.75 +	}
    7.76 +	ep[0] = circf;
    7.77 +	reglength = cp - ep;
    7.78 +	return sz ? ep : cp;
    7.79 +}
    7.80 +
    7.81 +#define	INIT			register char *sp = instring;
    7.82 +#define	GETC()			(*sp++)
    7.83 +#define	PEEKC()			(*sp)
    7.84 +#define	UNGETC(c)		(--sp)
    7.85 +#define	RETURN(c)		return (c);
    7.86 +#define	ERROR(c)		{ regerrno = c; return 0; }
    7.87 +
    7.88 +#define	compile(a, b, c, d)	regexpr_compile(a, b, c, d)
    7.89 +#define	regexp_h_static		static
    7.90 +#define	REGEXP_H_STEP_INIT	circf = *p2++;
    7.91 +#define	REGEXP_H_ADVANCE_INIT	circf = *ep++;
    7.92 +
    7.93 +#include	"regexp.h"
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/regexpr.h	Mon Sep 05 16:31:35 2011 +0200
     8.3 @@ -0,0 +1,53 @@
     8.4 +/*
     8.5 + * Simple Regular Expression functions. Derived from Unix 7th Edition,
     8.6 + * /usr/src/cmd/expr.y
     8.7 + *
     8.8 + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003.
     8.9 + *
    8.10 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
    8.11 + *
    8.12 + * Redistribution and use in source and binary forms, with or without
    8.13 + * modification, are permitted provided that the following conditions
    8.14 + * are met:
    8.15 + *   Redistributions of source code and documentation must retain the
    8.16 + *    above copyright notice, this list of conditions and the following
    8.17 + *    disclaimer.
    8.18 + *   Redistributions in binary form must reproduce the above copyright
    8.19 + *    notice, this list of conditions and the following disclaimer in the
    8.20 + *    documentation and/or other materials provided with the distribution.
    8.21 + *   All advertising materials mentioning features or use of this software
    8.22 + *    must display the following acknowledgement:
    8.23 + *      This product includes software developed or owned by Caldera
    8.24 + *      International, Inc.
    8.25 + *   Neither the name of Caldera International, Inc. nor the names of
    8.26 + *    other contributors may be used to endorse or promote products
    8.27 + *    derived from this software without specific prior written permission.
    8.28 + *
    8.29 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    8.30 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    8.31 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    8.32 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    8.33 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    8.34 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    8.35 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    8.36 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    8.37 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    8.38 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    8.39 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    8.40 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    8.41 + */
    8.42 +
    8.43 +/*	Sccsid @(#)regexpr.h	1.2 (gritter) 1/11/03	*/
    8.44 +
    8.45 +#define	NBRA	9
    8.46 +
    8.47 +extern char	*braslist[NBRA];
    8.48 +extern char	*braelist[NBRA];
    8.49 +extern int	nbra;
    8.50 +extern int	regerrno, reglength;
    8.51 +extern char	*loc1, *loc2, *locs;
    8.52 +extern int	sed;
    8.53 +
    8.54 +extern char	*compile(const char *, char *, char *);
    8.55 +extern int	step(const char *, const char *);
    8.56 +extern int	advance(const char *, const char *);
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/sigrelse.c	Mon Sep 05 16:31:35 2011 +0200
     9.3 @@ -0,0 +1,41 @@
     9.4 +/*
     9.5 + * Copyright (c) 2004 Gunnar Ritter
     9.6 + *
     9.7 + * This software is provided 'as-is', without any express or implied
     9.8 + * warranty. In no event will the authors be held liable for any damages
     9.9 + * arising from the use of this software.
    9.10 + *
    9.11 + * Permission is granted to anyone to use this software for any purpose,
    9.12 + * including commercial applications, and to alter it and redistribute
    9.13 + * it freely, subject to the following restrictions:
    9.14 + *
    9.15 + * 1. The origin of this software must not be misrepresented; you must not
    9.16 + *    claim that you wrote the original software. If you use this software
    9.17 + *    in a product, an acknowledgment in the product documentation would be
    9.18 + *    appreciated but is not required.
    9.19 + *
    9.20 + * 2. Altered source versions must be plainly marked as such, and must not be
    9.21 + *    misrepresented as being the original software.
    9.22 + *
    9.23 + * 3. This notice may not be removed or altered from any source distribution.
    9.24 + */
    9.25 +/*	Sccsid @(#)sigrelse.c	1.8 (gritter) 1/22/06	*/
    9.26 +
    9.27 +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
    9.28 +	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
    9.29 +#include <signal.h>
    9.30 +#include "sigset.h"
    9.31 +
    9.32 +int
    9.33 +sigrelse(int sig)
    9.34 +{
    9.35 +	sigset_t	set, oset;
    9.36 +
    9.37 +	if (sig <= 0)
    9.38 +		return -1;
    9.39 +	sigemptyset(&set);
    9.40 +	sigaddset(&set, sig);
    9.41 +	return sigprocmask(SIG_UNBLOCK, &set, &oset);
    9.42 +}
    9.43 +#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
    9.44 +	__DragonFly__ || __APPLE__ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/sigset.c	Mon Sep 05 16:31:35 2011 +0200
    10.3 @@ -0,0 +1,55 @@
    10.4 +/*
    10.5 + * Copyright (c) 2004 Gunnar Ritter
    10.6 + *
    10.7 + * This software is provided 'as-is', without any express or implied
    10.8 + * warranty. In no event will the authors be held liable for any damages
    10.9 + * arising from the use of this software.
   10.10 + *
   10.11 + * Permission is granted to anyone to use this software for any purpose,
   10.12 + * including commercial applications, and to alter it and redistribute
   10.13 + * it freely, subject to the following restrictions:
   10.14 + *
   10.15 + * 1. The origin of this software must not be misrepresented; you must not
   10.16 + *    claim that you wrote the original software. If you use this software
   10.17 + *    in a product, an acknowledgment in the product documentation would be
   10.18 + *    appreciated but is not required.
   10.19 + *
   10.20 + * 2. Altered source versions must be plainly marked as such, and must not be
   10.21 + *    misrepresented as being the original software.
   10.22 + *
   10.23 + * 3. This notice may not be removed or altered from any source distribution.
   10.24 + */
   10.25 +/*	Sccsid @(#)sigset.c	1.7 (gritter) 1/22/06	*/
   10.26 +
   10.27 +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
   10.28 +	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
   10.29 +#include <signal.h>
   10.30 +#include "sigset.h"
   10.31 +
   10.32 +void (*sigset(int sig, void (*func)(int)))(int)
   10.33 +{
   10.34 +	struct sigaction nact, oact;
   10.35 +	sigset_t	nset, oset;
   10.36 +
   10.37 +	if (sig <= 0)
   10.38 +		return SIG_ERR;
   10.39 +	sigemptyset(&nset);
   10.40 +	sigaddset(&nset, sig);
   10.41 +	if (sigprocmask(func==SIG_HOLD?SIG_BLOCK:SIG_UNBLOCK, &nset, &oset) < 0)
   10.42 +		return SIG_ERR;
   10.43 +	nact.sa_handler = func;
   10.44 +	nact.sa_flags = 0;
   10.45 +	if (sig == SIGCHLD && func == SIG_IGN)
   10.46 +		nact.sa_flags |= SA_NOCLDSTOP|SA_NOCLDWAIT;
   10.47 +	sigemptyset(&nact.sa_mask);
   10.48 +	sigaddset(&nact.sa_mask, sig);
   10.49 +	if (sigaction(sig, func==SIG_HOLD?(struct sigaction *)0:&nact, &oact)
   10.50 +			== -1)
   10.51 +		return SIG_ERR;
   10.52 +	if (sigismember(&oset, sig))
   10.53 +		return SIG_HOLD;
   10.54 +	else
   10.55 +		return (oact.sa_handler);
   10.56 +}
   10.57 +#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
   10.58 +	__DragonFly__ || __APPLE__ */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/sigset.h	Mon Sep 05 16:31:35 2011 +0200
    11.3 @@ -0,0 +1,38 @@
    11.4 +/*
    11.5 + * Copyright (c) 2004 Gunnar Ritter
    11.6 + *
    11.7 + * This software is provided 'as-is', without any express or implied
    11.8 + * warranty. In no event will the authors be held liable for any damages
    11.9 + * arising from the use of this software.
   11.10 + *
   11.11 + * Permission is granted to anyone to use this software for any purpose,
   11.12 + * including commercial applications, and to alter it and redistribute
   11.13 + * it freely, subject to the following restrictions:
   11.14 + *
   11.15 + * 1. The origin of this software must not be misrepresented; you must not
   11.16 + *    claim that you wrote the original software. If you use this software
   11.17 + *    in a product, an acknowledgment in the product documentation would be
   11.18 + *    appreciated but is not required.
   11.19 + *
   11.20 + * 2. Altered source versions must be plainly marked as such, and must not be
   11.21 + *    misrepresented as being the original software.
   11.22 + *
   11.23 + * 3. This notice may not be removed or altered from any source distribution.
   11.24 + */
   11.25 +/*	Sccsid @(#)sigset.h	1.9 (gritter) 1/22/06	*/
   11.26 +
   11.27 +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
   11.28 +	defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__)
   11.29 +
   11.30 +#ifndef	SIG_HOLD
   11.31 +#define	SIG_HOLD	((void (*)(int))2)
   11.32 +#endif	/* !SIG_HOLD */
   11.33 +
   11.34 +extern int	sighold(int);
   11.35 +extern int	sigignore(int);
   11.36 +extern int	sigpause(int);
   11.37 +extern int	sigrelse(int);
   11.38 +extern void	(*sigset(int, void (*)(int)))(int);
   11.39 +extern void	(*signal(int, void (*)(int)))(int);
   11.40 +#endif	/* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ ||
   11.41 +	__DragonFly__ || __APPLE__ */