Был дан этот код на SO, но как сделать так, чтобы он выводился на стандартный вывод? - PullRequest
0 голосов
/ 08 апреля 2011

добрый пользователь дал мне немного кода для работы с оболочкой командной строки, но я хочу, чтобы он выводил значения stdout и stderr вместо использования экрана или чего-либо еще, что он делает сейчас.Я новичок в C, поэтому я ничего не знаю о его преобразовании.Мне также нужна его способность обнаруживать сохраненные клавиши со стрелками ... Я пытаюсь сделать упрощенный клон Bash.Это то, что у меня есть сейчас, это примерно 50% моего кода и 50% других ... да, это глючит.Есть большие закомментированные разделы, потому что они больше не использовались или потому что они были сломаны.Игнорируй их.:)

Особая трудность заключается в использовании draw_frame() в main().

#include "os1shell.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> /* standard unix functions, like getpid()       */
#include <sys/types.h>  /* various type definitions, like pid_t         */
#include <signal.h> /* signal name macros, and the kill() prototype */
#include <ncurses/curses.h> /* a library for cursor-based programs  */

#include <poll.h>
#include <termios.h>
#include <time.h>

/** VT100 command to clear the screen. Use puts(VT100_CLEAR_SCREEN) to clear
 *  the screen. */
#define VT100_CLEAR_SCREEN "\033[2J"

/** VT100 command to reset the cursor to the top left hand corner of the
 *  screen. */
#define VT100_CURSOR_TO_ORIGIN "\033[H"

struct frame_s {
int x;
int y;
char *data;
};

char* inputBuffer;  /* the command input buffer, will be length 65 and null
                * terminated. */
char** cmdHistory;  /* the command history, will be no longer than 20
                * elements and null terminated. */
int historySize = 0;

void addToHistory(char* newItem) {
    char** h;
    int historySize = 0;
    for (historySize; historySize < 21; ++historySize) {
        if (cmdHistory[historySize] == NULL) break;
    }
    if (historySize == 20) {
        char** newPtr = cmdHistory + sizeof(char *);
        free(cmdHistory[0]);
        cmdHistory = newPtr;
        h = (char**)realloc(cmdHistory,21*sizeof(char *));
        cmdHistory = h;
        cmdHistory[19] = newItem;
        cmdHistory[20] = NULL;
    } else {
        h = (char**)realloc(cmdHistory,(historySize+2)*sizeof(char *));
        cmdHistory = h;
        cmdHistory[historySize] = newItem;
        cmdHistory[historySize+1] = NULL;
    }
}

/* Some help from http://stackoverflow.com/users/1491/judge-maygarden*/
char** getArguments(char* input) {
    char** arguments;
    int k = 0;
    char* tokenized;
    arguments = calloc(1, sizeof (char *));
    tokenized = strtok(input, " &");
    while (tokenized != NULL) {
        arguments[k] = tokenized;
        ++k;
        arguments = realloc(arguments, sizeof (char *) * (k + 1));            
        tokenized = strtok(NULL, " &");
    }

    // an extra NULL is required to terminate the array for execvp()
    arguments[k] = NULL;

    return arguments;
}

void printHistory(struct frame_s *frame) {
    snprintf(frame->data, frame->x, "\n\n");
    char** currCmd = cmdHistory;
    while (*currCmd != NULL) {
        snprintf(frame->data[(2*frame->x)], frame->x, "%s\n", *currCmd);
        currCmd++;
    }
    snprintf(frame->data, frame->x, "\n\n");
}

/* Some help from http://stackoverflow.com/users/659981/ben*/
static int draw_frame(struct frame_s *frame) {
    int row;
    char *data;
    int attrib;

    puts(VT100_CLEAR_SCREEN);
    puts(VT100_CURSOR_TO_ORIGIN);

    for (   row = 0, data = frame->data;
        row  < frame->y;
        row++, data += frame->x ) {
        //  0 for normal, 1 for bold, 7 for reverse.
        attrib = 0;

        //  The VT100 commands to move the cursor, set the attribute,
        //  and the actual frame line.
        fprintf(    stdout,
                "\033[%d;%dH\033[0m\033[%dm%.*s",
                row + 1,
                0,
                attrib, frame->x, data);
        fflush(stdout);
    }

    return (0);
}

