]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - apps/opt.c
Remove MAC cruft
[thirdparty/openssl.git] / apps / opt.c
index d694fe15f20d141e25d0118f619e65702516bfcc..c2a5878ef68d1b07e15998fbc3a4171d75ce8d02 100644 (file)
@@ -1,17 +1,21 @@
 /*
- * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
- * Licensed under the OpenSSL license (the "License").  You may not use
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  * in the file LICENSE in the source distribution or at
  * https://www.openssl.org/source/license.html
  */
 
-/* #define COMPILE_STANDALONE_TEST_DRIVER  */
-#include "apps.h"
+/*
+ * This file is also used by the test suite. Do not #include "apps.h".
+ */
+#include "opt.h"
+#include "fmt.h"
+#include "internal/nelem.h"
 #include <string.h>
 #if !defined(OPENSSL_SYS_MSDOS)
-# include OPENSSL_UNISTD
+# include <unistd.h>
 #endif
 
 #include <stdlib.h>
@@ -60,10 +64,10 @@ char *opt_progname(const char *argv0)
         n -= 4;
 
     /* Copy over the name, in lowercase. */
-    if (n > sizeof prog - 1)
-        n = sizeof prog - 1;
+    if (n > sizeof(prog) - 1)
+        n = sizeof(prog) - 1;
     for (q = prog, i = 0; i < n; i++, p++)
-        *q++ = isupper(*p) ? tolower(*p) : *p;
+        *q++ = tolower((unsigned char)*p);
     *q = '\0';
     return prog;
 }
@@ -82,9 +86,9 @@ char *opt_progname(const char *argv0)
         }
 
     q = strrchr(p, '.');
-    strncpy(prog, p, sizeof prog - 1);
-    prog[sizeof prog - 1] = '\0';
-    if (q != NULL && q - p < sizeof prog)
+    strncpy(prog, p, sizeof(prog) - 1);
+    prog[sizeof(prog) - 1] = '\0';
+    if (q != NULL && q - p < sizeof(prog))
         prog[q - p] = '\0';
     return prog;
 }
@@ -101,8 +105,8 @@ char *opt_progname(const char *argv0)
             p++;
             break;
         }
-    strncpy(prog, p, sizeof prog - 1);
-    prog[sizeof prog - 1] = '\0';
+    strncpy(prog, p, sizeof(prog) - 1);
+    prog[sizeof(prog) - 1] = '\0';
     return prog;
 }
 #endif
@@ -118,7 +122,7 @@ char *opt_init(int ac, char **av, const OPTIONS *o)
     /* Store state. */
     argc = ac;
     argv = av;
-    opt_index = 1;
+    opt_begin();
     opts = o;
     opt_progname(av[0]);
     unknown = NULL;
@@ -135,15 +139,15 @@ char *opt_init(int ac, char **av, const OPTIONS *o)
         i = o->valtype;
 
         /* Make sure options are legit. */
-        assert(o->name[0] != '-');
-        assert(o->retval > 0);
+        OPENSSL_assert(o->name[0] != '-');
+        OPENSSL_assert(o->retval > 0);
         switch (i) {
         case   0: case '-': case '/': case '<': case '>': case 'E': case 'F':
         case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's':
         case 'u': case 'c':
             break;
         default:
-            assert(0);
+            OPENSSL_assert(0);
         }
 
         /* Make sure there are no duplicates. */
@@ -152,13 +156,13 @@ char *opt_init(int ac, char **av, const OPTIONS *o)
              * Some compilers inline strcmp and the assert string is too long.
              */
             duplicated = strcmp(o->name, next->name) == 0;
-            assert(!duplicated);
+            OPENSSL_assert(!duplicated);
         }
 #endif
         if (o->name[0] == '\0') {
-            assert(unknown == NULL);
+            OPENSSL_assert(unknown == NULL);
             unknown = o;
-            assert(unknown->valtype == 0 || unknown->valtype == '-');
+            OPENSSL_assert(unknown->valtype == 0 || unknown->valtype == '-');
         }
     }
     return prog;
