1 /*
2 * Copyright (c) 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 LINE_BUF_MAX 3145728
31
32 #define IS_SEPARATOR(p) \
33 ' ' == *p || '\n' == *p || '\0' == *p
34 #define IS_NOT_SEPARATOR(p) \
35 ' ' != *p && '\n' != *p && '\0' != *p
36
37 #define IS_SPACE(p) \
38 ' ' == *p
39
40 #define IS_LF(p) \
41 '\n' == *p
42
43 #define itor(index) R_INDEX_TO_ARGV[index]
44
45 #define IS_SWAP_TARGET(index) \
46 NULL != R_ARGV_ARG1[itor(index)] && \
47 ( ('@' == *R_ARGV_ARG1[itor(index)] && '\n' == *retu_p) || \
48 ('@' == *R_ARGV_ARG1[itor(index)] && '\0' == *retu_p) || \
49 (0 == strncmp(R_ARGV_ARG1[itor(index)], retu_p, \
50 strlen(R_ARGV_ARG1[itor(index)]))))
51
52 #define SWAPED_STRING(index) \
53 R_ARGV_ARG2[itor(index)]
54
55 static const char atmark[2] = "@";
56
57 static inline void do_swap_print(FILE *fp);
58
59 static bool outputed;
60
61 void
swap_print(void)62 swap_print(void)
63 {
64 FILE *fp;
65
66 outputed = false;
67
68 // Process the first file
69 int file_i = 1;
70 char line_buf[LINE_BUF_MAX];
71
72 fp = fopen(F_ARGV[file_i], "r");
73 if (NULL == fp)
74 err(errno, "%s", F_ARGV[file_i]);
75
76 // Delete the first line
77 if (FLAG_1)
78 fgets(line_buf, LINE_BUF_MAX, fp);
79
80 do_swap_print(fp);
81
82 fclose(fp);
83
84 // Process second and subsequent files
85 for (file_i = 2; file_i <= F_ARGC; file_i++) {
86 fp = fopen(F_ARGV[file_i], "r");
87 if (NULL == fp)
88 err(errno, "%s", F_ARGV[file_i]);
89
90 do_swap_print(fp);
91
92 fclose(fp);
93 }
94
95 // If option -e is specified, only one line is output if
96 // there is no output.
97 if (FLAG_e && ! outputed) {
98 int outputed_retu_count = 0;
99 for (int i = 1; i <=R_INDEX_MAX; i++) {
100 if (R_INDEX_EXIST[i]) {
101 if (NULL != R_ARGV_ARG2[R_INDEX_TO_ARGV[i]])
102 printf("%s",
103 R_ARGV_ARG2[R_INDEX_TO_ARGV[i]]);
104 else
105 printf("@");
106 ++outputed_retu_count;
107 if (R_ARGC == outputed_retu_count)
108 putchar('\n');
109 else
110 putchar(' ');
111 }
112 }
113 }
114 }
115
116 static inline void
do_swap_print(FILE * fp)117 do_swap_print(FILE *fp)
118 {
119 char line_buf[LINE_BUF_MAX];
120 char *p;
121 char *retu_p;
122
123 // Array to access the string of columns from the number of
124 // columns:
125 // retu_to_string[RETU_NUMBER] --> RETU_STRING
126 //
127 char *retu_to_string[1 + R_INDEX_MAX];
128
129 // 0 is always access to the atmark.
130 retu_to_string[0] = atmark;
131
132 while (NULL != fgets(line_buf, LINE_BUF_MAX, fp)) {
133 // Divide the line_buf by column and set access method
134 // (retu_to_string[RETU_NUMBER] --> RETU_STRING).
135 p = line_buf;
136
137 for (int retu_i = 1; retu_i <= R_INDEX_MAX;
138 retu_i++) {
139
140 // Pointer to the column string
141 retu_p = p;
142
143 // Move to end of string
144 while (IS_NOT_SEPARATOR(p))
145 ++p;
146
147 // Set access if selected column
148 if (R_INDEX_EXIST[retu_i]) {
149 if (IS_SWAP_TARGET(retu_i)) {
150 retu_to_string[retu_i] =
151 SWAPED_STRING(retu_i);
152 }
153 else {
154 if (retu_p == p)
155 retu_to_string[retu_i] =
156 atmark;
157 else
158 retu_to_string[retu_i] =
159 retu_p;
160 }
161 }
162
163 // Move to beginning of next column
164 if (IS_SPACE(p)) {
165 *p = '\0';
166 ++p;
167 }
168 // Since there is no line data left, everything
169 // is set to access "@" or swaped string.
170 else {
171 if (IS_LF(p))
172 *p = '\0';
173
174 for (++retu_i; retu_i <= R_INDEX_MAX;
175 retu_i++) {
176 if (R_INDEX_EXIST[retu_i]) {
177 if (NULL != R_ARGV_ARG2[R_INDEX_TO_ARGV[retu_i]])
178 retu_to_string[retu_i] =
179 R_ARGV_ARG2[R_INDEX_TO_ARGV[retu_i]];
180 else
181 retu_to_string[retu_i] =
182 atmark;
183 }
184 }
185 }
186 }
187
188 // Output in specified column order
189 for (int retu_i = 1; retu_i < R_ARGC; retu_i++)
190 printf("%s ", retu_to_string[R_ARGV[retu_i]]);
191 printf("%s\n", retu_to_string[R_ARGV[R_ARGC]]);
192
193 outputed = true;
194 }
195 }
196