Selaa lähdekoodia

sys: getopt wrapper and reimplementation (first iteration).

legacy
Sam Hocevar 8 vuotta sitten
vanhempi
commit
c5a4f59517
8 muutettua tiedostoa jossa 342 lisäystä ja 45 poistoa
  1. +12
    -0
      build/autotools/m4/lol-conf.m4
  2. +3
    -3
      src/Makefile.am
  3. +2
    -0
      src/lol-core.vcxproj
  4. +6
    -0
      src/lol-core.vcxproj.filter
  5. +9
    -6
      src/lol/sys/all.h
  6. +41
    -0
      src/lol/sys/getopt.h
  7. +195
    -0
      src/sys/getopt.cpp
  8. +74
    -36
      tools/lolremez/lolremez.cpp

+ 12
- 0
build/autotools/m4/lol-conf.m4 Näytä tiedosto

@@ -68,6 +68,18 @@ LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/mingw-std-threads"
LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/pegtl"
LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/imgui"

dnl Use system-provided getopt_long?
ac_cv_have_getopt_long="no"
AC_CHECK_HEADERS(getopt.h unistd.h)
AC_CHECK_FUNCS(getopt_long,
[ac_cv_have_getopt_long="yes"],
[AC_CHECK_LIB(gnugetopt, getopt_long,
[ac_cv_have_getopt_long="yes"
LIBS="${LIBS} -lgnugetopt"])])
if test "$ac_cv_have_getopt_long" != "no"; then
AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the ‘getopt_long’ function.)
fi


dnl Use NativeClient?
ac_cv_my_have_nacl="no"


+ 3
- 3
src/Makefile.am Näytä tiedosto

@@ -47,8 +47,8 @@ liblol_core_headers = \
lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \
\
lol/sys/all.h \
lol/sys/init.h lol/sys/file.h lol/sys/thread.h lol/sys/threadtypes.h \
lol/sys/timer.h \
lol/sys/init.h lol/sys/file.h lol/sys/getopt.h lol/sys/thread.h \
lol/sys/threadtypes.h lol/sys/timer.h \
\
lol/image/all.h \
lol/image/pixel.h lol/image/color.h lol/image/image.h lol/image/movie.h \
@@ -108,7 +108,7 @@ liblol_core_sources = \
mesh/primitivemesh.cpp mesh/primitivemesh.h \
\
sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \
sys/thread.cpp sys/threadtypes.cpp \
sys/thread.cpp sys/threadtypes.cpp sys/getopt.cpp \
\
image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \
image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \


+ 2
- 0
src/lol-core.vcxproj Näytä tiedosto

@@ -202,6 +202,7 @@
<ClCompile Include="scene.cpp" />
<ClCompile Include="sprite.cpp" />
<ClCompile Include="sys\file.cpp" />
<ClCompile Include="sys\getopt.cpp" />
<ClCompile Include="sys\hacks.cpp" />
<ClCompile Include="sys\init.cpp" />
<ClCompile Include="sys\thread.cpp" />
@@ -301,6 +302,7 @@
<ClInclude Include="lol\public.h" />
<ClInclude Include="lol\sys\all.h" />
<ClInclude Include="lol\sys\file.h" />
<ClInclude Include="lol\sys\getopt.h" />
<ClInclude Include="lol\sys\init.h" />
<ClInclude Include="lol\sys\thread.h" />
<ClInclude Include="lol\sys\threadtypes.h" />


+ 6
- 0
src/lol-core.vcxproj.filter Näytä tiedosto

@@ -291,6 +291,9 @@
<ClCompile Include="sys\file.cpp">
<Filter>sys</Filter>
</ClCompile>
<ClCompile Include="sys\getopt.cpp">
<Filter>sys</Filter>
</ClCompile>
<ClCompile Include="sys\timer.cpp">
<Filter>sys</Filter>
</ClCompile>
@@ -652,6 +655,9 @@
<ClInclude Include="lol\sys\file.h">
<Filter>lol\sys</Filter>
</ClInclude>
<ClInclude Include="lol\sys\getopt.h">
<Filter>lol\sys</Filter>
</ClInclude>
<ClInclude Include="lol\gpu\framebuffer.h">
<Filter>lol\gpu</Filter>
</ClInclude>


+ 9
- 6
src/lol/sys/all.h Näytä tiedosto

@@ -1,11 +1,13 @@
//
// Lol Engine
// Lol Engine
//
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
// Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
//

#pragma once
@@ -13,6 +15,7 @@
#include <lol/sys/timer.h>
#include <lol/sys/thread.h>
#include <lol/sys/threadtypes.h>
#include <lol/sys/getopt.h>
#include <lol/sys/init.h>
#include <lol/sys/file.h>


