<commit_before>/*
 * Copyright (C) 2015 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <cstdlib>

#include "ProcInvoker.h"
#include "RuntimeContext.h"
#include "../misc/num.h"
#include "../misc/debug.h"

namespace ydsh {
namespace core {

/**
 * for builtin command error message.
 */
static void builtin_perror(FILE *fp, const char *prefix) {
    const unsigned int size = 128;
    char buf[size];
    strerror_r(errno, buf, size);
    fprintf(fp, "%s: %s\n", prefix, buf);
}

// builtin command definition

static int builtin_help(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised);

static int builtin_cd(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    const char *destDir = getenv("HOME");
    if(bctx.argc > 1) {
        destDir = bctx.argv[1];
    }
    if(chdir(destDir) != 0) {
        builtin_perror(bctx.fp_stderr, "-ydsh: cd");
        return 1;
    }

    ctx->updateWorkingDir();
    return 0;
}

static int builtin_exit(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    int ret = 0;
    if(bctx.argc > 1) {
        const char *num = bctx.argv[1];
        int status;
        long value = convertToInt64(num, status, false);
        if(status == 0) {
            ret = value;
        }
    }
    ctx->exitShell(ret);
    raised = true;
    return ret;
}

const struct {
    const char *commandName;
    ProcInvoker::builtin_command_t cmd_ptr;
    const char *usage;
    const char *detail;
} builtinCommands[] {
        {"cd", builtin_cd, "[dir]",
                "    Changing the current directory to DIR. The Environment variable\n"
                "    HOME is the default DIR.  A null directory name is the same as\n"
                "    the current directory."},
        {"exit", builtin_exit, "[n]",
                "    Exit the shell with a status of N.  If N is omitted, the exit\n"
                "    status is 0."},
        {"help", builtin_help, "[-s] [pattern ...]",
                "    Display helpful information about builtin commands."}
};

template<typename T, size_t N>
static size_t sizeOfArray(const T (&array)[N]) {
    return N;
}


static void printAllUsage(FILE *fp) {
    unsigned int size = sizeOfArray(builtinCommands);
    for(unsigned int i = 0; i < size; i++) {
        fprintf(fp, "%s %s\n", builtinCommands[i].commandName, builtinCommands[i].usage);
    }
}

static int builtin_help(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    if(bctx.argc == 1) {
        printAllUsage(bctx.fp_stdout);
        return 0;
    }
    bool isShortHelp = false;
    bool foundValidCommand = false;
    for(int i = 1; i < bctx.argc; i++) {
        const char *arg = bctx.argv[i];
        if(strcmp(arg, "-s") == 0 && bctx.argc == 2) {
            printAllUsage(bctx.fp_stdout);
            foundValidCommand = true;
        }
        else if(strcmp(arg, "-s") == 0 && i == 1) {
            isShortHelp = true;
        }
        else {
            unsigned int size = sizeOfArray(builtinCommands);
            for(unsigned int j = 0; j < size; j++) {
                if(strcmp(arg, builtinCommands[j].commandName) == 0) {
                    foundValidCommand = true;
                    fprintf(bctx.fp_stdout, "%s: %s %s\n", arg, arg, builtinCommands[j].usage);
                    if(!isShortHelp) {
                        fprintf(bctx.fp_stdout, "%s\n", builtinCommands[j].detail);
                    }
                    break;
                }
            }
        }
    }
    if(!foundValidCommand) {
        fprintf(bctx.fp_stderr,
                "-ydsh: help: no help topics match `%s'.  Try `help help'.\n", bctx.argv[bctx.argc - 1]);
        return 1;
    }
    return 0;
}


// #########################
// ##     ProcInvoker     ##
// #########################

ProcInvoker::ProcInvoker(RuntimeContext *ctx) :
        ctx(ctx), builtinMap(), argArray(), redirOptions(), procOffsets(), procCtxs() {
    // register builtin command
    unsigned int size = sizeOfArray(builtinCommands);
    for(unsigned int i = 0; i < size; i++) {
        this->builtinMap.insert(std::make_pair(builtinCommands[i].commandName, builtinCommands[i].cmd_ptr));
    }
}

void ProcInvoker::openProc() {
    unsigned int argOffset = this->argArray.getUsedSize();
    unsigned int redirOffset = this->redirOptions.size();
    this->procOffsets.push_back(std::make_pair(argOffset, redirOffset));
}

void ProcInvoker::closeProc() {
    this->argArray.append(nullptr);
    this->redirOptions.push_back(std::make_pair(RedirectOP::DUMMY, nullptr));
}

void ProcInvoker::addCommandName(const std::string &name) {
    this->argArray.append(name.c_str());
}
<commit_msg>add check_env command, close #31<commit_after>/*
 * Copyright (C) 2015 <NAME>i
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <cstdlib>

#include "ProcInvoker.h"
#include "RuntimeContext.h"
#include "../misc/num.h"
#include "../misc/debug.h"

