9511_project03

project 3 for algorithms & programming I (9511) prof. Cardozo
Index Commits Files Refs README LICENSE
commit bd65d08bf77f1d39df6baf364ba2ef9526bc6bcb
parent 634904e117e0638ac7edb053773b5327ac4416f2
Author: klewer-martin <martin.cachari@gmail.com>
Date:   Thu, 22 Jul 2021 17:52:03 -0300

Update after long time

Diffstat:
MMakefile | 45++++++++++++++++++++++++++++++++++++---------
Mexamples/input_gen.py | 8++++----
Minclude/cla.h | 9++++++---
Minclude/io.h | 48++++++++++++++++++++++++++++++++++++++----------
Minclude/sort.h | 11+++++++----
Ainclude/status.h | 37+++++++++++++++++++++++++++++++++++++
Minclude/types.h | 1+
Msource/cla.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msource/io.c | 323++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msource/main.c | 61+++++++++++++++++++++++++++++++++++++++++++------------------
Msource/sort.c | 53++++++++++++++++++++++++++++++++++++++---------------
Asource/status.c | 44++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 588 insertions(+), 123 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,28 +1,55 @@
 CC=gcc
-CFLAGS=-std=c99 -pedantic -Wall
+CFLAGS=-g -pedantic -Wall
 SRCFOLDER=source
 HFOLDER=include
 PROGNAME=main
 
 all: main clean
 
-main: main.o cla.o errors.o io.o sort.o
-    $(CC) $(CFLAGS) main.o cla.o errors.o io.o sort.o -o $(PROGNAME)
+main: main.o cla.o status.o io.o sort.o
+    $(CC) $(CFLAGS) main.o cla.o status.o io.o sort.o -o $(PROGNAME)
 
-main.o: $(HFOLDER)/cla.h $(HFOLDER)/errors.h
+main.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/main.c
 
-cla.o: $(HFOLDER)/cla.h $(HFOLDER)/types.h
+cla.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/cla.c
 
-errors.o: $(HFOLDER)/types.h
-    $(CC) $(CFLAGS) -c $(SRCFOLDER)/errors.c
+status.o: $(HFOLDER)/status.h
+    $(CC) $(CFLAGS) -c $(SRCFOLDER)/status.c
 
-io.o: $(HFOLDER)/types.h
+io.o: $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/io.c
 
-sort.o: $(HFOLDER)/types.h
+sort.o: $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/sort.c
 
 clean:
     rm *.o
+
+run20:
+    ./main -fmt csv -out output.csv -in examples/test_file_20.csv -ti 1320498000 -tf 1320498046
+
+run2k:
+    ./main -fmt csv -out output.csv -in examples/test_file_2k.csv -ti 1320498000 -tf 1325499000
+
+run50:
+    ./main -fmt csv -out output.csv -in examples/test_file_50.csv -ti 1320498000 -tf 1320498049
+
+run500:
+    ./main -fmt csv -out output.csv -in examples/test_file_500.csv -ti 1320498000 -tf 1320529000
+
+run5k:
+    ./main -fmt csv -out output.csv -in examples/test_file_5k.csv -ti 1320498000 -tf 1320529000
+
+run50k:
+    ./main -fmt csv -out output.csv -in examples/test_file_50k.csv -ti 1320498000 -tf 1420529000
+
+run500k:
+    ./main -fmt csv -out output.csv -in examples/test_file_500k.csv -ti 1320498000 -tf 1420529000
+
+run50xml:
+    ./main -fmt xml -out output.xml -in examples/test_file_50.csv -ti 1320498000 -tf 1320498049
+
+run5kxml:
+    ./main -fmt xml -out output.xml -in examples/test_file_5k.csv -ti 1320498000 -tf 1360498049
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 = 2000
+LINES = 5000
 
 # OUTPUT:
 #     ID_TRANSACCION, ID_USUARIO, FECHA, MONTO, NUMERO DE TRAJETA, DESCRIPCION
@@ -16,14 +16,14 @@ def card_number_generator():
 def generate_file(max_lines):
     id_transaction_base = 123400
     id_user_base = 1