+ 41
- 0
src/lol/sys/getopt.h Näytä tiedosto

@@ -0,0 +1,41 @@
//
// Lol Engine
//
// Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
//

#pragma once

//
// The getopt functions
// --------------------
//

namespace lol
{

class getopt
{
public:
getopt(int argc, char ** _argv);
getopt(int argc, char * const * _argv);
~getopt();

void add_arg(int short_opt, char const *long_opt, bool has_arg);
int parse();

int index;
char *arg;

private:
std::unique_ptr<struct getopt_private> m_private;
};

}


+ 195
- 0
src/sys/getopt.cpp Näytä tiedosto

@@ -0,0 +1,195 @@
//
// Lol Engine
//
// Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
//

#include <lol/engine-internal.h>

#if HAVE_GETOPT_H
# include <getopt.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif

namespace lol
{

struct getopt_private
{
getopt_private(int argc, char * const * _argv)
: m_argc(argc),
m_argv(_argv)
{}

#if HAVE_GETOPT_LONG
typedef option optdesc;
#else
struct optdesc
{
char const *name;
int has_arg;
int *flag;
int val;
};
#endif

int m_argc;
char * const *m_argv;

String m_optstring;
array<optdesc> m_opts;
};

getopt::getopt(int argc, char ** _argv)
: index(1),
arg(nullptr),
m_private(new getopt_private(argc, _argv))
{
}

getopt::getopt(int argc, char * const * _argv)
: index(1),
arg(nullptr),
m_private(new getopt_private(argc, _argv))
{
}

getopt::~getopt()
{
}

void getopt::add_arg(int short_opt, char const *long_opt, bool has_arg)
{
getopt_private::optdesc o = { long_opt, has_arg, nullptr, short_opt };
m_private->m_opts.push(o);

if (isalnum(short_opt))
{
m_private->m_optstring += (char)short_opt;
if (has_arg)
m_private->m_optstring += ':';
}
}

int getopt::parse()
{
int longindex = 0; // FIXME: what is this?

#if HAVE_GETOPT_LONG
int ret;
optind = this->index;
optarg = this->arg;
m_private->m_opts.push(getopt_private::optdesc { nullptr, 0, nullptr, 0 });
ret = getopt_long(m_private->m_argc, m_private->m_argv, m_private->m_optstring.C(),
(option const *)m_private->m_opts.data(), &longindex);
this->index = optind;
this->arg = optarg;
return ret;

#else
/* XXX: this getopt_long implementation should not be trusted for other
* applications without any serious peer reviewing. It “just works” with
* zzuf and a few libcaca programs but may fail miserably in other
* programs. */
char **argv = (char **)(uintptr_t)m_private->m_argv;
char *flag;

if (this->index >= m_private->m_argc)
return -1;

flag = argv[this->index];

if (flag[0] == '-' && flag[1] != '-')
{
char const *tmp;
int ret = flag[1];

if (ret == '\0')
return -1;

tmp = strchr(m_private->m_optstring.C(), ret);
if (!tmp || ret == ':')
return '?';

this->index++;
if (tmp[1] == ':')
{
if (flag[2] != '\0')
this->arg = flag + 2;
else if (this->index < m_private->m_argc)
this->arg = argv[this->index++];
else
goto too_few;
return ret;
}

if (flag[2] != '\0')
{
flag[1] = '-';
this->index--;
argv[this->index]++;
}

return ret;
}

if (flag[0] == '-' && flag[1] == '-')
{
if (flag[2] == '\0')
return -1;

for (int i = 0; m_private->m_opts[i].name; i++)
{
size_t l = strlen(m_private->m_opts[i].name);

if (strncmp(flag + 2, m_private->m_opts[i].name, l))
continue;

switch (flag[2 + l])
{
case '=':
if (!m_private->m_opts[i].has_arg)
goto bad_opt;
longindex = i;
this->index++;
this->arg = flag + 2 + l + 1;
return m_private->m_opts[i].val;
case '\0':
longindex = i;
this->index++;
if (m_private->m_opts[i].has_arg)
{
if (this->index < m_private->argc)
this->arg = argv[this->index++];
else
goto too_few;
}
return m_private->m_opts[i].val;
default:
break;
}
}
bad_opt:
fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag);
return '?';

too_few:
fprintf(stderr, "%s: option `%s' requires an argument\n",
argv[0], flag);
return '?';
}

return -1;
#endif
}

} // namespace lol


