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 #define FILEPROCESS_RETU { \
29 	FILE *fp_fp; \
30 	int fp_no_output = 0; \
31 	int fp_b = 0, fp_r_i = 1; \
32 	int fp_buf_i, fp_buf_len; \
33 	char *fp_buf, *fp_p = NULL, *fp_newbuf, *fp_buf_end; \
34 	fp_buf_len = BUFFER_SIZE; \
35 	fp_buf = calloc(fp_buf_len, sizeof(char)); \
36 	for (int fp_file_i = 1; fp_file_i <= F_ARGC; fp_file_i++) { \
37 		fp_fp = fopen(F_ARGV[fp_file_i], "r"); \
38 		if (NULL == fp_fp) \
39 			err(errno, "%s", F_ARGV[fp_file_i]); \
40 		while (EOF != (fp_b = fgetc(fp_fp))) { \
41 			fp_p = fp_buf; \
42 			fp_buf_i = 0; \
43 			fp_buf_end = &fp_buf[fp_buf_len - 1]; \
44 			*fp_p = fp_b; \
45 			while (' ' != *fp_p && \
46 			       '\n' != *fp_p && EOF != *fp_p) { \
47 				++fp_p; \
48 				++fp_buf_i; \
49 				FILEPROCESS_RETU_BUFFER_EXPANSION \
50 				*fp_p = fgetc(fp_fp); \
51 			} \
52 			if ((' ' == fp_b && *fp_p == fp_b) || \
53 			    ('\n' == fp_b && *fp_p == fp_b)) { \
54 				*fp_p = '@'; \
55 				++fp_p; \
56 				++fp_buf_i; \
57 				FILEPROCESS_RETU_BUFFER_EXPANSION \
58 			} \
59 			else { \
60 				fp_b = *fp_p; \
61 			} \
62 			*fp_p = '\0'; \
63 			if (fp_r_i <= R_INDEX_MAX && \
64 			    R_INDEX_EXIST[fp_r_i]) { \
65 				TGT_RETU_PROCESS(fp_buf,fp_buf_len,fp_r_i) \
66 			} \
67 			else { \
68 				NOTGT_RETU_PROCESS(fp_buf,fp_buf_len,fp_r_i) \
69 			} \
70 			switch (fp_b) { \
71 			case ' ': \
72 				if (!fp_no_output) putchar(' '); \
73 				++fp_r_i; \
74 				break; \
75 			case '\n': \
76 			case EOF: \
77 				if (!fp_no_output) putchar('\n'); \
78 				fp_r_i = 1; \
79 				END_OF_LINE_RETU_PROCESS \
80 				break; \
81 			} \
82 		} \
83 		fclose(fp_fp); \
84 	} \
85 }
86 
87 #define FILEPROCESS_RETU_BUFFER_EXPANSION { \
88 	if (fp_p == fp_buf_end) { \
89 		fp_newbuf = \
90 			calloc(fp_buf_len + BUFFER_SIZE, sizeof(char)); \
91 		if (NULL == fp_newbuf) \
92 			err(errno, "ttt_utils.h#FILEPROCESS_RETU"); \
93 		memcpy(fp_newbuf, fp_buf, fp_buf_len * sizeof(char)); \
94 		fp_buf_len += BUFFER_SIZE; \
95 		free(fp_buf); \
96 		fp_buf = fp_newbuf; \
97 		fp_buf_end = &fp_buf[fp_buf_len - 1]; \
98 		fp_p = &fp_buf[fp_buf_i]; \
99 	} \
100 }
101 
102 #define FILEPROCESS_GYO { \
103 	FILE *fp_fp; \
104 	struct stat fp_sb; \
105 	int fp_b = 0, fp_r_i = 1, fled = 0; \
106 	int fp_buf_i, fp_buf_len, fp_ibuf_len, fp_nf; \
107 	char *fp_buf, *fp_buf_end, **fp_ibuf; \
108 	char *fp_p = NULL, *fp_newbuf, **fp_newibuf; \
109 	int *r_index_to_argv, *r_index_exist, r_index_max; \
110 	fp_buf_len = BUFFER_SIZE; \
111 	fp_ibuf_len = 32; \
112 	fp_buf = calloc(fp_buf_len, sizeof(char)); \
113 	fp_ibuf = calloc(fp_ibuf_len + 1, sizeof(char *)); \
114 	for (int fp_file_i = 1; \
115 	     fp_file_i <= F_ARGC; fp_file_i++) { \
116 		fp_fp = fopen(F_ARGV[fp_file_i], "r"); \
117 		if (NULL == fp_fp) \
118 			err(errno, "%s", F_ARGV[fp_file_i]); \
119 		stat(F_ARGV[fp_file_i], &fp_sb); \
120 		fp_p = fp_buf; \
121 		fp_buf_i = fp_nf = 0; \
122 		fp_buf_end = &fp_buf[fp_buf_len - 1]; \
123 		while (1) { \
124 			fp_b = fgetc(fp_fp); \
125 			if (EOF == fp_b) { \
126 				if (fled) { fled = 0; break; } \
127 				else fp_nf -= 1; \
128 			} \
129 			fled = 0; \
130 			*fp_p = fp_b; \
131 			while (' ' != *fp_p && \
132 			       '\n' != *fp_p && EOF != *fp_p) { \
133 				++fp_p; \
134 				++fp_buf_i; \
135 				FILEPROCESS_GYO_BUFFER_EXPANSION \
136 				*fp_p = fgetc(fp_fp); \
137 			} \
138 			if ((' ' == fp_b && *fp_p == fp_b) || \
139 			    ('\n' == fp_b && *fp_p == fp_b) || \
140 			    (EOF == fp_b && *fp_p == fp_b)) { \
141 				*fp_p = '@'; \
142 				++fp_p; \
143 				++fp_buf_i; \
144 				FILEPROCESS_GYO_BUFFER_EXPANSION \
145 			} \
146 			else { \
147 				fp_b = *fp_p; \
148 			} \
149 			*fp_p = '\0'; \
150 			++fp_nf; \
151 			switch (fp_b) { \
152 			case ' ': \
153 				++fp_p; \
154 				++fp_buf_i; \
155 				FILEPROCESS_GYO_BUFFER_EXPANSION \
156 				++fp_r_i; \
157 				break; \
158 			case '\n': \
159 				fled = 1; \
160 			case EOF: \
161 				fp_r_i = 1; \
162 				FILEPROCESS_GYO_IBUFFER_EXPANSION \
163 				FILEPROCESS_GYO_IBUFFER_ASSIGN \
164 				FILEPROCESS_GYO_R_INDEX_EXPANSION \
165 				TGT_GYO_PROCESS(fp_ibuf,fp_nf) \
166 				fp_p = fp_buf; \
167 				fp_buf_i = fp_nf = 0; \
168 				break; \
169 			} \
170 			if (EOF == fp_b) \
171 				break; \
172 		} \
173 		fclose(fp_fp); \
174 	} \
175 }
176 
177 #define FILEPROCESS_GYO_FILESIZE_IS_ZERO \
178 	0 == fp_sb.st_size
179 
180 #define FILEPROCESS_GYO_BUFFER_EXPANSION { \
181 	if (fp_p == fp_buf_end) { \
182 		fp_newbuf = \
183 			calloc(fp_buf_len + BUFFER_SIZE, sizeof(char)); \
184 		if (NULL == fp_newbuf) \
185 			err(errno, \
186 			    "ttt_utils.h#" \
187 			    "FILEPROCESS_GYO_BUFFER_EXPANSION"); \
188 		memcpy(fp_newbuf, fp_buf, fp_buf_len * sizeof(char)); \
189 		fp_buf_len += BUFFER_SIZE; \
190 		free(fp_buf); \
191 		fp_buf = fp_newbuf; \
192 		fp_buf_end = &fp_buf[fp_buf_len - 1]; \
193 		fp_p = &fp_buf[fp_buf_i]; \
194 	} \
195 }
196 
197 #define FILEPROCESS_GYO_IBUFFER_EXPANSION { \
198 	if (fp_ibuf_len < fp_nf) { \
199 	 	fp_newibuf = calloc(fp_nf + 1, sizeof(char *)); \
200 		if (NULL == fp_newibuf) \
201 			err(errno, \
202 			    "ttt_utils.h#" \
203 			    "FILEPROCESS_GYO_IBUFFER_EXPANSION"); \
204 		memcpy(fp_newibuf, fp_ibuf, fp_ibuf_len * sizeof(char *)); \
205 		fp_ibuf_len = fp_nf; \
206 	 	free(fp_ibuf); \
207 		fp_ibuf = fp_newibuf; \
208 	} \
209 }
210 
211 #define FILEPROCESS_GYO_IBUFFER_ASSIGN { \
212 	fp_p = fp_buf; \
213 	fp_ibuf[1] = fp_buf; \
214 	for (int fp_i = 2; fp_i <= fp_nf; fp_i++) { \
215 		while ('\0' != *fp_p) { \
216 			++fp_p; \
217 		} \
218 		++fp_p; \
219 		fp_ibuf[fp_i] = fp_p; \
220 	} \
221 }
222 
223 #define FILEPROCESS_GYO_R_INDEX_EXPANSION { \
224 	if (R_INDEX_MAX < fp_nf) { \
225 		r_index_max = fp_nf; \
226 		r_index_to_argv = \
227 			calloc(r_index_max + 1, sizeof(int)); \
228 		if (NULL == r_index_to_argv) \
229 			err(errno, \
230 			    "ttt_utils.h#" \
231 			    "FILEPROCESS_GYO_R_INDEX_EXPANSION"); \
232 		memcpy(r_index_to_argv, R_INDEX_TO_ARGV, \
233 			(r_index_max + 1) * sizeof(int)); \
234 		for (int fp_i = R_INDEX_MAX + 1; \
235 			fp_i <= r_index_max + 1; fp_i++) \
236 			r_index_to_argv[fp_i] = R_INDEX_IS_NONE; \
237 		free(R_INDEX_TO_ARGV); \
238 		R_INDEX_TO_ARGV = r_index_to_argv; \
239 		; \
240 		r_index_exist = calloc(r_index_max + 1, sizeof(int)); \
241 		if (NULL == r_index_exist) \
242 			err(errno, \
243 			    "ttt_utils.h#" \
244 			    "FILEPROCESS_GYO_R_INDEX_EXPANSION"); \
245 		memcpy(r_index_exist, R_INDEX_EXIST, \
246 			(r_index_max + 1) * sizeof(int)); \
247 		for (int fp_i = R_INDEX_MAX + 1; \
248 			fp_i <=r_index_max + 1; fp_i++) \
249 			r_index_exist[fp_i] = R_INDEX_IS_NOT_EXISTENCE; \
250 		free(R_INDEX_EXIST); \
251 		R_INDEX_EXIST = r_index_exist; \
252 		R_INDEX_MAX = r_index_max; \
253 	} \
254 }
255 
256 #define FILEPROCESS_CHAR { \
257 	FILE *fp_fp; \
258 	int fp_b = 0; \
259 	for (int fp_file_i = 1; fp_file_i <= F_ARGC; fp_file_i++) { \
260 		fp_fp = fopen(F_ARGV[fp_file_i], "r"); \
261 		if (NULL == fp_fp) \
262 			err(errno, "%s", F_ARGV[fp_file_i]); \
263 		while (1) { \
264 			fp_b = fgetc(fp_fp); \
265 			TGT_CHAR_PROCESS(fp_b) \
266 			if (EOF == fp_b) \
267 				break; \
268 		} \
269 		fclose(fp_fp); \
270 	} \
271 }
272 
273 #define FILEPROCESS_CAT { \
274 	FILE *fp_fp; \
275 	int fp_b = 0; \
276 	char fp_bpre; \
277 	for (int fp_file_i = 1; fp_file_i <= F_ARGC; fp_file_i++) { \
278 		fp_fp = fopen(F_ARGV[fp_file_i], "r"); \
279 		if (NULL == fp_fp) \
280 			err(errno, "%s", F_ARGV[fp_file_i]); \
281 		while (1) { \
282 			fp_b = fgetc(fp_fp); \
283 			if (EOF == fp_b) { \
284 				if ('\n' != fp_bpre) \
285 					putchar('\n'); \
286 				break; \
287 			} \
288 			putchar(fp_b); \
289 			fp_bpre = fp_b; \
290 		} \
291 		fclose(fp_fp); \
292 	} \
293 }
294 
295 #define FILEPROCESS_ALLBUFFER { \
296 	int fp_fd, fp_size, fp_rsize; \
297 	struct stat fp_st; \
298 	char *fp_buf; \
299 	for (int fp_file_i = 1; fp_file_i <= F_ARGC; fp_file_i++) { \
300 		if (-1 == stat(F_ARGV[fp_file_i], &fp_st )) \
301 			err(errno, "%s", F_ARGV[fp_file_i]); \
302 		fp_size = fp_st.st_size; \
303 		fp_buf = calloc(fp_size + 1, sizeof(char)); \
304 		if (-1 == (fp_fd = open(F_ARGV[fp_file_i], O_RDONLY))) \
305 			err(errno, "%s", F_ARGV[fp_file_i]); \
306 		fp_rsize = 0; \
307 		while (fp_rsize != fp_size) \
308 			fp_rsize += read(fp_fd, fp_buf+fp_rsize, \
309 				fp_size-fp_rsize); \
310 		TGT_BUFFER_PROCESS(fp_buf, fp_size) \
311 		free(fp_buf); \
312 		close(fp_fd); \
313 	} \
314 }
315