1 /* guia08/ej11.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 ARGS 2 /* Program name and file to read name */ 11 #define FILE_NAME_POS 1 12 13 #define MSG_USAGE "Usage: ./a.out <file name>" 14 15 #define ARR_INIT_SIZE 3 16 #define STR_INIT_SIZE 10 17 18 #define GROWTH_FACTOR 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 char **split(const char *s, 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(!(arr = split(input, ',', &len))) return 1; 49 50 for(i = 0; i <= len; i++) 51 printf("%s\n", arr[i]); 52 53 while(len + 1) free(arr[len--]); 54 55 free(arr); 56 free(input); 57 58 return 0; 59 } 60 61 status_t validate_arguments(int argc, char *argv[]) 62 { 63 if(!argv) return ERROR_NULL_POINTER; 64 if(argc != ARGS) return ERROR_PROGRAM_INVOCATION; 65 66 return OK; 67 } 68 69 status_t load_file(const char *file_name, char **array) 70 { 71 FILE *fp; 72 size_t alloc_size; 73 74 if(!(fp = fopen(file_name, "rt"))) return ERROR_OPENING_FILE; 75 76 alloc_size = LOAD_FILE_BUFFER_SIZE; 77 if(!(*array = calloc(sizeof(char), alloc_size))) return ERROR_ALLOC_MEMORY; 78 79 for(size_t i = 0; ((*array)[i] = fgetc(fp)) != EOF; i++) { 80 if(i == (alloc_size - 2)) { 81 alloc_size *= 2; 82 if(!(*array = realloc(*array, alloc_size))) { 83 free(*array); 84 array = NULL; 85 fclose(fp); 86 return ERROR_ALLOC_MEMORY; 87 } 88 } 89 } 90 91 fclose(fp); 92 return OK; 93 } 94 95 /* 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 */ 96 char **split(const char *s, char delim, size_t *fields) 97 { 98 if(!s || !fields) return NULL; 99 100 char **arr; 101 size_t i, arr_size, str_size; 102 103 arr_size = ARR_INIT_SIZE; 104 str_size = STR_INIT_SIZE; 105 106 if(!(arr = (char **)calloc(sizeof(char *), arr_size))) return NULL; 107 108 if(!(*arr = (char *)calloc(sizeof(char), str_size))) { 109 free(arr); 110 return NULL; 111 } 112 113 for(*fields = i = 0; *s; i++, s++) { 114 /* If the array doesn't have any memory left then it gets more memory */ 115 if(*fields == (arr_size - 1)) { 116 /* Exponential growth of the array */ 117 arr_size *= GROWTH_FACTOR; 118 119 if(!(arr = (char **)realloc(arr, arr_size * sizeof(char *)))) { 120 /* If it can't get more memory then all the previous allocations gets freed */ 121 while((*fields) + 1) free(arr[(*fields)--]); 122 free(arr); 123 return NULL; 124 } 125 } 126 if((*s == delim) || (*s == '\n')) { 127 if(!(arr[++(*fields)] = (char *)calloc(sizeof(char), str_size))) { 128 /* If it can't get more memory then all the previous allocations gets freed */ 129 while(*fields) 130 free(arr[(*fields)--]); 131 132 free(arr); 133 return NULL; 134 } 135 i = 0; 136 s++; 137 } 138 /* This makes sure that the current string has available memory, if not then it gets more */ 139 if(i == (str_size - 2)) { 140 str_size *= GROWTH_FACTOR; 141 if(!(arr[*fields] = (char *)realloc(arr[*fields], str_size))) { 142 /* If it can't get more memory all the previous used memmory gets freed */ 143 while((*fields) + 1) 144 free(arr[(*fields)--]); 145 146 free(arr); 147 return NULL; 148 } 149 /* Sets all the new memory to the null character */ 150 for(size_t j = i; j < str_size; j++) (*arr)[j] = '\0'; 151 } 152 arr[*fields][i] = (*s); 153 } 154 free(arr[(*fields)--]); 155 return arr; 156 }