-    id_user_max = 2000
-    amount_base = 10
+    id_user_max = 200
+    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() 
-        date = strftime("%d/%m/%Y %H:%M:%S", gmtime(1320487200 + i))
+        date = strftime("%d.%m.%Y %H:%M:%S", gmtime(1320487200 + i))
         
         j = randint(1, len(descs) - 1)
         desc = descs[j] 
diff --git a/include/cla.h b/include/cla.h
@@ -5,7 +5,7 @@
 #include <string.h>
 #include <stdbool.h>
 
-#include "types.h"
+#include "status.h"
 
 #define NO_ARGS_ENTERED 1
 #define NORMAL_AMOUNT_ARGS 11
@@ -22,14 +22,17 @@ typedef enum {
 
 typedef struct {
     char *fmt, *fi, *fo;
-    unsigned long ti, tf;
+    unsigned long ti, tf, parsed_lines;
 } 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 setup(int argc, char **argv, cla_t *cla);
+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);
 
 extern const char *available_flags[FLAGS_MAX];
diff --git a/include/io.h b/include/io.h
@@ -6,32 +6,60 @@
 #include <string.h>
 
 #include "cla.h"
-#include "types.h"
+#include "status.h"
 #include "sort.h"
 
+#define _XOPEN_SOURCE
+#define __USE_XOPEN
+#include <time.h>
+
 #define INPUT_FILE_FIELDS 6
 #define BUFFER_SIZE        1000
 
+#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_TRANSACTION,
+    POS_ID_TXN,
     POS_USER_ID,
-    POS_TRANSACTION_DATE,
+    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 set_data(user_t *user, char **data);
 
-status_t tmp_file_write(FILE *bfp, const user_t user);
-status_t tmp_file_read(FILE *bfp, user_t user);
+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);
 
-status_t split(char *s, 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 load_values(FILE *);
-status_t export_data(cla_t cla, FILE *bfp);
+status_t destroy_users(user_t *users, size_t size);
 
-void print_user(const user_t user);
+status_t user_create(user_t *usr);
+status_t user_set_data(user_t usr, int id, long credit, long debt);
 
-status_t tmp_file_gen(cla_t cla, FILE **bfp);
 #endif
diff --git a/include/sort.h b/include/sort.h
@@ -2,14 +2,17 @@
 #define SORT__H
 
 #include "cla.h"
-#include "types.h"
+#include "status.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
-int minmax(const void *, const void *);
-int maxmix(const void *, const void *);
+int credit_minmax(const void *, const void *);
+int credit_maxmix(const void *, const void *);
 
-status_t tmp_file_sort(FILE *tmp, size_t len, char order);
+int debt_minmax(const void *, const void *);
+int debt_maxmin(const void *, const void *);
+
+status_t sort_users(user_t *users, size_t size, char *order);
 
 #endif
diff --git a/include/status.h b/include/status.h
@@ -0,0 +1,37 @@
+#ifndef STATUS__H
+#define STATUS__H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define ERROR_RETRY_MSG "Verifique y vuelva a intentar"
+
+#define STATUS_T_MAX 12
+
+typedef enum {
+    OK,
+    ERROR_MEMORY,
+    ERROR_WRONG_FLAGS,
+    ERROR_WRONG_TIME,
+    ERROR_MISSING_ARGS,
+    ERROR_OPENING_FILE,
+    ERROR_CORRUPT_DATA,
+    ERROR_FLAG_REPEATED,
+    ERROR_FLAG_NOT_FOUND,
+    ERROR_FORMAT_NOT_FOUND,
+    ERROR_USER_NOT_FOUND,
+    ERROR_NULL_POINTER
+} status_t;
+
+typedef struct {
+    size_t id;
+    long credit, debt;
+} ADT_user_t, *user_t;
+
+void show_status(status_t st);
+void free_arrays(size_t num,...);
+
+extern const char *status_strings[STATUS_T_MAX];
+
+#endif
diff --git a/include/types.h b/include/types.h
@@ -12,6 +12,7 @@ typedef enum {
     ERROR_FLAG_NOT_FOUND,
     ERROR_FLAG_REPEATED,
     ERROR_OPENING_FILE,
+    ERROR_MEMORY,
     ERROR_NULL_POINTER
 } status_t;
 
diff --git a/source/cla.c b/source/cla.c
@@ -31,13 +31,12 @@ status_t check_flags_position(int argc, char **argv)
     return OK;
 }
 
