1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <limits.h>
4 #include <errno.h>
5 #include <mba/msgno.h>
6 #include <mba/csv.h>
7
8 #define BUF_MAX 0x7FFF
9 #define ROW_MAX 0xFFF
10
11 int
run(const char * filename,const char * format,int filter,int count,int sep)12 run(const char *filename, const char *format, int filter, int count, int sep)
13 {
14 FILE *in;
15 unsigned char buf[BUF_MAX], *row[ROW_MAX];
16 int n, flags = CSV_TRIM | CSV_QUOTES;
17
18 if ((in = fopen(filename, "r")) == NULL) {
19 PMNF(errno, ": %s", filename);
20 return -1;
21 }
22
23 if (sep == '\t') {
24 flags &= ~CSV_QUOTES; /* do not interpret quotes with tab delimited files */
25 }
26
27 while ((n = csv_row_fread(in, buf, BUF_MAX, row, ROW_MAX, sep, flags)) > 0) {
28 const char *fmt = format;
29 char outbuf[BUF_MAX];
30 char *out = outbuf;
31
32 if (filter && strcmp(row[0], "0") == 0) {
33 continue;
34 }
35
36 while (*fmt) {
37 if (*fmt == '\\') {
38 fmt++;
39 switch (*fmt) {
40 case '\0':
41 return -1;
42 case 'n':
43 *out++ = '\n';
44 break;
45 case 't':
46 *out++ = '\t';
47 break;
48 case 'r':
49 *out++ = '\r';
50 break;
51 default:
52 *out++ = *fmt;
53 }
54 fmt++;
55 } else if (*fmt == '%') {
56 unsigned long i;
57 char *endptr;
58 fmt++;
59
60 if (*fmt == 'c') {
61 int n;
62 if ((n = sprintf(out, "%d", count)) == -1) {
63 PMNO(errno);
64 return -1;
65 }
66 out += n;
67 fmt++;
68 continue;
69 }
70
71 if ((i = strtoul(fmt, &endptr, 10)) == ULONG_MAX) {
72 PMNF(errno, ": %s", fmt);
73 return -1;
74 }
75 fmt = endptr;
76 if (i < ROW_MAX) {
77 const char *s = row[i];
78 if (s) {
79 while (*s) {
80 *out++ = *s++;
81 }
82 } else {
83 *out++ = '-';
84 }
85 }
86 } else {
87 *out++ = *fmt++;
88 }
89 }
90 *out = '\0';
91
92 count++;
93
94 fputs(outbuf, stdout);
95 }
96 if (n == -1) {
97 AMSG("");
98 return -1;
99 }
100
101 fclose(in);
102
103 return 0;
104 }
105
106 int
main(int argc,char * argv[])107 main(int argc, char *argv[])
108 {
109 char **args;
110 char *filename = NULL;
111 char *format = NULL;
112 int filter = 0;
113 unsigned long count = 1;
114 int sep = ',';
115
116 if (argc < 3) {
117 usage:
118 fprintf(stderr, "usage: %s [-f] [-s <sep>] <filename> <format>\n", argv[0]);
119 return EXIT_FAILURE;
120 }
121
122 errno = 0;
123
124 args = argv;
125 args++; argc--;
126
127 while (argc) {
128 if (strcmp(*args, "-f") == 0) {
129 filter = 1;
130 } else if (strcmp(*args, "-c") == 0) {
131 args++; argc--;
132 if ((count = strtoul(*args, NULL, 0)) == ULONG_MAX) {
133 fprintf(stderr, "invalid count value: %s", *args);
134 goto usage;
135 }
136 } else if (strcmp(*args, "-s") == 0) {
137 args++; argc--;
138 sep = **args;
139 if (sep == '\\') {
140 sep = *(*args + 1);
141 switch (sep) {
142 case 't':
143 sep = '\t';
144 break;
145 }
146 }
147 } else if (filename) {
148 if (format) {
149 fprintf(stderr, "invalid argument: %s\n", *args);
150 goto usage;
151 }
152 format = *args;
153 } else {
154 filename = *args;
155 }
156 args++; argc--;
157 }
158
159 if (run(filename, format, filter, count, sep) == -1) {
160 MMSG("Run failed.");
161 return EXIT_FAILURE;
162 }
163
164 return EXIT_SUCCESS;
165 }
166