#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <mba/msgno.h>
#include <mba/csv.h>
#define BUF_MAX 0x7FFF
#define ROW_MAX 0xFFF
int
run(const char *filename, const char *format, int filter, int count, int sep)
{
FILE *in;
unsigned char buf[BUF_MAX], *row[ROW_MAX];
int n, flags = CSV_TRIM | CSV_QUOTES;
if ((in = fopen(filename, "r")) == NULL) {
PMNF(errno, ": %s", filename);
return -1;
}
if (sep == '\t') {
flags &= ~CSV_QUOTES; /* do not interpret quotes with tab delimited files */
}
while ((n = csv_row_fread(in, buf, BUF_MAX, row, ROW_MAX, sep, flags)) > 0) {
const char *fmt = format;
char outbuf[BUF_MAX];
char *out = outbuf;
if (filter && strcmp(row[0], "0") == 0) {
continue;
}
while (*fmt) {
if (*fmt == '\\') {
fmt++;
switch (*fmt) {
case '\0':
return -1;
case 'n':
*out++ = '\n';
break;
case 't':
*out++ = '\t';
break;
case 'r':
*out++ = '\r';
break;
default:
*out++ = *fmt;
}
fmt++;
} else if (*fmt == '%') {
unsigned long i;
char *endptr;
fmt++;
if (*fmt == 'c') {
int n;
if ((n = sprintf(out, "%d", count)) == -1) {
PMNO(errno);
return -1;
}
out += n;
fmt++;
continue;
}
if ((i = strtoul(fmt, &endptr, 10)) == ULONG_MAX) {
PMNF(errno, ": %s", fmt);
return -1;
}
fmt = endptr;
if (i < ROW_MAX) {
const char *s = row[i];
if (s) {
while (*s) {
*out++ = *s++;
}
} else {
*out++ = '-';
}
}
} else {
*out++ = *fmt++;
}
}
*out = '\0';
count++;
fputs(outbuf, stdout);
}
if (n == -1) {
AMSG("");
return -1;
}
fclose(in);
return 0;
}
int
main(int argc, char *argv[])
{
char **args;
char *filename = NULL;
char *format = NULL;
int filter = 0;
unsigned long count = 1;
int sep = ',';
if (argc < 3) {
usage:
fprintf(stderr, "usage: %s [-f] [-s <sep>] <filename> <format>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
args = argv;
args++; argc--;
while (argc) {
if (strcmp(*args, "-f") == 0) {
filter = 1;
} else if (strcmp(*args, "-c") == 0) {
args++; argc--;
if ((count = strtoul(*args, NULL, 0)) == ULONG_MAX) {
fprintf(stderr, "invalid count value: %s", *args);
goto usage;
}
} else if (strcmp(*args, "-s") == 0) {
args++; argc--;
sep = **args;
if (sep == '\\') {
sep = *(*args + 1);
switch (sep) {
case 't':
sep = '\t';
break;
}
}
} else if (filename) {
if (format) {
fprintf(stderr, "invalid argument: %s\n", *args);
goto usage;
}
format = *args;
} else {
filename = *args;
}
args++; argc--;
}
if (run(filename, format, filter, count, sep) == -1) {
MMSG("Run failed.");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1