www.pudn.com > Linuxserial.zip > cmd.c


/*
 * File         : cmd.c
 * Date         : 2002-04-20
 * Author       : yfy001
 * Description	: process commands input by user
 * Copyright (C) 2001, 2002  yfy001
 */
#include               // printf, fprintf, fgets
#include              // strcpy
#include              // NAME_MAX, CHAR_MAX
#include              // exit
#include           // pid_t
#include              // fork, vfork, _exit
#include            // wait
#include               // isspace

#include "types.h"              // p_packge_info_t, p_portinfo_t
#include "tty.h"                // tty_write
#include "prompt.h"             // prompt
#include "strings.h"            // str_nonspace
#include "cmd.h"

static void cmd_makeargv(char *cmd_line, char **argv);
static INT8 cmd_is_valid(char **argv);
static char *cmd_get_shell();

static void cmd_help(char **argv);
static void cmd_shell(char **argv);
static void cmd_display(char **argv);
static void cmd_send(char **argv);
static void cmd_open(char **argv);
static void cmd_close(char **argv);
static void cmd_clear(char **argv);
static void cmd_error(char **argv);
static void cmd_exit(char **argv);

static pid_t pid_recv;          // pid of receiving process
typedef struct {
    char *name;
    void (*func) (char **);
} cmds_t;
static cmds_t cmds[] = {
    {"bye", cmd_exit},
    {"clear", cmd_clear},
    {"close", cmd_close},
    {"display", cmd_display},
    {"exit", cmd_exit},
    {"help", cmd_help},
    {"open", cmd_open},
    {"quit", cmd_exit},
    {"usage", cmd_help},
    {"!", cmd_shell},
    {"@", cmd_send},
    {"?", cmd_help},
    {NULL, cmd_error}
};

/*
 * Arguments    : none	
 * Return value : none
 * Decription   : wait for users' input command to execute
 */
void cmd()
{
    static char *argv[NAME_MAX];
    static char cmd_line[NAME_MAX + 1];

    switch ((pid_recv = fork())) {
    case -1:
        return;
    case 0:                    // child 
        close(STDIN_FILENO);
        tty_set_sig_on();
        while (1) {
            sleep(2);
        }
        exit(0);
        break;
    default:                   // parent 
        while (1) {
            prompt();
            fgets(cmd_line, sizeof(cmd_line), stdin);
            cmd_makeargv(cmd_line, argv);
            if (!cmd_is_valid(argv))
                break;
        }
    }
}

/* 
 * Arguments    : 	
 *                argv[0]==NULL, no commands at all, just white space, return(1)
 * Return value :
 *                1, continue;
 *                0, break;
 */
static INT8 cmd_is_valid(char **argv)
{
    cmds_t *cmdp = cmds;
    if (NULL == *argv)
        return 1;
    while (cmdp->name && strcmp(*argv, cmdp->name)) {
        cmdp++;
    }
    cmdp->func(argv);
    return 1;
}

/*
 * Arguments    :
 *                argv[0]: pointer to shell name
 * Return value : none
 * Description  : execute a comman in a sub shell
 */
static void cmd_shell(char **argv)
{
    char **shell_argv = argv;
    char *cmd_line = argv[1];
    char *cp = str_fnws(cmd_line);

    *argv++ = cmd_get_shell();
    if (*cp) {                  // with extra arguments
        *argv++ = "-c";
        *argv++ = cp;
    }
    *argv = NULL;

    switch (fork()) {
    case -1:
        perror("Fork failed\r\n");
        break;
    case 0:
        {
            execvp(shell_argv[0], shell_argv);
            perror("execvp");
            _exit(1);
        }
    default:
        wait((int *) 0);        // Wait for the shell to complete 
        break;
    }
}

/*
 * Arguments    : char *cmd_line, char **argv
 * Description  :
 *                argv[0]: stores first command
 *                argv[0]: NULL, no command, just white space
 * Return value : none
 */
