9511_project03

Command line program that parses a bank .csv file and generates and output file in format .csv or .xml containing the debits and credits of every user.
Index Commits Files Refs README LICENSE
commit 3ae4b956f9251c372ff86f743afb905df7ef47ae
parent 7de7356a1b085cf76c9818d475f1145e44a62a16
Author: klewer-martin <martin.cachari@gmail.com>
Date:   Wed, 28 Jul 2021 23:24:08 -0300

Update:

Diffstat:
MMakefile | 8++++----
Dinclude/io.h | 66------------------------------------------------------------------
Dinclude/sort.h | 18------------------
Minclude/user.h | 1+
Ainclude/utils.h | 36++++++++++++++++++++++++++++++++++++
Minclude/vector.h | 10+++-------
Dsource/io.c | 112-------------------------------------------------------------------------------
Msource/main.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Dsource/sort.c | 53-----------------------------------------------------
Msource/user.c | 4+++-
Asource/utils.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msource/vector.c | 42+++++++++++-------------------------------
12 files changed, 195 insertions(+), 302 deletions(-)
diff --git a/Makefile b/Makefile
@@ -6,8 +6,8 @@ PROGNAME=main
 
 all: main clean
 
-main: cla.o status.o io.o main.o user.o vector.o
-    $(CC) $(CFLAGS) main.o cla.o status.o io.o user.o vector.o -o $(PROGNAME)
+main: cla.o status.o utils.o main.o user.o vector.o
+    $(CC) $(CFLAGS) main.o cla.o status.o utils.o user.o vector.o -o $(PROGNAME)
 
 main.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h $(HFOLDER)/user.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/main.c
@@ -21,8 +21,8 @@ vector.o: $(HFOLDER)/vector.h $(HFOLDER)/status.h
 status.o: $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/status.c
 
-io.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
-    $(CC) $(CFLAGS) -c $(SRCFOLDER)/io.c
+utils.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
+    $(CC) $(CFLAGS) -c $(SRCFOLDER)/utils.c
 
 user.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/user.c
diff --git a/include/io.h b/include/io.h
@@ -1,66 +0,0 @@
-#ifndef IO__H
-#define IO__H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cla.h"
-#include "user.h"
-#include "status.h"
-
-#define _XOPEN_SOURCE
-#define __USE_XOPEN
-#include <time.h>
-
-#define INIT_SIZE        1000
-#define INPUT_FILE_FIELDS 6
-
-#define BUFFER_SIZE        1000
-#define GROWTH_FACTOR     2
-
-#define INPUT_FILE_DELIM ","
-#define CSV_OUTPUT_DELIM    ","
-
-#define XML_HEADER        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
-#define XML_ROOT_OPEN    "<root>"
-#define XML_ROOT_CLOSE    "</root>"
-
-#define XML_ROW_OPEN    "<row>"
-#define XML_ROW_CLOSE    "</row>"
-
-#define XML_ID_OPEN        "<user>"
-#define XML_ID_CLOSE    "</user>"
-
-#define XML_CREDIT_OPEN        "<credits>"
-#define XML_CREDIT_CLOSE    "</credits>"
-
-#define XML_DEBT_OPEN    "<debits>"
-#define XML_DEBT_CLOSE    "</debits>"
-
-/* typedef enum { */
-/*     POS_ID_TXN, */
-/*     POS_USER_ID, */
-/*     POS_TXN_DATE, */
-/*     POS_AMOUNT, */
-/*     POS_CARD_NUMBER, */
-/*     POS_DESC */
-/* } csv_pos_t; */
-
-status_t string_split(char *s, char **data, char *delim);
-
-status_t load_values(FILE *, cla_t *data);
-
-void clean_data(char **data);
-
-/*
-status_t export_data_as_csv(FILE *fo, const user_t *users, size_t size);
-status_t export_data_as_xml(FILE *fo, const user_t *users, size_t size);
-*/
-
-status_t destroy_data(char **, size_t);
-status_t get_date(time_t *e, char **data);
-
-void clean_buffer(char *buf);
-
-#endif
diff --git a/include/sort.h b/include/sort.h
@@ -1,18 +0,0 @@
-#ifndef SORT__H
-#define SORT__H
-
-#include "cla.h"
-#include "user.h"
-#include "status.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int credit_minmax(const void *, const void *);
-int credit_maxmix(const void *, const void *);
-
-int debt_minmax(const void *, const void *);
-int debt_maxmin(const void *, const void *);
-
-
-#endif
diff --git a/include/user.h b/include/user.h
@@ -2,6 +2,7 @@
 #define USER__H
 
 #include "status.h"
