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 e89839f281cac8a05411172f4294b3e714e6377d
parent b0bd63f5cbe875194b8929d20802394ca794da5a
Author: Martin J. Klöckner <64109770+klewer-martin@users.noreply.github.com>
Date:   Thu, 29 Jul 2021 22:28:39 -0300

Merge pull request #3 from klewer-martin/segunda_entrega

Segunda entrega
Diffstat:
MMakefile | 25+++++++++++++++++--------
Mexamples/input_gen.py | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Minclude/cla.h | 19+++++++++----------
Dinclude/io.h | 67-------------------------------------------------------------------
Dinclude/sort.h | 18------------------
Minclude/status.h | 11++++++-----
Minclude/user.h | 28++++++++++++++++++----------
Ainclude/utils.h | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/vector.h | 40++++++++++++++++++++++++++++++++++++++++
Msource/cla.c | 74++++++++++++++++++++++++++++++++++++++++++--------------------------------
Dsource/io.c | 247-------------------------------------------------------------------------------
Msource/main.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Dsource/sort.c | 53-----------------------------------------------------
Msource/status.c | 23-----------------------
Msource/user.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Asource/utils.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/vector.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17 files changed, 812 insertions(+), 549 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,13 +1,13 @@
 CC=gcc
-CFLAGS=-pedantic -Wall
+CFLAGS=-pedantic -Wall -g
 SRCFOLDER=source
 HFOLDER=include
 PROGNAME=main
 
 all: main clean
 
-main: cla.o status.o sort.o io.o main.o user.o 
-    $(CC) $(CFLAGS) main.o cla.o status.o io.o sort.o user.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
@@ -15,14 +15,14 @@ main.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h $(HFOLDER)/user.h
 cla.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/cla.c
 
+vector.o: $(HFOLDER)/vector.h $(HFOLDER)/status.h
+    $(CC) $(CFLAGS) -c $(SRCFOLDER)/vector.c
+
 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
-
-sort.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
-    $(CC) $(CFLAGS) -c $(SRCFOLDER)/sort.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
@@ -30,6 +30,9 @@ user.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
 clean:
     rm *.o
 
+run5:
+    ./main -fmt csv -out output.csv -in examples/test_file_5.csv -ti 1320498000 -tf 1320498046
+
 run20:
     ./main -fmt csv -out output.csv -in examples/test_file_20.csv -ti 1320498000 -tf 1320498046
 
@@ -48,9 +51,15 @@ run5k:
 run50k:
     ./main -fmt csv -out output.csv -in examples/test_file_50k.csv -ti 1320498000 -tf 1420529000
 
+run100k:
+    ./main -fmt csv -out output.csv -in examples/test_file_100k.csv -ti 1320498000 -tf 1420529000
+
 run500k:
     ./main -fmt csv -out output.csv -in examples/test_file_500k.csv -ti 1320498000 -tf 1420529000
 
+run50m:
+    ./main -fmt csv -out output.csv -in examples/test_file_50m.csv -ti 1320498000 -tf 1420529000
+
 run50xml:
     ./main -fmt xml -out output.xml -in examples/test_file_50.csv -ti 1320498000 -tf 1320498049
 
diff --git a/examples/input_gen.py b/examples/input_gen.py
@@ -2,7 +2,7 @@ from string import digits
 from time import strftime, gmtime
 from random import randint, choice
 
-LINES = 500000
+LINES = 10000
 
 # OUTPUT:
 #     ID_TRANSACCION, ID_USUARIO, FECHA, MONTO, NUMERO DE TRAJETA, DESCRIPCION
@@ -10,19 +10,99 @@ LINES = 500000
 
 descs = [ "Compras supermercado", "Pago tarjeta", "Compras libreria", "Pago Mecanico", "Pago Dentista", "Pago Servicios online", "Compras Ferreteria",  "Compras Accesorios Informatica", "Compras farmacia", "Ventas online", "Extraccion cajero" ]
 
