#### 29.5.1 Data Structures for the Shell ¶

All of the program examples included in this chapter are part of a simple shell program. This section presents data structures and utility functions which are used throughout the example.

The sample shell deals mainly with two data structures. The `job` type contains information about a job, which is a set of subprocesses linked together with pipes. The `process` type holds information about a single subprocess. Here are the relevant data structure declarations:

    /* A process is a single process.  */
    typedef struct process
    {
      struct process *next;       /* next process in pipeline */
      char **argv;                /* for exec */
      pid_t pid;                  /* process ID */
      char completed;             /* true if process has completed */
      char stopped;               /* true if process has stopped */
      int status;                 /* reported status value */
    } process;

    /* A job is a pipeline of processes.  */
    typedef struct job
    {
      struct job *next;           /* next active job */
      char *command;              /* command line, used for messages */
      process *first_process;     /* list of processes in this job */
      pid_t pgid;                 /* process group ID */
      char notified;              /* true if user told about stopped job */
      struct termios tmodes;      /* saved terminal modes */
      int stdin, stdout, stderr;  /* standard i/o channels */
    } job;

    /* The active jobs are linked into a list.  This is its head.   */
    job *first_job = NULL;

Here are some utility functions that are used for operating on `job` objects.

    /* Find the active job with the indicated pgid.  */
    job *
    find_job (pid_t pgid)
    {
      job *j;

      for (j = first_job; j; j = j->next)
        if (j->pgid == pgid)
          return j;
      return NULL;
    }

    /* Return true if all processes in the job have stopped or completed.  */
    int
    job_is_stopped (job *j)
    {
      process *p;

      for (p = j->first_process; p; p = p->next)
        if (!p->completed && !p->stopped)
          return 0;
      return 1;
    }

    /* Return true if all processes in the job have completed.  */
    int
    job_is_completed (job *j)
    {
      process *p;

      for (p = j->first_process; p; p = p->next)
        if (!p->completed)
          return 0;
      return 1;
    }