Use symbols for score ranks
[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 time_t make_time_from_utc(struct tm *tm)
131 {
132     struct tm local, *utc;
133     time_t t;
134
135     t = mktime(tm);
136
137     local = *localtime(&t);
138     utc   =  gmtime(&t);
139
140     local.tm_year += local.tm_year - utc->tm_year;
141     local.tm_mon  += local.tm_mon  - utc->tm_mon ;
142     local.tm_mday += local.tm_mday - utc->tm_mday;
143     local.tm_hour += local.tm_hour - utc->tm_hour;
144     local.tm_min  += local.tm_min  - utc->tm_min ;
145     local.tm_sec  += local.tm_sec  - utc->tm_sec ;
146
147     return mktime(&local);
148 }
149
150 const char *date_to_str(time_t i)
151 {
152     static char str[sizeof ("YYYY-mm-dd HH:MM:SS")];
153     strftime(str, sizeof (str), "%Y-%m-%d %H:%M:%S", localtime(&i));
154     return str;
155 }
156
157 int file_exists(const char *name)
158 {
159     FILE *fp;
160
161     if ((fp = fopen(name, "r")))
162     {
163         fclose(fp);
164         return 1;
165     }
166     return 0;
167 }
168
169 int file_rename(const char *src, const char *dst)
170 {
171 #ifdef _WIN32
172     if (file_exists(dst))
173         remove(dst);
174 #endif
175     return rename(src, dst);
176 }
177
178 void file_copy(FILE *fin, FILE *fout)
179 {
180     char   buff[MAXSTR];
181     size_t size;
182
183     while ((size = fread(buff, 1, sizeof (buff), fin)) > 0)
184         fwrite(buff, 1, size, fout);
185 }
186
187 /*---------------------------------------------------------------------------*/
188
189 int path_is_sep(int c)
190 {
191 #ifdef _WIN32
192     return c == '/' || c == '\\';
193 #else
194     return c == '/';
195 #endif
196 }
197
198 int path_is_abs(const char *path)
199 {
200     if (path_is_sep(path[0]))
201         return 1;
202
203 #ifdef _WIN32
204     if (isalpha(path[0]) && path[1] == ':' && path_is_sep(path[2]))
205         return 1;
206 #endif
207
208     return 0;
209 }
210
211 static const char *path_last_sep(const char *path)
212 {
213     const char *sep;
214
215     sep = strrchr(path, '/');
216
217 #ifdef _WIN32
218     if (!sep)
219     {
220         sep = strrchr(path, '\\');
221     }
222     else
223     {
224         const char *tmp;
225
226         if ((tmp = strrchr(sep, '\\')))
227             sep = tmp;
228     }
229 #endif
230
231     return sep;
232 }
233
234 const char *base_name_sans(const char *name, const char *suffix)
235 {
236     static char base[MAXSTR];
237     size_t blen, slen;
238
239     if (!name)
240         return NULL;
241     if (!suffix)
242         return base_name(name);
243
244     /* Remove the directory part. */
245
246     strncpy(base, base_name(name), sizeof (base) - 1);
247
248     /* Remove the suffix. */
249
250     blen = strlen(base);
251     slen = strlen(suffix);
252
253     if (blen >= slen && strcmp(base + blen - slen, suffix) == 0)
254         base[blen - slen] = '\0';
255
256     return base;
257 }
258
259 const char *base_name(const char *name)
260 {
261     const char *sep;
262     return (name && (sep = path_last_sep(name))) ? sep + 1 : name;
263 }
264
265 const char *dir_name(const char *name)
266 {
267     static char buff[MAXSTR];
268
269     char *sep;
270
271     strncpy(buff, name, sizeof (buff) - 1);
272
273     if ((sep = (char *) path_last_sep(buff)))
274     {
275         if (sep == buff)
276             return "/";
277
278         *sep = '\0';
279
280         return buff;
281     }
282
283     return ".";
284 }
285
286 /*
287  * Given a path to a file REF and another path REL relative to REF,
288  * construct and return a new path that can be used to refer to REL
289  * directly.
290  */
291 char *path_resolve(const char *ref, const char *rel)
292 {
293     static char new[MAXSTR * 2];
294
295     if (path_is_abs(rel))
296     {
297         strncpy(new, rel, sizeof (new) - 1);
298         return new;
299     }
300
301     strncpy(new, dir_name(ref), sizeof (new) - 1);
302     strncat(new, "/",           sizeof (new) - strlen(new) - 1);
303     strncat(new, rel,           sizeof (new) - strlen(new) - 1);
304
305     return new;
306 }
307
308 /*---------------------------------------------------------------------------*/
309
310 int rand_between(int low, int high)
311 {
312     return low + rand() / (RAND_MAX / (high - low + 1) + 1);
313 }
314
315 /*---------------------------------------------------------------------------*/