-def card_number_generator():
-    return ''.join(choice(digits) for i in range(1, 16))
+def calculate_luhn(cc):
+    num = list(map(int, str(cc)))
+    check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
+    return 0 if check_digit == 10 else check_digit
+
+def generate_card(type):
+    """
+    Prefill some values based on the card type
+    """
+    card_types = ["americanexpress","visa13", "visa16","mastercard","discover"]
+
+    def prefill(t):
+        # typical number of digits in credit card
+        def_length = 16
+
+        """
+        Prefill with initial numbers and return it including the total number of digits
+        remaining to fill
+        """
+        if t == card_types[0]:
+            # american express starts with 3 and is 15 digits long
+            # override the def lengths
+            return [3, randint(4,7)], 13
+
+        elif t == card_types[1] or t == card_types[2]:
+            # visa starts with 4
+            if t.endswith("16"):
+                return [4], def_length - 1
+            else:
+                return [4], 12
+
+        elif t == card_types[3]:
+            # master card start with 5 and is 16 digits long
+            return [5, randint(1,5)], def_length - 2
+
+        elif t == card_types[4]:
+            # discover card starts with 6011 and is 16 digits long
+            return [6, 0, 1, 1], def_length - 4
+
+        else:
+            # this section probably not even needed here
+            return [], def_length
+
+    def finalize(nums):
+        """
+        Make the current generated list pass the Luhn check by checking and adding
+        the last digit appropriately bia calculating the check sum
+        """
+        check_sum = 0
+
+        #is_even = True if (len(nums) + 1 % 2) == 0 else False
+
+        """
+        Reason for this check offset is to figure out whether the final list is going
+        to be even or odd which will affect calculating the check_sum.
+        This is mainly also to avoid reversing the list back and forth which is specified
+        on the Luhn algorithm.
+        """
+        check_offset = (len(nums) + 1) % 2
+
+        for i, n in enumerate(nums):
+            if (i + check_offset) % 2 == 0:
+                n_ = n*2
+                check_sum += n_ -9 if n_ > 9 else n_
+            else:
+                check_sum += n
+        return nums + [10 - (check_sum % 10) ]
+
+    # main body
+    t = type.lower()
+    if t not in card_types:
+        print("Unknown type: '%s'" % type)
+        print("Please pick one of these supported types: %s" % card_types)
+        return
+
+    initial, rem = prefill(t)
+    so_far = initial + [randint(1,9) for x in range(rem - 1)]
+    return ("".join(map(str,finalize(so_far))))
 
 def generate_file(max_lines):
     id_transaction_base = 123400
     id_user_base = 1
-    id_user_max = 20000
+    id_user_max = 30000
     amount_base = 1
     amount_max = 10000
     for i in range(max_lines):
         id_transaction = (i + id_transaction_base)
         id_user = randint(id_user_base, id_user_max)
-        card_nr = card_number_generator() 
+
+        card_nr = generate_card("visa16")
+        while calculate_luhn(card_nr) != 0:
+            card_nr = generate_card("visa16")
+
         date = strftime("%d.%m.%Y %H:%M:%S", gmtime(1320487200 + i))
         
         j = randint(1, len(descs) - 1)
diff --git a/include/cla.h b/include/cla.h
@@ -21,19 +21,18 @@ typedef enum {
 } flags_t;
 
 typedef struct {
-    char *fmt, *fi, *fo;
-    unsigned long ti, tf, parsed_lines;
+    char *fmt;
+    FILE *fi, *fo;
+    unsigned long ti, tf;
 } ADT_cla_t, *cla_t;
 
-status_t validate_arguments(int argc, char **argv);
-status_t check_flags_position(int argc, char **argv);
-status_t check_flags_repeated(int argc, char **argv);
+status_t validate_arguments(int, char **, cla_t);
+status_t check_flags_position(int, char **);
+status_t check_flags_repeated(int, char **);
 
-status_t cla_create(cla_t *cla);
-status_t cla_setup(int argc, char **argv, cla_t *cla);
-status_t cla_destroy(cla_t *cla);
-
-void clean(cla_t cla);
+status_t cla_create(cla_t *);
+status_t cla_setup(int, char **, cla_t);
+status_t cla_destroy(cla_t);
 
 extern const char *available_flags[FLAGS_MAX];
 extern const char *available_formats[FORMATS_MAX];
diff --git a/include/io.h b/include/io.h
@@ -1,67 +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 process_file(cla_t cla, user_t **users, size_t *i);
-
-status_t string_split(char *s, char **data, char *delim);
-
-status_t load_values(FILE *, cla_t *data);
-
-status_t export_data(cla_t cla, const user_t *users, size_t size);
-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 **data);
-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/status.h b/include/status.h
@@ -5,10 +5,11 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
-#define ERROR_RETRY_MSG "Verifique y vuelva a intentar"
-#define EXIT_SUCCESS_MSG "Ejecución terminada exitosamente"
-#define USERS_REGISTERED_MSG    "Usuarios registrados: "
-#define PROCESED_LINES_MSG        "Lineas procesadas: "
+#define MSG_ERROR_RETRY                "Verifique y vuelva a intentar"
+#define MSG_EXIT_SUCCESS            "Ejecución terminada exitosamente"
+#define MSG_USERS_REGISTERED        "Usuarios registrados"
+#define MSG_PROCESED_LINES            "Lineas procesadas"
+#define STR_INVALID_CARD_NUMBER        "Número no válido"
 
 #define STATUS_T_MAX 12
 
