OS之子进程简单模拟shell解释环境(再次)

(1)当输入一条指令后,将指令拆分成独立的符号;

(2)如果指令的最后一个符号是’&’,则(4)子进程执行指令的时候,父进程将不会wait()子进程执行完毕,继续接收下一条指令进行解释;

(3)History指令由主程序使用循环队列进行维护,最多只记录10条历史指令;'!!'执行最近执行过的指令,'! + 数字'执行对应的历史指令;

(4)如果是非history指令,fork()一个子进程,调用execvp()进行解释执行;

一、主程序

/*
** FILE: osh.c
** NOTE: 2016-01-11 created by Jack Liu
** DESC: 
*/
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"history.h"

#define MAX_HISTORY 10 

/* how many stokens */
int stoken_cmd_num( char *cpCmd );
/* split the command into stokens */
char **stoken_cmd( char *cpCmd, int *iTokenNum );
/* remember the command */
int do_history( char *cpCmd, PHISTORY_LIST pHistory );
/* when children terminate, recycle it */
void child_fun( int sig );

int
main( void )
{
    char caCmd[ MAX_CMD ];
    char **cppCmdStokens;
    pid_t pid;
    int  iTokenNum;
    int  iConcurrent;
    struct sigaction newSigAct, oldSigAct;
    HISTORY_LIST history;

    newSigAct.sa_handler = child_fun; 
    if( sigaction( SIGCHLD, &newSigAct, &oldSigAct ) < 0 )
    {
        perror( "sigaction" );
        return -1;
    }

    if( history_init( &history, MAX_HISTORY ) < 0 )
    {
        fprintf( stderr, "fail to init history list\n" );
        return -1;
    }

    while( 1 )
    {
        int i = 0;
        iConcurrent = 0;
        printf( "osh>" );

        /*
        ** get the input command 
        */
        if( fgets( caCmd, MAX_CMD, stdin ) == NULL )
        {   /* the user want to exit, ctrl + D */
            putchar( '\n' );
            break;
        }
        if( caCmd[ strlen( caCmd ) - 1 ] == '\n' )
            caCmd[ strlen( caCmd ) - 1 ] = '\0';

        if( caCmd[ 0 ] == '\0' )  /* just input enter, ignore it */
            continue;

        /*
        ** record the command
        */
        if( do_history( caCmd, &history ) < 0 )
            continue;

        /*
        ** split the command
        */
        if( strcmp( caCmd, "exit" ) == 0 )
        {   /* the user want to exit, input exit */
            break;
        }

        cppCmdStokens = stoken_cmd( caCmd, &iTokenNum );
        if( cppCmdStokens == NULL )
        {
            fprintf( stderr, "couldn't recognize: %s\n", caCmd );
            continue;
        }

        /*
        ** fork a child to exec the command
        ** or 
        ** print the history commands
        */
        if( cppCmdStokens[ iTokenNum - 2 ][ strlen( cppCmdStokens[ iTokenNum - 2 ] ) - 1 ] == '&' )
        {
            iConcurrent = 1;    /* concurrent the command */
            /*
            ** clear the '&' character
            */
            cppCmdStokens[ iTokenNum - 2 ][ strlen( cppCmdStokens[ iTokenNum - 2 ] ) - 1 ] = '\0';
            if( cppCmdStokens[ iTokenNum - 2 ][ 0 ] == '\0' )
            {   /* '&' occupy a stoken, clear the stoken */
                free( cppCmdStokens[ iTokenNum - 2 ] );
                cppCmdStokens[ iTokenNum - 2 ] = NULL;
            }
        }

        if( strcmp( cppCmdStokens[ 0 ], "history" ) == 0 )
        {
            history_print( &history );
        }
        else
        {
            if( ( pid = fork() ) < 0 )
            {
                fprintf( stderr, "fail to exec: %s\n", caCmd );
                continue;
            }
            else if( pid == 0 )
            {   /* child */
                execvp( cppCmdStokens[ 0 ], cppCmdStokens );
                fprintf( stderr, "fail to exec: %s\n", caCmd );
                exit( -1 );
            }
        }

        i = 0;
        /*
        ** clear stokens
        */
        while( cppCmdStokens[ i ] )
            free( cppCmdStokens[ i++ ] );
        free( cppCmdStokens );

        if( !iConcurrent ) /* wait the child to exec */
            waitpid( pid, NULL, 0 );
    }
    history_clear( &history );
    return 0;
}


