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

Contents of /navit/navit/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 56 - (show annotations) (download)
Sun Mar 19 08:44:36 2017 UTC (7 years ago) by zoff99
File MIME type: text/plain
File size: 15511 byte(s)
updates
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 #if 1==1
170 #ifndef ANDROID_ARM64
171
172 /*
173 * ssize_t getdelim(char ** __restrict, size_t * __restrict, int,
174 FILE * __restrict);
175 ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
176 *
177 */
178
179 /**
180 * Read the part of a file up to a delimiter to a string.
181 * <p>
182 * Read up to (and including) a DELIMITER from FP into *LINEPTR (and
183 NUL-terminate it).
184 * @param lineptr Pointer to a pointer returned from malloc (or
185 NULL), pointing to a buffer. It is realloc'ed as
186 necessary and will receive the data read.
187 * @param n Size of the buffer.
188 *
189 * @return Number of characters read (not including
190 the null terminator), or -1 on error or EOF.
191 */
192
193
194 // TODO: android studio ---------
195 // TODO: android studio ---------
196 #if 1
197 int
198 getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
199 {
200 int result;
201 size_t cur_len = 0;
202
203 if (lineptr == NULL || n == NULL || fp == NULL)
204 {
205 return -1;
206 }
207
208 flockfile (fp);
209
210 if (*lineptr == NULL || *n == 0)
211 {
212 *n = 120;
213 *lineptr = (char *) realloc (*lineptr, *n);
214 if (*lineptr == NULL)
215 {
216 result = -1;
217 goto unlock_return;
218 }
219 }
220
221 for (;;)
222 {
223 int i;
224
225 i = getc (fp);
226 if (i == EOF)
227 {
228 result = -1;
229 break;
230 }
231
232 /* Make enough space for len+1 (for final NUL) bytes. */
233 if (cur_len + 1 >= *n)
234 {
235 size_t needed_max=SIZE_MAX;
236 size_t needed = 2 * *n + 1; /* Be generous. */
237 char *new_lineptr;
238 if (needed_max < needed)
239 needed = needed_max;
240 if (cur_len + 1 >= needed)
241 {
242 result = -1;
243 goto unlock_return;
244 }
245
246 new_lineptr = (char *) realloc (*lineptr, needed);
247 if (new_lineptr == NULL)
248 {
249 result = -1;
250 goto unlock_return;
251 }
252
253 *lineptr = new_lineptr;
254 *n = needed;
255 }
256
257 (*lineptr)[cur_len] = i;
258 cur_len++;
259
260 if (i == delimiter)
261 break;
262 }
263 (*lineptr)[cur_len] = '\0';
264 result = cur_len ? cur_len : result;
265
266 unlock_return:
267 funlockfile (fp); /* doesn't set errno */
268
269 return result;
270 }
271
272 int
273 getline (char **lineptr, size_t *n, FILE *stream)
274 {
275 return getdelim (lineptr, n, '\n', stream);
276 }
277 #endif
278 // TODO: android studio ---------
279 // TODO: android studio ---------
280
281
282 #endif
283 #endif
284
285
286
287 #if defined(_UNICODE)
288 wchar_t* newSysString(const char *toconvert)
289 {
290 int newstrlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, 0, 0);
291 wchar_t *newstring = g_new(wchar_t,newstrlen);
292 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, newstring, newstrlen) ;
293 return newstring;
294 }
295 #else
296 char * newSysString(const char *toconvert)
297 {
298 return g_strdup(toconvert);
299 }
300 #endif
301 #endif
302
303 #if defined(_MSC_VER) || (!defined(HAVE_GETTIMEOFDAY) && defined(HAVE_API_WIN32_BASE))
304 /**
305 * Impements a simple incomplete version of gettimeofday. Only usefull for messuring
306 * time spans, not the real time of day.
307 */
308 int gettimeofday(struct timeval *time, void *local)
309 {
310 int milliseconds = GetTickCount();
311
312 time->tv_sec = milliseconds/1000;
313 time->tv_usec = (milliseconds - (time->tv_sec * 1000)) * 1000;
314
315 return 0;
316 }
317 #endif
318 /**
319 * Convert an ISO 8601-style time string into epoch time.
320 *
321 * @param iso8601 Pointer to a string containing the time in ISO 8601 format.
322 *
323 * @return An unsigned integer representing the number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
324 */
325 unsigned int
326 iso8601_to_secs(char *iso8601)
327 {
328 int a,b,d,val[6],i=0;
329 char *start=iso8601,*pos=iso8601;
330 while (*pos && i < 6) {
331 if (*pos < '0' || *pos > '9') {
332 val[i++]=atoi(start);
333 pos++;
334 start=pos;
335 }
336 pos++;
337 }
338
339 a=val[0]/100;
340 b=2-a+a/4;
341
342 if (val[1] < 2) {
343 val[0]--;
344 val[1]+=12;
345 }
346
347 d=1461*(val[0]+4716)/4+306001*(val[1]+1)/10000+val[2]+b-2442112;
348
349 return ((d*24+val[3])*60+val[4])*60+val[5];
350 }
351
352 /**
353 * Output local system time in ISO 8601 format.
354 *
355 * @return Pointer to a string containing the time in ISO 8601 format
356 */
357 char *
358 current_to_iso8601(void)
359 {
360 char *timep=NULL;
361 #ifdef HAVE_API_WIN32_BASE
362 SYSTEMTIME ST;
363 GetSystemTime(&ST);
364 timep=g_strdup_printf("%d-%02d-%02dT%02d:%02d:%02dZ",ST.wYear,ST.wMonth,ST.wDay,ST.wHour,ST.wMinute,ST.wSecond);
365 #else
366 char buffer[32];
367 time_t tnow;
368 struct tm *tm;
369 tnow = time(0);
370 tm = gmtime(&tnow);
371 if (tm) {
372 strftime(buffer, sizeof(buffer), "%Y-%m-%dT%TZ", tm);
373 timep=g_strdup(buffer);
374 }
375 #endif
376 return timep;
377 }
378
379
380 struct spawn_process_info {
381 #ifdef HAVE_API_WIN32_BASE
382 PROCESS_INFORMATION pr;
383 #else
384 pid_t pid; // = -1 if non-blocking spawn isn't supported
385 int status; // exit status if non-blocking spawn isn't supported
386 #endif
387 };
388
389
390 /**
391 * Escape and quote string for shell
392 *
393 * @param in arg string to escape
394 * @returns escaped string
395 */
396 char *
397 shell_escape(char *arg)
398 {
399 char *r;
400 int arglen=strlen(arg);
401 int i,j,rlen;
402 #ifdef HAVE_API_WIN32_BASE
403 {
404 int bscount=0;
405 rlen=arglen+3;
406 r=g_new(char,rlen);
407 r[0]='"';
408 for(i=0,j=1;i<arglen;i++) {
409 if(arg[i]=='\\') {
410 bscount++;
411 if(i==(arglen-1)) {
412 // Most special case - last char is
413 // backslash. We can't escape it inside
414 // quoted string due to Win unescaping
415 // rules so quote should be closed
416 // before backslashes and these
417 // backslashes shouldn't be doubled
418 rlen+=bscount;
419 r=g_realloc(r,rlen);
420 r[j++]='"';
421 memset(r+j,'\\',bscount);
422 j+=bscount;
423 }
424 } else {
425 //Any preceeding backslashes will be doubled.
426 bscount*=2;
427 // Double quote needs to be preceeded by
428 // at least one backslash
429 if(arg[i]=='"')
430 bscount++;
431 if(bscount>0) {
432 rlen+=bscount;
433 r=g_realloc(r,rlen);
434 memset(r+j,'\\',bscount);
435 j+=bscount;
436 bscount=0;
437 }
438 r[j++]=arg[i];
439 if(i==(arglen-1)) {
440 r[j++]='"';
441 }
442 }
443 }
444 r[j++]=0;
445 }
446 #else
447 {
448 // Will use hard quoting for the whole string
449 // and replace each singular quote found with a '\'' sequence.
450 rlen=arglen+3;
451 r=g_new(char,rlen);
452 r[0]='\'';
453 for(i=0,j=1;i<arglen;i++) {
454 if(arg[i]=='\'') {
455 rlen+=3;
456 r=g_realloc(r,rlen);
457 g_strlcpy(r+j,"'\\''",rlen-j);
458 } else {
459 r[j++]=arg[i];
460 }
461 }
462 r[j++]='\'';
463 r[j++]=0;
464 }
465 #endif
466 return r;
467 }
468
469 #ifndef _POSIX_C_SOURCE
470 static char*
471 spawn_process_compose_cmdline(char **argv)
472 {
473 int i,j;
474 char *cmdline=shell_escape(argv[0]);
475 for(i=1,j=strlen(cmdline);argv[i];i++) {
476 char *arg=shell_escape(argv[i]);
477 int arglen=strlen(arg);
478 cmdline[j]=' ';
479 cmdline=g_realloc(cmdline,j+1+arglen+1);
480 memcpy(cmdline+j+1,arg,arglen+1);
481 g_free(arg);
482 j=j+1+arglen;
483 }
484 return cmdline;
485 }
486 #endif
487
488 #ifdef _POSIX_C_SOURCE
489
490 #if 0 /* def _POSIX_THREADS */
491 #define spawn_process_sigmask(how,set,old) pthread_sigmask(how,set,old)
492 #else
493 #define spawn_process_sigmask(how,set,old) sigprocmask(how,set,old)
494 #endif
495
496 GList *spawn_process_children=NULL;
497
498 #endif
499
500
501 /**
502 * Call external program
503 *
504 * @param in argv NULL terminated list of parameters,
505 * zeroeth argument is program name
506 * @returns 0 - success, >0 - return code, -1 - error
507 */
508 struct spawn_process_info*
509 spawn_process(char **argv)
510 {
511 struct spawn_process_info*r=g_new(struct spawn_process_info,1);
512 #ifdef _POSIX_C_SOURCE
513 {
514 pid_t pid;
515
516 sigset_t set, old;
517 sigemptyset(&set);
518 sigaddset(&set,SIGCHLD);
519 spawn_process_sigmask(SIG_BLOCK,&set,&old);
520 pid=fork();
521 if(pid==0) {
522 execvp(argv[0], argv);
523 /*Shouldn't reach here*/
524 exit(1);
525 } else if(pid>0) {
526 r->status=-1;
527 r->pid=pid;
528 spawn_process_children=g_list_prepend(spawn_process_children,r);
529 } else {
530 dbg(0,"fork() returned error.");
531 g_free(r);
532 r=NULL;
533 }
534 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
535 return r;
536 }
537 #else
538 #ifdef HAVE_API_WIN32_BASE
539 {
540 char *cmdline;
541 LPCWSTR cmd,args;
542 DWORD dwRet;
543
544 // For [desktop] Windows it's adviceable not to use
545 // first CreateProcess parameter because PATH is not used
546 // if it is defined.
547 //
548 // On WinCE 6.0 I was unable to launch anything
549 // without first CreateProcess parameter, also it seems that
550 // no WinCE program has support for quoted strings in arguments.
551 // So...
552 #ifdef HAVE_API_WIN32_CE
553 cmdline=g_strjoinv(" ",argv+1);
554 args=newSysString(cmdline);
555 cmd = newSysString(argv[0]);
556 dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr));
557 dbg(0, "CreateProcess(%s,%s), PID=%i\n",argv[0],cmdline,r->pr.dwProcessId);
558 g_free(cmd);
559 #else
560 STARTUPINFO startupInfo;
561 memset(&startupInfo, 0, sizeof(startupInfo));
562 startupInfo.cb = sizeof(startupInfo);
563 cmdline=spawn_process_compose_cmdline(argv);
564 args=newSysString(cmdline);
565 dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &(r->pr));
566 dbg(0, "CreateProcess(%s), PID=%i\n",cmdline,r->pr.dwProcessId);
567 #endif
568 g_free(cmdline);
569 g_free(args);
570 return r;
571 }
572 #else
573 {
574 char *cmdline=spawn_process_compose_cmdline(argv);
575 int status;
576 dbg(0,"Unblocked spawn_process isn't availiable on this platform.\n");
577 status=system(cmdline);
578 g_free(cmdline);
579 r->status=status;
580 r->pid=0;
581 return r;
582 }
583 #endif
584 #endif
585 }
586
587 /**
588 * Check external program status
589 *
590 * @param in *pi pointer to spawn_process_info structure
591 * @param in block =0 do not block =1 block until child terminated
592 * @returns -1 - still running, >=0 program exited,
593 * =255 trminated abnormally or wasn't run at all.
594 *
595 */
596 int spawn_process_check_status(struct spawn_process_info *pi, int block)
597 {
598 if(pi==NULL) {
599 dbg(0,"Trying to get process status of NULL, assuming process is terminated.\n");
600 return 255;
601 }
602 #ifdef HAVE_API_WIN32_BASE
603 {int failcount=0;
604 while(1){
605 DWORD dw;
606 if(GetExitCodeProcess(pi->pr.hProcess,&dw)) {
607 if(dw!=STILL_ACTIVE) {
608 return dw;
609 break;
610 }
611 } else {
612 dbg(0,"GetExitCodeProcess failed. Assuming the process is terminated.");
613 return 255;
614 }
615 if(!block)
616 return -1;
617
618 dw=WaitForSingleObject(pi->pr.hProcess,INFINITE);
619 if(dw==WAIT_FAILED && failcount++==1) {
620 dbg(0,"WaitForSingleObject failed twice. Assuming the process is terminated.");
621 return 0;
622 break;
623 }
624 }
625 }
626 #else
627 #ifdef _POSIX_C_SOURCE
628 if(pi->status!=-1) {
629 return pi->status;
630 }
631 while(1) {
632 int status;
633 pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG);
634 if(w>0) {
635 if(WIFEXITED(status))
636 pi->status=WEXITSTATUS(status);
637 return pi->status;
638 if(WIFSTOPPED(status)) {
639 dbg(0,"child is stopped by %i signal\n",WSTOPSIG(status));
640 } else if (WIFSIGNALED(status)) {
641 dbg(0,"child terminated by signal %i\n",WEXITSTATUS(status));
642 pi->status=255;
643 return 255;
644 }
645 if(!block)
646 return -1;
647 } else if(w==0) {
648 if(!block)
649 return -1;
650 } else {
651 if(pi->status!=-1) // Signal handler has changed pi->status while in this function
652 return pi->status;
653 dbg(0,"waitpid() indicated error, reporting process termination.\n");
654 return 255;
655 }
656 }
657 #else
658 dbg(0, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.\n");
659 return pi->status;
660 #endif
661 #endif
662 }
663
664 void spawn_process_info_free(struct spawn_process_info *pi)
665 {
666 if(pi==NULL)
667 return;
668 #ifdef HAVE_API_WIN32_BASE
669 CloseHandle(pi->pr.hProcess);
670 CloseHandle(pi->pr.hThread);
671 #endif
672 #ifdef _POSIX_C_SOURCE
673 {
674 sigset_t set, old;
675 sigemptyset(&set);
676 sigaddset(&set,SIGCHLD);
677 spawn_process_sigmask(SIG_BLOCK,&set,&old);
678 spawn_process_children=g_list_remove(spawn_process_children,pi);
679 spawn_process_sigmask(SIG_SETMASK,&old,NULL);
680 }
681 #endif
682 g_free(pi);
683 }
684
685 #ifdef _POSIX_C_SOURCE
686 static void spawn_process_sigchld(int sig)
687 {
688 int status;
689 pid_t pid;
690 while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
691 GList *el=g_list_first(spawn_process_children);
692 while(el) {
693 struct spawn_process_info *p=el->data;
694 if(p->pid==pid) {
695 p->status=status;
696 }
697 el=g_list_next(el);
698 }
699 }
700 }
701 #endif
702
703 void spawn_process_init()
704 {
705 #ifdef _POSIX_C_SOURCE
706 struct sigaction act;
707 act.sa_handler=spawn_process_sigchld;
708 act.sa_flags=0;
709 sigemptyset(&act.sa_mask);
710 sigaction(SIGCHLD, &act, NULL);
711 #endif
712 return;
713 }
714
715

   
Visit the ZANavi Wiki