namespace ydsh {
namespace core {

/**
 * for builtin command error message.
 */
static void builtin_perror(FILE *fp, const char *prefix) {
    const unsigned int size = 128;
    char buf[size];
    strerror_r(errno, buf, size);
    fprintf(fp, "%s: %s\n", prefix, buf);
}

// builtin command definition

static int builtin_help(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised);

static int builtin_cd(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    const char *destDir = getenv("HOME");
    if(bctx.argc > 1) {
        destDir = bctx.argv[1];
    }
    if(chdir(destDir) != 0) {
        builtin_perror(bctx.fp_stderr, "-ydsh: cd");
        return 1;
    }

    ctx->updateWorkingDir();
    return 0;
}

static int builtin_check_env(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised);

static int builtin_exit(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    int ret = 0;
    if(bctx.argc > 1) {
        const char *num = bctx.argv[1];
        int status;
        long value = convertToInt64(num, status, false);
        if(status == 0) {
            ret = value;
        }
    }
    ctx->exitShell(ret);
    raised = true;
    return ret;
}

const struct {
    const char *commandName;
    ProcInvoker::builtin_command_t cmd_ptr;
    const char *usage;
    const char *detail;
} builtinCommands[] {
        {"cd", builtin_cd, "[dir]",
                "    Changing the current directory to DIR. The Environment variable\n"
                "    HOME is the default DIR.  A null directory name is the same as\n"
                "    the current directory."},
        {"check_env", builtin_check_env, "[environmental variable ...]",
                "    Check existence of specified environmental variables.\n"
                "    If all of variables are exist and not empty string, exit with 0."},
        {"exit", builtin_exit, "[n]",
                "    Exit the shell with a status of N.  If N is omitted, the exit\n"
                "    status is 0."},
        {"help", builtin_help, "[-s] [pattern ...]",
                "    Display helpful information about builtin commands."}
};

template<typename T, size_t N>
static size_t sizeOfArray(const T (&array)[N]) {
    return N;
}


static void printAllUsage(FILE *fp) {
    unsigned int size = sizeOfArray(builtinCommands);
    for(unsigned int i = 0; i < size; i++) {
        fprintf(fp, "%s %s\n", builtinCommands[i].commandName, builtinCommands[i].usage);
    }
}

static int builtin_help(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    if(bctx.argc == 1) {
        printAllUsage(bctx.fp_stdout);
        return 0;
    }
    bool isShortHelp = false;
    bool foundValidCommand = false;
    for(unsigned int i = 1; i < bctx.argc; i++) {
        const char *arg = bctx.argv[i];
        if(strcmp(arg, "-s") == 0 && bctx.argc == 2) {
            printAllUsage(bctx.fp_stdout);
            foundValidCommand = true;
        }
        else if(strcmp(arg, "-s") == 0 && i == 1) {
            isShortHelp = true;
        }
        else {
            unsigned int size = sizeOfArray(builtinCommands);
            for(unsigned int j = 0; j < size; j++) {
                if(strcmp(arg, builtinCommands[j].commandName) == 0) {
                    foundValidCommand = true;
                    fprintf(bctx.fp_stdout, "%s: %s %s\n", arg, arg, builtinCommands[j].usage);
                    if(!isShortHelp) {
                        fprintf(bctx.fp_stdout, "%s\n", builtinCommands[j].detail);
                    }
                    break;
                }
            }
        }
    }
    if(!foundValidCommand) {
        fprintf(bctx.fp_stderr,
                "-ydsh: help: no help topics match `%s'.  Try `help help'.\n", bctx.argv[bctx.argc - 1]);
        return 1;
    }
    return 0;
}

static int builtin_check_env(RuntimeContext *ctx, const BuiltinContext &bctx, bool &raised) {
    if(bctx.argc == 1) {
        fprintf(bctx.fp_stderr, "%s: usage: %s [environmental variable ...]\n", bctx.argv[0], bctx.argv[0]);
        return 1;
    }
    for(unsigned int i = 1; i < bctx.argc; i++) {
        const char *env = getenv(bctx.argv[i]);
        if(env == nullptr || strlen(env) == 0) {
            return 1;
        }
    }
    return 0;
}


// #########################
// ##     ProcInvoker     ##
// #########################

ProcInvoker::ProcInvoker(RuntimeContext *ctx) :
        ctx(ctx), builtinMap(), argArray(), redirOptions(), procOffsets(), procCtxs() {
    // register builtin command
    unsigned int size = sizeOfArray(builtinCommands);
    for(unsigned int i = 0; i < size; i++) {
        this->builtinMap.insert(std::make_pair(builtinCommands[i].commandName, builtinCommands[i].cmd_ptr));
    }
}

void ProcInvoker::openProc() {
    unsigned int argOffset = this->argArray.getUsedSize();
    unsigned int redirOffset = this->redirOptions.size();
    this->procOffsets.push_back(std::make_pair(argOffset, redirOffset));
}

void ProcInvoker::closeProc() {
    this->argArray.append(nullptr);
    this->redirOptions.push_back(std::make_pair(RedirectOP::DUMMY, nullptr));
}

void ProcInvoker::addCommandName(const std::string &name) {
    this->argArray.append(name.c_str());
}

{'fraction_non_alphanumeric': 0.13936235979863992, 'fraction_numerical': 0.007506844475845624, 'mean_word_length': 2.54873080539016, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1040947', 'n_tokens_mistral': 3626, 'n_tokens_neox': 3550, 'n_words': 970}