@@ -170,7 +174,6 @@ static OPT_PAIR formats[] = {
     {"smime", OPT_FMT_SMIME},
     {"engine", OPT_FMT_ENGINE},
     {"msblob", OPT_FMT_MSBLOB},
-    {"netscape", OPT_FMT_NETSCAPE},
     {"nss", OPT_FMT_NSS},
     {"text", OPT_FMT_TEXT},
     {"http", OPT_FMT_HTTP},
@@ -183,15 +186,15 @@ int opt_format_error(const char *s, unsigned long flags)
 {
     OPT_PAIR *ap;
 
-    if (flags == OPT_FMT_PEMDER)
-        BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n",
-                   prog, s);
-    else {
-        BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n",
-                   prog, s);
+    if (flags == OPT_FMT_PEMDER) {
+        opt_printf_stderr("%s: Bad format \"%s\"; must be pem or der\n",
+                          prog, s);
+    else {
+        opt_printf_stderr("%s: Bad format \"%s\"; must be one of:\n",
+                          prog, s);
         for (ap = formats; ap->name; ap++)
             if (flags & ap->retval)
-                BIO_printf(bio_err, "   %s\n", ap->name);
+                opt_printf_stderr("   %s\n", ap->name);
     }
     return 0;
 }
@@ -266,8 +269,9 @@ int opt_format(const char *s, unsigned long flags, int *result)
             if ((flags & OPT_FMT_PKCS12) == 0)
                 return opt_format_error(s, flags);
             *result = FORMAT_PKCS12;
-        } else
+        } else {
             return 0;
+        }
         break;
     }
     return 1;
@@ -277,9 +281,9 @@ int opt_format(const char *s, unsigned long flags, int *result)
 int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
 {
     *cipherp = EVP_get_cipherbyname(name);
-    if (*cipherp)
+    if (*cipherp != NULL)
         return 1;
-    BIO_printf(bio_err, "%s: Unknown cipher %s\n", prog, name);
+    opt_printf_stderr("%s: Unrecognized flag %s\n", prog, name);
     return 0;
 }
 
@@ -289,9 +293,9 @@ int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
 int opt_md(const char *name, const EVP_MD **mdp)
 {
     *mdp = EVP_get_digestbyname(name);
-    if (*mdp)
+    if (*mdp != NULL)
         return 1;
-    BIO_printf(bio_err, "%s: Unknown digest %s\n", prog, name);
+    opt_printf_stderr("%s: Unrecognized flag %s\n", prog, name);
     return 0;
 }
 
@@ -305,9 +309,9 @@ int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
             *result = pp->retval;
             return 1;
         }
-    BIO_printf(bio_err, "%s: Value must be one of:\n", prog);
+    opt_printf_stderr("%s: Value must be one of:\n", prog);
     for (pp = pairs; pp->name; pp++)
-        BIO_printf(bio_err, "\t%s\n", pp->name);
+        opt_printf_stderr("\t%s\n", pp->name);
     return 0;
 }
 
@@ -320,13 +324,36 @@ int opt_int(const char *value, int *result)
         return 0;
     *result = (int)l;
     if (*result != l) {
-        BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n",
-                   prog, value);
+        opt_printf_stderr("%s: Value \"%s\" outside integer range\n",
+                          prog, value);
         return 0;
     }
     return 1;
 }
 
