带有 C99 内联函数的 OpenBSD 5.9 header

OpenBSD 5.9 header with C99 inline function

我正在构建一个自定义 shell 并在我编译时看到 usr/include/ctype.h:92 似乎需要 函数,但编译器说 C99 内联函数不需要支持的。可以使用编译器的参数禁用警告,但它是一个需要修复的错误吗?

这是我的main.c

#define _XOPEN_SOURCE 500

#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include "openshell.h"
#include "errors.h"
#include <errno.h>
#include <locale.h>
#include <readline/readline.h>
#include <getopt.h>
#include <unistd.h>
#include <assert.h>
#include <readline/history.h>
#ifdef SIGDET
#if SIGDET == 1
int isSignal = 1;       /*Termination detected by signals*/
#endif
#endif
static int sourceCount = 0;
static FILE *sourcefiles[MAX_SOURCE];
/*
 * The special maximum argument value which means that there is
 * no limit to the number of arguments on the command line.
 */
#define    INFINITE_ARGS    0x7fffffff


/*
 * The table of built-in commands.
 * A command is terminated wih an entry containing NULL values.
 */
static const CommandEntry commandEntryTable[] =
        {
                {
                        "checkenv", do_checkenv, 1, INFINITE_ARGS,
                        "Check environment variables",
                        ""
                },

                {
                        "add2path", do_add2path, 3, INFINITE_ARGS,
                        "do_add2path",
                        "[txp]v arFileName fileName ..."
                },

                {
                        "cd",       do_cd,       1, 2,
                        "Change current directory",
                        "[dirName]"
                },


                {
                        "exit",     do_exit,     1, 2,
                        "Exit from shell",
                        "[exit value]"
                },


                {
                        "help",     do_help,     1, 2,
                        "Print help about a command",
                        "[word]"
                },

                {
                        "kill",     do_kill,     2, INFINITE_ARGS,
                        "Send a signal to the specified process",
                        "[-sig] pid ..."
                },


                {
                        NULL,       0,           0, 0,
                        NULL,
                        NULL
                }
        };

struct command {
    char *const *argv;
};
char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}
char ** stripped;
char ** create_pipeline(int argc, char ** argv) {
    if(!strstr(argv[argc], "|")) { /* && ! isBetweenquotes*/
        stripped = argv;
        return stripped;

    }
    else {
    stripped = argv;
    return create_pipeline(argc, argv);
    }
}

