master xplshn/aruu / cmd / posix / head.c
 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}