aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-02-16 13:09:28 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-02-16 13:09:28 +0200
commitb0f10ec7274144b4e048953b11f2a4d98e055810 (patch)
tree4bcc06122d183582d0b53fe2b8ba4c87b289b96f
parent169a680208f2de8f92b4a2a4977953d4452e981f (diff)
downloadwydawca-b0f10ec7274144b4e048953b11f2a4d98e055810.tar.gz
wydawca-b0f10ec7274144b4e048953b11f2a4d98e055810.tar.bz2
Improve argument parsing
* src/cmdline.opt, src/getopt.m4: New files. * src/wydawca.c: Switch to new way of command line parsing. * src/wydawca.h (gettext): Define. * bootstrap.conf: Add formatting flags for gconf_warning and gconf_error * gconf-preproc.c (pp_list_find): Minor change. * gconf/gconf.h (gconf_warning,gconf_error): Mark as printflike. * src/.gitignore: Add cmdline.h * src/Makefile.am (wydawca_SOURCES): Add cmdline.h. (.opt.h): New rule. * src/config.c (cb_archive): Archive is now a block statement (unless type "none" is declared). (all functions): Tighten input checking * src/update-2.0.awk: Reflect the above change. * src/directive.c (process_directives): Minor change. * src/diskio.c (symlink_file): Minor change.
-rw-r--r--bootstrap.conf8
-rw-r--r--gconf/gconf-preproc.c5
-rw-r--r--gconf/gconf.h6
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am9
-rw-r--r--src/cmdline.opt90
-rw-r--r--src/config.c170
-rw-r--r--src/directive.c2
-rw-r--r--src/diskio.c2
-rw-r--r--src/getopt.m4517
-rw-r--r--src/update-2.0.awk41
-rw-r--r--src/wydawca.c75
-rw-r--r--src/wydawca.h1
13 files changed, 760 insertions, 167 deletions
diff --git a/bootstrap.conf b/bootstrap.conf
index 1d1a1fa..6119189 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -39,8 +39,4 @@ XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
--flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format\\\
- --flag=argp_error:2:c-format\\\
- --flag=__argp_error:2:c-format\\\
- --flag=argp_failure:4:c-format\\\
- --flag=__argp_failure:4:c-format\\\
- --flag=argp_fmtstream_printf:2:c-format\\\
- --flag=__argp_fmtstream_printf:2:c-format\\\
+ --flag=gconf_warning:3:c-format\\\
+ --flag=gconf_error:3:c-format\\\
'
diff --git a/gconf/gconf-preproc.c b/gconf/gconf-preproc.c
index af26d1a..eb50474 100644
--- a/gconf/gconf-preproc.c
+++ b/gconf/gconf-preproc.c
@@ -260,3 +260,3 @@ pp_list_find (gl_list_t list, struct file_data *dptr)
- while (gl_list_iterator_next (&itr, &p, NULL))
+ while (!dptr->found && gl_list_iterator_next (&itr, &p, NULL))
{
@@ -272,4 +272,3 @@ pp_list_find (gl_list_t list, struct file_data *dptr)
strcat (dptr->buf, dptr->name);
- if (dptr->found = (access (dptr->buf, F_OK) == 0))
- break;
+ dptr->found = access (dptr->buf, F_OK) == 0;
}
diff --git a/gconf/gconf.h b/gconf/gconf.h
index 8c04b6d..f88e87a 100644
--- a/gconf/gconf.h
+++ b/gconf/gconf.h
@@ -103,4 +103,6 @@ extern void gconf_print_diag(gconf_locus_t *, int, int, const char*);
-void gconf_warning(gconf_locus_t *locus, int errcode, const char *fmt, ...);
-void gconf_error(gconf_locus_t *locus, int errcode, const char *fmt, ...);
+void gconf_warning(gconf_locus_t *locus, int errcode, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+void gconf_error(gconf_locus_t *locus, int errcode, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
void gconf_set_keywords(struct gconf_keyword *kwd);
diff --git a/src/.gitignore b/src/.gitignore
index 2e5d6fc..02f7682 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,2 +1,3 @@
.gdbinit
+cmdline.h
wydawca
diff --git a/src/Makefile.am b/src/Makefile.am
index a6611af..10a6b60 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,2 +18,3 @@ sbin_PROGRAMS=wydawca
wydawca_SOURCES=\
+ cmdline.h\
config.c\
@@ -35,3 +36,9 @@ wydawca_SOURCES=\
-EXTRA_DIST=pp-setup
+BUILT_SOURCES=cmdline.h
+EXTRA_DIST=cmdline.opt getopt.m4 pp-setup
+
+SUFFIXES=.opt .c .h
+
+.opt.h:
+ m4 -s $(srcdir)/getopt.m4 $< | sed '1d' > $@
diff --git a/src/cmdline.opt b/src/cmdline.opt
new file mode 100644
index 0000000..00bbedc
--- /dev/null
+++ b/src/cmdline.opt
@@ -0,0 +1,90 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007, 2009 Sergey Poznyakoff
+
+ Wydawca 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.
+
+ Wydawca 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 wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+OPTIONS_BEGIN(gnu, "wydawca",
+ [<wydawca synchronizes files from a set of upload directories with the corresponding distribution sites>])
+
+OPTION(config-file,c,FILE,
+ [<use FILE instead of the default configuration>])
+BEGIN
+ conffile = optarg;
+END
+
+OPTION(cron,,,
+ [<log to syslog>])
+ALIAS(syslog)
+BEGIN
+ log_to_stderr = 0;
+END
+
+OPTION(stderr,e,,
+ [<log to stderr>])
+BEGIN
+END
+
+OPTION(debug,d,,
+ [<increase debugging level>])
+BEGIN
+END
+
+OPTION(include-directory,I,[DIR],
+ [<add include directory>])
+BEGIN
+ gconf_preproc_add_include_dir (optarg);
+END
+
+OPTION(dry-run,n,,
+ [<do nothing, print almost everything; implies `--debug --stderr',
+ use additional `--debug' options to get even more info>])
+BEGIN
+ log_to_stderr = 1;
+ debug_level++;
+ dry_run_mode = 1;
+END
+
+OPTION(lint,t,,
+ [<parse configuration file and exit>])
+BEGIN
+ lint_mode = 1;
+ log_to_stderr = 1;
+END
+
+OPTION(dump-grammar-trace,,,
+ [<dump configuration grammar traces>])
+BEGIN
+ gconf_gram_trace (1);
+END
+
+OPTION(dump-lex-trace,,,
+ [<dump lexical analyzer traces>])
+BEGIN
+ gconf_lex_trace (1);
+END
+
+OPTION(config-help,,,
+ [<show configuration file summary>])
+BEGIN
+ config_help ();
+ exit (0);
+END
+
+OPTIONS_END
+
+void
+parse_options(int argc, char *argv[])
+{
+ GETOPT(argc, argv)
+}
diff --git a/src/config.c b/src/config.c
index 3545e05..32b54dd 100644
--- a/src/config.c
+++ b/src/config.c
@@ -220,3 +220,3 @@ assert_string_arg (gconf_locus_t *locus,
enum gconf_callback_command cmd,
- gconf_value_t *value)
+ const gconf_value_t *value)
{
@@ -227,5 +227,5 @@ assert_string_arg (gconf_locus_t *locus,
}
- if (value->type != GCONF_TYPE_STRING)
+ if (!value || value->type != GCONF_TYPE_STRING)
{
- gconf_error (locus, 0, _("expected scalar value but found list"));
+ gconf_error (locus, 0, _("expected scalar value as a tag"));
return 1;
@@ -269,5 +269,5 @@ cb_mailer (enum gconf_callback_command cmd,
}
- if (value->type != GCONF_TYPE_STRING)
+ if (!value || value->type != GCONF_TYPE_STRING)
{
- gconf_error (locus, 0, _("expected scalar value but found list"));
+ gconf_error (locus, 0, _("expected scalar value"));
return 1;
@@ -573,3 +573,3 @@ cb_sql (enum gconf_callback_command cmd,
case gconf_callback_section_begin:
- if (value->type != GCONF_TYPE_STRING || !value->v.string)
+ if (!value || value->type != GCONF_TYPE_STRING)
{
@@ -616,5 +616,2 @@ cb_syslog_facility (enum gconf_callback_command cmd,
{
- struct sqlconn *pconn = varptr;
- char *p;
-
if (assert_string_arg (locus, cmd, value))
@@ -643,3 +640,3 @@ cb_define_message (enum gconf_callback_command cmd,
}
- if (value->type != GCONF_TYPE_ARRAY || value->v.arg.c != 2)
+ if (!value || value->type != GCONF_TYPE_ARRAY || value->v.arg.c != 2)
{
@@ -738,2 +735,26 @@ get_backup_version (gconf_locus_t *locus, const char *ctx,
static int
+cb_backup (enum gconf_callback_command cmd,
+ gconf_locus_t *locus,
+ void *varptr,
+ gconf_value_t *value,
+ void *cb_data)
+{
+ enum backup_type *ptype = varptr;
+
+ if (assert_string_arg (locus, cmd, value))
+ return 1;
+ *ptype = get_backup_version (locus, NULL, value->v.string);
+ return 0;
+}
+
+static struct gconf_keyword archive_kw[] = {
+ { "name", N_("file-or-dir"), N_("Name of archive file or directory"),
+ gconf_type_string, NULL, offsetof(struct archive_descr, name) },
+ { "backup", N_("type"), N_("Define backup type"),
+ gconf_type_string, NULL, offsetof(struct archive_descr, backup_type),
+ cb_backup },
+ { NULL }
+};
+
+static int
cb_archive (enum gconf_callback_command cmd,
@@ -745,66 +766,56 @@ cb_archive (enum gconf_callback_command cmd,
struct archive_descr *arch = varptr;
- gconf_value_t *argp;
- const char *type;
-
- if (cmd != gconf_callback_set_value)
- {
- gconf_error (locus, 0, _("Unexpected block statement"));
- return 1;
- }
-
- if (value->type != GCONF_TYPE_ARRAY || value->v.arg.c > 3)
- {
- gconf_error (locus, 0, _("expected 1-3 arguments"));
- return 1;
- }
-
- argp = get_arg (locus, value, 0, GCONF_TYPE_STRING);
- if (!argp)
- return 1;
+ void **pdata = cb_data;
- type = argp->v.string;
- if (strcmp (type, "none") == 0)
- {
- arch->type = archive_none;
- if (value->v.arg.c > 1)
- gconf_warning (locus, 0,
- _("rest of line ignored for archive type `none'"));
- }
- else
+ switch (cmd)
{
- argp = get_arg (locus, value, 1, GCONF_TYPE_STRING);
- if (!argp)
- return 1;
- arch->name = safe_file_name (xstrdup (argp->v.string));
- if (!arch->name)
- {
- gconf_error (locus, 0, _("invalid archive name: %s"),
- argp->v.string);
+ case gconf_callback_section_begin:
+ *pdata = arch;
+ /* fallthrough */
+ case gconf_callback_set_value:
+ if (!value)
+ {
+ gconf_error (locus, 0, _("expected tag"));
return 1;
}
-
- if (strcmp (type, "tar") == 0)
+
+ if (value->type != GCONF_TYPE_STRING)
{
- arch->type = archive_tar;
- if (value->v.arg.c > 2)
- gconf_warning (locus, 0,
- _("junk after the archive name ignored"));
+ gconf_error (locus, 0, _("expected scalar value but found list"));
+ return 1;
}
- else if (strcmp (type, "directory") == 0)
+
+ if (strcmp (value->v.string, "none") == 0)
+ arch->type = archive_none;
+ else if (strcmp (value->v.string, "tar") == 0)
+ arch->type = archive_tar;
+ else if (strcmp (value->v.string, "directory") == 0)
+ arch->type = archive_directory;
+ else
{
- arch->type = archive_directory;
- if (value->v.arg.c > 2)
- {
- argp = get_arg (locus, value, 2, GCONF_TYPE_STRING);
- arch->backup_type = get_backup_version (locus, NULL,
- argp->v.string);
- }
- else
- get_backup_version (locus,
- "VERSION_CONTROL environment variable",
- getenv ("VERSION_CONTROL"));
+ gconf_error (locus, 0, _("unknown archive type"));
+ return 1;
}
- else
- gconf_warning (locus, 0, _("unknown archive type"));
+ if (cmd == gconf_callback_section_begin)
+ return 0;
+ break;
+
+ case gconf_callback_section_end:
+ break;
+ }
+
+ if (arch->type == archive_none)
+ return 0;
+
+ if (arch->name == NULL)
+ {
+ gconf_error (locus, 0, _("at least archive name must be set"));
+ return 1;
+ }
+
+ if (arch->type == archive_tar && arch->backup_type != no_backups)
+ {
+ gconf_warning (locus, 0, _("backup type ignored for this archive type"));
+ return 1;
}
+
return 0;
@@ -945,3 +956,3 @@ cb_access_method_params (enum gconf_callback_command cmd,
}
- if (value->type != GCONF_TYPE_LIST)
+ if (!value || value->type != GCONF_TYPE_LIST)
{
@@ -956,3 +967,3 @@ cb_access_method_params (enum gconf_callback_command cmd,
{
- gconf_value_t *vp = gl_list_get_at (value->v.list, 0);
+ const gconf_value_t *vp = gl_list_get_at (value->v.list, 0);
@@ -1025,3 +1036,3 @@ cb_access_method (enum gconf_callback_command cmd,
case gconf_callback_section_begin:
- if (value->type != GCONF_TYPE_STRING || !value->v.string)
+ if (!value || value->type != GCONF_TYPE_STRING)
{
@@ -1081,7 +1092,5 @@ static struct gconf_keyword directory_kw[] = {
cb_access_method, NULL, access_method_kw },
- { "archive",
- N_("<type: string> <archive-name: string> [<backup-method: method>]"),
- N_("Set up archivation"),
- gconf_type_string, NULL, offsetof(struct directory_pair, archive),
- cb_archive },
+ { "archive", N_("type: string"), N_("Set up archivation"),
+ gconf_type_section, NULL, offsetof(struct directory_pair, archive),
+ cb_archive, NULL, archive_kw },
{ NULL }
@@ -1103,3 +1112,3 @@ cb_directory (enum gconf_callback_command cmd,
case gconf_callback_section_begin:
- if (value->type != GCONF_TYPE_STRING || !value->v.string)
+ if (!value || value->type != GCONF_TYPE_STRING)
{
@@ -1126,4 +1135,3 @@ cb_directory (enum gconf_callback_command cmd,
if (ec)
- gconf_error (locus, ec, _("cannot access %s"),
- dpair->source_dir, strerror (ec));
+ gconf_error (locus, ec, _("cannot access %s"), dpair->source_dir);
else
@@ -1135,4 +1143,3 @@ cb_directory (enum gconf_callback_command cmd,
if (ec)
- gconf_error (locus, ec, _("cannot access %s"),
- dpair->dest_dir, strerror (ec));
+ gconf_error (locus, ec, _("cannot access %s"), dpair->dest_dir);
else
@@ -1204,6 +1211,5 @@ static struct gconf_keyword wydawca_kw[] = {
- { "archive",
- N_("<type: string> <archive-name: string> [<backup-method: method>]"),
- N_("Set up archivation"),
- gconf_type_string, &default_archive_descr, 0, cb_archive },
+ { "archive", N_("type: string"), N_("Set up archivation"),
+ gconf_type_section, &default_archive_descr, 0,
+ cb_archive, NULL, archive_kw },
diff --git a/src/directive.c b/src/directive.c
index eeb82c1..ed28cc5 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -365,3 +365,3 @@ process_directives (struct file_triplet *trp, struct directory_pair *dpair)
- if (rc = argcv_get (val, NULL, NULL, &argc, &argv))
+ if ((rc = argcv_get (val, NULL, NULL, &argc, &argv)))
{
diff --git a/src/diskio.c b/src/diskio.c
index 3cffd10..2148abd 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -645,3 +645,3 @@ symlink_file (struct file_triplet *trp, struct directory_pair *dpair,
"file %s exists and is not a symbolic link",
- dst, strerror (errno));
+ dst);
rc = 1;
diff --git a/src/getopt.m4 b/src/getopt.m4
new file mode 100644
index 0000000..d6f5580
--- /dev/null
+++ b/src/getopt.m4
@@ -0,0 +1,517 @@
+dnl This file is part of GNU Rush.
+dnl Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff.
+dnl
+dnl GNU Rush is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl GNU Rush is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+divert(-1)
+changequote([<,>])
+changecom(/*,*/)
+
+dnl upcase(ARGS...)
+dnl Concatenate and convert ARGS to upper case.
+dnl
+define([<upcase>], [<translit([<$*>], [<a-z>], [<A-Z>])>])
+
+dnl concat(ARGS...)
+dnl Concatenate arguments, inserting ", " between each of pair of them.
+dnl
+define([<concat>],[<ifelse([<$#>],1,[<$1>],[<$1, concat(shift($@))>])>])
+
+dnl flushleft(ARGS...)
+dnl Concatenate ARGS and remove any leading whitespace
+dnl
+define([<flushleft>],
+ [<patsubst([<concat($*)>], [<^[ ]+>])>])
+
+dnl chop(ARGS...)
+dnl Concatenate ARGS and remove any trailing whitespace
+dnl
+define([<chop>],
+ [<patsubst([<$*>], [<[ ]+$>])>])
+
+dnl escape(ARGS...)
+dnl Concatenate ARGS and escape any occurrences of double-quotes with
+dnl backslashes.
+dnl
+define([<escape>],
+[<patsubst([<concat($*)>],[<[\"]>],[<\\\&>])>])
+
+dnl prep(ARG)
+dnl Prepare ARG for including in C strings: replace newlines with any amount
+dnl of preceding and following whitespace by a single space character, remove
+dnl leading whitespace, and escape double-quotes.
+dnl
+define([<prep>],
+ [<escape(flushleft(patsubst([<$1>],[<[ ]*
++[ ]*>],[< >])))>])
+
+dnl SHORT_OPTS
+dnl Accumulator for the 3rd argument of getopt_long
+dnl
+define([<SHORT_OPTS>],[<>])
+
+dnl GROUP(STRING)
+dnl Begin a named group of options
+dnl
+define([<GROUP>],[<dnl
+divert(3)
+ { NULL, NULL, 0, N_("prep([<$1>])") },
+divert(-1)>])
+
+define([<__GATHER_OPTIONS>],[<
+define([<KEY>],ifelse([<$2>],,[<OPTION_>]upcase(patsubst($1,-,_)),'$2'))
+ifelse([<$2>],,[<
+divert(1)
+ KEY,
+divert(-1)
+>])
+define([<SELECTOR>],ifdef([<SELECTOR>],SELECTOR) case KEY:)
+ifelse([<$1>],,,[<
+divert(2)
+ { "$1", ARGTYPE, 0, KEY },
+divert(-1)>])
+dnl
+define([<SHORT_OPTS>],SHORT_OPTS[<>]dnl
+ifelse([<$2>],,,$2[<>]ifelse(ARGTYPE,[<no_argument>],,ARGTYPE,[<required_argument>],:,ARGTYPE,[<optional_argument>],::)))
+dnl
+ifelse([<$1>],,,dnl
+[<define([<LONG_TAG>],ifelse(LONG_TAG,,[<--$1>],[<LONG_TAG; --$1>]))>])
+ifelse([<$2>],,,dnl
+[<define([<SHORT_TAG>],ifelse(SHORT_TAG,,[<-$2>],[<SHORT_TAG; -$2>]))>])
+>])
+
+dnl OPTION(long-opt, short-opt, [arg], [descr])
+dnl Introduce a command line option. Arguments:
+dnl long-opt Long option.
+dnl short-opt Short option (a single char)
+dnl (At least one of long-opt or short-opt must be present)
+dnl
+dnl Optional arguments:
+dnl arg Option argument.
+dnl descr Option description
+dnl
+dnl If arg is absent, the option does not take any arguments. If arg is
+dnl enclosed in square brackets, the option takes an optional argument.
+dnl Otherwise, the argument is required.
+dnl
+dnl If descr is not given the option will not appear in the --help and
+dnl --usage outputs.
+dnl
+define([<OPTION>],[<
+pushdef([<LONG_TAG>])
+pushdef([<SHORT_TAG>])
+pushdef([<ARGNAME>],[<$3>])
+pushdef([<DOCSTRING>],[<prep([<$4>])>])
+pushdef([<ARGTYPE>],[<ifelse([<$3>],,[<no_argument>],dnl
+patsubst([<$3>],[<\[.*\]>]),,[<optional_argument>],dnl
+[<required_argument>])>])
+__GATHER_OPTIONS($@)
+>])
+
+dnl ALIAS(long-opt, short-opt)
+dnl Declare aliases for the previous OPTION statement.
+dnl long-opt Long option.
+dnl short-opt Short option (a single char)
+dnl (At least one of long-opt or short-opt must be present)
+dnl An OPTION statement may be followed by any number of ALIAS statements.
+dnl
+define([<ALIAS>],[<
+__GATHER_OPTIONS($1,$2)
+>])
+
+dnl BEGIN
+dnl Start an action associated with the declared option. Must follow OPTION
+dnl statement, with optional ALIAS statements in between.
+dnl
+define([<BEGIN>],[<
+ifelse([<DOCSTRING>],,,[<
+divert(3)
+ { "translit(dnl
+ifelse(SHORT_TAG,,LONG_TAG,[<SHORT_TAG[<>]ifelse(LONG_TAG,,,; LONG_TAG)>]),
+ [<;>],[<,>])", ifelse(ARGNAME,,[<NULL, 0>],
+[<ifelse(ARGTYPE,[<optional_argument>],
+[<patsubst(ARGNAME,[<\[\(.*\)\]>],[<N_("\1"), 1>])>],[<N_("ARGNAME"), 0>])>]), N_("DOCSTRING") },
+divert(-1)>])
+popdef([<ARGTYPE>])
+popdef([<ARGNAME>])
+popdef([<DOCSTRING>])
+divert(4)dnl
+popdef([<LONG_TAG>])dnl
+popdef([<SHORT_TAG>])dnl
+ SELECTOR
+ {
+>])
+
+dnl END
+dnl Finish the associated action
+dnl
+define([<END>],[<
+ break;
+ }
+divert(-1)
+undefine([<SELECTOR>])>])
+
+dnl GETOPT(argc, argv, [default])
+dnl Emit option parsing code. Arguments:
+dnl
+dnl argc Name of the 1st argument to getopt_long.
+dnl argv Name of the 2nd argument to getopt_long.
+dnl default Code for the default branch
+dnl
+define([<GETOPT>],[<
+ {
+ int c;
+
+ifelse([<$#>],3,opterr = 0;)
+ while ((c = getopt_long($1, $2, "SHORT_OPTS",
+ long_options, NULL)) != EOF)
+ {
+ switch (c)
+ {
+ default:
+ ifelse([<$#>],3,$3,[<exit(1)>]);
+
+ undivert(4)
+ }
+ }
+ }
+>])
+
+define([<STDFUNC>],[<
+divert(0)
+void print_help(void);
+void print_usage(void);
+divert(5)
+const char *program_version = [<$1>];
+static char doc[] = N_("[<$3>]");
+static char args_doc[] = N_("[<$4>]");
+const char *program_bug_address = "<" PACKAGE_BUGREPORT ">";
+
+#define DESCRCOLUMN 30
+#define RMARGIN 79
+#define GROUPCOLUMN 2
+#define USAGECOLUMN 13
+
+static void
+indent (size_t start, size_t col)
+{
+ for (; start < col; start++)
+ putchar (' ');
+}
+
+static void
+print_option_descr (const char *descr, size_t lmargin, size_t rmargin)
+{
+ while (*descr)
+ {
+ size_t s = 0;
+ size_t i;
+ size_t width = rmargin - lmargin;
+
+ for (i = 0; ; i++)
+ {
+ if (descr[i] == 0 || isspace (descr[i]))
+ {
+ if (i > width)
+ break;
+ s = i;
+ if (descr[i] == 0)
+ break;
+ }
+ }
+ printf ("%*.*s\n", s, s, descr);
+ descr += s;
+ if (*descr)
+ {
+ indent (0, lmargin);
+ descr++;
+ }
+ }
+}
+
+void
+print_help(void)
+{
+ unsigned i;
+
+ printf ("%s %s [%s]... %s\n", _("Usage:"), [<$2>], _("[<OPTION>]"),
+ gettext (args_doc));
+ if (doc && doc[0])
+ print_option_descr(gettext (doc), 0, RMARGIN);
+ putchar ('\n');
+
+ for (i = 0; i < sizeof (opthelp) / sizeof (opthelp[0]); i++)
+ {
+ unsigned n;
+ if (opthelp[i].opt)
+ {
+ n = printf (" %s", opthelp[i].opt);
+ if (opthelp[i].arg)
+ {
+ char *cb, *ce, *sep = "";
+ if (opthelp[i].is_optional)
+ {
+ cb = "[";
+ ce = "]";
+ }
+ else
+ cb = ce = "";
+
+ if (strlen (opthelp[i].opt) == 2)
+ {
+ if (!opthelp[i].is_optional)
+ sep = " ";
+ }
+ else
+ sep = "=";
+ n += printf ("%s%s%s%s", cb, sep, gettext (opthelp[i].arg), ce);
+ }
+ if (n >= DESCRCOLUMN)
+ {
+ putchar ('\n');
+ n = 0;
+ }
+ indent (n, DESCRCOLUMN);
+ print_option_descr (gettext (opthelp[i].descr), DESCRCOLUMN, RMARGIN);
+ }
+ else
+ {
+ if (i)
+ putchar ('\n');
+ indent (0, GROUPCOLUMN);
+ print_option_descr (gettext (opthelp[i].descr),
+ GROUPCOLUMN, RMARGIN);
+ putchar ('\n');
+ }
+ }
+
+ putchar ('\n');
+dnl **************************************************************************
+dnl This string cannot be split over several lines, because this would trigger
+dnl a bug in GNU M4 (version 1.4.9 and 1.4.10), which would insert #line
+dnl directives between the lines.
+dnl **************************************************************************
+ print_option_descr (_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN);
+ putchar ('\n');
+ printf (_("Report bugs to %s.\n"), program_bug_address);
+}
+
+void
+print_usage(void)
+{
+ unsigned i;
+ int f = 0;
+ unsigned n;
+ char buf[RMARGIN+1];
+
+#define FLUSH dnl
+ do dnl
+ { dnl
+ buf[n] = 0; dnl
+ printf ("%s\n", buf); dnl
+ n = USAGECOLUMN; dnl
+ memset (buf, ' ', n); dnl
+ } dnl
+ while (0)
+#define ADDC(c) dnl
+ do { if (n == RMARGIN) FLUSH; buf[n++] = c; } while (0)
+
+ n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"), [<$2>]);
+
+ /* Print a list of short options without arguments. */
+ for (i = 0; i < sizeof (opthelp) / sizeof (opthelp[0]); i++)
+ {
+ if (opthelp[i].opt && opthelp[i].descr && opthelp[i].opt[1] != '-'
+ && opthelp[i].arg == NULL)
+ {
+ if (f == 0)
+ {
+ ADDC('[');
+ ADDC('-');
+ f = 1;
+ }
+ ADDC(opthelp[i].opt[1]);
+ }
+ }
+ if (f)
+ ADDC(']');
+
+ /* Print a list of short options with arguments. */
+ for (i = 0; i < sizeof (opthelp) / sizeof (opthelp[0]); i++)
+ {
+ if (opthelp[i].opt && opthelp[i].descr && opthelp[i].opt[1] != '-'
+ && opthelp[i].arg)
+ {
+ size_t len = 5
+ + strlen (opthelp[i].arg)
+ + (opthelp[i].is_optional ? 2 : 1);
+ if (n + len > RMARGIN) FLUSH;
+ buf[n++] = ' ';
+ buf[n++] = '[';
+ buf[n++] = '-';
+ buf[n++] = opthelp[i].opt[1];
+ if (opthelp[i].is_optional)
+ {
+ buf[n++] = '[';
+ strcpy (&buf[n], opthelp[i].arg);
+ n += strlen (opthelp[i].arg);
+ buf[n++] = ']';
+ }
+ else
+ {
+ buf[n++] = ' ';
+ strcpy (&buf[n], opthelp[i].arg);
+ n += strlen (opthelp[i].arg);
+ }
+ buf[n++] = ']';
+ }
+ }
+
+ /* Print a list of long options */
+ for (i = 0; i < sizeof (opthelp) / sizeof (opthelp[0]); i++)
+ {
+ if (opthelp[i].opt && opthelp[i].descr)
+ {
+ size_t len;
+ const char *longopt;
+
+ if (opthelp[i].opt[1] == '-')
+ longopt = opthelp[i].opt;
+ else if (opthelp[i].opt[2] == ',')
+ longopt = opthelp[i].opt + 4;
+ else
+ continue;
+
+ len = 3 + strlen (longopt)
+ + (opthelp[i].arg ? 1 + strlen (opthelp[i].arg)
+ + (opthelp[i].is_optional ? 2 : 0) : 0);
+ if (n + len > RMARGIN) FLUSH;
+ buf[n++] = ' ';
+ buf[n++] = '[';
+ strcpy (&buf[n], longopt);
+ n += strlen (longopt);
+ if (opthelp[i].arg)
+ {
+ buf[n++] = '=';
+ if (opthelp[i].is_optional)
+ {
+ buf[n++] = '[';
+ strcpy (&buf[n], opthelp[i].arg);
+ n += strlen (opthelp[i].arg);
+ buf[n++] = ']';
+ }
+ else
+ {
+ strcpy (&buf[n], opthelp[i].arg);
+ n += strlen (opthelp[i].arg);
+ }
+ }
+ buf[n++] = ']';
+ }
+ }
+ FLUSH;
+
+}
+
+const char version_etc_copyright[] =
+ /* Do *not* mark this string for translation. %s is a copyright
+ symbol suitable for this locale, and %d is the copyright
+ year. */
+ "Copyright %s 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff";
+
+void
+print_version_only(const char *program_version, FILE *stream)
+{
+ fprintf (stream, "%s\n", program_version);
+ /* TRANSLATORS: Translate "(C)" to the copyright symbol
+ (C-in-a-circle), if this symbol is available in the user's
+ locale. Otherwise, do not translate "(C)"; leave it as-is. */
+ fprintf (stream, version_etc_copyright, _("(C)"));
+ fputc ('\n', stream);
+}
+
+void
+print_version(const char *program_version, FILE *stream)
+{
+ print_version_only(program_version, stream);
+
+dnl **************************************************************************
+dnl This string cannot be split over serveal lines, because this would trigger
+dnl a bug in GNU M4 (version 1.4.9 and 1.4.10), which would insert #line
+dnl directives between the lines.
+dnl **************************************************************************
+ fputs (_("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n\n"),
+ stream);
+
+dnl /* TRANSLATORS: %s denotes an author name. */
+dnl fprintf (stream, _("Written by %s.\n"), "Sergey Poznyakoff");
+}
+
+divert(-1)
+popdef([<ADDC>])
+popdef([<FLUSH>])
+>])
+
+define([<OPTIONS_BEGIN>],
+ [<divert(-1)
+ define([<GETOPT_STYLE>],[<$1>])
+ ifelse([<$1>],[<gnu>],
+ [<STDFUNC([<$2 " (" PACKAGE_NAME ") " PACKAGE_VERSION>], [<$2>], [<$3>], [<$4>])>])
+>])
+
+define([<OPTIONS_END>],[<
+ifelse(GETOPT_STYLE,[<gnu>],[<
+ GROUP([<Other options>])
+ OPTION([<help>],h,,[<Give this help list>])
+ BEGIN
+ print_help ();
+ exit (0);
+ END
+ OPTION([<usage>],,,[<Give a short usage message>])
+ BEGIN
+ print_usage ();
+ exit (0);
+ END
+ OPTION([<version>],,,[<Print program version>])
+ BEGIN
+ /* Give version */
+ print_version(program_version, stdout);
+ exit (0);
+ END>])
+divert
+/* Option codes */
+enum {
+ _OPTION_INIT=255,
+ undivert(1)
+ MAX_OPTION
+};
+static struct option long_options[] = {
+ undivert(2)
+ {0, 0, 0, 0}
+};
+static struct opthelp {
+ const char *opt;
+ const char *arg;
+ int is_optional;
+ const char *descr;
+} opthelp[] = {
+ undivert(3)
+};
+undivert(5)
+>])
+
+divert(0)dnl
+/* -*- buffer-read-only: t -*- vi: set ro:
+ THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT.
+*/
+
diff --git a/src/update-2.0.awk b/src/update-2.0.awk
index 8f74d90..2fd6657 100644
--- a/src/update-2.0.awk
+++ b/src/update-2.0.awk
@@ -1 +1,17 @@
+# This file is part of Wydawca
+# Copyright (C) 2007, 2009 Sergey Poznyakoff
+#
+# Wydawca 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, or (at your option)
+# any later version.
+#
+# Wydawca 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 Wydawca. If not, see <http://www.gnu.org/licenses/>.
+
state == 1 && NF == 1 && $1 == "end" {
@@ -5,2 +21,6 @@ state == 1 && NF == 1 && $1 == "end" {
}
+state == 1 && $1 == "include" {
+ printf("m4_include(%s)\n",$2)
+ next
+}
state == 1 { print $0; next }
@@ -48,3 +68,3 @@ $1 == "file-sweep-time" || $1 == "tar-program" || $1 == "admin-address" ||
-$1 == "umask" || $1 == "archive" {
+$1 == "umask" {
len = get_indent()
@@ -57,2 +77,21 @@ $1 == "umask" || $1 == "archive" {
+$1 == "archive" {
+ len = get_indent()
+ kw = $1
+ indent(len)
+ printf("archive %s", $2)
+ if (NF > 2) {
+ print " {"
+ indent(len + 2)
+ printf("name \"%s\";\n", $3)
+ if (NF > 3) {
+ indent(len + 2)
+ printf("backup %s;\n", $4)
+ }
+ indent(len)
+ print "}"
+ } else
+ print ";"
+}
+
$1 == "project-owner" || $1 == "user-data" || $1 == "verify-user" ||
diff --git a/src/wydawca.c b/src/wydawca.c
index 36201ca..4e6e635 100644
--- a/src/wydawca.c
+++ b/