static int runCmd(const char *cmd) {
    const char *cp;
    pid_t pid;
    int status;
    struct command shellcommand[4];
    char **argv = 0;
    int argc = 1;
    bool pipe = false;
    char *command[40];
    char *cmd2[20] = {"cmd2", 0};
    int numberofpipelines = 0;
    unsigned long i3 = 0;
    unsigned long i2 = 0;
    unsigned long i1 = 0;
    unsigned long n = 0;
    char *string;
    char *string1;
    int max_args = 1; /* there's at least one argument or we wouldn't reach this */
    cmd2[0] = NULL;
    cmd2[1] = NULL;
    cmd2[2] = NULL;
    command[0] = NULL;
    command[1] = NULL;
    command[3] = NULL;
    char *string2 = NULL;
    char** tokens;
    for (cp = cmd; *cp; cp++) {
        if ((*cp >= 'a') && (*cp <= 'z')) {
            continue;
        }
        if ((*cp >= 'A') && (*cp <= 'Z')) {
            continue;
        }
        if (isDecimal(*cp)) {
            continue;
        }
        if (isBlank(*cp)){
            continue;
        }
        if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
            (*cp == '+') || (*cp == '=') || (*cp == '_') ||
            (*cp == ':') || (*cp == ',') || (*cp == '\'') ||
            (*cp == '"')) {
            continue;
        }
    }
    makeArgs(cmd, &argc, (const char ***) &argv, pipe);
    char a[20] = {0};
    if (sscanf(cmd, "%*[^']'%[^']'", a) == 1) {
        printf("<undefined>");
    }


    char cmdtmp[75];
    strcpy(cmdtmp, cmd);

    tokens = str_split( cmdtmp, '|');

    if (tokens)
    {
        int i;
        for (i = 0; *(tokens + i); i++)
        {
            printf("month=[%s]\n", *(tokens + i));
            free(*(tokens + i));
        }
        printf("\n");
        free(tokens);
    }
    for (int i = 0; i < argc; i++) {
        if (argv[i] != NULL && strstr(argv[i], "|")) {




            numberofpipelines++;
            char subbuff[40];
            i1 = 0;
            i2 = 0;
            i3 = 0;
            subbuff[0]='[=11=]';
            string = strstr(argv[i], "|");
            if (string != NULL) {
                i3 = string - argv[i];
                printf("**** is null ***");
                cmd2[1] = argv[argc - 1];
            }
            string1 = strstr(&argv[i][i3 + 2], "|");
            if (string1 != NULL) {
                i2 = string1 - argv[i3 + 1];
                printf("i2: %lu", i2);
            } else {
                char *found3 = strstr(&argv[i][i3 + 1], " ");
                if (found3 != NULL) {}
                string2 = strstr(argv[1], "|");
                if (string2 != NULL) {
                    i1 = string2 - argv[1];
                }
                n = strlen(argv[1]) - i1;
                if (argc > 2) {
                    memcpy(subbuff, &argv[i][i3 + 1], n - 1);
                    subbuff[n - 1] = '[=11=]';
                    cmd2[0] = subbuff;
                    cmd2[1] = argv[argc - 1];
                } else {
                    memcpy(subbuff, &argv[i][i3 + 1], n);
                    subbuff[n] = '[=11=]';
                    cmd2[0] = subbuff;
                    cmd2[1] = argv[argc - 1];
                }
                argc++;
                argv[i + 1] = subbuff;
                command[i] = "<undefined>";
                argv[i + 2] = NULL;
                max_args = i;
            }
        }
        if (argv[i] != NULL) {
            if (i < max_args) {
                command[i] =  argv[i];
                command[i+1] =  0;
                max_args++;
                cmd2[1] = argv[argc - 1];
            } else {
                command[max_args] =  argv[max_args];
                command[max_args+1] =  0;
                cmd2[1] = argv[argc - 1];
            }
        }
        if (argv[i] != NULL) {
            char *p = strchr(argv[i], '|');
            if (!p) {
                /* deal with error: / not present" */;
            } else {
                *p = 0;
            }
        }

    }
    dump_argv((const char *) "d", argc, argv);
/*  makeArgs(cmd, &argc, &argv, pipe);*/
 /*   command[2]= 0;*/
    shellcommand[0].argv = command;
    shellcommand[1].argv = cmd2;
    pid = fork();
    if (pid < 0) {
        perror("fork failed");
        return -1;
    }
    /* If we are the child process, then go execute the program.*/
    if (pid == 0) {
        /* spawn(cmd);*/
        fork_pipes(numberofpipelines, shellcommand);
    }
    /*
     * We are the parent process.
     * Wait for the child to complete.
     */
    status = 0;
    while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
    if (pid < 0) {
        fprintf(stderr, "Error from waitpid: %s", strerror(errno));
        return -1;
    }
    if (WIFSIGNALED(status)) {
        fprintf(stderr, "pid %ld: killed by signal %d\n",
                (long) pid, WTERMSIG(status));

        return -1;
    }
    return WEXITSTATUS(status);
}

/* The shell performs wildcard expansion on each token it extracts while parsing the command line.
 * Oftentimes, globbing will obviously not do anything (for example, ls just returns ls).
 * When you want nullglob behavior you'll have to know whether the glob function actually found any glob characters, though
 */
static void expandVariable(char *shellcommand) {
    char mystring[CMD_LEN];
    char *cp;
    char *ep;

    strcpy(mystring, shellcommand);
    cp = strstr(mystring, "$(");
    if (cp) {
        *cp++ = '[=11=]';
        strcpy(shellcommand, mystring);
        ep = ++cp;
        while (*ep && (*ep != ')')) ep++;
        if (*ep == ')') *ep++ = '[=11=]';
        cp = getenv(cp);
        if (cp) strcat(shellcommand, cp);
        strcat(shellcommand, ep);
    }
    return;
}

