views:

101

answers:

2

I have to add a custom function which shows currently running foreground and background processes launched by this shell. How do I define and call that function from the shell's command line?

   a#include "smallsh.h" /*include file for example*/

/*program buffers and work pointers*/
static char inpbuf[MAXBUF], tokbuf[2*MAXBUF],
*ptr = inpbuf, *tok = tokbuf;

userin(p) /*print prompt and read a line*/
char *p;
{

  int c, count;

  /*initialization for later routines*/
  ptr = inpbuf;
  tok = tokbuf;

  /*display prompt*/
  printf("%s ",p);

  for(count = 0;;)
  {
    if((c = getchar()) == EOF)
      return(EOF);

    if(count<MAXBUF)
      inpbuf[count++] = c;

    if(c == '\n' && count <MAXBUF)
    {
      inpbuf[count] = '\0';
      return(count);
    }

    /*if line too long restart*/
    if(c == '\n')
    {
      printf("smallsh:input line too long\n");
      count = 0;
      printf("%s",p);
    }
  }
}

gettok(outptr) /*get token and place into tokbuf*/
char **outptr;
{
  int type;

*outptr = tok;

/*strip white space*/
for(;*ptr == ' ' || *ptr == '\t'; ptr++)
  ;

*tok++ = *ptr;

  switch(*ptr++)
  {
    case '\n':
      type = EOL; break;
    case '&':
      type = AMPERSAND; break;
    case ';':
      type = SEMICOLON; break;
    case '#':
      type = POUND; break;
    default:
      type = ARG;
      while(inarg(*ptr))
        *tok++ = *ptr++;
  }

*tok++ = '\0';
return(type);
}

static char special[]=
{' ', '\t', '&', ':', '\n', '\0'};

inarg(c) /*are we in an ordinary argument*/
char c;
{
  char *wrk;

  for(wrk = special;*wrk != '\0';wrk++)
    if(c == *wrk)
      return(0);

    return(1);
}

#include "smallsh.h"

procline() /*process input line*/
{
  char *arg[MAXARG+1]; /*pointer array for runcommand*/
  int toktype; /*type of token in command*/
  int narg; /*number of arguments so far*/
  int type; /*FOREGROUND or BACKGROUND*/

  for(narg = 0;;)
  {
    /*loop FOREVER*/

    /*take action according to token type*/

    switch(toktype = gettok(&arg[narg]))
    {
      case ARG:

      if(narg<MAXARG)
        narg++;
      break;

      case EOL:
      case SEMICOLON:
      case AMPERSAND:
      case POUND:

        type = (toktype == AMPERSAND) ?
        BACKGROUND : FOREGROUND;

        if(narg!=0)
        {
          arg[narg] = NULL;
          runcommand(arg, type);
        }

        if((toktype == EOL)||(toktype=POUND))
          return;

        narg = 0;
        break;
    }
  }
}


#include "smallsh.h"

/*execute a command with optional wait*/
runcommand(cline,where)
char **cline;
int where;
{
  int pid, exitstat, ret;

  if((pid = fork()) <0)
  {
    perror("smallsh");
    return(-1);
  }

  if(pid == 0)
  {
    /*child*/
    execvp(*cline, cline);
    perror(*cline);
    exit(127);
  }

  /*code for parent*/
  /*if background process print pid and exit*/

  if(where == BACKGROUND)
  {
    printf("[Process id %d]\n", pid);
    return(0);
  }

  /*wait until process pid exists*/

  while( (ret=wait(&exitstat)) != pid && ret != -1)
    ;

  return(ret == -1 ? -1 : exitstat);
}

#include "smallsh.h"

char *prompt = "Command>"; /*prompt*/

main()
{
  while(userin(prompt) != EOF)
    procline();
}

Edit:

To try to call a function, Inside of runcommand, before the code for the child process, I tried to add another if statement saying if(cline == "dowork"){dowork();}, and tried putting in similar lines elsewhere, but nothing like that works

A: 

You could maintain a list of internal commands like:

"cd" "ls" and check the user input against this list, if an internal command is regonized simply call the function that implements the internal command.

EDIT: I was assuming you're implementing a small shell like application.

stacker
eah, it is a small shell like application, but I'm supposed to define a command/function that provides additional functionality and then call it from the shell
@user336291 you should add the requirements to your question
stacker
I have edited the question.
+1  A: 

Since this is C, cline == "dowork" will not do what you want. You need to change that to:

if (strcmp(cline, "dowork") == 0)
{
    ...
}

If you wanted your shell to also handle "DOWORK", "DoWork", etc. you can replace strcmp with strcasecmp.

Update: since you have char **cline, you need to change that to:

if (strcmp(*cline, "dowork") == 0)

Also, you should be compiling with warnings - if you do that the compile will have told you you had a type mismatch here.

R Samuel Klatchko
Where exactly would this go? I placed it like so at the front of runcommand:runcommand(cline,where)char **cline;int where;{int pid, exitstat, ret;if(strcasecmp(cline, "dowork")==0){   dowork(proclist);}if((pid = fork()) <0){   perror("smallsh");   return(-1);}And it simply printed another line of the command prompt
@user336291 - updated answer.
R Samuel Klatchko