-/* Need to add a record for already founded flags */
 status_t check_flags_repeated(int argc, char **argv)
 {
     size_t i, j, fflags_index;
     int founded_flags[FLAGS_MAX];
 
-    /* Inicializa a -1 para evitar confuciones con 0 */
+    /* Inicializa a -1 para evitar confusiones con 0 */
     for(i = 0; i < FLAGS_MAX; i++) founded_flags[i] = -1;
 
     for(i = 1, fflags_index = 0; i <= (argc - 2); i += 2) {
@@ -55,14 +54,9 @@ status_t check_flags_repeated(int argc, char **argv)
     return OK;
 }
 
-status_t setup(int argc, char **argv, cla_t *cla)
+status_t cla_setup(int argc, char **argv, cla_t *cla)
 {
-    /* Falta validar memoria */
-    *cla = (cla_t)malloc(sizeof(ADT_cla_t));
-
-    (*cla)->fmt = calloc(sizeof(char), 100);
-    (*cla)->fo = calloc(sizeof(char), 100);
-    (*cla)->fi = calloc(sizeof(char), 100);
+    char *endptr;
 
     for(size_t i = 1; i < argc; i += 2) {
         for(flags_t f = FLAG_FMT; f < FLAGS_MAX; f++) {
@@ -71,20 +65,65 @@ status_t setup(int argc, char **argv, cla_t *cla)
                     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], NULL, 10); break;
-                    case FLAG_TF: (*cla)->tf = strtoul(argv[i + 1], NULL, 10); 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;
                 }
             }
         }
     }
+
     return OK;
 }
 
-void clean(cla_t cla)
+
+status_t cla_create(cla_t *cla)
 {
-    free(cla->fmt);
-    free(cla->fi);
-    free(cla->fo);
-    free(cla);
+    if(cla == NULL) return ERROR_NULL_POINTER;
+
+    if((*cla = (cla_t)malloc(sizeof(ADT_cla_t))) == NULL)
+        return ERROR_MEMORY;
+
+    if(((*cla)->fmt = calloc(sizeof(char), 100)) == NULL) {
+        free(cla);
+        cla = NULL;
+        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;
+    }
+
+    return OK;
+}
+
+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);
+
+    cla = NULL;
+
+    return OK;
 }
diff --git a/source/io.c b/source/io.c
@@ -1,95 +1,330 @@
 #include "../include/io.h"
 