+ 74
- 36
tools/lolremez/lolremez.cpp Näytä tiedosto

@@ -1,7 +1,7 @@
//
// LolRemez - Remez algorithm implementation
//
// Copyright © 2005—2015 Sam Hocevar <sam@hocevar.net>
// Copyright © 2005—2016 Sam Hocevar <sam@hocevar.net>
//
// This program is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
@@ -21,70 +21,108 @@
#include "solver.h"
#include "expression.h"

using lol::array;
using lol::real;
using lol::String;

void FAIL(char const *message)
static void version(void)
{
printf("Error: %s\n", message);
printf("lolremez %s\n", PACKAGE_VERSION);
printf("Copyright © 2005—2016 Sam Hocevar <sam@hocevar.net>\n");
printf("This program is free software. It comes without any warranty, to the extent\n");
printf("permitted by applicable law. You can redistribute it and/or modify it under\n");
printf("the terms of the Do What the Fuck You Want to Public License, Version 2, as\n");
printf("published by the WTFPL Task Force. See http://www.wtfpl.net/ for more details.\n");
printf("\n");
printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
}

static void usage()
{
printf("Usage: lolremez [-d degree] [-r xmin:xmax] x-expression [x-error]\n");
printf(" lolremez -h | --help\n");
printf(" lolremez -V | --version\n");
printf("Find a polynomial approximation for x-expression.\n");
printf("\n");
printf("Usage:\n");
printf(" lolremez [-d degree] [-i xmin xmax] x-expression [x-error]\n");
printf("Mandatory arguments to long options are mandatory for short options too.\n");
printf(" -d, --degree <degree> degree of final polynomial\n");
printf(" -r, --range <xmin>:<xmax> range over which to approximate\n");
printf(" -h, --help display this help and exit\n");
printf(" -V, --version output version information and exit\n");
printf("\n");
printf("Example:\n");
printf(" lolremez -d 4 -i -1 1 \"atan(exp(1+x))\"\n");
printf(" lolremez -d 4 -i -1 1 \"atan(exp(1+x))\" \"exp(1+x)\"\n");
printf("Examples:\n");
printf(" lolremez -d 4 -r -1:1 \"atan(exp(1+x))\"\n");
printf(" lolremez -d 4 -r -1:1 \"atan(exp(1+x))\" \"exp(1+x)\"\n");
printf("\n");
printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
}

static void FAIL(char const *message)
{
printf("Error: %s\n", message);
printf("\n");
usage();
exit(EXIT_FAILURE);
}

/* See the tutorial at http://lolengine.net/wiki/doc/maths/remez */
int main(int argc, char **argv)
{
char const *xmin = "-1", *xmax = "1";
String xmin("-1"), xmax("1");
char const *f = nullptr, *g = nullptr;
int degree = 4;

for (int i = 1; i < argc; ++i)
{
if (argv[i] == String("-d"))
{
if (i + 1 >= argc)
FAIL("not enough arguments for -d");
lol::getopt opt(argc, argv);
opt.add_arg('d', "degree", true);
opt.add_arg('r', "range", true);
opt.add_arg('h', "help", false);
opt.add_arg('v', "version", false);

degree = atoi(argv[++i]);
}
else if (argv[i] == String("-i"))
{
if (i + 2 >= argc)
FAIL("not enough arguments for -i");
for (;;)
{
int c = opt.parse();
if (c == -1)
break;

xmin = argv[++i];
xmax = argv[++i];
}
else if (g)
{
FAIL("unknown argument");
}
else if (f)
{
g = argv[i];
}
else
switch (c)
{
f = argv[i];
case 'd': /* --degree */
degree = atoi(opt.arg);
break;
case 'r': { /* --range */
array<String> arg = String(opt.arg).split(':');
if (arg.count() != 2)
FAIL("invalid range");
xmin = arg[0];
xmax = arg[1];
} break;
case 'h': /* --help */
usage();
return EXIT_SUCCESS;
case 'v': /* --version */
version();
return EXIT_SUCCESS;
default:
return EXIT_FAILURE;
}
}

if (opt.index < argc)
f = argv[opt.index++];

if (opt.index < argc)
g = argv[opt.index++];

if (!f)
FAIL("no function specified");
else if (opt.index < argc)
FAIL("too many arguments");

if (real(xmin) >= real(xmax))
if (real(xmin.C()) >= real(xmax.C()))
FAIL("invalid range");

remez_solver solver(degree, 20);
solver.run(xmin, xmax, f, g);
solver.run(xmin.C(), xmax.C(), f, g);

return 0;
}


Ladataan…
Peruuta
Tallenna