int do_help(int argc, const char **argv) {
    const CommandEntry *entry;
    const char *str;

    str = NULL;

    if (argc == 2)
        str = argv[1];

    /*
     * Check for an exact match, in which case describe the program.
     */
    if (str) {
        for (entry = commandEntryTable; entry->name; entry++) {
            if (strcmp(str, entry->name) == 0) {
                printf("%s\n", entry->description);

                printf("usage: %s %s\n", entry->name,
                       entry->usage);

                return 0;
            }
        }
    }

    /*
     * Print short information about commands which contain the
     * specified word.
     */
    for (entry = commandEntryTable; entry->name; entry++) {
        if ((str == NULL) || (strstr(entry->name, str) != NULL) ||
            (strstr(entry->usage, str) != NULL)) {
            printf("%-10s %s\n", entry->name, entry->usage);
        }
    }

    return 0;
}

/*
 * Try to execute a built-in command.
 * Returns TRUE if the command is a built in, whether or not the
 * command succeeds.  Returns FALSE if this is not a built-in command.
 */
bool exec_builtin(const char *cmd) {
    const char *endCmd;
    const CommandEntry *entry;
    int argc;
    const char **argv;
    char cmdName[CMD_LEN];

    /*
     * Look for the end of the command name and then copy the
     * command name to a buffer so we can null terminate it.
     */
    endCmd = cmd;

    while (*endCmd && !isBlank(*endCmd))
        endCmd++;

    memcpy(cmdName, cmd, endCmd - cmd);
    cmdName[endCmd - cmd] = '[=11=]';

    /*
     * Search the command table looking for the command name.
     */
    for (entry = commandEntryTable; entry->name != NULL; entry++) {
        if (strcmp(entry->name, cmdName) == 0)
            break;
    }

    /*
     * If the command is not a built-in, return indicating that.
     */
    if (entry->name == NULL) {
        return false;
    }

    bool bo = false;
    /*
     * The command is a built-in.
     * Break the command up into arguments and expand wildcards.
     */
    if (!makeArgs(cmd, &argc, &argv, bo)) {
        return true;
    }

    /*
     * Give a usage string if the number of arguments is too large
     * or too small.
     */
    if ((argc < entry->minArgs) || (argc > entry->maxArgs)) {
        fprintf(stderr, "usage: %s %s\n", entry->name, entry->usage);
        return true;
    }

    /*
     * Call the built-in function with the argument list.
     */
    entry->func(argc, argv);
    return true;
}


/*
 * Parse and execute one null-terminated command line string.
 * This breaks the command line up into words, checks to see if the
 * command is an alias, and expands wildcards.
 */
int command(const char *cmd) {
    const char *endCmd;
    char cmdName[CMD_LEN];
    freeChunks();

    /*
     * Skip leading blanks.
     */
    while (isBlank(*cmd))
        cmd++;
    /*
     * If the command is empty or is a comment then ignore it.
     */
    if ((*cmd == '[=11=]') || (*cmd == '#'))
        return 0;
    /*
     * Look for the end of the command name and then copy the
     * command name to a buffer so we can null terminate it.
     */
    endCmd = cmd;
    while (*endCmd && !isBlank(*endCmd))
        endCmd++;

    memcpy(cmdName, cmd, endCmd - cmd);
    cmdName[endCmd - cmd] = '[=11=]';
    /*
     * Expand simple environment variables
     */
    while (strstr(cmd, "$(")) expandVariable((char *) cmd);
    /*
     * Now look for the command in the builtin table, and execute
     * the command if found.
     */
    if (exec_builtin(cmd)) {
        return 0;
    }
    /*
     * The command is not a built-in, so run the program along
     * the PATH list.
     */
    return runCmd(cmd);
}

/*
 * Execute the specified file or program
 * A null name pointer indicates to read from stdin.
 */

