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