summaryrefslogtreecommitdiff
path: root/sed
diff options
context:
space:
mode:
authorPaolo Bonzini <bonzini@gnu.org>2006-12-15 12:30:25 +0000
committerPaolo Bonzini <bonzini@gnu.org>2008-01-09 16:12:20 +0100
commitba68fb42b8db505a89da4987df5936997a3c226a (patch)
tree28c41aecc082a91b95312909851db53cb1bda464 /sed
parent2128ec657b3d6bb3378424d0ddda923cdf8e2713 (diff)
downloadsed-ba68fb42b8db505a89da4987df5936997a3c226a.tar.gz
--posix disables all extensions to regular expressions
2006-12-15 Paolo Bonzini <bonzini@gnu.org> * sed/regexp.c: Disable all extensions on --posix. git-archimport-id: bonzini@gnu.org--2004b/sed--stable--4.1--patch-84
Diffstat (limited to 'sed')
-rw-r--r--sed/execute.c13
-rw-r--r--sed/regexp.c23
-rw-r--r--sed/sed.c14
-rw-r--r--sed/sed.h3
-rw-r--r--sed/utils.c83
-rw-r--r--sed/utils.h1
6 files changed, 127 insertions, 10 deletions
diff --git a/sed/execute.c b/sed/execute.c
index 0ca2ca5..6b6632c 100644
--- a/sed/execute.c
+++ b/sed/execute.c
@@ -762,15 +762,22 @@ closedown(input)
if (in_place_extension && output_file.fp != NULL)
{
+ const char *target_name;
ck_fclose (output_file.fp);
+
+ if (follow_symlinks)
+ target_name = follow_symlink (input->in_file_name);
+ else
+ target_name = input->in_file_name;
+
if (strcmp(in_place_extension, "*") != 0)
{
- char *backup_file_name = get_backup_file_name(input->in_file_name);
- ck_rename (input->in_file_name, backup_file_name, input->out_file_name);
+ char *backup_file_name = get_backup_file_name(target_name);
+ ck_rename (target_name, backup_file_name, input->out_file_name);
free (backup_file_name);
}
- ck_rename (input->out_file_name, input->in_file_name, input->out_file_name);
+ ck_rename (input->out_file_name, target_name, input->out_file_name);
free (input->out_file_name);
}
diff --git a/sed/regexp.c b/sed/regexp.c
index 1297c5e..4daefe2 100644
--- a/sed/regexp.c
+++ b/sed/regexp.c
@@ -64,15 +64,24 @@ compile_regex_1 (new_regex, needed_sub)
const char *error;
int syntax = ((extended_regexp_flags & REG_EXTENDED)
? RE_SYNTAX_POSIX_EXTENDED
- : RE_SYNTAX_POSIX_BASIC)
- & ~RE_DOT_NOT_NULL;
-
- if (posixicity == POSIXLY_EXTENDED)
- syntax &= ~RE_UNMATCHED_RIGHT_PAREN_ORD;
- else
- syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD;
+ : RE_SYNTAX_POSIX_BASIC);
+ syntax &= ~RE_DOT_NOT_NULL;
syntax |= RE_NO_POSIX_BACKTRACKING;
+
+ switch (posixicity)
+ {
+ case POSIXLY_EXTENDED:
+ syntax &= ~RE_UNMATCHED_RIGHT_PAREN_ORD;
+ break;
+ case POSIXLY_CORRECT:
+ syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD;
+ break;
+ case POSIXLY_BASIC:
+ syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD | RE_LIMITED_OPS | RE_NO_GNU_OPS;
+ break;
+ }
+
#ifdef RE_ICASE
syntax |= (new_regex->flags & REG_ICASE) ? RE_ICASE : 0;
#endif
diff --git a/sed/sed.c b/sed/sed.c
index 178d2cf..e78cf4e 100644
--- a/sed/sed.c
+++ b/sed/sed.c
@@ -72,6 +72,9 @@ bool no_default_output = false;
/* If set, reset line counts on every new file. */
bool separate_files = false;
+/* If set, follow symlinks when processing in place */
+bool follow_symlinks = false;
+
/* How do we edit files in-place? (we don't if NULL) */
char *in_place_extension = NULL;
@@ -110,6 +113,10 @@ Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n\
add the script to the commands to be executed\n"));
fprintf(out, _(" -f script-file, --file=script-file\n\
add the contents of script-file to the commands to be executed\n"));
+#ifdef ENABLE_FOLLOW_SYMLINKS
+ fprintf(out, _(" --follow-symlinks\n\
+ follow symlinks when processing in place\n"));
+#endif
fprintf(out, _(" -i[SUFFIX], --in-place[=SUFFIX]\n\
edit files in place (makes backup if extension supplied)\n"));
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) || defined(__EMX__)
@@ -173,6 +180,9 @@ main(argc, argv)
{"unbuffered", 0, NULL, 'u'},
{"version", 0, NULL, 'v'},
{"help", 0, NULL, 'h'},
+#ifdef ENABLE_FOLLOW_SYMLINKS
+ {"follow-symlinks", 0, NULL, 'F'},
+#endif
{NULL, 0, NULL, 0}
};
@@ -226,6 +236,10 @@ main(argc, argv)
the_program = compile_file(the_program, optarg);
break;
+ case 'F':
+ follow_symlinks = true;
+ break;
+
case 'i':
separate_files = true;
if (optarg == NULL)
diff --git a/sed/sed.h b/sed/sed.h
index ce74db7..781fbdf 100644
--- a/sed/sed.h
+++ b/sed/sed.h
@@ -220,6 +220,9 @@ 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;
diff --git a/sed/utils.c b/sed/utils.c
index b4f0164..78bb2ff 100644
--- a/sed/utils.c
+++ b/sed/utils.c
@@ -35,6 +35,10 @@
# include <stdlib.h>
#endif /* HAVE_STDLIB_H */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
#include "utils.h"
const char *myname;
@@ -342,6 +346,85 @@ do_ck_fclose(fp)
}
+/* Follow symlink and panic if something fails. Return the ultimate
+ symlink target, stored in a temporary buffer that the caller should
+ not free. */
+const char *
+follow_symlink(const char *fname)
+{
+#ifdef ENABLE_FOLLOW_SYMLINKS
+ static char *buf1, *buf2;
+ static int buf_size;
+
+ struct stat statbuf;
+ const char *buf = fname, *c;
+ int rc;
+
+ if (buf_size == 0)
+ {
+ buf1 = ck_malloc (PATH_MAX + 1);
+ buf2 = ck_malloc (PATH_MAX + 1);
+ buf_size = PATH_MAX + 1;
+ }
+
+ while ((rc = lstat (buf, &statbuf)) == 0
+ && (statbuf.st_mode & S_IFLNK) == S_IFLNK)
+ {
+ if (buf == buf2)
+ {
+ strcpy (buf1, buf2);
+ buf = buf1;
+ }
+
+ while ((rc = readlink (buf, buf2, buf_size)) == buf_size)
+ {
+ buf_size *= 2;
+ buf1 = ck_realloc (buf1, buf_size);
+ buf2 = ck_realloc (buf2, buf_size);
+ }
+ if (rc < 0)
+ panic (_("couldn't follow symlink %s: %s"), buf, strerror(errno));
+ else
+ buf2 [rc] = '\0';
+
+ if (buf2[0] != '/' && (c = strrchr (buf, '/')) != NULL)
+ {
+ /* Need to handle relative paths with care. Reallocate buf1 and
+ buf2 to be big enough. */
+ int len = c - buf + 1;
+ if (len + rc + 1 > buf_size)
+ {
+ buf_size = len + rc + 1;
+ buf1 = ck_realloc (buf1, buf_size);
+ buf2 = ck_realloc (buf2, buf_size);
+ }
+
+ /* Always store the new path in buf1. */
+ if (buf != buf1)
+ memcpy (buf1, buf, len);
+
+ /* Tack the relative symlink at the end of buf1. */
+ memcpy (buf1 + len, buf2, rc + 1);
+ buf = buf1;
+ }
+ else
+ {
+ /* Use buf2 as the buffer, it saves a strcpy if it is not pointing to
+ another link. It works for absolute symlinks, and as long as
+ symlinks do not leave the current directory. */
+ buf = buf2;
+ }
+ }
+
+ if (rc < 0)
+ panic (_("cannot stat %s: %s"), buf, strerror(errno));
+
+ return buf;
+#else
+ return fname;
+#endif /* ENABLE_FOLLOW_SYMLINKS */
+}
+
/* Panic on failing rename */
void
ck_rename (from, to, unlink_if_fail)
diff --git a/sed/utils.h b/sed/utils.h
index cef0f6d..a80202d 100644
--- a/sed/utils.h
+++ b/sed/utils.h
@@ -28,6 +28,7 @@ void ck_fwrite P_((const VOID *ptr, size_t size, size_t nmemb, FILE *stream));
size_t ck_fread P_((VOID *ptr, size_t size, size_t nmemb, FILE *stream));
void ck_fflush P_((FILE *stream));
void ck_fclose P_((FILE *stream));
+const char *follow_symlink P_((const char *path));
size_t ck_getline P_((char **text, size_t *buflen, FILE *stream));
FILE * ck_mkstemp P_((char **p_filename, char *tmpdir, char *base));
void ck_rename P_((const char *from, const char *to, const char *unlink_if_fail));