Commit eabfdf6f authored by Vivien Kraus's avatar Vivien Kraus
Browse files

Start moving away from gengetopt (no i18n)

parent b7f7aa12
Pipeline #70098 passed with stages
in 5 minutes and 39 seconds
......@@ -81,7 +81,7 @@ AM_LDADD = $(LTLIBINTL) $(LTLIBTHREAD) @INTL_MACOSX_LIBS@
AM_MAKEINFOHTMLFLAGS =
CLEANFILES =
TESTS =
AM_TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute
AM_TESTS_ENVIRONMENT = LANG="C" $(LIBTOOL) --mode=execute
if HAVE_VALGRIND
AM_TESTS_ENVIRONMENT += $(VALGRIND) --tool=memcheck
endif # HAVE_VALGRIND
......
......@@ -19,6 +19,7 @@
(echo "@setfilename tarot.info" \
&& echo '\bye') > doc/tarot.texi || exit 1
gnulib-tool --import malloc getopt-gnu assert gettext-h setlocale
gnulib-tool --libtool \
--import malloc-gnu getopt-gnu assert gettext-h setlocale xalloc
autoreconf -vif || exit 1
rm doc/tarot.texi || exit 1
......@@ -14,6 +14,7 @@ make indent || exit 1
# Build the recursive targets in parallel depth-first:
(cd lib && make -j 16) || exit 1
# src/program/tarot is called when making the manual page.
make -j 16 src/program/tarot || exit 1
......
dnl Copyright (C) 2017, 2018 Vivien Kraus <vivien@planete-kraus.eu>
dnl
dnl This program is free software: you can redistribute it and/or
dnl modify it under the terms of the GNU General Public License as
dnl published by the Free Software Foundation, either version 3 of the
dnl License, or (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see
dnl <http://www.gnu.org/licenses/>.
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([tarot],
......@@ -22,6 +9,7 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([m4])
AC_CONFIG_MACRO_DIRS([custom-m4])
# Checks for programs.
AC_PROG_CC
AC_PROG_CC_STDC
gl_EARLY
......@@ -48,8 +36,8 @@ AS_IF([test "x$enable_valgrind" = "xyes"], [
])
AM_CONDITIONAL([HAVE_VALGRIND], [test "x$HAVE_VALGRIND" = "xyes"])
# Checks for libraries.
gl_INIT
AC_ARG_WITH([asan], AS_HELP_STRING([--with-asan=yes],
[Enforce AddressSanitizer]))
AS_IF([test "$with_asan" = "xyes"], [
......@@ -57,7 +45,6 @@ AS_IF([test "$with_asan" = "xyes"], [
AC_MSG_ERROR([ASAN is not working.])
])
])
AC_ARG_WITH([libunistring], AS_HELP_STRING([--with-libunistring=yes],
[Try to link with libunistring (default: if available)]))
AS_IF([test "x$with_libunistring" != "xno"], [
......@@ -71,13 +58,30 @@ AS_IF([test "x$with_libunistring" != "xno"], [
])
])
])
AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [AC_MSG_ERROR([readline is not working.])])
AC_SEARCH_LIBS([readline], [readline], [], [AC_MSG_ERROR([readline is not working.])])
AC_SEARCH_LIBS([add_history], [readline], [], [AC_MSG_ERROR([readline is not working.])])
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.19])
# Checks for header files.
AC_FUNC_ALLOCA
AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [AC_MSG_ERROR([readline is not working.])])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_C_INLINE
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT8_T
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
# Checks for library functions.
AC_CONFIG_FILES([
po/Makefile.in
Makefile
......@@ -86,7 +90,6 @@ AC_CONFIG_FILES([
.dir-locals.el
])
dnl According to the GNU coding standards
AC_DEFINE([FIRST_LINE], [1], [First line of a file, for the lexer])
AC_DEFINE([FIRST_COLUMN], [1], [First column in a line, for the lexer])
AC_DEFINE([TAB_WIDTH], [8], [Number of columns in a tab])
......
......@@ -20,6 +20,7 @@ sh ./autogen.sh || exit 1
|| (cat config.log; exit 1)
make -j 16 indent || exit 1
## The introspected programs are invalid
(cd lib && make -j 16) || exit 1
make -j 16 src/program/tarot || exit 1
make -j 16 dist || exit 1
make -j 16 || exit 1
......
# List of source files which contain translatable strings.
src/program/options.c
src/program/main.c
src/program/tarot-bid-implementation.c
src/program/tarot-call-implementation.c
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: tarot 0.0.4-d030\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
"POT-Creation-Date: 2018-08-21 23:07+0200\n"
"POT-Creation-Date: 2018-08-22 20:53+0200\n"
"PO-Revision-Date: 2018-08-21 22:48+0200\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French\n"
......@@ -18,12 +18,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/program/main.c:105
#: src/program/main.c:91
#, c-format
msgid "Dynamic memory exhausted.\n"
msgstr "Plus de mémoire dynamique.\n"
#: src/program/main.c:119
#: src/program/main.c:105
#, c-format
msgid ""
"tarot Copyright (C) 2018 Vivien Kraus\n"
......@@ -36,12 +36,12 @@ msgstr ""
"Ceci est un logiciel libre, vous êtes invité à le redistribuer\n"
"sous certaines conditions ; tapez « license » pour plus de détails.\n"
#: src/program/main.c:260
#: src/program/main.c:182
#, c-format
msgid "Unknown command '%s', please try 'help'\n"
msgstr "Commande « %s » inconnue, veuillez essayer « help » (pour /aide/)\n"
#: src/program/main.c:288
#: src/program/main.c:210
#, c-format
msgid ""
"Manage the game of tarot.\n"
......@@ -84,7 +84,7 @@ msgstr ""
"\n"
"Appelez chaque commande avec « --help » pour avoir plus d'aide.\n"
#: src/program/main.c:315
#: src/program/main.c:237
#, c-format
msgid "The game has been restarted.\n"
msgstr "La partie a recommencé.\n"
......
......@@ -23,7 +23,6 @@ noinst_LTLIBRARIES += %reldir%/libcmdline.la
dist_mansix_DATA += %reldir%/tarot.6.gz
EXTRA_DIST += \
%reldir%/tarot.gg \
%reldir%/tarot-help.gg \
%reldir%/tarot-version.gg \
%reldir%/tarot-license.gg \
......@@ -54,8 +53,10 @@ EXTRA_DIST += \
%reldir%/tarot-play-implementation.c
%canon_reldir%_libcmdline_la_SOURCES = \
%reldir%/cmdline.c \
%reldir%/cmdline.h \
%reldir%/options.h \
%reldir%/options.c \
%reldir%/tokenizer.h \
%reldir%/tokenizer.c \
%reldir%/tarot-help.c \
%reldir%/tarot-help.h \
%reldir%/tarot-version.c \
......@@ -94,9 +95,13 @@ EXTRA_DIST += \
$(AM_CPPFLAGS)
%canon_reldir%_libcmdline_la_LIBADD = \
$(asan_LIBS) \
$(AM_LIBS)
$(AM_LIBS) \
lib/libgnu.la
%canon_reldir%_libcmdline_la_LDFLAGS = \
$(AM_LDADD)
$(AM_LDADD) \
$(LTLIBINTL) \
$(LTLIBTHREAD) \
@INTL_MACOSX_LIBS@
%canon_reldir%_tarot_SOURCES = \
%reldir%/main.c
......@@ -111,7 +116,10 @@ EXTRA_DIST += \
%reldir%/libcmdline.la \
src/liblibtarot.la \
$(asan_LIBS) \
$(AM_LDADD)
$(AM_LDADD) \
$(LTLIBINTL) \
$(LTLIBTHREAD) \
@INTL_MACOSX_LIBS@
AM_CPPFLAGS += -I $(srcdir)/%reldir% -I %reldir%
......@@ -121,9 +129,6 @@ INDENTED += \
%reldir%/main.c: %reldir%/tarot-help.h %reldir%/tarot-version.h %reldir%/tarot-license.h %reldir%/tarot-new.h %reldir%/tarot-status.h %reldir%/tarot-setup.h %reldir%/tarot-deal.h %reldir%/tarot-bid.h %reldir%/tarot-decl.h %reldir%/tarot-call.h %reldir%/tarot-dog.h %reldir%/tarot-discard.h %reldir%/tarot-handful.h %reldir%/tarot-play.h
%reldir%/cmdline.c %reldir%/cmdline.h: %reldir%/tarot.gg
$(AM_V_GEN) (cd $(srcdir)/%reldir% && $(GENGETOPT) < tarot.gg)
%.h %.c: %.gg
$(AM_V_GEN) ($(GENGETOPT) < $<)
......
......@@ -20,7 +20,8 @@
#include <config.h>
#include <tarot.h>
#include "cmdline.h"
#include "options.h"
#include "tokenizer.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
......@@ -56,28 +57,13 @@ static int work ();
int
main (int argc, char *argv[])
{
struct gengetopt_args_info args;
int error = 0;
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
error = cmdline_parser (argc, argv, &args);
if (error == 0 && args.help_given)
{
cmdline_parser_print_help ();
return 0;
}
if (error == 0 && args.version_given)
{
cmdline_parser_print_version ();
}
if (error == 0)
{
init ();
while (work () == 0)
;
}
return error;
tarot_options_init (argc, argv);
init ();
while (work () == 0)
;
}
static int handle_help (int argc, char **argv);
......@@ -123,77 +109,13 @@ under certain conditions; type `license' for details.\n\
"));
}
static size_t
str_to_token (const char *str, char **end, size_t max, char *dest)
{
size_t needed = 0;
*end = (char *) str;
while (**end == ' ' || **end == '\t')
{
*end = *end + 1;
}
while (**end != '\0' && **end != ' ' && **end != '\t')
{
if (needed < max)
{
dest[needed] = **end;
}
*end = *end + 1;
needed++;
}
if (needed >= max && max > 0)
{
dest[max - 1] = '\0';
}
else if (needed < max)
{
dest[needed] = '\0';
}
return needed;
}
static void
tokenize (const char *str, int *argc, char ***argv)
{
char *end = (char *) str;
int i = 0;
char **arg_values;
*argc = 0;
while (str_to_token (end, &end, 0, NULL) != 0)
{
*argc = *argc + 1;
}
arg_values = x_malloc ((*argc + 1) * sizeof (char *));
end = (char *) str;
for (i = 0; i < *argc; i++)
{
char *ptr = end;
size_t needed = str_to_token (ptr, &end, 0, NULL);
arg_values[i] = x_malloc (1 + needed);
str_to_token (ptr, &end, needed + 1, arg_values[i]);
}
arg_values[*argc] = NULL;
*argv = arg_values;
}
static void
free_argv (int argc, char **argv)
{
int i = 0;
for (i = 0; i < argc; i++)
{
free (argv[i]);
}
free (argv);
}
static int
parse (const char *str)
{
int argc;
size_t argc;
char **argv;
int ret = 0;
tokenize (str, &argc, &argv);
tarot_tokenize_alloc (str, &argc, &argv);
if (argc == 0)
{
ret = 0;
......@@ -260,7 +182,7 @@ parse (const char *str)
fprintf (stderr, _("Unknown command '%s', please try 'help'\n"),
argv[0]);
}
free_argv (argc, argv);
tarot_tokens_free (argc, argv);
return ret;
}
......
/**
* file options.c Command line argument parser.
*
* Copyright (C) 2018 Vivien Kraus <vivien@planete-kraus.eu>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "options.h"
#include <tarot.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "gettext.h"
#include <locale.h>
#include "getopt.h"
#define _(String) gettext (String)
#define N_(String) String
void
tarot_options_init (int argc, char *argv[])
{
int c = 0;
while (1)
{
static struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'V'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "hV", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 'h':
printf (_("%s\n\
Play tarot.\n\
\n\
Usage: %s [OPTIONS]...\n\
\n\
Available options:\n\
-h, --help Print this help message and exit\n\
-V, --version Print version information and exit\n\
"), PACKAGE_VERSION, argv[0]);
exit (0);
break;
case 'V':
printf (_("%s\n\
Copyright (C) 2017, 2018 Vivien Kraus <vivien@planete-kraus.eu>\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), PACKAGE_VERSION);
exit (0);
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort ();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
fprintf (stderr, _("Unrecognized arguments:\n"));
while (optind < argc)
{
fprintf (stderr, " - %s\n", argv[optind++]);
}
fprintf (stderr, "\n");
}
}
/**
* file options.h Command line argument parser.
*
* Copyright (C) 2018 Vivien Kraus <vivien@planete-kraus.eu>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef H_TAROT_OPTIONS_INCLUDED
#define H_TAROT_OPTIONS_INCLUDED
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
void tarot_options_init (int argc, char *argv[]);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* H_TAROT_OPTIONS_INCLUDED */
purpose "Play the tarot game."
description "Manage a game of tarot."
versiontext "Copyright (C) 2017, 2018 Vivien Kraus \
<vivien@planete-kraus.eu>\nThis is free software; see the source for \
copying conditions. There is NO warranty; not even for \
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
args "-S"
\ No newline at end of file
/**
* file tokenizer.c Command line argument tokenizer for the help
* command.
*
* Copyright (C) 2018 Vivien Kraus <vivien@planete-kraus.eu>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "xalloc.h"
static size_t
parse_token (const char *str, char **end, size_t max, char *where)
{
size_t ret = 0, i = 0;
*end = (char *) str;
while (**end == ' ' || **end == '\t')
{
*end = *end + 1;
}
while (**end != ' ' && **end != '\t' && **end != '\0')
{
if (i < max)
{
where[i] = **end;
}
i++;
*end = *end + 1;
ret++;
}
if (i < max)
{
where[i] = '\0';
}
else if (max != 0)
{
where[max - 1] = '\0';
}
return ret;
}
size_t
tarot_tokenize (const char *str,
size_t max,
size_t * lengths, const size_t * max_lengths, char **tokens)
{
size_t ret = 0;
while (*str != '\0')
{
char *end;
size_t token_length;
size_t tk_max = 0;
char *where = NULL;
size_t length_required = 0;
if (max != 0)
{
tk_max = *max_lengths;
where = *tokens;
}
length_required = parse_token (str, &end, tk_max, where);
if (max != 0)
{
*lengths = length_required;
lengths++;
max_lengths++;
tokens++;
}
ret++;
str = end;
}
return ret;
}
void
tarot_tokenize_alloc (const char *str, size_t * argc, char ***argv)
{
size_t n = tarot_tokenize (str, 0, NULL, NULL, NULL);
size_t *lengths = xmalloc (n * sizeof (size_t));
size_t *max_lengths = xcalloc (n, sizeof (size_t));
char **tokens = xmalloc (n * sizeof (char *));
size_t n2 = tarot_tokenize (str, n, lengths, max_lengths, tokens);
size_t i = 0;
assert (n2 == n);
for (i = 0; i < n; i++)
{
max_lengths[i] = lengths[i] + 1;
tokens[i] = xmalloc (max_lengths[i]);
}
n2 = tarot_tokenize (str, n, lengths, max_lengths, tokens);
assert (n2 == n);
for (i = 0; i < n; i++)
{
assert (lengths[i] + 1 == max_lengths[i]);
}
free (max_lengths);
free (lengths);
*argc = n;
*argv = tokens;
}
void
tarot_tokens_free (size_t argc, char **argv)
{
size_t i = 0;
for (i = 0; i < argc; i++)
{
free (argv[i]);
}
free (argv);
}
/**
* file tokenizer.h Command line argument tokenizer for the help
* command.
*
* Copyright (C) 2018 Vivien Kraus <vivien@planete-kraus.eu>