+static void opt_number_error(const char *v)
+{
+    size_t i = 0;
+    struct strstr_pair_st {
+        char *prefix;
+        char *name;
+    } b[] = {
+        {"0x", "a hexadecimal"},
+        {"0X", "a hexadecimal"},
+        {"0", "an octal"}
+    };
+
+    for (i = 0; i < OSSL_NELEM(b); i++) {
+        if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) {
+            opt_printf_stderr("%s: Can't parse \"%s\" as %s number\n",
+                              prog, v, b[i].name);
+            return;
+        }
+    }
+    opt_printf_stderr("%s: Can't parse \"%s\" as a number\n", prog, v);
+    return;
+}
+
 /* Parse a long, put it into *result; return 0 on failure, else 1. */
 int opt_long(const char *value, long *result)
 {
@@ -340,8 +367,7 @@ int opt_long(const char *value, long *result)
             || endp == value
             || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
             || (l == 0 && errno != 0)) {
-        BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
-                   prog, value);
+        opt_number_error(value);
         errno = oerrno;
         return 0;
     }
@@ -351,7 +377,8 @@ int opt_long(const char *value, long *result)
 }
 
 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
-    defined(INTMAX_MAX) && defined(UINTMAX_MAX)
+    defined(INTMAX_MAX) && defined(UINTMAX_MAX) && \
+    !defined(OPENSSL_NO_INTTYPES_H)
 
 /* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */
 int opt_imax(const char *value, intmax_t *result)
@@ -366,8 +393,7 @@ int opt_imax(const char *value, intmax_t *result)
             || endp == value
             || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE)
             || (m == 0 && errno != 0)) {
-        BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
-                   prog, value);
+        opt_number_error(value);
         errno = oerrno;
         return 0;
     }
@@ -389,8 +415,7 @@ int opt_umax(const char *value, uintmax_t *result)
             || endp == value
             || (m == UINTMAX_MAX && errno == ERANGE)
             || (m == 0 && errno != 0)) {
-        BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
-                   prog, value);
+        opt_number_error(value);
         errno = oerrno;
         return 0;
     }
@@ -415,8 +440,7 @@ int opt_ulong(const char *value, unsigned long *result)
             || endptr == value
             || ((l == ULONG_MAX) && errno == ERANGE)
             || (l == 0 && errno != 0)) {
-        BIO_printf(bio_err, "%s: Can't parse \"%s\" as an unsigned number\n",
-                   prog, value);
+        opt_number_error(value);
         errno = oerrno;
         return 0;
     }
@@ -440,9 +464,9 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
     X509_PURPOSE *xptmp;
     const X509_VERIFY_PARAM *vtmp;
 
-    assert(vpm != NULL);
-    assert(opt > OPT_V__FIRST);
-    assert(opt < OPT_V__LAST);
+    OPENSSL_assert(vpm != NULL);
+    OPENSSL_assert(opt > OPT_V__FIRST);
+    OPENSSL_assert(opt < OPT_V__LAST);
 
     switch ((enum range)opt) {
     case OPT_V__FIRST:
@@ -451,7 +475,7 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
     case OPT_V_POLICY:
         otmp = OBJ_txt2obj(opt_arg(), 0);
         if (otmp == NULL) {
-            BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg());
+            opt_printf_stderr("%s: Invalid Policy %s\n", prog, opt_arg());
             return 0;
         }
         X509_VERIFY_PARAM_add0_policy(vpm, otmp);
@@ -460,7 +484,7 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
         /* purpose name -> purpose index */
         i = X509_PURPOSE_get_by_sname(opt_arg());
         if (i < 0) {
-            BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
+            opt_printf_stderr("%s: Invalid purpose %s\n", prog, opt_arg());
             return 0;
         }
 
@@ -471,17 +495,16 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
         i = X509_PURPOSE_get_id(xptmp);
 
         if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) {
-            BIO_printf(bio_err,
-                       "%s: Internal error setting purpose %s\n",
-                       prog, opt_arg());
+            opt_printf_stderr("%s: Internal error setting purpose %s\n",
+                              prog, opt_arg());
             return 0;
         }
         break;
     case OPT_V_VERIFY_NAME:
         vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
         if (vtmp == NULL) {
-            BIO_printf(bio_err, "%s: Invalid verify name %s\n",
-                       prog, opt_arg());
+            opt_printf_stderr("%s: Invalid verify name %s\n",
+                              prog, opt_arg());
             return 0;
         }
         X509_VERIFY_PARAM_set1(vpm, vtmp);
