/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include "mailutils/libargp.h" /* ************************************************************************* */ /* Capability array and auxiliary functions. */ /* ************************************************************************* */ #define MU_MAX_CAPA 24 struct argp_capa { char *capability; struct argp_child *child; } mu_argp_capa[MU_MAX_CAPA] = { {NULL,} }; int mu_register_argp_capa (const char *name, struct argp_child *child) { int i; for (i = 0; i < MU_MAX_CAPA; i++) if (mu_argp_capa[i].capability == NULL) { mu_argp_capa[i].capability = strdup (name); mu_argp_capa[i].child = child; return 0; } return 1; } static struct argp_capa * find_capa (const char *name) { int i; for (i = 0; mu_argp_capa[i].capability; i++) if (strcmp (mu_argp_capa[i].capability, name) == 0) return &mu_argp_capa[i]; return NULL; } static struct argp * mu_build_argp (const struct argp *template, char **capa) { int n; int nchild; struct argp_child *ap; const struct argp_option *opt; struct argp *argp; int group = 0; /* Count the capabilities. */ for (n = 0; capa && capa[n]; n++) ; if (template->children) for (; template->children[n].argp; n++) ; ap = calloc (n + 1, sizeof (*ap)); if (!ap) { mu_error (_("not enough memory")); abort (); } /* Copy the template's children. */ nchild = 0; if (template->children) for (n = 0; template->children[n].argp; n++, nchild++) ap[nchild] = template->children[n]; /* Find next group number */ for (opt = template->options; opt && ((opt->name && opt->key) || opt->doc); opt++) if (opt->group > group) group = opt->group; group++; /* Append any capabilities to the children or options, as appropriate. */ for (n = 0; capa && capa[n]; n++) { struct argp_capa *cp = find_capa (capa[n]); if (cp) { ap[nchild] = *cp->child; ap[nchild].group = group++; nchild++; } } ap[nchild].argp = NULL; /* Copy the template, and give it the expanded children. */ argp = malloc (sizeof (*argp)); if (!argp) { mu_error (_("not enough memory")); abort (); } memcpy (argp, template, sizeof (*argp)); argp->children = ap; return argp; } struct cap_buf { char **capa; size_t numcapa; size_t maxcapa; }; static void cap_buf_init (struct cap_buf *bp) { bp->numcapa = 0; bp->maxcapa = 2; bp->capa = calloc (bp->maxcapa, sizeof bp->capa[0]); if (!bp->capa) { mu_error ("%s", mu_strerror (errno)); abort (); } bp->capa[0] = NULL; } static void cap_buf_add (struct cap_buf *bp, char *str) { if (bp->numcapa == bp->maxcapa) { bp->maxcapa *= 2; bp->capa = realloc (bp->capa, bp->maxcapa * sizeof bp->capa[0]); if (!bp->capa) { mu_error ("%s", mu_strerror (errno)); abort (); } } bp->capa[bp->numcapa] = str; if (str) bp->numcapa++; } static void cap_buf_free (struct cap_buf *bp) { free (bp->capa); } static int argp_reg_action (void *item, void *data) { struct cap_buf *bp = data; cap_buf_add (bp, item); return 0; } struct argp * mu_argp_build (const struct argp *init_argp, char ***pcapa) { struct cap_buf cb; struct argp *argp; cap_buf_init (&cb); mu_gocs_enumerate (argp_reg_action, &cb); cap_buf_add (&cb, NULL); mu_libargp_init (); argp = mu_build_argp (init_argp, cb.capa); if (pcapa) *pcapa = cb.capa; else cap_buf_free (&cb); return argp; } void mu_argp_done (struct argp *argp) { free ((void*) argp->children); free ((void*) argp); }