Remove SOL body flags
[neverball] / share / common.c
1 /*
2  *  Copyright (C) 2007  Neverball contributors
3  *
4  *  This  program is  free software;  you can  redistribute  it and/or
5  *  modify it  under the  terms of the  GNU General Public  License as
6  *  published by the Free Software Foundation; either version 2 of the
7  *  License, or (at your option) any later version.
8  *
9  *  This program  is distributed in the  hope that it  will be useful,
10  *  but  WITHOUT ANY WARRANTY;  without even  the implied  warranty of
11  *  MERCHANTABILITY or FITNESS FOR  A PARTICULAR PURPOSE.  See the GNU
12  *  General Public License for more details.
13  *
14  *  You should have received a  copy of the GNU General Public License
15  *  along  with this  program;  if  not, write  to  the Free  Software
16  *  Foundation,  Inc.,   59  Temple  Place,  Suite   330,  Boston,  MA
17  *  02111-1307 USA
18  */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <time.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26 #include <assert.h>
27
28 #include "common.h"
29 #include "fs.h"
30
31 #define MAXSTR 256
32
33 /*---------------------------------------------------------------------------*/
34
35 int read_line(char **dst, fs_file fin)
36 {
37     char buff[MAXSTR];
38
39     char *line, *new;
40     size_t len0, len1;
41
42     line = NULL;
43
44     while (fs_gets(buff, sizeof (buff), fin))
45     {
46         /* Append to data read so far. */
47
48         if (line)
49         {
50             new  = concat_string(line, buff, NULL);
51             free(line);
52             line = new;
53         }
54         else
55         {
56             line = strdup(buff);
57         }
58
59         /* Strip newline, if any. */
60
61         len0 = strlen(line);
62         strip_newline(line);
63         len1 = strlen(line);
64
65         if (len1 != len0)
66         {
67             /* We hit a newline, clean up and break. */
68             line = realloc(line, len1 + 1);
69             break;
70         }
71     }
72
73     return (*dst = line) ? 1 : 0;
74 }
75
76 char *strip_newline(char *str)
77 {
78     char *c = str + strlen(str) - 1;
79
80     while (c >= str && (*c == '\n' || *c =='\r'))
81         *c-- = '\0';
82
83     return str;
84 }
85
86 char *dupe_string(const char *src)
87 {
88     char *dst = NULL;
89
90     if (src && (dst = malloc(strlen(src) + 1)))
91         strcpy(dst, src);
92
93     return dst;
94 }
95
96 char *concat_string(const char *first, ...)
97 {
98     char *full;
99
100     if ((full = strdup(first)))
101     {
102         const char *part;
103         va_list ap;
104
105         va_start(ap, first);
106
107         while ((part = va_arg(ap, const char *)))
108         {
109             char *new;
110
111             if ((new = realloc(full, strlen(full) + strlen(part) + 1)))
112             {
113                 full = new;
114                 strcat(full, part);
115             }
116             else
117             {
118                 free(full);
119                 full = NULL;
120                 break;
121             }
122         }
123
124         va_end(ap);
125     }
126
127     return full;
128 }
129
130 char *trunc_string(const char *src, char *dst, int len)
131 {
132     static const char ell[] = "...";
133
134     assert(len > sizeof (ell));
135
136     if (dst[len - 1] = '\0', strncpy(dst, src, len), dst[len - 1] != '\0')
137         strcpy(dst + len - sizeof (ell), ell);
138
139     return dst;
140 }
141
142 time_t make_time_from_utc(struct tm *tm)
143 {
144     struct tm local, *utc;
145     time_t t;
146
147     t = mktime(tm);
148
149     local = *localtime(&t);
150     utc   =  gmtime(&t);
151
152     local.tm_year += local.tm_year - utc->tm_year;
153     local.tm_mon  += local.tm_mon  - utc->tm_mon ;
154     local.tm_mday += local.tm_mday - utc->tm_mday;
155     local.tm_hour += local.tm_hour - utc->tm_hour;
156     local.tm_min  += local.tm_min  - utc->tm_min ;
157     local.tm_sec  += local.tm_sec  - utc->tm_sec ;
158
159     return mktime(&local);
160 }
161
162 const char *date_to_str(time_t i)
163 {
164     static char str[sizeof ("YYYY-mm-dd HH:MM:SS")];
165     strftime(str, sizeof (str), "%Y-%m-%d %H:%M:%S", localtime(&i));
166     return str;
167 }
168
169 int file_exists(const char *name)
170 {
171     FILE *fp;
172
173     if ((fp = fopen(name, "r")))
174     {
175         fclose(fp);
176         return 1;
177     }
178     return 0;
179 }
180
181 int file_rename(const char *src, const char *dst)
182 {
183 #ifdef _WIN32
184     if (file_exists(dst))
185         remove(dst);
186 #endif
187     return rename(src, dst);
188 }
189
190 void file_copy(FILE *fin, FILE *fout)
191 {
192     char   buff[MAXSTR];
193     size_t size;
194
195     while ((size = fread(buff, 1, sizeof (buff), fin)) > 0)
196         fwrite(buff, 1, size, fout);
197 }
198
199 /*---------------------------------------------------------------------------*/
200
201 int path_is_sep(int c)
202 {
203 #ifdef _WIN32
204     return c == '/' || c == '\\';
205 #else
206     return c == '/';
207 #endif
208 }
209
210 int path_is_abs(const char *path)
211 {
212     if (path_is_sep(path[0]))
213         return 1;
214
215 #ifdef _WIN32
216     if (isalpha(path[0]) && path[1] == ':' && path_is_sep(path[2]))
217         return 1;
218 #endif
219
220     return 0;
221 }
222
223 static char *path_last_sep(const char *path)
224 {
225     char *sep;
226
227     sep = strrchr(path, '/');
228
229 #ifdef _WIN32
230     if (!sep)
231     {
232         sep = strrchr(path, '\\');
233     }
234     else
235     {
236         char *tmp;
237
238         if ((tmp = strrchr(sep, '\\')))
239             sep = tmp;
240     }
241 #endif
242
243     return sep;
244 }
245
246 char *base_name(const char *name, const char *suffix)
247 {
248     static char buf[MAXSTR];
249     char *base;
250
251     if (!name)
252         return NULL;
253
254     /* Remove the directory part. */
255
256     base = path_last_sep(name);
257
258     strncpy(buf, base ? base + 1 : name, sizeof (buf) - 1);
259
260     /* Remove the suffix. */
261
262     if (suffix)
263     {
264         int l = strlen(buf) - strlen(suffix);
265
266         if (l >= 0 && strcmp(buf + l, suffix) == 0)
267             buf[l] = '\0';
268     }
269
270     return buf;
271 }
272
273 const char *dir_name(const char *name)
274 {
275     static char buff[MAXSTR];
276
277     char *sep;
278
279     strncpy(buff, name, sizeof (buff) - 1);
280
281     if ((sep = path_last_sep(buff)))
282     {
283         if (sep == buff)
284             return "/";
285
286         *sep = '\0';
287
288         return buff;
289     }
290
291     return ".";
292 }
293
294 /*
295  * Given a path to a file REF and another path REL relative to REF,
296  * construct and return a new path that can be used to refer to REL
297  * directly.
298  */
299 char *path_resolve(const char *ref, const char *rel)
300 {
301     static char new[MAXSTR * 2];
302
303     if (path_is_abs(rel))
304     {
305         strncpy(new, rel, sizeof (new) - 1);
306         return new;
307     }
308
309     strncpy(new, dir_name(ref), sizeof (new) - 1);
310     strncat(new, "/",           sizeof (new) - strlen(new) - 1);
311     strncat(new, rel,           sizeof (new) - strlen(new) - 1);
312
313     return new;
314 }
315
316 /*---------------------------------------------------------------------------*/
317
318 int rand_between(int low, int high)
319 {
320     return low + rand() / (RAND_MAX / (high - low + 1) + 1);
321 }
322
323 /*---------------------------------------------------------------------------*/