/* Some help from http://stackoverflow.com/users/659981/ben*/
int main(void) {
    const struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
    struct frame_s frame;
    struct termios tty_old;
    struct termios tty_new;
    unsigned char line[65];     // the input buffer
    unsigned int count = 0;     // the count of characters in the buff
    int ret;
    struct pollfd fds[1];
    sigset_t sigmask;
    struct tm *tp;
    time_t current_time;

    cmdHistory = (char**)calloc(21,sizeof(char *)); // initialize the
                            // command history
    cmdHistory[20] = NULL;      // null terminate the history
    int histInd = 0;        // an index for the history for arrows

    int t;
    int r;
    char** downTemp;
    char** enterTemp;

    //  Set up a little frame.
    frame.x = 80;
    frame.y = 32;
    frame.data = malloc(frame.x * frame.y);

    if (frame.data == NULL) {
        fprintf(stderr, "No memory\n");
        exit (1);
    }

    memset(frame.data, ' ', frame.x * frame.y);

    //  Get the terminal state.
    tcgetattr(STDIN_FILENO, &tty_old);
    tty_new = tty_old;

    //  Turn off "cooked" mode (line buffering) and set minimum characters
    //  to zero (i.e. non-blocking).
    tty_new.c_lflag &= ~ICANON;
    tty_new.c_cc[VMIN] = 0;

        // Set the terminal attributes.
        tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);

    //  Un-mask all signals while in ppoll() so any signal will cause
    //  ppoll() to return prematurely.
    sigemptyset(&sigmask);

    fds[0].events = POLLIN;
    fds[0].fd = STDIN_FILENO;

    // Loop forever waiting for key presses. Update the output on every key
    // press and every 1.0s (when ppoll() times out).
    do {
        fd_set rdset;
        int nfds = STDIN_FILENO + 1;

        FD_ZERO(&rdset);
        FD_SET(STDIN_FILENO, &rdset);
        ret = pselect(nfds, &rdset, NULL, NULL, &timeout, &sigmask);

        if (ret < 0) {          // check for pselect() error.
            if (errno == EINTR) {
                continue;
            } else {
                break;
            }
        }

        if (FD_ISSET(STDIN_FILENO, &rdset)) {
            ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);

//  do {
//      fds[0].revents = 0;
//      ret = poll(fds, sizeof(fds) / sizeof(struct pollfd), 1000);
//
//      if (fds[0].revents & POLLIN) {
//          ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);

            if (ret > 0) {
                line[count + ret] = '\0';

                if (strcmp(&line[count], "\033[A") == 0) {
                    if (histInd > 0) {
                        --histInd;
                    }
                    count = 0;
                    if(cmdHistory[histInd]!=NULL) {
                        snprintf(&frame.data[(2*frame.x)],
                            frame.x,
                            "hist: %s",
                            cmdHistory[histInd]);
                        strcpy(line, cmdHistory[histInd]);
                    }
                } else if (strcmp(&line[count],"\033[B")==0) {
                    char** downTemp = cmdHistory;
                    r = 0;
                    while (*downTemp != NULL) {
                        ++downTemp;
                        ++r;
                    }
                    if (histInd < r-1 && r!= 0) {
                        ++histInd;
                    }
                    count = 0;
                    if(cmdHistory[histInd]!=NULL) {
                        snprintf(&frame.data[(2*frame.x)],
                            frame.x,
                            "hist: %s",
                            cmdHistory[histInd]);
                        strcpy(line, cmdHistory[histInd]);
                    }
                } else if (line[count] == 127) {
                    if (count != 0) {
                        line[count] = '\0';
                        count -= ret;
                    }
                    snprintf(&frame.data[(2*frame.x)], frame.x, "backspace");
                } else if (line[count] == '\n') {
                    char** arguments = getArguments(line);
                    snprintf(   &frame.data[(2*frame.x)],
                            frame.x, 
                            "entered: %s",
                            line);
                    if (count > 0) {
                        int hasAmpersand = 0;
                        char* cmd = (char*)
                            malloc(65*sizeof(char));
                        strcpy(cmd, line);
                        addToHistory(cmd);
                        /*
                        char* temp = cmd;
                        while (*temp != '\0') {
                            if (*temp == '&') {
                                hasAmpersand = 1;
                            }
                            ++temp;
                        }
                        pid_t pid;
                        pid = fork();
                        if (pid == 0) {
                            int exeret;
                            exeret = execvp(*arguments, 
                                    arguments);
                            if (exeret < 0) {
                                snprintf(
                                    &frame.data[
                                        (2*frame.x)],
                                    frame.x,
                                    "Exec failed.\n\n");
                                exit(1);
                            }
                        } else if (pid < 0) {
                            snprintf(
                                &frame.data[
                                    (2*frame.x)],
                                frame.x,
                                "Fork failed.\n\n");
                            exit(1);
                        } else if (pid > 0) {
                            if (!hasAmpersand) {
                                wait(NULL);
                            }
                            free(arguments);
                            snprintf(frame.data,
                                frame.x,
                                "\n\n");
                        }*/
                    } else {
                        free(arguments);
                    }
                    enterTemp = cmdHistory;
                    t = 0;
                    while (*enterTemp != NULL) {
                        ++enterTemp;
                        ++t;
                    }
                    if (t > histInd) histInd = t;
                    count = 0;
                } else {
                    //snprintf( frame.data,
                    //      frame.x, 
                    //      "char: %c",
                    //      line[count]);
                    count += ret;
                }
            }
        }

        // Print the current time to the output buffer.
        //current_time = time(NULL);
        //tp = localtime(&current_time);
        //strftime( &frame.data[1 * frame.x],
        //      frame.x,
        //      "%Y/%m/%d %H:%M:%S",
        //      tp);

        //  Print the command line.
        line[count] = '\0';
        snprintf(   frame.data,
                frame.x, 
                "OS1Shell -> %s",
                line);

        draw_frame(&frame);
    } while (1);

    //  Restore terminal and free resources.
    tcsetattr(STDIN_FILENO, TCSANOW, &tty_old);
    free(frame.data);
    int n = 0;
    while (n < 21) {
        free(cmdHistory[n]);
        ++n;
    }
    free(cmdHistory);

    return (0);
}

. Любая помощь, заставляющая его действовать более похоже на bash, будет высоко оценена!Часть заслуг заключается в правильном использовании stderr в любом случае, так что это определенно поможет принять подход stdin / stdout / stderr.

1 Ответ

0 голосов
/ 08 апреля 2011

Мне кажется, это уже собирается в STDOUT

fprintf(    stdout,
        "\033[%d;%dH\033[0m\033[%dm%.*s",
        row + 1,
        0,
        attrib, frame->x, data);
fflush(stdout);
...