[dev] [sbase] changes to test

From: <random832_AT_fastmail.us>
Date: Thu, 30 May 2013 10:09:51 -0400

I had partially implemented the test/[ command a while ago, and then got
distracted with other things and never came back to it - I remembered
about it when I saw this other sbase patch.

This version has binary operators (e.g. = != -gt -lt) implemented
(limited to the r, and properly handles being called as /bin/[ (previous
version required argv[0] to be == "[" to invoke [ behavior, this one
simply checks the last character of argv[0])

It still only supports the POSIX single-test syntax, with no support for
the XSI ( ) -a -o operators.


/* See LICENSE file for copyright and license details. */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "util.h"

static bool unary(const char *, const char *);
static bool binary(const char *, const char *, const char *);
static void usage(void);
bool is_bracket = false;

int
main(int argc, char *argv[])
{
        bool ret = false, not = false;

        argv0 = argv[0];
        if(*argv0 && argv0[strlen(argv0)-1] == '[') {
                /* checks if argv[0] ends with [
                 * for [ or /bin/[ etc */
                is_bracket = true;
                if(strcmp(argv[argc-1], "]") != 0)
                        usage();
                argc--;
        }

        if(argc > 2 && !strcmp(argv[1], "!")) {
                not = true;
                argv++;
                argc--;
        }
        switch(argc) {
        case 2:
                ret = *argv[1] != '\0';
                break;
        case 3:
                ret = unary(argv[1], argv[2]);
                break;
        case 4:
                ret = binary(argv[1], argv[2], argv[3]);
                break;
        default:
                usage();
        }
        if(not)
                ret = !ret;
        return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}

bool
unary(const char *op, const char *arg)
{
        struct stat st;
        int r;

        if(op[0] != '-' || op[1] == '\0' || op[2] != '\0')
                usage();
        switch(op[1]) {
        case 'b': case 'c': case 'd': case 'f': case 'g':
        case 'p': case 'S': case 's': case 'u':
                if((r = stat(arg, &st)) == -1)
                        return false; /* -e */
                switch(op[1]) {
                case 'b':
                        return S_ISBLK(st.st_mode);
                case 'c':
                        return S_ISCHR(st.st_mode);
                case 'd':
                        return S_ISDIR(st.st_mode);
                case 'f':
                        return S_ISREG(st.st_mode);
                case 'g':
                        return st.st_mode & S_ISGID;
                case 'p':
                        return S_ISFIFO(st.st_mode);
                case 'S':
                        return S_ISSOCK(st.st_mode);
                case 's':
                        return st.st_size > 0;
                case 'u':
                        return st.st_mode & S_ISUID;
                }
        case 'e':
                return access(arg, F_OK) == 0;
        case 'r':
                return access(arg, R_OK) == 0;
        case 'w':
                return access(arg, W_OK) == 0;
        case 'x':
                return access(arg, X_OK) == 0;
        case 'h': case 'L':
                return lstat(arg, &st) == 0 && S_ISLNK(st.st_mode);
        case 't':
                return isatty((int)estrtol(arg, 0));
        case 'n':
                return arg[0] != '\0';
        case 'z':
                return arg[0] == '\0';
        default:
                usage();
        }
        return false; /* should not reach */
}

bool
binary(const char *arg1, const char *op, const char *arg2)
{
        intmax_t iarg1, iarg2;
        if(!strcmp(op,"=") || !strcmp(op,"==")) {
                return strcmp(arg1,arg2) == 0;
        }
        if(!strcmp(op,"!=")) {
                return strcmp(arg1,arg2) != 0;
        }
        /* Note: this does not handle correctly if the values are both
         * out of range in the same direction, it will consider them
         * equal. */
        iarg1 = strtoimax(arg1, 0, 10);
        iarg2 = strtoimax(arg2, 0, 10);
        if(!strcmp(op,"-eq")) return iarg1 == iarg2;
        if(!strcmp(op,"-ne")) return iarg1 != iarg2;
        if(!strcmp(op,"-gt")) return iarg1 > iarg2;
        if(!strcmp(op,"-ge")) return iarg1 >= iarg2;
        if(!strcmp(op,"-lt")) return iarg1 < iarg2;
        if(!strcmp(op,"-le")) return iarg1 <= iarg2;
        usage();
}

void
usage(void)
{
        const char *ket = is_bracket ? " ]" : "";

        eprintf("usage: %s string%s\n"
                " %s [!] [-bcdefghLnprSstuwxz] string%s\n"
                " %s [!] string1 {=,!=} string2%s\n"
                " %s [!] int1 -{eq,ne,gt,ge,lt,le} int2%s\n"
                , argv0, ket, argv0, ket, argv0, ket, argv0, ket);
}
Received on Thu May 30 2013 - 16:09:51 CEST

This archive was generated by hypermail 2.3.0 : Thu May 30 2013 - 16:12:05 CEST