#include <stdio.h>
#include <string.h>
int lineCounter = 0;
int die(const char *message) {
fprintf(stderr, "%s\n", message);
return 1;
}
// For numbers like "$1,000.00", trim out that extra comma, as it kills the comma-delimited parsing
void trimLargeNumbers(char *s, const char *prefix) {
char *a, *b, *c;
c = strstr(s, prefix);
if (c) {
a = c+2;
b = c+3;
do {
*a = *b;
a++;
b++;
} while (*a);
}
}
void convert(FILE *in, FILE *out) {
char line[256], *payee, *amount, *date, *c;
fprintf(out, "!Type:Bank\n");
fgets(line, sizeof(line) - 1, in); // Read the header line to get it out of the way
while (fgets(line, sizeof(line) - 1, in) != NULL) {
lineCounter++;
line[sizeof(line) - 1] = 0;
trimLargeNumbers(line, "$1,"); // Mmmm... copy & paste
trimLargeNumbers(line, "$2,");
trimLargeNumbers(line, "$3,");
trimLargeNumbers(line, "$4,"); // No income/expenses larger than $4,999 in these accounts (for now!)
for (c = line; *c; c++) // Trim off line endings and other control characters
if (*c < ' ')
*c = 0;
if ((amount = strrchr(line, ',')) == NULL) {
fprintf(stderr, "Could not find amount comma in line %d: %s\n", lineCounter, line);
continue;
}
*amount = 0;
amount++;
if ((date = strrchr(line, ',')) == NULL) {
fprintf(stderr, "Could not find date comma in line %d: %s\n", lineCounter, line);
continue;
}
*date = 0;
date++;
payee = &line[0];
if (*payee == '"') {
payee++;
c = strrchr(payee, '"');
*c = 0;
}
// If amount is in quotes, strip 'em
if (*amount == '"') {
amount++;
for (c = amount; *c; c++)
if (*c == '"')
*c = 0;
}
// Convert date to positive value (without $) or negative value (without $ or parens)
amount++;
if (*amount == '$') {
*amount = '-';
for (c = amount; *c; c++)
if (*c == ')')
*c = 0;
}
fprintf(out, "P%s\nD%s\nU%s\n^\n", payee, date, amount);
}
}
int main(int argc, char **argv) {
FILE *in, *out;
if (argc != 3) {
fprintf(stderr, "Converts Cha-Ching CSV files to Quicken QIF format\n"
"Usage: %s inputfilename outputfilename\n"
"NOTE: if you get a lot of \"Could not find amount comma\" errors, then convert your CSV to UTF-8\n",
argv[0]);
return 1;
}
if ((in = fopen(argv[1], "r")) == 0)
return die("Unable to open input file");
if ((out = fopen(argv[2], "w")) == 0)
return die("Unable to open output file");
convert(in, out);
fclose(in);
fclose(out);
}