9.5. Start a Process - start_process, find_on_path

   /*--------------------------------------------------------------------
    * Function:    start_process
    * Returns:     t or nil
    * Description: Starts a process using a fork and exec pair.  It places
    *              the new process ID, name, and associated GUI button in
    *              a list so that we can use SIGCHLD to clean up the child
    *              list and the screen at once.
    *------------------------------------------------------------------*/
   function start_process (button, prog, process_name, args)
   {
     local pid;
   
     if ((prog == "gnuplot") && (find_on_path("gnuplot") == nil))
       {
         anygui_makemsg(string("\nIt looks like you don't have\n",
                               "gnuplot on your system.",
                               "\n\nYou must install gnuplot to make plots.\n"));
       }
     else if ((prog == "textlog") && (find_on_path("textlog") == nil))
       {
         anygui_makemsg(string("To work correctly, this part of the demo requires",
                               " the Cascade TextLogger,\nwhich apparently is not",
                               " installed on your system.\n\n",
                               "You can download the Cascade TextLogger from the Cogent Web Site\n",
                               "at http://www.cogent.ca/Software/TextLogger_Software.html"));
       }

The gnuplot program is an open-source plotting program that is not currently available in QNX, and may or may not be installed on a user's Linux machine. So we have to check for it, using the find_on_path function (below), and if it is missing, display a message box, using the anygui_makemsg function.

     else
       {
         block_signal(SIGCHLD);
         if ((pid = fork()) == 0)        
           {
             /* This is the child process. */
             exec (prog, car(args), cadr(args), caddr(args),
                   car(cdddr(args)), car(nth_cdr(args, 4)), 
                   car(nth_cdr(args, 5)), car(nth_cdr(args, 6)),
                   car(nth_cdr(args, 7)), car(nth_cdr(args, 8)),
                   car(nth_cdr(args, 9)));      
             /* In case the above exec commands fails, the following will be
              * called, and it's virtually guaranteed not to fail.  Thus in
              * any circumstance a child process gets created.*/
             exec("/bin/true");
           }
         Children = cons (list (pid, process_name, button, prog), Children);
         unblock_signal(SIGCHLD);
     
         pid;
       }
   }
   

The Gamma functions used here are fork to spawn a child process, exec to execute a program, list to create a list, and cons to add new elements to a list.

The list Children is an association list, which is a list whose members are also lists. Usually each sub-list within an association list has two members, and the list is typically used to store values and look them up, associating the second member of the sub-list with the first. In this case, each sub-list has three members, but it follows the same principle. You can see how the sub-list members of Children are accessed by looking at the child_died function.

When a process starts, the start_process function adds the process ID, name, and associated button to the Children association list, so that it can be found and stopped when necessary.

The find_on_path function uses the Gamma string_split, getenv, cdr, car, string and access functions to determine whether a command can be found in the PATH of the current operating system.

   /*--------------------------------------------------------------------
    * Function:    find_on_path
    * Returns:     t on success, or nil
    * Description: Determines if a command exists on the operating system.
    *              Used by start_process when loading the Log or History
    *              programs to check whether the gnuplot and/or the Cascade
    *              TextLogger program is installed on the system.  Also
    *              used by program_startup to check that the Cascade
    *              DataHub and Cascade Historian are installed.
    *------------------------------------------------------------------*/
   function find_on_path(name)
   {
      local bin_path = string_split (getenv("PATH"), ":", 0);
      local found;
   
      for (; !found && bin_path; bin_path = cdr(bin_path))
      {
        if (access (string(car(bin_path),"/",name), 0) == 0)
          found = car(bin_path);
      }
      found;
    }