mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 03:32:24 +00:00
Fix handling of files without newlines in the head
and tail
builtins (#365)
The head and tail builtins don't correctly handle files that lack newlines[*]: $ print -n foo > /tmp/bar $ /opt/ast/bin/head -1 /tmp/bar # No output $ print -n 'foo\nbar' > /tmp/bar $ /opt/ast/bin/tail -1 /tmp/bar foo bar$ This commit backports the required changes from ksh93v- to handle files without a newline in the head and tail builtins. (Also note that the required fix to sfmove was already backported in commit 1bd06207.) src/lib/libcmd/{head,tail}.c: - Backport the relevant ksh93v- code for handling files without newlines. src/cmd/ksh93/tests/builtins.sh: - Add a few regression tests for using 'head -1' and 'tail -1' on a file missing and ending newline. [*]: https://www.illumos.org/issues/4149
This commit is contained in:
parent
beccb93fd4
commit
2b8eaa6609
4 changed files with 52 additions and 12 deletions
3
NEWS
3
NEWS
|
@ -15,6 +15,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
|||
return value that fits in a signed integer, typically a 32-bit value.
|
||||
Note that $? is truncated to 8 bits when the current (sub)shell exits.
|
||||
|
||||
- The head and tail builtins now correctly handle files that do not have an
|
||||
ending newline. (Note that the tail builtin is not compiled in by default.)
|
||||
|
||||
2021-12-05:
|
||||
|
||||
- Fixed an issue on illumos that caused some parameters in the getconf
|
||||
|
|
|
@ -1396,5 +1396,22 @@ got=$?; exp=1
|
|||
got=$?; exp=2
|
||||
(( got == exp )) || err_exit "cd -eP to empty string has wrong exit status (expected $exp, got $got)"
|
||||
|
||||
# ======
|
||||
# The head and tail builtins should work on files without newlines
|
||||
if builtin head 2> /dev/null; then
|
||||
print -n nonewline > "$tmp/nonewline"
|
||||
exp=nonewline
|
||||
got=$(head -1 "$tmp/nonewline")
|
||||
[[ $got == $exp ]] || err_exit "head builtin fails to correctly handle files without an ending newline" \
|
||||
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
fi
|
||||
if builtin tail 2> /dev/null; then
|
||||
print -n 'newline\nnonewline' > "$tmp/nonewline"
|
||||
exp=nonewline
|
||||
got=$(tail -1 "$tmp/nonewline")
|
||||
[[ $got == $exp ]] || err_exit "tail builtin fails to correctly handle files without an ending newline" \
|
||||
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
fi
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/***********************************************************************
|
||||
* *
|
||||
* This software is part of the ast package *
|
||||
* Copyright (c) 1992-2012 AT&T Intellectual Property *
|
||||
* Copyright (c) 1992-2013 AT&T Intellectual Property *
|
||||
* Copyright (c) 2020-2021 Contributors to ksh 93u+m *
|
||||
* and is licensed under the *
|
||||
* Eclipse Public License, Version 1.0 *
|
||||
|
@ -15,8 +15,8 @@
|
|||
* AT&T Research *
|
||||
* Florham Park NJ *
|
||||
* *
|
||||
* Glenn Fowler <gsf@research.att.com> *
|
||||
* David Korn <dgk@research.att.com> *
|
||||
* Glenn Fowler <glenn.s.fowler@gmail.com> *
|
||||
* David Korn <dgkorn@gmail.com> *
|
||||
* *
|
||||
***********************************************************************/
|
||||
#pragma prototyped
|
||||
|
@ -28,7 +28,7 @@
|
|||
*/
|
||||
|
||||
static const char usage[] =
|
||||
"[-n?\n@(#)$Id: head (AT&T Research) 2012-05-31 $\n]"
|
||||
"[-n?\n@(#)$Id: head (AT&T Research) 2013-09-19 $\n]"
|
||||
"[--catalog?" ERROR_CATALOG "]"
|
||||
"[+NAME?head - output beginning portion of one or more files ]"
|
||||
"[+DESCRIPTION?\bhead\b copies one or more input files to standard "
|
||||
|
@ -81,6 +81,7 @@ b_head(int argc, register char** argv, Shbltin_t* context)
|
|||
register off_t keep = 10;
|
||||
register off_t skip = 0;
|
||||
register int delim = '\n';
|
||||
off_t moved;
|
||||
int header = 1;
|
||||
char* format = (char*)header_fmt+1;
|
||||
|
||||
|
@ -145,9 +146,16 @@ b_head(int argc, register char** argv, Shbltin_t* context)
|
|||
sfprintf(sfstdout, format, cp);
|
||||
format = (char*)header_fmt;
|
||||
if (skip > 0)
|
||||
sfmove(fp, NiL, skip, delim);
|
||||
if (sfmove(fp, sfstdout, keep, delim) < 0 && !ERROR_PIPE(errno) && errno != EINTR)
|
||||
{
|
||||
if ((moved = sfmove(fp, NiL, skip, delim)) < 0 && !ERROR_PIPE(errno) && errno != EINTR)
|
||||
error(ERROR_system(0), "%s: skip error", cp);
|
||||
if (delim >= 0 && moved < skip)
|
||||
goto next;
|
||||
}
|
||||
if ((moved = sfmove(fp, sfstdout, keep, delim)) < 0 && !ERROR_PIPE(errno) && errno != EINTR ||
|
||||
delim >= 0 && moved < keep && sfmove(fp, sfstdout, SF_UNBOUND, -1) < 0 && !ERROR_PIPE(errno) && errno != EINTR)
|
||||
error(ERROR_system(0), "%s: read error", cp);
|
||||
next:
|
||||
if (fp != sfstdin)
|
||||
sfclose(fp);
|
||||
} while (cp = *argv++);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/***********************************************************************
|
||||
* *
|
||||
* This software is part of the ast package *
|
||||
* Copyright (c) 1992-2012 AT&T Intellectual Property *
|
||||
* Copyright (c) 1992-2013 AT&T Intellectual Property *
|
||||
* Copyright (c) 2020-2021 Contributors to ksh 93u+m *
|
||||
* and is licensed under the *
|
||||
* Eclipse Public License, Version 1.0 *
|
||||
|
@ -15,8 +15,8 @@
|
|||
* AT&T Research *
|
||||
* Florham Park NJ *
|
||||
* *
|
||||
* Glenn Fowler <gsf@research.att.com> *
|
||||
* David Korn <dgk@research.att.com> *
|
||||
* Glenn Fowler <glenn.s.fowler@gmail.com> *
|
||||
* David Korn <dgkorn@gmail.com> *
|
||||
* *
|
||||
***********************************************************************/
|
||||
#pragma prototyped
|
||||
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
static const char usage[] =
|
||||
"+[-?\n@(#)$Id: tail (AT&T Research) 2012-10-10 $\n]"
|
||||
"+[-?\n@(#)$Id: tail (AT&T Research) 2013-09-19 $\n]"
|
||||
"[--catalog?" ERROR_CATALOG "]"
|
||||
"[+NAME?tail - output trailing portion of one or more files ]"
|
||||
"[+DESCRIPTION?\btail\b copies one or more input files to standard output "
|
||||
|
@ -164,6 +164,7 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim)
|
|||
register Sfoff_t last;
|
||||
register char* s;
|
||||
register char* t;
|
||||
unsigned char incomplete;
|
||||
struct stat st;
|
||||
|
||||
last = sfsize(fp);
|
||||
|
@ -175,6 +176,7 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim)
|
|||
return first;
|
||||
return offset;
|
||||
}
|
||||
incomplete = 1;
|
||||
for (;;)
|
||||
{
|
||||
if ((offset = last - SF_BUFSIZE) < first)
|
||||
|
@ -184,6 +186,15 @@ tailpos(register Sfio_t* fp, register Sfoff_t number, int delim)
|
|||
if (!(s = sfreserve(fp, n, SF_LOCKR)))
|
||||
return -1;
|
||||
t = s + n;
|
||||
if (incomplete)
|
||||
{
|
||||
if (t > s && *(t - 1) != delim && number-- <= 0)
|
||||
{
|
||||
sfread(fp, s, 0);
|
||||
return offset + (t - s);
|
||||
}
|
||||
incomplete = 0;
|
||||
}
|
||||
while (t > s)
|
||||
if (*--t == delim && number-- <= 0)
|
||||
{
|
||||
|
@ -415,6 +426,7 @@ b_tail(int argc, char** argv, Shbltin_t* context)
|
|||
char* t;
|
||||
char* r;
|
||||
char* file;
|
||||
Sfoff_t moved;
|
||||
Sfoff_t offset;
|
||||
Sfoff_t number = DEFAULT;
|
||||
unsigned long timeout = 0;
|
||||
|
@ -765,8 +777,8 @@ b_tail(int argc, char** argv, Shbltin_t* context)
|
|||
if (number < 0 || !number && (flags & POSITIVE))
|
||||
{
|
||||
sfset(ip, SF_SHARE, 1);
|
||||
if (number < -1)
|
||||
sfmove(ip, NiL, -number - 1, delim);
|
||||
if (number < -1 && (moved = sfmove(ip, NiL, -(number + 1), delim)) >= 0 && delim >= 0 && moved < -(number + 1))
|
||||
(void)sfgetr(ip, delim, SF_LASTR);
|
||||
if (flags & REVERSE)
|
||||
rev_line(ip, sfstdout, sfseek(ip, (Sfoff_t)0, SEEK_CUR));
|
||||
else
|
||||
|
|
Loading…
Reference in a new issue