share/common: add function to obtain random numbers in a range
[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 <errno.h>
24 #include <time.h>
25 #include <ctype.h>
26
27 #include "common.h"
28
29 #define MAXSTR 256
30
31 /*---------------------------------------------------------------------------*/
32
33 int read_line(char **dst, FILE *fin)
34 {
35     char buffer[MAXSTR] = "";
36     int  buffer_size    = 0;
37
38     char *store      = NULL;
39     char *store_new  = NULL;
40     int   store_size = 0;
41
42     int seen_newline = 0;
43
44     while (!seen_newline)
45     {
46         if (fgets(buffer, sizeof (buffer), fin) == NULL)
47         {
48             if (store_size > 0)
49                 break;
50             else
51             {
52                 *dst = NULL;
53                 return 0;
54             }
55         }
56
57         buffer_size = strlen(buffer) + 1;
58
59         /* Erase trailing newline. */
60
61         if (buffer[buffer_size - 2] == '\n')
62         {
63             seen_newline = 1;
64             buffer[buffer_size - 2] = '\0';
65             buffer_size--;
66         }
67
68         /* Allocate or reallocate space for the buffer. */
69
70         if ((store_new = (char *) realloc(store, store_size + buffer_size)))
71         {
72             /* Avoid passing garbage to string functions. */
73
74             if (store == NULL)
75                 store_new[0] = '\0';
76
77             store       = store_new;
78             store_size += buffer_size;
79
80             store_new = NULL;
81         }
82         else
83         {
84             fprintf(stderr, "Failed to allocate memory.\n");
85
86             free(store);
87             *dst = NULL;
88             return 0;
89         }
90
91         strncat(store, buffer, buffer_size);
92     }
93
94     *dst = store;
95
96     return 1;
97 }
98
99 char *strip_newline(char *str)
100 {
101     char *c = str + strlen(str) - 1;
102
103     while (c >= str && (*c == '\n' || *c =='\r'))
104         *c-- = '\0';
105
106     return str;
107 }
108
109 char *dupe_string(const char *src)
110 {
111     char *dst = NULL;
112
113     if (src && (dst = malloc(strlen(src) + 1)))
114         strcpy(dst, src);
115
116     return dst;
117 }
118
119 time_t make_time_from_utc(struct tm *tm)
120 {
121     struct tm local, *utc;
122     time_t t;
123
124     t = mktime(tm);
125
126     local = *localtime(&t);
127     utc   =  gmtime(&t);
128
129     local.tm_year += local.tm_year - utc->tm_year;
130     local.tm_mon  += local.tm_mon  - utc->tm_mon ;
131     local.tm_mday += local.tm_mday - utc->tm_mday;
132     local.tm_hour += local.tm_hour - utc->tm_hour;
133     local.tm_min  += local.tm_min  - utc->tm_min ;
134     local.tm_sec  += local.tm_sec  - utc->tm_sec ;
135
136     return mktime(&local);
137 }
138
139 const char *date_to_str(time_t i)
140 {
141     static char str[sizeof ("YYYY-mm-dd HH:MM:SS")];
142     strftime(str, sizeof (str), "%Y-%m-%d %H:%M:%S", localtime(&i));
143     return str;
144 }
145
146 int file_exists(const char *name)
147 {
148     FILE *fp;
149
150     if ((fp = fopen(name, "r")))
151     {
152         fclose(fp);
153         return 1;
154     }
155     return 0;
156 }
157
158 int file_rename(const char *src, const char *dst)
159 {
160 #ifdef _WIN32
161     if (file_exists(dst))
162         remove(dst);
163 #endif
164     return rename(src, dst);
165 }
166
167 void file_copy(FILE *fin, FILE *fout)
168 {
169     char   buff[MAXSTR];
170     size_t size;
171
172     while ((size = fread(buff, 1, sizeof (buff), fin)) > 0)
173         fwrite(buff, 1, size, fout);
174 }
175
176 /*---------------------------------------------------------------------------*/
177
178 int path_is_sep(int c)
179 {
180 #ifdef _WIN32
181     return c == '/' || c == '\\';
182 #else
183     return c == '/';
184 #endif
185 }
186
187 int path_is_abs(const char *path)
188 {
189     if (path_is_sep(path[0]))
190         return 1;
191
192 #ifdef _WIN32
193     if (isalpha(path[0]) && path[1] == ':' && path_is_sep(path[2]))
194         return 1;
195 #endif
196
197     return 0;
198 }
199
200 static char *path_last_sep(const char *path)
201 {
202     char *sep;
203
204     sep = strrchr(path, '/');
205
206 #ifdef _WIN32
207     if (!sep)
208     {
209         sep = strrchr(path, '\\');
210     }
211     else
212     {
213         char *tmp;
214
215         if ((tmp = strrchr(sep, '\\')))
216             sep = tmp;
217     }
218 #endif
219
220     return sep;
221 }
222
223 char *base_name(const char *name, const char *suffix)
224 {
225     static char buf[MAXSTR];
226     char *base;
227
228     if (!name)
229         return NULL;
230
231     /* Remove the directory part. */
232
233     base = path_last_sep(name);
234
235     strncpy(buf, base ? base + 1 : name, sizeof (buf));
236
237     /* Remove the suffix. */
238
239     if (suffix)
240     {
241         int l = strlen(buf) - strlen(suffix);
242
243         if (l >= 0 && strcmp(buf + l, suffix) == 0)
244             buf[l] = '\0';
245     }
246
247     return buf;
248 }
249
250 const char *dir_name(const char *name)
251 {
252     static char buff[MAXSTR];
253
254     char *sep;
255
256     strncpy(buff, name, sizeof (buff) - 1);
257
258     if ((sep = path_last_sep(buff)))
259     {
260         if (sep == buff)
261             return "/";
262
263         *sep = '\0';
264
265         return buff;
266     }
267
268     return ".";
269 }
270
271 /*
272  * Given a path to a file REF and another path REL relative to REF,
273  * construct and return a new path that can be used to refer to REL
274  * directly.
275  */
276 char *path_resolve(const char *ref, const char *rel)
277 {
278     static char new[MAXSTR * 2];
279
280     if (path_is_abs(rel))
281     {
282         strncpy(new, rel, sizeof (new) - 1);
283         return new;
284     }
285
286     strncpy(new, dir_name(ref), sizeof (new) - 1);
287     strncat(new, "/",           sizeof (new) - strlen(new) - 1);
288     strncat(new, rel,           sizeof (new) - strlen(new) - 1);
289
290     return new;
291 }
292
293 /*---------------------------------------------------------------------------*/
294
295 int rand_between(int low, int high)
296 {
297     return low + rand() / (RAND_MAX / (high - low + 1) + 1);
298 }
299
300 /*---------------------------------------------------------------------------*/