1 /*
2 * io/utils.c
3 *
4 * c Ronny Lorenz
5 * Vienna RNA package
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <time.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <stdint.h>
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <libgen.h>
23
24 #include "ViennaRNA/utils/basic.h"
25 #include "ViennaRNA/utils/strings.h"
26 #include "ViennaRNA/io/utils.h"
27
28 #define PRIVATE static
29 #define PUBLIC
30
31 /*
32 #################################
33 # GLOBAL VARIABLES #
34 #################################
35 */
36
37
38 /*
39 #################################
40 # PRIVATE VARIABLES #
41 #################################
42 */
43 #ifdef _WIN32
44 #ifdef __MINGW32__
45 #include <direct.h>
46 #endif
47 #define DIRSEPC '\\'
48 #define DIRSEPS "\\"
49 #else
50 #define DIRSEPC '/'
51 #define DIRSEPS "/"
52 #endif
53
54 /*
55 #################################
56 # PRIVATE FUNCTION DECLARATIONS #
57 #################################
58 */
59 PRIVATE int is_absolute_path(const char *p);
60
61
62 /*
63 #################################
64 # BEGIN OF FUNCTION DEFINITIONS #
65 #################################
66 */
67 PUBLIC void
vrna_file_copy(FILE * from,FILE * to)68 vrna_file_copy(FILE *from,
69 FILE *to)
70 {
71 int c;
72
73 while ((c = getc(from)) != EOF)
74 (void)putc(c, to);
75 }
76
77
78 PUBLIC char *
vrna_read_line(FILE * fp)79 vrna_read_line(FILE *fp)
80 {
81 /* reads lines of arbitrary length from fp */
82
83 char s[512], *line, *cp;
84 int len = 0, size = 0, l, l2;
85
86 line = NULL;
87 do {
88 if (fgets(s, 512, fp) == NULL)
89 break;
90
91 cp = strchr(s, '\n');
92 if (cp != NULL)
93 *cp = '\0';
94
95 l2 = (int)strlen(s);
96 l = len + l2;
97 if (l + 1 > size) {
98 size = (int)((l + 1) * 1.2);
99 line = (char *)vrna_realloc(line, size * sizeof(char));
100 }
101 memcpy(line + len,
102 s,
103 sizeof(char) * l2);
104
105 line[l] = '\0';
106 len = l;
107 } while (cp == NULL);
108
109 return line;
110 }
111
112
113 PUBLIC int
vrna_mkdir_p(const char * path)114 vrna_mkdir_p(const char *path)
115 {
116 struct stat sb;
117 char *slash, *ptr;
118 int done = 0;
119
120 if (!is_absolute_path(path))
121 ptr = vrna_strdup_printf(".%c%s", DIRSEPC, path);
122 else
123 ptr = strdup(path);
124
125 slash = ptr;
126
127 while (!done) {
128 slash += strspn(slash, DIRSEPS);
129 slash += strcspn(slash, DIRSEPS);
130
131 done = (*slash == '\0');
132 *slash = '\0';
133
134 if (stat(ptr, &sb)) {
135 #ifdef _WIN32
136 if (errno != ENOENT || (_mkdir(ptr) &&
137 errno != EEXIST)) {
138 #else
139 if (errno != ENOENT || (mkdir(ptr, 0777) &&
140 errno != EEXIST)) {
141 #endif
142 vrna_message_warning("Can't create directory %s", ptr);
143 free(ptr);
144 return -1;
145 }
146 } else if (!S_ISDIR(sb.st_mode)) {
147 vrna_message_warning("File exists but is not a directory %s: %s", ptr, strerror(ENOTDIR));
148 free(ptr);
149 return -1;
150 }
151
152 *slash = DIRSEPC;
153 }
154
155 free(ptr);
156 return 0;
157 }
158
159
160 PUBLIC char *
161 vrna_basename(const char *path)
162 {
163 char *name, *ptr;
164
165 name = NULL;
166
167 if (path) {
168 ptr = strrchr(path, DIRSEPC);
169
170 if (ptr && (*(ptr + 1) != '\0'))
171 name = strdup(ptr + 1);
172 else if (!ptr)
173 name = strdup(path);
174 }
175
176 return name;
177 }
178
179
180 PUBLIC char *
181 vrna_dirname(const char *path)
182 {
183 char *name, *p, *ptr;
184 int pos;
185
186 name = NULL;
187
188 if (path) {
189 if (!is_absolute_path(path))
190 ptr = vrna_strdup_printf(".%c%s", DIRSEPC, path);
191 else
192 ptr = strdup(path);
193
194 pos = (int)strlen(ptr);
195 p = ptr + pos;
196
197 do /* remove part after last separator */
198 *p = '\0';
199 while ((--p > ptr) && (*p != DIRSEPC));
200
201 if (p > ptr)
202 name = ptr;
203 }
204
205 return name;
206 }
207
208
209 PUBLIC char *
210 vrna_filename_sanitize(const char *name,
211 const char *replacement)
212 {
213 if (name) {
214 const char *ptr, *start, *illegal_chars;
215 char *sanitized_name;
216 unsigned int i, n;
217
218 illegal_chars = "\\/?%*:|\"<> ";
219 sanitized_name = (char *)vrna_alloc(sizeof(char) * (strlen(name) + 1));
220 start = name;
221 i = 0;
222 while ((ptr = strpbrk(start, illegal_chars))) {
223 /* find illegal chars */
224 strncpy(sanitized_name + i, start, ptr - start);
225 i += ptr - start;
226 if (replacement && (*replacement))
227 sanitized_name[i++] = *replacement;
228
229 start = ptr + 1; /* skip invalid character */
230 }
231 /* copy remaining part */
232 if (start < (name + strlen(name))) {
233 unsigned int diff = name - start + strlen(name);
234 strncpy(sanitized_name + i, start, diff);
235 i += diff;
236 }
237
238 /* resize the output string to actual requirements */
239 sanitized_name = (char *)vrna_realloc(sanitized_name, sizeof(char) * (i + 1));
240 sanitized_name[i] = '\0';
241
242 /* check for reserved unix file names */
243 if ((!strcmp(sanitized_name, ".")) || (!strcmp(sanitized_name, ".."))) {
244 sanitized_name = (char *)vrna_realloc(sanitized_name, sizeof(char));
245 sanitized_name[0] = '\0';
246 }
247
248 /* check for length restrictions */
249 n = strlen(sanitized_name);
250 if (n > 255) {
251 char *suff = NULL;
252 /* try to leave file suffix, i.e. everything after last dot '.', intact */
253 if ((suff = strrchr(sanitized_name, '.')) && (sanitized_name + n - suff < 255)) {
254 unsigned int n_suff = sanitized_name + n - suff;
255 memmove(sanitized_name + (255 - n_suff), sanitized_name + n - n_suff,
256 sizeof(char) * n_suff);
257 }
258
259 sanitized_name = (char *)vrna_realloc(sanitized_name, sizeof(char) * 256);
260 sanitized_name[255] = '\0';
261 }
262
263 /* finally, return the sanitized file name */
264 return sanitized_name;
265 } else {
266 return NULL;
267 }
268 }
269
270
271 PUBLIC int
272 vrna_file_exists(const char *filename)
273 {
274 int r = 0;
275
276 #ifdef _WIN32
277 struct _stat buf;
278 r = _stat(filename, &buf) == 0 ? 1 : 0;
279 #else
280 struct stat buf;
281 r = stat(filename, &buf) == 0 ? 1 : 0;
282 #endif
283 return r;
284 }
285
286
287 #ifdef _WIN32
288 PRIVATE int
289 is_drive_char(const char c)
290 {
291 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
292 return 1;
293
294 return 0;
295 }
296
297
298 #endif
299
300
301 PRIVATE int
302 is_absolute_path(const char *p)
303 {
304 if (*p == DIRSEPC)
305 return 1;
306
307 #ifdef _WIN32
308 if (is_drive_char((const char)*p) && (strlen(p) > 3))
309 if ((*(p + 1) == ':') && ((*(p + 2) == '\\') || (*(p + 2) == '/')))
310 return 1;
311
312 #endif
313 return 0;
314 }
315