+#include "utils.h"
 
 #define OUT_FILE_DELIM    ","
 
diff --git a/include/utils.h b/include/utils.h
@@ -0,0 +1,36 @@
+#ifndef UTILS__H
+#define UTILS__H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cla.h"
+#include "user.h"
+#include "status.h"
+
+#define _XOPEN_SOURCE
+#define __USE_XOPEN
+#include <time.h>
+
+#define IN_FILE_MAX_LEN    100
+#define IN_FILE_DELIM    ","
+#define IN_FILE_FIELDS    6
+#define IN_FILE_FIELDS_MAX_LEN    50
+
+#define XML_STR_HEADER    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+#define XML_STR_ROOT    "root"
+#define XML_STR_ROW        "row"
+#define XML_STR_ID        "user"
+#define XML_STR_CREDIT    "credits"
+#define XML_STR_DEBIT    "debits"
+
+status_t get_date(time_t *, char **);
+status_t array_destroy(char **, size_t);
+status_t string_split(char *, char **, char *);
+
+void clean_array(char **);
+void clean_buffer(char *);
+
+
+#endif
diff --git a/include/vector.h b/include/vector.h
@@ -4,11 +4,9 @@
 #define VECTOR_INIT_SIZE        10
 #define VECTOR_GROWTH_FACTOR    2
 
-#define STR_XML_ROOT    "root"
-#define STR_XML_HEADER    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
-
 #include <stdlib.h>
 
+#include "utils.h"
 #include "status.h"
 
 typedef status_t (*printer_t)(const void *, FILE *);
@@ -27,8 +25,6 @@ status_t ADT_Vector_create(ADT_Vector_t **);
 status_t ADT_Vector_add(ADT_Vector_t **, void *);
 status_t ADT_Vector_destroy(ADT_Vector_t **);
 
-status_t ADT_Vector_load(ADT_Vector_t *, FILE *);
-
 status_t ADT_Vector_set(ADT_Vector_t **, void *, size_t);
 status_t ADT_Vector_print(const ADT_Vector_t *, FILE *, printer_t);
 status_t ADT_Vector_sort(ADT_Vector_t *, comparator_t);
@@ -38,7 +34,7 @@ void *ADT_Vector_get_elem(const ADT_Vector_t *v, void *e);
 status_t ADT_Vector_set_printer(ADT_Vector_t *, printer_t);
 status_t ADT_Vector_set_comparator(ADT_Vector_t *, comparator_t);
 
-status_t ADT_Vector_export_as_xml(ADT_Vector_t *, FILE *, printer_t);
-status_t ADT_Vector_export_as_csv(ADT_Vector_t *, FILE *, printer_t);
+status_t ADT_Vector_export_as_xml(const ADT_Vector_t *, FILE *, printer_t);
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *, FILE *, printer_t);
 
 #endif
