1 /*
2  * Copyright (c) 2016,2019 Daichi GOTO
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "command.h"
29 
30 #define BUFLEN  65536
31 
32 int
main(int argc,char * argv[])33 main(int argc, char *argv[])
34 {
35 	getcmdargs(argc, argv, "hvD", CMDARGS_R_NONE);
36 
37 	int	rfd;
38 	int	wfd;
39 
40 	ssize_t	nr, nw;
41 	int	off;
42 
43 	char	buf[BUFLEN];
44 	char	*p;
45 
46 	bool	outputed;	// Holds whether data is output or not
47 	bool	tagremoved;	// Holds whether tag is removed or not
48 
49 	wfd = fileno(stdout);
50 
51 	/*
52 	 * Process the first file
53 	 */
54 	rfd = open(F_ARGV[1], O_RDONLY);
55 	if (-1 == rfd)
56 		err(EX_NOINPUT, "%s", F_ARGV[1]);
57 
58 	tagremoved = false;
59 	outputed = false;
60 	nw = 0;
61 	while ((nr = read(rfd, buf, BUFLEN)) > 0) {
62 		for (off = 0; nr; nr -= nw, off += nw) {
63 			// Skip tags
64 			if (!tagremoved) {
65 				p = buf;
66 				while ('\n' != *p && '\0' != *p) {
67 					++p;
68 					++off;
69 				}
70 				if ('\n' == *p) {
71 					++off;
72 					tagremoved = true;
73 				}
74 				nr -= off;
75 			}
76 
77 			// If the read data is all tags, move to the next
78 			// read without outputting
79 			if (0 >= nr)
80 				break;
81 
82 			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
83 				err(1, "stdout");
84 			outputed = true;
85 		}
86 	}
87 
88 	// If there is no line feed at the end of the file, an additional
89 	// line break is output.
90 	if (outputed && '\n' != buf[off + nr - 1])
91 		putchar('\n');
92 
93 	close(rfd);
94 
95 	// Flush the standard output before processing the next file.
96 	// If this processing is not performed, the output may go wrong.
97 	fflush(stdout);
98 
99 	/*
100 	 * Process second and subsequent files
101 	 */
102 	for (int file_i = 2; file_i <= F_ARGC; file_i++) {
103 		rfd = open(F_ARGV[file_i], O_RDONLY);
104 		if (-1 == rfd)
105 			err(EX_NOINPUT, "%s", F_ARGV[1]);
106 
107 		outputed = false;
108 		nw = 0;
109 		while ((nr = read(rfd, buf, BUFLEN)) > 0) {
110 			for (off = 0; nr; nr -= nw, off += nw) {
111 				if ((nw = write(wfd, buf + off,
112 						(size_t)nr)) < 0)
113 					err(1, "stdout");
114 				outputed = true;
115 			}
116 		}
117 
118 		// If there is no line feed at the end of the file, an
119 		// additional line break is output.
120 		if (outputed && '\n' != buf[off + nr - 1])
121 			putchar('\n');
122 
123 		close(rfd);
124 
125 		// Flush the standard output before processing the next
126 		// file.  If this processing is not performed, the output
127 		// may go wrong.
128 		fflush(stdout);
129 	}
130 
131 	exit(EX_OK);
132 }
133