#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <curl/curl.h>
#define BASE_CURRENCY "USD"
// Define the allowed expense categories
const char *allowedCategories[] = {
"Housing", "Transportation", "Food", "Healthcare", "Utilities", "Debt",
"Personal Care", "Entertainment", "Insurance", "Education", "Savings/Investments",
"Clothing", "Charity", "Travel", "Miscellaneous"
};
// Function prototypes
void displayExpensesAndTotal
(FILE *file);void displayExpensesPerMonthAndTotal
(FILE *file);void editExpense
(FILE *file, const char
*filename
);void deleteExpense
(FILE *file, const char
*filename
);void displayCategories();
size_t write_callback(char *ptr, size_t size, size_t nmemb, char *data);
double getExchangeRate(const char *from, const char *to);
int main() {
char first_name[50], last_name[50];
printf("Enter your first and last name: "); scanf("%s %s", first_name, last_name);
// Create a file with the user's name to store expenses or open existing file if it exists
char filename[150]; // Assuming a maximum length of 150 characters for the filename
sprintf(filename
, "%s_%s_expenses.txt", first_name
, last_name
);
int choice;
do {
printf("\nCurrent User: %s %s\n", first_name
, last_name
); printf("Expense Tracker Menu\n"); printf("2. Display Expenses and Total\n"); printf("3. Display Expenses per Month and Total\n"); printf("5. Delete Expense\n"); printf("6. Categorize Spending\n"); printf("Enter your choice: "); scanf("%d", &choice);
printf("Error opening file!\n"); return 1;
}
switch (choice) {
case 1:
break;
case 2:
displayExpensesAndTotal
(file); break;
case 3:
displayExpensesPerMonthAndTotal
(file); break;
case 4:
editExpense
(file, filename
); break;
case 5:
deleteExpense
(file, filename
); break;
case 6:
categorizeSpending
(file); break;
case 7:
break;
case 8:
break;
default:
printf("Invalid choice! Please try again.\n"); }
} while (choice != 8);
return 0;
}
printf("Available Expense Categories:\n"); displayCategories();
char category[50];
float amount;
char currency[4]; // Assuming currency code is 3 characters long
int categoryNum;
// Input validation for category number
while (true) {
printf("Enter category number: "); if (scanf
("%d", &categoryNum
) != 1 || categoryNum
< 1 || categoryNum
> sizeof(allowedCategories
) / sizeof(allowedCategories
[0])) { printf("Invalid category number! Please choose a valid category number.\n"); // Clear input buffer
while (getchar() != '\n');
} else {
strcpy(category, allowedCategories[categoryNum - 1]);
break;
}
}
// Input validation for amount
while (true) {
if (scanf("%f", &amount) == 1 && amount > 0.0f)
break;
else {
printf("Invalid input! Please enter a valid amount greater than 0.\n"); // Clear input buffer
while (getchar() != '\n');
}
}
// Input validation for date format (DD-MM-YYYY)
char dateInput[11]; // Assuming maximum length of the date input is 10 characters (including null terminator)
while (true) {
printf("Enter date (DD-MM-YYYY): "); if (scanf("%10s", dateInput) != 1) {
printf("Invalid input! Please enter the date in DD-MM-YYYY format.\n"); // Clear input buffer
while (getchar() != '\n');
continue;
}
// Parse date input into day, month, and year components
int day, month, year;
if (sscanf(dateInput
, "%d-%d-%d", &day
, &month
, &year
) != 3) { printf("Invalid date format! Please enter the date in DD-MM-YYYY format.\n"); continue;
}
// Validate day, month, and year ranges
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1900 || year > 9999) {
printf("Invalid date! Please enter a valid date.\n"); continue;
}
// Date input is valid
break;
}
// Input currency code
printf("Enter currency code (e.g., USD, EUR): "); scanf("%s", currency);
// Convert currency to base currency (USD)
double exchangeRate = getExchangeRate(currency, BASE_CURRENCY);
if (exchangeRate < 0) {
fprintf(stderr
, "Failed to get exchange rate for %s to %s\n", currency
, BASE_CURRENCY
); return;
}
// Convert amount to base currency
amount *= exchangeRate;
// Save expense to file
printf("Expense added successfully!\n"); }
void displayExpensesAndTotal
(FILE *file) { rewind(file); // Move file pointer to the beginning char category[50];
float amount;
char currency[4];
float total = 0.0f;
int expenseCount = 0;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) != 4) { printf("No expenses recorded.\n"); return;
}
printf("Index Category Amount Currency Date\n"); do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", ++expenseCount
, category
, amount
, currency
, date); total += amount;
} while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4);
printf("\nTotal Expenses: $%.2f\n", total
); }
void displayExpensesPerMonthAndTotal
(FILE *file) { rewind(file); // Move file pointer to the beginning char category[50];
float amount;
char currency[4];
float total = 0.0f;
// Buffer to store month and year in MM-YYYY format
char inputMonthYear[8];
printf("Enter month and year (MM-YYYY): "); scanf("%s", inputMonthYear);
bool foundExpenses = false;
while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4) { // Extract month and year from the date
char expenseMonthYear[8];
strncpy
(expenseMonthYear
, date + 3, 7); // Extract MM-YYYY from DD-MM-YYYY expenseMonthYear[7] = '\0';
// Check if the extracted month and year match the user-provided input
if (strcmp(expenseMonthYear
, inputMonthYear
) == 0) { if (!foundExpenses) {
printf("Category\tAmount\tCurrency\tDate\n"); foundExpenses = true;
}
printf("%-15s%.2f\t%-3s\t%s\n", category
, amount
, currency
, date); total += amount;
}
}
if (!foundExpenses) {
printf("No expenses for %s\n", inputMonthYear
); return;
}
printf("\nTotal Expenses for %s: $%.2f\n", inputMonthYear
, total
); }
void editExpense
(FILE *file, const char
*filename
) { // Display current expenses
printf("Current Expenses:\n");
// Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
int currentIndex = 1;
bool found = false;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) != 4) { printf("No expenses recorded.\n"); return;
}
printf("Index Category Amount Currency Date\n"); do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", currentIndex
, category
, amount
, currency
, date); currentIndex++;
} while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4);
int index;
printf("Enter the index of the expense you want to edit: "); scanf("%d", &index);
// Move file pointer to the beginning
// Create a temporary file to store updated data
char tempFilename[150];
sprintf(tempFilename
, "temp_%s", filename
); if (tempFile == NULL) {
printf("Error creating temporary file!\n"); return;
}
currentIndex = 1;
char dateInput[11]; // Moved the declaration outside the switch statement
while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4) { if (currentIndex == index) {
// Editing logic here
printf("What do you want to edit?\n"); int editChoice;
printf("Enter your choice: "); scanf("%d", &editChoice);
switch (editChoice) {
case 1:
// Edit category
printf("Choose a new category:\n"); displayCategories();
int categoryNum;
// Input validation for category number
while (true) {
printf("Enter category number: "); if (scanf
("%d", &categoryNum
) != 1 || categoryNum
< 1 || categoryNum
> sizeof(allowedCategories
) / sizeof(allowedCategories
[0])) { printf("Invalid category number! Please choose a valid category number.\n"); // Clear input buffer
while (getchar() != '\n');
} else {
strcpy(category, allowedCategories[categoryNum - 1]);
break;
}
}
break;
case 2:
// Edit amount
while (true) {
if (scanf("%f", &amount) == 1 && amount > 0.0f)
break;
else {
printf("Invalid input! Please enter a valid amount greater than 0.\n"); // Clear input buffer
while (getchar() != '\n');
}
}
break;
case 3:
// Edit date
while (true) {
printf("Enter new date (DD-MM-YYYY): "); if (scanf("%10s", dateInput) != 1) {
printf("Invalid input! Please enter the date in DD-MM-YYYY format.\n"); // Clear input buffer
while (getchar() != '\n');
continue;
}
// Parse date input into day, month, and year components
int day, month, year;
if (sscanf(dateInput
, "%d-%d-%d", &day
, &month
, &year
) != 3) { printf("Invalid date format! Please enter the date in DD-MM-YYYY format.\n"); continue;
}
// Validate day, month, and year ranges
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1900 || year > 9999) {
printf("Invalid date! Please enter a valid date.\n"); continue;
}
// Date input is valid
break;
}
break;
default:
printf("Invalid choice! Please try again.\n"); }
}
fprintf(tempFile
, "%s %.2f %s %s\n", category
, amount
, currency
, date); currentIndex++;
}
// Remove the old file
remove(filename);
// Rename the temporary file to the original filename
rename(tempFilename
, filename
);
// Reopen the file for further operations
printf("Error reopening file!\n"); return;
}
printf("Expense edited successfully!\n"); }
void deleteExpense
(FILE *file, const char
*filename
) { // Display current expenses
printf("Current Expenses:\n");
// Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
int currentIndex = 1;
bool found = false;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) != 4) { printf("No expenses recorded.\n"); return;
}
printf("Index Category Amount Currency Date\n"); do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", currentIndex
, category
, amount
, currency
, date); currentIndex++;
} while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4);
int index;
printf("Enter the index of the expense you want to delete: "); scanf("%d", &index);
// Move file pointer to the beginning
// Create a temporary file to store updated data
char tempFilename[150];
sprintf(tempFilename
, "temp_%s", filename
); if (tempFile == NULL) {
printf("Error creating temporary file!\n"); return;
}
currentIndex = 1;
while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4) { if (currentIndex != index)
fprintf(tempFile
, "%s %.2f %s %s\n", category
, amount
, currency
, date); else
found = true;
currentIndex++;
}
if (!found) {
printf("Expense not found!\n"); remove(tempFilename); // Delete temporary file
return;
}
// Remove the old file
remove(filename);
// Rename the temporary file to the original filename
rename(tempFilename
, filename
);
// Reopen the file for further operations
printf("Error reopening file!\n"); return;
}
printf("Expense deleted successfully!\n"); }
void displayCategories() {
int i;
for (i
= 0; i
< sizeof(allowedCategories
) / sizeof(allowedCategories
[0]); i
++) { printf("%d. %s\n", i
+ 1, allowedCategories
[i
]); }
}
rewind(file); // Move file pointer to the beginning char category[50];
float amount;
char currency[4];
float categoryTotal
[sizeof(allowedCategories
) / sizeof(allowedCategories
[0])] = {0};
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) != 4) { printf("No expenses recorded.\n"); return;
}
// Iterate through expenses and calculate total spending per category
do {
for (int i
= 0; i
< sizeof(allowedCategories
) / sizeof(allowedCategories
[0]); i
++) { if (strcmp(category
, allowedCategories
[i
]) == 0) { categoryTotal[i] += amount;
break;
}
}
} while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4);
// Display total spending per category
printf("Category\tTotal Spending\n"); for (int i
= 0; i
< sizeof(allowedCategories
) / sizeof(allowedCategories
[0]); i
++) { printf("%s\t%.2f\n", allowedCategories
[i
], categoryTotal
[i
]); }
}
rewind(file); // Move file pointer to the beginning char category[50];
float amount;
char currency[4];
float total = 0.0f;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) != 4) { printf("No expenses recorded.\n"); return;
}
// Calculate total spending
do {
total += amount;
} while (fscanf(file, "%s %f %s %s", category
, &amount
, currency
, date) == 4);
float budget;
printf("Enter your budget: "); scanf("%f", &budget);
printf("Total spending: $%.2f\n", total
); printf("Budget: $%.2f\n", budget
);
if (total > budget) {
printf("You have exceeded your budget.\n"); } else {
printf("You are within your budget.\n"); }
}
size_t write_callback(char *ptr, size_t size, size_t nmemb, char *data) {
strcat(data, ptr);
return size * nmemb;
}
double getExchangeRate(const char *from, const char *to) {
// API request URL for fetching exchange rates
char url[100] = "https://o...content-available-to-author-only...i.com/v6/latest/";
strcat(url, from);
strcat(url, "?symbols=");
strcat(url, to);
// Initialize CURL
CURL *curl = curl_easy_init();
if (!curl) {
fprintf(stderr
, "Failed to initialize CURL\n"); return -1.0;
}
// Data buffer to store API response
char data[100];
data[0] = '\0';
// Set CURL options
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
// Perform the request
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr
, "Failed to perform CURL request: %s\n", curl_easy_strerror
(res
)); curl_easy_cleanup(curl);
return -1.0;
}
// Cleanup CURL
curl_easy_cleanup(curl);
// Parse the JSON response to get the exchange rate
if (!ptr) {
fprintf(stderr
, "Failed to parse JSON response\n"); return -1.0;
}
ptr
+= strlen(to
) + 3; // Move pointer to the exchange rate value return atof(ptr);
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8c3RkYm9vbC5oPgojaW5jbHVkZSA8Y3VybC9jdXJsLmg+CgojZGVmaW5lIEJBU0VfQ1VSUkVOQ1kgIlVTRCIKCi8vIERlZmluZSB0aGUgYWxsb3dlZCBleHBlbnNlIGNhdGVnb3JpZXMKY29uc3QgY2hhciAqYWxsb3dlZENhdGVnb3JpZXNbXSA9IHsKICAgICJIb3VzaW5nIiwgIlRyYW5zcG9ydGF0aW9uIiwgIkZvb2QiLCAiSGVhbHRoY2FyZSIsICJVdGlsaXRpZXMiLCAiRGVidCIsIAogICAgIlBlcnNvbmFsIENhcmUiLCAiRW50ZXJ0YWlubWVudCIsICJJbnN1cmFuY2UiLCAiRWR1Y2F0aW9uIiwgIlNhdmluZ3MvSW52ZXN0bWVudHMiLCAKICAgICJDbG90aGluZyIsICJDaGFyaXR5IiwgIlRyYXZlbCIsICJNaXNjZWxsYW5lb3VzIgp9OwoKLy8gRnVuY3Rpb24gcHJvdG90eXBlcwp2b2lkIGFkZEV4cGVuc2UoRklMRSAqZmlsZSk7CnZvaWQgZGlzcGxheUV4cGVuc2VzQW5kVG90YWwoRklMRSAqZmlsZSk7CnZvaWQgZGlzcGxheUV4cGVuc2VzUGVyTW9udGhBbmRUb3RhbChGSUxFICpmaWxlKTsKdm9pZCBlZGl0RXhwZW5zZShGSUxFICpmaWxlLCBjb25zdCBjaGFyICpmaWxlbmFtZSk7CnZvaWQgZGVsZXRlRXhwZW5zZShGSUxFICpmaWxlLCBjb25zdCBjaGFyICpmaWxlbmFtZSk7CnZvaWQgZGlzcGxheUNhdGVnb3JpZXMoKTsKdm9pZCBjYXRlZ29yaXplU3BlbmRpbmcoRklMRSAqZmlsZSk7CnZvaWQgdHJhY2tCdWRnZXQoRklMRSAqZmlsZSk7CnNpemVfdCB3cml0ZV9jYWxsYmFjayhjaGFyICpwdHIsIHNpemVfdCBzaXplLCBzaXplX3Qgbm1lbWIsIGNoYXIgKmRhdGEpOwpkb3VibGUgZ2V0RXhjaGFuZ2VSYXRlKGNvbnN0IGNoYXIgKmZyb20sIGNvbnN0IGNoYXIgKnRvKTsKCmludCBtYWluKCkgewogICAgY2hhciBmaXJzdF9uYW1lWzUwXSwgbGFzdF9uYW1lWzUwXTsKICAgIHByaW50ZigiRW50ZXIgeW91ciBmaXJzdCBhbmQgbGFzdCBuYW1lOiAiKTsKICAgIHNjYW5mKCIlcyAlcyIsIGZpcnN0X25hbWUsIGxhc3RfbmFtZSk7CgogICAgLy8gQ3JlYXRlIGEgZmlsZSB3aXRoIHRoZSB1c2VyJ3MgbmFtZSB0byBzdG9yZSBleHBlbnNlcyBvciBvcGVuIGV4aXN0aW5nIGZpbGUgaWYgaXQgZXhpc3RzCiAgICBjaGFyIGZpbGVuYW1lWzE1MF07IC8vIEFzc3VtaW5nIGEgbWF4aW11bSBsZW5ndGggb2YgMTUwIGNoYXJhY3RlcnMgZm9yIHRoZSBmaWxlbmFtZQogICAgc3ByaW50ZihmaWxlbmFtZSwgIiVzXyVzX2V4cGVuc2VzLnR4dCIsIGZpcnN0X25hbWUsIGxhc3RfbmFtZSk7CgogICAgaW50IGNob2ljZTsKCiAgICBkbyB7CiAgICAgICAgcHJpbnRmKCJcbkN1cnJlbnQgVXNlcjogJXMgJXNcbiIsIGZpcnN0X25hbWUsIGxhc3RfbmFtZSk7CiAgICAgICAgcHJpbnRmKCJFeHBlbnNlIFRyYWNrZXIgTWVudVxuIik7CiAgICAgICAgcHJpbnRmKCIxLiBBZGQgRXhwZW5zZVxuIik7CiAgICAgICAgcHJpbnRmKCIyLiBEaXNwbGF5IEV4cGVuc2VzIGFuZCBUb3RhbFxuIik7CiAgICAgICAgcHJpbnRmKCIzLiBEaXNwbGF5IEV4cGVuc2VzIHBlciBNb250aCBhbmQgVG90YWxcbiIpOwogICAgICAgIHByaW50ZigiNC4gRWRpdCBFeHBlbnNlXG4iKTsKICAgICAgICBwcmludGYoIjUuIERlbGV0ZSBFeHBlbnNlXG4iKTsKICAgICAgICBwcmludGYoIjYuIENhdGVnb3JpemUgU3BlbmRpbmdcbiIpOwogICAgICAgIHByaW50ZigiNy4gVHJhY2sgQnVkZ2V0XG4iKTsKICAgICAgICBwcmludGYoIjguIEV4aXRcbiIpOwogICAgICAgIHByaW50ZigiRW50ZXIgeW91ciBjaG9pY2U6ICIpOwogICAgICAgIHNjYW5mKCIlZCIsICZjaG9pY2UpOwoKICAgICAgICBGSUxFICpmaWxlID0gZm9wZW4oZmlsZW5hbWUsICJhKyIpOwogICAgICAgIGlmIChmaWxlID09IE5VTEwpIHsKICAgICAgICAgICAgcHJpbnRmKCJFcnJvciBvcGVuaW5nIGZpbGUhXG4iKTsKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgfQoKICAgICAgICBzd2l0Y2ggKGNob2ljZSkgewogICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICBhZGRFeHBlbnNlKGZpbGUpOwogICAgICAgICAgICAgICAgZmNsb3NlKGZpbGUpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgIGRpc3BsYXlFeHBlbnNlc0FuZFRvdGFsKGZpbGUpOwogICAgICAgICAgICAgICAgZmNsb3NlKGZpbGUpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgIGRpc3BsYXlFeHBlbnNlc1Blck1vbnRoQW5kVG90YWwoZmlsZSk7CiAgICAgICAgICAgICAgICBmY2xvc2UoZmlsZSk7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgZWRpdEV4cGVuc2UoZmlsZSwgZmlsZW5hbWUpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgIGRlbGV0ZUV4cGVuc2UoZmlsZSwgZmlsZW5hbWUpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgIGNhdGVnb3JpemVTcGVuZGluZyhmaWxlKTsKICAgICAgICAgICAgICAgIGZjbG9zZShmaWxlKTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIDc6CiAgICAgICAgICAgICAgICB0cmFja0J1ZGdldChmaWxlKTsKICAgICAgICAgICAgICAgIGZjbG9zZShmaWxlKTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIDg6CiAgICAgICAgICAgICAgICBwcmludGYoIkV4aXRpbmcuLi5cbiIpOwogICAgICAgICAgICAgICAgZmNsb3NlKGZpbGUpOyAvLyBDbG9zZSB0aGUgZmlsZSBiZWZvcmUgZXhpdGluZwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICBwcmludGYoIkludmFsaWQgY2hvaWNlISBQbGVhc2UgdHJ5IGFnYWluLlxuIik7CiAgICAgICAgfQogICAgfSB3aGlsZSAoY2hvaWNlICE9IDgpOwoKICAgIHJldHVybiAwOwp9Cgp2b2lkIGFkZEV4cGVuc2UoRklMRSAqZmlsZSkgewogICAgcHJpbnRmKCJBdmFpbGFibGUgRXhwZW5zZSBDYXRlZ29yaWVzOlxuIik7CiAgICBkaXNwbGF5Q2F0ZWdvcmllcygpOwogICAgCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgZGF0ZVsyMF07CiAgICBjaGFyIGN1cnJlbmN5WzRdOyAvLyBBc3N1bWluZyBjdXJyZW5jeSBjb2RlIGlzIDMgY2hhcmFjdGVycyBsb25nCiAgICAKICAgIGludCBjYXRlZ29yeU51bTsKICAgIC8vIElucHV0IHZhbGlkYXRpb24gZm9yIGNhdGVnb3J5IG51bWJlcgogICAgd2hpbGUgKHRydWUpIHsKICAgICAgICBwcmludGYoIkVudGVyIGNhdGVnb3J5IG51bWJlcjogIik7CiAgICAgICAgaWYgKHNjYW5mKCIlZCIsICZjYXRlZ29yeU51bSkgIT0gMSB8fCBjYXRlZ29yeU51bSA8IDEgfHwgY2F0ZWdvcnlOdW0gPiBzaXplb2YoYWxsb3dlZENhdGVnb3JpZXMpIC8gc2l6ZW9mKGFsbG93ZWRDYXRlZ29yaWVzWzBdKSkgewogICAgICAgICAgICBwcmludGYoIkludmFsaWQgY2F0ZWdvcnkgbnVtYmVyISBQbGVhc2UgY2hvb3NlIGEgdmFsaWQgY2F0ZWdvcnkgbnVtYmVyLlxuIik7CiAgICAgICAgICAgIC8vIENsZWFyIGlucHV0IGJ1ZmZlcgogICAgICAgICAgICB3aGlsZSAoZ2V0Y2hhcigpICE9ICdcbicpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHN0cmNweShjYXRlZ29yeSwgYWxsb3dlZENhdGVnb3JpZXNbY2F0ZWdvcnlOdW0gLSAxXSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgIH0KCiAgICAvLyBJbnB1dCB2YWxpZGF0aW9uIGZvciBhbW91bnQKICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgcHJpbnRmKCJFbnRlciBhbW91bnQ6ICIpOwogICAgICAgIGlmIChzY2FuZigiJWYiLCAmYW1vdW50KSA9PSAxICYmIGFtb3VudCA+IDAuMGYpCiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIGVsc2UgewogICAgICAgICAgICBwcmludGYoIkludmFsaWQgaW5wdXQhIFBsZWFzZSBlbnRlciBhIHZhbGlkIGFtb3VudCBncmVhdGVyIHRoYW4gMC5cbiIpOwogICAgICAgICAgICAvLyBDbGVhciBpbnB1dCBidWZmZXIKICAgICAgICAgICAgd2hpbGUgKGdldGNoYXIoKSAhPSAnXG4nKTsKICAgICAgICB9CiAgICB9CgogICAgLy8gSW5wdXQgdmFsaWRhdGlvbiBmb3IgZGF0ZSBmb3JtYXQgKERELU1NLVlZWVkpCiAgICBjaGFyIGRhdGVJbnB1dFsxMV07IC8vIEFzc3VtaW5nIG1heGltdW0gbGVuZ3RoIG9mIHRoZSBkYXRlIGlucHV0IGlzIDEwIGNoYXJhY3RlcnMgKGluY2x1ZGluZyBudWxsIHRlcm1pbmF0b3IpCiAgICB3aGlsZSAodHJ1ZSkgewogICAgICAgIHByaW50ZigiRW50ZXIgZGF0ZSAoREQtTU0tWVlZWSk6ICIpOwogICAgICAgIGlmIChzY2FuZigiJTEwcyIsIGRhdGVJbnB1dCkgIT0gMSkgewogICAgICAgICAgICBwcmludGYoIkludmFsaWQgaW5wdXQhIFBsZWFzZSBlbnRlciB0aGUgZGF0ZSBpbiBERC1NTS1ZWVlZIGZvcm1hdC5cbiIpOwogICAgICAgICAgICAvLyBDbGVhciBpbnB1dCBidWZmZXIKICAgICAgICAgICAgd2hpbGUgKGdldGNoYXIoKSAhPSAnXG4nKTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgfQoKICAgICAgICAvLyBQYXJzZSBkYXRlIGlucHV0IGludG8gZGF5LCBtb250aCwgYW5kIHllYXIgY29tcG9uZW50cwogICAgICAgIGludCBkYXksIG1vbnRoLCB5ZWFyOwogICAgICAgIGlmIChzc2NhbmYoZGF0ZUlucHV0LCAiJWQtJWQtJWQiLCAmZGF5LCAmbW9udGgsICZ5ZWFyKSAhPSAzKSB7CiAgICAgICAgICAgIHByaW50ZigiSW52YWxpZCBkYXRlIGZvcm1hdCEgUGxlYXNlIGVudGVyIHRoZSBkYXRlIGluIERELU1NLVlZWVkgZm9ybWF0LlxuIik7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KCiAgICAgICAgLy8gVmFsaWRhdGUgZGF5LCBtb250aCwgYW5kIHllYXIgcmFuZ2VzCiAgICAgICAgaWYgKGRheSA8IDEgfHwgZGF5ID4gMzEgfHwgbW9udGggPCAxIHx8IG1vbnRoID4gMTIgfHwgeWVhciA8IDE5MDAgfHwgeWVhciA+IDk5OTkpIHsKICAgICAgICAgICAgcHJpbnRmKCJJbnZhbGlkIGRhdGUhIFBsZWFzZSBlbnRlciBhIHZhbGlkIGRhdGUuXG4iKTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgfQoKICAgICAgICAvLyBEYXRlIGlucHV0IGlzIHZhbGlkCiAgICAgICAgc3ByaW50ZihkYXRlLCAiJTAyZC0lMDJkLSUwNGQiLCBkYXksIG1vbnRoLCB5ZWFyKTsKICAgICAgICBicmVhazsKICAgIH0KICAgIAogICAgLy8gSW5wdXQgY3VycmVuY3kgY29kZQogICAgcHJpbnRmKCJFbnRlciBjdXJyZW5jeSBjb2RlIChlLmcuLCBVU0QsIEVVUik6ICIpOwogICAgc2NhbmYoIiVzIiwgY3VycmVuY3kpOwoKICAgIC8vIENvbnZlcnQgY3VycmVuY3kgdG8gYmFzZSBjdXJyZW5jeSAoVVNEKQogICAgZG91YmxlIGV4Y2hhbmdlUmF0ZSA9IGdldEV4Y2hhbmdlUmF0ZShjdXJyZW5jeSwgQkFTRV9DVVJSRU5DWSk7CiAgICBpZiAoZXhjaGFuZ2VSYXRlIDwgMCkgewogICAgICAgIGZwcmludGYoc3RkZXJyLCAiRmFpbGVkIHRvIGdldCBleGNoYW5nZSByYXRlIGZvciAlcyB0byAlc1xuIiwgY3VycmVuY3ksIEJBU0VfQ1VSUkVOQ1kpOwogICAgICAgIHJldHVybjsKICAgIH0KCiAgICAvLyBDb252ZXJ0IGFtb3VudCB0byBiYXNlIGN1cnJlbmN5CiAgICBhbW91bnQgKj0gZXhjaGFuZ2VSYXRlOwoKICAgIC8vIFNhdmUgZXhwZW5zZSB0byBmaWxlCiAgICBmcHJpbnRmKGZpbGUsICIlcyAlLjJmICVzICVzXG4iLCBjYXRlZ29yeSwgYW1vdW50LCBCQVNFX0NVUlJFTkNZLCBkYXRlKTsKICAgIHByaW50ZigiRXhwZW5zZSBhZGRlZCBzdWNjZXNzZnVsbHkhXG4iKTsKfQoKdm9pZCBkaXNwbGF5RXhwZW5zZXNBbmRUb3RhbChGSUxFICpmaWxlKSB7CiAgICByZXdpbmQoZmlsZSk7IC8vIE1vdmUgZmlsZSBwb2ludGVyIHRvIHRoZSBiZWdpbm5pbmcKICAgIGNoYXIgY2F0ZWdvcnlbNTBdOwogICAgZmxvYXQgYW1vdW50OwogICAgY2hhciBjdXJyZW5jeVs0XTsKICAgIGNoYXIgZGF0ZVsyMF07CiAgICBmbG9hdCB0b3RhbCA9IDAuMGY7CiAgICBpbnQgZXhwZW5zZUNvdW50ID0gMDsKCiAgICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgYW55IGV4cGVuc2VzIGluIHRoZSBmaWxlCiAgICBpZiAoZnNjYW5mKGZpbGUsICIlcyAlZiAlcyAlcyIsIGNhdGVnb3J5LCAmYW1vdW50LCBjdXJyZW5jeSwgZGF0ZSkgIT0gNCkgewogICAgICAgIHByaW50ZigiTm8gZXhwZW5zZXMgcmVjb3JkZWQuXG4iKTsKICAgICAgICByZXR1cm47CiAgICB9CgogICAgcHJpbnRmKCJJbmRleCAgIENhdGVnb3J5ICAgICAgICBBbW91bnQgIEN1cnJlbmN5ICAgIERhdGVcbiIpOwogICAgZG8gewogICAgICAgIHByaW50ZigiJWRcdCUtMTVzJS4yZlx0JS0zc1x0JXNcbiIsICsrZXhwZW5zZUNvdW50LCBjYXRlZ29yeSwgYW1vdW50LCBjdXJyZW5jeSwgZGF0ZSk7CiAgICAgICAgdG90YWwgKz0gYW1vdW50OwogICAgfSB3aGlsZSAoZnNjYW5mKGZpbGUsICIlcyAlZiAlcyAlcyIsIGNhdGVnb3J5LCAmYW1vdW50LCBjdXJyZW5jeSwgZGF0ZSkgPT0gNCk7CgogICAgcHJpbnRmKCJcblRvdGFsIEV4cGVuc2VzOiAkJS4yZlxuIiwgdG90YWwpOwp9Cgp2b2lkIGRpc3BsYXlFeHBlbnNlc1Blck1vbnRoQW5kVG90YWwoRklMRSAqZmlsZSkgewogICAgcmV3aW5kKGZpbGUpOyAvLyBNb3ZlIGZpbGUgcG9pbnRlciB0byB0aGUgYmVnaW5uaW5nCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgY3VycmVuY3lbNF07CiAgICBjaGFyIGRhdGVbMjBdOwogICAgZmxvYXQgdG90YWwgPSAwLjBmOwoKICAgIC8vIEJ1ZmZlciB0byBzdG9yZSBtb250aCBhbmQgeWVhciBpbiBNTS1ZWVlZIGZvcm1hdAogICAgY2hhciBpbnB1dE1vbnRoWWVhcls4XTsKCiAgICBwcmludGYoIkVudGVyIG1vbnRoIGFuZCB5ZWFyIChNTS1ZWVlZKTogIik7CiAgICBzY2FuZigiJXMiLCBpbnB1dE1vbnRoWWVhcik7CgogICAgYm9vbCBmb3VuZEV4cGVuc2VzID0gZmFsc2U7CgogICAgd2hpbGUgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpID09IDQpIHsKICAgICAgICAvLyBFeHRyYWN0IG1vbnRoIGFuZCB5ZWFyIGZyb20gdGhlIGRhdGUKICAgICAgICBjaGFyIGV4cGVuc2VNb250aFllYXJbOF07CiAgICAgICAgc3RybmNweShleHBlbnNlTW9udGhZZWFyLCBkYXRlICsgMywgNyk7IC8vIEV4dHJhY3QgTU0tWVlZWSBmcm9tIERELU1NLVlZWVkKICAgICAgICBleHBlbnNlTW9udGhZZWFyWzddID0gJ1wwJzsKCiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGV4dHJhY3RlZCBtb250aCBhbmQgeWVhciBtYXRjaCB0aGUgdXNlci1wcm92aWRlZCBpbnB1dAogICAgICAgIGlmIChzdHJjbXAoZXhwZW5zZU1vbnRoWWVhciwgaW5wdXRNb250aFllYXIpID09IDApIHsKICAgICAgICAgICAgaWYgKCFmb3VuZEV4cGVuc2VzKSB7CiAgICAgICAgICAgICAgICBwcmludGYoIkNhdGVnb3J5XHRBbW91bnRcdEN1cnJlbmN5XHREYXRlXG4iKTsKICAgICAgICAgICAgICAgIGZvdW5kRXhwZW5zZXMgPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHByaW50ZigiJS0xNXMlLjJmXHQlLTNzXHQlc1xuIiwgY2F0ZWdvcnksIGFtb3VudCwgY3VycmVuY3ksIGRhdGUpOwogICAgICAgICAgICB0b3RhbCArPSBhbW91bnQ7CiAgICAgICAgfQogICAgfQoKICAgIGlmICghZm91bmRFeHBlbnNlcykgewogICAgICAgIHByaW50ZigiTm8gZXhwZW5zZXMgZm9yICVzXG4iLCBpbnB1dE1vbnRoWWVhcik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIHByaW50ZigiXG5Ub3RhbCBFeHBlbnNlcyBmb3IgJXM6ICQlLjJmXG4iLCBpbnB1dE1vbnRoWWVhciwgdG90YWwpOwp9Cgp2b2lkIGVkaXRFeHBlbnNlKEZJTEUgKmZpbGUsIGNvbnN0IGNoYXIgKmZpbGVuYW1lKSB7CiAgICAvLyBEaXNwbGF5IGN1cnJlbnQgZXhwZW5zZXMKICAgIHByaW50ZigiQ3VycmVudCBFeHBlbnNlczpcbiIpOwoKICAgIC8vIE1vdmUgZmlsZSBwb2ludGVyIHRvIHRoZSBiZWdpbm5pbmcKICAgIHJld2luZChmaWxlKTsKCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgY3VycmVuY3lbNF07CiAgICBjaGFyIGRhdGVbMjBdOwogICAgaW50IGN1cnJlbnRJbmRleCA9IDE7CiAgICBib29sIGZvdW5kID0gZmFsc2U7CgogICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBleHBlbnNlcyBpbiB0aGUgZmlsZQogICAgaWYgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpICE9IDQpIHsKICAgICAgICBwcmludGYoIk5vIGV4cGVuc2VzIHJlY29yZGVkLlxuIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIHByaW50ZigiSW5kZXggICBDYXRlZ29yeSAgICAgICAgQW1vdW50ICBDdXJyZW5jeSAgICBEYXRlXG4iKTsKICAgIGRvIHsKICAgICAgICBwcmludGYoIiVkXHQlLTE1cyUuMmZcdCUtM3NcdCVzXG4iLCBjdXJyZW50SW5kZXgsIGNhdGVnb3J5LCBhbW91bnQsIGN1cnJlbmN5LCBkYXRlKTsKICAgICAgICBjdXJyZW50SW5kZXgrKzsKICAgIH0gd2hpbGUgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpID09IDQpOwoKICAgIGludCBpbmRleDsKICAgIHByaW50ZigiRW50ZXIgdGhlIGluZGV4IG9mIHRoZSBleHBlbnNlIHlvdSB3YW50IHRvIGVkaXQ6ICIpOwogICAgc2NhbmYoIiVkIiwgJmluZGV4KTsKCiAgICAvLyBNb3ZlIGZpbGUgcG9pbnRlciB0byB0aGUgYmVnaW5uaW5nCiAgICByZXdpbmQoZmlsZSk7CgogICAgLy8gQ3JlYXRlIGEgdGVtcG9yYXJ5IGZpbGUgdG8gc3RvcmUgdXBkYXRlZCBkYXRhCiAgICBjaGFyIHRlbXBGaWxlbmFtZVsxNTBdOwogICAgc3ByaW50Zih0ZW1wRmlsZW5hbWUsICJ0ZW1wXyVzIiwgZmlsZW5hbWUpOwogICAgRklMRSAqdGVtcEZpbGUgPSBmb3Blbih0ZW1wRmlsZW5hbWUsICJ3KyIpOwogICAgaWYgKHRlbXBGaWxlID09IE5VTEwpIHsKICAgICAgICBwcmludGYoIkVycm9yIGNyZWF0aW5nIHRlbXBvcmFyeSBmaWxlIVxuIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIGN1cnJlbnRJbmRleCA9IDE7CiAgICBjaGFyIGRhdGVJbnB1dFsxMV07IC8vIE1vdmVkIHRoZSBkZWNsYXJhdGlvbiBvdXRzaWRlIHRoZSBzd2l0Y2ggc3RhdGVtZW50CiAgICB3aGlsZSAoZnNjYW5mKGZpbGUsICIlcyAlZiAlcyAlcyIsIGNhdGVnb3J5LCAmYW1vdW50LCBjdXJyZW5jeSwgZGF0ZSkgPT0gNCkgewogICAgICAgIGlmIChjdXJyZW50SW5kZXggPT0gaW5kZXgpIHsKICAgICAgICAgICAgLy8gRWRpdGluZyBsb2dpYyBoZXJlCiAgICAgICAgICAgIHByaW50ZigiV2hhdCBkbyB5b3Ugd2FudCB0byBlZGl0P1xuIik7CiAgICAgICAgICAgIHByaW50ZigiMS4gQ2F0ZWdvcnlcbiIpOwogICAgICAgICAgICBwcmludGYoIjIuIEFtb3VudFxuIik7CiAgICAgICAgICAgIHByaW50ZigiMy4gRGF0ZVxuIik7CiAgICAgICAgICAgIGludCBlZGl0Q2hvaWNlOwogICAgICAgICAgICBwcmludGYoIkVudGVyIHlvdXIgY2hvaWNlOiAiKTsKICAgICAgICAgICAgc2NhbmYoIiVkIiwgJmVkaXRDaG9pY2UpOwoKICAgICAgICAgICAgc3dpdGNoIChlZGl0Q2hvaWNlKSB7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgICAgLy8gRWRpdCBjYXRlZ29yeQogICAgICAgICAgICAgICAgICAgIHByaW50ZigiQ2hvb3NlIGEgbmV3IGNhdGVnb3J5OlxuIik7CiAgICAgICAgICAgICAgICAgICAgZGlzcGxheUNhdGVnb3JpZXMoKTsKICAgICAgICAgICAgICAgICAgICBpbnQgY2F0ZWdvcnlOdW07CiAgICAgICAgICAgICAgICAgICAgLy8gSW5wdXQgdmFsaWRhdGlvbiBmb3IgY2F0ZWdvcnkgbnVtYmVyCiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnRmKCJFbnRlciBjYXRlZ29yeSBudW1iZXI6ICIpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2NhbmYoIiVkIiwgJmNhdGVnb3J5TnVtKSAhPSAxIHx8IGNhdGVnb3J5TnVtIDwgMSB8fCBjYXRlZ29yeU51bSA+IHNpemVvZihhbGxvd2VkQ2F0ZWdvcmllcykgLyBzaXplb2YoYWxsb3dlZENhdGVnb3JpZXNbMF0pKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludGYoIkludmFsaWQgY2F0ZWdvcnkgbnVtYmVyISBQbGVhc2UgY2hvb3NlIGEgdmFsaWQgY2F0ZWdvcnkgbnVtYmVyLlxuIik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDbGVhciBpbnB1dCBidWZmZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChnZXRjaGFyKCkgIT0gJ1xuJyk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJjcHkoY2F0ZWdvcnksIGFsbG93ZWRDYXRlZ29yaWVzW2NhdGVnb3J5TnVtIC0gMV0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgICAgLy8gRWRpdCBhbW91bnQKICAgICAgICAgICAgICAgICAgICBwcmludGYoIkVudGVyIG5ldyBhbW91bnQ6ICIpOwogICAgICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzY2FuZigiJWYiLCAmYW1vdW50KSA9PSAxICYmIGFtb3VudCA+IDAuMGYpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludGYoIkludmFsaWQgaW5wdXQhIFBsZWFzZSBlbnRlciBhIHZhbGlkIGFtb3VudCBncmVhdGVyIHRoYW4gMC5cbiIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2xlYXIgaW5wdXQgYnVmZmVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSAoZ2V0Y2hhcigpICE9ICdcbicpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgICAgIC8vIEVkaXQgZGF0ZQogICAgICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHByaW50ZigiRW50ZXIgbmV3IGRhdGUgKERELU1NLVlZWVkpOiAiKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNjYW5mKCIlMTBzIiwgZGF0ZUlucHV0KSAhPSAxKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludGYoIkludmFsaWQgaW5wdXQhIFBsZWFzZSBlbnRlciB0aGUgZGF0ZSBpbiBERC1NTS1ZWVlZIGZvcm1hdC5cbiIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2xlYXIgaW5wdXQgYnVmZmVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSAoZ2V0Y2hhcigpICE9ICdcbicpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBhcnNlIGRhdGUgaW5wdXQgaW50byBkYXksIG1vbnRoLCBhbmQgeWVhciBjb21wb25lbnRzCiAgICAgICAgICAgICAgICAgICAgICAgIGludCBkYXksIG1vbnRoLCB5ZWFyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3NjYW5mKGRhdGVJbnB1dCwgIiVkLSVkLSVkIiwgJmRheSwgJm1vbnRoLCAmeWVhcikgIT0gMykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnRmKCJJbnZhbGlkIGRhdGUgZm9ybWF0ISBQbGVhc2UgZW50ZXIgdGhlIGRhdGUgaW4gREQtTU0tWVlZWSBmb3JtYXQuXG4iKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSBkYXksIG1vbnRoLCBhbmQgeWVhciByYW5nZXMKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRheSA8IDEgfHwgZGF5ID4gMzEgfHwgbW9udGggPCAxIHx8IG1vbnRoID4gMTIgfHwgeWVhciA8IDE5MDAgfHwgeWVhciA+IDk5OTkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50ZigiSW52YWxpZCBkYXRlISBQbGVhc2UgZW50ZXIgYSB2YWxpZCBkYXRlLlxuIik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGF0ZSBpbnB1dCBpcyB2YWxpZAogICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKGRhdGUsICIlMDJkLSUwMmQtJTA0ZCIsIGRheSwgbW9udGgsIHllYXIpOwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICAgIHByaW50ZigiSW52YWxpZCBjaG9pY2UhIFBsZWFzZSB0cnkgYWdhaW4uXG4iKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBmcHJpbnRmKHRlbXBGaWxlLCAiJXMgJS4yZiAlcyAlc1xuIiwgY2F0ZWdvcnksIGFtb3VudCwgY3VycmVuY3ksIGRhdGUpOwogICAgICAgIGN1cnJlbnRJbmRleCsrOwogICAgfQoKICAgIGZjbG9zZShmaWxlKTsKICAgIGZjbG9zZSh0ZW1wRmlsZSk7CgogICAgLy8gUmVtb3ZlIHRoZSBvbGQgZmlsZQogICAgcmVtb3ZlKGZpbGVuYW1lKTsKCiAgICAvLyBSZW5hbWUgdGhlIHRlbXBvcmFyeSBmaWxlIHRvIHRoZSBvcmlnaW5hbCBmaWxlbmFtZQogICAgcmVuYW1lKHRlbXBGaWxlbmFtZSwgZmlsZW5hbWUpOwoKICAgIC8vIFJlb3BlbiB0aGUgZmlsZSBmb3IgZnVydGhlciBvcGVyYXRpb25zCiAgICBmaWxlID0gZm9wZW4oZmlsZW5hbWUsICJyKyIpOwogICAgaWYgKGZpbGUgPT0gTlVMTCkgewogICAgICAgIHByaW50ZigiRXJyb3IgcmVvcGVuaW5nIGZpbGUhXG4iKTsKICAgICAgICByZXR1cm47CiAgICB9CgogICAgcHJpbnRmKCJFeHBlbnNlIGVkaXRlZCBzdWNjZXNzZnVsbHkhXG4iKTsKfQoKdm9pZCBkZWxldGVFeHBlbnNlKEZJTEUgKmZpbGUsIGNvbnN0IGNoYXIgKmZpbGVuYW1lKSB7CiAgICAvLyBEaXNwbGF5IGN1cnJlbnQgZXhwZW5zZXMKICAgIHByaW50ZigiQ3VycmVudCBFeHBlbnNlczpcbiIpOwoKICAgIC8vIE1vdmUgZmlsZSBwb2ludGVyIHRvIHRoZSBiZWdpbm5pbmcKICAgIHJld2luZChmaWxlKTsKCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgY3VycmVuY3lbNF07CiAgICBjaGFyIGRhdGVbMjBdOwogICAgaW50IGN1cnJlbnRJbmRleCA9IDE7CiAgICBib29sIGZvdW5kID0gZmFsc2U7CgogICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBleHBlbnNlcyBpbiB0aGUgZmlsZQogICAgaWYgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpICE9IDQpIHsKICAgICAgICBwcmludGYoIk5vIGV4cGVuc2VzIHJlY29yZGVkLlxuIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIHByaW50ZigiSW5kZXggICBDYXRlZ29yeSAgICAgICAgQW1vdW50ICBDdXJyZW5jeSAgICBEYXRlXG4iKTsKICAgIGRvIHsKICAgICAgICBwcmludGYoIiVkXHQlLTE1cyUuMmZcdCUtM3NcdCVzXG4iLCBjdXJyZW50SW5kZXgsIGNhdGVnb3J5LCBhbW91bnQsIGN1cnJlbmN5LCBkYXRlKTsKICAgICAgICBjdXJyZW50SW5kZXgrKzsKICAgIH0gd2hpbGUgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpID09IDQpOwoKICAgIGludCBpbmRleDsKICAgIHByaW50ZigiRW50ZXIgdGhlIGluZGV4IG9mIHRoZSBleHBlbnNlIHlvdSB3YW50IHRvIGRlbGV0ZTogIik7CiAgICBzY2FuZigiJWQiLCAmaW5kZXgpOwoKICAgIC8vIE1vdmUgZmlsZSBwb2ludGVyIHRvIHRoZSBiZWdpbm5pbmcKICAgIHJld2luZChmaWxlKTsKCiAgICAvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgZmlsZSB0byBzdG9yZSB1cGRhdGVkIGRhdGEKICAgIGNoYXIgdGVtcEZpbGVuYW1lWzE1MF07CiAgICBzcHJpbnRmKHRlbXBGaWxlbmFtZSwgInRlbXBfJXMiLCBmaWxlbmFtZSk7CiAgICBGSUxFICp0ZW1wRmlsZSA9IGZvcGVuKHRlbXBGaWxlbmFtZSwgIncrIik7CiAgICBpZiAodGVtcEZpbGUgPT0gTlVMTCkgewogICAgICAgIHByaW50ZigiRXJyb3IgY3JlYXRpbmcgdGVtcG9yYXJ5IGZpbGUhXG4iKTsKICAgICAgICByZXR1cm47CiAgICB9CgogICAgY3VycmVudEluZGV4ID0gMTsKICAgIHdoaWxlIChmc2NhbmYoZmlsZSwgIiVzICVmICVzICVzIiwgY2F0ZWdvcnksICZhbW91bnQsIGN1cnJlbmN5LCBkYXRlKSA9PSA0KSB7CiAgICAgICAgaWYgKGN1cnJlbnRJbmRleCAhPSBpbmRleCkKICAgICAgICAgICAgZnByaW50Zih0ZW1wRmlsZSwgIiVzICUuMmYgJXMgJXNcbiIsIGNhdGVnb3J5LCBhbW91bnQsIGN1cnJlbmN5LCBkYXRlKTsKICAgICAgICBlbHNlCiAgICAgICAgICAgIGZvdW5kID0gdHJ1ZTsKICAgICAgICBjdXJyZW50SW5kZXgrKzsKICAgIH0KCiAgICBmY2xvc2UoZmlsZSk7CiAgICBmY2xvc2UodGVtcEZpbGUpOwoKICAgIGlmICghZm91bmQpIHsKICAgICAgICBwcmludGYoIkV4cGVuc2Ugbm90IGZvdW5kIVxuIik7CiAgICAgICAgcmVtb3ZlKHRlbXBGaWxlbmFtZSk7IC8vIERlbGV0ZSB0ZW1wb3JhcnkgZmlsZQogICAgICAgIHJldHVybjsKICAgIH0KCiAgICAvLyBSZW1vdmUgdGhlIG9sZCBmaWxlCiAgICByZW1vdmUoZmlsZW5hbWUpOwoKICAgIC8vIFJlbmFtZSB0aGUgdGVtcG9yYXJ5IGZpbGUgdG8gdGhlIG9yaWdpbmFsIGZpbGVuYW1lCiAgICByZW5hbWUodGVtcEZpbGVuYW1lLCBmaWxlbmFtZSk7CgogICAgLy8gUmVvcGVuIHRoZSBmaWxlIGZvciBmdXJ0aGVyIG9wZXJhdGlvbnMKICAgIGZpbGUgPSBmb3BlbihmaWxlbmFtZSwgInIrIik7CiAgICBpZiAoZmlsZSA9PSBOVUxMKSB7CiAgICAgICAgcHJpbnRmKCJFcnJvciByZW9wZW5pbmcgZmlsZSFcbiIpOwogICAgICAgIHJldHVybjsKICAgIH0KCiAgICBwcmludGYoIkV4cGVuc2UgZGVsZXRlZCBzdWNjZXNzZnVsbHkhXG4iKTsKfQoKdm9pZCBkaXNwbGF5Q2F0ZWdvcmllcygpIHsKICAgIGludCBpOwogICAgZm9yIChpID0gMDsgaSA8IHNpemVvZihhbGxvd2VkQ2F0ZWdvcmllcykgLyBzaXplb2YoYWxsb3dlZENhdGVnb3JpZXNbMF0pOyBpKyspIHsKICAgICAgICBwcmludGYoIiVkLiAlc1xuIiwgaSArIDEsIGFsbG93ZWRDYXRlZ29yaWVzW2ldKTsKICAgIH0KfQoKdm9pZCBjYXRlZ29yaXplU3BlbmRpbmcoRklMRSAqZmlsZSkgewogICAgcmV3aW5kKGZpbGUpOyAvLyBNb3ZlIGZpbGUgcG9pbnRlciB0byB0aGUgYmVnaW5uaW5nCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgY3VycmVuY3lbNF07CiAgICBjaGFyIGRhdGVbMjBdOwogICAgZmxvYXQgY2F0ZWdvcnlUb3RhbFtzaXplb2YoYWxsb3dlZENhdGVnb3JpZXMpIC8gc2l6ZW9mKGFsbG93ZWRDYXRlZ29yaWVzWzBdKV0gPSB7MH07CgogICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBleHBlbnNlcyBpbiB0aGUgZmlsZQogICAgaWYgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpICE9IDQpIHsKICAgICAgICBwcmludGYoIk5vIGV4cGVuc2VzIHJlY29yZGVkLlxuIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIC8vIEl0ZXJhdGUgdGhyb3VnaCBleHBlbnNlcyBhbmQgY2FsY3VsYXRlIHRvdGFsIHNwZW5kaW5nIHBlciBjYXRlZ29yeQogICAgZG8gewogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgc2l6ZW9mKGFsbG93ZWRDYXRlZ29yaWVzKSAvIHNpemVvZihhbGxvd2VkQ2F0ZWdvcmllc1swXSk7IGkrKykgewogICAgICAgICAgICBpZiAoc3RyY21wKGNhdGVnb3J5LCBhbGxvd2VkQ2F0ZWdvcmllc1tpXSkgPT0gMCkgewogICAgICAgICAgICAgICAgY2F0ZWdvcnlUb3RhbFtpXSArPSBhbW91bnQ7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0gd2hpbGUgKGZzY2FuZihmaWxlLCAiJXMgJWYgJXMgJXMiLCBjYXRlZ29yeSwgJmFtb3VudCwgY3VycmVuY3ksIGRhdGUpID09IDQpOwoKICAgIC8vIERpc3BsYXkgdG90YWwgc3BlbmRpbmcgcGVyIGNhdGVnb3J5CiAgICBwcmludGYoIkNhdGVnb3J5XHRUb3RhbCBTcGVuZGluZ1xuIik7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IHNpemVvZihhbGxvd2VkQ2F0ZWdvcmllcykgLyBzaXplb2YoYWxsb3dlZENhdGVnb3JpZXNbMF0pOyBpKyspIHsKICAgICAgICBwcmludGYoIiVzXHQlLjJmXG4iLCBhbGxvd2VkQ2F0ZWdvcmllc1tpXSwgY2F0ZWdvcnlUb3RhbFtpXSk7CiAgICB9Cn0KCnZvaWQgdHJhY2tCdWRnZXQoRklMRSAqZmlsZSkgewogICAgcmV3aW5kKGZpbGUpOyAvLyBNb3ZlIGZpbGUgcG9pbnRlciB0byB0aGUgYmVnaW5uaW5nCiAgICBjaGFyIGNhdGVnb3J5WzUwXTsKICAgIGZsb2F0IGFtb3VudDsKICAgIGNoYXIgY3VycmVuY3lbNF07CiAgICBjaGFyIGRhdGVbMjBdOwogICAgZmxvYXQgdG90YWwgPSAwLjBmOwoKICAgIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBhbnkgZXhwZW5zZXMgaW4gdGhlIGZpbGUKICAgIGlmIChmc2NhbmYoZmlsZSwgIiVzICVmICVzICVzIiwgY2F0ZWdvcnksICZhbW91bnQsIGN1cnJlbmN5LCBkYXRlKSAhPSA0KSB7CiAgICAgICAgcHJpbnRmKCJObyBleHBlbnNlcyByZWNvcmRlZC5cbiIpOwogICAgICAgIHJldHVybjsKICAgIH0KCiAgICAvLyBDYWxjdWxhdGUgdG90YWwgc3BlbmRpbmcKICAgIGRvIHsKICAgICAgICB0b3RhbCArPSBhbW91bnQ7CiAgICB9IHdoaWxlIChmc2NhbmYoZmlsZSwgIiVzICVmICVzICVzIiwgY2F0ZWdvcnksICZhbW91bnQsIGN1cnJlbmN5LCBkYXRlKSA9PSA0KTsKCiAgICBmbG9hdCBidWRnZXQ7CiAgICBwcmludGYoIkVudGVyIHlvdXIgYnVkZ2V0OiAiKTsKICAgIHNjYW5mKCIlZiIsICZidWRnZXQpOwoKICAgIHByaW50ZigiVG90YWwgc3BlbmRpbmc6ICQlLjJmXG4iLCB0b3RhbCk7CiAgICBwcmludGYoIkJ1ZGdldDogJCUuMmZcbiIsIGJ1ZGdldCk7CgogICAgaWYgKHRvdGFsID4gYnVkZ2V0KSB7CiAgICAgICAgcHJpbnRmKCJZb3UgaGF2ZSBleGNlZWRlZCB5b3VyIGJ1ZGdldC5cbiIpOwogICAgfSBlbHNlIHsKICAgICAgICBwcmludGYoIllvdSBhcmUgd2l0aGluIHlvdXIgYnVkZ2V0LlxuIik7CiAgICB9Cn0KCnNpemVfdCB3cml0ZV9jYWxsYmFjayhjaGFyICpwdHIsIHNpemVfdCBzaXplLCBzaXplX3Qgbm1lbWIsIGNoYXIgKmRhdGEpIHsKICAgIHN0cmNhdChkYXRhLCBwdHIpOwogICAgcmV0dXJuIHNpemUgKiBubWVtYjsKfQoKZG91YmxlIGdldEV4Y2hhbmdlUmF0ZShjb25zdCBjaGFyICpmcm9tLCBjb25zdCBjaGFyICp0bykgewogICAgLy8gQVBJIHJlcXVlc3QgVVJMIGZvciBmZXRjaGluZyBleGNoYW5nZSByYXRlcwogICAgY2hhciB1cmxbMTAwXSA9ICJodHRwczovL28uLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmkuY29tL3Y2L2xhdGVzdC8iOwogICAgc3RyY2F0KHVybCwgZnJvbSk7CiAgICBzdHJjYXQodXJsLCAiP3N5bWJvbHM9Iik7CiAgICBzdHJjYXQodXJsLCB0byk7CgogICAgLy8gSW5pdGlhbGl6ZSBDVVJMCiAgICBDVVJMICpjdXJsID0gY3VybF9lYXN5X2luaXQoKTsKICAgIGlmICghY3VybCkgewogICAgICAgIGZwcmludGYoc3RkZXJyLCAiRmFpbGVkIHRvIGluaXRpYWxpemUgQ1VSTFxuIik7CiAgICAgICAgcmV0dXJuIC0xLjA7CiAgICB9CgogICAgLy8gRGF0YSBidWZmZXIgdG8gc3RvcmUgQVBJIHJlc3BvbnNlCiAgICBjaGFyIGRhdGFbMTAwXTsKICAgIGRhdGFbMF0gPSAnXDAnOwoKICAgIC8vIFNldCBDVVJMIG9wdGlvbnMKICAgIGN1cmxfZWFzeV9zZXRvcHQoY3VybCwgQ1VSTE9QVF9VUkwsIHVybCk7CiAgICBjdXJsX2Vhc3lfc2V0b3B0KGN1cmwsIENVUkxPUFRfV1JJVEVGVU5DVElPTiwgd3JpdGVfY2FsbGJhY2spOwogICAgY3VybF9lYXN5X3NldG9wdChjdXJsLCBDVVJMT1BUX1dSSVRFREFUQSwgZGF0YSk7CgogICAgLy8gUGVyZm9ybSB0aGUgcmVxdWVzdAogICAgQ1VSTGNvZGUgcmVzID0gY3VybF9lYXN5X3BlcmZvcm0oY3VybCk7CiAgICBpZiAocmVzICE9IENVUkxFX09LKSB7CiAgICAgICAgZnByaW50ZihzdGRlcnIsICJGYWlsZWQgdG8gcGVyZm9ybSBDVVJMIHJlcXVlc3Q6ICVzXG4iLCBjdXJsX2Vhc3lfc3RyZXJyb3IocmVzKSk7CiAgICAgICAgY3VybF9lYXN5X2NsZWFudXAoY3VybCk7CiAgICAgICAgcmV0dXJuIC0xLjA7CiAgICB9CgogICAgLy8gQ2xlYW51cCBDVVJMCiAgICBjdXJsX2Vhc3lfY2xlYW51cChjdXJsKTsKCiAgICAvLyBQYXJzZSB0aGUgSlNPTiByZXNwb25zZSB0byBnZXQgdGhlIGV4Y2hhbmdlIHJhdGUKICAgIGNoYXIgKnB0ciA9IHN0cnN0cihkYXRhLCB0byk7CiAgICBpZiAoIXB0cikgewogICAgICAgIGZwcmludGYoc3RkZXJyLCAiRmFpbGVkIHRvIHBhcnNlIEpTT04gcmVzcG9uc2VcbiIpOwogICAgICAgIHJldHVybiAtMS4wOwogICAgfQogICAgcHRyICs9IHN0cmxlbih0bykgKyAzOyAvLyBNb3ZlIHBvaW50ZXIgdG8gdGhlIGV4Y2hhbmdlIHJhdGUgdmFsdWUKICAgIHJldHVybiBhdG9mKHB0cik7Cn0K
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <curl/curl.h>
#define BASE_CURRENCY "USD"
// Define the allowed expense categories
const char *allowedCategories[] = {
"Housing", "Transportation", "Food", "Healthcare", "Utilities", "Debt",
"Personal Care", "Entertainment", "Insurance", "Education", "Savings/Investments",
"Clothing", "Charity", "Travel", "Miscellaneous"
};
// Function prototypes
void addExpense(FILE *file);
void displayExpensesAndTotal(FILE *file);
void displayExpensesPerMonthAndTotal(FILE *file);
void editExpense(FILE *file, const char *filename);
void deleteExpense(FILE *file, const char *filename);
void displayCategories();
void categorizeSpending(FILE *file);
void trackBudget(FILE *file);
size_t write_callback(char *ptr, size_t size, size_t nmemb, char *data);
double getExchangeRate(const char *from, const char *to);
int main() {
char first_name[50], last_name[50];
printf("Enter your first and last name: ");
scanf("%s %s", first_name, last_name);
// Create a file with the user's name to store expenses or open existing file if it exists
char filename[150]; // Assuming a maximum length of 150 characters for the filename
sprintf(filename, "%s_%s_expenses.txt", first_name, last_name);
int choice;
do {
printf("\nCurrent User: %s %s\n", first_name, last_name);
printf("Expense Tracker Menu\n");
printf("1. Add Expense\n");
printf("2. Display Expenses and Total\n");
printf("3. Display Expenses per Month and Total\n");
printf("4. Edit Expense\n");
printf("5. Delete Expense\n");
printf("6. Categorize Spending\n");
printf("7. Track Budget\n");
printf("8. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
FILE *file = fopen(filename, "a+");
if (file == NULL) {
printf("Error opening file!\n");
return 1;
}
switch (choice) {
case 1:
addExpense(file);
fclose(file);
break;
case 2:
displayExpensesAndTotal(file);
fclose(file);
break;
case 3:
displayExpensesPerMonthAndTotal(file);
fclose(file);
break;
case 4:
editExpense(file, filename);
break;
case 5:
deleteExpense(file, filename);
break;
case 6:
categorizeSpending(file);
fclose(file);
break;
case 7:
trackBudget(file);
fclose(file);
break;
case 8:
printf("Exiting...\n");
fclose(file); // Close the file before exiting
break;
default:
printf("Invalid choice! Please try again.\n");
}
} while (choice != 8);
return 0;
}
void addExpense(FILE *file) {
printf("Available Expense Categories:\n");
displayCategories();
char category[50];
float amount;
char date[20];
char currency[4]; // Assuming currency code is 3 characters long
int categoryNum;
// Input validation for category number
while (true) {
printf("Enter category number: ");
if (scanf("%d", &categoryNum) != 1 || categoryNum < 1 || categoryNum > sizeof(allowedCategories) / sizeof(allowedCategories[0])) {
printf("Invalid category number! Please choose a valid category number.\n");
// Clear input buffer
while (getchar() != '\n');
} else {
strcpy(category, allowedCategories[categoryNum - 1]);
break;
}
}
// Input validation for amount
while (true) {
printf("Enter amount: ");
if (scanf("%f", &amount) == 1 && amount > 0.0f)
break;
else {
printf("Invalid input! Please enter a valid amount greater than 0.\n");
// Clear input buffer
while (getchar() != '\n');
}
}
// Input validation for date format (DD-MM-YYYY)
char dateInput[11]; // Assuming maximum length of the date input is 10 characters (including null terminator)
while (true) {
printf("Enter date (DD-MM-YYYY): ");
if (scanf("%10s", dateInput) != 1) {
printf("Invalid input! Please enter the date in DD-MM-YYYY format.\n");
// Clear input buffer
while (getchar() != '\n');
continue;
}
// Parse date input into day, month, and year components
int day, month, year;
if (sscanf(dateInput, "%d-%d-%d", &day, &month, &year) != 3) {
printf("Invalid date format! Please enter the date in DD-MM-YYYY format.\n");
continue;
}
// Validate day, month, and year ranges
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1900 || year > 9999) {
printf("Invalid date! Please enter a valid date.\n");
continue;
}
// Date input is valid
sprintf(date, "%02d-%02d-%04d", day, month, year);
break;
}
// Input currency code
printf("Enter currency code (e.g., USD, EUR): ");
scanf("%s", currency);
// Convert currency to base currency (USD)
double exchangeRate = getExchangeRate(currency, BASE_CURRENCY);
if (exchangeRate < 0) {
fprintf(stderr, "Failed to get exchange rate for %s to %s\n", currency, BASE_CURRENCY);
return;
}
// Convert amount to base currency
amount *= exchangeRate;
// Save expense to file
fprintf(file, "%s %.2f %s %s\n", category, amount, BASE_CURRENCY, date);
printf("Expense added successfully!\n");
}
void displayExpensesAndTotal(FILE *file) {
rewind(file); // Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
char date[20];
float total = 0.0f;
int expenseCount = 0;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category, &amount, currency, date) != 4) {
printf("No expenses recorded.\n");
return;
}
printf("Index Category Amount Currency Date\n");
do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", ++expenseCount, category, amount, currency, date);
total += amount;
} while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4);
printf("\nTotal Expenses: $%.2f\n", total);
}
void displayExpensesPerMonthAndTotal(FILE *file) {
rewind(file); // Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
char date[20];
float total = 0.0f;
// Buffer to store month and year in MM-YYYY format
char inputMonthYear[8];
printf("Enter month and year (MM-YYYY): ");
scanf("%s", inputMonthYear);
bool foundExpenses = false;
while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4) {
// Extract month and year from the date
char expenseMonthYear[8];
strncpy(expenseMonthYear, date + 3, 7); // Extract MM-YYYY from DD-MM-YYYY
expenseMonthYear[7] = '\0';
// Check if the extracted month and year match the user-provided input
if (strcmp(expenseMonthYear, inputMonthYear) == 0) {
if (!foundExpenses) {
printf("Category\tAmount\tCurrency\tDate\n");
foundExpenses = true;
}
printf("%-15s%.2f\t%-3s\t%s\n", category, amount, currency, date);
total += amount;
}
}
if (!foundExpenses) {
printf("No expenses for %s\n", inputMonthYear);
return;
}
printf("\nTotal Expenses for %s: $%.2f\n", inputMonthYear, total);
}
void editExpense(FILE *file, const char *filename) {
// Display current expenses
printf("Current Expenses:\n");
// Move file pointer to the beginning
rewind(file);
char category[50];
float amount;
char currency[4];
char date[20];
int currentIndex = 1;
bool found = false;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category, &amount, currency, date) != 4) {
printf("No expenses recorded.\n");
return;
}
printf("Index Category Amount Currency Date\n");
do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", currentIndex, category, amount, currency, date);
currentIndex++;
} while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4);
int index;
printf("Enter the index of the expense you want to edit: ");
scanf("%d", &index);
// Move file pointer to the beginning
rewind(file);
// Create a temporary file to store updated data
char tempFilename[150];
sprintf(tempFilename, "temp_%s", filename);
FILE *tempFile = fopen(tempFilename, "w+");
if (tempFile == NULL) {
printf("Error creating temporary file!\n");
return;
}
currentIndex = 1;
char dateInput[11]; // Moved the declaration outside the switch statement
while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4) {
if (currentIndex == index) {
// Editing logic here
printf("What do you want to edit?\n");
printf("1. Category\n");
printf("2. Amount\n");
printf("3. Date\n");
int editChoice;
printf("Enter your choice: ");
scanf("%d", &editChoice);
switch (editChoice) {
case 1:
// Edit category
printf("Choose a new category:\n");
displayCategories();
int categoryNum;
// Input validation for category number
while (true) {
printf("Enter category number: ");
if (scanf("%d", &categoryNum) != 1 || categoryNum < 1 || categoryNum > sizeof(allowedCategories) / sizeof(allowedCategories[0])) {
printf("Invalid category number! Please choose a valid category number.\n");
// Clear input buffer
while (getchar() != '\n');
} else {
strcpy(category, allowedCategories[categoryNum - 1]);
break;
}
}
break;
case 2:
// Edit amount
printf("Enter new amount: ");
while (true) {
if (scanf("%f", &amount) == 1 && amount > 0.0f)
break;
else {
printf("Invalid input! Please enter a valid amount greater than 0.\n");
// Clear input buffer
while (getchar() != '\n');
}
}
break;
case 3:
// Edit date
while (true) {
printf("Enter new date (DD-MM-YYYY): ");
if (scanf("%10s", dateInput) != 1) {
printf("Invalid input! Please enter the date in DD-MM-YYYY format.\n");
// Clear input buffer
while (getchar() != '\n');
continue;
}
// Parse date input into day, month, and year components
int day, month, year;
if (sscanf(dateInput, "%d-%d-%d", &day, &month, &year) != 3) {
printf("Invalid date format! Please enter the date in DD-MM-YYYY format.\n");
continue;
}
// Validate day, month, and year ranges
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 1900 || year > 9999) {
printf("Invalid date! Please enter a valid date.\n");
continue;
}
// Date input is valid
sprintf(date, "%02d-%02d-%04d", day, month, year);
break;
}
break;
default:
printf("Invalid choice! Please try again.\n");
}
}
fprintf(tempFile, "%s %.2f %s %s\n", category, amount, currency, date);
currentIndex++;
}
fclose(file);
fclose(tempFile);
// Remove the old file
remove(filename);
// Rename the temporary file to the original filename
rename(tempFilename, filename);
// Reopen the file for further operations
file = fopen(filename, "r+");
if (file == NULL) {
printf("Error reopening file!\n");
return;
}
printf("Expense edited successfully!\n");
}
void deleteExpense(FILE *file, const char *filename) {
// Display current expenses
printf("Current Expenses:\n");
// Move file pointer to the beginning
rewind(file);
char category[50];
float amount;
char currency[4];
char date[20];
int currentIndex = 1;
bool found = false;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category, &amount, currency, date) != 4) {
printf("No expenses recorded.\n");
return;
}
printf("Index Category Amount Currency Date\n");
do {
printf("%d\t%-15s%.2f\t%-3s\t%s\n", currentIndex, category, amount, currency, date);
currentIndex++;
} while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4);
int index;
printf("Enter the index of the expense you want to delete: ");
scanf("%d", &index);
// Move file pointer to the beginning
rewind(file);
// Create a temporary file to store updated data
char tempFilename[150];
sprintf(tempFilename, "temp_%s", filename);
FILE *tempFile = fopen(tempFilename, "w+");
if (tempFile == NULL) {
printf("Error creating temporary file!\n");
return;
}
currentIndex = 1;
while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4) {
if (currentIndex != index)
fprintf(tempFile, "%s %.2f %s %s\n", category, amount, currency, date);
else
found = true;
currentIndex++;
}
fclose(file);
fclose(tempFile);
if (!found) {
printf("Expense not found!\n");
remove(tempFilename); // Delete temporary file
return;
}
// Remove the old file
remove(filename);
// Rename the temporary file to the original filename
rename(tempFilename, filename);
// Reopen the file for further operations
file = fopen(filename, "r+");
if (file == NULL) {
printf("Error reopening file!\n");
return;
}
printf("Expense deleted successfully!\n");
}
void displayCategories() {
int i;
for (i = 0; i < sizeof(allowedCategories) / sizeof(allowedCategories[0]); i++) {
printf("%d. %s\n", i + 1, allowedCategories[i]);
}
}
void categorizeSpending(FILE *file) {
rewind(file); // Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
char date[20];
float categoryTotal[sizeof(allowedCategories) / sizeof(allowedCategories[0])] = {0};
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category, &amount, currency, date) != 4) {
printf("No expenses recorded.\n");
return;
}
// Iterate through expenses and calculate total spending per category
do {
for (int i = 0; i < sizeof(allowedCategories) / sizeof(allowedCategories[0]); i++) {
if (strcmp(category, allowedCategories[i]) == 0) {
categoryTotal[i] += amount;
break;
}
}
} while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4);
// Display total spending per category
printf("Category\tTotal Spending\n");
for (int i = 0; i < sizeof(allowedCategories) / sizeof(allowedCategories[0]); i++) {
printf("%s\t%.2f\n", allowedCategories[i], categoryTotal[i]);
}
}
void trackBudget(FILE *file) {
rewind(file); // Move file pointer to the beginning
char category[50];
float amount;
char currency[4];
char date[20];
float total = 0.0f;
// Check if there are any expenses in the file
if (fscanf(file, "%s %f %s %s", category, &amount, currency, date) != 4) {
printf("No expenses recorded.\n");
return;
}
// Calculate total spending
do {
total += amount;
} while (fscanf(file, "%s %f %s %s", category, &amount, currency, date) == 4);
float budget;
printf("Enter your budget: ");
scanf("%f", &budget);
printf("Total spending: $%.2f\n", total);
printf("Budget: $%.2f\n", budget);
if (total > budget) {
printf("You have exceeded your budget.\n");
} else {
printf("You are within your budget.\n");
}
}
size_t write_callback(char *ptr, size_t size, size_t nmemb, char *data) {
strcat(data, ptr);
return size * nmemb;
}
double getExchangeRate(const char *from, const char *to) {
// API request URL for fetching exchange rates
char url[100] = "https://o...content-available-to-author-only...i.com/v6/latest/";
strcat(url, from);
strcat(url, "?symbols=");
strcat(url, to);
// Initialize CURL
CURL *curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "Failed to initialize CURL\n");
return -1.0;
}
// Data buffer to store API response
char data[100];
data[0] = '\0';
// Set CURL options
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
// Perform the request
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Failed to perform CURL request: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return -1.0;
}
// Cleanup CURL
curl_easy_cleanup(curl);
// Parse the JSON response to get the exchange rate
char *ptr = strstr(data, to);
if (!ptr) {
fprintf(stderr, "Failed to parse JSON response\n");
return -1.0;
}
ptr += strlen(to) + 3; // Move pointer to the exchange rate value
return atof(ptr);
}