LibC: Implement getopt_long{,_only}
Few ports attempt to use this so lets add them :D
This commit is contained in:
parent
c9355ad94a
commit
fde4d4662e
|
@ -12,6 +12,7 @@ set(LIBC_SOURCES
|
||||||
fenv.cpp
|
fenv.cpp
|
||||||
fnmatch.cpp
|
fnmatch.cpp
|
||||||
ftw.cpp
|
ftw.cpp
|
||||||
|
getopt.cpp
|
||||||
grp.cpp
|
grp.cpp
|
||||||
ifaddrs.cpp
|
ifaddrs.cpp
|
||||||
inttypes.cpp
|
inttypes.cpp
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char* optarg = nullptr;
|
||||||
|
int opterr = 1;
|
||||||
|
int optind = 1;
|
||||||
|
int optopt = 0;
|
||||||
|
|
||||||
|
static int s_idx_in_arg = -1;
|
||||||
|
static int s_old_optind = 1;
|
||||||
|
|
||||||
|
static int getopt_long_impl(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex, bool need_double_hyphen)
|
||||||
|
{
|
||||||
|
if (optind >= argc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (optind == 0)
|
||||||
|
{
|
||||||
|
s_old_optind = -1;
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
optind = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* curr = argv[optind];
|
||||||
|
if (curr == nullptr || curr[0] != '-' || curr[1] == '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (curr[1] == '-' && curr[2] == '\0')
|
||||||
|
{
|
||||||
|
optind++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_old_optind != optind)
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
struct dummy { ~dummy() { s_old_optind = optind; }} _;
|
||||||
|
|
||||||
|
if (s_idx_in_arg == -1 && (!need_double_hyphen || curr[1] == '-'))
|
||||||
|
{
|
||||||
|
for (size_t i = 0; longopts[i].name; i++)
|
||||||
|
{
|
||||||
|
const auto& opt = longopts[i];
|
||||||
|
const size_t name_len = strlen(opt.name);
|
||||||
|
if (strncmp(curr + 2, opt.name, name_len) != 0)
|
||||||
|
continue;
|
||||||
|
if (curr[2 + name_len] != '=' && curr[2 + name_len] != '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool has_argument;
|
||||||
|
switch (opt.has_arg)
|
||||||
|
{
|
||||||
|
case no_argument:
|
||||||
|
has_argument = false;
|
||||||
|
break;
|
||||||
|
case required_argument:
|
||||||
|
has_argument = true;
|
||||||
|
break;
|
||||||
|
case optional_argument:
|
||||||
|
has_argument = (curr[2 + name_len] == '=')
|
||||||
|
|| (optind + 1 < argc && argv[optind + 1][0] != '-');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_argument)
|
||||||
|
{
|
||||||
|
if (curr[2 + name_len] == '=')
|
||||||
|
{
|
||||||
|
if (opterr && optstring[0] != ':')
|
||||||
|
fprintf(stderr, "%s: option takes no argument -- %.*s\n", argv[0], static_cast<int>(name_len), curr + 2);
|
||||||
|
optind++;
|
||||||
|
return (optstring[0] == ':') ? ':' : '?';
|
||||||
|
}
|
||||||
|
optarg = nullptr;
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (curr[2 + name_len] == '=')
|
||||||
|
{
|
||||||
|
optarg = const_cast<char*>(curr + 2 + name_len + 1);
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (optind + 1 >= argc)
|
||||||
|
{
|
||||||
|
if (opterr && optstring[0] != ':')
|
||||||
|
fprintf(stderr, "%s: option requires an argument -- %.*s\n", argv[0], static_cast<int>(name_len), curr + 2);
|
||||||
|
optind++;
|
||||||
|
return (optstring[0] == ':') ? ':' : '?';
|
||||||
|
}
|
||||||
|
optarg = argv[optind + 1];
|
||||||
|
optind += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (longindex != nullptr)
|
||||||
|
*longindex = i;
|
||||||
|
|
||||||
|
if (opt.flag == nullptr)
|
||||||
|
return opt.val;
|
||||||
|
*opt.flag = opt.val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curr[1] == '-')
|
||||||
|
{
|
||||||
|
if (opterr && optstring[0] != ':')
|
||||||
|
fprintf(stderr, "%s: illegal option -- %s\n", argv[0], curr + 2);
|
||||||
|
optind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_idx_in_arg == -1)
|
||||||
|
s_idx_in_arg = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; optstring[i]; i++)
|
||||||
|
{
|
||||||
|
if (optstring[i] == ':')
|
||||||
|
continue;
|
||||||
|
if (curr[s_idx_in_arg] != optstring[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool has_argument = (optstring[i + 1] == ':');
|
||||||
|
if (!has_argument)
|
||||||
|
{
|
||||||
|
s_idx_in_arg++;
|
||||||
|
if (curr[s_idx_in_arg] == '\0')
|
||||||
|
{
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (curr[s_idx_in_arg + 1] != '\0')
|
||||||
|
{
|
||||||
|
optarg = const_cast<char*>(curr + s_idx_in_arg + 1);
|
||||||
|
optind++;
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (optind + 1 >= argc)
|
||||||
|
{
|
||||||
|
if (opterr && optstring[0] != ':')
|
||||||
|
fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optstring[i]);
|
||||||
|
optopt = optstring[i];
|
||||||
|
optind++;
|
||||||
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
|
}
|
||||||
|
optarg = const_cast<char*>(argv[optind + 1]);
|
||||||
|
optind += 2;
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return optstring[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opterr && optstring[0] != ':')
|
||||||
|
fprintf(stderr, "%s: illegal option -- %c\n", argv[0], curr[s_idx_in_arg]);
|
||||||
|
optopt = curr[s_idx_in_arg];
|
||||||
|
|
||||||
|
s_idx_in_arg++;
|
||||||
|
if (curr[s_idx_in_arg] == '\0')
|
||||||
|
{
|
||||||
|
s_idx_in_arg = -1;
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
int getopt(int argc, char* const argv[], const char* optstring)
|
||||||
|
{
|
||||||
|
struct option option {};
|
||||||
|
return getopt_long_impl(argc, argv, optstring, &option, nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getopt_long(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex)
|
||||||
|
{
|
||||||
|
return getopt_long_impl(argc, argv, optstring, longopts, longindex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getopt_long_only(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex)
|
||||||
|
{
|
||||||
|
return getopt_long_impl(argc, argv, optstring, longopts, longindex, false);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _BITS_GETOPT_H
|
||||||
|
#define _BITS_GETOPT_H 1
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
int getopt(int argc, char* const argv[], const char* optstring);
|
||||||
|
|
||||||
|
extern char* optarg;
|
||||||
|
extern int opterr, optind, optopt;
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef _GETOPT_H
|
||||||
|
#define _GETOPT_H 1
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <bits/getopt.h>
|
||||||
|
|
||||||
|
struct option
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
int has_arg;
|
||||||
|
int* flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define no_argument 0
|
||||||
|
#define required_argument 1
|
||||||
|
#define optional_argument 2
|
||||||
|
|
||||||
|
int getopt_long(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex);
|
||||||
|
int getopt_long_only(int argc, char* argv[], const char* optstring, const struct option* longopts, int* longindex);
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -124,6 +124,8 @@ __BEGIN_DECLS
|
||||||
#define __need_useconds_t
|
#define __need_useconds_t
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <bits/getopt.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
_CS_PATH = 1,
|
_CS_PATH = 1,
|
||||||
|
@ -547,7 +549,6 @@ long gethostid(void);
|
||||||
int gethostname(char* name, size_t namelen);
|
int gethostname(char* name, size_t namelen);
|
||||||
char* getlogin(void);
|
char* getlogin(void);
|
||||||
int getlogin_r(char* name, size_t namesize);
|
int getlogin_r(char* name, size_t namesize);
|
||||||
int getopt(int argc, char* const argv[], const char* optstring);
|
|
||||||
pid_t getpgid(pid_t pid);
|
pid_t getpgid(pid_t pid);
|
||||||
pid_t getpgrp(void);
|
pid_t getpgrp(void);
|
||||||
pid_t getpid(void);
|
pid_t getpid(void);
|
||||||
|
@ -600,9 +601,6 @@ int chroot(const char* path);
|
||||||
int getpagesize(void);
|
int getpagesize(void);
|
||||||
char* getpass(const char* prompt);
|
char* getpass(const char* prompt);
|
||||||
|
|
||||||
extern char* optarg;
|
|
||||||
extern int opterr, optind, optopt;
|
|
||||||
|
|
||||||
long syscall(long syscall, ...);
|
long syscall(long syscall, ...);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -541,91 +541,6 @@ int rmdir(const char* path)
|
||||||
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* optarg = nullptr;
|
|
||||||
int opterr = 1;
|
|
||||||
int optind = 1;
|
|
||||||
int optopt = 0;
|
|
||||||
|
|
||||||
int getopt(int argc, char* const argv[], const char* optstring)
|
|
||||||
{
|
|
||||||
if (optind >= argc)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
static int idx = 1;
|
|
||||||
const char* current = argv[optind];
|
|
||||||
|
|
||||||
// if "--" is encountered, no more options are parsed
|
|
||||||
if (idx == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// if current is nullptr, does not start with '-' or is string "-", return -1
|
|
||||||
if (current == nullptr || current[0] != '-' || current[1] == '\0')
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// if current points to string "--" increment optind and return -1
|
|
||||||
if (current[1] == '-' && current[2] == '\0')
|
|
||||||
{
|
|
||||||
idx = -1;
|
|
||||||
optind++;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; optstring[i]; i++)
|
|
||||||
{
|
|
||||||
if (optstring[i] == ':')
|
|
||||||
continue;
|
|
||||||
if (current[idx] != optstring[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (optstring[i + 1] == ':')
|
|
||||||
{
|
|
||||||
if (current[idx + 1])
|
|
||||||
{
|
|
||||||
optarg = const_cast<char*>(current + idx + 1);
|
|
||||||
optind += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
optarg = const_cast<char*>(argv[optind + 1]);
|
|
||||||
optind += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = 1;
|
|
||||||
|
|
||||||
if (optind > argc)
|
|
||||||
{
|
|
||||||
if (opterr && optstring[0] != ':')
|
|
||||||
fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optstring[i]);
|
|
||||||
optopt = optstring[i];
|
|
||||||
return optstring[0] == ':' ? ':' : '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return optstring[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (current[++idx] == '\0')
|
|
||||||
{
|
|
||||||
idx = 1;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return optstring[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opterr && optstring[0] != ':')
|
|
||||||
fprintf(stderr, "%s: illegal option -- %c\n", argv[0], current[idx]);
|
|
||||||
|
|
||||||
if (current[++idx] == '\0')
|
|
||||||
{
|
|
||||||
idx = 1;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
int chroot(const char* path)
|
int chroot(const char* path)
|
||||||
{
|
{
|
||||||
return syscall(SYS_CHROOT, path);
|
return syscall(SYS_CHROOT, path);
|
||||||
|
|
Loading…
Reference in New Issue