diff --git a/source/io.c b/source/io.c
@@ -1,112 +0,0 @@
-#include "../include/io.h"
-
-status_t string_split(char *s, char **data, char *delim)
-{
-    char *p, *tmp;
-    size_t fields = 0;
-
-    for(p = s; (tmp = strtok(p, delim)); p = NULL)
-        strcpy(data[fields++], tmp);
-
-    if(fields != INPUT_FILE_FIELDS)
-        return ERROR_CORRUPT_DATA;
-
-    return OK;
-}
-
-status_t destroy_data(char **data, size_t fields)
-{
-    size_t i;
-
-    if(data == NULL) return ERROR_NULL_POINTER;
-
-    for(i = 0; i < fields; i++) {
-        free(data[i]);
-        data[i] = NULL;
-    }
-
-    free(data);
-    return OK;
-}
-/*
-status_t export_data_as_csv(FILE *fo, const user_t *users, size_t size)
-{
-    size_t i;
-
-    if(fo == NULL || users == NULL)
-        return ERROR_NULL_POINTER;
-
-    for(i = 0; i < size; i++)
-        fprintf(fo, "%ld%s%ld%s%ld\n", users[i]->id, CSV_OUTPUT_DELIM,\
-                users[i]->c, CSV_OUTPUT_DELIM, users[i]->d);
-
-    return OK;
-}
-
-status_t export_data_as_xml(FILE *fo, const user_t *users, size_t size)
-{
-    size_t i;
-
-    if(fo == NULL || users == NULL)
-        return ERROR_NULL_POINTER;
-
-    fprintf(fo, "%s\n%s\n", XML_HEADER, XML_ROOT_OPEN);
-
-    for(i = 0; i < size; i++) {
-        fprintf(fo, "\t%s\n", XML_ROW_OPEN);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_ID_OPEN, users[i]->id, XML_ID_CLOSE);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_CREDIT_OPEN, users[i]->c, XML_CREDIT_CLOSE);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_DEBT_OPEN, users[i]->d, XML_DEBT_CLOSE);
-        fprintf(fo, "\t%s\n", XML_ROW_CLOSE);
-    }
-
-    fprintf(fo, "%s\n", XML_ROOT_CLOSE);
-    return OK;
-}
-*/
-void clean_buffer(char *buf)
-{
-    size_t i;
-
-    for(i = 0; i < BUFFER_SIZE; i++)
-        buf[i] = '\0';
-}
-
-void clean_data(char **data)
-{
-    size_t i;
-
-    for(i = 0; i < INPUT_FILE_FIELDS; i++) {
-        free(data[i]);
-        data[i] = NULL;
-    }
-}
-
-status_t get_date(time_t *e, char **data)
-{
-    struct tm tm;
-
-    if(e == NULL || data == NULL) return ERROR_NULL_POINTER;
-
-    /* Desactiva el horario de verano */
-    tm.tm_isdst = 0;
-
-    switch(data[POS_TXN_DATE][2]) {
-        case '/': 
-            strptime(data[2], "%d/%m/%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-        case '-':
-            strptime(data[2], "%d-%m-%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-        case '.':
-            strptime(data[2], "%d.%m.%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-
-        default: return ERROR_CORRUPT_DATA; break;
-    }
-
-    return OK;
-}
diff --git a/source/main.c b/source/main.c
@@ -1,12 +1,11 @@
-#include "../include/io.h"
 #include "../include/cla.h"
 #include "../include/user.h"
+#include "../include/utils.h"
 #include "../include/status.h"
 #include "../include/vector.h"
 
 #define IN_FILE_MAX_LEN    100
 #define IN_FILE_DELIM    ","
-#define OUT_FILE_DELIM    ","
 #define IN_FILE_FIELDS    6
 #define IN_FILE_FIELDS_MAX_LEN    50
 
@@ -17,17 +16,18 @@ int main (int argc, char *argv[])
     ADT_Vector_t *v;
     ADT_user_t *user, *user_tmp;
     char buffer[IN_FILE_MAX_LEN];
-    char **data;
-    char *endptr;
+    char *endptr, **data;
+    size_t i;
     long amount;
+    time_t epoch;
 
-    /* Asigna memoria a cla */
+    /* Asigna memoria a cla (c.l.a.: "command line arguments") */
     if((st = cla_create(&cla)) != OK) {
         show_status(st);
         return st;
     }
 
-    /* Valida que los argumentos sean correctos */
+    /* Valida que los argumentos sean correctos y asigna valores a cla */
     if((st = validate_arguments(argc, argv, cla)) != OK) {
         show_status(st);
         return st;
@@ -40,58 +40,108 @@ int main (int argc, char *argv[])
         return st;
     }
 
+    /* Crea un arreglo de cadenas de caracteres */
+    if((data = malloc(sizeof(char *) * IN_FILE_FIELDS)) == NULL) {
+        show_status(ERROR_MEMORY);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        return ERROR_MEMORY;
+    }
+
+    for(i = 0; i < IN_FILE_FIELDS; i++) {
+        if((data[i] = calloc(sizeof(char), IN_FILE_FIELDS_MAX_LEN)) == NULL) {
+            show_status(ERROR_MEMORY);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return ERROR_MEMORY;
+        }
+    }
+
     /* Setea el comparador a ADT_Vector */    
     if((st = ADT_Vector_set_comparator(v, user_equals)) != OK) {
         show_status(st);
         cla_destroy(cla);
         ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
+    /* Crea un usuario temporal */
     if((st = user_create(&user_tmp)) != OK) {
         show_status(st);
         cla_destroy(cla);
         ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
+    /* Lee linea por linea del archivo de entrada */
     while(fgets(buffer, IN_FILE_MAX_LEN, cla->fi)) {
+
+        /* Separa la linea leida segun un caracter delimitador */
         string_split(buffer, data, IN_FILE_DELIM);
+
+        /* Setea el usuario temporal con los datos obtenidos de la linea */
         user_set_data(user_tmp, data);
 
         amount = strtol(data[POS_AMOUNT], &endptr, 10);
         if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
+        /* Transforma el tiempo de la linea leida a formato UNIX */
+        get_date(&epoch, data);
+
+        /* Comprueba que el tiempo de la linea leida no supere los argumentos ingresados */
+        if(epoch < cla->ti) continue;
+        else if(epoch > cla->tf) break;
+
+        /* Busca el id del usuario en el vector */
         if((user = ADT_Vector_get_elem(v, user_tmp)) != NULL) {
-            /* El usuario ya existe */
+            /* Si lo encuentra le suma el monto correspondiente */
             user_add_amount(user, amount);
         }
         else { 
-            /* El usuario no existe */
+            /* Si no lo encuentra crea un usuario nuevo */
             user_create(&user);
             user_set_data(user, data);
-            ADT_Vector_add(&v, user);
+
+            /* Y lo agrega al vector */
+            if((st = ADT_Vector_add(&v, user)) != OK){
+                show_status(st);
+                free(user_tmp);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                return st;
+            }
         }
+        clean_buffer(buffer);
+        clean_array(data);
     }
 
+    /* Ordena el vector con los usuarios */
     if((st = ADT_Vector_sort(v, user_comparator_credits_maxmin)) != OK) {
         show_status(st);
         free(user_tmp);
         cla_destroy(cla);
         ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
-    if((st = ADT_Vector_print(v, stdout, user_print_as_csv)) != OK) {
+    /* Imprime el vector con los usuarios */
+    if((st = ADT_Vector_export_as_xml(v, stdout, user_print_as_xml)) != OK) {
         show_status(st);
         free(user_tmp);
         cla_destroy(cla);
         ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
     free(user_tmp);
     cla_destroy(cla);
     ADT_Vector_destroy(&v);
+    array_destroy(data, IN_FILE_FIELDS);
     return OK;
 }
diff --git a/source/sort.c b/source/sort.c
@@ -1,53 +0,0 @@
-#include "../include/sort.h"
-
-int credit_minmax(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->c > (*B)->c) ? 1 : 0;
-}
-
-int credit_maxmin(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->c > (*B)->c) ? 0 : 1;
-}
-
-int debt_minmax(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->d > (*B)->d) ? 1 : 0;
-}
-
-int debt_maxmin(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->d > (*B)->d) ? 0 : 1;
-}
-
-status_t sort_users(user_t *users, size_t l, char *order)
-{
-    if(users == NULL || order == NULL)
-        return ERROR_NULL_POINTER;
-
-    if(!strcmp(order, "ca"))
-        qsort(users, l, sizeof(user_t), credit_minmax);
-
-    if(!strcmp(order, "cd"))
-        qsort(users, l, sizeof(user_t), credit_maxmin);
-
-    if(!strcmp(order, "da"))
-        qsort(users, l, sizeof(user_t), debt_minmax);
-
-    if(!strcmp(order, "dd"))
-        qsort(users, l, sizeof(user_t), debt_maxmin);
-
-    return OK;
-}
diff --git a/source/user.c b/source/user.c
@@ -72,7 +72,9 @@ status_t user_print_as_xml(const void *u, FILE *fp)
 
     ADT_user_t *user = (ADT_user_t *)u;
 
-    fprintf(fp, "id: %6ld| credits: %6ld| debits: %6ld\n", user->id, user->c, user->d);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_ID, user->id, XML_STR_ID);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_CREDIT, user->c, XML_STR_CREDIT);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_DEBIT, user->d, XML_STR_DEBIT);
 
     return OK;
 }