int
stoken_cmd_num( char *cpCmd )
{
    char caTmpCmd[ MAX_CMD ];
    char *cpIndex;
    int  iNum = 0;
    if( cpCmd == NULL )
    {
        fprintf( stderr, "Illegal cmd\n" );
        return -1;
    }
    strncpy( caTmpCmd, cpCmd, MAX_CMD );

    cpIndex = strtok( caTmpCmd, " " );
    while( cpIndex )
    {
        iNum++;
        cpIndex = strtok( NULL, " " );
    }

    return iNum;
}

char **
stoken_cmd( char *cpCmd, int *iTokenNum )
{
    char caTmpCmd[ MAX_CMD ];
    char *cpIndex;
    char *cpStoken;
    char **cppStokens;
    int  iNum;
    if( cpCmd == NULL )
    {
        fprintf( stderr, "Illegal command line\n" );
        return NULL;
    }
    strncpy( caTmpCmd, cpCmd, MAX_CMD );
    if( ( iNum = stoken_cmd_num( cpCmd ) ) > 0 )
    {
        /*
        ** the last element is NULL
        */
        *iTokenNum = iNum + 1;
        cppStokens = malloc( sizeof( char * ) * ( iNum + 1 ) );
        if( cppStokens == NULL )
        {
            perror( "malloc" );
            return NULL;
        }
    }
    else
    {
        fprintf( stderr, "Illegal command line\n" );
        return NULL;
    }
    memset( cppStokens, 0x00, sizeof( char * ) * ( iNum + 1 ) );

    /*
    ** begin to split
    */
    iNum = 0;
    cpIndex = strtok( caTmpCmd, " " );
    while( cpIndex )
    {
        if( ( cpStoken = malloc( strlen( cpIndex ) + 1 ) ) == NULL )
        {
            int i;
            for( i = 0; i < iNum; i++ )
                free( cppStokens[ i ] );
            free( cppStokens );
            perror( "malloc" );
            return NULL;
        }
        memset( cpStoken, 0x00, strlen( cpIndex ) + 1 );
        strcpy( cpStoken, cpIndex ); 
        cppStokens[ iNum++ ] = cpStoken;
        cpIndex = strtok( NULL, " " );
    }
    cppStokens[ iNum ] = NULL; 

    return cppStokens;
}

int 
do_history( char *cpCmd, PHISTORY_LIST pHistory )
{
    PHISTORY_RECORD pRecord;
    int iIndex = -1;
    char caTmpCmd[ MAX_CMD ] = { 0 };
    if( cpCmd[ 0 ] == '!' )
    {
        memcpy( caTmpCmd, cpCmd + 1, strlen( cpCmd ) ); /* include the NULL-terminated */
        if( strcmp( caTmpCmd, "!" ) != 0 )
            iIndex = atoi( caTmpCmd );
        else
            iIndex = 1; 

        if( iIndex <= 0 || iIndex > pHistory->iLen )
        {
            fprintf( stderr, "no such history command\n" );
            return -1;
        }

        pRecord = history_index( pHistory, iIndex );
        if( pRecord == NULL )
        {
            fprintf( stderr, "no such history command\n" );
            return -1;
        }
        strcpy( cpCmd, pRecord->cpCmd );
    }
    else
    {   /* record the command */
        pRecord = history_get_record( cpCmd );
        history_pushback( pHistory, pRecord );
    }

    return 0;
}

void
child_fun( int sig )
{
    waitpid( -1, NULL, WNOHANG ); 
}

二、history队列维护头文件

/*
** FILE: history.h
** NOTE: 2016-01-11 created by Jack Liu
** DESC: manage the historic commands up to 10
*/
#ifndef COM_JACKLIU_HISTORY_H
#define COM_JACKLIU_HISTORY_H

#define MAX_CMD 512

typedef struct history_record
{
    char cpCmd[ MAX_CMD ];
    struct history_record *prev;
    struct history_record *next;
} HISTORY_RECORD, *PHISTORY_RECORD; 

typedef struct history_list
{
    PHISTORY_RECORD front;
    PHISTORY_RECORD rear;
    int iLen;
    int iMax;
} HISTORY_LIST, *PHISTORY_LIST;

int history_init( PHISTORY_LIST list, int iMax );
PHISTORY_RECORD history_get_record( char *cpCmd );
int history_pushback( PHISTORY_LIST list, PHISTORY_RECORD record ); 
PHISTORY_RECORD history_pop( PHISTORY_LIST list );
PHISTORY_RECORD history_front( PHISTORY_LIST list );
PHISTORY_RECORD history_index( PHISTORY_LIST list, int iIndex );
int history_print( PHISTORY_LIST list );
int history_clear( PHISTORY_LIST list );

