]> pd.if.org Git - pdutils/blob - posix/head/head.c
implemented pwd
[pdutils] / posix / head / head.c
1 /*
2  * head.c - copy the first part of files
3  *
4  * Version: 2008-1.01
5  * Build:   c89 -o head head.c
6  * Source:  <http://pdcore.sourceforge.net/>
7  * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/head.html>
8  *
9  * This is free and unencumbered software released into the public domain,
10  * provided "as is", without warranty of any kind, express or implied. See the
11  * file UNLICENSE and the website <http://unlicense.org> for further details.
12  */
13
14
15 #define _POSIX_SOURCE
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <locale.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #define USAGE   "usage: head [-n number] [file ...]\n"
28 #define BUFSIZE 4096
29
30 static long ctol(char *s);
31 static void headfile(int fd, char *fn, int lines);
32 static void error(char *s);
33
34 static int exitstatus;
35
36
37 int main(int argc, char **argv)
38 {
39     extern int opterr, optind;
40     extern char *optarg;
41     int c, fd, many, first;
42     char *fn;
43     long lines = 10;
44
45     setlocale(LC_ALL, "");
46     opterr = 0;
47
48     while ((c = getopt(argc, argv, "n:")) != -1)
49         switch (c)
50         {
51         case 'n':
52             if (*optarg && (lines = ctol(optarg)) > 0)
53                 break;
54             /* else fall through */
55         default:
56             fprintf(stderr, USAGE);
57             exit(1);
58         }
59
60     if (optind >= argc)
61         headfile(STDIN_FILENO, "stdin", lines);
62     else
63     {
64         many  = (optind + 1 < argc) ? 1 : 0;
65         first = 1;
66
67         while (optind < argc)
68         {
69             fn = argv[optind++];
70
71             if (many)
72             {
73                 if (first)
74                     first = 0;
75                 else
76                     printf("\n");
77                 printf("==> %s <==\n", fn);
78             }
79
80             if (strcmp(fn, "-") == 0)
81                 headfile(STDIN_FILENO, "stdin", lines);
82             else
83                 if ((fd = open(fn, O_RDONLY)) == -1)
84                     error(fn);
85                 else
86                 {
87                     headfile(fd, fn, lines);
88                     if (close(fd) == -1)
89                         error(fn);
90                 }
91         }
92     }
93
94     return(exitstatus);
95 }
96
97
98 long ctol(char *s)
99 {
100     int badch = 0;
101     char *c = s;
102
103     /* only copes with non-zero, optionally signed, */
104     /* decimal integers; that's all we need         */
105     if (! (isdigit(*c) || *c == '+' || *c == '-'))
106         badch = 1;
107     else
108         for (c++; *c; c++)
109             if (! isdigit(*c))
110                 badch = 1;
111
112     return (badch ? 0 : atol(s));
113 }
114
115
116 void headfile(int fd, char *fn, int lines)
117 {
118     unsigned char buf[BUFSIZE], *c;
119     ssize_t n, o;
120
121     while (lines)
122     {
123         if ((n = read(fd, buf, BUFSIZE)) <= 0)
124             break;
125
126         for (c = buf; lines && c < (buf + n); c++)
127             if (*c == '\n')
128                 lines--;
129
130         o = lines ? n : c - buf;
131         if (write(STDOUT_FILENO, buf, (size_t)o) != o)
132         {
133             error("stdout");
134             break;
135         }
136     }
137
138     if (n < 0)
139         error(fn);
140 }
141
142
143 void error(char *s)
144 {
145     fprintf(stderr, "head: %s: %s\n", s, strerror(errno));
146     exitstatus = 1;
147 }