diff --git a/source/utils.c b/source/utils.c
@@ -0,0 +1,77 @@
+#include "../include/utils.h"
+
+status_t string_split(char *s, char **data, char *delim)
+{
+    char *p, *tmp;
+    size_t fields = 0;
+
+    for(p = s; (tmp = strtok(p, delim)); p = NULL)
+        strcpy(data[fields++], tmp);
+
+    if(fields != IN_FILE_FIELDS)
+        return ERROR_CORRUPT_DATA;
+
+    return OK;
+}
+
+
+void clean_buffer(char *buf)
+{
+    size_t i;
+
+    for(i = 0; i < IN_FILE_MAX_LEN; i++)
+        buf[i] = '\0';
+}
+
+void clean_array(char **data)
+{
+    size_t i, j;
+
+    for(i = 0; i < IN_FILE_FIELDS; i++) {
+        for(j = 0; j < IN_FILE_FIELDS_MAX_LEN; j++)
+            data[i][j] = '\0';
+    }
+}
+
+status_t array_destroy(char **data, size_t fields)
+{
+    size_t i;
+
+    if(data == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < fields; i++) {
+        free(data[i]);
+        data[i] = NULL;
+    }
+
+    free(data);
+    return OK;
+}
+
+status_t get_date(time_t *e, char **data)
+{
+    struct tm tm;
+
+    if(e == NULL || data == NULL) return ERROR_NULL_POINTER;
+
+    /* Desactiva el horario de verano */
+    tm.tm_isdst = 0;
+
+    switch(data[POS_TXN_DATE][2]) {
+        case '/': 
+            strptime(data[2], "%d/%m/%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+        case '-':
+            strptime(data[2], "%d-%m-%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+        case '.':
+            strptime(data[2], "%d.%m.%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+
+        default: return ERROR_CORRUPT_DATA; break;
+    }
+    return OK;
+}
diff --git a/source/vector.c b/source/vector.c
@@ -55,30 +55,6 @@ status_t ADT_Vector_destroy(ADT_Vector_t **v)
     return OK;
 }
 
-#define BUFFER_SIZE    100
-status_t ADT_Vector_load(ADT_Vector_t *v, FILE *fi)
-{
-    char *b, *endptr;
-    int  *tmp;
-
-    if(v == NULL || fi == NULL) return ERROR_NULL_POINTER;
-
-    if((b = calloc(sizeof(char), BUFFER_SIZE)) == NULL)
-        return ERROR_MEMORY;
-
-    while(fgets(b, BUFFER_SIZE, fi))
-    {
-        tmp = (int *)malloc(sizeof(int));
-
-        *tmp = (int)strtol(b, &endptr, 10);
-        if(*endptr != '\n') return ERROR_CORRUPT_DATA;
-
-        ADT_Vector_add(&v, tmp);
-    }
-
-    return OK;
-}
-
 status_t ADT_Vector_set(ADT_Vector_t **v, void *e, size_t pos)
 {
     void ** aux;
@@ -173,7 +149,7 @@ status_t ADT_Vector_set_comparator(ADT_Vector_t *v, comparator_t pf)
     return OK;
 }
 
-status_t ADT_Vector_export_as_csv(ADT_Vector_t *v, FILE *fp, printer_t pf)
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *v, FILE *fp, printer_t pf)
 {
     status_t st;
     size_t i;
@@ -187,20 +163,24 @@ status_t ADT_Vector_export_as_csv(ADT_Vector_t *v, FILE *fp, printer_t pf)
     return OK;
 }
 
-status_t ADT_Vector_export_as_xml(ADT_Vector_t *v, FILE *fp, printer_t pf)
+status_t ADT_Vector_export_as_xml(const ADT_Vector_t *v, FILE *fp, printer_t pf)
 {
     status_t st;
     size_t i;
 
     if(v == NULL) return ERROR_NULL_POINTER;
 
-    fprintf(fp, "%s\n", STR_XML_HEADER);
-    fprintf(fp, "<%s>\n", STR_XML_ROOT);
+    fprintf(fp, "%s\n", XML_STR_HEADER);
+    fprintf(fp, "<%s>\n", XML_STR_ROOT);
 
-    for(i = 0; i < v->size; i++)
-        if((st = (*pf)(v->a[i], fp)) != OK) 
+    for(i = 0; i < v->size; i++){
+        fprintf(fp, "\t<%s>\n", XML_STR_ROW);
+        if((st = (*pf)(v->a[i], fp)) != OK)
             return st;
 
-    fprintf(fp, "</%s>\n", STR_XML_ROOT);
+        fprintf(fp, "\t</%s>\n", XML_STR_ROW);
+    }
+
+    fprintf(fp, "</%s>\n", XML_STR_ROOT);
     return OK;
 }