@@ -500,8 +523,8 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
         if (!opt_imax(opt_arg(), &t))
             return 0;
         if (t != (time_t)t) {
-            BIO_printf(bio_err, "%s: epoch time out of range %s\n",
-                       prog, opt_arg());
+            opt_printf_stderr("%s: epoch time out of range %s\n",
+                              prog, opt_arg());
             return 0;
         }
         X509_VERIFY_PARAM_set_time(vpm, (time_t)t);
@@ -580,11 +603,21 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
     case OPT_V_NO_CHECK_TIME:
         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
         break;
+    case OPT_V_ALLOW_PROXY_CERTS:
+        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS);
+        break;
     }
     return 1;
 
 }
 
+void opt_begin(void)
+{
+    opt_index = 1;
+    arg = NULL;
+    flag = NULL;
+}
+
 /*
  * Parse the next flag (and value if specified), return 0 if done, -1 on
  * error, otherwise the flag's retval.
@@ -630,8 +663,8 @@ int opt_next(void)
         /* If it doesn't take a value, make sure none was given. */
         if (o->valtype == 0 || o->valtype == '-') {
             if (arg) {
-                BIO_printf(bio_err,
-                           "%s: Option -%s does not take a value\n", prog, p);
+                opt_printf_stderr("%s: Option -%s does not take a value\n",
+                                  prog, p);
                 return -1;
             }
             return o->retval;
@@ -640,8 +673,8 @@ int opt_next(void)
         /* Want a value; get the next param if =foo not used. */
         if (arg == NULL) {
             if (argv[opt_index] == NULL) {
-                BIO_printf(bio_err,
-                           "%s: Option -%s needs a value\n", prog, o->name);
+                opt_printf_stderr("%s: Option -%s needs a value\n",
+                                  prog, o->name);
                 return -1;
             }
             arg = argv[opt_index++];
@@ -654,65 +687,50 @@ int opt_next(void)
             /* Just a string. */
             break;
         case '/':
-            if (app_isdir(arg) >= 0)
+            if (opt_isdir(arg) > 0)
                 break;
-            BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg);
+            opt_printf_stderr("%s: Not a directory: %s\n", prog, arg);
             return -1;
         case '<':
             /* Input file. */
-            if (strcmp(arg, "-") == 0 || app_access(arg, R_OK) >= 0)
-                break;
-            BIO_printf(bio_err,
-                       "%s: Cannot open input file %s, %s\n",
-                       prog, arg, strerror(errno));
-            return -1;
+            break;
         case '>':
             /* Output file. */
-            if (strcmp(arg, "-") == 0 || app_access(arg, W_OK) >= 0 || errno == ENOENT)
-                break;
-            BIO_printf(bio_err,
-                       "%s: Cannot open output file %s, %s\n",
-                       prog, arg, strerror(errno));
-            return -1;
+            break;
         case 'p':
         case 'n':
             if (!opt_int(arg, &ival)
                     || (o->valtype == 'p' && ival <= 0)) {
-                BIO_printf(bio_err,
-                           "%s: Non-positive number \"%s\" for -%s\n",
-                           prog, arg, o->name);
+                opt_printf_stderr("%s: Non-positive number \"%s\" for -%s\n",
+                                  prog, arg, o->name);
                 return -1;
             }
             break;
         case 'M':
             if (!opt_imax(arg, &imval)) {
-                BIO_printf(bio_err,
-                           "%s: Invalid number \"%s\" for -%s\n",
-                           prog, arg, o->name);
+                opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
+                                  prog, arg, o->name);
                 return -1;
             }
             break;
         case 'U':
             if (!opt_umax(arg, &umval)) {
-                BIO_printf(bio_err,
-                           "%s: Invalid number \"%s\" for -%s\n",
-                           prog, arg, o->name);
+                opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
+                                  prog, arg, o->name);
                 return -1;
             }
             break;
         case 'l':
             if (!opt_long(arg, &lval)) {
-                BIO_printf(bio_err,
-                           "%s: Invalid number \"%s\" for -%s\n",
-                           prog, arg, o->name);
+                opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
+                                  prog, arg, o->name);
                 return -1;
             }
             break;
         case 'u':
             if (!opt_ulong(arg, &ulval)) {
-                BIO_printf(bio_err,
-                           "%s: Invalid number \"%s\" for -%s\n",
-                           prog, arg, o->name);
+                opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
+                                  prog, arg, o->name);
                 return -1;
             }
             break;