@@ -17,6 +18,7 @@ typedef enum {
     ERROR_MEMORY,
     ERROR_WRONG_FLAGS,
     ERROR_WRONG_TIME,
+    ERROR_INVALID_POS,
     ERROR_MISSING_ARGS,
     ERROR_OPENING_FILE,
     ERROR_CORRUPT_DATA,
@@ -37,7 +39,6 @@ typedef enum {
 } csv_pos_t;
 
 void show_status(status_t st);
-void free_arrays(size_t num,...);
 
 extern const char *status_strings[STATUS_T_MAX];
 
diff --git a/include/user.h b/include/user.h
@@ -2,21 +2,29 @@
 #define USER__H
 
 #include "status.h"
+#include "utils.h"
+
+#define OUT_FILE_DELIM    ","
+
+typedef unsigned long ulong;
 
 typedef struct {
-    size_t id;
-    long credit, debt;
-} ADT_user_t, *user_t;
+    /* id: user id / c: user credits / d: user debits */
+    ulong id, c, d;
+} ADT_user_t;
+
+status_t user_create(ADT_user_t **);
+status_t user_destroy(ADT_user_t **);
+status_t user_set_data(ADT_user_t *, char **);
+status_t user_add_amount(ADT_user_t *, long);
 
-user_t user_find(const user_t *users, int id, size_t size);
-user_t user_dup(user_t src);
+int user_equals(const void *, const void *);
 
-status_t user_create(user_t *usr);
-status_t user_set_data(user_t *user, char **data);
+status_t user_print_as_csv(const void *, FILE *);
+status_t user_print_as_xml(const void *, FILE *);
 
-void user_clean(user_t usr);
+int user_comparator_credits_minmax(const void *, const void *);
+int user_comparator_credits_maxmin(const void *, const void *);
 
-status_t sort_users(user_t *users, size_t size, char *order);
-status_t destroy_users(user_t *users, size_t size);
 
 #endif
diff --git a/include/utils.h b/include/utils.h
@@ -0,0 +1,43 @@
+#ifndef UTILS__H
+#define UTILS__H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.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 STR_FMT_CSV "csv"
+#define STR_FMT_XML "xml"
+
+#define CARD_NO_VALID_LEN 16
+
+#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 *);
+
+bool is_valid_card(char *);
+
+void clean_array(char **);
+void clean_buffer(char *);
+
+#endif
diff --git a/include/vector.h b/include/vector.h
@@ -0,0 +1,40 @@
+#ifndef VECTOR__H
+#define VECTOR__H
+
+#define VECTOR_INIT_SIZE        10
+#define VECTOR_GROWTH_FACTOR    2
+
+#include <stdlib.h>
+
+#include "utils.h"
+#include "status.h"
+
+typedef status_t (*printer_t)(const void *, FILE *);
+typedef int (*comparator_t)(const void *, const void *);
+
+typedef struct {
+    void **a;
+    size_t size, alloc;
+
+    printer_t printer;
+    comparator_t comparator;
+
+} ADT_Vector_t;
+
+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_set(ADT_Vector_t **, void *, size_t);
+status_t ADT_Vector_print(const ADT_Vector_t *, FILE *);
+status_t ADT_Vector_sort(ADT_Vector_t *, comparator_t);
+
+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(const ADT_Vector_t *, FILE *);
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *, FILE *);
+
+#endif
diff --git a/source/cla.c b/source/cla.c
@@ -3,17 +3,20 @@
 const char *available_flags[] = { "-fmt", "-out", "-in", "-ti", "-tf" };
 const char *available_formats[] = { "csv", "xml" };
 
-status_t validate_arguments(int argc,  char **argv)
+status_t validate_arguments(int argc, char **argv, cla_t cla)
 {
     status_t st;
 
-    if(argv == NULL) return ERROR_NULL_POINTER;
+    if(argv == NULL || cla == NULL) return ERROR_NULL_POINTER;
     if((argc == NO_ARGS_ENTERED) || (argc != NORMAL_AMOUNT_ARGS))
         return ERROR_MISSING_ARGS;
 
     if((st = check_flags_position(argc, argv))) return st;
     if((st = check_flags_repeated(argc, argv))) return st;
 
+    /* Asigna a la estructura 'cla' los argumentos ingresados */
+    if((st = cla_setup(argc, argv, cla))) return st;
+
     return OK;
 }
 
@@ -60,25 +63,45 @@ status_t check_flags_repeated(int argc, char **argv)
     return OK;
 }
 