static void cmd_makeargv(char *cmd_line, char **argv)
{
    char *cp = cmd_line;
    int newword = 1;

    cp = str_fnws(cp);
    if ('!' == *cp || '@' == *cp || '?' == *cp) {
        *argv++ = *cp == '!' ? "!" : *cp == '@' ? "@" : "?";
        *argv++ = ++cp;
        *argv = NULL;
        return;
    }

    for (newword = 1; *cp; cp++) {
        if (isspace(*cp)) {
            *cp = '\0';
            newword = 1;
        } else if (newword) {
            newword = 0;
            *argv++ = cp;
        }
    }
    *argv = NULL;
}

/*
 * Arguments    : char **argv 
 * Return value : none
 * Description  : show help message;
 */
static void cmd_help(char **argv)
{
    char *program_name = basename(p_args->p_pkginfo->program_name);
    fprintf(stdout,
            "Commands are:\n\n" "clear  \t\tclear screen\n"
            "close  \t\tclose an open serial port\n"
            "display\t\tdisplay operating parameters\n"
            "exit   \t\texit %s\n" "help   \t\tprint help information\n"
            "open   \t\topen a serail port\n" "quit   \t\tquit %s\n"
            "@      \t\tsend messages\n"
            "!      \t\tinvoke a subshell, example: !ls /bin /usr\n"
            "?      \t\tprint help information\n", program_name,
            program_name);
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : display operating parameters
 */
static void cmd_display(char **argv)
{
    portinfo_t *p_port = p_args->p_portinfo;
    printf("\n"
           "baudrate   \t%d\n"
           "databit    \t%d\n"
           "debug      \t%s\n"
           "echo       \t%s\n"
           "flowcontrol\t%s\n"
           "parity     \t%s\n"
           "prompt     \t%s\n"
           "stopbit    \t%d\n"
           "tty        \tttyS%d\n",
           p_port->baudrate,
           p_port->databit,
           p_port->debug ? "on" : "off",
           p_port->echo ? "on" : "off",
           p_port->fctrl == 0 ? "none" : p_port->fctrl ==
           1 ? "hardware" : "software",
           p_port->parity == 0 ? "none" : p_port->parity ==
           1 ? "odd" : "even",
           p_port->prompt ? "on" : "off", p_port->stopbit, p_port->tty);
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : send data
 */
static void cmd_send(char **argv)
{
    char *data = *++argv;
    int retval = tty_write(data, strlen(data));
    if (E_NOTOPEN == retval) {
        fprintf(stderr, "/dev/ttyS%d is not open\n",
                p_args->p_portinfo->tty);
    } else if (strlen(data) != retval) {
        fprintf(stderr, "cannot send data correctly\n");
    }
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : open a serial port and then print success or failure.
 */
static void cmd_open(char **argv)
{
    int retval = 0;
    retval = tty_open(p_args->p_portinfo);
    if (retval) {
        fprintf(stderr,
                "Make sure /dev/ttyS%d "
                "not in use or you have enough privilege.\n\n",
                p_args->p_portinfo->tty);
    } else {
        printf("/dev/ttyS%d opened\n", p_args->p_portinfo->tty);
    }
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : close com port and print whether it is successful.
 */
static void cmd_close(char **argv)
{
    tty_close();
    printf("/dev/ttyS%d closed\n", p_args->p_portinfo->tty);
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : print error message if coming accross invalid command
 */
static void cmd_error(char **argv)
{
    char *command = *argv;
    fprintf(stderr,
            "Invalid command: %s\n"
            "type \"?\" to show commands\n", command);
}

/* 
 * Arguments    : char **argv
 * Return value : none 
 * Description  : reset  and clear the screen
 */
static void cmd_clear(char **argv)
{
    argv[0] = "!";
    argv[1] = "reset >/dev/null 2>&1";
    argv[2] = NULL;
    cmd_shell(argv);
    argv[0] = "!";
    argv[1] = "clear";
    argv[2] = NULL;
    cmd_shell(argv);
}

/*
 * Arguments    : none
 * Return value : char *shellp pointer to shell path and name
 */
static char *cmd_get_shell()
{
    char *shellp = getenv("SHELL");
    return shellp ? shellp : "/bin/sh";
}

/*
 * Arguments    : char **argv
 * Return value : none
 * Description  : close child process receive, and exit
 */
static void cmd_exit(char **argv)
{
    if (pid_recv > 0)
        kill(pid_recv, SIGTERM);        // terminate recv process 
    exit(0);
}