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 static const char atmark[2] = "@";
44
45 static inline void do_fast_print(FILE *fp);
46
47 static bool outputed;
48
49 void
fast_print(void)50 fast_print(void)
51 {
52 FILE *fp;
53
54 outputed = false;
55
56 // Process the first file
57 int file_i = 1;
58 char line_buf[LINE_BUF_MAX];
59
60 fp = fopen(F_ARGV[file_i], "r");
61 if (NULL == fp)
62 err(errno, "%s", F_ARGV[file_i]);
63
64 // Delete the first line
65 if (FLAG_1)
66 fgets(line_buf, LINE_BUF_MAX, fp);
67
68 do_fast_print(fp);
69
70 fclose(fp);
71
72 // Process second and subsequent files
73 for (file_i = 2; file_i <= F_ARGC; file_i++) {
74 fp = fopen(F_ARGV[file_i], "r");
75 if (NULL == fp)
76 err(errno, "%s", F_ARGV[file_i]);
77
78 do_fast_print(fp);
79
80 fclose(fp);
81 }
82
83 // If option -e is specified, only one line is output if
84 // there is no output.
85 if (FLAG_e && ! outputed) {
86 for (int i = 1; i < R_ARGC; i++)
87 printf("@ ");
88 printf("@\n");
89 }
90 }
91
92 static inline void
do_fast_print(FILE * fp)93 do_fast_print(FILE *fp)
94 {
95 char line_buf[LINE_BUF_MAX];
96 char *p;
97 char *retu_p;
98
99 // Array to access the string of columns from the number of
100 // columns:
101 // retu_to_string[RETU_NUMBER] --> RETU_STRING
102 //
103 char *retu_to_string[1 + R_INDEX_MAX];
104
105 // 0 is always access to the atmark.
106 retu_to_string[0] = atmark;
107
108 while (NULL != fgets(line_buf, LINE_BUF_MAX, fp)) {
109 // Divide the line_buf by column and set access method
110 // (retu_to_string[RETU_NUMBER] --> RETU_STRING).
111 p = line_buf;
112
113 for (int retu_i = 1; retu_i <= R_INDEX_MAX;
114 retu_i++) {
115
116 // Pointer to the column string
117 retu_p = p;
118
119 // Move to end of string
120 while (IS_NOT_SEPARATOR(p))
121 ++p;
122
123 // Set access if selected column
124 if (R_INDEX_EXIST[retu_i]) {
125 if (retu_p == p)
126 retu_to_string[retu_i] = atmark;
127 else
128 retu_to_string[retu_i] = retu_p;
129 }
130
131 // Move to beginning of next column
132 if (IS_SPACE(p)) {
133 *p = '\0';
134 ++p;
135 }
136 // Since there is no line data left, everything
137 // is set to access "@"
138 else {
139 if (IS_LF(p))
140 *p = '\0';
141
142 for (++retu_i; retu_i <= R_INDEX_MAX;
143 retu_i++) {
144 if (R_INDEX_EXIST[retu_i])
145 retu_to_string[retu_i] =
146 atmark;
147 }
148 }
149 }
150
151 // Output in specified column order
152 for (int retu_i = 1; retu_i < R_ARGC; retu_i++)
153 printf("%s ", retu_to_string[R_ARGV[retu_i]]);
154 printf("%s\n", retu_to_string[R_ARGV[R_ARGC]]);
155
156 outputed = true;
157 }
158 }
159