2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
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
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
28 #ifdef _POSIX_C_SOURCE
30 #include <sys/types.h>
41 strtoupper(char *dest, const char *src)
44 *dest++=toupper(*src++);
49 strtolower(char *dest, const char *src)
52 *dest++=tolower(*src++);
58 hash_callback(gpointer key, gpointer value, gpointer user_data)
61 *l=g_list_prepend(*l, value);
65 g_hash_to_list(GHashTable *h)
68 g_hash_table_foreach(h, hash_callback, &ret);
74 hash_callback_key(gpointer key, gpointer value, gpointer user_data)
77 *l=g_list_prepend(*l, key);
81 g_hash_to_list_keys(GHashTable *h)
84 g_hash_table_foreach(h, hash_callback_key, &ret);
90 g_strconcat_printf(gchar *buffer, gchar *fmt, ...)
96 str=g_strdup_vprintf(fmt, ap);
100 ret=g_strconcat(buffer, str, NULL);
107 int g_utf8_strlen_force_link(gchar *buffer, int max);
109 g_utf8_strlen_force_link(gchar *buffer, int max)
111 return g_utf8_strlen(buffer, max);
115 #if defined(_WIN32) || defined(__CEGCC__)
117 #include <sys/types.h>
120 #if defined(_WIN32) || defined(__CEGCC__) || defined (__APPLE__) || defined(HAVE_API_ANDROID)
122 char *stristr(const char *String, const char *Pattern)
124 char *pptr, *sptr, *start;
126 for (start = (char *)String; *start != (int)NULL; start++)
128 /* find start of pattern in string */
129 for ( ; ((*start!=(int)NULL) && (toupper(*start) != toupper(*Pattern))); start++)
131 if ((int)NULL == *start)
134 pptr = (char *)Pattern;
135 sptr = (char *)start;
137 while (toupper(*sptr) == toupper(*pptr))
142 /* if end of pattern then pattern was found */
144 if ((int)NULL == *pptr)
152 # define SIZE_MAX ((size_t) -1)
155 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
159 # define flockfile(x) ((void) 0)
161 #if !HAVE_FUNLOCKFILE
163 # define funlockfile(x) ((void) 0)
166 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
168 # define EOVERFLOW E2BIG
172 #ifndef HAVE_GETDELIM
174 * Read the part of a file up to a delimiter to a string.
176 * Read up to (and including) a DELIMITER from FP into *LINEPTR (and
178 * @param lineptr Pointer to a pointer returned from malloc (or
179 NULL), pointing to a buffer. It is realloc'ed as
180 necessary and will receive the data read.
181 * @param n Size of the buffer.
183 * @return Number of characters read (not including
184 the null terminator), or -1 on error or EOF.
187 getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
192 if (lineptr == NULL || n == NULL || fp == NULL)
199 if (*lineptr == NULL || *n == 0)
202 *lineptr = (char *) realloc (*lineptr, *n);
203 if (*lineptr == NULL)
221 /* Make enough space for len+1 (for final NUL) bytes. */
222 if (cur_len + 1 >= *n)
224 size_t needed_max=SIZE_MAX;
225 size_t needed = 2 * *n + 1; /* Be generous. */
227 if (needed_max < needed)
229 if (cur_len + 1 >= needed)
235 new_lineptr = (char *) realloc (*lineptr, needed);
236 if (new_lineptr == NULL)
242 *lineptr = new_lineptr;
246 (*lineptr)[cur_len] = i;
252 (*lineptr)[cur_len] = '\0';
253 result = cur_len ? cur_len : result;
256 funlockfile (fp); /* doesn't set errno */
264 getline (char **lineptr, size_t *n, FILE *stream)
266 return getdelim (lineptr, n, '\n', stream);
270 #if defined(_UNICODE)
271 wchar_t* newSysString(const char *toconvert)
273 int newstrlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, 0, 0);
274 wchar_t *newstring = g_new(wchar_t,newstrlen);
275 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, newstring, newstrlen) ;
279 char * newSysString(const char *toconvert)
281 return g_strdup(toconvert);
286 #if defined(_MSC_VER) || (!defined(HAVE_GETTIMEOFDAY) && defined(HAVE_API_WIN32_BASE))
288 * Impements a simple incomplete version of gettimeofday. Only usefull for messuring
289 * time spans, not the real time of day.
291 int gettimeofday(struct timeval *time, void *local)
293 int milliseconds = GetTickCount();
295 time->tv_sec = milliseconds/1000;
296 time->tv_usec = (milliseconds - (time->tv_sec * 1000)) * 1000;
302 * Convert an ISO 8601-style time string into epoch time.
304 * @param iso8601 Pointer to a string containing the time in ISO 8601 format.
306 * @return An unsigned integer representing the number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
309 iso8601_to_secs(char *iso8601)
311 int a,b,d,val[6],i=0;
312 char *start=iso8601,*pos=iso8601;
313 while (*pos && i < 6) {
314 if (*pos < '0' || *pos > '9') {
315 val[i++]=atoi(start);
331 d=1461*(val[0]+4716)/4+306001*(val[1]+1)/10000+val[2]+b-2442112;
333 return ((d*24+val[3])*60+val[4])*60+val[5];
337 * Output local system time in ISO 8601 format.
339 * @return Pointer to a string containing the time in ISO 8601 format
342 current_to_iso8601(void)
345 #ifdef HAVE_API_WIN32_BASE
348 timep=g_strdup_printf("%d-%02d-%02dT%02d:%02d:%02dZ",ST.wYear,ST.wMonth,ST.wDay,ST.wHour,ST.wMinute,ST.wSecond);
356 strftime(buffer, sizeof(buffer), "%Y-%m-%dT%TZ", tm);
357 timep=g_strdup(buffer);
364 struct spawn_process_info {
365 #ifdef HAVE_API_WIN32_BASE
366 PROCESS_INFORMATION pr;
368 pid_t pid; // = -1 if non-blocking spawn isn't supported
369 int status; // exit status if non-blocking spawn isn't supported
375 * Escape and quote string for shell
377 * @param in arg string to escape
378 * @returns escaped string
381 shell_escape(char *arg)
384 int arglen=strlen(arg);
386 #ifdef HAVE_API_WIN32_BASE
392 for(i=0,j=1;i<arglen;i++) {
396 // Most special case - last char is
397 // backslash. We can't escape it inside
398 // quoted string due to Win unescaping
399 // rules so quote should be closed
400 // before backslashes and these
401 // backslashes shouldn't be doubled
405 memset(r+j,'\\',bscount);
409 //Any preceeding backslashes will be doubled.
411 // Double quote needs to be preceeded by
412 // at least one backslash
418 memset(r+j,'\\',bscount);
432 // Will use hard quoting for the whole string
433 // and replace each singular quote found with a '\'' sequence.
437 for(i=0,j=1;i<arglen;i++) {
441 g_strlcpy(r+j,"'\\''",rlen-j);
453 #ifndef _POSIX_C_SOURCE
455 spawn_process_compose_cmdline(char **argv)
458 char *cmdline=shell_escape(argv[0]);
459 for(i=1,j=strlen(cmdline);argv[i];i++) {
460 char *arg=shell_escape(argv[i]);
461 int arglen=strlen(arg);
463 cmdline=g_realloc(cmdline,j+1+arglen+1);
464 memcpy(cmdline+j+1,arg,arglen+1);
472 #ifdef _POSIX_C_SOURCE
474 #if 0 /* def _POSIX_THREADS */
475 #define spawn_process_sigmask(how,set,old) pthread_sigmask(how,set,old)
477 #define spawn_process_sigmask(how,set,old) sigprocmask(how,set,old)
480 GList *spawn_process_children=NULL;
486 * Call external program
488 * @param in argv NULL terminated list of parameters,
489 * zeroeth argument is program name
490 * @returns 0 - success, >0 - return code, -1 - error
492 struct spawn_process_info*
493 spawn_process(char **argv)
495 struct spawn_process_info*r=g_new(struct spawn_process_info,1);
496 #ifdef _POSIX_C_SOURCE
502 sigaddset(&set,SIGCHLD);
503 spawn_process_sigmask(SIG_BLOCK,&set,&old);
506 execvp(argv[0], argv);
507 /*Shouldn't reach here*/
512 spawn_process_children=g_list_prepend(spawn_process_children,r);
514 dbg(0,"fork() returned error.");
518 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
522 #ifdef HAVE_API_WIN32_BASE
527 // For [desktop] Windows it's adviceable not to use
528 // first CreateProcess parameter because PATH is not used
531 // On WinCE 6.0 I was unable to launch anything
532 // without first CreateProcess parameter, also it seems that
533 // no WinCE program has support for quoted strings in arguments.
535 #ifdef HAVE_API_WIN32_CE
537 cmdline=g_strjoinv(" ",argv+1);
538 args=newSysString(cmdline);
539 cmd = newSysString(argv[0]);
540 dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr));
541 dbg(0, "CreateProcess(%s,%s), PID=%i\n",argv[0],cmdline,r->pr.dwProcessId);
545 STARTUPINFO startupInfo;
546 memset(&startupInfo, 0, sizeof(startupInfo));
547 startupInfo.cb = sizeof(startupInfo);
548 cmdline=spawn_process_compose_cmdline(argv);
549 args=newSysString(cmdline);
550 dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &(r->pr));
551 dbg(0, "CreateProcess(%s), PID=%i\n",cmdline,r->pr.dwProcessId);
559 char *cmdline=spawn_process_compose_cmdline(argv);
561 dbg(0,"Unblocked spawn_process isn't availiable on this platform.\n");
562 status=system(cmdline);
573 * Check external program status
575 * @param in *pi pointer to spawn_process_info structure
576 * @param in block =0 do not block =1 block until child terminated
577 * @returns -1 - still running, >=0 program exited,
578 * =255 trminated abnormally or wasn't run at all.
581 int spawn_process_check_status(struct spawn_process_info *pi, int block)
584 dbg(0,"Trying to get process status of NULL, assuming process is terminated.\n");
587 #ifdef HAVE_API_WIN32_BASE
591 if(GetExitCodeProcess(pi->pr.hProcess,&dw)) {
592 if(dw!=STILL_ACTIVE) {
597 dbg(0,"GetExitCodeProcess failed. Assuming the process is terminated.");
603 dw=WaitForSingleObject(pi->pr.hProcess,INFINITE);
604 if(dw==WAIT_FAILED && failcount++==1) {
605 dbg(0,"WaitForSingleObject failed twice. Assuming the process is terminated.");
612 #ifdef _POSIX_C_SOURCE
618 pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG);
620 if(WIFEXITED(status))
621 pi->status=WEXITSTATUS(status);
623 if(WIFSTOPPED(status)) {
624 dbg(0,"child is stopped by %i signal\n",WSTOPSIG(status));
625 } else if (WIFSIGNALED(status)) {
626 dbg(0,"child terminated by signal %i\n",WEXITSTATUS(status));
636 if(pi->status!=-1) // Signal handler has changed pi->status while in this function
638 dbg(0,"waitpid() indicated error, reporting process termination.\n");
643 dbg(0, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.\n");
649 void spawn_process_info_free(struct spawn_process_info *pi)
653 #ifdef HAVE_API_WIN32_BASE
654 CloseHandle(pi->pr.hProcess);
655 CloseHandle(pi->pr.hThread);
657 #ifdef _POSIX_C_SOURCE
661 sigaddset(&set,SIGCHLD);
662 spawn_process_sigmask(SIG_BLOCK,&set,&old);
663 spawn_process_children=g_list_remove(spawn_process_children,pi);
664 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
670 #ifdef _POSIX_C_SOURCE
671 static void spawn_process_sigchld(int sig)
675 while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
676 GList *el=g_list_first(spawn_process_children);
678 struct spawn_process_info *p=el->data;
688 void spawn_process_init()
690 #ifdef _POSIX_C_SOURCE
691 struct sigaction act;
692 act.sa_handler=spawn_process_sigchld;
694 sigemptyset(&act.sa_mask);
695 sigaction(SIGCHLD, &act, NULL);