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