-/* Lee los datos de el archivo de entrada linea por linea 
- * y los imprime en un archivo binario temporal */
-status_t tmp_file_gen(cla_t cla, FILE **bfp)
+#define INIT_SIZE        1000
+#define GROWTH_FACTOR     2
+
+user_t find_user(const user_t *users, int id, size_t size);
+status_t destroy_data(char **data);
+
+status_t get_date(time_t *e, char **data);
+
+void user_clean(user_t usr);
+void clean_buffer(char *buf);
+void clean_data(char **data);
+
+user_t user_dup(user_t src);
+
+/* 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, *fpo;
+    FILE *fpi;
     char *buffer, **data;
-    size_t i;
-    user_t user;
+    time_t epoch;
+    size_t alloc_size;
+    user_t user, user_found, *tmp;
     status_t st;
 
-    if((fpi = fopen(cla->fi, "rt")) == NULL) return ERROR_OPENING_FILE;
+    *size = cla->parsed_lines = 0;
+    alloc_size = INIT_SIZE;
+    user = user_found = NULL;
 
-    if((fpo = fopen(cla->fo, "wt")) == NULL) return ERROR_OPENING_FILE;
-
-    if(((*bfp) = fopen(TMP_FILE_NAME, "wb")) == NULL) return ERROR_OPENING_FILE;
+    if((fpi = fopen(cla->fi, "rt")) == NULL) {
+        *users = NULL;
+        return ERROR_OPENING_FILE;
+    }
 
-    data = (char **)malloc(sizeof(char *) * INPUT_FILE_FIELDS);
+    if((data = (char **)malloc(sizeof(char *) * INPUT_FILE_FIELDS)) == NULL) {
+        fclose(fpi);
+        return ERROR_MEMORY;
+    }
 
-    for(i = 0; i < INPUT_FILE_FIELDS; i++)
-        data[i] = calloc(sizeof(char), BUFFER_SIZE);
+    if((buffer = calloc(sizeof(char), BUFFER_SIZE)) == NULL) {
+        destroy_data(data);
+        fclose(fpi);
+        return ERROR_MEMORY;
+    }
 
-    buffer = calloc(sizeof(char), BUFFER_SIZE);
+    if(user_create(&user) != OK) {
+        free(buffer);
+        destroy_data(data);
+        fclose(fpi);
+    }
 
-    /* Lee los datos de el archivo de entrada linea por linea 
-     * y los imprime en un archivo binario temporal */
-    for(i = 0; (fgets(buffer, BUFFER_SIZE, fpi) != NULL); i++) {
-        if((st = split(buffer, data))) return st;
-        if((st = set_data(&user, data))) return st;
-        tmp_file_write(*bfp, user);
+    /* 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);
     }
 
-    /* tmp_file_sort(*bfp, i, 'd'); */
+    /* 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;
+        }
 
-    /* tmp_file_read(*bfp, user); */
+        /* 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;
+        }
 
-    /* print_user(user); */
+        /* Asigna a 'user' id, creditos y debitos cargados en data */
+        if((st = set_data(&user, data)) != OK) {
+            destroy_data(data);
+            free(buffer);
+            fclose(fpi);
+            return st;
+        }
 
-    /* rewind(*bfp); */
-    /* for(i = 0; fread(user, 1, sizeof(ADT_user_t), *bfp); i++) */
-    /*     print_user(user); */
+        /* 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 = find_user(*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);
-    fclose(fpo);
     return OK;
 }
 
 status_t set_data(user_t *user, char **data) 
 {
-    int amount;
+    if(data == NULL || user == NULL) return ERROR_NULL_POINTER;
 
-    (*user) = (user_t)malloc(sizeof(user_t));
+    char *endptr;
+    long amount;
 
-    (*user)->id = strtol(data[POS_USER_ID], NULL, 10);
+    (*user)->id = strtol(data[POS_USER_ID], &endptr, 10);
+    if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
-    amount = strtol(data[POS_AMOUNT], NULL, 10);
+    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;
+    if(amount > 0) (*user)->credit = amount;
+    else if(amount < 0) (*user)->debt = -amount; /* '-=' Para eliminar el menos    */
 
     return OK;
 }
 
-status_t split(char *s, char **data)
+status_t string_split(char *s, char **data, char *delim)
 {
-    char *p;
+    char *p, *tmp;
     size_t fields = 0;
-    for(p = s; (data[fields++] = strtok(p, ",")); p = NULL);
+
+    for(p = s; (tmp = strtok(p, delim)); p = NULL)
+        data[fields++] = strdup(tmp);
+
+    if(fields != INPUT_FILE_FIELDS)
+        return ERROR_CORRUPT_DATA;
 
     return OK;
 }
 
-void print_user(const user_t user)
+
+status_t destroy_users(user_t *users, size_t size)
 {
-    printf("ID: %5d CREDITS: %5d DEBITS: %5d\n", user->id, user->credit, user->debt);
+    if(users == NULL) return ERROR_NULL_POINTER;
+
+    for(size_t i = 0; i < size; i++)
+        free(users[i]);
+
+    free(users);
+    return OK;
 }
 
