/* GNU SED, a batch stream editor.
Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "basicdefs.h"
#include "regex.h"
#ifndef BOOTSTRAP
#include <stdio.h>
#include "unlocked-io.h"
#endif
#include "utils.h"
/* Struct vector is used to describe a compiled sed program. */
struct vector {
struct sed_cmd *v; /* a dynamically allocated array */
size_t v_allocated; /* ... number slots allocated */
size_t v_length; /* ... number of slots in use */
};
/* This structure tracks files used by sed so that they may all be
closed cleanly at normal program termination. A flag is kept that tells
if a missing newline was encountered, so that it is added on the
next line and the two lines are not concatenated. */
struct output {
char *name;
bool missing_newline;
FILE *fp;
struct output *link;
};
struct text_buf {
char *text;
size_t text_length;
};
struct regex {
regex_t pattern;
int flags;
size_t sz;
char re[1];
};
enum replacement_types {
REPL_ASIS = 0,
REPL_UPPERCASE = 1,
REPL_LOWERCASE = 2,
REPL_UPPERCASE_FIRST = 4,
REPL_LOWERCASE_FIRST = 8,
REPL_MODIFIERS = REPL_UPPERCASE_FIRST | REPL_LOWERCASE_FIRST,
/* These are given to aid in debugging */
REPL_UPPERCASE_UPPERCASE = REPL_UPPERCASE_FIRST | REPL_UPPERCASE,
REPL_UPPERCASE_LOWERCASE = REPL_UPPERCASE_FIRST | REPL_LOWERCASE,
REPL_LOWERCASE_UPPERCASE = REPL_LOWERCASE_FIRST | REPL_UPPERCASE,
REPL_LOWERCASE_LOWERCASE = REPL_LOWERCASE_FIRST | REPL_LOWERCASE
};
enum text_types {
TEXT_BUFFER,
TEXT_REPLACEMENT,
TEXT_REGEX
};
enum posixicity_types {
POSIXLY_EXTENDED, /* with GNU extensions */
POSIXLY_CORRECT, /* with POSIX-compatible GNU extensions */
POSIXLY_BASIC /* pedantically POSIX */
};
enum addr_state {
RANGE_INACTIVE, /* never been active */
RANGE_ACTIVE, /* between first and second address */
RANGE_CLOSED /* like RANGE_INACTIVE, but range has ended once */
};
enum addr_types {
ADDR_IS_NULL, /* null address */
ADDR_IS_REGEX, /* a.addr_regex is valid */
ADDR_IS_NUM, /* a.addr_number is valid */
ADDR_IS_NUM_MOD, /* a.addr_number is valid, addr_step is modulo */
ADDR_IS_STEP, /* address is +N (only valid for addr2) */
ADDR_IS_STEP_MOD, /* address is ~N (only valid for addr2) */
ADDR_IS_LAST /* address is $ */
};
struct addr {
enum addr_types addr_type;
countT addr_number;
countT addr_step;
struct regex *addr_regex;
};
struct replacement {
char *prefix;
size_t prefix_length;
int subst_id;
enum replacement_types repl_type;
struct replacement *next;
};
struct subst {
struct regex *regx;
struct replacement *replacement;
countT numb; /* if >0, only substitute for match number "numb" */
struct output *outf; /* 'w' option given */
unsigned global : 1; /* 'g' option given */
unsigned print : 2; /* 'p' option given (before/after eval) */
unsigned eval : 1; /* 'e' option given */
unsigned max_id : 4; /* maximum backreference on the RHS */
};
#ifdef REG_PERL
/* This is the structure we store register match data in. See
regex.texinfo for a full description of what registers match. */
struct re_registers
{
unsigned num_regs;
regoff_t *start;
regoff_t *end;
};
#endif
struct sed_cmd {
struct addr *a1; /* save space: usually is NULL */
struct addr *a2;
/* See description the enum, above. */
enum addr_state range_state;
/* Non-zero if command is to be applied to non-matches. */
char addr_bang;
/* The actual command character. */
char cmd;
/* auxiliary data for various commands */
union {
/* This structure is used for a, i, and c commands. */
struct text_buf cmd_txt;
/* This is used for the l, q and Q commands. */
int int_arg;
/* This is used for the {}, b, and t commands. */
countT jump_index;
/* This is used for the r command. */
char *fname;
/* This is used for the hairy s command. */
struct subst *cmd_subst;
/* This is used for the w command. */
struct output *outf;
/* This is used for the R command. */
FILE *fp;
/* This is used for the y command. */
unsigned char *translate;
char **translatemb;
} x;
};
void bad_prog P_((const char *why));
size_t normalize_text P_((char *text, size_t len, enum text_types buftype));
struct vector *compile_string P_((struct vector *, char *str, size_t len));
struct vector *compile_file P_((struct vector *, const char *cmdfile));
void check_final_program P_((struct vector *));
void rewind_read_files P_((void));
void finish_program P_((struct vector *));
struct regex *compile_regex P_((struct buffer *b, int flags, int needed_sub));
int match_regex P_((struct regex *regex,
char *buf, size_t buflen, size_t buf_start_offset,
struct re_registers *regarray, int regsize));
#ifdef DEBUG_LEAKS
void release_regex P_((struct regex *));
#endif
int process_files P_((struct vector *, char **argv));
int main P_((int, char **));
extern void fmt P_ ((const char *line, const char *line_end, int max_length, FILE *output_file));
extern int extended_regexp_flags;
/* If set, fflush(stdout) on every line output. */
extern bool unbuffered_output;
/* If set, don't write out the line unless explicitly told to. */
extern bool no_default_output;
/* If set, reset line counts on every new file. */
extern bool separate_files;
/* If set, follow symlinks when invoked with -i option */
extern bool follow_symlinks;
/* Do we need to be pedantically POSIX compliant? */
extern enum posixicity_types posixicity;
/* How long should the `l' command's output line be? */
extern countT lcmd_out_line_len;
/* How do we edit files in-place? (we don't if NULL) */
extern char *in_place_extension;
/* The mode to use to read files, either "rt" or "rb". */
extern char *read_mode;
/* Should we use EREs? */
extern bool use_extended_syntax_p;
/* Declarations for multibyte character sets. */
extern int mb_cur_max;
extern bool is_utf8;
#ifdef HAVE_MBRTOWC
#ifdef HAVE_BTOWC
#define MBRTOWC(pwc, s, n, ps) \
(mb_cur_max == 1 ? \
(*(pwc) = btowc (*(unsigned char *) (s)), 1) : \
mbrtowc ((pwc), (s), (n), (ps)))
#define WCRTOMB(s, wc, ps) \
(mb_cur_max == 1 ? \
(*(s) = wctob ((wint_t) (wc)), 1) : \
wcrtomb ((s), (wc), (ps)))
#else
#define MBRTOWC(pwc, s, n, ps) \
mbrtowc ((pwc), (s), (n), (ps))
#define WCRTOMB(s, wc, ps) \
wcrtomb ((s), (wc), (ps))
#endif
#define MBSINIT(s) \
(mb_cur_max == 1 ? 1 : mbsinit ((s)))
#define MBRLEN(s, n, ps) \
(mb_cur_max == 1 ? 1 : mbrtowc (NULL, s, n, ps))
#define BRLEN(ch, ps) \
(mb_cur_max == 1 ? 1 : brlen (ch, ps))
#else
#define MBSINIT(s) 1
#define MBRLEN(s, n, ps) 1
#define BRLEN(ch, ps) 1
#endif
extern int brlen P_ ((int ch, mbstate_t *ps));
extern void initialize_mbcs P_ ((void));