-status_t cla_setup(int argc, char **argv, cla_t *cla)
+status_t cla_setup(int argc, char **argv, cla_t cla)
 {
     char *endptr;
     size_t i;
+    FILE *fp;
     flags_t f;
 
     for(i = 1; i < argc; i += 2) {
         for(f = FLAG_FMT; f < FLAGS_MAX; f++) {
             if(!strcmp(available_flags[f], argv[i])) {
                 switch (f) {
-                    case FLAG_FMT: strcpy((*cla)->fmt, argv[i + 1]); break;
-                    case FLAG_OUT: strcpy((*cla)->fo, argv[i + 1]); break;
-                    case FLAG_IN: strcpy((*cla)->fi, argv[i + 1]); break;
-                    case FLAG_TI: (*cla)->ti = strtoul(argv[i + 1], &endptr, 10); 
-                                  if(*endptr != '\0') return ERROR_WRONG_TIME;
-                                  break;
-                    case FLAG_TF: (*cla)->tf = strtoul(argv[i + 1], &endptr, 10); 
-                                  if(*endptr != '\0') return ERROR_WRONG_TIME;
-                                  break;
+                    case FLAG_FMT: 
+                        strcpy(cla->fmt, argv[i + 1]);
+                       break;
+
+                    case FLAG_OUT:
+                       if((fp = fopen(argv[i + 1], "wt")) == NULL)
+                           return ERROR_OPENING_FILE;
+
+                       cla->fo = fp; 
+                       break;
+
+                    case FLAG_IN:
+                       if((fp = fopen(argv[i + 1], "rt")) == NULL)
+                           return ERROR_OPENING_FILE;
+
+                       cla->fi = fp; 
+                       break;
+
+                    case FLAG_TI:
+                       cla->ti = strtoul(argv[i + 1], &endptr, 10); 
+                       if(*endptr != '\0') return ERROR_WRONG_TIME;
+                       break;
+
+                    case FLAG_TF:
+                       cla->tf = strtoul(argv[i + 1], &endptr, 10); 
+                       if(*endptr != '\0') return ERROR_WRONG_TIME;
+                       break;
+
                     default: return ERROR_FLAG_NOT_FOUND;
                 }
             }
@@ -101,34 +124,21 @@ status_t cla_create(cla_t *cla)
         return ERROR_MEMORY;
     }
 
-    if(((*cla)->fo = calloc(sizeof(char), 100)) == NULL) {
-        free((*cla)->fmt);
-        free(cla);
-        cla = NULL;
-        return ERROR_MEMORY;
-    }
-
-    if(((*cla)->fi = calloc(sizeof(char), 100)) == NULL) {
-        free((*cla)->fo);
-        free((*cla)->fmt);
-        free(cla);
-        cla = NULL;
-        return ERROR_MEMORY;
-    }
+    (*cla)->fi = NULL;
+    (*cla)->fo = NULL;
 
     return OK;
 }
 
-status_t cla_destroy(cla_t *cla)
+status_t cla_destroy(cla_t cla)
 {
     if(cla == NULL) return ERROR_NULL_POINTER;
 
-    free((*cla)->fmt);
-    free((*cla)->fo);
-    free((*cla)->fi);
-    free(*cla);
+    if(cla->fi != NULL) fclose(cla->fi);
+    if(cla->fo != NULL)    fclose(cla->fo);
 
-    *cla = NULL;
+    free(cla->fmt);
+    free(cla);
 
     return OK;
 }
diff --git a/source/io.c b/source/io.c
@@ -1,247 +0,0 @@
-#include "../include/io.h"
-
-/* Lee los datos del archivo de entrada linea por linea mientras los procesa y asigna a un arreglo de usuarios */
-status_t process_file(cla_t cla, user_t **users, size_t *size)
-{
-    FILE *fpi;
-    char *buffer, **data;
-    time_t epoch;
-    size_t alloc_size;
-    user_t user, user_found, *tmp;
-    status_t st;
-
-    *size = cla->parsed_lines = 0;
-    alloc_size = INIT_SIZE;
-    user = user_found = NULL;
-
-    if((fpi = fopen(cla->fi, "rt")) == NULL) {
-        *users = NULL;
-        return ERROR_OPENING_FILE;
-    }
-
-    if((data = (char **)malloc(sizeof(char *) * INPUT_FILE_FIELDS)) == NULL) {
-        fclose(fpi);
-        return ERROR_MEMORY;
-    }
-
-    if((buffer = calloc(sizeof(char), BUFFER_SIZE)) == NULL) {
-        destroy_data(data);
-        fclose(fpi);
-        return ERROR_MEMORY;
-    }
-
-    if(user_create(&user) != OK) {
-        free(buffer);
-        destroy_data(data);
-        fclose(fpi);
-    }
-
-    /* En caso de haber algun error users no es liberado, se libera luego en main */
-    if(((*users) = (user_t *)malloc(sizeof(user_t) * INIT_SIZE)) == NULL) {
-        free(buffer);
-        free(user);
-        destroy_data(data);
-        fclose(fpi);
-    }
-
-    /* Lee los datos de el archivo de entrada linea por linea */ 
-    while(fgets(buffer, BUFFER_SIZE, fpi) != NULL) {
-        /* Extiende el arreglo de usuarios en caso de que haya poca memoria */
-        if(*size == alloc_size) {
-            alloc_size *= GROWTH_FACTOR;
-            if((tmp = realloc((*users), alloc_size * sizeof(user_t))) == NULL) {
-                fclose(fpi);
-                free(buffer);
-                destroy_data(data);
-                return ERROR_MEMORY;
-            }
-            (*users) = tmp;
-        }
-
-        /* Divide el buffer en subarreglos segun un caracter delimitador */
-        if((st = string_split(buffer, data, INPUT_FILE_DELIM)) != OK) {
-            fclose(fpi);
-            free(buffer);
-            destroy_data(data);
-            return st;
-        }
-
-        /* Asigna a 'user' id, creditos y debitos cargados en data */
-        if((st = user_set_data(&user, data)) != OK) {
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return st;
-        }
-
-        /* Transforma la fecha leida a tiempo UNIX en segundos */
-        if((st = get_date(&epoch, data)) != OK) {
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return st;
-        }
-
-        /* Comprueba que la fecha leida este dentro del rango de fechas ingresadas en CLA */
-        if(epoch < cla->ti) continue;
-        else if(epoch > cla->tf) {
-            free(user);
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return OK;
-        }
-
-        /* Busca el numero de id en los usuarios ya ingresados, si no lo encuentra agrega un usuario nuevo al arreglo de usuarios */
-        if((user_found = user_find(*users, user->id, *size)) != NULL) {
-            user_found->credit += user->credit;
-            user_found->debt += user->debt;
-        } else {
-            (*users)[(*size)++] = user_dup(user);
-        }
-
-        cla->parsed_lines++;
-
-        user_clean(user);
-        clean_data(data);
-        clean_buffer(buffer);
-    } /* End while */
-
-    free(user);
-    destroy_data(data);
-    free(buffer);
-    fclose(fpi);
-    return OK;
-}
-
-
-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)
-        data[fields++] = strdup(tmp);
-
-    if(fields != INPUT_FILE_FIELDS)
-        return ERROR_CORRUPT_DATA;
-
-    return OK;
-}
-
-status_t destroy_data(char **data)
-{
-    size_t i;
-
-    if(data == NULL) return ERROR_NULL_POINTER;
-
-    for(i = 0; i < INPUT_FILE_FIELDS; i++) {
-        free(data[i]);
-        data[i] = NULL;
-    }
-
-    free(data);
-    return OK;
-}
-
-status_t export_data(cla_t cla, const user_t *users, size_t size)
-{
-    FILE *fo;
-
-    if(users == NULL) return ERROR_NULL_POINTER;
-
-    if((fo = fopen(cla->fo, "wt")) == NULL)
-        return ERROR_OPENING_FILE;
-
-    if(!strcmp(cla->fmt, "csv")) {
-        export_data_as_csv(fo, users, size);
-    } else if(!strcmp(cla->fmt, "xml")) {
-        export_data_as_xml(fo, users, size);
-    } else return ERROR_FORMAT_NOT_FOUND;
-
-    fclose(fo);
-    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]->credit, CSV_OUTPUT_DELIM, users[i]->debt);
-
-    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]->credit, XML_CREDIT_CLOSE);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_DEBT_OPEN, users[i]->debt, 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,75 +1,221 @@
-#include "../include/io.h"
 #include "../include/cla.h"
 #include "../include/user.h"