-status_t tmp_file_write(FILE *bfp, const user_t user)
+status_t destroy_data(char **data)
 {
-    if(bfp == NULL) return ERROR_NULL_POINTER;
+    if(data == NULL) return ERROR_NULL_POINTER;
 
-    fwrite(user, 1, sizeof(ADT_user_t), bfp);
+    for(size_t 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)
+{
+    if(users == NULL) return ERROR_NULL_POINTER;
+
+    FILE *fo;
+
+    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 tmp_file_read(FILE *bfp, user_t user)
+status_t export_data_as_csv(FILE *fo, const user_t *users, size_t size)
 {
-    if(bfp == NULL || user == NULL) return ERROR_NULL_POINTER;
+    if(fo == NULL || users == NULL)
+        return ERROR_NULL_POINTER;
 
-    fread(user, 1, sizeof(ADT_user_t), bfp);
+    for(size_t 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)
+{
+    if(fo == NULL || users == NULL)
+        return ERROR_NULL_POINTER;
+
+    fprintf(fo, "%s\n%s\n", XML_HEADER, XML_ROOT_OPEN);
+    for(size_t 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)
+{
+    for(size_t i = 0; i < BUFFER_SIZE; i++)
+        buf[i] = '\0';
+}
+
+void clean_data(char **data)
+{
+    for(size_t i = 0; i < INPUT_FILE_FIELDS; i++) {
+        free(data[i]);
+        data[i] = NULL;
+    }
+}
+
+status_t get_date(time_t *e, char **data)
+{
+    if(e == NULL || data == NULL) return ERROR_NULL_POINTER;
+
+    struct tm tm;
+
+    /* 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;
+}
+
+void user_clean(user_t usr)
+{
+    usr->id = 0;
+    usr->credit = 0;
+    usr->debt = 0;
+}
+
+status_t user_set_data(user_t usr, int id, long credit, long debt)
+{
+    usr->id = id;
+    usr->credit = credit;
+    usr->debt = debt;
+
+    return OK;
+}
+
+user_t user_dup(user_t src)
+{
+    user_t dst = NULL;
+
+    user_create(&dst);
+
+    dst->id = src->id;
+    dst->credit = src->credit;
+    dst->debt = src->debt;
+
+    return dst;
+}
+
+status_t user_create(user_t *usr)
+{
+    if(((*usr) = (user_t)malloc(sizeof(ADT_user_t))) == NULL)
+        return ERROR_MEMORY;
+
+    (*usr)->id = 0;
+    (*usr)->credit = 0;
+    (*usr)->debt = 0;
+
+    return OK;
+}
+
+user_t find_user(const user_t *users, int id, size_t size)
+{
+    for(size_t i = 0; i < size; i++) {
+        if(users[i]->id == id) {
+            return users[i];
+        }
+    }
+    return NULL;
+}
diff --git a/source/main.c b/source/main.c
@@ -1,45 +1,70 @@
 #include "../include/cla.h"
-#include "../include/errors.h"
+#include "../include/status.h"
 #include "../include/io.h" /* output_gen() */
 #include "../include/sort.h"
 
-#include <stdlib.h>
+/* "ca" - creditos ascendentes | "cd" - creditos descendentes
+ * "da" - debitos ascendentes  | "dd" - debitos descendentes */
+#define SORTING_ORDER    "cd"
 
-#define SORTING_ORDER    "a"
-
-status_t create_array(int *arr, size_t len);
-status_t load_values(int **arr, size_t len);
-status_t destroy_array(int *arr, size_t len);
+#define EXIT_SUCCESS_MSG "EjecuciĆ³n terminada exitosamente"
+#define USERS_REGISTERED_MSG    "Usuarios registrados: "
+#define PROCESED_LINES_MSG        "Lineas procesadas: "
 
 int main (int argc, char *argv[])
 {
     status_t st;
-    FILE *tmp_file;
     cla_t cla;
+    user_t *users;
+    size_t size;
 
+    /* Valida que los argumentos sean correctos */
     if((st = validate_arguments(argc, argv)) != OK) {
         show_status(st);
         return st;
     }
 
-    if((st = setup(argc, argv, &cla)) != OK) {
+    /* Asigna memoria a cla */
+    if((st = cla_create(&cla)) != OK) {
+        show_status(st);
+        return st;
+    }
+
+    /* Asigna a la estructura 'cla' los argumentos ingresados */
+    if((st = cla_setup(argc, argv, &cla)) != OK) {
+        show_status(st);
+        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;
     }
-    /* En este punto ya tengo todos los datos que necesito, el nombre de los archivos de entrada, el tiempo inicial y final, y el formato de el archivo de salida */
 
-    /* Genera un archivo binario temporal con los datos parseados  */
-    if((st = tmp_file_gen(cla, &tmp_file)) != OK) {
+    /* Ordena los usuarios con orden SORTING_ORDER */
+    if((st = sort_users(users, size, SORTING_ORDER)) != OK) {
         show_status(st);
+        cla_destroy(&cla);
+        destroy_users(users, size);
         return st;
     }
 
-    /* Exporta el archivo temporal a un archivo de texto con formato de acuerdo a la flag recibida como argumento */
-    /* if((st = export_data(cla, tmp_file)) != OK) { */
-    /*     show_status(st); */
-    /*     return st; */
-    /* } */
+    /* Imprime los datos cargados en users a un archivo de salida */
+    if((st = export_data(cla, users, size)) != OK) {
+        show_status(st);
+        cla_destroy(&cla);
+        destroy_users(users, size);
+        return st;
+    }
+
+    printf("\n%s\n%s%ld\n%s%ld\n", EXIT_SUCCESS_MSG, USERS_REGISTERED_MSG,\
+            size, PROCESED_LINES_MSG, cla->parsed_lines);
+
+    cla_destroy(&cla);
+    destroy_users(users, size);
 
-    clean(cla);
     return OK;
 }
diff --git a/source/sort.c b/source/sort.c
@@ -1,30 +1,53 @@
 #include "../include/sort.h"
 
-int minmax(const void *a, const void *b)
+int credit_minmax(const void *a, const void *b)
 {
-    int *A = (int *)a;
-    int *B = (int *)b;
+    user_t *A = (user_t *)a;
+    user_t *B = (user_t *)b;
 
-    return (*A > *B) ? *A : (*A - *B);
+    return ((*A)->credit > (*B)->credit) ? 1 : 0;
 }
 
-int maxmin(const void *a, const void *b)
+int credit_maxmin(const void *a, const void *b)
 {
-    int *A = (int *)a;
-    int *B = (int *)b;
+    user_t *A = (user_t *)a;
+    user_t *B = (user_t *)b;
 
-    return (*A > *B) ? *A : (*A - *B);
+    return ((*A)->credit > (*B)->credit) ? 0 : 1;
 }
 
-status_t tmp_file_sort(FILE *tmp, size_t len, char order)
+int debt_minmax(const void *a, const void *b)
 {
-    if(tmp == NULL) return ERROR_NULL_POINTER;
+    user_t *A = (user_t *)a;
+    user_t *B = (user_t *)b;
 
-    switch (order)
-    {
-        case 'a': qsort(tmp, len, sizeof(ADT_cla_t), minmax); break;
-        case 'd': qsort(tmp, len, sizeof(ADT_cla_t), maxmin); break;
-    }
+    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
@@ -0,0 +1,44 @@
+#include "../include/status.h"
+
+const char *status_strings[] = {
+    "Everything executed succesfully. Have a nice day.",
+    "There is a problem with the memory",
+    "There is a flags misspeled",
+    "There is a problem with entered time",
+    "There are arguments missing",
+    "Error el archivo de se pudo abrir, puede que no existe o que el nombre sea incorrecto",
+    "Error al leer un dato, puede que el archivo de entrada este corrupto",
+    "Error hay una flag repetida",
+    "Error flag no encontrada",
+    "Error el formato de salida no se reconoce",
+    "Error usuario no encontrado, puede que el archivo de entrada este corrupto",
+    "ERROR_NULL_POINTER"
+};
+
+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 *));
+}