1#ifndef BITMAPSFROMTEXTFILES_H_
2#define BITMAPSFROMTEXTFILES_H_
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE
5#endif
6#include <dirent.h>
7#include <inttypes.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13
14/*********************************/
15/********************************
16 * General functions to load up bitmaps from text files.
17 * Except format: comma-separated integers.
18 *******************************/
19/*********************************/
20
21/**
22 * Read the content of a file to a char array. Caller is
23 * responsible for memory de-allocation.
24 * Returns NULL on error.
25 *
26 * (If the individual files are small, this function is
27 * a good idea.)
28 */
29static char *read_file(const char *filename) {
30 FILE *fp = fopen(filename, "r");
31 if (!fp) {
32 printf("Could not open file %s\n", filename);
33 return NULL;
34 }
35
36 fseek(fp, 0, SEEK_END);
37 size_t size = (size_t)ftell(fp);
38 rewind(fp);
39 char *answer = (char *)malloc(size + 1);
40 if (!answer) {
41 fclose(fp);
42 return NULL;
43 }
44 if (fread(answer, size, 1, fp) != 1) {
45 free(answer);
46 return NULL;
47 }
48 answer[size] = '\0';
49 fclose(fp);
50 return answer;
51}
52
53/**
54 * Given a file made of comma-separated integers,
55 * read it all and generate an array of integers.
56 * The caller is responsible for memory de-allocation.
57 */
58static uint32_t *read_integer_file(const char *filename, size_t *howmany) {
59 char *buffer = read_file(filename);
60 if (buffer == NULL) return NULL;
61
62 size_t howmanyints = 1;
63 size_t i1 = 0;
64 for (; buffer[i1] != '\0'; i1++) {
65 if (buffer[i1] == ',') ++howmanyints;
66 }
67
68 uint32_t *answer = (uint32_t *)malloc(howmanyints * sizeof(uint32_t));
69 if (answer == NULL) return NULL;
70 size_t pos = 0;
71 for (size_t i = 0; (i < i1) && (buffer[i] != '\0'); i++) {
72 uint32_t currentint;
73 while ((buffer[i] < '0') || (buffer[i] > '9')) {
74 i++;
75 if (buffer[i] == '\0') goto END;
76 }
77 currentint = (uint32_t)(buffer[i] - '0');
78 i++;
79 for (; (buffer[i] >= '0') && (buffer[i] <= '9'); i++)
80 currentint = currentint * 10 + (uint32_t)(buffer[i] - '0');
81 answer[pos++] = currentint;
82 }
83END:
84 if (pos != howmanyints) {
85 printf("unexpected number of integers! %d %d \n", (int)pos,
86 (int)howmanyints);
87 }
88 *howmany = pos;
89 free(buffer);
90 return answer;
91}
92
93/**
94 * Does the file filename ends with the given extension.
95 */
96static bool hasExtension(const char *filename, const char *extension) {
97 const char *ext = strrchr(filename, '.');
98 return (ext && !strcmp(ext, extension));
99}
100
101/**
102 * read all (count) integer files in a directory. Caller is responsible
103 * for memory de-allocation. In case of error, a NULL is returned.
104 */
105static uint32_t **read_all_integer_files(const char *dirname,
106 const char *extension,
107 size_t **howmany, size_t *count) {
108 struct dirent **entry_list;
109
110 int c = scandir(dirname, &entry_list, 0, alphasort);
111 if (c < 0) return NULL;
112 size_t truec = 0;
113 for (int i = 0; i < c; i++) {
114 if (hasExtension(entry_list[i]->d_name, extension)) ++truec;
115 }
116 *count = truec;
117 *howmany = (size_t *)malloc(sizeof(size_t) * (*count));
118 uint32_t **answer = (uint32_t **)malloc(sizeof(uint32_t *) * (*count));
119 size_t dirlen = strlen(dirname);
120 char *modifdirname = (char *)dirname;
121 if (modifdirname[dirlen - 1] != '/') {
122 modifdirname = (char *)malloc(dirlen + 2);
123 strcpy(modifdirname, dirname);
124 modifdirname[dirlen] = '/';
125 modifdirname[dirlen + 1] = '\0';
126 dirlen++;
127 }
128 for (size_t i = 0, pos = 0; i < (size_t)c;
129 i++) { /* formerly looped while i < *count */
130 if (!hasExtension(entry_list[i]->d_name, extension)) continue;
131 size_t filelen = strlen(entry_list[i]->d_name);
132 char *fullpath = (char *)malloc(dirlen + filelen + 1);
133 strcpy(fullpath, modifdirname);
134 strcpy(fullpath + dirlen, entry_list[i]->d_name);
135 answer[pos] = read_integer_file(fullpath, &((*howmany)[pos]));
136 pos++;
137 free(fullpath);
138 }
139 if (modifdirname != dirname) {
140 free(modifdirname);
141 }
142 for (int i = 0; i < c; ++i) free(entry_list[i]);
143 free(entry_list);
144 return answer;
145}
146
147#endif /* BITMAPSFROMTEXTFILES_H_ */
148