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}