#include <ctype.h>
#include <err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void head(FILE *, size_t);
static void head_bytes(FILE *, size_t);
static void obsolete(char *[]);
static void usage(void) __dead2;
int
main(int argc, char **argv)
{
int ch;
FILE *fp;
bool first;
bool qflag = false, vflag = false;
int linecnt = -1, bytecnt = -1, eval = 0;
char *ep;
obsolete(argv);
while ((ch = getopt(argc, argv, "c:n:qv")) != -1) {
switch(ch) {
case 'c':
bytecnt = strtol(optarg, &ep, 10);
if (*ep != 0 || bytecnt <= 0)
errx(1, "illegal byte count -- %s", optarg);
break;
case 'n':
linecnt = strtol(optarg, &ep, 10);
if (*ep != 0 || linecnt <= 0)
errx(1, "illegal line count -- %s", optarg);
break;
case 'q':
qflag = true;
vflag = false;
break;
case 'v':
vflag = true;
qflag = false;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (linecnt != -1 && bytecnt != -1)
errx(1, "can't combine line and byte counts");
if (linecnt == -1 )
linecnt = 10;
if (*argv) {
first = true;
for (; *argv; ++argv) {
if ((fp = fopen(*argv, "r")) == NULL) {
warn("%s", *argv);
eval = 1;
continue;
}
if (vflag || (!qflag && argc > 1)) {
printf("%s==> %s <==\n",
first ? "" : "\n", *argv);
first = false;
}
if (bytecnt == -1)
head(fp, linecnt);
else
head_bytes(fp, bytecnt);
fclose(fp);
}
} else if (bytecnt == -1)
head(stdin, linecnt);
else
head_bytes(stdin, bytecnt);
exit(eval);
}
static void
head(FILE *fp, size_t cnt)
{
char *cp;
size_t error, readlen;
while (cnt && (cp = fgetln(fp, &readlen)) != NULL) {
error = fwrite(cp, sizeof(char), readlen, stdout);
if (error != readlen)
err(1, "stdout");
cnt--;
}
}
static void
head_bytes(FILE *fp, size_t cnt)
{
char buf[4096];
size_t readlen;
while (cnt) {
if (cnt < sizeof(buf))
readlen = cnt;
else
readlen = sizeof(buf);
readlen = fread(buf, sizeof(char), readlen, fp);
if (readlen == 0)
break;
if (fwrite(buf, sizeof(char), readlen, stdout) != readlen)
err(1, "stdout");
cnt -= readlen;
}
}
static void
obsolete(char **argv)
{
char *ap;
while ((ap = *++argv)) {
if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1]))
return;
if ((ap = malloc(strlen(*argv) + 2)) == NULL)
err(1, "malloc failed");
ap[0] = '-';
ap[1] = 'n';
strcpy(ap + 2, *argv + 1);
*argv = ap;
}
}
static void __dead2
usage(void)
{
fprintf(stderr,
"usage: head [-q | -v] [-n lines | -c bytes] [file ...]\n");
exit(1);
}