@@ -726,9 +744,8 @@ int opt_next(void)
                            o->valtype == 'F' ? OPT_FMT_PEMDER
                            : OPT_FMT_ANY, &ival))
                 break;
-            BIO_printf(bio_err,
-                       "%s: Invalid format \"%s\" for -%s\n",
-                       prog, arg, o->name);
+            opt_printf_stderr("%s: Invalid format \"%s\" for -%s\n",
+                              prog, arg, o->name);
             return -1;
         }
 
@@ -739,7 +756,7 @@ int opt_next(void)
         dunno = p;
         return unknown->retval;
     }
-    BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p);
+    opt_printf_stderr("%s: Option unknown option -%s\n", prog, p);
     return -1;
 }
 
@@ -837,29 +854,28 @@ void opt_help(const OPTIONS *list)
             i += 1 + strlen(valtype2param(o));
         if (i < MAX_OPT_HELP_WIDTH && i > width)
             width = i;
-        assert(i < (int)sizeof start);
+        OPENSSL_assert(i < (int)sizeof(start));
     }
 
     if (standard_prolog)
-        BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n",
-                   prog);
+        opt_printf_stderr("Usage: %s [options]\nValid options are:\n", prog);
 
     /* Now let's print. */
     for (o = list; o->name; o++) {
         help = o->helpstr ? o->helpstr : "(No additional info)";
         if (o->name == OPT_HELP_STR) {
-            BIO_printf(bio_err, help, prog);
+            opt_printf_stderr(help, prog);
             continue;
         }
 
         /* Pad out prefix */
         memset(start, ' ', sizeof(start) - 1);
-        start[sizeof start - 1] = '\0';
+        start[sizeof(start) - 1] = '\0';
 
         if (o->name == OPT_MORE_STR) {
             /* Continuation of previous line; pad and print. */
             start[width] = '\0';
-            BIO_printf(bio_err, "%s  %s\n", start, help);
+            opt_printf_stderr("%s  %s\n", start, help);
             continue;
         }
 
@@ -878,97 +894,62 @@ void opt_help(const OPTIONS *list)
         *p = ' ';
         if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
             *p = '\0';
-            BIO_printf(bio_err, "%s\n", start);
+            opt_printf_stderr("%s\n", start);
             memset(start, ' ', sizeof(start));
         }
         start[width] = '\0';
-        BIO_printf(bio_err, "%s  %s\n", start, help);
+        opt_printf_stderr("%s  %s\n", start, help);
     }
 }
 
