# HG changeset patch # User markus schnalke # Date 1315233095 -7200 # Node ID 1493bea5ac22c3a472ead00e5955933948f0c30c Initial version of the standalone heirloom-ed diff -r 000000000000 -r 1493bea5ac22 LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,1 @@ +Look into the source files directly. diff -r 000000000000 -r 1493bea5ac22 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,22 @@ +Ed -- The Standard Text Editor +============================== + +This version of ed had been cut out of Gunnar Ritter's Heirloom Toolchest. +The reason for doing so is to have Heirloom ed quickly at hand when I am +annoyed again by GNU ed. Having to configure and install the complete +Heirloom Toolchest is more than I usually want. This ed is slightly +stripped down as only the traditional variant gets created. Any references +to the other variants and features only in them are removed from the man +page. Parts of libcommon had been ripped out and included directly. Thus +the makefile had been reworked. + +To install do: + + vi makefile + make + make install + + +2011-09-05 +markus schnalke +http://hg.marmaro.de/heirloom-ed diff -r 000000000000 -r 1493bea5ac22 ed.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ed.1 Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,914 @@ +'\" t +.\" Sccsid @(#)ed.1 1.48 (gritter) 6/22/05 +.\" Parts taken from ed(1), Unix 7th edition: +.\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" Redistributions of source code and documentation must retain the +.\" above copyright notice, this list of conditions and the following +.\" disclaimer. +.\" Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed or owned by Caldera +.\" International, Inc. +.\" Neither the name of Caldera International, Inc. nor the names of +.\" other contributors may be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE +.\" LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.TH ED 1 "6/22/05" "Heirloom Toolchest" "User Commands" +.if t .ds q \(aa +.if n .ds q ' +.SH NAME +ed \- text editor +.SH SYNOPSIS +\fBed\fR [\fB\-\fR\ |\ \fB\-s\fR] [\fB\-p\fI\ prompt\fR] [\fIname\fR] +.SH DESCRIPTION +.I Ed +is the standard text editor. +.PP +If a +.I name +argument is given, +.I ed +simulates an +.I e +command (see below)\| on the named file; that is to say, +the file is read into +.IR ed 's +buffer so that it can be edited. +The optional +.B \- +or +.B \-s +suppresses the printing +of character counts by +.IR e , +.IR r , +and +.I w +commands, +and of the `!' after completion of a shell command. +.PP +With the +.B \-p +option, +the given +.I prompt +string is printed before each command is read. +.PP +.I Ed +operates on a copy of any file it is editing; changes made +in the copy have no effect on the file until a +.IR w "" +(write)\| +command is given. +The copy of the text being edited resides +in a temporary file called the +.IR buffer . +.PP +The editor supports format specifications as defined in +.IR fspec (5). +If the terminal is configured to expand tabulators +(as enabled with +.I stty tab3 +or +.IR "stty \-tabs"), +and the first line of the file being edited +contains a format specification, +the +.I t +and +.I s +are interpreted, +that is, tabulators are expanded and lines are truncated +when printing to the terminal. For example, +.RS +<:t\-f s72:> +.sp +.RE +selects FORTRAN format and truncates lines at 72 characters. +No expansion or truncation is performed by +.I ed +when input is typed to the terminal. +.PP +Commands to +.I ed +have a simple and regular structure: zero or +more +.I addresses +followed by a single character +.I command, +possibly +followed by parameters to the command. +These addresses specify one or more lines in the buffer. +Missing addresses are supplied by default. +.PP +In general, only one command may appear on a line. +Certain commands allow the +addition of text to the buffer. +While +.I ed +is accepting text, it is said +to be in +.I "input mode." +In this mode, no commands are recognized; +all input is merely collected. +Input mode is left by typing a period `\fB.\fR' alone at the +beginning of a line. +.PP +.I Ed +supports a limited form of +.I "regular expression" +notation. +A regular expression specifies +a set of strings of characters. +A member of this set of strings is said to be +.I matched +by the regular expression. +In the following specification for regular expressions +the word `character' means any character but newline. +.B ed +uses simple regular expressions. +.SS "Simple Regular Expressions" +.IP 1. +Any character except a special character +matches itself. +Special characters are +the regular expression delimiter plus +.RB \e\|[\| . +and sometimes ^\|*\|$. +.IP 2. +A +.B .\& +matches any character. +.IP 3. +A \fB\e\fR followed by any character except a digit +or (\|) {\|} <\|> matches that character. +.IP 4. +A nonempty string +.I s +bracketed +\fB[\fI\|s\|\fB]\fR +(or +\fB[^\fIs\|\fB]\fR) +forms a \fIbracket expression\fR that +matches any character in (or not in) +.I s. +In +.I s, +\e has no special meaning, and ] may only appear as +the first letter. +A substring +\fIa\fB\-\fIb\fR, +with +.I a +and +.I b +in ascending ASCII order, stands for the inclusive +range of ASCII characters. +.IP 5. +A regular expression of form 1-4 followed by \fB*\fR matches a sequence of +0 or more matches of the regular expression. +.IP 6. +A regular expression of form 1-4 +followed by \fB\e{\fIm\fB,\fIn\fB\e}\fR +forms an \fIinterval expression\fR that +matches a sequence of \fIm\fR through \fIn\fR matches, inclusive, +of the regular expression. +The values of \fIm\fR and \fIn\fR must be non-negative +and smaller than 256. +The form \fB\e{\fIm\fB\e}\fR matches exactly \fIm\fR occurrences, +\fB\e{\fIm\fB,\e}\fR matches at least \fIm\fR occurrences. +.IP 7. +The sequence \fB\e<\fR forces the match +to occur only at the beginning of a ``variable'' or ``word''; +that is, either at the beginning of a line, +or just before a letter, digit or underline +and after a character not one of these. +.IP 8. +The sequence \fB\e>\fR matches the end +of a ``variable'' or ``word'', +i.\|e. either the end of the line +or before character which is neither a letter, +nor a digit, nor the underline character. +.IP 9. +A regular expression, +.I x, +of form 1-11, parenthesized +\fB\e(\fI\|x\|\fB\e)\fR +is called a \fIsubexpression\fR and +matches what +.I x +matches. +.IP 10. +A \fB\e\fR followed by a digit +.I n +forms a \fIbackreference\fR and +matches a copy of the string that the +parenthesized regular expression beginning with the +.IR n th +\e( matched. +.IP 11. +A regular expression of form 1-11, +.I x, +followed by a regular expression of form 1-10, +.I y +matches a match for +.I x +followed by a match for +.I y, +with the +.I x +match being as long as possible while still permitting a +.I y +match. +.IP 12. +A regular expression of form 1-11 preceded by \fB^\fR +(or followed by \fB$\fR), is constrained to matches that +begin at the left (or end at the right) end of a line +(\fIanchoring\fR). +.IP 13. +A regular expression of form 1-12 picks out the +longest among the leftmost matches in a line. +.IP 14. +An empty regular expression stands for a copy of the +last regular expression encountered. +.PP +Regular expressions are used in addresses to specify +lines and in one command +(see +.I s +below)\| +to specify a portion of a line which is to be replaced. +If it is desired to use one of +the regular expression metacharacters as an ordinary +character, that character may be preceded by `\e'. +This also applies to the character bounding the regular +expression (often `/')\| and to `\e' itself. +.PP +To understand addressing in +.I ed +it is necessary to know that at any time there is a +.I "current line." +Generally speaking, the current line is +the last line affected by a command; however, +the exact effect on the current line +is discussed under the description of +the command. +Addresses are constructed as follows. +.TP +1. +The character `\fB.\fR' addresses the current line. +.TP +2. +The character `\fB$\fR' addresses the last line of the buffer. +.TP +3. +A decimal number +.I n +addresses the +.IR n -th +line of the buffer. +.TP +4. +`\fB\(fm\fIx\fR' addresses the line marked with the name +.IR x , +which must be a lower-case letter. +Lines are marked with the +.I k +command described below. +.TP +5. +A regular expression enclosed in slashes `\fB/\fR' addresses +the line found by searching forward from the current line +and stopping at the first line containing a +string that matches the regular expression. +If necessary the search wraps around to the beginning of the +buffer. +.TP +6. +A regular expression enclosed in queries `\fB?\fR' addresses +the line found by searching backward from the current line +and stopping at the first line containing +a string that matches the regular expression. +If necessary +the search wraps around to the end of the buffer. +.TP +7. +An address followed by a plus sign `\fB+\fR' +or a minus sign `\fB\-\fR' followed by a decimal number +specifies that address plus +(resp. minus)\| the indicated number of lines. +The plus sign may be omitted. +.TP +8. +If an address begins with `\fB+\fR' or `\fB\-\fR' +the addition or subtraction is taken with respect to the current line; +e.g. `\-5' is understood to mean `\fB.\fR\-5'. +.TP +9. +If an address ends with `\fB+\fR' or `\fB\-\fR', +then 1 is added (resp. subtracted). +As a consequence of this rule and rule 8, +the address `\-' refers to the line before the current line. +Moreover, +trailing +`+' and `\-' characters +have cumulative effect, so `\-\-' refers to the current +line less 2. +.TP +10. +To maintain compatibility with earlier versions of the editor, +the character `\fB^\fR' in addresses is +equivalent to `\-'. +.PP +Commands may require zero, one, or two addresses. +Commands which require no addresses regard the presence +of an address as an error. +Commands which accept one or two addresses +assume default addresses when insufficient are given. +If more addresses are given than such a command requires, +the last one or two (depending on what is accepted)\| are used. +.PP +Addresses are separated from each other typically by a comma +`\fB,\fR'. +They may also be separated by a semicolon +`\fB;\fR'. +In this case the current line `\fB.\fR' is set to +the previous address before the next address is interpreted. +This feature can be used to determine the starting +line for forward and backward searches (`/', `?')\|. +The second address of any two-address sequence +must correspond to a line following the line corresponding to the first address. +.PP +Omission of the first address causes +the first line to be used with `,', +or the current line with `;', respectively; +if the second address is also omitted, +the last line of the buffer is used. +Thus a single `,' specifies the entire contents of the buffer, +and a single `;' specifies the contents +ranging from the current line to the last one. +.PP +In the following list of +.I ed +commands, the default addresses +are shown in parentheses. +The parentheses are not part of +the address, but are used to show that the given addresses are +the default. +.PP +As mentioned, it is generally illegal for more than one +command to appear on a line. +However, most commands may be suffixed by `p', `l', or `n', +in which case +the current line is either +printed, listed, or numbered respectively +in the way discussed below. +.TP 5 +\fR(\|\fI.\|\fR)\fB\|a\fR +.br +.ns +.TP 5 + +.br +.ns +.TP 5 +.B . +.br +The append command reads the given text +and appends it after the addressed line. +`\fB.\fR' is left +on the last line input, if there +were any, otherwise at the addressed line. +Address `0' is legal for this command; text is placed +at the beginning of the buffer. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBc\fR +.br +.ns +.TP 5 + +.br +.ns +.TP 5 +.B . +.br +The change +command deletes the addressed lines, then accepts input +text which replaces these lines. +`\fB.\fR' is left at the last line input; if there were none, +it is left at the line preceding the deleted lines. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBd\fR +The delete command deletes the addressed lines from the buffer. +The line originally after the last line deleted becomes the current line; +if the lines deleted were originally at the end, +the new last line becomes the current line. +.TP 5 +\fBe\ \fIfilename\fR +The edit +command causes the entire contents of the buffer to be deleted, +and then the named file to be read in. +`\fB.\fR' is set to the last line of the buffer. +The number of characters read is typed. +`\fIfilename\fR' is remembered for possible use as a default file name +in a subsequent +.I r +or +.I w +command. +If `\fIfilename\fR' is missing, the remembered name is used. +A `\fIfilename\fR' starting with a `\fB!\fR' +causes the output of the shell command following this character +to be read in. +.TP 5 +\fBE\ \fIfilename\fR +This command is the same as +.IR e , +except that no diagnostic results when no +.I w +has been given since the last buffer alteration. +.TP 5 +\fBf\ \fIfilename\fR +The filename command prints the currently remembered file name. +If `\fIfilename\fR' is given, +the currently remembered file name is changed to `\fIfilename\fR'. +.TP 5 +\fR(\fI1\fB,\fI$\fR)\|\fBg/\fIregular expression\fB/\fIcommand list\fR +In the global +command, the first step is to mark every line which matches +the given \fIregular expression\fR. +Then for every such line, the +given \fIcommand list\fR is executed +with `\fB.\fR' initially set to that line. +A single command or the first of multiple commands +appears on the same line with the global command. +All lines of a multi-line list except the last line must be ended with `\e'. +.I A, +.I i, +and +.I c +commands and associated input are permitted; +the `\fB.\fR' terminating input mode may be omitted if it would be on the +last line of the command list. +The commands +.I g +and +.I v +are not permitted in the command list. +.TP 5 +\fR(\fI1\fB,\fI$\fR)\|\fBG/\fIregular expression\fB/\fR +The interactive global command +first marks every line matching the given \fIregular expression\fR. +Then each line is printed +and a command is read and executed for this line. +A single newline character causes the line to remain unchanged, +an isolated `\fB&\fR' repeats the command given for the previous line. +The command can be terminated by an interrupt signal. +.TP 5 +.B h +This command prints a verbose description for the +last error encountered. +.TP +.B H +This command acts like the +.I h +command, +but also causes verbose descriptions to be printed +on all following error conditions. +Another +.I H +turns verbose mode off. +.TP 5 +\fR(\|\fI.\|\fR)\|\fBi\fR +.br +.ns +.TP 5 + +.br +.ns +.TP 5 +.B . +.br +This command inserts the given text before the addressed line. +`\fB.\fR' is left at the last line input, or, if there were none, +at the line before the addressed line. +This command differs from the +.I a +command only in the placement of the +text. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.+1\fR)\|\fBj\fR +This command joins the addressed lines into a single line; +intermediate newlines simply disappear. +`\fB.\fR' is left at the resulting line. +.TP 5 +\fR(\fI.\fR)\|\fBk\fIx\fR +The mark command marks the addressed line with +name +.IR x , +which must be a lower-case letter. +The address form `\(fm\fIx\fR' then addresses this line. +.ne 2.5 +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBl\fR +The list command +prints the addressed lines in an unambiguous way: +non-graphic control characters are printed in three-digit octal; +Long lines are folded. +The +.I l +command may be placed on the same line after any non-i/o +command. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBm\fIa\fR +The move command repositions the addressed lines after the line +addressed by +.IR a . +The last of the moved lines becomes the current line. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBn\fR +This command prints lines preceded by their line numbers. +It otherwise acts like the +.I p +command described below. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBp\fR +The print command prints the addressed lines. +`\fB.\fR' +is left at the last line printed. +The +.I p +command +may +be placed on the same line after any non-i/o command. +.TP +.B P +This command causes a prompt to be printed +before following commands are read. +The default prompt is a `*' character, +but can be set with the +.I \-p +command line option (which also enables the prompt). +Another +.I P +disables the prompt. +.TP 5 +.B q +The quit command causes +.I ed +to exit. +No automatic write +of a file is done. +.TP 5 +.B Q +This command is the same as +.I q, +except that no diagnostic results when no +.I w +has been given since the last buffer alteration. +.TP 5 +\fR(\fI$\fR)\|\fBr\ \fIfilename\fR +The read command +reads in the given file after the addressed line. +If no file name is given, +the remembered file name, if any, is used +(see +.I e +and +.I f +commands)\|. +The file name is remembered if there was no +remembered file name already. +Address `0' is legal for +.I r +and causes the +file to be read at the beginning of the buffer. +If the read is successful, the number of characters +read is typed. +`\fB.\fR' is left at the last line read in from the file. +A `filename' starting with a `\fB!\fR' +causes the output of the shell command following this character +to be read in. +.TP 5 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/\fR or, +.br +.ns +.TP 5 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/g\fR or, +.br +.ns +.TP 5 +\fR(\|\fI.\fB\|,\|\fI.\fR\|)\|\fBs/\fIregular expression\fB/\fIreplacement\fB/\fInumber\fR +The substitute command searches each addressed +line for an occurrence of the specified regular expression. +On each line in which a match is found, +all matched strings are replaced by the replacement specified, +if the global replacement indicator +.RB ` g ' +appears after the command. +If the global indicator does not appear, only the first occurrence +of the matched string is replaced; +if the \fInumber\fR indicator is given, +the numbered occurrence is replaced. +It is an error for the substitution to fail on all addressed lines. +Any character other than space or new-line +may be used instead of `/' to delimit the regular expression +and the replacement. +`\fB.\fR' is left at the last line substituted. +.IP +An ampersand +.RB ` & ' +appearing in the replacement +is replaced by the string matching the regular expression. +The special meaning of `&' in this context may be +suppressed by preceding it by +.RB ` \e '. +The characters `\|\fB\e\fIn\fR' +where +.I n +is a digit, +are replaced by the text matched by the +.IR n -th +regular subexpression +enclosed between `\e(' and `\e)'. +When +nested, parenthesized subexpressions +are present, +.I n +is determined by counting occurrences of `\e(' starting from the left. +.IP +A substitution string consisting of a single +.RB ` % ' +causes the string given on the previous substitution to be re-used. +.IP +Lines may be split by substituting new-line characters into them. +The new-line in the +replacement string +must be escaped by preceding it by +.RB ` \e '. +.TP 5 +\fR(\|\fI.\|\fB,\|\fI.\|\fR)\|\fBt\|\fIa\fR +This command acts just like the +.I m +command, except that a copy of the addressed lines is placed +after address +.I a +(which may be 0). +`\fB.\fR' is left on the last line of the copy. +.TP 5 +.B u +The undo command restores +the contents of the buffer +before the last command was executed. +If the undo command is given twice, +the current state is restored. +.TP 5 +\fR(\fI1\fB,\fI$\fR)\|\fBv/\fIregular expression\fB/\fIcommand list\fR +This command is the same as the global command +.I g +except that the command list is executed +.I g +with `\fB.\fR' initially set to every line +.I except +those +matching the regular expression. +.TP 5 +\fR(\fI1\fB,\fI$\fR)\|\fBV/\fIregular expression\fB/\fR +This command is the same as the interactive global command +.I G +except that the commands are read +.I g +with `\fB.\fR' initially set to every line +.I except +those +matching the regular expression. +.TP 5 +\fR(\fI1\fB,\fI$\fR)\|\fBw\ \fIfilename\fR +.br +The write command writes the addressed lines onto +the given file. +If the file does not exist, +it is created mode 666 (readable and writable by everyone)\|. +The file name is remembered if there was no +remembered file name already. +If no file name is given, +the remembered file name, if any, is used +(see +.I e +and +.I f +commands)\|. +`\fB.\fR' is unchanged. +If the command is successful, the number of characters written is +printed. +A `filename' starting with a `\fB!\fR' +causes the string following this character +to be executed as a shell command +with the addressed lines as standard input. +.TP +\fR(\fI1\fB,\fI$\fR)\fBW\ \fIfilename\fR +This command is the same as +.I w, +except that the addressed lines are appended to the file. +.TP 5 +\fR(\fI$\fR)\|\fB=\fR +The line number of the addressed line is typed. +`\fB.\fR' is unchanged by this command. +.TP 5 +\fB!\fR +The remainder of the line after the `!' is sent +to +.IR sh (1) +to be interpreted as a command. +.RB ` . ' +is unchanged. +If the command starts with a +.RB ` ! ', +the previous command is inserted. +A +.RB ` % ' +causes the current file name to be inserted. +.TP 5 +\fR(\|\fI.+1\fR)\| +An address alone on a line causes the addressed line to be printed. +A blank line alone is equivalent to `.+1p'; it is useful +for stepping through text. +.PP +The following commands are extensions: +.TP 5 +\fR(\|\fI.\|\fR)\fB\|b\fR[\fIcount\fR] +Prints a screenful of lines, +starting at the addressed one, +and browses forward in the buffer by this amount. +With the optional +.I count +argument, the screen size for this and following +.I b +commands is set to the given number of lines. +.TP 5 +.B help +Causes a summary of +.I ed +commands along with short descriptions +to be printed on the terminal. +.TP 5 +.B N +Makes the +.I p +command behave like the +.I n +command and vice-versa. +If given a second time, +the original semantics are restored. +.TP 5 +\fR(\|\fI.\|\fR)\fB\|o\fR[\fIcount\fR] +Prints a screenful of lines centered around the addressed one. +The current line is not changed. +With the optional +.I count +argument, the amount of lines printed above and below +for this and following +.I o +commands is set to the given number. +.TP 5 +.B z +Performs the same actions as a +.I w +command followed by a +.I q +command. +.PP +If an interrupt signal is sent, +.I ed +prints a `?' and returns to its command level. +.PP +An input line that consists exactly of the two characters `\e.' +causes a period `.' to be inserted with the +.IR a , +.IR c , +and +.IR i +commands. +.PP +Some size limitations: +The maximum number of bytes in the buffer +corresponds to the address size; +on machines with 32-bit addressing, +it is 2\ G bytes, +with 64-bit addressing, +it is 9\ E bytes. +The limit on the number of lines depends on the amount of core: +each line takes 2 words. +.PP +If a line contains a NUL character, +regular expressions cannot match beyond this character. +A substitute command deletes a NUL +and all following characters on the line. +NUL characters in command input are discarded. +If an input file does not end with a newline, +.I ed +prints a message and appends one. +.PP +Omission of the `/' character +following the regular expression or the replacement string +to the global and substitute commands +causes the affected lines to be printed. +Thus the following commands have the same effect: +.RS +g/pattern g/pattern/p +.br +s/pattern/repl s/pattern/repl/p +.br +s/pattern/ s/pattern//p +.RE +.SH "ENVIRONMENT VARIABLES" +.TP +.BR LANG ", " LC_ALL +See +.IR locale (7). +.TP +.B LC_CTYPE +Determines the mapping of bytes to characters +and the set of printable characters for the +.I l +command. +.TP +.B TMPDIR +Determines the location of the temporary file +if it contains the name of an accessible directory. +.SH FILES +/var/tmp/e* +.br +/tmp/e* +.br +ed.hup: work is saved here if terminal hangs up +.SH "SEE ALSO" +B. W. Kernighan, +.I +A Tutorial Introduction to the ED Text Editor +.br +B. W. Kernighan, +.I Advanced editing on UNIX +.br +bfs(1), +grep(1), +sed(1), +sh(1) +.SH DIAGNOSTICS +`?name' for inaccessible file; +`?' for +errors in commands, +possibly followed by a verbose description +(see the description for the +.I h +and +.I H +commands above). +.PP +To protect against throwing away valuable work, +a +.I q +or +.I e +command is considered to be in error, unless a +.I w +has occurred since the last buffer change. +A second +.I q +or +.I e +will be obeyed regardless. +.SH NOTES +A +.I !\& +command cannot be subject to a +.I g +command. +.PP +The LC_COLLATE variable has currently no effect. +Ranges in bracket expressions are ordered +as byte values in single-byte locales +and as wide character values in multibyte locales. +.PP +For portable programs, restrict textual data +to the US-ASCII character set and +set the LC_CTYPE and LC_COLLATE variables to `C' or `POSIX'. diff -r 000000000000 -r 1493bea5ac22 ed.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ed.c Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,2822 @@ +/* + * Editor + */ + +/* + * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003. + */ +/* from Unix 32V /usr/src/cmd/ed.c */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 +#define USED __attribute__ ((used)) +#elif defined __GNUC__ +#define USED __attribute__ ((unused)) +#else +#define USED +#endif +#if defined (SU3) +static const char sccsid[] USED = "@(#)ed_su3.sl 1.99 (gritter) 7/27/06"; +#elif defined (SUS) +static const char sccsid[] USED = "@(#)ed_sus.sl 1.99 (gritter) 7/27/06"; +#elif defined (S42) +static const char sccsid[] USED = "@(#)ed_s42.sl 1.99 (gritter) 7/27/06"; +#else /* !SU3, !SUS, !S42 */ +static const char sccsid[] USED = "@(#)ed.sl 1.99 (gritter) 7/27/06"; +#endif /* !SU3, !SUS, !S42 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sigset.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +static int FNSIZE; +static int LBSIZE; +static int RHSIZE; +#define ESIZE 2048 +static int GBSIZE; +#undef EOF +#define EOF -1 +#define puts(s) xxputs(s) +#define getline(t, n) xxgetline(t, n) + +#if (LONG_MAX > 017777777777L) +#define MAXCNT 0777777777777777777777L /* 2^63-1 */ +#else +#define MAXCNT 017777777777L /* 2^31-1 */ +#endif +#define BLKMSK (MAXCNT>>8) /* was 0377 */ + +#define READ 0 +#define WRITE 1 +#define EXIST 2 + +struct tabulator { + struct tabulator *t_nxt; /* next list element */ + const char *t_str; /* tabulator string */ + int t_tab; /* tab stop position */ + int t_rep; /* repetitive tab count */ +}; + +static int peekc; +static int lastc; +static char *savedfile; +static char *file; +static struct stat fstbuf; +static char *linebuf; +static char *rhsbuf; +static char expbuf[ESIZE + 4]; +static long *zero; +static long *undzero; +static long *dot; +static long *unddot; +static long *dol; +static long *unddol; +static long *addr1; +static long *addr2; +static char *genbuf; +static long count; +static char *linebp; +static int ninbuf; +static int io; +static int ioeof; +static int pflag; +static char *wrtemp; +static uid_t myuid; +static void (*oldhup)(int); +static void (*oldquit)(int); +static void (*oldpipe)(int); +static int vflag = 1; +static int listf; +static int numbf; +static char *globp; +static int tfile = -1; +static long tline; +static char tfname[64]; +static char ibuff[512]; +static int iblock = -1; +static char obuff[512]; +static int oblock = -1; +static int ichanged; +static int nleft; +static long *names; +static long *undnames; +static int anymarks; +static int subnewa; +static int fchange; +static int wrapp; +static unsigned nlall = 128; +static const char *progname; +static const char *prompt = "*"; +static int Pflag; +static int prhelp; +static const char *prvmsg; +static int lastsig; +static int pipid = -1; +static int readop; +static int status; +static int mb_cur_max; +static int needsub; +static int insub; +static struct tabulator *tabstops; +static int maxlength; +static int rspec; +static int Nflag; +static int bcount = 22; +static int ocount = 11; + +static jmp_buf savej; + +static void usage(char, int); +static void commands(void); +static long *address(void); +static void setdot(void); +static void setall(void); +static void setnoaddr(void); +static void nonzero(void); +static void newline(void); +static void filename(int); +static void exfile(void); +static void onintr(int); +static void onhup(int); +static void onpipe(int); +static void error(const char *); +static void error2(const char *, const char *); +static void errput(const char *, const char *); +static int getchr(void); +static int gettty(void); +static long getnum(void); +static int getfile(void); +static void putfile(void); +static int append(int (*)(void), long *); +static void callunix(void); +static char *readcmd(void); +static void quit(int); +static void delete(void); +static void rdelete(long *, long *); +static void gdelete(void); +static char *getline(long, int); +static int putline(void); +static char *getblock(long, long); +static void blkio(long, char *, int); +static void init(void); +static void global(int, int); +static void globrd(char **, int); +static void join(void); +static void substitute(int); +static int compsub(void); +static int getsub(void); +static int dosub(int); +static int place(int, const char *, const char *); +static void move(int); +static void reverse(long *, long *); +static int getcopy(void); +static int execute(int, long *, int); +static void cmplerr(int); +static void doprnt(long *, long *); +static void putd(long); +static void puts(const char *); +static void nlputs(const char *); +static void list(const char *); +static int lstchr(int); +static void putstr(const char *); +static void putchr(int); +static void checkpoint(void); +static void undo(void); +static int maketf(int); +static int creatf(const char *); +static int sopen(const char *, int); +static void sclose(int); +static void fspec(const char *); +static const char *ftok(const char **); +static struct tabulator *tabstring(const char *); +static void freetabs(void); +static void expand(const char *); +static void growlb(const char *); +static void growrhs(const char *); +static void growfn(const char *); +static void help(void); + +#define INIT +#define GETC() getchr() +#define UNGETC(c) (peekc = c) +#define PEEKC() (peekc = getchr()) +#define RETURN(c) return c +#define ERROR(c) cmplerr(c) +static wint_t GETWC(char *); + +#if defined (SUS) || defined (S42) || defined (SU3) + +#include + +#define NBRA 9 + +static char *braslist[NBRA]; +static char *braelist[NBRA]; +static char *loc1, *loc2, *locs; +static int nbra; +static int circf; +static int nodelim; + +static char *compile(char *, char *, const char *, int); +static int step(const char *, const char *); + +#else /* !SUS, !S42, !SU3 */ + +#include + +#endif /* !SUS, !S42, !SU3 */ + +int +main(int argc, char **argv) +{ + register int i; + void (*oldintr)(int); + + progname = basename(argv[0]); +#if defined (SUS) || defined (S42) || defined (SU3) + setlocale(LC_COLLATE, ""); +#endif + setlocale(LC_CTYPE, ""); + mb_cur_max = MB_CUR_MAX; + myuid = getuid(); + oldquit = sigset(SIGQUIT, SIG_IGN); + oldhup = sigset(SIGHUP, SIG_IGN); + oldintr = sigset(SIGINT, SIG_IGN); + if (sigset(SIGTERM, SIG_IGN) != SIG_IGN) + sigset(SIGTERM, quit); + oldpipe = sigset(SIGPIPE, onpipe); + argv++; + while (argc > 1 && **argv=='-') { + if ((*argv)[1] == '\0') { + vflag = 0; + goto next; + } else if ((*argv)[1] == '-' && (*argv)[2] == '\0') { + argv++; + argc--; + break; + } + letter: switch((*argv)[1]) { + + case 's': + vflag = 0; + break; + + case 'q': + sigset(SIGQUIT, SIG_DFL); + vflag = 1; + break; + + case 'p': + if ((*argv)[2]) + prompt = &(*argv)[2]; + else if (argv[1]) { + prompt = argv[1]; + argv++; + argc--; + } else + usage((*argv)[1], 1); + Pflag = 1; + goto next; + + default: + usage((*argv)[1], 0); + } + if ((*argv)[2]) { + (*argv)++; + goto letter; + } + next: argv++; + argc--; + } + + growfn("no space"); + if (argc>1) { + i = -1; + do + if (++i >= FNSIZE) + growfn("maximum of characters in " + "file names reached"); + while (savedfile[i] = (*argv)[i]); + globp = "e"; + } + names = malloc(26*sizeof *names); + undnames = malloc(26*sizeof *undnames); + zero = malloc(nlall*sizeof *zero); + if ((undzero = malloc(nlall*sizeof *undzero)) == NULL) + puts("no memory for undo"); + growlb("no space"); + growrhs("no space"); + init(); + if (oldintr != SIG_IGN) + sigset(SIGINT, onintr); + if (oldhup != SIG_IGN) + sigset(SIGHUP, onhup); + setjmp(savej); + if (lastsig) { + sigrelse(lastsig); + lastsig = 0; + } + commands(); + quit(0); + /*NOTREACHED*/ + return 0; +} + +static void +usage(char c, int misarg) +{ + if (c) { + write(2, progname, strlen(progname)); + if (misarg) + write(2, ": option requires an argument -- ", 33); + else + write(2, ": illegal option -- ", 20); + write(2, &c, 1); + write(2, "\n", 1); + } + write(2, "usage: ", 7); + write(2, progname, strlen(progname)); + write(2, " [- | -s] [-p string] [file]\n", 29); + exit(2); +} + +static void +commands(void) +{ + register long *a1; + register int c; + int n; + + for (;;) { + if (pflag) { + pflag = 0; + addr1 = addr2 = dot; + goto print; + } + if (Pflag && globp == NULL) + write(1, prompt, strlen(prompt)); + addr1 = 0; + addr2 = 0; + switch (c = getchr()) { + case ',': + case ';': + addr2 = c == ',' ? zero+1 : dot; + if (((peekc = getchr()) < '0' || peekc > '9') && + peekc != ' ' && peekc != '\t' && + peekc != '+' && peekc != '-' && + peekc != '^' && peekc != '?' && + peekc != '/' && peekc != '$' && + peekc != '.' && peekc != '\'') { + addr1 = addr2; + a1 = dol; + goto loop; + } + break; + default: + peekc = c; + } + do { + addr1 = addr2; + if ((a1 = address())==0) { + c = getchr(); + break; + } + loop: addr2 = a1; + if ((c=getchr()) == ';') { + c = ','; + dot = a1; + } + } while (c==','); + if (addr1==0) + addr1 = addr2; + switch(c) { + + case 'a': + setdot(); + newline(); + checkpoint(); + append(gettty, addr2); + continue; + + case 'c': +#if defined (SU3) + if (addr1 == zero && addr1+1 <= dol) { + if (addr1 == addr2) + addr2++; + addr1++; + } +#endif /* SU3 */ + delete(); + append(gettty, addr1-1); +#if defined (SUS) || defined (SU3) + if (dot == addr1-1 && addr1 <= dol) + dot = addr1; +#endif /* SUS || SU3 */ + continue; + + case 'd': + delete(); + continue; + + case 'E': + fchange = 0; + c = 'e'; + case 'e': + setnoaddr(); + if (vflag && fchange) { + fchange = 0; + error("warning: expecting `w'"); + } + filename(c); + init(); + addr2 = zero; + goto caseread; + + case 'f': + setnoaddr(); + filename(c); + puts(savedfile); + continue; + + case 'g': + global(1, 0); + continue; + + case 'G': + global(1, 1); + continue; + + case 'H': + prhelp = !prhelp; + /*FALLTHRU*/ + + case 'h': + if ((peekc = getchr()) == 'e') { + peekc = 0; + if (getchr() != 'l' || getchr() != 'p' || + getchr() != '\n') + error("illegal suffix"); + setnoaddr(); + help(); + continue; + } + newline(); + setnoaddr(); + if (prvmsg) + puts(prvmsg); + continue; + + case 'i': + setdot(); +#if defined (SU3) + if (addr1 == zero) { + if (addr1 == addr2) + addr2++; + addr1++; + if (dol != zero) + nonzero(); + } else +#endif /* SU3 */ + nonzero(); + newline(); + checkpoint(); + append(gettty, addr2-1); + if (dot == addr2-1) + dot++; + continue; + + + case 'j': + if (addr2==0) { + addr1 = dot; + addr2 = dot+1; + } + setdot(); + newline(); + nonzero(); + checkpoint(); + if (addr1 != addr2) + join(); + continue; + + case 'k': + if ((c = getchr()) < 'a' || c > 'z') + error("mark not lower case"); + newline(); + setdot(); + nonzero(); + names[c-'a'] = *addr2 & ~01; + anymarks |= 01; + continue; + + case 'm': + move(0); + continue; + + case '\n': + if (addr2==0) + addr2 = dot+1; + addr1 = addr2; + goto print; + + case 'n': + numbf = 1; + newline(); + goto print; + + case 'N': + newline(); + setnoaddr(); + Nflag = !Nflag; + continue; + + case 'b': + case 'o': + n = getnum(); + newline(); + setdot(); + nonzero(); + if (n >= 0) { + if (c == 'b') + bcount = n; + else + ocount = n; + } + if (c == 'b') { + a1 = addr2+bcount > dol ? dol : addr2 + bcount; + doprnt(addr1, a1); + dot = a1; + } else { + a1 = addr2+ocount > dol ? dol : addr2 + ocount; + doprnt(addr2-ocount wrtemp && tp[-1] != '/') + tp--; + for (cp = "\7XXXXXX"; *cp; cp++) + *tp++ = *cp; + *tp = '\0'; + if ((nio = mkstemp(wrtemp)) < 0) { + free(wrtemp); + wrtemp = NULL; + ftruncate(io, 0); + } else { + close(io); + io = nio; + } + } else { + if ((io = sopen(file, WRITE)) < 0) + error("cannot create output file"); + } + } + if (zero != dol) { + ioeof = 0; + wrapp = 0; + putfile(); + } + exfile(); + if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero) + fchange = 0; + if (c == 'z') + quit(0); + continue; + + case 'z': + if ((peekc=getchr()) != '\n') + error("illegal suffix"); + setnoaddr(); + goto write; + + case '=': + setall(); + newline(); + putd((addr2-zero)&MAXCNT); + putchr('\n'); + continue; + + case '!': + callunix(); + continue; + + case EOF: + return; + + } + error("unknown command"); + } +} + +static long * +address(void) +{ + register long *a1; + register int minus, c; + int n, relerr; + + minus = 0; + a1 = 0; + for (;;) { + c = getchr(); + if ('0'<=c && c<='9') { + n = 0; + do { + n *= 10; + n += c - '0'; + } while ((c = getchr())>='0' && c<='9'); + peekc = c; + if (a1==0) + a1 = zero; + if (minus<0) + n = -n; + a1 += n; + minus = 0; + continue; + } + relerr = 0; + if (a1 || minus) + relerr++; + switch(c) { + case ' ': + case '\t': + continue; + + case '+': + minus++; + if (a1==0) + a1 = dot; + continue; + + case '-': + case '^': + minus--; + if (a1==0) + a1 = dot; + continue; + + case '?': + case '/': + compile(NULL, expbuf, &expbuf[ESIZE], c); + a1 = dot; + for (;;) { + if (c=='/') { + a1++; + if (a1 > dol) + a1 = zero; + } else { + a1--; + if (a1 < zero) + a1 = dol; + } + if (execute(0, a1, 0)) + break; + if (a1==dot) + error("search string not found"); + } + break; + + case '$': + a1 = dol; + break; + + case '.': + a1 = dot; + break; + + case '\'': + if ((c = getchr()) < 'a' || c > 'z') + error("mark not lower case"); + for (a1=zero; a1<=dol; a1++) + if (names[c-'a'] == (*a1 & ~01)) + break; + break; + + default: + peekc = c; + if (a1==0) + return(0); + a1 += minus; + if (a1dol) + error("line out of range"); + return(a1); + } + if (relerr) + error("bad number"); + } +} + +static void +setdot(void) +{ + if (addr2 == 0) + addr1 = addr2 = dot; + if (addr1 > addr2) + error("bad range"); +} + +static void +setall(void) +{ + if (addr2==0) { + addr1 = zero+1; + addr2 = dol; + if (dol==zero) + addr1 = zero; + } + setdot(); +} + +static void +setnoaddr(void) +{ + if (addr2) + error("Illegal address count"); +} + +static void +nonzero(void) +{ + if (addr1<=zero || addr2>dol) + error("line out of range"); +} + +static void +newline(void) +{ + register int c; + + if ((c = getchr()) == '\n') + return; + if (c=='p' || c=='l' || c=='n') { + pflag++; + if (c=='l') + listf++; + else if (c=='n') + numbf = 1; + if (getchr() == '\n') + return; + } + error("illegal suffix"); +} + +static void +filename(int comm) +{ + register char *p1, *p2; + register int c, i; + + count = 0; + c = getchr(); + if (c=='\n' || c==EOF) { + p1 = savedfile; + if (*p1==0 && comm!='f') + error("illegal or missing filename"); + p2 = file; + while (*p2++ = *p1++) + ; + return; + } + if (c!=' ') + error("no space after command"); + while ((c = getchr()) == ' ') + ; + if (c=='\n') + error("illegal or missing filename"); + i = 0; + do { + if (i >= FNSIZE) + growfn("maximum of characters in file names reached"); + file[i++] = c; + if (c==' ' && file[0] != '!' || c==EOF) + error("illegal or missing filename"); + } while ((c = getchr()) != '\n'); + file[i++] = 0; + if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') { + p1 = savedfile; + p2 = file; + while (*p1++ = *p2++) + ; + } +} + +static void +exfile(void) +{ + sclose(io); + io = -1; + if (wrtemp) { + extern int rename(const char *, const char *); + if (rename(wrtemp, file) < 0) + error("cannot create output file"); + if (myuid == 0) + chown(file, fstbuf.st_uid, fstbuf.st_gid); + chmod(file, fstbuf.st_mode & 07777); + free(wrtemp); + wrtemp = NULL; + } + if (vflag) { + putd(count); + putchr('\n'); + } +} + +static void +onintr(int signo) +{ + lastsig = signo; + putchr('\n'); + lastc = '\n'; + if (readop) { + puts("\007read may be incomplete - beware!\007"); + fchange = 0; + } + error("interrupt"); +} + +static void +onhup(int signo) +{ + if (dol > zero && fchange) { + addr1 = zero+1; + addr2 = dol; + io = creat("ed.hup", 0666); + if (io < 0) { + char *home = getenv("HOME"); + if (home) { + char *fn = malloc(strlen(home) + 10); + if (fn) { + strcpy(fn, home); + strcat(fn, "/ed.hup"); + io = creat(fn, 0666); + } + } + } + if (io >= 0) + putfile(); + } + fchange = 0; + status = 0200 | signo; + quit(0); +} + +static void +onpipe(int signo) +{ + lastsig = signo; + error("write or open on pipe failed"); +} + +static void +error(const char *s) +{ + error2(s, NULL); +} + +static void +error2(const char *s, const char *fn) +{ + register int c; + + wrapp = 0; + listf = 0; + numbf = 0; + errput(s, fn); + count = 0; + if (lseek(0, 0, SEEK_END) > 0) + status = 2; + pflag = 0; + if (globp) + lastc = '\n'; + globp = 0; + peekc = lastc; + if(lastc) + while ((c = getchr()) != '\n' && c != EOF) + ; + if (io > 0) { + sclose(io); + io = -1; + } + if (wrtemp) { + unlink(wrtemp); + free(wrtemp); + wrtemp = NULL; + } + longjmp(savej, 1); +} + +static void +errput(const char *s, const char *fn) +{ + prvmsg = s; + if (fn) { + putchr('?'); + puts(fn); + } else + puts("?"); + if (prhelp) + puts(s); +} + +static int +getchr(void) +{ + char c; + if (lastc=peekc) { + peekc = 0; + return(lastc); + } + if (globp) { + if ((lastc = *globp++) != 0) + return(lastc); + globp = 0; + return(EOF); + } + if (read(0, &c, 1) <= 0) + return(lastc = EOF); + lastc = c; + return(lastc); +} + +static int +gettty(void) +{ + register int c, i; + register char *gf; + + i = 0; + gf = globp; + while ((c = getchr()) != '\n') { + if (c==EOF) { + if (gf) + peekc = c; + return(c); + } + if (c == 0) + continue; + if (i >= LBSIZE) + growlb("line too long"); + linebuf[i++] = c; + } + if (i >= LBSIZE-2) + growlb("line too long"); + linebuf[i++] = 0; + if (linebuf[0]=='.' && linebuf[1]==0) + return(EOF); +#if !defined (SUS) && !defined (SU3) + if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) + linebuf[0]='.', linebuf[1]=0; +#endif + return(0); +} + +static long +getnum(void) +{ + char scount[20]; + int i; + + i = 0; + while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) { + scount[i++] = peekc; + peekc = 0; + } + scount[i] = '\0'; + return i ? atol(scount) : -1; +} + +static int +getfile(void) +{ + register int c, i, j; + static int nextj; + + i = 0; + j = nextj; + do { + if (--ninbuf < 0) { + if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) { + if (ioeof == 0 && ninbuf < -1) { + puts("input error"); + status = 1; + } + if (i > 0) { + puts("'\\n' appended"); + c = '\n'; + ioeof = 1; + goto wrc; + } + return(EOF); + } + j = 0; + } + c = genbuf[j++]&0377; + wrc: if (i >= LBSIZE) { + lastc = '\n'; + growlb("line too long"); + } + linebuf[i++] = c ? c : '\n'; + count++; + } while (c != '\n'); + linebuf[--i] = 0; + nextj = j; + if (rspec && dot == zero) + fspec(linebuf); + if (maxlength && i > maxlength) { + putstr("line too long: lno = "); + putd((dot - zero+1)&MAXCNT); + putchr('\n'); + } + return(0); +} + +static void +putfile(void) +{ + long *a1; + int n; + register char *fp, *lp; + register int nib; + + nib = 512; + fp = genbuf; + a1 = addr1; + do { + lp = getline(*a1++, 0); + if (maxlength) { + for (n = 0; lp[n]; n++); + if (n > maxlength) { + putstr("line too long: lno = "); + putd((a1-1 - zero)&MAXCNT); + putchr('\n'); + } + } + for (;;) { + if (--nib < 0) { + n = fp-genbuf; + if(write(io, genbuf, n) != n) + error("write error"); + nib = 511; + fp = genbuf; + } + count++; + if ((*fp++ = *lp++) == 0) { + fp[-1] = '\n'; + break; + } else if (fp[-1] == '\n') + fp[-1] = '\0'; + } + } while (a1 <= addr2); + n = fp-genbuf; + if(write(io, genbuf, n) != n) + error("write error"); +} + +static int +append(int (*f)(void), long *a) +{ + register long *a1, *a2, *rdot; + int nline, tl; + + nline = 0; + dot = a; + while ((*f)() == 0) { + if ((dol-zero)+1 >= nlall) { + long *ozero = zero; + nlall += 512; + if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) { + lastc = '\n'; + zero = ozero; + error("out of memory for append"); + } + dot += zero - ozero; + dol += zero - ozero; + addr1 += zero - ozero; + addr2 += zero - ozero; + if (unddot) { + unddot += zero - ozero; + unddol += zero - ozero; + } + if (undzero) { + ozero = undzero; + if ((undzero = realloc(undzero, + nlall*sizeof *undzero)) == 0) { + puts("no memory for undo"); + free(ozero); + } + } + } + tl = putline(); + nline++; + a1 = ++dol; + a2 = a1+1; + rdot = ++dot; + while (a1 > rdot) + *--a2 = *--a1; + *rdot = tl; + } + return(nline); +} + +static void +callunix(void) +{ + char *line; + void (*savint)(int); + pid_t pid, rpid; + int retcode; + + setnoaddr(); + line = readcmd(); + if ((pid = fork()) == 0) { + sigset(SIGHUP, oldhup); + sigset(SIGQUIT, oldquit); + sigset(SIGPIPE, oldpipe); + execl(SHELL, "sh", "-c", line, NULL); + _exit(0100); + } else if (pid < 0) + error("fork failed - try again"); + savint = sigset(SIGINT, SIG_IGN); + while ((rpid = wait(&retcode)) != pid && rpid != -1) + ; + sigset(SIGINT, savint); + if (vflag) + puts("!"); +} + +#define cmadd(c) ((i>=cmsize ? \ + ((line=realloc(line,cmsize+=128)) == 0 ? \ + (error("line too long"),0) : 0, 0) \ + : 0), line[i++]=(c)) + +static char * +readcmd(void) +{ + static char *line, *prev; + static int cmsize, pvsize; + char *pp; + int c, mod = 0, i; + + i = 0; + if ((c = getchr()) == '!') { + for (pp = prev; *pp; pp++) + line[i++] = *pp; + mod = 1; + c = getchr(); + } + while (c != '\n' && c != EOF) { + if (c == '\\') { + c = getchr(); + if (c != '%') + cmadd('\\'); + cmadd(c); + } else if (c == '%') { + for (pp = savedfile; *pp; pp++) + cmadd(*pp); + mod = 1; + } else + cmadd(c); + c = getchr(); + } + cmadd('\0'); + if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0) + error("line too long"); + strcpy(prev, line); + if (mod) + nlputs(line); + return line; +} + +static void +quit(int signo) +{ + lastsig = signo; + if (vflag && fchange) { + fchange = 0; + error("warning: expecting `w'"); + } + if (wrtemp) + unlink(wrtemp); + unlink(tfname); + exit(status); +} + +static void +delete(void) +{ + setdot(); + newline(); + nonzero(); + checkpoint(); + rdelete(addr1, addr2); +} + +static void +rdelete(long *ad1, long *ad2) +{ + register long *a1, *a2, *a3; + + a1 = ad1; + a2 = ad2+1; + a3 = dol; + dol -= a2 - a1; + do { + *a1++ = *a2++; + } while (a2 <= a3); + a1 = ad1; + if (a1 > dol) + a1 = dol; + dot = a1; + fchange = 1; +} + +static void +gdelete(void) +{ + register long *a1, *a2, *a3; + + a3 = dol; + for (a1=zero+1; (*a1&01)==0; a1++) + if (a1>=a3) + return; + for (a2=a1+1; a2<=a3;) { + if (*a2&01) { + a2++; + dot = a1; + } else + *a1++ = *a2++; + } + dol = a1-1; + if (dot>dol) + dot = dol; + fchange = 1; +} + +static char * +getline(long tl, int nulterm) +{ + register char *bp, *lp; + register long nl; + + lp = linebuf; + bp = getblock(tl, READ); + nl = nleft; + tl &= ~0377; + while (*lp++ = *bp++) { + if (lp[-1] == '\n' && nulterm) { + lp[-1] = '\0'; + break; + } + if (--nl == 0) { + bp = getblock(tl+=0400, READ); + nl = nleft; + } + } + return(linebuf); +} + +static int +putline(void) +{ + register char *bp, *lp; + register long nl; + long tl; + + fchange = 1; + lp = linebuf; + tl = tline; + bp = getblock(tl, WRITE); + nl = nleft; + tl &= ~0377; + while (*bp = *lp++) { + if (*bp++ == '\n' && insub) { + *--bp = 0; + linebp = lp; + break; + } + if (--nl == 0) { + bp = getblock(tl+=0400, WRITE); + nl = nleft; + } + } + nl = tline; + tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1); + return(nl); +} + +static char * +getblock(long atl, long iof) +{ + register long bno, off; + + bno = (atl>>8)&BLKMSK; + off = (atl<<1)&0774; + if (bno >= BLKMSK) { + lastc = '\n'; + error("temp file too big"); + } + nleft = 512 - off; + if (bno==iblock) { + ichanged |= iof; + return(ibuff+off); + } + if (bno==oblock) + return(obuff+off); + if (iof==READ) { + if (ichanged) + blkio(iblock, ibuff, 1); + ichanged = 0; + iblock = bno; + blkio(bno, ibuff, 0); + return(ibuff+off); + } + if (oblock>=0) + blkio(oblock, obuff, 1); + oblock = bno; + return(obuff+off); +} + +static void +blkio(long b, char *buf, int wr) +{ + lseek(tfile, b<<9, SEEK_SET); + if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) { + status = 1; + error("I/O error on temp file"); + } +} + +static void +init(void) +{ + register long *markp; + + tline = 2; + for (markp = names; markp < &names[26]; markp++) + *markp = 0; + for (markp = undnames; markp < &undnames[26]; markp++) + *markp = 0; + subnewa = 0; + anymarks = 0; + iblock = -1; + oblock = -1; + ichanged = 0; + tfile = maketf(tfile); + dot = dol = zero; + unddot = NULL; +} + +static void +global(int k, int ia) +{ + register int c; + register long *a1; + static char *globuf; + char mb[MB_LEN_MAX+1]; + int spflag = 0; + + if (globp) + error("multiple globals not allowed"); + setall(); + nonzero(); + if ((c=GETWC(mb))=='\n') + error("incomplete global expression"); + compile(NULL, expbuf, &expbuf[ESIZE], c); + if (!ia) { + globrd(&globuf, EOF); + if (globuf[0] == '\n') + globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0'; + } else { + newline(); + spflag = pflag; + pflag = 0; + } + checkpoint(); + for (a1=zero; a1<=dol; a1++) { + *a1 &= ~01; + if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k) + *a1 |= 01; + } + /* + * Special case: g/.../d (avoid n^2 algorithm) + */ + if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') { + gdelete(); + return; + } + for (a1=zero; a1<=dol; a1++) { + if (*a1 & 01) { + *a1 &= ~01; + dot = a1; + if (ia) { + puts(getline(*a1, 0)); + if ((c = getchr()) == EOF) + error("command expected"); + if (c == 'a' || c == 'c' || c == 'i') + error("a, i, or c not allowed in G"); + else if (c == '&') { + if ((c = getchr()) != '\n') + error("end of line expected"); + if (globuf == 0 || *globuf == 0) + error("no remembered command"); + } else if (c == '\n') { + a1 = zero; + continue; + } else + globrd(&globuf, c); + } + globp = globuf; + commands(); + globp = NULL; + a1 = zero; + } + } + if (ia) + pflag = spflag; +} + +static void +globrd(char **globuf, register int c) +{ + register int i; + + if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0) + error("global too long"); + i = 0; + if (c != EOF) + (*globuf)[i++] = c; + while ((c = getchr()) != '\n') { + if (c==EOF) + error("incomplete global expression"); + if (c=='\\') { + c = getchr(); + if (c!='\n') + (*globuf)[i++] = '\\'; + } + (*globuf)[i++] = c; + if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0) + error("global too long"); + } + (*globuf)[i++] = '\n'; + (*globuf)[i++] = 0; +} + +static void +join(void) +{ + register int i, j; + register long *a1; + + j = 0; + for (a1=addr1; a1<=addr2; a1++) { + i = getline(*a1, 0) - linebuf; + while (genbuf[j] = linebuf[i++]) + if (j++ >= LBSIZE-2) + growlb("line too long"); + } + i = 0; + j = 0; + while (linebuf[i++] = genbuf[j++]) + ; + *addr1 = putline(); + if (addr1= RHSIZE-2) + growrhs("replacement string too long"); + rhsbuf[i++] = c; + c = GETWC(mb); + } else if (c=='\n') { + if (globp && *globp) { + if (i >= RHSIZE-2) + growrhs("replacement string too long"); + rhsbuf[i++] = '\\'; + } + else if (nodelim) + error("illegal or missing delimiter"); + else { + peekc = c; + pflag++; + break; + } + } else if (c==seof) + break; + for (c = 0; c==0 || mb[c]; c++) { + if (i >= RHSIZE-2) + growrhs("replacement string too long"); + rhsbuf[i++] = mb[c]; + } + } + rhsbuf[i++] = 0; + if (rhsbuf[0] == '%' && rhsbuf[1] == 0) { + if (orhssz == 0) + error("no remembered replacement string"); + strcpy(rhsbuf, oldrhs); + } else { + if (orhssz < RHSIZE && + (oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0) + error("replacement string too long"); + strcpy(oldrhs, rhsbuf); + } + if ((peekc = getchr()) == 'g') { + peekc = 0; + newline(); + return(-1); + } else if (peekc >= '0' && peekc <= '9') { + c = getnum(); + if (c < 1 || c > LBSIZE) + error("invalid count"); + newline(); + return c; + } + newline(); + return(0); +} + +static int +getsub(void) +{ + register char *p1, *p2; + + p1 = linebuf; + if ((p2 = linebp) == 0) + return(EOF); + while (*p1++ = *p2++) + ; + linebp = 0; + return(0); +} + +static int +dosub(int really) +{ + register char *lp, *sp; + register int i, j, k; + int c; + + if (!really) + goto copy; + i = 0; + j = 0; + k = 0; + while (&linebuf[i] < loc1) + genbuf[j++] = linebuf[i++]; + while (c = rhsbuf[k++]&0377) { + if (c=='&') { + j = place(j, loc1, loc2); + continue; + } else if (c == '\\') { + c = rhsbuf[k++]&0377; + if (c >='1' && c < nbra+'1') { + j = place(j, braslist[c-'1'], braelist[c-'1']); + continue; + } + } + if (j >= LBSIZE) + growlb("line too long"); + genbuf[j++] = c; + } + i = loc2 - linebuf; + loc2 = j + linebuf; +#if defined (SUS) || defined (SU3) || defined (S42) + if (loc1 == &linebuf[i]) { + int n; + wchar_t wc; + if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0) + loc2 += n; + else + loc2++; + } +#endif /* SUS || SU3 || S42 */ + while (genbuf[j++] = linebuf[i++]) + if (j >= LBSIZE) + growlb("line too long"); + if (really) { + lp = linebuf; + sp = genbuf; + } else { + copy: sp = linebuf; + lp = genbuf; + } + while (*lp++ = *sp++) + ; + return really; +} + +static int +place(register int j, register const char *l1, register const char *l2) +{ + + while (l1 < l2) { + genbuf[j++] = *l1++; + if (j >= LBSIZE) + growlb("line too long"); + } + return(j); +} + +static void +move(int cflag) +{ + register long *adt, *ad1, *ad2; + + setdot(); + nonzero(); + if ((adt = address())==0) + error("illegal move destination"); + newline(); + checkpoint(); + if (cflag) { + long *ozero; + intptr_t delta; + ad1 = dol; + ozero = zero; + append(getcopy, ad1++); + ad2 = dol; + delta = zero - ozero; + ad1 += delta; + adt += delta; + } else { + ad2 = addr2; + for (ad1 = addr1; ad1 <= ad2;) + *ad1++ &= ~01; + ad1 = addr1; + } + ad2++; + if (adt= ad2) { + dot = adt++; + reverse(ad1, ad2); + reverse(ad2, adt); + reverse(ad1, adt); + } else + error("illegal move destination"); + fchange = 1; +} + +static void +reverse(register long *a1, register long *a2) +{ + register int t; + + for (;;) { + t = *--a2; + if (a2 <= a1) + return; + *a2 = *a1; + *a1++ = t; + } +} + +static int +getcopy(void) +{ + if (addr1 > addr2) + return(EOF); + getline(*addr1++, 0); + return(0); +} + +static int +execute(int gf, long *addr, int subst) +{ + register char *p1, *p2, c; + + for (c=0; c 1 && *lp&0200) + n = mbtowc(&c, lp, mb_cur_max); + else { + n = 1; + c = *lp&0377; + } + if (col+1 >= 72) { + col = 0; + putchr('\\'); + putchr('\n'); + } + if (n<0 || +#if defined (SUS) || defined (S42) || defined (SU3) + c == '\\' || +#endif /* SUS || S42 || SU3 */ + !(mb_cur_max>1 ? iswprint(c) : isprint(c))) { + if (n<0) + n = 1; + while (n--) + col += lstchr(*lp++&0377); + } else if (mb_cur_max>1) { + col += wcwidth(c); + while (n--) + putchr(*lp++&0377); + } else { + putchr(*lp++&0377); + col++; + } + } +#if defined (SUS) || defined (S42) || defined (SU3) + putchr('$'); +#endif + putchr('\n'); +} + +static int +lstchr(int c) +{ + int cad = 1, d; + +#if !defined (SUS) && !defined (S42) && !defined (SU3) + if (c=='\t') { + c = '>'; + goto esc; + } + if (c=='\b') { + c = '<'; + esc: + putchr('-'); + putchr('\b'); + putchr(c); + } else if (c == '\n') { + putchr('\\'); + putchr('0'); + putchr('0'); + putchr('0'); + cad = 4; +#else /* !SUS, !S42, !SU3 */ + if (c == '\n') + c = '\0'; + if (c == '\\') { + putchr('\\'); + putchr('\\'); + cad = 2; + } else if (c == '\a') { + putchr('\\'); + putchr('a'); + cad = 2; + } else if (c == '\b') { + putchr('\\'); + putchr('b'); + cad = 2; + } else if (c == '\f') { + putchr('\\'); + putchr('f'); + cad = 2; + } else if (c == '\r') { + putchr('\\'); + putchr('r'); + cad = 2; + } else if (c == '\t') { + putchr('\\'); + putchr('t'); + cad = 2; + } else if (c == '\v') { + putchr('\\'); + putchr('v'); + cad = 2; +#endif /* !SUS, !S42, !SU3 */ + } else { + putchr('\\'); + putchr(((c&~077)>>6)+'0'); + c &= 077; + d = c & 07; + putchr(c > d ? ((c-d)>>3)+'0' : '0'); + putchr(d+'0'); + cad = 4; + } + return cad; +} + +static void +putstr(const char *s) +{ + while (*s) + putchr(*s++); +} + +static char line[70]; +static char *linp = line; + +static void +putchr(int ac) +{ + register char *lp; + register int c; + + lp = linp; + c = ac; + *lp++ = c; + if(c == '\n' || lp >= &line[64]) { + linp = line; + write(1, line, lp-line); + return; + } + linp = lp; +} + +static void +checkpoint(void) +{ + long *a1, *a2; + + if (undzero && globp == NULL) { + for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++) + *a2 = *a1; + unddot = &undzero[dot-zero]; + unddol = &undzero[dol-zero]; + for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++) + *a2 = *a1; + } +} + +#define swap(a, b) (t = a, a = b, b = t) + +static void +undo(void) +{ + long *t; + + if (undzero == NULL) + error("no undo information saved"); + swap(zero, undzero); + swap(dot, unddot); + swap(dol, unddol); + swap(names, undnames); +} + +static int +maketf(int fd) +{ + char *tmpdir; + + if (fd == -1) { + if ((tmpdir = getenv("TMPDIR")) == NULL || + (fd = creatf(tmpdir)) < 0) + if ((fd = creatf("/var/tmp")) < 0 && + (fd = creatf("/tmp")) < 0) + error("cannot create temporary file"); + } else + ftruncate(fd, 0); /* blkio() will seek to 0 anyway */ + return fd; +} + +static int +creatf(const char *tmpdir) +{ + if (strlen(tmpdir) >= sizeof tfname - 9) + return -1; + strcpy(tfname, tmpdir); + strcat(tfname, "/eXXXXXX"); + return mkstemp(tfname); +} + +static int +sopen(const char *fn, int rdwr) +{ + int pf[2], fd = -1; + + if (fn[0] == '!') { + fn++; + if (pipe(pf) < 0) + error("write or open on pipe failed"); + switch (pipid = fork()) { + case 0: + if (rdwr == READ) + dup2(pf[1], 1); + else + dup2(pf[0], 0); + close(pf[0]); + close(pf[1]); + sigset(SIGHUP, oldhup); + sigset(SIGQUIT, oldquit); + sigset(SIGPIPE, oldpipe); + execl(SHELL, "sh", "-c", fn, NULL); + _exit(0100); + default: + close(pf[rdwr == READ ? 1 : 0]); + fd = pf[rdwr == READ ? 0 : 1]; + break; + case -1: + error("fork failed - try again"); + } + } else if (rdwr == READ) + fd = open(fn, O_RDONLY); + else if (rdwr == EXIST) + fd = open(fn, O_WRONLY); + else /*if (rdwr == WRITE)*/ + fd = creat(fn, 0666); + if (fd >= 0 && rdwr == READ) + readop = 1; + if (fd >= 0) + fstat(fd, &fstbuf); + return fd; +} + +static void +sclose(int fd) +{ + int status; + + close(fd); + if (pipid >= 0) { + while (wait(&status) != pipid); + pipid = -1; + } + readop = 0; +} + +static void +fspec(const char *lp) +{ + struct termios ts; + const char *cp; + + freetabs(); + maxlength = 0; + if (tcgetattr(1, &ts) < 0 +#ifdef TAB3 + || (ts.c_oflag&TAB3) == 0 +#endif + ) + return; + while (lp[0]) { + if (lp[0] == '<' && lp[1] == ':') + break; + lp++; + } + if (lp[0]) { + lp += 2; + while ((cp = ftok(&lp)) != NULL) { + switch (*cp) { + case 't': + freetabs(); + if ((tabstops = tabstring(&cp[1])) == NULL) + goto err; + break; + case 's': + maxlength = atoi(&cp[1]); + break; + case 'm': + case 'd': + case 'e': + break; + case ':': + if (cp[1] == '>') { + if (tabstops == NULL) + if ((tabstops = tabstring("0")) + == NULL) + goto err; + return; + } + /*FALLTHRU*/ + default: + err: freetabs(); + maxlength = 0; + errput("PWB spec problem", NULL); + return; + } + } + } +} + +static const char * +ftok(const char **lp) +{ + const char *cp; + + while (**lp && **lp != ':' && (**lp == ' ' || **lp == '\t')) + (*lp)++; + cp = *lp; + while (**lp && **lp != ':' && **lp != ' ' && **lp != '\t') + (*lp)++; + return cp; +} + +static struct tabulator * +repetitive(int repetition) +{ + struct tabulator *tp, *tabspec; + int col, i; + + if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) + return NULL; + tp->t_rep = repetition; + if (repetition > 0) { + for (col = 1+repetition, i = 0; i < 22; col += repetition) { + if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) + return NULL; + tp = tp->t_nxt; + tp->t_tab = col; + } + } + return tabspec; +} + +#define blank(c) ((c) == ' ' || (c) == '\t') + +static struct tabulator * +tablist(const char *s) +{ + struct tabulator *tp, *tabspec; + char *x; + int prev = 0, val; + + if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) + return NULL; + for (;;) { + while (*s == ',') + s++; + if (*s == '\0' || blank(*s) || *s == ':') + break; + val = strtol(s, &x, 10); + if (*s == '+') + val += prev; + prev = val; + if (*s == '-' || (*x != ',' && !blank(*x) && *x != ':' && + *x != '\0')) + return NULL; + s = x; + if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) + return NULL; + tp = tp->t_nxt; + tp->t_tab = val; + } + return tabspec; +} + +static struct tabulator * +tabstring(const char *s) +{ + const struct { + const char *c_nam; + const char *c_str; + } canned[] = { + { "a", "1,10,16,36,72" }, + { "a2", "1,10,16,40,72" }, + { "c", "1,8,12,16,20,55" }, + { "c2", "1,6,10,14,49" }, + { "c3", "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67" }, + { "f", "1,7,11,15,19,23" }, + { "p", "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61" }, + { "s", "1,10,55" }, + { "u", "1,12,20,44" }, + { 0, 0 } + }; + + int i, j; + + if (s[0] == '-') { + if (s[1] >= '0' && s[1] <= '9' && ((i = atoi(&s[1])) != 0)) + return repetitive(i); + for (i = 0; canned[i].c_nam; i++) { + for (j = 0; canned[i].c_nam[j]; j++) + if (s[j+1] != canned[i].c_nam[j]) + break; + if ((s[j+1]=='\0' || s[j+1]==':' || blank(s[j+1])) && + canned[i].c_nam[j] == '\0') + return tablist(canned[i].c_str); + } + return NULL; + } else + return tablist(s); +} + +static void +freetabs(void) +{ + struct tabulator *tp; + + tp = tabstops; + while (tp) { + tabstops = tp->t_nxt; + free(tp); + tp = tabstops; + } +} + +static void +expand(const char *s) +{ + struct tabulator *tp = tabstops; + int col = 0, n = 1, m, tabcnt = 0, nspc; + wchar_t wc; + + while (*s) { + nspc = 0; + switch (*s) { + case '\n': + putchr('\0'); + s++; + continue; + case '\t': + if (tp) { + if (tp->t_rep) { + if (col % tp->t_rep == 0) { + nspc++; + col++; + } + while (col % tp->t_rep) { + nspc++; + col++; + } + break; + } + while (tp && (col>tp->t_tab || tp->t_tab == 0)) + tp = tp->t_nxt; + if (tp && col == tp->t_tab) { + nspc++; + col++; + tp = tp->t_nxt; + } + if (tp) { + while (col < tp->t_tab) { + nspc++; + col++; + } + tp = tp->t_nxt; + break; + } + } + tabcnt = 1; + nspc++; + break; + default: + if (mb_cur_max>1 && (n=mbtowc(&wc, s, mb_cur_max))>0) { + if ((m = wcwidth(wc)) > 0) + col += m; + } else { + col++; + n = 1; + } + } + if (maxlength && col > maxlength) { + putstr("\ntoo long"); + break; + } + if (nspc) { + while (nspc--) + putchr(' '); + s++; + } else + while (n--) + putchr(*s++); + } + if (tabcnt) + putstr("\ntab count"); + putchr('\n'); +} + +static wint_t +GETWC(char *mb) +{ + int c, n; + + n = 1; + mb[0] = c = GETC(); + mb[1] = '\0'; + if (mb_cur_max > 1 && c&0200 && c != EOF) { + int m; + wchar_t wc; + + while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \ + genbuf[i++] = (c)) + +#define copy(s) { \ + int m; \ + for (m = 0; m==0 || s[m]; m++) \ + add(s[m]); \ +} + +static char * +compile(char *unused, char *ep, const char *endbuf, int seof) +{ + INIT + int c, d, i; + regex_t *rp; + char *op; + char mb[MB_LEN_MAX+1]; + + op = ep; + ep += 2; + if ((rp = fetchptr(ep)) == NULL) { + if ((rp = calloc(1, sizeof *rp)) == NULL) + ERROR(50); + storeptr(rp, ep); + } + ep += sizeof (void *); + i = 0; + nbra = 0; + do { + if ((c = GETWC(mb)) == seof) + add('\0'); + else if (c == '\\') { + copy(mb); + c = GETWC(mb); + if (c == '(') + nbra++; + goto normchar; + } else if (c == '[') { + add(c); + d = EOF; + do { + c = GETWC(mb); + if (c == EOF || c == '\n') + ERROR(49); + copy(mb); + if (d=='[' && (c==':' || c=='.' || c=='=')) { + d = c; + do { + c = GETWC(mb); + if (c == EOF || c == '\n') + ERROR(49); + copy(mb); + } while (c != d || PEEKC() != ']'); + c = GETWC(mb); + copy(mb); + c = EOF; + } + d = c; + } while (c != ']'); + } else { + if (c == EOF || c == '\n') { + if (c == '\n') + UNGETC(c); + mb[0] = c = '\0'; + } + if (c == '\0') + nodelim = 1; + normchar: copy(mb); + } + } while (genbuf[i-1] != '\0'); + if (genbuf[0]) { + int reflags = 0; + +#ifdef REG_ANGLES + reflags |= REG_ANGLES; +#endif +#if defined (SU3) && defined (REG_AVOIDNULL) + reflags |= REG_AVOIDNULL; +#endif + if (op[0]) + regfree(rp); + op[0] = 0; + switch (regcomp(rp, genbuf, reflags)) { + case 0: + break; + case REG_ESUBREG: + ERROR(25); + /*NOTREACHED*/ + case REG_EBRACK: + ERROR(49); + /*NOTREACHED*/ + case REG_EPAREN: + ERROR(42); + /*NOTREACHED*/ + case REG_BADBR: + case REG_EBRACE: + ERROR(45); + /*NOTREACHED*/ + case REG_ERANGE: + ERROR(11); + /*NOTREACHED*/ + case REG_ESPACE: + ERROR(50); + /*NOTREACHED*/ + default: + ERROR(-1); + } + op[0] = 1; + circf = op[1] = genbuf[0] == '^'; + } else if (op[0]) { + circf = op[1]; + } else + ERROR(41); + return ep + sizeof (void *); +} + +static int +step(const char *lp, const char *ep) +{ + regex_t *rp; + regmatch_t bralist[NBRA+1]; + int eflag = 0; + int res; + int i; + + rp = fetchptr(&ep[2]); + if (ep[0] == 0) + return 0; + if (locs) + eflag |= REG_NOTBOL; + if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 && + needsub) { + loc1 = (char *)lp + bralist[0].rm_so; + loc2 = (char *)lp + bralist[0].rm_eo; + for (i = 1; i <= NBRA; i++) { + if (bralist[i].rm_so != -1) { + braslist[i-1] = (char *)lp + bralist[i].rm_so; + braelist[i-1] = (char *)lp + bralist[i].rm_eo; + } else + braslist[i-1] = braelist[i-1] = NULL; + } + } + return res == 0; +} +#endif /* SUS || S42 || SU3 */ + +static void +help(void) +{ + const char *desc[] = { + "(.)a append up to .", + "(.)b[n] browse n lines", + "(.,.)c change up to .", + "(.,.)d delete lines", + "e [file] edit file", + "E [file] force edit", + "f [file] print or set file", + "(1,$)g/RE/cmd global cmd", + "(1,$)G/RE/ interactive global", + "h print last error", + "H toggle error messages", + "help print this screen", + "(.)i insert up to .", + "(.,.+1)j join lines", + "(.)kx mark line with x", + "(.,.)l list lines", + "(.,.)ma move lines to a", + "(.,.)n number lines", + "N revert n and p", + "(.)o[n] show n lines of context", + "(.,.)p print lines", + "P toggle prompt", + "q quit", + "Q force quit", + "($)r read file", + "(.,.)s/RE/repl/ search and replace", + "(.,.)s/RE/rp/g replace all occurrences", + "(.,.)s/RE/rp/n replace n-th occurrence", + "(.,.)ta transfer lines to a", + "u undo last change", + "(1,$)v/RE/cmd reverse global", + "(1,$)V/RE/ reverse i/a global", + "(1,$)w [file] write file", + "(1,$)W [file] append to file", + "z write buffer and quit", + "($)= print line number", + "!command execute shell command", + "(.+1) print one line", + "/RE find RE forwards", + "?RE find RE backwards", + "1 first line", + ". current line", + "$ last line", + ", 1,$", + "; .,$", + NULL + }; + char line[100]; + int c, half, i, k; + + half = (sizeof desc / sizeof *desc) / 2; + for (i = 0; i < half && desc[i]; i++) { + c = 0; + for (k = 0; desc[i][k]; k++) + line[c++] = desc[i][k]; + if (desc[i+half]) { + while (c < 40) + line[c++] = ' '; + for (k = 0; desc[i+half][k]; k++) + line[c++] = desc[i+half][k]; + } + line[c] = 0; + puts(line); + } +} diff -r 000000000000 -r 1493bea5ac22 makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/makefile Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,121 @@ +# +# Root directory. Mainly useful for package building; leave empty for +# normal installation. +# +ROOT = + +PREFIX = /usr/local + +# +# Location for binaries. +# +BINDIR = $(PREFIX)/bin + +# +# Location for manual pages (with man1, man1b ... man8 below). +# +MANDIR = $(PREFIX)/share/man + +# +# Compiler and linker flags. +# + +#CC = $(HOME)/src/diet gcc +CC = cc + +LD = $(CC) +#LDFLAGS = --static +LDFLAGS = + +# +# Flags for the C preprocessor. +# On Linux with glibc or uClibc, add -D_GNU_SOURCE. +# On Solaris, -D__EXTENSIONS__ should be added. +# On HP-UX, -D_INCLUDE__STDC_A1_SOURCE must be added. +# On AIX, -D_TPARM_COMPAT must be added. +# On AIX, -D_MTEXTEND_H should be added if mtextend.h is not found. +# On NetBSD, add -DUSE_TERMCAP. +# +CPPFLAGS = -D_GNU_SOURCE + +# +# CFLAGS makes it possible to give special +# compiler flags for objects where speed is critical. There is no other +# purpose with this so setting all to -O will work too. +# +WARN = +CFLAGS = -O -fomit-frame-pointer $(WARN) + + +# +# Whether to use the supplied widechar emulation library. This should +# only be enabled if the system lacks appropriate widechar support. +# It is currently needed on +# - Linux/diet libc +# - FreeBSD 4 +# - NetBSD 1.x, because it lacks wctype_t/wctrans_t etc. in wctype.h. +# - OpenBSD +# +#IWCHAR = -I../libwchar +#LWCHAR = -L../libwchar -lwchar + + +# +# Binaries are stripped with this command after installation. +# +STRIP = strip -s -R .comment -R .note + +# +# This is the shell used for the compilation phase, the execution of most +# installed scripts, and the shell escapes in the traditional command +# versions. It needs not conform to POSIX. The system shell should work +# fine; for maximum compatibility with traditional tools, the Heirloom +# Bourne shell is recommended. It then must obviously be compiled and +# installed first. +# +SHELL = /bin/sh + +# +# Don't change the rest of this file unless you really know what you are +# doing. +# + +######################################################################## +######################################################################## +######################################################################## +######################################################################## +######################################################################## + +all: ed + +ed: ed.o regexpr.o sigset.o sigrelse.o + $(LD) $(LDFLAGS) ed.o -o ed + +ed.o: ed.c regexp.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(IWCHAR) -DSHELL='"$(SHELL)"' -I. -c ed.c + +regexpr.o: regexpr.c regexpr.h regexp.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(IWCHAR) -I. -c regexpr.c + +sigset.o: sigset.c sigset.h + $(CC) $(CFLAGS) $(CPPFLAGS) -I. -c sigset.c + +sigrelse.o: sigrelse.c sigset.h + $(CC) $(CFLAGS) $(CPPFLAGS) -I. -c sigrelse.c + + +install: all + mkdir -p $(ROOT)$(BINDIR) + cp ed $(ROOT)$(BINDIR)/ed + chmod 755 $(ROOT)$(BINDIR)/ed + $(STRIP) $(ROOT)$(BINDIR)/ed + mkdir -p $(ROOT)$(MANDIR)/man1 + cp ed.1 $(ROOT)$(MANDIR)/man1/ed.1 + chmod 644 $(ROOT)$(MANDIR)/man1/ed.1 + +clean: + rm -f ed.o regexpr.o sigset.o sigrelse.o core log *~ + +mrproper: clean + rm -f ed + diff -r 000000000000 -r 1493bea5ac22 regexp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regexp.h Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,1211 @@ +/* + * Simple Regular Expression functions. Derived from Unix 7th Edition, + * /usr/src/cmd/expr.y + * + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, February 2002. + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 +#define REGEXP_H_USED __attribute__ ((used)) +#elif defined __GNUC__ +#define REGEXP_H_USED __attribute__ ((unused)) +#else +#define REGEXP_H_USED +#endif +static const char regexp_h_sccsid[] REGEXP_H_USED = + "@(#)regexp.sl 1.56 (gritter) 5/29/05"; + +#if !defined (REGEXP_H_USED_FROM_VI) && !defined (__dietlibc__) +#define REGEXP_H_WCHARS +#endif + +#define CBRA 2 +#define CCHR 4 +#define CDOT 8 +#define CCL 12 +/* CLNUM 14 used in sed */ +/* CEND 16 used in sed */ +#define CDOL 20 +#define CCEOF 22 +#define CKET 24 +#define CBACK 36 +#define CNCL 40 +#define CBRC 44 +#define CLET 48 +#define CCH1 52 +#define CCH2 56 +#define CCH3 60 + +#define STAR 01 +#define RNGE 03 +#define REGEXP_H_LEAST 0100 + +#ifdef REGEXP_H_WCHARS +#define CMB 0200 +#else /* !REGEXP_H_WCHARS */ +#define CMB 0 +#endif /* !REGEXP_H_WCHARS */ + +#define NBRA 9 + +#define PLACE(c) ep[c >> 3] |= bittab[c & 07] +#define ISTHERE(c) (ep[c >> 3] & bittab[c & 07]) + +#ifdef REGEXP_H_WCHARS +#define REGEXP_H_IS_THERE(ep, c) ((ep)[c >> 3] & bittab[c & 07]) +#endif + +#include +#include +#include +#ifdef REGEXP_H_WCHARS +#include +#include +#include +#endif /* REGEXP_H_WCHARS */ + +#define regexp_h_uletter(c) (isalpha(c) || (c) == '_') +#ifdef REGEXP_H_WCHARS +#define regexp_h_wuletter(c) (iswalpha(c) || (c) == L'_') + +/* + * Used to allocate memory for the multibyte star algorithm. + */ +#ifndef regexp_h_malloc +#define regexp_h_malloc(n) malloc(n) +#endif +#ifndef regexp_h_free +#define regexp_h_free(p) free(p) +#endif + +/* + * Can be predefined to 'inline' to inline some multibyte functions; + * may improve performance for files that contain many multibyte + * sequences. + */ +#ifndef regexp_h_inline +#define regexp_h_inline +#endif + +/* + * Mask to determine whether the first byte of a sequence possibly + * starts a multibyte character. Set to 0377 to force mbtowc() for + * any byte sequence (except 0). + */ +#ifndef REGEXP_H_MASK +#define REGEXP_H_MASK 0200 +#endif +#endif /* REGEXP_H_WCHARS */ + +/* + * For regexpr.h. + */ +#ifndef regexp_h_static +#define regexp_h_static +#endif +#ifndef REGEXP_H_STEP_INIT +#define REGEXP_H_STEP_INIT +#endif +#ifndef REGEXP_H_ADVANCE_INIT +#define REGEXP_H_ADVANCE_INIT +#endif + +char *braslist[NBRA]; +char *braelist[NBRA]; +int nbra; +char *loc1, *loc2, *locs; +int sed; +int nodelim; + +regexp_h_static int circf; +regexp_h_static int low; +regexp_h_static int size; + +regexp_h_static unsigned char bittab[] = { + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128 +}; +static int regexp_h_advance(register const char *lp, + register const char *ep); +static void regexp_h_getrnge(register const char *str, int least); + +static const char *regexp_h_bol; /* beginning of input line (for \<) */ + +#ifdef REGEXP_H_WCHARS +static int regexp_h_wchars; +static int regexp_h_mbcurmax; + +static const char *regexp_h_firstwc; /* location of first + multibyte character + on input line */ + +#define regexp_h_getwc(c) { \ + if (regexp_h_wchars) { \ + char mbbuf[MB_LEN_MAX + 1], *mbptr; \ + wchar_t wcbuf; \ + int mb, len; \ + mbptr = mbbuf; \ + do { \ + mb = GETC(); \ + *mbptr++ = mb; \ + *mbptr = '\0'; \ + } while ((len = mbtowc(&wcbuf, mbbuf, regexp_h_mbcurmax)) < 0 \ + && mb != eof && mbptr < mbbuf + MB_LEN_MAX); \ + if (len == -1) \ + ERROR(67); \ + c = wcbuf; \ + } else { \ + c = GETC(); \ + } \ +} + +#define regexp_h_store(wc, mb, me) { \ + int len; \ + if (wc == WEOF) \ + ERROR(67); \ + if ((len = me - mb) <= regexp_h_mbcurmax) { \ + char mt[MB_LEN_MAX]; \ + if (wctomb(mt, wc) >= len) \ + ERROR(50); \ + } \ + switch (len = wctomb(mb, wc)) { \ + case -1: \ + ERROR(67); \ + case 0: \ + mb++; \ + break; \ + default: \ + mb += len; \ + } \ +} + +static regexp_h_inline wint_t +regexp_h_fetchwc(const char **mb, int islp) +{ + wchar_t wc; + int len; + + if ((len = mbtowc(&wc, *mb, regexp_h_mbcurmax)) < 0) { + (*mb)++; + return WEOF; + } + if (islp && regexp_h_firstwc == NULL) + regexp_h_firstwc = *mb; + /*if (len == 0) { + (*mb)++; + return L'\0'; + } handled in singlebyte code */ + *mb += len; + return wc; +} + +#define regexp_h_fetch(mb, islp) ((*(mb) & REGEXP_H_MASK) == 0 ? \ + (*(mb)++&0377): \ + regexp_h_fetchwc(&(mb), islp)) + +static regexp_h_inline wint_t +regexp_h_showwc(const char *mb) +{ + wchar_t wc; + + if (mbtowc(&wc, mb, regexp_h_mbcurmax) < 0) + return WEOF; + return wc; +} + +#define regexp_h_show(mb) ((*(mb) & REGEXP_H_MASK) == 0 ? (*(mb)&0377): \ + regexp_h_showwc(mb)) + +/* + * Return the character immediately preceding mb. Since no byte is + * required to be the first byte of a character, the longest multibyte + * character ending at &[mb-1] is searched. + */ +static regexp_h_inline wint_t +regexp_h_previous(const char *mb) +{ + const char *p = mb; + wchar_t wc, lastwc = WEOF; + int len, max = 0; + + if (regexp_h_firstwc == NULL || mb <= regexp_h_firstwc) + return (mb > regexp_h_bol ? (mb[-1] & 0377) : WEOF); + while (p-- > regexp_h_bol) { + mbtowc(NULL, NULL, 0); + if ((len = mbtowc(&wc, p, mb - p)) >= 0) { + if (len < max || len < mb - p) + break; + max = len; + lastwc = wc; + } else if (len < 0 && max > 0) + break; + } + return lastwc; +} + +#define regexp_h_cclass(set, c, af) \ + ((c) == 0 || (c) == WEOF ? 0 : ( \ + ((c) > 0177) ? \ + regexp_h_cclass_wc(set, c, af) : ( \ + REGEXP_H_IS_THERE((set)+1, (c)) ? (af) : !(af) \ + ) \ + ) \ + ) + +static regexp_h_inline int +regexp_h_cclass_wc(const char *set, register wint_t c, int af) +{ + register wint_t wc, wl = WEOF; + const char *end; + + end = &set[18] + set[0] - 1; + set += 17; + while (set < end) { + wc = regexp_h_fetch(set, 0); +#ifdef REGEXP_H_VI_BACKSLASH + if (wc == '\\' && set < end && + (*set == ']' || *set == '-' || + *set == '^' || *set == '\\')) { + wc = regexp_h_fetch(set, 0); + } else +#endif /* REGEXP_H_VI_BACKSLASH */ + if (wc == '-' && wl != WEOF && set < end) { + wc = regexp_h_fetch(set, 0); +#ifdef REGEXP_H_VI_BACKSLASH + if (wc == '\\' && set < end && + (*set == ']' || *set == '-' || + *set == '^' || *set == '\\')) { + wc = regexp_h_fetch(set, 0); + } +#endif /* REGEXP_H_VI_BACKSLASH */ + if (c > wl && c < wc) + return af; + } + if (c == wc) + return af; + wl = wc; + } + return !af; +} +#else /* !REGEXP_H_WCHARS */ +#define regexp_h_wchars 0 +#define regexp_h_getwc(c) { c = GETC(); } +#endif /* !REGEXP_H_WCHARS */ + +regexp_h_static char * +compile(char *instring, char *ep, const char *endbuf, int seof) +{ + INIT /* Dependent declarations and initializations */ + register int c; + register int eof = seof; + char *lastep = instring; + int cclcnt; + char bracket[NBRA], *bracketp; + int closed; + char neg; + int lc; + int i, cflg; + +#ifdef REGEXP_H_WCHARS + char *eq; + regexp_h_mbcurmax = MB_CUR_MAX; + regexp_h_wchars = regexp_h_mbcurmax > 1 ? CMB : 0; +#endif + lastep = 0; + bracketp = bracket; + if((c = GETC()) == eof || c == '\n') { + if (c == '\n') { + UNGETC(c); + nodelim = 1; + } + if(*ep == 0 && !sed) + ERROR(41); + if (bracketp > bracket) + ERROR(42); + RETURN(ep); + } + circf = closed = nbra = 0; + if (c == '^') + circf++; + else + UNGETC(c); + for (;;) { + if (ep >= endbuf) + ERROR(50); + regexp_h_getwc(c); + if(c != '*' && ((c != '\\') || (PEEKC() != '{'))) + lastep = ep; + if (c == eof) { + *ep++ = CCEOF; + if (bracketp > bracket) + ERROR(42); + RETURN(ep); + } + switch (c) { + + case '.': + *ep++ = CDOT|regexp_h_wchars; + continue; + + case '\n': + if (sed == 0) { + UNGETC(c); + *ep++ = CCEOF; + nodelim = 1; + RETURN(ep); + } + ERROR(36); + case '*': + if (lastep==0 || *lastep==CBRA || *lastep==CKET || + *lastep==(CBRC|regexp_h_wchars) || + *lastep==(CLET|regexp_h_wchars)) + goto defchar; + *lastep |= STAR; + continue; + + case '$': + if(PEEKC() != eof) + goto defchar; + *ep++ = CDOL; + continue; + + case '[': +#ifdef REGEXP_H_WCHARS + if (regexp_h_wchars == 0) { +#endif + if(&ep[33] >= endbuf) + ERROR(50); + + *ep++ = CCL; + lc = 0; + for(i = 0; i < 32; i++) + ep[i] = 0; + + neg = 0; + if((c = GETC()) == '^') { + neg = 1; + c = GETC(); + } + + do { + c &= 0377; + if(c == '\0' || c == '\n') + ERROR(49); +#ifdef REGEXP_H_VI_BACKSLASH + if(c == '\\' && ((c = PEEKC()) == ']' || + c == '-' || c == '^' || + c == '\\')) { + c = GETC(); + c &= 0377; + } else +#endif /* REGEXP_H_VI_BACKSLASH */ + if(c == '-' && lc != 0) { + if ((c = GETC()) == ']') { + PLACE('-'); + break; + } +#ifdef REGEXP_H_VI_BACKSLASH + if(c == '\\' && + ((c = PEEKC()) == ']' || + c == '-' || + c == '^' || + c == '\\')) + c = GETC(); +#endif /* REGEXP_H_VI_BACKSLASH */ + c &= 0377; + while(lc < c) { + PLACE(lc); + lc++; + } + } + lc = c; + PLACE(c); + } while((c = GETC()) != ']'); + if(neg) { + for(cclcnt = 0; cclcnt < 32; cclcnt++) + ep[cclcnt] ^= 0377; + ep[0] &= 0376; + } + + ep += 32; +#ifdef REGEXP_H_WCHARS + } else { + if (&ep[18] >= endbuf) + ERROR(50); + *ep++ = CCL|CMB; + *ep++ = 0; + lc = 0; + for (i = 0; i < 16; i++) + ep[i] = 0; + eq = &ep[16]; + regexp_h_getwc(c); + if (c == L'^') { + regexp_h_getwc(c); + ep[-2] = CNCL|CMB; + } + do { + if (c == '\0' || c == '\n') + ERROR(49); +#ifdef REGEXP_H_VI_BACKSLASH + if(c == '\\' && ((c = PEEKC()) == ']' || + c == '-' || c == '^' || + c == '\\')) { + regexp_h_store(c, eq, endbuf); + regexp_h_getwc(c); + } else +#endif /* REGEXP_H_VI_BACKSLASH */ + if (c == '-' && lc != 0 && lc <= 0177) { + regexp_h_store(c, eq, endbuf); + regexp_h_getwc(c); + if (c == ']') { + PLACE('-'); + break; + } +#ifdef REGEXP_H_VI_BACKSLASH + if(c == '\\' && + ((c = PEEKC()) == ']' || + c == '-' || + c == '^' || + c == '\\')) { + regexp_h_store(c, eq, + endbuf); + regexp_h_getwc(c); + } +#endif /* REGEXP_H_VI_BACKSLASH */ + while (lc < (c & 0177)) { + PLACE(lc); + lc++; + } + } + lc = c; + if (c <= 0177) + PLACE(c); + regexp_h_store(c, eq, endbuf); + regexp_h_getwc(c); + } while (c != L']'); + if ((i = eq - &ep[16]) > 255) + ERROR(50); + lastep[1] = i; + ep = eq; + } +#endif /* REGEXP_H_WCHARS */ + + continue; + + case '\\': + regexp_h_getwc(c); + switch(c) { + + case '(': + if(nbra >= NBRA) + ERROR(43); + *bracketp++ = nbra; + *ep++ = CBRA; + *ep++ = nbra++; + continue; + + case ')': + if(bracketp <= bracket) + ERROR(42); + *ep++ = CKET; + *ep++ = *--bracketp; + closed++; + continue; + + case '<': + *ep++ = CBRC|regexp_h_wchars; + continue; + + case '>': + *ep++ = CLET|regexp_h_wchars; + continue; + + case '{': + if(lastep == (char *) (0)) + goto defchar; + *lastep |= RNGE; + cflg = 0; + nlim: + c = GETC(); + i = 0; + do { + if ('0' <= c && c <= '9') + i = 10 * i + c - '0'; + else + ERROR(16); + } while(((c = GETC()) != '\\') && (c != ',')); + if (i > 255) + ERROR(11); + *ep++ = i; + if (c == ',') { + if(cflg++) + ERROR(44); + if((c = GETC()) == '\\') { + *ep++ = (char)255; + *lastep |= REGEXP_H_LEAST; + } else { + UNGETC(c); + goto nlim; /* get 2'nd number */ + } + } + if(GETC() != '}') + ERROR(45); + if(!cflg) /* one number */ + *ep++ = i; + else if((ep[-1] & 0377) < (ep[-2] & 0377)) + ERROR(46); + continue; + + case '\n': + ERROR(36); + + case 'n': + c = '\n'; + goto defchar; + + default: + if(c >= '1' && c <= '9') { + if((c -= '1') >= closed) + ERROR(25); + *ep++ = CBACK; + *ep++ = c; + continue; + } + } + /* Drop through to default to use \ to turn off special chars */ + + defchar: + default: + lastep = ep; +#ifdef REGEXP_H_WCHARS + if (regexp_h_wchars == 0) { +#endif + *ep++ = CCHR; + *ep++ = c; +#ifdef REGEXP_H_WCHARS + } else { + char mbbuf[MB_LEN_MAX]; + + switch (wctomb(mbbuf, c)) { + case 1: *ep++ = CCH1; + break; + case 2: *ep++ = CCH2; + break; + case 3: *ep++ = CCH3; + break; + default: + *ep++ = CCHR|CMB; + } + regexp_h_store(c, ep, endbuf); + } +#endif /* REGEXP_H_WCHARS */ + } + } +} + +int +step(const char *p1, const char *p2) +{ + register int c; +#ifdef REGEXP_H_WCHARS + register int d; +#endif /* REGEXP_H_WCHARS */ + + REGEXP_H_STEP_INIT /* get circf */ + regexp_h_bol = p1; +#ifdef REGEXP_H_WCHARS + regexp_h_firstwc = NULL; +#endif /* REGEXP_H_WCHARS */ + if (circf) { + loc1 = (char *)p1; + return(regexp_h_advance(p1, p2)); + } + /* fast check for first character */ + if (*p2==CCHR) { + c = p2[1] & 0377; + do { + if ((*p1 & 0377) != c) + continue; + if (regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + } while (*p1++); + return(0); + } +#ifdef REGEXP_H_WCHARS + else if (*p2==CCH1) { + do { + if (p1[0] == p2[1] && regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + c = regexp_h_fetch(p1, 1); + } while (c); + return(0); + } else if (*p2==CCH2) { + do { + if (p1[0] == p2[1] && p1[1] == p2[2] && + regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + c = regexp_h_fetch(p1, 1); + } while (c); + return(0); + } else if (*p2==CCH3) { + do { + if (p1[0] == p2[1] && p1[1] == p2[2] && p1[2] == p2[3]&& + regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + c = regexp_h_fetch(p1, 1); + } while (c); + return(0); + } else if ((*p2&0377)==(CCHR|CMB)) { + d = regexp_h_fetch(p2, 0); + do { + c = regexp_h_fetch(p1, 1); + if (c == d && regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + } while(c); + return(0); + } + /* regular algorithm */ + if (regexp_h_wchars) + do { + if (regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + c = regexp_h_fetch(p1, 1); + } while (c); + else +#endif /* REGEXP_H_WCHARS */ + do { + if (regexp_h_advance(p1, p2)) { + loc1 = (char *)p1; + return(1); + } + } while (*p1++); + return(0); +} + +#ifdef REGEXP_H_WCHARS +/* + * It is painfully slow to read character-wise backwards in a + * multibyte string (see regexp_h_previous() above). For the star + * algorithm, we therefore keep track of every character as it is + * read in forward direction. + * + * Don't use alloca() for stack blocks since there is no measurable + * speedup and huge amounts of memory are used up for long input + * lines. + */ +#ifndef REGEXP_H_STAKBLOK +#define REGEXP_H_STAKBLOK 1000 +#endif + +struct regexp_h_stack { + struct regexp_h_stack *s_nxt; + struct regexp_h_stack *s_prv; + const char *s_ptr[REGEXP_H_STAKBLOK]; +}; + +#define regexp_h_push(sb, sp, sc, lp) (regexp_h_wchars ? \ + regexp_h_pushwc(sb, sp, sc, lp) : (void)0) + +static regexp_h_inline void +regexp_h_pushwc(struct regexp_h_stack **sb, + struct regexp_h_stack **sp, + const char ***sc, const char *lp) +{ + if (regexp_h_firstwc == NULL || lp < regexp_h_firstwc) + return; + if (*sb == NULL) { + if ((*sb = regexp_h_malloc(sizeof **sb)) == NULL) + return; + (*sb)->s_nxt = (*sb)->s_prv = NULL; + *sp = *sb; + *sc = &(*sb)->s_ptr[0]; + } else if (*sc >= &(*sp)->s_ptr[REGEXP_H_STAKBLOK]) { + if ((*sp)->s_nxt == NULL) { + struct regexp_h_stack *bq; + + if ((bq = regexp_h_malloc(sizeof *bq)) == NULL) + return; + bq->s_nxt = NULL; + bq->s_prv = *sp; + (*sp)->s_nxt = bq; + *sp = bq; + } else + *sp = (*sp)->s_nxt; + *sc = &(*sp)->s_ptr[0]; + } + *(*sc)++ = lp; +} + +static regexp_h_inline const char * +regexp_h_pop(struct regexp_h_stack **sb, struct regexp_h_stack **sp, + const char ***sc, const char *lp) +{ + if (regexp_h_firstwc == NULL || lp <= regexp_h_firstwc) + return &lp[-1]; + if (*sp == NULL) + return regexp_h_firstwc; + if (*sc == &(*sp)->s_ptr[0]) { + if ((*sp)->s_prv == NULL) { + regexp_h_free(*sp); + *sp = NULL; + *sb = NULL; + return regexp_h_firstwc; + } + *sp = (*sp)->s_prv; + regexp_h_free((*sp)->s_nxt); + (*sp)->s_nxt = NULL ; + *sc = &(*sp)->s_ptr[REGEXP_H_STAKBLOK]; + } + return *(--(*sc)); +} + +static void +regexp_h_zerostak(struct regexp_h_stack **sb, struct regexp_h_stack **sp) +{ + for (*sp = *sb; *sp && (*sp)->s_nxt; *sp = (*sp)->s_nxt) + if ((*sp)->s_prv) + regexp_h_free((*sp)->s_prv); + if (*sp) { + if ((*sp)->s_prv) + regexp_h_free((*sp)->s_prv); + regexp_h_free(*sp); + } + *sp = *sb = NULL; +} +#else /* !REGEXP_H_WCHARS */ +#define regexp_h_push(sb, sp, sc, lp) +#endif /* !REGEXP_H_WCHARS */ + +static int +regexp_h_advance(const char *lp, const char *ep) +{ + register const char *curlp; + int c, least; +#ifdef REGEXP_H_WCHARS + int d; + struct regexp_h_stack *sb = NULL, *sp = NULL; + const char **sc; +#endif /* REGEXP_H_WCHARS */ + char *bbeg; + int ct; + + for (;;) switch (least = *ep++ & 0377, least & ~REGEXP_H_LEAST) { + + case CCHR: +#ifdef REGEXP_H_WCHARS + case CCH1: +#endif + if (*ep++ == *lp++) + continue; + return(0); + +#ifdef REGEXP_H_WCHARS + case CCHR|CMB: + if (regexp_h_fetch(ep, 0) == regexp_h_fetch(lp, 1)) + continue; + return(0); + + case CCH2: + if (ep[0] == lp[0] && ep[1] == lp[1]) { + ep += 2, lp += 2; + continue; + } + return(0); + + case CCH3: + if (ep[0] == lp[0] && ep[1] == lp[1] && ep[2] == lp[2]) { + ep += 3, lp += 3; + continue; + } + return(0); +#endif /* REGEXP_H_WCHARS */ + + case CDOT: + if (*lp++) + continue; + return(0); +#ifdef REGEXP_H_WCHARS + case CDOT|CMB: + if ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF) + continue; + return(0); +#endif /* REGEXP_H_WCHARS */ + + case CDOL: + if (*lp==0) + continue; + return(0); + + case CCEOF: + loc2 = (char *)lp; + return(1); + + case CCL: + c = *lp++ & 0377; + if(ISTHERE(c)) { + ep += 32; + continue; + } + return(0); + +#ifdef REGEXP_H_WCHARS + case CCL|CMB: + case CNCL|CMB: + c = regexp_h_fetch(lp, 1); + if (regexp_h_cclass(ep, c, (ep[-1] & 0377) == (CCL|CMB))) { + ep += (*ep & 0377) + 17; + continue; + } + return 0; +#endif /* REGEXP_H_WCHARS */ + + case CBRA: + braslist[*ep++ & 0377] = (char *)lp; + continue; + + case CKET: + braelist[*ep++ & 0377] = (char *)lp; + continue; + + case CBRC: + if (lp == regexp_h_bol && locs == NULL) + continue; + if ((isdigit(lp[0] & 0377) || regexp_h_uletter(lp[0] & 0377)) + && !regexp_h_uletter(lp[-1] & 0377) + && !isdigit(lp[-1] & 0377)) + continue; + return(0); + +#ifdef REGEXP_H_WCHARS + case CBRC|CMB: + c = regexp_h_show(lp); + d = regexp_h_previous(lp); + if ((iswdigit(c) || regexp_h_wuletter(c)) + && !regexp_h_wuletter(d) + && !iswdigit(d)) + continue; + return(0); +#endif /* REGEXP_H_WCHARS */ + + case CLET: + if (!regexp_h_uletter(lp[0] & 0377) && !isdigit(lp[0] & 0377)) + continue; + return(0); + +#ifdef REGEXP_H_WCHARS + case CLET|CMB: + c = regexp_h_show(lp); + if (!regexp_h_wuletter(c) && !iswdigit(c)) + continue; + return(0); +#endif /* REGEXP_H_WCHARS */ + + case CCHR|RNGE: + c = *ep++; + regexp_h_getrnge(ep, least); + while(low--) + if(*lp++ != c) + return(0); + curlp = lp; + while(size--) { + regexp_h_push(&sb, &sp, &sc, lp); + if(*lp++ != c) + break; + } + if(size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + lp++; + } + ep += 2; + goto star; + +#ifdef REGEXP_H_WCHARS + case CCHR|RNGE|CMB: + case CCH1|RNGE: + case CCH2|RNGE: + case CCH3|RNGE: + c = regexp_h_fetch(ep, 0); + regexp_h_getrnge(ep, least); + while (low--) + if (regexp_h_fetch(lp, 1) != c) + return 0; + curlp = lp; + while (size--) { + regexp_h_push(&sb, &sp, &sc, lp); + if (regexp_h_fetch(lp, 1) != c) + break; + } + if(size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + regexp_h_fetch(lp, 1); + } + ep += 2; + goto star; +#endif /* REGEXP_H_WCHARS */ + + case CDOT|RNGE: + regexp_h_getrnge(ep, least); + while(low--) + if(*lp++ == '\0') + return(0); + curlp = lp; + while(size--) { + regexp_h_push(&sb, &sp, &sc, lp); + if(*lp++ == '\0') + break; + } + if(size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + lp++; + } + ep += 2; + goto star; + +#ifdef REGEXP_H_WCHARS + case CDOT|RNGE|CMB: + regexp_h_getrnge(ep, least); + while (low--) + if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF) + return 0; + curlp = lp; + while (size--) { + regexp_h_push(&sb, &sp, &sc, lp); + if ((c = regexp_h_fetch(lp, 1)) == L'\0' || c == WEOF) + break; + } + if (size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + regexp_h_fetch(lp, 1); + } + ep += 2; + goto star; +#endif /* REGEXP_H_WCHARS */ + + case CCL|RNGE: + regexp_h_getrnge(ep + 32, least); + while(low--) { + c = *lp++ & 0377; + if(!ISTHERE(c)) + return(0); + } + curlp = lp; + while(size--) { + regexp_h_push(&sb, &sp, &sc, lp); + c = *lp++ & 0377; + if(!ISTHERE(c)) + break; + } + if(size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + lp++; + } + ep += 34; /* 32 + 2 */ + goto star; + +#ifdef REGEXP_H_WCHARS + case CCL|RNGE|CMB: + case CNCL|RNGE|CMB: + regexp_h_getrnge(ep + (*ep & 0377) + 17, least); + while (low--) { + c = regexp_h_fetch(lp, 1); + if (!regexp_h_cclass(ep, c, + (ep[-1] & 0377 & ~REGEXP_H_LEAST) + == (CCL|RNGE|CMB))) + return 0; + } + curlp = lp; + while (size--) { + regexp_h_push(&sb, &sp, &sc, lp); + c = regexp_h_fetch(lp, 1); + if (!regexp_h_cclass(ep, c, + (ep[-1] & 0377 & ~REGEXP_H_LEAST) + == (CCL|RNGE|CMB))) + break; + } + if (size < 0) { + regexp_h_push(&sb, &sp, &sc, lp); + regexp_h_fetch(lp, 1); + } + ep += (*ep & 0377) + 19; + goto star; +#endif /* REGEXP_H_WCHARS */ + + case CBACK: + bbeg = braslist[*ep & 0377]; + ct = braelist[*ep++ & 0377] - bbeg; + + if(strncmp(bbeg, lp, ct) == 0) { + lp += ct; + continue; + } + return(0); + + case CBACK|STAR: + bbeg = braslist[*ep & 0377]; + ct = braelist[*ep++ & 0377] - bbeg; + curlp = lp; + while(strncmp(bbeg, lp, ct) == 0) + lp += ct; + + while(lp >= curlp) { + if(regexp_h_advance(lp, ep)) return(1); + lp -= ct; + } + return(0); + + + case CDOT|STAR: + curlp = lp; + do + regexp_h_push(&sb, &sp, &sc, lp); + while (*lp++); + goto star; + +#ifdef REGEXP_H_WCHARS + case CDOT|STAR|CMB: + curlp = lp; + do + regexp_h_push(&sb, &sp, &sc, lp); + while ((c = regexp_h_fetch(lp, 1)) != L'\0' && c != WEOF); + goto star; +#endif /* REGEXP_H_WCHARS */ + + case CCHR|STAR: + curlp = lp; + do + regexp_h_push(&sb, &sp, &sc, lp); + while (*lp++ == *ep); + ep++; + goto star; + +#ifdef REGEXP_H_WCHARS + case CCHR|STAR|CMB: + case CCH1|STAR: + case CCH2|STAR: + case CCH3|STAR: + curlp = lp; + d = regexp_h_fetch(ep, 0); + do + regexp_h_push(&sb, &sp, &sc, lp); + while (regexp_h_fetch(lp, 1) == d); + goto star; +#endif /* REGEXP_H_WCHARS */ + + case CCL|STAR: + curlp = lp; + do { + regexp_h_push(&sb, &sp, &sc, lp); + c = *lp++ & 0377; + } while(ISTHERE(c)); + ep += 32; + goto star; + +#ifdef REGEXP_H_WCHARS + case CCL|STAR|CMB: + case CNCL|STAR|CMB: + curlp = lp; + do { + regexp_h_push(&sb, &sp, &sc, lp); + c = regexp_h_fetch(lp, 1); + } while (regexp_h_cclass(ep, c, (ep[-1] & 0377) + == (CCL|STAR|CMB))); + ep += (*ep & 0377) + 17; + goto star; +#endif /* REGEXP_H_WCHARS */ + + star: +#ifdef REGEXP_H_WCHARS + if (regexp_h_wchars == 0) { +#endif + do { + if(--lp == locs) + break; + if (regexp_h_advance(lp, ep)) + return(1); + } while (lp > curlp); +#ifdef REGEXP_H_WCHARS + } else { + do { + lp = regexp_h_pop(&sb, &sp, &sc, lp); + if (lp <= locs) + break; + if (regexp_h_advance(lp, ep)) { + regexp_h_zerostak(&sb, &sp); + return(1); + } + } while (lp > curlp); + regexp_h_zerostak(&sb, &sp); + } +#endif /* REGEXP_H_WCHARS */ + return(0); + + } +} + +static void +regexp_h_getrnge(register const char *str, int least) +{ + low = *str++ & 0377; + size = least & REGEXP_H_LEAST ? /*20000*/INT_MAX : (*str & 0377) - low; +} + +int +advance(const char *lp, const char *ep) +{ + REGEXP_H_ADVANCE_INIT /* skip past circf */ + regexp_h_bol = lp; +#ifdef REGEXP_H_WCHARS + regexp_h_firstwc = NULL; +#endif /* REGEXP_H_WCHARS */ + return regexp_h_advance(lp, ep); +} diff -r 000000000000 -r 1493bea5ac22 regexpr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regexpr.c Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,90 @@ +/* + * Simple Regular Expression functions. Derived from Unix 7th Edition, + * /usr/src/cmd/expr.y + * + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003. + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Sccsid @(#)regexpr.c 1.8 (gritter) 10/13/04 */ + +#include +#include "regexpr.h" + +int regerrno, reglength; +static int circf; + +static char *regexpr_compile(char *, char *, const char *, int); + +char * +compile(const char *instring, char *ep, char *endbuf) +{ + char *cp; + int sz = 0; + + if (ep == 0) { + for (cp = (char *)instring; *cp != '\0'; cp++) + if (*cp == '[') + sz += 32; + sz += 2 * (cp - instring) + 5; + if ((ep = malloc(sz)) == 0) { + regerrno = 11; + return 0; + } + endbuf = &ep[sz]; + ep[1] = '\0'; + } + if ((cp=regexpr_compile((char *)instring, &ep[1], endbuf, '\0')) == 0) { + if (sz) + free(ep); + return 0; + } + ep[0] = circf; + reglength = cp - ep; + return sz ? ep : cp; +} + +#define INIT register char *sp = instring; +#define GETC() (*sp++) +#define PEEKC() (*sp) +#define UNGETC(c) (--sp) +#define RETURN(c) return (c); +#define ERROR(c) { regerrno = c; return 0; } + +#define compile(a, b, c, d) regexpr_compile(a, b, c, d) +#define regexp_h_static static +#define REGEXP_H_STEP_INIT circf = *p2++; +#define REGEXP_H_ADVANCE_INIT circf = *ep++; + +#include "regexp.h" diff -r 000000000000 -r 1493bea5ac22 regexpr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regexpr.h Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,53 @@ +/* + * Simple Regular Expression functions. Derived from Unix 7th Edition, + * /usr/src/cmd/expr.y + * + * Modified by Gunnar Ritter, Freiburg i. Br., Germany, January 2003. + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Sccsid @(#)regexpr.h 1.2 (gritter) 1/11/03 */ + +#define NBRA 9 + +extern char *braslist[NBRA]; +extern char *braelist[NBRA]; +extern int nbra; +extern int regerrno, reglength; +extern char *loc1, *loc2, *locs; +extern int sed; + +extern char *compile(const char *, char *, char *); +extern int step(const char *, const char *); +extern int advance(const char *, const char *); diff -r 000000000000 -r 1493bea5ac22 sigrelse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sigrelse.c Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 Gunnar Ritter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + */ +/* Sccsid @(#)sigrelse.c 1.8 (gritter) 1/22/06 */ + +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \ + defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__) +#include +#include "sigset.h" + +int +sigrelse(int sig) +{ + sigset_t set, oset; + + if (sig <= 0) + return -1; + sigemptyset(&set); + sigaddset(&set, sig); + return sigprocmask(SIG_UNBLOCK, &set, &oset); +} +#endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ || + __DragonFly__ || __APPLE__ */ diff -r 000000000000 -r 1493bea5ac22 sigset.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sigset.c Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Gunnar Ritter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + */ +/* Sccsid @(#)sigset.c 1.7 (gritter) 1/22/06 */ + +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \ + defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__) +#include +#include "sigset.h" + +void (*sigset(int sig, void (*func)(int)))(int) +{ + struct sigaction nact, oact; + sigset_t nset, oset; + + if (sig <= 0) + return SIG_ERR; + sigemptyset(&nset); + sigaddset(&nset, sig); + if (sigprocmask(func==SIG_HOLD?SIG_BLOCK:SIG_UNBLOCK, &nset, &oset) < 0) + return SIG_ERR; + nact.sa_handler = func; + nact.sa_flags = 0; + if (sig == SIGCHLD && func == SIG_IGN) + nact.sa_flags |= SA_NOCLDSTOP|SA_NOCLDWAIT; + sigemptyset(&nact.sa_mask); + sigaddset(&nact.sa_mask, sig); + if (sigaction(sig, func==SIG_HOLD?(struct sigaction *)0:&nact, &oact) + == -1) + return SIG_ERR; + if (sigismember(&oset, sig)) + return SIG_HOLD; + else + return (oact.sa_handler); +} +#endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ || + __DragonFly__ || __APPLE__ */ diff -r 000000000000 -r 1493bea5ac22 sigset.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sigset.h Mon Sep 05 16:31:35 2011 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004 Gunnar Ritter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + */ +/* Sccsid @(#)sigset.h 1.9 (gritter) 1/22/06 */ + +#if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \ + defined (__OpenBSD__) || defined (__DragonFly__) || defined (__APPLE__) + +#ifndef SIG_HOLD +#define SIG_HOLD ((void (*)(int))2) +#endif /* !SIG_HOLD */ + +extern int sighold(int); +extern int sigignore(int); +extern int sigpause(int); +extern int sigrelse(int); +extern void (*sigset(int, void (*)(int)))(int); +extern void (*signal(int, void (*)(int)))(int); +#endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __OpenBSD__ || + __DragonFly__ || __APPLE__ */