// ps.C: Process table management, ps command, etc.

#include "shell.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

process* ptable=NULL;

//:::::::::::::::::::::::::::::: addproc :::::::::::::::::::::::::::::::://
/* Function:  addproc()
 * Purpose:   Adds a process record to the process table linked list.
 * Returns:   n/a
 * Uses:      str* (string.h)
 */

void addproc(pid_t pid,char* name)
{
  process* newproc=new process;           // Build a new process entry.
  newproc->pid=pid;
  newproc->name=new char[(strlen(name)+1)];
  strcpy(newproc->name,name);
  newproc->next=NULL;

  if (ptable)
    {
      process* i=ptable;
      while (1)
	{
	  if (i->next) 
	    i=i->next;
	  else
	    break;
	}
      i->next=newproc;                  // and add the new one.
    }
  else
    ptable=newproc;
}

//::::::::::::::::::::::::::::::: rmproc ::::::::::::::::::::::::::::::::://
/* Function:  rmproc()
 * Purpose:   Removes a process record from the process table linked list.
 * Returns:   n/a
 * Uses:      str* (string.h)
 */

void rmproc (pid_t pid)
{
  process* i=ptable,*prevproc=ptable;
  if (ptable)
    while (1)
      { 
	if (i->pid==pid)
	  {
	    if (i=ptable) 
	      ptable=NULL;
	    else
	      prevproc->next=i->next;
	    break;
	  }
	if (i->next)
	  {
	    prevproc=i;
	    i=i->next;
	  }
	else
	  break;
      }
}

//:::::::::::::::::::::::::::::::::: ps :::::::::::::::::::::::::::::::::://
/* Function:  ps()
 * Purpose:   Displays the process table linked list.
 * Returns:   n/a
 * Uses:      stdio        h)
 */

void ps()
{
  printf(" PID\tCOMMAND\n");
  if (ptable) 
    {
      process* i=ptable;
      while (1)
	{
	  printf (" %i\t%s\n",i->pid,i->name);
	  if (! i->next) break;
	  i=i->next;
	}
    }
   else
   printf("(No processes.)\n");
}

//:::::::::::::::::::::::::::: find_exit ::::::::::::::::::::::::::::::::::://
/* Function:  find_exit()
 * Purpose:   Invoked when the prompt is displayed; looks for processes that
 *            are still in the process table but have exited.  Notifies the 
 *            user.
 * Returns:   n/a
 * Uses:      rmproc, etc.
 */

void find_exit ()
{
  int status;
  process* i=ptable;
  if (ptable)
    while (1)
      {
	process* next=i->next;
	status=0;
	if ( waitpid (i->pid, &status, WNOHANG) != 0 )
  	  {
	    printf ("[%i]  done\t%s\n",i->pid,i->name);
	    rmproc (i->pid);
	  }
        if (!next) break;
        i=next;
      }
}

//::::::::::::::::::::::::::::::: kill ::::::::::::::::::::::::::::::::::::://
/* Function:  kill_pid()
 * Purpose:   Kills a process.
 * Returns:   n/a
 * Uses:      kill(), stdio.
 */

void kill_pid(char* args)
{
   int pid;  
   sscanf(args,"%d", &pid);
   if (kill (pid,SIGKILL) != 0)
   perror("kill");
}
