* Copyright (c) 1992 Diomidis Spinellis.
* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)process.c 5.5 (Berkeley) %G%";
char *space
; /* Current space pointer. */
size_t len
; /* Current length. */
int deleted
; /* If deleted. */
char *back
; /* Backing memory. */
size_t blen
; /* Backing memory length. */
static inline int applies
__P((struct s_command
*));
static void cspace
__P((SPACE
*, char *, size_t, int));
static void flush_appends
__P((void));
static void lputs
__P((char *));
static inline int regexec_e
__P((regex_t
*, const char *,
size_t, regmatch_t
[], int));
static void regsub
__P((regmatch_t
*, char *, char *, SPACE
*));
static int substitute
__P((struct s_command
*));
struct s_appends
*appends
; /* Array of pointers to strings to append. */
static int appendx
; /* Index into appends array. */
int appendnum
; /* Size of appends array. */
static int lastaddr
; /* Set by applies if last address of a range. */
static int sdone
; /* If any substitutes since last line input. */
/* Iov structure for 'w' commands. */
static struct iovec iov
[2] = { NULL
, 0, "\n", 1 };
for (linenum
= 0; ps
= mf_fgets(&psl
);) {
if (appendx
>= appendnum
)
appends
= xrealloc(appends
,
sizeof(struct s_appends
) *
appends
[appendx
].type
= AP_STRING
;
appends
[appendx
].s
= cp
->t
;
if (cp
->a2
== NULL
|| lastaddr
)
(void)printf("%s", cp
->t
);
if ((p
= strchr(ps
, '\n')) == NULL
)
(void)printf("%s", cp
->t
);
(void)printf("%s\n", ps
);
if ((p
= mf_fgets(&len
)) == NULL
) {
(void)printf("%s\n", ps
);
(void)printf("%s\n", ps
);
if ((p
= strchr(ps
, '\n')) != NULL
) {
(void)printf("%s\n", ps
);
(void)printf("%s\n", ps
);
if (appendx
>= appendnum
)
appends
= xrealloc(appends
,
sizeof(struct s_appends
) *
appends
[appendx
].type
= AP_FILE
;
appends
[appendx
].s
= cp
->t
;
if (cp
->u
.fd
== -1 && (cp
->u
.fd
= open(cp
->t
,
O_WRONLY
|O_APPEND
|O_CREAT
|O_TRUNC
,
if (writev(cp
->u
.fd
, iov
, 2) != psl
+ 1)
for (p
= ps
, len
= psl
; len
--; ++p
)
(void)printf("%lu\n", linenum
);
(void)printf("%s\n", ps
);
* TRUE if the address passed matches the current program state
* (lastline, linenumber, ps).
regexec_e((a)->u.r, ps, 0, NULL, 0) : \
(a)->type == AT_LINE ? linenum == (a)->u.l : lastline
* Return TRUE if the command applies to the current line. Sets the inrange
* flag to process ranges. Interprets the non-select (``!'') flag.
if (cp
->a1
== NULL
&& cp
->a2
== NULL
)
} else if (MATCH(cp
->a1
)) {
* If the second address is a number less than or
* equal to the line number first selected, only
* one line shall be selected.
if (cp
->a2
->type
== AT_LINE
&&
return (cp
->nonsel
? ! r
: r
);
* Do substitutions in the pattern space. Currently, we build a
* copy of the new pattern space in the substitute space structure
if (defpreg
!= NULL
&& cp
->u
.s
->maxbref
> defnmatch
) {
linenum
= cp
->u
.s
->linenum
;
err(COMPILE
, "\\%d not defined in the RE",
if (!regexec_e(re
, s
, nsub
, cp
->u
.s
->pmatch
, 0))
SS
.len
= 0; /* Clean substitute space. */
/* Locate start of replaced string. */
re_off
= cp
->u
.s
->pmatch
[0].rm_so
;
/* Locate end of replaced string + 1. */
endp
= s
+ cp
->u
.s
->pmatch
[0].rm_eo
;
/* Copy leading retained string. */
cspace(&SS
, s
, re_off
, 0);
/* Add in regular expression. */
regsub(cp
->u
.s
->pmatch
, s
, cp
->u
.s
->new, &SS
);
/* Move past this match. */
s
+= cp
->u
.s
->pmatch
[0].rm_eo
;
} while(regexec_e(re
, s
, nsub
, cp
->u
.s
->pmatch
, REG_NOTBOL
));
/* Copy trailing retained string. */
cspace(&SS
, s
, strlen(s
), 0);
default: /* Nth occurrence */
s
+= cp
->u
.s
->pmatch
[0].rm_eo
;
s
, nsub
, cp
->u
.s
->pmatch
, REG_NOTBOL
))
case 1: /* 1st occurrence */
/* Locate start of replaced string. */
re_off
= cp
->u
.s
->pmatch
[0].rm_so
+ s
- ps
;
/* Copy leading retained string. */
cspace(&SS
, ps
, re_off
, 0);
/* Add in regular expression. */
regsub(cp
->u
.s
->pmatch
, s
, cp
->u
.s
->new, &SS
);
/* Copy trailing retained string. */
s
+= cp
->u
.s
->pmatch
[0].rm_eo
;
cspace(&SS
, s
, strlen(s
), 0);
* Swap the substitute space and the pattern space, and make sure
* that any leftover pointers into stdio memory get lost.
/* Handle the 'p' flag. */
(void)printf("%s\n", ps
);
/* Handle the 'w' flag. */
if (cp
->u
.s
->wfile
&& !pd
) {
if (cp
->u
.s
->wfd
== -1 && (cp
->u
.s
->wfd
= open(cp
->u
.s
->wfile
,
O_WRONLY
|O_APPEND
|O_CREAT
|O_TRUNC
, DEFFILEMODE
)) == -1)
err(FATAL
, "%s: %s\n", cp
->u
.s
->wfile
, strerror(errno
));
if (writev(cp
->u
.s
->wfd
, iov
, 2) != psl
+ 1)
err(FATAL
, "%s: %s\n", cp
->u
.s
->wfile
, strerror(errno
));
* Flush append requests. Always called before reading a line,
* therefore it also resets the substitution done (sdone) flag.
for (i
= 0; i
< appendx
; i
++)
switch (appends
[i
].type
) {
(void)printf("%s", appends
[i
].s
);
* Read files probably shouldn't be cached. Since
* it's not an error to read a non-existent file,
* it's possible that another program is interacting
* with the sed script through the file system. It
* would be truly bizarre, but possible. It's probably
* not that big a performance win, anyhow.
if ((f
= fopen(appends
[i
].s
, "r")) == NULL
)
while (count
= fread(buf
, 1, sizeof(buf
), f
))
(void)fwrite(buf
, 1, count
, stdout
);
err(FATAL
, "stdout: %s", strerror(errno
? errno
: EIO
));
register char *escapes
, *p
;
static int termwidth
= -1;
if (p
= getenv("COLUMNS"))
else if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &win
) == 0 &&
for (count
= 0; *s
; ++s
) {
if (count
>= termwidth
) {
if (isascii(*s
) && isprint(*s
) && *s
!= '\\') {
escapes
= "\\\a\b\f\n\r\t\v";
if (p
= strchr(escapes
, *s
)) {
(void)putchar("\\abfnrtv"[p
- escapes
]);
(void)printf("%03o", (u_char
)*s
);
err(FATAL
, "stdout: %s", strerror(errno
? errno
: EIO
));
regexec_e(preg
, string
, nmatch
, pmatch
, eflags
)
err(FATAL
, "first RE may not be empty");
string
, pmatch
== NULL
? 0 : defnmatch
, pmatch
, eflags
);
err(FATAL
, "RE error: %s", strregerror(eval
, defpreg
));
* regsub - perform substitutions after a regexp match
* Based on a routine by Henry Spencer
regsub(pmatch
, string
, src
, sp
)
if (sp->len >= sp->blen - (reqlen) - 1) { \
sp->blen += (reqlen) + 1024; \
sp->space = sp->back = xrealloc(sp->back, sp->blen); \
dst = sp->space + sp->len; \
dst
= sp
->space
+ sp
->len
;
while ((c
= *src
++) != '\0') {
else if (c
== '\\' && isdigit(*src
))
if (no
< 0) { /* Ordinary character. */
if (c
== '\\' && (*src
== '\\' || *src
== '&'))
} else if (pmatch
[no
].rm_so
!= -1 && pmatch
[no
].rm_eo
!= -1) {
len
= pmatch
[no
].rm_eo
- pmatch
[no
].rm_so
;
memmove(dst
, string
+ pmatch
[no
].rm_so
, len
);
* Append the source space to the destination space, allocating new
cspace(sp
, p
, len
, append
)
/* Current pointer may point to something else at the moment. */
needcopy
= sp
->space
!= sp
->back
;
* Make sure SPACE has enough memory and ramp up quickly.
* Add in two extra bytes, one for the newline, one for a
tlen
= sp
->len
+ len
+ 2;
sp
->back
= xrealloc(sp
->back
, sp
->blen
);
memmove(sp
->back
, sp
->space
, sp
->len
+ 1);
/* May just be copying out of a stdio buffer. */
/* Append a separating newline. */
sp
->space
[sp
->len
++] = '\n';
/* Append the new stuff, plus its terminating NULL. */
memmove(sp
->space
+ sp
->len
, p
, len
+ 1);
* Close all cached opened files and report any errors
register struct s_command
*cp
;
for (; cp
!= NULL
; cp
= cp
->next
)
if (cp
->u
.s
->wfd
!= -1 && close(cp
->u
.s
->wfd
))
"%s: %s", cp
->u
.s
->wfile
, strerror(errno
));
if (cp
->u
.fd
!= -1 && close(cp
->u
.fd
))
err(FATAL
, "%s: %s", cp
->t
, strerror(errno
));