/[zanavi_public1]/navit/navit/util.c
ZANavi

Contents of /navit/navit/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (8 years, 2 months ago) by zoff99
File MIME type: text/plain
File size: 15118 byte(s)
import files
1 /**
2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
4 *
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.
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
12 * GNU 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
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <time.h>
25 #include <limits.h>
26 #include <string.h>
27
28 #ifdef _POSIX_C_SOURCE
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #endif
33 #include "util.h"
34 #include "debug.h"
35
36 void
37 strtoupper(char *dest, const char *src)
38 {
39 while (*src)
40 *dest++=toupper(*src++);
41 *dest='\0';
42 }
43
44 void
45 strtolower(char *dest, const char *src)
46 {
47 while (*src)
48 *dest++=tolower(*src++);
49 *dest='\0';
50 }
51
52
53 static void
54 hash_callback(gpointer key, gpointer value, gpointer user_data)
55 {
56 GList **l=user_data;
57 *l=g_list_prepend(*l, value);
58 }
59
60 GList *
61 g_hash_to_list(GHashTable *h)
62 {
63 GList *ret=NULL;
64 g_hash_table_foreach(h, hash_callback, &ret);
65
66 return ret;
67 }
68
69 static void
70 hash_callback_key(gpointer key, gpointer value, gpointer user_data)
71 {
72 GList **l=user_data;
73 *l=g_list_prepend(*l, key);
74 }
75
76 GList *
77 g_hash_to_list_keys(GHashTable *h)
78 {
79 GList *ret=NULL;
80 g_hash_table_foreach(h, hash_callback_key, &ret);
81
82 return ret;
83 }
84
85 gchar *
86 g_strconcat_printf(gchar *buffer, gchar *fmt, ...)
87 {
88 gchar *str,*ret;
89 va_list ap;
90
91 va_start(ap, fmt);
92 str=g_strdup_vprintf(fmt, ap);
93 va_end(ap);
94 if (! buffer)
95 return str;
96 ret=g_strconcat(buffer, str, NULL);
97 g_free(buffer);
98 g_free(str);
99 return ret;
100 }
101
102 #ifndef HAVE_GLIB
103 int g_utf8_strlen_force_link(gchar *buffer, int max);
104 int
105 g_utf8_strlen_force_link(gchar *buffer, int max)
106 {
107 return g_utf8_strlen(buffer, max);
108 }
109 #endif
110
111 #if defined(_WIN32) || defined(__CEGCC__)
112 #include <windows.h>
113 #include <sys/types.h>
114 #endif
115
116 #if defined(_WIN32) || defined(__CEGCC__) || defined (__APPLE__) || defined(HAVE_API_ANDROID)
117 #include <stdio.h>
118 char *stristr(const char *String, const char *Pattern)
119 {
120 char *pptr, *sptr, *start;
121
122 for (start = (char *)String; *start != (int)NULL; start++)
123 {
124 /* find start of pattern in string */
125 for ( ; ((*start!=(int)NULL) && (toupper(*start) != toupper(*Pattern))); start++)
126 ;
127 if ((int)NULL == *start)
128 return NULL;
129
130 pptr = (char *)Pattern;
131 sptr = (char *)start;
132
133 while (toupper(*sptr) == toupper(*pptr))
134 {
135 sptr++;
136 pptr++;
137
138 /* if end of pattern then pattern was found */
139
140 if ((int)NULL == *pptr)
141 return (start);
142 }
143 }
144 return NULL;
145 }
146
147 #ifndef SIZE_MAX
148 # define SIZE_MAX ((size_t) -1)
149 #endif
150 #ifndef SSIZE_MAX
151 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
152 #endif
153 #if !HAVE_FLOCKFILE
154 # undef flockfile
155 # define flockfile(x) ((void) 0)
156 #endif
157 #if !HAVE_FUNLOCKFILE
158 # undef funlockfile
159 # define funlockfile(x) ((void) 0)
160 #endif
161
162 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
163 #ifndef EOVERFLOW
164 # define EOVERFLOW E2BIG
165 #endif
166
167
168 /**
169 * Read the part of a file up to a delimiter to a string.
170 * <p>
171 * Read up to (and including) a DELIMITER from FP into *LINEPTR (and
172 NUL-terminate it).
173 * @param lineptr Pointer to a pointer returned from malloc (or
174 NULL), pointing to a buffer. It is realloc'ed as
175 necessary and will receive the data read.
176 * @param n Size of the buffer.
177 *
178 * @return Number of characters read (not including
179 the null terminator), or -1 on error or EOF.
180 */
181 int
182 getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
183 {
184 int result;
185 size_t cur_len = 0;
186
187 if (lineptr == NULL || n == NULL || fp == NULL)
188 {
189 return -1;
190 }
191
192 flockfile (fp);
193
194 if (*lineptr == NULL || *n == 0)
195 {
196 *n = 120;
197 *lineptr = (char *) realloc (*lineptr, *n);
198 if (*lineptr == NULL)
199 {
200 result = -1;
201 goto unlock_return;
202 }
203 }
204
205 for (;;)
206 {
207 int i;
208
209 i = getc (fp);
210 if (i == EOF)
211 {
212 result = -1;
213 break;
214 }
215
216 /* Make enough space for len+1 (for final NUL) bytes. */
217 if (cur_len + 1 >= *n)
218 {
219 size_t needed_max=SIZE_MAX;
220 size_t needed = 2 * *n + 1; /* Be generous. */
221 char *new_lineptr;
222 if (needed_max < needed)
223 needed = needed_max;
224 if (cur_len + 1 >= needed)
225 {
226 result = -1;
227 goto unlock_return;
228 }
229
230 new_lineptr = (char *) realloc (*lineptr, needed);
231 if (new_lineptr == NULL)
232 {
233 result = -1;
234 goto unlock_return;
235 }
236
237 *lineptr = new_lineptr;
238 *n = needed;
239 }
240
241 (*lineptr)[cur_len] = i;
242 cur_len++;
243
244 if (i == delimiter)
245 break;
246 }
247 (*lineptr)[cur_len] = '\0';
248 result = cur_len ? cur_len : result;
249
250 unlock_return:
251 funlockfile (fp); /* doesn't set errno */
252
253 return result;
254 }
255
256 int
257 getline (char **lineptr, size_t *n, FILE *stream)
258 {
259 return getdelim (lineptr, n, '\n', stream);
260 }
261
262 #if defined(_UNICODE)
263 wchar_t* newSysString(const char *toconvert)
264 {
265 int newstrlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, 0, 0);
266 wchar_t *newstring = g_new(wchar_t,newstrlen);
267 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, newstring, newstrlen) ;
268 return newstring;
269 }
270 #else
271 char * newSysString(const char *toconvert)
272 {
273 return g_strdup(toconvert);
274 }
275 #endif
276 #endif
277
278 #if defined(_MSC_VER) || (!defined(HAVE_GETTIMEOFDAY) && defined(HAVE_API_WIN32_BASE))
279 /**
280 * Impements a simple incomplete version of gettimeofday. Only usefull for messuring
281 * time spans, not the real time of day.
282 */
283 int gettimeofday(struct timeval *time, void *local)
284 {
285 int milliseconds = GetTickCount();
286
287 time->tv_sec = milliseconds/1000;
288 time->tv_usec = (milliseconds - (time->tv_sec * 1000)) * 1000;
289
290 return 0;
291 }
292 #endif
293 /**
294 * Convert an ISO 8601-style time string into epoch time.
295 *
296 * @param iso8601 Pointer to a string containing the time in ISO 8601 format.
297 *
298 * @return An unsigned integer representing the number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
299 */
300 unsigned int
301 iso8601_to_secs(char *iso8601)
302 {
303 int a,b,d,val[6],i=0;
304 char *start=iso8601,*pos=iso8601;
305 while (*pos && i < 6) {
306 if (*pos < '0' || *pos > '9') {
307 val[i++]=atoi(start);
308 pos++;
309 start=pos;
310 }
311 pos++;
312 }
313
314 a=val[0]/100;
315 b=2-a+a/4;
316
317 if (val[1] < 2) {
318 val[0]--;
319 val[1]+=12;
320 }
321
322 d=1461*(val[0]+4716)/4+306001*(val[1]+1)/10000+val[2]+b-2442112;
323
324 return ((d*24+val[3])*60+val[4])*60+val[5];
325 }
326
327 /**
328 * Output local system time in ISO 8601 format.
329 *
330 * @return Pointer to a string containing the time in ISO 8601 format
331 */
332 char *
333 current_to_iso8601(void)
334 {
335 char *timep=NULL;
336 #ifdef HAVE_API_WIN32_BASE
337 SYSTEMTIME ST;
338 GetSystemTime(&ST);
339 timep=g_strdup_printf("%d-%02d-%02dT%02d:%02d:%02dZ",ST.wYear,ST.wMonth,ST.wDay,ST.wHour,ST.wMinute,ST.wSecond);
340 #else
341 char buffer[32];
342 time_t tnow;
343 struct tm *tm;
344 tnow = time(0);
345 tm = gmtime(&tnow);
346 if (tm) {
347 strftime(buffer, sizeof(buffer), "%Y-%m-%dT%TZ", tm);
348 timep=g_strdup(buffer);
349 }
350 #endif
351 return timep;
352 }
353
354
355 struct spawn_process_info {
356 #ifdef HAVE_API_WIN32_BASE
357 PROCESS_INFORMATION pr;
358 #else
359 pid_t pid; // = -1 if non-blocking spawn isn't supported
360 int status; // exit status if non-blocking spawn isn't supported
361 #endif
362 };
363
364
365 /**
366 * Escape and quote string for shell
367 *
368 * @param in arg string to escape
369 * @returns escaped string
370 */
371 char *
372 shell_escape(char *arg)
373 {
374 char *r;
375 int arglen=strlen(arg);
376 int i,j,rlen;
377 #ifdef HAVE_API_WIN32_BASE
378 {
379 int bscount=0;
380 rlen=arglen+3;
381 r=g_new(char,rlen);
382 r[0]='"';
383 for(i=0,j=1;i<arglen;i++) {
384 if(arg[i]=='\\') {
385 bscount++;
386 if(i==(arglen-1)) {
387 // Most special case - last char is
388 // backslash. We can't escape it inside
389 // quoted string due to Win unescaping
390 // rules so quote should be closed
391 // before backslashes and these
392 // backslashes shouldn't be doubled
393 rlen+=bscount;
394 r=g_realloc(r,rlen);
395 r[j++]='"';
396 memset(r+j,'\\',bscount);
397 j+=bscount;
398 }
399 } else {
400 //Any preceeding backslashes will be doubled.
401 bscount*=2;
402 // Double quote needs to be preceeded by
403 // at least one backslash
404 if(arg[i]=='"')
405 bscount++;
406 if(bscount>0) {
407 rlen+=bscount;
408 r=g_realloc(r,rlen);
409 memset(r+j,'\\',bscount);
410 j+=bscount;
411 bscount=0;
412 }
413 r[j++]=arg[i];
414 if(i==(arglen-1)) {
415 r[j++]='"';
416 }
417 }
418 }
419 r[j++]=0;
420 }
421 #else
422 {
423 // Will use hard quoting for the whole string
424 // and replace each singular quote found with a '\'' sequence.
425 rlen=arglen+3;
426 r=g_new(char,rlen);
427 r[0]='\'';
428 for(i=0,j=1;i<arglen;i++) {
429 if(arg[i]=='\'') {
430 rlen+=3;
431 r=g_realloc(r,rlen);
432 g_strlcpy(r+j,"'\\''",rlen-j);
433 } else {
434 r[j++]=arg[i];
435 }
436 }
437 r[j++]='\'';
438 r[j++]=0;
439 }
440 #endif
441 return r;
442 }
443
444 #ifndef _POSIX_C_SOURCE
445 static char*
446 spawn_process_compose_cmdline(char **argv)
447 {
448 int i,j;
449 char *cmdline=shell_escape(argv[0]);
450 for(i=1,j=strlen(cmdline);argv[i];i++) {
451 char *arg=shell_escape(argv[i]);
452 int arglen=strlen(arg);
453 cmdline[j]=' ';
454 cmdline=g_realloc(cmdline,j+1+arglen+1);
455 memcpy(cmdline+j+1,arg,arglen+1);
456 g_free(arg);
457 j=j+1+arglen;
458 }
459 return cmdline;
460 }
461 #endif
462
463 #ifdef _POSIX_C_SOURCE
464
465 #if 0 /* def _POSIX_THREADS */
466 #define spawn_process_sigmask(how,set,old) pthread_sigmask(how,set,old)
467 #else
468 #define spawn_process_sigmask(how,set,old) sigprocmask(how,set,old)
469 #endif
470
471 GList *spawn_process_children=NULL;
472
473 #endif
474
475
476 /**
477 * Call external program
478 *
479 * @param in argv NULL terminated list of parameters,
480 * zeroeth argument is program name
481 * @returns 0 - success, >0 - return code, -1 - error
482 */
483 struct spawn_process_info*
484 spawn_process(char **argv)
485 {
486 struct spawn_process_info*r=g_new(struct spawn_process_info,1);
487 #ifdef _POSIX_C_SOURCE
488 {
489 pid_t pid;
490
491 sigset_t set, old;
492 sigemptyset(&set);
493 sigaddset(&set,SIGCHLD);
494 spawn_process_sigmask(SIG_BLOCK,&set,&old);
495 pid=fork();
496 if(pid==0) {
497 execvp(argv[0], argv);
498 /*Shouldn't reach here*/
499 exit(1);
500 } else if(pid>0) {
501 r->status=-1;
502 r->pid=pid;
503 spawn_process_children=g_list_prepend(spawn_process_children,r);
504 } else {
505 dbg(0,"fork() returned error.");
506 g_free(r);
507 r=NULL;
508 }
509 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
510 return r;
511 }
512 #else
513 #ifdef HAVE_API_WIN32_BASE
514 {
515 char *cmdline;
516 LPCWSTR cmd,args;
517 DWORD dwRet;
518
519 // For [desktop] Windows it's adviceable not to use
520 // first CreateProcess parameter because PATH is not used
521 // if it is defined.
522 //
523 // On WinCE 6.0 I was unable to launch anything
524 // without first CreateProcess parameter, also it seems that
525 // no WinCE program has support for quoted strings in arguments.
526 // So...
527 #ifdef HAVE_API_WIN32_CE
528 cmdline=g_strjoinv(" ",argv+1);
529 args=newSysString(cmdline);
530 cmd = newSysString(argv[0]);
531 dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr));
532 dbg(0, "CreateProcess(%s,%s), PID=%i\n",argv[0],cmdline,r->pr.dwProcessId);
533 g_free(cmd);
534 #else
535 STARTUPINFO startupInfo;
536 memset(&startupInfo, 0, sizeof(startupInfo));
537 startupInfo.cb = sizeof(startupInfo);
538 cmdline=spawn_process_compose_cmdline(argv);
539 args=newSysString(cmdline);
540 dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &(r->pr));
541 dbg(0, "CreateProcess(%s), PID=%i\n",cmdline,r->pr.dwProcessId);
542 #endif
543 g_free(cmdline);
544 g_free(args);
545 return r;
546 }
547 #else
548 {
549 char *cmdline=spawn_process_compose_cmdline(argv);
550 int status;
551 dbg(0,"Unblocked spawn_process isn't availiable on this platform.\n");
552 status=system(cmdline);
553 g_free(cmdline);
554 r->status=status;
555 r->pid=0;
556 return r;
557 }
558 #endif
559 #endif
560 }
561
562 /**
563 * Check external program status
564 *
565 * @param in *pi pointer to spawn_process_info structure
566 * @param in block =0 do not block =1 block until child terminated
567 * @returns -1 - still running, >=0 program exited,
568 * =255 trminated abnormally or wasn't run at all.
569 *
570 */
571 int spawn_process_check_status(struct spawn_process_info *pi, int block)
572 {
573 if(pi==NULL) {
574 dbg(0,"Trying to get process status of NULL, assuming process is terminated.\n");
575 return 255;
576 }
577 #ifdef HAVE_API_WIN32_BASE
578 {int failcount=0;
579 while(1){
580 DWORD dw;
581 if(GetExitCodeProcess(pi->pr.hProcess,&dw)) {
582 if(dw!=STILL_ACTIVE) {
583 return dw;
584 break;
585 }
586 } else {
587 dbg(0,"GetExitCodeProcess failed. Assuming the process is terminated.");
588 return 255;
589 }
590 if(!block)
591 return -1;
592
593 dw=WaitForSingleObject(pi->pr.hProcess,INFINITE);
594 if(dw==WAIT_FAILED && failcount++==1) {
595 dbg(0,"WaitForSingleObject failed twice. Assuming the process is terminated.");
596 return 0;
597 break;
598 }
599 }
600 }
601 #else
602 #ifdef _POSIX_C_SOURCE
603 if(pi->status!=-1) {
604 return pi->status;
605 }
606 while(1) {
607 int status;
608 pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG);
609 if(w>0) {
610 if(WIFEXITED(status))
611 pi->status=WEXITSTATUS(status);
612 return pi->status;
613 if(WIFSTOPPED(status)) {
614 dbg(0,"child is stopped by %i signal\n",WSTOPSIG(status));
615 } else if (WIFSIGNALED(status)) {
616 dbg(0,"child terminated by signal %i\n",WEXITSTATUS(status));
617 pi->status=255;
618 return 255;
619 }
620 if(!block)
621 return -1;
622 } else if(w==0) {
623 if(!block)
624 return -1;
625 } else {
626 if(pi->status!=-1) // Signal handler has changed pi->status while in this function
627 return pi->status;
628 dbg(0,"waitpid() indicated error, reporting process termination.\n");
629 return 255;
630 }
631 }
632 #else
633 dbg(0, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.\n");
634 return pi->status;
635 #endif
636 #endif
637 }
638
639 void spawn_process_info_free(struct spawn_process_info *pi)
640 {
641 if(pi==NULL)
642 return;
643 #ifdef HAVE_API_WIN32_BASE
644 CloseHandle(pi->pr.hProcess);
645 CloseHandle(pi->pr.hThread);
646 #endif
647 #ifdef _POSIX_C_SOURCE
648 {
649 sigset_t set, old;
650 sigemptyset(&set);
651 sigaddset(&set,SIGCHLD);
652 spawn_process_sigmask(SIG_BLOCK,&set,&old);
653 spawn_process_children=g_list_remove(spawn_process_children,pi);
654 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
655 }
656 #endif
657 g_free(pi);
658 }
659
660 #ifdef _POSIX_C_SOURCE
661 static void spawn_process_sigchld(int sig)
662 {
663 int status;
664 pid_t pid;
665 while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
666 GList *el=g_list_first(spawn_process_children);
667 while(el) {
668 struct spawn_process_info *p=el->data;
669 if(p->pid==pid) {
670 p->status=status;
671 }
672 el=g_list_next(el);
673 }
674 }
675 }
676 #endif
677
678 void spawn_process_init()
679 {
680 #ifdef _POSIX_C_SOURCE
681 struct sigaction act;
682 act.sa_handler=spawn_process_sigchld;
683 act.sa_flags=0;
684 sigemptyset(&act.sa_mask);
685 sigaction(SIGCHLD, &act, NULL);
686 #endif
687 return;
688 }
689
690

   
Visit the ZANavi Wiki