/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Remove all conversion flags; '-' is the only one valid
* with %s, and it's not useful here.
*/
pr->flags = F_BPAD;
pr->cchar[0] = 's';
pr->cchar[1] = '\0';
for (p1 = pr->fmt; *p1 != '%'; ++p1);
for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1);
while ((*p2++ = *p1++) != '\0');
}
static char **_argv;
static u_char *
get(void)
{
static int ateof = 1;
static u_char *curp, *savp;
int n;
int need, nread;
u_char *tmpp;
if (!curp) {
curp = ecalloc(blocksize, 1);
savp = ecalloc(blocksize, 1);
} else {
tmpp = curp;
curp = savp;
savp = tmpp;
address += blocksize;
}
for (need = blocksize, nread = 0;;) {
/*
* if read the right number of bytes, or at EOF for one file,
* and no other files are available, zero-pad the rest of the
* block and set the end flag.
*/
if (!length || (ateof && !next())) {
if (need == blocksize)
return NULL ;
if (!need && vflag != ALL &&
!memcmp(curp, savp, nread)) {
if (vflag != DUP)
(void)printf("*\n");
return NULL ;
}
memset((char *)curp + nread, 0, need);
eaddress = address + nread;
return curp ;
}
n = fread((char *)curp + nread, sizeof(u_char),
length == -1 ? need : MIN(length, need), stdin);
if (!n) {
if (ferror(stdin))
warn("%s", _argv[-1]);
ateof = 1;
continue;
}
ateof = 0;
if (length != -1)
length -= n;
if (!(need -= n)) {
if (vflag == ALL || vflag == FIRST ||
memcmp(curp, savp, blocksize)) {
if (vflag == DUP || vflag == FIRST)
vflag = WAIT;
return curp ;
}
if (vflag == WAIT)
(void)printf("*\n");
vflag = DUP;
address += blocksize;
need = blocksize;
nread = 0;
}
else
nread += n;
}
}
/*
* Save argv for later retrieval.
*/
void
stashargv(char **argv)
{
_argv = argv;
}
/*
* Get the next file. The idea with the twisty logic seems to be to
* either read N filenames from argv and then exit, or if there aren't
* any, to use stdin and then exit. It should probably be simplified.
* The "done" flag doesn't mean "we are done", it means "we are done
* once we run out of filenames".
*
* Is there any reason not to remove the logic that inhibits
* calling fstat if using stdin and not a filename? It should be safe
* to call fstat on any fd. Yes, because on stdin it st_size will not
* convey useful information. In addition on kernfs/procfs stat might
* not return proper size info.
*
* Note: I have ruled that if there is one file on the command line
* and it doesn't open, we should exit after complaining about it and
* not then proceed to read stdin; the latter seems like unexpected
* and undesirable behavior. Also, it didn't work anyway, because the
* freopen call clobbers stdin while failing. -- dholland 20160303
*/
int
next(void)
{
static int done;
int statok;
for (;;) {
if (*_argv) {
done = 1;
if (!(freopen(*_argv, "r", stdin))) {
warn("%s", *_argv);
exitval = 1;
++_argv;
continue;
}
statok = 1;
} else {
if (done++)
return 0 ;
statok = 0;
}
if (skip)
doskip(statok ? *_argv : "stdin", statok);
if (*_argv)
++_argv;
if (!skip)
return 1 ;
}
/* NOTREACHED */
}
void
doskip(const char *fname, int statok)
{
int cnt;
struct stat sb;