int exec_program(const char *name) {
    FILE *fp;
    int r = 0;
    char *input, shell_prompt[100];
    if (sourceCount >= MAX_SOURCE) {
        fprintf(stderr, "Too many source files\n");
        return 1;
    }
    fp = stdin;
    if (name) {
        fp = fopen(name, "r");

        if (fp == NULL) {
            perror(name);

            return 1;
        }
    }
    sourcefiles[sourceCount++] = fp;
    setlocale(LC_CTYPE, "");
    /*Configure readline to auto-complete paths when the tab key is hit.*/
    rl_bind_key('\t', rl_complete);
    /*stifle_history(7);*/
    for (; ;) {
        /* Create prompt string from user name and current working directory.*/
        snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
        // Display prompt and read input (NB: input must be freed after use)...
        input = readline(shell_prompt);
        // Check for EOF.
        if (!input)
            break;
        add_history(input);
        r = command(input);
        free(input);
    }
    return r;
}

static struct option long_options[] = {
        {"with_param", 1, 0, 'p'},
        {"version",    0, 0, 'v'},
        {"help",       0, 0, 'h'},
        {0,            0, 0, 0}
};

char s[] = "Interrupt\n";

void int_handler(int signum) {
    if (write(fileno(stdin), s, sizeof s - 1)) { } else { }
    if (signum) { if (false); } else { }
}

int main(int argc, char *argv[]) {
    struct sigaction sh;

    sh.sa_handler = int_handler;
    sigemptyset(&sh.sa_mask);
    sh.sa_flags = 0;
    sigaction(SIGINT, &sh, NULL);

    sourceCount = 0;
    const char *commandFile;
    commandFile = NULL;
    char *pathValue;
    int option;
    sh.sa_handler = int_handler;
    sigemptyset(&sh.sa_mask);
    sh.sa_flags = 0;
    sigaction(SIGINT, &sh, NULL);
    int option_index = 0;
    while (1) {
        option_index = 0;
        option = getopt_long(argc, argv, "p:vh",
                             long_options, &option_index);
        if (option == -1)
            break;
        switch (option) {
            case 'p': {
                /* store_parameter(optarg); */
                break;
            }
            case 'v': {
                printf("OpenShell version 0.1(a)\n");
                printf("Version: %s\n", VERSION);
                exit(EXIT_SUCCESS);

            }
            case 'h': {
                printf("Usage: ./shell\n");
                /*print_help();*/
                exit(EXIT_SUCCESS);

            }
            default: {
                /*                fprintf(stderr, "Error (%s): unrecognized option.\n", __FUNCTION__);*/
                /* print_help();*/
                return 1;/*RETURN_FAILURE;*/

            }
        } /* end switch */
    }
    /* get the PATH environment to find if less is installed */
    pathValue = getenv("PATH");
    if (!pathValue || getenv("PATH") == NULL) {
        printf("'%s' is not set.\n", "PATH");
        /* Default our path if it is not set. */
        putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc");
    }
    else {
        printf("'%s' is set to %s.\n", "PATH", pathValue);
    }
    exec_program(commandFile);
    return (0);
}

我的生成文件:

CC = gcc
GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags)
CFLAGS := $(CFLAGS) -L/usr/local/include/ -L/usr/include -pedantic -std=c99 -Wall -O3 -g -DVERSION=\"$(GIT_VERSION)\" -ledit -lncurses

LDIRS = -L/usr/local/lib -L/usr/lib
LIBS =su -lcurses

shell: main.o
    $(CC) -o shell main.o errors.c util.c pipeline.c -ledit -lncurses -lcurses

main.o: main.c errors.c util.c
USERNAME := $(shell whoami >> username.txt)
GIT:= $(shell head -n -1 openshell.h > temp.txt ; mv temp.txt openshell.h;git describe --abbrev=4 --dirty --always --tags > VERSION; echo "\#define VERSION \"$(GIT_VERSION)\"" >> openshell.h)

.PHONY: clean
clean:
    rm -f *.o

您应该使用 c99 或 c11 进行编译,并为 gcc 设置标志:

gcc -std=c99

gcc -std=c11