/* * external.c * * functions that deals with external commmands * such as csound, play, playmidi, lpr... * * this is part of the GNU Denemo, * Copyright (c) 2000-2006 Adam Tee */ #include #include "prefops.h" #include #include "external.h" /* test it a given temp filename points to an * existing file in the dotdenemo directory. */ gboolean exists_temp_filename (const GString * name) { GString *path; path = g_string_new (locatedotdenemo ()); g_string_append (path, "/"); g_string_append (path, name->str); return g_file_test (name->str, G_FILE_TEST_EXISTS); } /* parse spaces and tabs as field delimitors, return an argv * suitable for use without the need of system() * FIXME: let delimitors "as is" if they are inside quotations mark */ static gchar ** build_argv (gchar * cmd) { gint i = 0; /* index in cmd */ gint argi = 0; /* arg index in vector */ gint vlen = 0; /* vector length in args */ gchar **argv = NULL; argv = (gchar **) g_malloc (sizeof (gchar *)); argv[0] = 0; /* vlen = 0 */ if (!cmd) return NULL; while (cmd[i] != 0) { gint ci = 0; /* char index in current arg */ gint alen = 0; /* arg length in chars */ if (argi >= (vlen - 2)) /* ensure to not overflow */ argv = (gchar **) realloc (argv, (vlen += 32) * sizeof (gchar *)); argv[argi] = g_malloc (sizeof (gchar)); argv[argi] = 0; /* curently, alen=0 */ while (cmd[i] == ' ' || cmd[i] == '\t' || cmd[i] == '\n') i++; /* crop */ while (cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != 0) { if (ci >= (alen - 2)) /* ensure to not overflow */ argv[argi] = (gchar *) realloc (argv[argi], (alen += 32) * sizeof (gchar)); argv[argi][ci] = cmd[i]; ci++, i++; } argv[argi][ci] = 0; /* close string */ argi++; if (cmd[i]) i++; #ifdef DEBUG fprintf (stderr, "argv[%d]=#%s#\n", (argi - 1), argv[argi - 1]); #endif } argv[argi] = NULL; /* close args list */ return argv; } /* free memory that was allocated by build_argv */ static void free_argv (gchar ** av) { int i = 0; if (!av) return; while (av[i]) { free (av[i++]); } } /* give a filepath string pointing to the user's * Denemo temporary directory. * * if constname is NULL, basename is random. * else, basename is the given constname. * * returns: the filepath string */ GString * get_temp_filename (gchar * constname) { GString *path = NULL; if (constname) { path = g_string_new (locatedotdenemo ()); g_string_append (path, "/"); g_string_append (path, constname); } else { path = g_string_new (""); while (exists_temp_filename (path)); /* GCC warns, but i know what i am doing */ g_string_append (path, tmpnam (NULL)); } #ifdef DEBUG fprintf (stderr, "temp filename: %s\n", path->str); #endif return path; } /* init pid files */ void ext_init (void) { GString *pidpath; FILE *fp; int i, len; len = sizeof (ext_pidfiles) / sizeof (gchar *); for (i = 0; i < len; i++) { pidpath = get_temp_filename (ext_pidfiles[i]); fp = fopen (pidpath->str, "w+"); fprintf (fp, "%d", -1); fclose (fp); g_string_free (pidpath, TRUE); } } /* invalid pid files */ void ext_quit (void) { GString *pidpath; FILE *fp; int i, pid, len; len = sizeof (ext_pidfiles) / sizeof (gchar *); for (i = 0; i < len; i++) { pidpath = get_temp_filename (ext_pidfiles[i]); fp = fopen (pidpath->str, "r+"); fscanf (fp, "%d", &pid); #ifdef DEBUG fprintf (stderr, "ext_quit: read pid %d\n", pid); #endif if (pid > 0) kill (pid, SIGTERM); rewind (fp); fprintf (fp, "%d", -1); fclose (fp); truncate (pidpath->str, 2); /* '-' '1' EOF */ g_string_free (pidpath, TRUE); } } /* * spawn an external shell command line with * its arguments and returns immediately. * * additional options can be put in cmdline, * separated by spaces or tabs. * * return: PID of spawned process. */ GPid spawn_external (const GString * cmdline) { GError *err = NULL; /* force implicit g_malloc */ gchar **argv; GPid pid = -1; gboolean ok; if (!cmdline->str) return -1; argv = build_argv (cmdline->str); ok = g_spawn_async (NULL, /* dir */ argv, NULL, /* env */ G_SPAWN_SEARCH_PATH, /* | G_SPAWN_DO_NOT_REAP_CHILD, */ NULL, /* child setup func */ NULL, /* user data passed to setup */ &pid, /* child pid */ &err); if (!ok) { g_warning ("error spawning pid %d: %s", pid, err->message); g_error_free (err); } free_argv (argv); return pid; }