LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   writing a shell (https://www.linuxquestions.org/questions/programming-9/writing-a-shell-28914/)

hopeless 08-27-2002 02:43 PM

writing a shell
 
Hi
I have to write a shell for a computer science prac. I have no clue what to do. Please could someone help. I especially need help with implementing the command execution facility by parsing the command line.
I also need help with implementing the path search capability.
I need help by tomorrow.
Please help!!

acid_kewpie 08-27-2002 02:55 PM

that's not really going to happen is it? a few people have asked this before, have a search. you won't find much useful information though, seeing as it's a pretty vast thing to ask for.

lackluster 08-27-2002 04:32 PM

I found the Bash code pretty helpful. I wish I could give you a link to it but I don't have it. If you want the tarball, I think I have that.

no2nt 08-30-2002 08:22 AM

This is a derivative from a previous post I made. Shows command line
parsing (with "" support) and process forking (background procs not
implemented).

Code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

typedef enum bool {false, true} bool;

/* prototype declarations */
int parseArguments(const char *, char *, int *, int *);
   
int main( int argc, char *argv[] )
{
    char cmdStr[256], *user, hostname[256], pwd[256];
    int backgroundJobs = 0;

    memset(hostname, 0x00, sizeof(hostname));
    memset(pwd, 0x00, sizeof(pwd));

    gethostname(hostname, sizeof(hostname));
    user = (char *)getenv("USER");

    if( user == NULL )
    {
        strcpy(user, "unknown");
    }

    while(1)
    {
        char *progArgsArray[256], arg[256], *placeholder;
        int index = 0, sz, ret, i=0;
       
        getcwd(pwd, sizeof(pwd));
        printf("<%s@%s %s> ", user, hostname, pwd);
        memset(cmdStr, 0x00, sizeof(cmdStr));
       
        /*
        * use fgets instead of gets. don't wanna be exploitable!
        *
        * remember that fgets traps everything typed into the command
        * line, event the carriage return!
        */
        fgets(cmdStr, sizeof(cmdStr), stdin);

        /*
        * take command line and split it into parts.
        * executable is put in execCmd.
        * args are put in dynamic arg array.
        */
        if( cmdStr[strlen(cmdStr)-1] == '\n' )
        {
            cmdStr[strlen(cmdStr)-1] = 0x00; // remove that carriage return
        }

        i = 0;
        sz = sizeof(arg);
        ret = parseArguments(cmdStr, arg, &sz, &index);
        placeholder = (char *)calloc(1, strlen(arg)+1);
        strcpy(placeholder, arg);
        progArgsArray[i] = placeholder;
        i++;

        /*
        * this is bad coding. fix it.
        */
        while( ret == 0 )
        {
            sz = sizeof(arg);
            ret = parseArguments(cmdStr, arg, &sz, &index);
            if( ret == 0 )
            {
                placeholder = NULL;
                placeholder = (char *)calloc(1, strlen(arg)+1);
                strcpy(placeholder, arg);
                progArgsArray[i] = placeholder;
                i++;
            }
        }

        progArgsArray[i] = NULL;

        if( strcmp("quit", progArgsArray[0]) == 0 )
        {
            if( backgroundJobs > 0 )
            {
                printf("background jobs still running\n");
            }
            else
            {
                // exit the shell
                break;
            }
        }
        else if( strcmp("cd", progArgsArray[0]) == 0 )
        {
            if( chdir(progArgsArray[1]) == -1 )
            {
                printf("operation not permitted\n");
            }
        }
        else if( strlen(progArgsArray[0]) > 0 )
        {
            pid_t cpid;

            /*
            * fork and attempt to execute the command
            */
            cpid = fork();

            switch(cpid)
            {
                case -1: // oops
                {
                    printf("Unable to claim system resources.\n");
                    break;
                }
                case 0: // i am child process
                {
                    // call execvp to start the user's command
                    if( execvp(progArgsArray[0], progArgsArray) == -1 )
                    {
                        switch(errno)
                        {
                            case EACCES:
                            {
                                printf("access is denied: %s\n", progArgsArray[0]);
                                break;
                            }
                            case EPERM:
                            {
                                printf("operation not permitted: %s\n", progArgsArray[0]);
                                break;
                            }
                            case ENOEXEC:
                            {
                                printf("ENOEXEC\n");
                                break;
                            }
                            case ENOENT:
                            {
                                printf("command not found: %s\n", progArgsArray[0]);
                                break;
                            }
                            default:
                            {
                                printf("Error code: %d\n", errno);
                            }
                        }
                    }

                    _exit(0);
                    break;
                }
                default: // i am parent process
                {
                    int status;

                    /*
                    if( cmdStr[strlen(cmdStr)] != '&' )
                    {
                    */
                        waitpid(cpid, &status, 0);
                    /*
                    }
                    else
                    {
                        printf("process id: %d\n", cpid);
                    }
                    */

                    /*
                    * this'll show exit status
                   
                    if( WIFEXITED(status) )
                    {
                        printf("%d [%d] exited\n", WEXITSTATUS(status), cpid);
                    }
                    */
                   
                    // this'll have to be rewritten when fg/bg are implemented
                    for( i = 0; progArgsArray[i] != NULL; i++ )
                    {
                        free(progArgsArray[i]);
                        progArgsArray[i] = NULL;
                    }
                    break;
                }
            }
        }

    }

    return 0;
}


/*
 * This function returns the next available "word" from <src> into <dest> starting
 * at <idx>. Words surrounded by "" are considered a word (spaces may exist).
 * Returns:
 *  0 = successful
 *  1 = no more words
 *  2 = destination buffer too small
 *  3 = unterminated single/double quote
 *
 * Example:
 * char src[] = "ls -al";
 * char dst[256];
 * int dst_sz = sizeof(dst);
 * int index = 0, ret;
 *
 * ret = parseArguments(src, dst, &dst_sz, &index);
 *
 * //dst == "ls"
 * //dst_sz == 2;
 * //index == 3;
 * //ret == 0;
 *
 * // call it again. remember index is now equal to 3.
 * ret = parseArguments(src, dst, &dst_sz, &index);
 *
 * //dst == "-al"
 * //dst_sz == 3;
 * //index == 6;
 * //ret == 1;
 *
 */
int parseArguments(const char *src, char *dest, int *dest_sz, int *idx)
{
    int src_len, dest_idx = 0;
    bool inQuotes = false;
    int ret = 1;

    memset(dest, 0x00, *dest_sz);
    src_len = strlen(src);

    while( *idx < src_len )
    {
        if( src[*idx] == ' ' )
        {
            //printf("      : space\n");
            if( inQuotes )
            {
                dest[dest_idx++] = src[*idx];
            }
            else if( strlen(dest) > 0 )
            {
                // we are finished, we have at least one character
                ret = 0;
                break;
            }
        }
        else if( src[*idx] == '"' )
        {
            //printf("      : double quote\n");
            inQuotes = !inQuotes;
            // are we starting or fininshing a word?
        }
        else
        {
            //printf("      : normal char \n");

            if( dest_idx < *dest_sz )
            {
                dest[dest_idx++] = src[*idx];
            }
            else
            {
                // dest buffer too small!!
                ret = 2;
                break;
            }
        }
        *idx += 1;
    }

    if( *idx >= src_len && strlen(dest) > 0 )
    {
        ret = 0;
    }

    if( inQuotes )
    {
        ret = 3;
    }
   
    return ret;
}

I guess the next step is to set the tty into raw mode for tabline
completion. background procs would be nice. command line
substitution (*, variables, etc) also.

as for the parent post.... don't tell me you waited until the day before
your project was due to rip off someone else's code? i hope i'm wrong.

hopeless 09-02-2002 04:27 AM

hi thanks for the code. NO I didn't wait till the last minute to do this. In the end I actually got it working, I worked with a group of friends. I handed it in on thurs

acid_kewpie 09-02-2002 11:40 AM

hopeless, do not ask about school questions here, we are NOT here to do your homework.

Keen_Eager 09-02-2002 11:13 PM

:confused: :newbie: :study:


Hi there

I dont mean to annoy anyone but guidance here is much appreciated. I need to do a shell script for unix.

This is what I have to do;
An electric power distribution compnay charges the domestic consumers as follows;

Consumption Units Rate of Charge
0-200 60 cents per unit

201-400 $120 plus 70 cents per unit excess of 200

401-600 $260 plus 80 cents per unit excess of 400

601 and above $420 plus $1.00 per unit excess of 600


Prepare a shell script which reads in customer number and power consumed and prints on the screen the amount to be paid by the customer(Call it powercal)
Note: Unix can carry out mathematical functions on integers only. The shell variables store numbers as integers. The student has to devise a method to display the amount in terms of dollars and cents.

All this after one lesson on scripting and I have no programming background, hence my dilemma. The other modules were fine. I just dont know where to begin and put them all together. Your help and guidance is greatly appreciated.

Regards
Keen_Eager

acid_kewpie 09-03-2002 02:04 AM

well firstly this is homework, and it's not allowed, but i guess you do clearly ask for help, not a solution, so i'll let you also. secondly welcome to lq, but please start a new thread for new questions, don't tag along on old threads.

hmm, ok then with no idea of what your input is it's pretty trivial really. to do the actual work itself you would check the value used in a block test ( [ ] ) statement, i.e if it's less that 200, less than 400 etc.... and then inside each clause you would print your output

Code:

if [ amountused -lt anothervalue ]
then
    echo blah blah blah = $(( rate * amountused ))
elif [ amountused -lt abiggervalue ]

etc...... (deliberatly vague you understand.... :))

as for getting those values, read the section about "read" way down in the bash manpage (quite near the end).

naturally there are nicer and better ways to do everything, but that's really for you to learn in your own time.

no2nt 09-03-2002 08:15 AM

Quote:

Note: Unix can carry out mathematical functions on integers only. The shell variables store numbers as integers.
(assuming you are using bash)
I don't know who told you that but they never apparently heard of $(()).
Hence...

no2nt@grep# echo $((50.0*1.25))
62.5
no2nt@grep# export a=65.1; export b=29.1; echo $(($a + $b))
94..1999999999999989

something possibly helpful for formatting floats/doubles:

no2nt@grep# echo `printf "%.2f" $((234.234 * 9092.23))`
2129709.40

welcome to lq!

Keen_Eager 09-04-2002 08:28 AM

Thank You for help, it's appreciated from a newbie like me for the only programming i have done is on a vcr. Thanks again
regards
keen_eager


All times are GMT -5. The time now is 11:25 PM.