master xplshn/aruu / cmd / posix / head.c
 1/* See LICENSE file for copyright and license details. */
 2
 3
 4#include <stdint.h>
 5#include <stdio.h>
 6#include <stdlib.h>
 7#include <string.h>
 8
 9#include "util.h"
10
11static void
12head(FILE *fp, const char *fname, size_t n)
13{
14	char *buf = NULL;
15	size_t i = 0, size = 0;
16	ssize_t len;
17
18	while (i < n && (len = getline(&buf, &size, fp)) > 0) {
19		fwrite(buf, 1, len, stdout);
20		i += (len && (buf[len - 1] == '\n'));
21	}
22	free(buf);
23	if (ferror(fp))
24		eprintf("getline %s:", fname);
25}
26
27static void
28usage(void)
29{
30	eprintf("usage: %s [-num | -n num] [file ...]\n", argv0);
31}
32
33// ?man head: output first part of files
34// ?man arguments: file ...
35// ?man print the first lines or bytes of files
36int
37main(int argc, char *argv[])
38{
39	size_t n = 10;
40	FILE *fp;
41	int ret = 0, newline = 0, many = 0;
42
43	ARGBEGIN {
44	// ?man -n:num: print line numbers or counts
45	case 'n':
46		n = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
47		break;
48	// ?man ARGNUM: specify RGNUM option
49	ARGNUM:
50		n = ARGNUMF();
51		break;
52	default:
53		usage();
54	} ARGEND
55
56	if (!argc) {
57		head(stdin, "<stdin>", n);
58	} else {
59		many = argc > 1;
60		for (newline = 0; *argv; argc--, argv++) {
61			if (!strcmp(*argv, "-")) {
62				*argv = "<stdin>";
63				fp = stdin;
64			} else if (!(fp = fopen(*argv, "r"))) {
65				weprintf("fopen %s:", *argv);
66				ret = 1;
67				continue;
68			}
69			if (many) {
70				if (newline)
71					putchar('\n');
72				printf("==> %s <==\n", *argv);
73			}
74			newline = 1;
75			head(fp, *argv, n);
76			if (fp != stdin && fshut(fp, *argv))
77				ret = 1;
78		}
79	}
80
81	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
82
83	return ret;
84}