-#include "../include/sort.h"
+#include "../include/utils.h"
 #include "../include/status.h"
-
-/* "ca" - creditos ascendentes | "cd" - creditos descendentes
- * "da" - debitos ascendentes  | "dd" - debitos descendentes */
-#define SORTING_ORDER    "cd"
-#define PRINT_EXIT_SUCCESS_MSG
+#include "../include/vector.h"
 
 int main (int argc, char *argv[])
 {
     status_t st;
     cla_t cla;
-    user_t *users;
-    size_t size;
+    ADT_Vector_t *v;
+    ADT_user_t *user, *user_tmp;
+    char buffer[IN_FILE_MAX_LEN];
+    char *endptr, **data;
+    size_t i;
+    long amount;
+    time_t epoch;
 
-    /* Valida que los argumentos sean correctos */
-    if((st = validate_arguments(argc, argv)) != OK) {
+    /* Asigna memoria a cla (c.l.a.: "command line arguments") */
+    if((st = cla_create(&cla)) != OK) {
         show_status(st);
         return st;
     }
 
-    /* Asigna memoria a cla */
-    if((st = cla_create(&cla)) != OK) {
+    /* Valida que los argumentos sean correctos y asigna valores a cla */
+    if((st = validate_arguments(argc, argv, cla)) != OK) {
         show_status(st);
+        cla_destroy(cla);
         return st;
     }
 
-    /* Asigna a la estructura 'cla' los argumentos ingresados */
-    if((st = cla_setup(argc, argv, &cla)) != OK) {
+    /* Crea un vector */
+    if((st = ADT_Vector_create(&v)) != OK) {
         show_status(st);
+        cla_destroy(cla);
         return st;
     }
 
-    /* Carga en users los usuarios desde el archivo de entrada */
-    if((st = process_file(cla, &users, &size)) != OK) {
-        show_status(st);
-        cla_destroy(&cla);
-        destroy_users(users, size);
-        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;
     }
 
-    /* Ordena los usuarios con orden SORTING_ORDER */
-    if((st = sort_users(users, size, SORTING_ORDER)) != OK) {
+    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);
-        destroy_users(users, size);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
-    /* Imprime los datos cargados en users a un archivo de salida */
-    if((st = export_data(cla, users, size)) != OK) {
+    /* Crea un usuario temporal */
+    if((st = user_create(&user_tmp)) != OK) {
         show_status(st);
-        cla_destroy(&cla);
-        destroy_users(users, size);
+        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 */
+        if((st = string_split(buffer, data, IN_FILE_DELIM)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return st;
+        }
+
+        /* Setea el usuario temporal con los datos obtenidos de la linea */
+        if((st = user_set_data(user_tmp, data)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return st;
+        }
+
+        amount = strtol(data[POS_AMOUNT], &endptr, 10);
+        if(*endptr != '\0') {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return ERROR_CORRUPT_DATA;
+        }
 
-#ifdef PRINT_EXIT_SUCCESS_MSG
+        /* Transforma el tiempo de la linea leida a formato UNIX */
+        get_date(&epoch, data);
 
-    /* Imprime un mensaje para darle a conocer al usuario
-     * que todo se ejecuto correctamente    */
-    printf("\n%s\n%s%ld\n%s%ld\n", EXIT_SUCCESS_MSG, USERS_REGISTERED_MSG,\
-            size, PROCESED_LINES_MSG, cla->parsed_lines);
+        /* Comprueba que el tiempo de la linea leida no supere los argumentos ingresados */
+        if(epoch < cla->ti) continue;
+        else if(epoch > cla->tf) break;
 
-#endif
+        /* Solo imprime en el archivo de salida las transacciones realizadas con una tarjeta valida */
+        if(!is_valid_card(data[POS_CARD_NUMBER])) {
+            fprintf(stderr, "%s: %s\n",STR_INVALID_CARD_NUMBER, data[POS_CARD_NUMBER]);
+            continue;
+        }
 
-    cla_destroy(&cla);
-    destroy_users(users, size);
+        /* Busca el id del usuario en el vector */
+        if((user = ADT_Vector_get_elem(v, user_tmp)) != NULL) {
+            /* Si lo encuentra le suma el monto correspondiente */
+            if((st = user_add_amount(user, amount)) != OK) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+        }
+
+        /* Si no lo encuentra crea un usuario nuevo */
+        else { 
+            if((st = user_create(&user)) != OK) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+
+            if((st = user_set_data(user, data))) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+
+            /* 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);
+                free(user_tmp);
+                return st;
+            }
+        }
+        clean_buffer(buffer);
+        clean_array(data);
+    } /* End while */
+
+    /* 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;
+    }
+
+    /* Setea el impresor a ADT_Vector */
+    if(!strcmp(cla->fmt, STR_FMT_CSV)) {
+        if((st = ADT_Vector_set_printer(v, user_print_as_csv)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+        /* E imprime el vector con los usuarios */
+        if((st = ADT_Vector_export_as_csv(v, cla->fo)) != OK) {
+            show_status(st);
+            free(user_tmp);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+    }
+    else if(!strcmp(cla->fmt, STR_FMT_XML)) {
+        if((st = ADT_Vector_set_printer(v, user_print_as_xml)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+        if((st = ADT_Vector_export_as_xml(v, cla->fo)) != 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)->credit > (*B)->credit) ? 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)->credit > (*B)->credit) ? 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)->debt > (*B)->debt) ? 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)->debt > (*B)->debt) ? 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/status.c b/source/status.c
@@ -18,27 +18,4 @@ const char *status_strings[] = {
 void show_status(status_t st)
 {
     fprintf(stderr, "\n%s\n", status_strings[st]);
-    fprintf(stderr, "%s\n", ERROR_RETRY_MSG);
-}
-
-void free_arrays(size_t num,...)
-{
-    va_list valist;
-    size_t i;
-
-    va_start(valist, num);
-
-    for(i = 0; i < num; i++)
-        free(va_arg(valist, char *));
-}
-
-void close_streams(size_t num,...)
-{
-    va_list valist;
-    size_t i;
-
-    va_start(valist, num);
-
-    for(i = 0; i < num; i++)
-        free(va_arg(valist, FILE *));
 }
diff --git a/source/user.c b/source/user.c
@@ -1,76 +1,118 @@
 #include "../include/user.h"
 
-status_t user_create(user_t *usr)
+status_t user_create(ADT_user_t **user)
 {
-    if(((*usr) = (user_t)malloc(sizeof(ADT_user_t))) == NULL)
+    if((*user = (ADT_user_t *)malloc(sizeof(ADT_user_t))) == NULL)
         return ERROR_MEMORY;
 
-    (*usr)->id = 0;
-    (*usr)->credit = 0;
-    (*usr)->debt = 0;
+    (*user)->id = 0;
+    (*user)->c = 0;
+    (*user)->d = 0;
 
     return OK;
 }
 
-void user_clean(user_t usr)
+status_t user_destroy(ADT_user_t **user)
 {
-    usr->id = 0;
-    usr->credit = 0;
-    usr->debt = 0;
+    if(user == NULL) return ERROR_NULL_POINTER;
+
+    free(*user);
+    *user = NULL;
+
+    return OK;
 }
 
-status_t user_set_data(user_t *user, char **data) 
+status_t user_set_data(ADT_user_t *user, char **data) 
 {
     char *endptr;
     long amount;
 
     if(data == NULL || user == NULL) return ERROR_NULL_POINTER;
 
-    (*user)->id = strtol(data[POS_USER_ID], &endptr, 10);
+    user->id = strtol(data[POS_USER_ID], &endptr, 10);
     if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
     amount = strtol(data[POS_AMOUNT], &endptr, 10);
     if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
-    if(amount > 0) (*user)->credit = amount;
-    else if(amount < 0) (*user)->debt = -amount; /* '-=' Para eliminar el menos    */
+    if(amount > 0) user->c = amount;
+    else if(amount < 0) user->d = -amount; /* '-=' Para eliminar el menos    */
+
+    return OK;
+}
+
+status_t user_add_amount(ADT_user_t *user, long amount)
+{
+    if(user == NULL) return ERROR_NULL_POINTER;
+
+    if(amount > 0) user->c += amount;
+    else if(amount < 0) user->d -= amount; /* '-=' Para eliminar el menos    */
 
     return OK;
 }
 
-user_t user_dup(user_t src)
+int user_equals(const void *a, const void *b)
 {
-    user_t dst = NULL;
+    ADT_user_t *A, *B;
 
-    user_create(&dst);
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
 
-    dst->id = src->id;
-    dst->credit = src->credit;
-    dst->debt = src->debt;
+    A = (ADT_user_t *)a;
+    B = (ADT_user_t *)b;
 
-    return dst;
+    if(A->id == B->id) return 1;
+
+    return 0;
 }
 
-user_t user_find(const user_t *users, int id, size_t size)
+status_t user_print_as_csv(const void *u, FILE *fp)
 {
-    size_t i;
-    for(i = 0; i < size; i++) {
-        if(users[i]->id == id) {
-            return users[i];
-        }
-    }
-    return NULL;
+    if(u == NULL || fp == NULL) return ERROR_NULL_POINTER;
+
+    ADT_user_t *user = (ADT_user_t *)u;
+
+    fprintf(fp, "%ld%s%ld%s%ld\n", user->id, OUT_FILE_DELIM, user->c, OUT_FILE_DELIM, user->d);
+
+    return OK;
 }
 
-status_t destroy_users(user_t *users, size_t size)
+status_t user_print_as_xml(const void *u, FILE *fp)
 {
-    size_t i;
+    if(u == NULL || fp == NULL) return ERROR_NULL_POINTER;
 
-    if(users == NULL) return ERROR_NULL_POINTER;
+    ADT_user_t *user = (ADT_user_t *)u;
 
-    for(i = 0; i < size; i++)
-        free(users[i]);
+    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);
 
-    free(users);
     return OK;
 }
+
+int user_comparator_credits_minmax(const void *a, const void *b)
+{
+    ADT_user_t *A, *B;
+
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
+
+    A = *(ADT_user_t **)a;
+    B = *(ADT_user_t **)b;
+
+    if(A->c > B->c) return 1;
+    else if(A->c == B->c) return 0;
+    return -1;
+}  
+
+int user_comparator_credits_maxmin(const void *a, const void *b)
+{
+    ADT_user_t *A, *B;
+
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
+
+    A = *(ADT_user_t **)a;
+    B = *(ADT_user_t **)b;
+
+    if(A->c < B->c) return 1;
+    else if(A->c == B->c) return 0;
+    return -1;
+}  
diff --git a/source/utils.c b/source/utils.c
@@ -0,0 +1,106 @@
+#include "../include/utils.h"
+
+status_t string_split(char *s, char **data, char *delim)
+{
+    char *p, *tmp;
+    size_t fields = 0;
+
+    if(s == NULL || data == NULL || delim == NULL)
+        return ERROR_NULL_POINTER;
+
+    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;
+}
+
+bool is_valid_card(char *card_no)
+{
+    size_t i, j, k;
+    int arr[4][4], sum;
+    char tmp[2];
+
+    if(card_no == NULL) return false;
+    if(strlen(card_no) != CARD_NO_VALID_LEN) return false;
+
+    for(i = 0, k = 0; i < 4; i++) {
+        for(j = 0; j < 4; j++) {
+            arr[i][j] = (card_no[k++] - '0');
+            if(j % 2) {
+                arr[i][j] *= 2;
+                sprintf(tmp, "%d", arr[i][j]);
+                if(!(strlen(tmp) - 1)) arr[i][j] = (tmp[0] - '0');
+                else arr[i][j] = ((tmp[0] - '0') + (tmp[1] - '0'));
+
+            }
+            sum += arr[i][j];
+        }
+    }
+
+    return (sum % 10) ? false : true;
+}
diff --git a/source/vector.c b/source/vector.c
@@ -0,0 +1,187 @@
+#include "../include/vector.h"
+
+status_t ADT_Vector_create(ADT_Vector_t **v)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    if((*v = (ADT_Vector_t *)malloc(sizeof(ADT_Vector_t))) == NULL)
+        return ERROR_MEMORY;
+
+    if(((*v)->a = (void **)malloc(sizeof(void *) * VECTOR_INIT_SIZE)) == NULL)
+        return ERROR_MEMORY;
+
+    (*v)->size = 0;
+    (*v)->alloc = VECTOR_INIT_SIZE;
+    (*v)->printer = NULL;
+    (*v)->comparator = NULL;
+
+    return OK;
+}
+
+status_t ADT_Vector_add(ADT_Vector_t **v, void *e)
+{
+    void *tmp;
+
+    if(v == NULL || e == NULL) return ERROR_NULL_POINTER;
+
+    /* Extends the array in case low memory left */
+    if(((*v)->size + 1) == (*v)->alloc) {
+        if((tmp = (void **)realloc((*v)->a, sizeof(void *) * (*v)->alloc * VECTOR_GROWTH_FACTOR)) == NULL)
+            return ERROR_MEMORY;
+        else {
+            (*v)->a = tmp;
+            (*v)->alloc *= VECTOR_GROWTH_FACTOR;
+        }
+    }
+
+    (*v)->a[(*v)->size++] = e;
+
+    return OK;
+}
+
+status_t ADT_Vector_destroy(ADT_Vector_t **v)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(size_t i = 0; i < (*v)->size; i++) {
+        free((*v)->a[i]);
+        (*v)->a[i] = NULL;
+    }
+
+    free((*v)->a);
+    free(*v);
+    *v = NULL;
+
+    return OK;
+}
+
+status_t ADT_Vector_set(ADT_Vector_t **v, void *e, size_t pos)
+{
+    void ** aux;
+    size_t i, alloc_size;
+
+    if(v == NULL || e == NULL) return ERROR_NULL_POINTER;
+    else if(pos > (*v)->size) return ERROR_INVALID_POS;
+
+    alloc_size = (*v)->alloc;
+
+    /* Cuenta cuanto tiene que alargar el arreglo p/ que entre el nuevo elemento */
+    while(pos >= alloc_size) {
+        alloc_size *= VECTOR_GROWTH_FACTOR;
+    }
+
+    /* Extiende el arreglo en caso de que no haya memoria suficiente */
+    if(pos > (*v)->alloc) {
+        if((aux = (void **)realloc((*v)->a, sizeof(void *) * alloc_size)) == NULL)
+            return ERROR_MEMORY;
+        else {
+            (*v)->a = aux;
+            (*v)->alloc = alloc_size;
+        }
+    }
+
+    for(i = (*v)->size; i < pos; i++) {
+        (*v)->a[pos] = NULL;
+    }
+
+    (*v)->a[pos] = e;
+
+    if(pos >= (*v)->size) {
+        (*v)->size = (pos + 1);
+    }
+
+    return OK;
+}
+
+void *ADT_Vector_get_elem(const ADT_Vector_t *v, void *e)
+{
+    size_t i;
+
+    if(v == NULL || e == NULL) return NULL;
+
+    for(i = 0; i < v->size; i++) { 
+        if(v->comparator(e, v->a[i])) {
+            return v->a[i];
+        }
+    }
+
+    return NULL;
+}
+
+status_t ADT_Vector_print(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < v->size; i++)
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+    return OK;
+}
+
+status_t ADT_Vector_sort(ADT_Vector_t *v, comparator_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    /* Quick sort */
+    qsort(v->a, v->size, sizeof(void *), pf);
+
+    return OK;
+}
+
+status_t ADT_Vector_set_printer(ADT_Vector_t *v, printer_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    v->printer = pf;
+
+    return OK;
+}
+
+status_t ADT_Vector_set_comparator(ADT_Vector_t *v, comparator_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    v->comparator = pf;
+
+    return OK;
+}
+
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < v->size; i++)
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+    return OK;
+}
+
+status_t ADT_Vector_export_as_xml(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    fprintf(fp, "%s\n", XML_STR_HEADER);
+    fprintf(fp, "<%s>\n", XML_STR_ROOT);
+
+    for(i = 0; i < v->size; i++){
+        fprintf(fp, "\t<%s>\n", XML_STR_ROW);
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+        fprintf(fp, "\t</%s>\n", XML_STR_ROW);
+    }
+
+    fprintf(fp, "</%s>\n", XML_STR_ROOT);
+    return OK;
+}