-#ifdef COMPILE_STANDALONE_TEST_DRIVER
-# include <sys/stat.h>
-
-typedef enum OPTION_choice {
-    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
-    OPT_IN, OPT_INFORM, OPT_OUT, OPT_COUNT, OPT_U, OPT_FLAG,
-    OPT_STR, OPT_NOTUSED
-} OPTION_CHOICE;
-
-static OPTIONS options[] = {
-    {OPT_HELP_STR, 1, '-', "Usage: %s flags\n"},
-    {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
-    {"help", OPT_HELP, '-', "Display this summary"},
-    {"in", OPT_IN, '<', "input file"},
-    {OPT_MORE_STR, 1, '-', "more detail about input"},
-    {"inform", OPT_INFORM, 'f', "input file format; defaults to pem"},
-    {"out", OPT_OUT, '>', "output file"},
-    {"count", OPT_COUNT, 'p', "a counter greater than zero"},
-    {"u", OPT_U, 'u', "an unsigned number"},
-    {"flag", OPT_FLAG, 0, "just some flag"},
-    {"str", OPT_STR, 's', "the magic word"},
-    {"areallyverylongoption", OPT_HELP, '-', "long way for help"},
-    {NULL}
-};
-
-BIO *bio_err;
-
-int app_isdir(const char *name)
+/* opt_isdir section */
+#ifdef _WIN32
+# include <windows.h>
+int opt_isdir(const char *name)
 {
-    struct stat sb;
-
-    return name != NULL && stat(name, &sb) >= 0 && S_ISDIR(sb.st_mode);
+    DWORD attr;
+# if defined(UNICODE) || defined(_UNICODE)
+    size_t i, len_0 = strlen(name) + 1;
+    WCHAR tempname[MAX_PATH];
+
+    if (len_0 > MAX_PATH)
+        return -1;
+
+#  if !defined(_WIN32_WCE) || _WIN32_WCE>=101
+    if (!MultiByteToWideChar(CP_ACP, 0, name, len_0, tempname, MAX_PATH))
+#  endif
+        for (i = 0; i < len_0; i++)
+            tempname[i] = (WCHAR)name[i];
+
+    attr = GetFileAttributes(tempname);
+# else
+    attr = GetFileAttributes(name);
+# endif
+    if (attr == INVALID_FILE_ATTRIBUTES)
+        return -1;
+    return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
 }
-
-int main(int ac, char **av)
+#else
+# include <sys/stat.h>
+# ifndef S_ISDIR
+#  if defined(_S_IFMT) && defined(_S_IFDIR)
+#   define S_ISDIR(a)   (((a) & _S_IFMT) == _S_IFDIR)
+#  else
+#   define S_ISDIR(a)   (((a) & S_IFMT) == S_IFDIR)
+#  endif
+# endif
+
+int opt_isdir(const char *name)
 {
-    OPTION_CHOICE o;
-    char **rest;
-    char *prog;
-
-    bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
-
-    prog = opt_init(ac, av, options);
-    while ((o = opt_next()) != OPT_EOF) {
-        switch (c) {
-        case OPT_NOTUSED:
-        case OPT_EOF:
-        case OPT_ERR:
-            printf("%s: Usage error; try -help.\n", prog);
-            return 1;
-        case OPT_HELP:
-            opt_help(options);
-            return 0;
-        case OPT_IN:
-            printf("in %s\n", opt_arg());
-            break;
-        case OPT_INFORM:
-            printf("inform %s\n", opt_arg());
-            break;
-        case OPT_OUT:
-            printf("out %s\n", opt_arg());
-            break;
-        case OPT_COUNT:
-            printf("count %s\n", opt_arg());
-            break;
-        case OPT_U:
-            printf("u %s\n", opt_arg());
-            break;
-        case OPT_FLAG:
-            printf("flag\n");
-            break;
-        case OPT_STR:
-            printf("str %s\n", opt_arg());
-            break;
-        }
-    }
-    argc = opt_num_rest();
-    argv = opt_rest();
-
-    printf("args = %d\n", argc);
-    if (argc)
-        while (*argv)
-            printf("  %s\n", *argv++);
-    return 0;
+# if defined(S_ISDIR)
+    struct stat st;
+
+    if (stat(name, &st) == 0)
+        return S_ISDIR(st.st_mode);
+    else
+        return -1;
+# else
+    return -1;
+# endif
 }
 #endif