summaryrefslogtreecommitdiff
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
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
-rw-r--r--ChangeLog4
-rw-r--r--NEWS12
-rw-r--r--configure.ac7
-rw-r--r--doc/sed.14
-rw-r--r--po/it.po91
-rw-r--r--po/sed.pot81
-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
12 files changed, 259 insertions, 77 deletions
diff --git a/ChangeLog b/ChangeLog
index 288ae2b..304081a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-12-15 Paolo Bonzini <bonzini@gnu.org>
+
+ * sed/regexp.c: Disable all extensions on --posix.
+
2006-09-24 Paolo Bonzini <bonzini@gnu.org>
* sed/execute.c: Support ACLs.
diff --git a/NEWS b/NEWS
index b4c01df..184d2ff 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,15 @@
+Sed 4.1b (release candidate for sed 4.2)
+
+* --posix disables all extensions to regular expressions.
+
+* new option --follow-symlinks, available when editing a file in-place.
+ This option may not be available on some systems (in this case, the
+ option will *not* be a no-op; it will be completely unavailable).
+ In the future, the option may be added as a no-op on systems without
+ symbolic links at all, since in this case a no-op is effectively
+ indistinguishable from a correct implementation.
+
+----------------------------------------------------------------------------
Sed 4.1a (release candidate for sed 4.2)
* much improved portability
diff --git a/configure.ac b/configure.ac
index 53f2335..2fa56a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,13 @@ enable_html=no)
AM_CONDITIONAL(BUILD_HTML, test "x$enable_html" != xno)
+# Check whether we are able to follow symlinks
+AC_CHECK_FUNC(lstat, have_lstat=yes)
+AC_CHECK_FUNC(readlink, have_readlink=yes)
+if test "x$have_lstat" = xyes -a "x$have_readlink" = xyes; then
+ AC_DEFINE(ENABLE_FOLLOW_SYMLINKS, ,[Follow symlinks when processing in place])
+fi
+
: ${TEXI2HTML=texi2html -monolithic}
AC_SUBST(TEXI2HTML)
diff --git a/doc/sed.1 b/doc/sed.1
index 3dfe77d..60b3289 100644
--- a/doc/sed.1
+++ b/doc/sed.1
@@ -32,6 +32,10 @@ add the script to the commands to be executed
.IP
add the contents of script-file to the commands to be executed
.HP
+\fB\-\-follow\-symlinks\fR
+.IP
+follow symlinks when processing in place
+.HP
\fB\-i[SUFFIX]\fR, \fB\-\-in\-place\fR[=\fISUFFIX\fR]
.IP
edit files in place (makes backup if extension supplied)
diff --git a/po/it.po b/po/it.po
index 6ea4c90..918ac54 100644
--- a/po/it.po
+++ b/po/it.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: sed 4.0a\n"
"Report-Msgid-Bugs-To: bonzini@gnu.org\n"
-"POT-Creation-Date: 2006-09-24 17:42+0200\n"
+"POT-Creation-Date: 2006-11-28 17:57+0100\n"
"PO-Revision-Date: 2002-11-26 12:44+0100\n"
"Last-Translator: Paolo Bonzini <bonzini@gnu.org>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
@@ -175,27 +175,27 @@ msgid "couldn't edit %s: not a regular file"
msgstr "impossibile modificare %s: non è un file normale"
# lib/utils.c:131
-#: sed/execute.c:735 sed/utils.c:229
+#: sed/execute.c:735 sed/utils.c:233
#, c-format
msgid "couldn't open temporary file %s: %s"
msgstr "impossibile aprire il file temporaneo %s: %s"
# sed/execute.c:1003 sed/execute.c:1183
-#: sed/execute.c:1258 sed/execute.c:1438
+#: sed/execute.c:1265 sed/execute.c:1445
msgid "error in subprocess"
msgstr "errore in un sottoprocesso"
# sed/execute.c:1005
-#: sed/execute.c:1260
+#: sed/execute.c:1267
msgid "option `e' not supported"
msgstr "opzione `e' non supportata"
# sed/execute.c:1185
-#: sed/execute.c:1440
+#: sed/execute.c:1447
msgid "`e' command not supported"
msgstr "comando `e' non supportato"
-#: sed/execute.c:1780
+#: sed/execute.c:1787
msgid "no input files"
msgstr "nessun file in ingresso"
@@ -216,7 +216,7 @@ msgid "invalid reference \\%d on `s' command's RHS"
msgstr "riferimento non valido \\%d nel secondo membro del comando `s'"
# sed/sed.c:98
-#: sed/sed.c:98
+#: sed/sed.c:101
msgid ""
" -R, --regexp-perl\n"
" use Perl 5's regular expressions syntax in the script.\n"
@@ -224,7 +224,7 @@ msgstr ""
" -R, --regexp-perl\n"
" usa la sintassi Perl 5 per le espressioni regolari\n"
-#: sed/sed.c:103
+#: sed/sed.c:106
#, c-format
msgid ""
"Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n"
@@ -234,7 +234,7 @@ msgstr ""
"file]...\n"
"\n"
-#: sed/sed.c:107
+#: sed/sed.c:110
#, c-format
msgid ""
" -n, --quiet, --silent\n"
@@ -243,7 +243,7 @@ msgstr ""
" -n, --quiet, --silent\n"
" sopprime la stampa automatica del pattern space\n"
-#: sed/sed.c:109
+#: sed/sed.c:112
#, c-format
msgid ""
" -e script, --expression=script\n"
@@ -252,7 +252,7 @@ msgstr ""
" -e script, --expression=script\n"
" aggiunge lo script ai comandi da eseguire\n"
-#: sed/sed.c:111
+#: sed/sed.c:114
#, c-format
msgid ""
" -f script-file, --file=script-file\n"
@@ -263,7 +263,16 @@ msgstr ""
" aggiunge il contenuto di file-script ai comandi da "
"eseguire\n"
-#: sed/sed.c:113
+#: sed/sed.c:117
+#, c-format
+msgid ""
+" --follow-symlinks\n"
+" follow symlinks when processing in place\n"
+msgstr ""
+" --follow-symlinks\n"
+" segue i link simbolici quando viene utilizzato -i\n"
+
+#: sed/sed.c:120
#, c-format
msgid ""
" -i[SUFFIX], --in-place[=SUFFIX]\n"
@@ -273,7 +282,7 @@ msgstr ""
" scrive il risultato sul file originale (facendo una copia\n"
" se è fornita un'estensione)\n"
-#: sed/sed.c:116
+#: sed/sed.c:123
#, c-format
msgid ""
" -b, --binary\n"
@@ -284,7 +293,7 @@ msgstr ""
" apre i file in modo binario (lasciando le sequenze CR"
"+LF se è immutate)\n"
-#: sed/sed.c:119
+#: sed/sed.c:126
#, c-format
msgid ""
" -l N, --line-length=N\n"
@@ -294,7 +303,7 @@ msgstr ""
" specifica la lunghezza delle linee generate dal comando "
"`l'\n"
-#: sed/sed.c:121
+#: sed/sed.c:128
#, c-format
msgid ""
" --posix\n"
@@ -304,7 +313,7 @@ msgstr ""
" disabilita tutte le estensioni GNU.\n"
# sed/sed.c:98
-#: sed/sed.c:123
+#: sed/sed.c:130
#, c-format
msgid ""
" -r, --regexp-extended\n"
@@ -313,7 +322,7 @@ msgstr ""
" -r, --regexp-extended\n"
" usa la sintassi di `egrep' per le espressioni regolari\n"
-#: sed/sed.c:126
+#: sed/sed.c:133
#, c-format
msgid ""
" -s, --separate\n"
@@ -325,7 +334,7 @@ msgstr ""
" considera i file di input come separati invece che come un\n"
" unico file lungo.\n"
-#: sed/sed.c:129
+#: sed/sed.c:136
#, c-format
msgid ""
" -u, --unbuffered\n"
@@ -336,17 +345,17 @@ msgstr ""
" -u, --unbuffered\n"
" carica e visualizza i dati una a pezzetti piu' piccoli\n"
-#: sed/sed.c:132
+#: sed/sed.c:139
#, c-format
msgid " --help display this help and exit\n"
msgstr " --help mostra questo aiuto ed esce\n"
-#: sed/sed.c:133
+#: sed/sed.c:140
#, c-format
msgid " --version output version information and exit\n"
msgstr " --version stampa le informazioni sulla versione ed esce\n"
-#: sed/sed.c:134
+#: sed/sed.c:141
#, c-format
msgid ""
"\n"
@@ -366,7 +375,7 @@ msgstr ""
"\n"
# sed/sed.c:132
-#: sed/sed.c:140
+#: sed/sed.c:147
#, c-format
msgid ""
"E-mail bug reports to: %s .\n"
@@ -376,13 +385,13 @@ msgstr ""
"Assicurarsi di includere la parola ``%s'' nell'oggetto del messaggio.\n"
# sed/sed.c:255
-#: sed/sed.c:285
+#: sed/sed.c:299
#, c-format
msgid "super-sed version %s\n"
msgstr "super-sed versione %s\n"
# sed/sed.c:256
-#: sed/sed.c:286
+#: sed/sed.c:300
#, c-format
msgid ""
"based on GNU sed version %s\n"
@@ -392,13 +401,13 @@ msgstr ""
"\n"
# sed/sed.c:258
-#: sed/sed.c:288
+#: sed/sed.c:302
#, c-format
msgid "GNU sed version %s\n"
msgstr "GNU sed versione %s\n"
# sed/sed.c:260
-#: sed/sed.c:290
+#: sed/sed.c:304
#, c-format
msgid ""
"%s\n"
@@ -413,39 +422,51 @@ msgstr ""
"SCOPO, nei limiti permessi dalla legge.\n"
# sed/execute.c:516
-#: sed/utils.c:98 sed/utils.c:363
+#: sed/utils.c:102 sed/utils.c:446
#, c-format
msgid "cannot remove %s: %s"
msgstr "impossibile rimuovere %s: %s"
# lib/utils.c:131
-#: sed/utils.c:168
+#: sed/utils.c:172
#, c-format
msgid "couldn't open file %s: %s"
msgstr "impossibile aprire il file %s: %s"
# lib/utils.c:161
-#: sed/utils.c:192
+#: sed/utils.c:196
#, c-format
msgid "couldn't attach to %s: %s"
-msgstr "Impossibile accedere a %s: %s"
+msgstr "impossibile accedere a %s: %s"
# lib/utils.c:161
-#: sed/utils.c:247
+#: sed/utils.c:251
#, c-format
msgid "couldn't write %d item to %s: %s"
msgid_plural "couldn't write %d items to %s: %s"
-msgstr[0] "Impossibile scrivere %d elemento su %s: %s"
-msgstr[1] "Impossibile scrivere %d elementi su %s: %s"
+msgstr[0] "impossibile scrivere %d elemento su %s: %s"
+msgstr[1] "impossibile scrivere %d elementi su %s: %s"
# lib/utils.c:176
-#: sed/utils.c:262 sed/utils.c:278
+#: sed/utils.c:266 sed/utils.c:282
#, c-format
msgid "read error on %s: %s"
msgstr "errore di lettura su %s: %s"
+# lib/utils.c:131
+#: sed/utils.c:386
+#, c-format
+msgid "couldn't follow symlink %s: %s"
+msgstr "impossibile seguire il link simbolico %s: %s"
+
+# sed/execute.c:516
+#: sed/utils.c:420
+#, c-format
+msgid "cannot stat %s: %s"
+msgstr "impossibile ottenere informazioni su %s: %s"
+
# sed/execute.c:516
-#: sed/utils.c:368
+#: sed/utils.c:451
#, c-format
msgid "cannot rename %s: %s"
msgstr "impossibile rinominare %s: %s"
diff --git a/po/sed.pot b/po/sed.pot
index 54ccd69..883286e 100644
--- a/po/sed.pot
+++ b/po/sed.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: bonzini@gnu.org\n"
-"POT-Creation-Date: 2006-09-24 17:42+0200\n"
+"POT-Creation-Date: 2006-11-28 17:57+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -148,24 +148,24 @@ msgstr ""
msgid "couldn't edit %s: not a regular file"
msgstr ""
-#: sed/execute.c:735 sed/utils.c:229
+#: sed/execute.c:735 sed/utils.c:233
#, c-format
msgid "couldn't open temporary file %s: %s"
msgstr ""
-#: sed/execute.c:1258 sed/execute.c:1438
+#: sed/execute.c:1265 sed/execute.c:1445
msgid "error in subprocess"
msgstr ""
-#: sed/execute.c:1260
+#: sed/execute.c:1267
msgid "option `e' not supported"
msgstr ""
-#: sed/execute.c:1440
+#: sed/execute.c:1447
msgid "`e' command not supported"
msgstr ""
-#: sed/execute.c:1780
+#: sed/execute.c:1787
msgid "no input files"
msgstr ""
@@ -182,34 +182,34 @@ msgstr ""
msgid "invalid reference \\%d on `s' command's RHS"
msgstr ""
-#: sed/sed.c:98
+#: sed/sed.c:101
msgid ""
" -R, --regexp-perl\n"
" use Perl 5's regular expressions syntax in the script.\n"
msgstr ""
-#: sed/sed.c:103
+#: sed/sed.c:106
#, c-format
msgid ""
"Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n"
"\n"
msgstr ""
-#: sed/sed.c:107
+#: sed/sed.c:110
#, c-format
msgid ""
" -n, --quiet, --silent\n"
" suppress automatic printing of pattern space\n"
msgstr ""
-#: sed/sed.c:109
+#: sed/sed.c:112
#, c-format
msgid ""
" -e script, --expression=script\n"
" add the script to the commands to be executed\n"
msgstr ""
-#: sed/sed.c:111
+#: sed/sed.c:114
#, c-format
msgid ""
" -f script-file, --file=script-file\n"
@@ -217,14 +217,21 @@ msgid ""
"executed\n"
msgstr ""
-#: sed/sed.c:113
+#: sed/sed.c:117
+#, c-format
+msgid ""
+" --follow-symlinks\n"
+" follow symlinks when processing in place\n"
+msgstr ""
+
+#: sed/sed.c:120
#, c-format
msgid ""
" -i[SUFFIX], --in-place[=SUFFIX]\n"
" edit files in place (makes backup if extension supplied)\n"
msgstr ""
-#: sed/sed.c:116
+#: sed/sed.c:123
#, c-format
msgid ""
" -b, --binary\n"
@@ -232,28 +239,28 @@ msgid ""
"specially)\n"
msgstr ""
-#: sed/sed.c:119
+#: sed/sed.c:126
#, c-format
msgid ""
" -l N, --line-length=N\n"
" specify the desired line-wrap length for the `l' command\n"
msgstr ""
-#: sed/sed.c:121
+#: sed/sed.c:128
#, c-format
msgid ""
" --posix\n"
" disable all GNU extensions.\n"
msgstr ""
-#: sed/sed.c:123
+#: sed/sed.c:130
#, c-format
msgid ""
" -r, --regexp-extended\n"
" use extended regular expressions in the script.\n"
msgstr ""
-#: sed/sed.c:126
+#: sed/sed.c:133
#, c-format
msgid ""
" -s, --separate\n"
@@ -262,7 +269,7 @@ msgid ""
" long stream.\n"
msgstr ""
-#: sed/sed.c:129
+#: sed/sed.c:136
#, c-format
msgid ""
" -u, --unbuffered\n"
@@ -271,17 +278,17 @@ msgid ""
" the output buffers more often\n"
msgstr ""
-#: sed/sed.c:132
+#: sed/sed.c:139
#, c-format
msgid " --help display this help and exit\n"
msgstr ""
-#: sed/sed.c:133
+#: sed/sed.c:140
#, c-format
msgid " --version output version information and exit\n"
msgstr ""
-#: sed/sed.c:134
+#: sed/sed.c:141
#, c-format
msgid ""
"\n"
@@ -292,31 +299,31 @@ msgid ""
"\n"
msgstr ""
-#: sed/sed.c:140
+#: sed/sed.c:147
#, c-format
msgid ""
"E-mail bug reports to: %s .\n"
"Be sure to include the word ``%s'' somewhere in the ``Subject:'' field.\n"
msgstr ""
-#: sed/sed.c:285
+#: sed/sed.c:299
#, c-format
msgid "super-sed version %s\n"
msgstr ""
-#: sed/sed.c:286
+#: sed/sed.c:300
#, c-format
msgid ""
"based on GNU sed version %s\n"
"\n"
msgstr ""
-#: sed/sed.c:288
+#: sed/sed.c:302
#, c-format
msgid "GNU sed version %s\n"
msgstr ""
-#: sed/sed.c:290
+#: sed/sed.c:304
#, c-format
msgid ""
"%s\n"
@@ -325,34 +332,44 @@ msgid ""
"to the extent permitted by law.\n"
msgstr ""
-#: sed/utils.c:98 sed/utils.c:363
+#: sed/utils.c:102 sed/utils.c:446
#, c-format
msgid "cannot remove %s: %s"
msgstr ""
-#: sed/utils.c:168
+#: sed/utils.c:172
#, c-format
msgid "couldn't open file %s: %s"
msgstr ""
-#: sed/utils.c:192
+#: sed/utils.c:196
#, c-format
msgid "couldn't attach to %s: %s"
msgstr ""
-#: sed/utils.c:247
+#: sed/utils.c:251
#, c-format
msgid "couldn't write %d item to %s: %s"
msgid_plural "couldn't write %d items to %s: %s"
msgstr[0] ""
msgstr[1] ""
-#: sed/utils.c:262 sed/utils.c:278
+#: sed/utils.c:266 sed/utils.c:282
#, c-format
msgid "read error on %s: %s"
msgstr ""
-#: sed/utils.c:368
+#: sed/utils.c:386
+#, c-format
+msgid "couldn't follow symlink %s: %s"
+msgstr ""
+
+#: sed/utils.c:420
+#, c-format
+msgid "cannot stat %s: %s"
+msgstr ""
+
+#: sed/utils.c:451
#, c-format
msgid "cannot rename %s: %s"
msgstr ""
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));