1 /* guia08/ej12.c + CLA 2 * por Martin J. Klöckner 3 * github.com/klewer-martin 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #define FILE_NAME_POS 1 11 #define ARGS 2 12 13 #define MSG_USAGE "Usage: ./a.out <file name>" 14 15 #define GROWTH_FACTOR 2 16 17 #define ARR_INIT_SIZE 1000 18 #define STR_INIT_SIZE 2 19 20 #define LOAD_FILE_BUFFER_SIZE 100 21 22 typedef enum { 23 OK, 24 ERROR_PROGRAM_INVOCATION, 25 ERROR_OPENING_FILE, 26 ERROR_ALLOC_MEMORY, 27 ERROR_NULL_POINTER 28 } status_t; 29 30 status_t validate_arguments(int argc, char *argv[]); 31 32 status_t load_file(const char *file_name, char **array); 33 status_t split(const char *s, char ***array, char delim, size_t *fields); 34 35 int main (int argc, char *argv[]) 36 { 37 char **arr, *input; 38 size_t i, len; 39 status_t st; 40 41 if((st = validate_arguments(argc, argv))) { 42 fprintf(stderr, "%s\n", MSG_USAGE); 43 return ERROR_PROGRAM_INVOCATION; 44 } 45 46 if((st = load_file(argv[FILE_NAME_POS], &input))) return st; 47 48 if((st = split(input, &arr, ',', &len))) return st; 49 50 free(input); 51 52 for(i = 0; i <= len; i++) 53 printf("%s\n", arr[i]); 54 55 while(len + 1) free(arr[len--]); 56 57 free(arr); 58 59 return 0; 60 } 61 62 status_t validate_arguments(int argc, char *argv[]) 63 { 64 if(!argv) return ERROR_NULL_POINTER; 65 if(argc != ARGS) return ERROR_PROGRAM_INVOCATION; 66 67 return OK; 68 } 69 70 status_t load_file(const char *file_name, char **array) 71 { 72 FILE *fp; 73 size_t alloc_size; 74 75 if(!(fp = fopen(file_name, "rt"))) return ERROR_OPENING_FILE; 76 77 alloc_size = LOAD_FILE_BUFFER_SIZE; 78 if(!(*array = calloc(sizeof(char), alloc_size))) return ERROR_ALLOC_MEMORY; 79 80 for(size_t i = 0; ((*array)[i] = fgetc(fp)) != EOF; i++) { 81 if(i == (alloc_size - 2)) { 82 alloc_size *= 2; 83 if(!(*array = realloc(*array, alloc_size))) { 84 free(*array); 85 array = NULL; 86 fclose(fp); 87 return ERROR_ALLOC_MEMORY; 88 } 89 } 90 } 91 92 fclose(fp); 93 return OK; 94 } 95 96 /* Recibe una cadena de caracteres de longitud desconocida, con valores separados por un caracter delimitador y los separa en cadenas de caracteres de longitud dinamica */ 97 status_t split(const char *s, char ***array, char delim, size_t *fields) 98 { 99 if(!s || !fields) return ERROR_NULL_POINTER; 100 101 size_t i, arr_size, str_size; 102 103 arr_size = ARR_INIT_SIZE; 104 str_size = STR_INIT_SIZE; 105 106 if(!(*array = (char **)calloc(sizeof(char *), arr_size))) return ERROR_ALLOC_MEMORY; 107 108 if(!(**array = (char *)calloc(sizeof(char), str_size))) { free(*array); return ERROR_ALLOC_MEMORY; } 109 110 for(*fields = i = 0; *s; i++, s++) { 111 /* If the array doesn't have any memory left then it gets more memory */ 112 if(*fields == (arr_size - 1)) { 113 /* Exponential growth of the array */ 114 arr_size *= GROWTH_FACTOR; 115 if(!(*array = (char **)realloc(*array, arr_size * sizeof(char *)))) { 116 /* If it can't get more memory then all the previous allocations gets freed */ 117 while((*fields) + 1) free((*array)[(*fields)--]); 118 free(*array); 119 return ERROR_ALLOC_MEMORY; 120 } 121 } 122 if((*s == delim) || (*s == '\n')) { 123 str_size = STR_INIT_SIZE; 124 if(!((*array)[++(*fields)] = (char *)calloc(sizeof(char), str_size))) { 125 /* If it can't get more memory then all the previous allocations gets freed */ 126 while(*fields) 127 free((*array)[(*fields)--]); 128 129 free(*array); 130 return ERROR_ALLOC_MEMORY; 131 } 132 s++; i = 0; 133 } 134 /* This makes sure that the current string has available memory, if not then it gets more */ 135 if(i == (str_size - 2)) { 136 str_size *= GROWTH_FACTOR; 137 if(!((*array)[*fields] = (char *)realloc((*array)[*fields], str_size))) { 138 /* If it can't get more memory all the previous used memmory gets freed */ 139 while((*fields) + 1) 140 free((*array)[(*fields)--]); 141 142 free(*array); 143 return ERROR_ALLOC_MEMORY; 144 } 145 } 146 (*array)[*fields][i] = (*s); 147 } /* End for loop */ 148 149 free((*array)[(*fields)--]); 150 return OK; 151 }