From: woglinde Date: Sun, 1 May 2011 22:07:06 +0000 (+0000) Subject: Add:core:Added command function for spawn systemprocesses and string catenation,... X-Git-Tag: navit-0.5.0.5194svn~737 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=412a522e3f36d0c9f4b5f72244eeaf0781c51337;p=profile%2Fivi%2Fnavit.git Add:core:Added command function for spawn systemprocesses and string catenation, patch provided by tryagain git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@4458 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- diff --git a/navit/navit/main.c b/navit/navit/main.c index 3db4932..3c6c618 100644 --- a/navit/navit/main.c +++ b/navit/navit/main.c @@ -49,6 +49,7 @@ #include "event.h" #include "callback.h" #include "navit_nls.h" +#include "util.h" #if HAVE_API_WIN32_BASE #include #include @@ -59,15 +60,6 @@ struct map_data *map_data_default; struct callback_list *cbl; - -static void sigchld(int sig) -{ -#if !defined(_WIN32) && !defined(__CEGCC__) - int status; - while (waitpid(-1, &status, WNOHANG) > 0); -#endif -} - #ifdef HAVE_API_WIN32 void setenv(char *var, char *val, int overwrite) @@ -340,9 +332,8 @@ main_init(const char *program) wchar_t wfilename[MAX_PATH + 1]; #endif -#ifndef _WIN32 - signal(SIGCHLD, sigchld); -#endif + spawn_process_init(); + cbl=callback_list_new(); #ifdef HAVE_API_WIN32_BASE win_set_nls(); diff --git a/navit/navit/navit.c b/navit/navit/navit.c index b80d5c7..b75f400 100644 --- a/navit/navit/navit.c +++ b/navit/navit/navit.c @@ -66,6 +66,10 @@ #include "vehicleprofile.h" #include "sunriset.h" #include "bookmarks.h" +#ifdef HAVE_API_WIN32_BASE +#include +#include "util.h" +#endif /** * @defgroup navit the navit core instance. navit is the object containing nearly everything: A set of maps, one or more vehicle, a graphics object for rendering the map, a gui object for displaying the user interface, a route object, a navigation object and so on. Be warned that it is theoretically possible to have more than one navit object @@ -1155,6 +1159,104 @@ navit_cmd_fmt_coordinates(struct navit *this, char *function, struct attr **in, } } +/** + * Join several string attributes into one + * + * @param navit The navit instance + * @param function unused (needed to match command function signiture) + * @param in input attributes in[0] - separator, in[1..] - attributes to join + * @param out output attribute joined attribute as string + * @param valid unused + * @returns nothing + */ +static void +navit_cmd_strjoin(struct navit *this, char *function, struct attr **in, struct attr ***out, int *valid) +{ + struct attr attr; + gchar *ret, *sep; + int i; + attr.type=attr_type_string_begin; + attr.u.str=NULL; + if(in[0] && in[1]) { + sep=attr_to_text(in[0],NULL,1); + ret=attr_to_text(in[1],NULL,1); + for(i=2;in[i];i++) { + gchar *in_i=attr_to_text(in[i],NULL,1); + gchar *r=g_strjoin(sep,ret,in_i,NULL); + g_free(in_i); + g_free(ret); + ret=r; + } + g_free(sep); + attr.u.str=ret; + if(out) { + *out=attr_generic_add_attr(*out, &attr); + } + g_free(ret); + } +} + +/** + * Call external program + * + * @param navit The navit instance + * @param function unused (needed to match command function signiture) + * @param in input attributes in[0] - name of executable, in[1..] - parameters + * @param out output attribute unused + * @param valid unused + * @returns nothing + */ +static void +navit_cmd_spawn(struct navit *this, char *function, struct attr **in, struct attr ***out, int *valid) +{ + int i,j, nparms, nvalid; + const char ** argv=NULL; + struct spawn_process_info *pi; + + nparms=0; + nvalid=0; + if(in) { + while(in[nparms]) { + if (in[nparms]->type!=attr_none) + nvalid++; + nparms++; + } + } + + if(nvalid>0) { + argv=g_new(char*,nvalid+1); + for(i=0,j=0;in[i];i++) { + if(in[i]->type!=attr_none ) { + argv[j++]=attr_to_text(in[i],NULL,1); + } else { + dbg(0,"Parameter #%i is attr_none - skipping\n",i); + } + } + argv[j]=NULL; + pi=spawn_process(argv); + + // spawn_process() testing suite - uncomment following code to test. + //sleep(3); + // example of non-blocking wait + //int st=spawn_process_check_status(pi,0);dbg(0,"status %i\n",st); + // example of blocking wait + //st=spawn_process_check_status(pi,1);dbg(0,"status %i\n",st); + // example of wait after process is finished and status is + // already tested + //st=spawn_process_check_status(pi,1);dbg(0,"status %i\n",st); + // example of wait after process is finished and status is + // already tested - unblocked + //st=spawn_process_check_status(pi,0);dbg(0,"status %i\n",st); + + // End testing suite + spawn_process_info_free(pi); + for(i=0;argv[i];i++) + g_free(argv[i]); + g_free(argv); + } +} + + static struct command_table commands[] = { {"zoom_in",command_cast(navit_cmd_zoom_in)}, {"zoom_out",command_cast(navit_cmd_zoom_out)}, @@ -1170,6 +1272,8 @@ static struct command_table commands[] = { {"pop_int",command_cast(navit_cmd_pop_int)}, {"int_stack_size",command_cast(navit_cmd_int_stack_size)}, {"toggle_layer",command_cast(navit_cmd_toggle_layer)}, + {"strjoin",command_cast(navit_cmd_strjoin)}, + {"spawn",command_cast(navit_cmd_spawn)}, {"map_add_curr_pos",command_cast(navit_cmd_map_add_curr_pos)}, {"map_item_set_attr",command_cast(navit_cmd_map_item_set_attr)}, {"set_attr_var",command_cast(navit_cmd_set_attr_var)}, diff --git a/navit/navit/util.c b/navit/navit/util.c index f079e3f..ba35b4c 100644 --- a/navit/navit/util.c +++ b/navit/navit/util.c @@ -23,7 +23,15 @@ #include #include #include +#include + +#ifdef _POSIX_C_SOURCE +#include +#include +#include +#endif #include "util.h" +#include "debug.h" void strtoupper(char *dest, const char *src) @@ -348,3 +356,338 @@ current_to_iso8601(void) #endif return timep; } + + +struct spawn_process_info { +#ifdef HAVE_API_WIN32_BASE + PROCESS_INFORMATION pr; +#else + pid_t pid; // = -1 if non-blocking spawn isn't supported + int status; // exit status if non-blocking spawn isn't supported +#endif +}; + + +/** + * Escape and quote string for shell + * + * @param in arg string to escape + * @returns escaped string + */ +char * +shell_escape(char *arg) +{ + char *r; + int arglen=strlen(arg); + int i,j,rlen; +#ifdef HAVE_API_WIN32_BASE + { + int bscount=0; + rlen=arglen+3; + r=g_new(char,rlen); + r[0]='"'; + for(i=0,j=1;i0) { + rlen+=bscount; + r=g_realloc(r,rlen); + memset(r+j,'\\',bscount); + j+=bscount; + bscount=0; + } + r[j++]=arg[i]; + if(i==(arglen-1)) { + r[j++]='"'; + } + } + } + r[j++]=0; + } +#else + { + // Will use hard quoting for the whole string + // and replace each singular quote found with a '\'' sequence. + rlen=arglen+3; + r=g_new(char,rlen); + r[0]='\''; + for(i=0,j=1;i0 - return code, -1 - error + */ +struct spawn_process_info* +spawn_process(char **argv) +{ + struct spawn_process_info*r=g_new(struct spawn_process_info,1); +#ifdef _POSIX_C_SOURCE + { + pid_t pid; + + sigset_t set, old; + sigemptyset(&set); + sigaddset(&set,SIGCHLD); + spawn_process_sigmask(SIG_BLOCK,&set,&old); + pid=fork(); + if(pid==0) { + execvp(argv[0], argv); + /*Shouldn't reach here*/ + exit(1); + } else if(pid>0) { + r->status=-1; + r->pid=pid; + spawn_process_children=g_list_prepend(spawn_process_children,r); + } else { + dbg(0,"fork() returned error."); + g_free(r); + r=NULL; + } + spawn_process_sigmask(SIG_SETMASK,&old,NULL); + return r; + } +#else +#ifdef HAVE_API_WIN32_BASE + { + char *cmdline; + LPCWSTR cmd,args; + DWORD dwRet; + + // For [desktop] Windows it's adviceable not to use + // first CreateProcess parameter because PATH is not used + // if it is defined. + // + // On WinCE 6.0 I was unable to launch anything + // without first CreateProcess parameter, also it seems that + // no WinCE program has support for quoted strings in arguments. + // So... +#ifdef HAVE_API_WIN32_CE + cmdline=g_strjoinv(" ",argv+1); + args=newSysString(cmdline); + cmd = newSysString(argv[0]); + dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr)); + dbg(0, "CreateProcess(%s,%s), PID=%i\n",argv[0],cmdline,r->pr.dwProcessId); + g_free(cmd); +#else + cmdline=spawn_process_compose_cmdline(argv); + args=newSysString(cmdline); + dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr)); + dbg(0, "CreateProcess(%s), PID=%i\n",cmdline,r->pr.dwProcessId); +#endif + g_free(cmdline); + g_free(args); + return r; + } +#else + { + char *cmdline=spawn_process_compose_cmdline(argv); + int status; + dbg(0,"Unblocked spawn_process isn't availiable on this platform.\n"); + status=system(cmdline); + g_free(cmdline); + r->status=status; + r->pid=0; + return r; + } +#endif +#endif +} + +/** + * Check external program status + * + * @param in *pi pointer to spawn_process_info structure + * @param in block =0 do not block =1 block until child terminated + * @returns -1 - still running, >=0 program exited, + * =255 trminated abnormally or wasn't run at all. + * + */ +int spawn_process_check_status(struct spawn_process_info *pi, int block) +{ + if(pi==NULL) { + dbg(0,"Trying to get process status of NULL, assuming process is terminated.\n"); + return 255; + } +#ifdef HAVE_API_WIN32_BASE + {int failcount=0; + while(1){ + DWORD dw; + if(GetExitCodeProcess(pi->pr.hProcess,&dw)) { + if(dw!=STILL_ACTIVE) { + return dw; + break; + } + } else { + dbg(0,"GetExitCodeProcess failed. Assuming the process is terminated."); + return 255; + } + if(!block) + return -1; + + dw=WaitForSingleObject(pi->pr.hProcess,INFINITE); + if(dw==WAIT_FAILED && failcount++==1) { + dbg(0,"WaitForSingleObject failed twice. Assuming the process is terminated."); + return 0; + break; + } + } + } +#else +#ifdef _POSIX_C_SOURCE + if(pi->status!=-1) { + return pi->status; + } + while(1) { + int status; + pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG); + if(w>0) { + if(WIFEXITED(status)) + pi->status=WEXITSTATUS(status); + return pi->status; + if(WIFSTOPPED(status)) { + dbg(0,"child is stopped by %i signal\n",WSTOPSIG(status)); + } else if (WIFSIGNALED(status)) { + dbg(0,"child terminated by signal %i\n",WEXITSTATUS(status)); + pi->status=255; + return 255; + } + if(!block) + return -1; + } else if(w==0) { + if(!block) + return -1; + } else { + if(pi->status!=-1) // Signal handler has changed pi->status while in this function + return pi->status; + dbg(0,"waitpid() indicated error, reporting process termination.\n"); + return 255; + } + } +#else + dbg(0, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.\n"); + return pi->status; +#endif +#endif +} + +void spawn_process_info_free(struct spawn_process_info *pi) +{ + if(pi==NULL) + return; +#ifdef HAVE_API_WIN32_BASE + CloseHandle(pi->pr.hProcess); + CloseHandle(pi->pr.hThread); +#endif +#ifdef _POSIX_C_SOURCE + { + sigset_t set, old; + sigemptyset(&set); + sigaddset(&set,SIGCHLD); + spawn_process_sigmask(SIG_BLOCK,&set,&old); + spawn_process_children=g_list_remove(spawn_process_children,pi); + spawn_process_sigmask(SIG_SETMASK,&old,NULL); + } +#endif + g_free(pi); +} + +#ifdef _POSIX_C_SOURCE +static void spawn_process_sigchld(int sig) +{ + int status; + pid_t pid; + while ((pid=waitpid(-1, &status, WNOHANG)) > 0) { + GList *el=g_list_first(spawn_process_children); + while(el) { + struct spawn_process_info *p=el->data; + if(p->pid==pid) { + p->status=status; + } + el=g_list_next(el); + } + } +} +#endif + +void spawn_process_init() +{ +#ifdef _POSIX_C_SOURCE + struct sigaction act; + act.sa_handler=spawn_process_sigchld; + act.sa_flags=0; + sigemptyset(&act.sa_mask); + sigaction(SIGCHLD, &act, NULL); +#endif + return; +} + + diff --git a/navit/navit/util.h b/navit/navit/util.h index f396060..1f8919b 100644 --- a/navit/navit/util.h +++ b/navit/navit/util.h @@ -46,5 +46,13 @@ int gettimeofday(struct timeval *time, void *); #endif +struct spawn_process_info; +char * shell_escape(char *arg); +struct spawn_process_info* spawn_process(char **argv); +int spawn_process_check_status(struct spawn_process_info *pi,int block); + +void spawn_process_info_free(struct spawn_process_info *pi); +void spawn_process_init(void); + #endif