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:
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 *));
+}