#endif

三、history队列维护实现

/*
** FILE: history.c
** NOTE: 2016-01-11 created by Jack Liu
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "history.h"

int
history_init( PHISTORY_LIST list, int iMax )
{
    if( list == NULL )
    {
        fprintf( stderr, "history operation: init error, list argument illegal\n" );
        return -1;
    }
    list->front = list->rear = NULL;
    list->iLen = 0;
    list->iMax = iMax;

    return 0;
}

PHISTORY_RECORD
history_get_record( char *cpCmd )
{
    PHISTORY_RECORD pRecord;

    pRecord = malloc( sizeof( HISTORY_RECORD ) );
    if( pRecord == NULL )
    {
        perror( "malloc" );
        return NULL;
    }
    memset( pRecord, 0x00, sizeof( HISTORY_RECORD ) );

    strcpy( pRecord->cpCmd, cpCmd );
    return pRecord;
}

int
history_pushback( PHISTORY_LIST list, PHISTORY_RECORD pRecord )
{
    if( list == NULL || pRecord == NULL )
    {
        fprintf( stderr, "illegal operation: list is empty\n" );
        return -1;
    }

    if( list->rear == NULL )
    {   /* first record */
        list->front = pRecord;
        pRecord->prev = pRecord->next = NULL;
    }
    else
    {
        list->rear->next = pRecord;
        pRecord->prev = list->rear;
        pRecord->next = NULL;
    }
    list->rear = pRecord;
    list->iLen++;
    if( list->iLen > list->iMax )
    {
        PHISTORY_RECORD pToFree = list->front;
        list->front = list->front->next;
        list->front->prev = NULL;
        free( pToFree );
        list->iLen = list->iMax;
    }

    return 0;
}

PHISTORY_RECORD
history_pop( PHISTORY_LIST list )
{
    PHISTORY_RECORD pRecord;
    if( list == NULL )
    {
        fprintf( stderr, "history operation: list is illegal\n" );
        return NULL;
    }

    if( list->rear == NULL )
        return NULL; /* the history list is emtpy */

    pRecord = list->rear;
    list->rear = list->rear->prev;

    if( list->rear == NULL ) /* now list is empty */
        list->front = NULL;
    else
        list->rear->next = NULL;

    return pRecord;
}

PHISTORY_RECORD
history_front( PHISTORY_LIST list )
{
    PHISTORY_RECORD pRecord;
    if( list == NULL )
    {
        fprintf( stderr, "history operation: list is illegal\n" );
        return NULL;
    }

    if( list->front == NULL )
        return NULL;     /* history list is empty */

    pRecord = list->front;
    list->front = list->front->next;

    if( list->front == NULL ) /* now list is empty */
        list->rear = NULL;
    else
        list->front->prev = NULL;

    return pRecord;
}

PHISTORY_RECORD
history_index( PHISTORY_LIST list, int iIndex )
{
    PHISTORY_RECORD pRecord;
    int i;
    if( list == NULL )
    {
        fprintf( stderr, "history operation: list is illegal\n" );
        return NULL;
    }

    if( list->front == NULL )
    {
        fprintf( stderr, "history operation: list is emtpy\n" );
        return NULL;
    }

    if( iIndex > list->iLen )
    {
        fprintf( stderr, "no such history command\n" );
        return NULL;
    }

    i = 1;
    pRecord = list->rear;
    while( ++i <= iIndex )
        pRecord = pRecord->prev; 

    return pRecord;
}

int
history_print( PHISTORY_LIST list )
{
    PHISTORY_RECORD pRecord;
    int i;
    if( list == NULL )
    {
        fprintf( stderr, "history operation: history list is empty\n" );
        return -1;
    }

    i = list->iLen;
    pRecord = list->front;
    while( i > 0 )
    {
        printf( "%02d %s\n", i--, pRecord->cpCmd ); 
        pRecord = pRecord->next;
    }


    return 0;
}

int
history_clear( PHISTORY_LIST list )
{
    if( list != NULL )
    {
        PHISTORY_RECORD pRecord;
        while( ( pRecord = history_front( list ) ) )
            free( pRecord );
    }

    return 0;
}

四、源代码

http://download.csdn.net/detail/qq123386926/9401186

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值