Use regex.[ch] from msysGit's /git
[cvsps/4msysgit.git] / util.c
blob44e384db6923c4ad83f44f0f62ff69bf743fde43
1 /*
2 * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc.
3 * See COPYING file for license information
4 */
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <limits.h>
11 #include <assert.h>
12 #ifdef __MINGW32__
13 #include <tsearch/search.h>
14 #include <windows.h>
15 int setenv(const char *name, const char *value, int overwrite);
16 void unsetenv(const char *name);
17 #else
18 #include <search.h>
19 #endif
20 #include <time.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <regex.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #ifndef __MINGW32__
28 #include <sys/wait.h>
29 #endif
31 #include <cbtcommon/debug.h>
33 #include "util.h"
35 typedef int (*compare_func)(const void *, const void *);
37 static void * string_tree;
38 char *readfile(char const *filename, char *buf, size_t size)
40 FILE *fp;
41 char *ptr;
42 size_t len;
44 fp = fopen(filename, "r");
45 if (!fp)
46 return NULL;
48 ptr = fgets(buf, size, fp);
49 fclose(fp);
51 if (!ptr)
52 return NULL;
54 len = strlen(buf);
55 if (buf[len-1] == '\n')
56 buf[len-1] = '\0';
58 return buf;
61 char *strrep(char *s, char find, char replace)
63 char * p = s;
64 while (*p)
66 if (*p == find)
67 *p = replace;
68 p++;
71 return s;
74 char *get_cvsps_dir()
76 struct stat sbuf;
77 static char prefix[PATH_MAX];
78 const char * home;
79 const char * home_env;
81 if (prefix[0])
82 return prefix;
84 #ifdef __MINGW32__
85 home_env = "APPDATA"; /* application data is below user's home dir */
86 #else
87 home_env = "HOME";
88 #endif
90 if (!(home = getenv(home_env)))
92 debug(DEBUG_APPERROR, "%s environment variable not set", home_env);
93 exit(1);
96 if (snprintf(prefix, PATH_MAX, "%s/%s", home, CVSPS_PREFIX) >= PATH_MAX)
98 debug(DEBUG_APPERROR, "prefix buffer overflow");
99 exit(1);
102 /* Make sure the prefix directory exists */
103 if (stat(prefix, &sbuf) < 0)
105 int ret;
106 #ifdef __MINGW32__
107 ret = mkdir(prefix);
108 #else
109 ret = mkdir(prefix, 0777);
110 #endif
111 if (ret < 0)
113 debug(DEBUG_SYSERROR, "Cannot create the cvsps directory '%s'", CVSPS_PREFIX);
114 exit(1);
117 else
119 if (!(S_ISDIR(sbuf.st_mode)))
120 debug(DEBUG_APPERROR, "cvsps directory '%s' is not a directory!", CVSPS_PREFIX);
123 return prefix;
126 char *xstrdup(char const *str)
128 char *ret;
129 assert(str);
130 ret = strdup(str);
131 if (!ret)
133 debug(DEBUG_ERROR, "strdup failed");
134 exit(1);
137 return ret;
140 void strzncpy(char * dst, const char * src, int n)
142 strncpy(dst, src, n);
143 dst[n - 1] = 0;
146 char *get_string(char const *str)
148 char ** res;
150 if (!str)
151 return NULL;
153 res = (char **)tfind(str, &string_tree, (compare_func)strcmp);
154 if (!res)
156 char *key = xstrdup(str);
157 res = (char **)tsearch(key, &string_tree, (compare_func)strcmp);
158 *res = key;
161 return *res;
164 static int get_int_substr(const char * str, const regmatch_t * p)
166 char buff[256];
167 memcpy(buff, str + p->rm_so, p->rm_eo - p->rm_so);
168 buff[p->rm_eo - p->rm_so] = 0;
169 return atoi(buff);
172 static time_t mktime_utc(struct tm * tm)
174 char * old_tz = getenv("TZ");
175 time_t ret;
177 setenv("TZ", "UTC", 1);
179 tzset();
181 ret = mktime(tm);
183 if (old_tz)
184 setenv("TZ", old_tz, 1);
185 else
186 unsetenv("TZ");
188 tzset();
190 return ret;
193 void convert_date(time_t * t, const char * dte)
195 static regex_t date_re;
196 static int init_re;
198 #define MAX_MATCH 16
199 size_t nmatch = MAX_MATCH;
200 regmatch_t match[MAX_MATCH];
202 if (!init_re)
204 if (regcomp(&date_re, "([0-9]{4})[-/]([0-9]{2})[-/]([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})", REG_EXTENDED))
206 fprintf(stderr, "FATAL: date regex compilation error\n");
207 exit(1);
209 init_re = 1;
212 if (regexec(&date_re, dte, nmatch, match, 0) == 0)
214 regmatch_t * pm = match;
215 struct tm tm = {0};
217 /* first regmatch_t is match location of entire re */
218 pm++;
220 tm.tm_year = get_int_substr(dte, pm++);
221 tm.tm_mon = get_int_substr(dte, pm++);
222 tm.tm_mday = get_int_substr(dte, pm++);
223 tm.tm_hour = get_int_substr(dte, pm++);
224 tm.tm_min = get_int_substr(dte, pm++);
225 tm.tm_sec = get_int_substr(dte, pm++);
227 tm.tm_year -= 1900;
228 tm.tm_mon--;
230 *t = mktime_utc(&tm);
232 else
234 *t = atoi(dte);
238 static struct timeval start_time;
240 void timing_start()
242 gettimeofday(&start_time, NULL);
245 void timing_stop(const char * msg)
247 struct timeval stop_time;
248 gettimeofday(&stop_time, NULL);
249 stop_time.tv_sec -= start_time.tv_sec;
250 stop_time.tv_usec -= start_time.tv_usec;
251 if (stop_time.tv_usec < 0)
252 stop_time.tv_sec--,stop_time.tv_usec += 1000000;
254 printf("Elapsed time for %s: %d.%06d\n", msg, (int)stop_time.tv_sec, (int)stop_time.tv_usec);
257 extern char ** environ;
259 /* taken from the linux manual page for system
260 See http://linux.die.net/man/3/system
262 int my_system (const char *command)
264 #ifdef __MINGW32__
265 /* Launch child process */
266 STARTUPINFO si;
267 ZeroMemory( &si, sizeof( si ) );
268 si.cb = sizeof( si );
269 PROCESS_INFORMATION pi;
270 ZeroMemory( &pi, sizeof( pi ) );
271 if( !CreateProcess(
272 0, /* module name (0 means use first token in command line) */
273 (char*)command, /* command line */
274 0, /* process security attributes */
275 0, /* primary thread security attributes */
276 TRUE, /* handles are inherited */
277 0, /* creation flags (none) */
278 0, /* use parent's environment */
279 0, /* use parent's current directory */
280 &si, /* STARTUPINFO pointer */
281 &pi /* receives PROCESS_INFORMATION */
282 ) ) {
283 debug(DEBUG_APPERROR, "CreateProcess failed.\n command line was: %s", command);
284 return -1;
287 /* Wait for child process to exit */
288 DWORD timeout = 10*1000; /* milliseconds */
289 DWORD ret = WaitForSingleObject( pi.hProcess, timeout );
290 if (ret == WAIT_OBJECT_0) {
291 /* OK. Child has exited */
293 else if (ret == WAIT_FAILED) {
294 DWORD last_err = GetLastError();
295 debug(DEBUG_APPERROR, "WaitForSingleObject failed.\n GetLastError returned : %d", last_err);
296 return -1;
298 else {
299 debug(DEBUG_APPERROR, "WaitForSingleObject returned %x", ret);
300 return -1;
303 /* Retrieve exit code */
304 DWORD exit_code;
305 if( !GetExitCodeProcess( pi.hProcess, &exit_code ) ) {
306 DWORD last_err = GetLastError();
307 debug(DEBUG_APPERROR, "GetExitCodeProcess failed.\n GetLastError returned : %d", last_err);
308 return -1;
311 return exit_code;
312 #else
313 int pid, status;
315 if (command == 0)
316 return 1;
317 pid = fork();
318 if (pid == -1)
319 return -1;
320 if (pid == 0) {
321 char *argv[4];
322 argv[0] = "sh";
323 argv[1] = "-c";
324 argv[2] = (char*)command; /* discard const */
325 argv[3] = 0;
326 execve("/bin/sh", argv, environ);
327 exit(127);
329 do {
330 if (waitpid(pid, &status, 0) == -1) {
331 if (errno != EINTR)
332 return -1;
333 } else
334 return status;
335 } while(1);
336 #endif
339 int escape_filename(char * dst, int len, const char * src)
341 static char * naughty_chars = " \\\"'@<>=;|&()#$`?*[!:{";
343 if (len > 0)
345 while (len > 1 && *src)
347 if (strchr(naughty_chars, *src))
349 if (len == 2)
350 break;
351 *dst++ = '\\';
352 len--;
355 *dst++ = *src++;
356 len--;
359 *dst = 0;
362 return (*src == 0) ? 0 : -1;