RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  j...@rpm5.org
  Module: rpm                              Date:   14-Jun-2009 18:13:21
  Branch: HEAD                             Handle: 2009061416132100

  Added files:
    rpm/tools               augtool.c augtool.h
  Modified files:
    rpm/tools               .cvsignore Makefile.am

  Log:
    - augeas: swipe a copy of augtool.c/internal.h for reworking.

  Summary:
    Revision    Changes     Path
    1.31        +1  -0      rpm/tools/.cvsignore
    2.127       +5  -2      rpm/tools/Makefile.am
    2.1         +717 -0     rpm/tools/augtool.c
    2.1         +525 -0     rpm/tools/augtool.h
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/tools/.cvsignore
  ============================================================================
  $ cvs diff -u -r1.30 -r1.31 .cvsignore
  --- rpm/tools/.cvsignore      13 May 2009 23:54:57 -0000      1.30
  +++ rpm/tools/.cvsignore      14 Jun 2009 16:13:21 -0000      1.31
  @@ -5,6 +5,7 @@
   .libs
   *.gcda
   *.gcno
  +augtool
   convertdb1
   db_tool
   debugedit
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/tools/Makefile.am
  ============================================================================
  $ cvs diff -u -r2.126 -r2.127 Makefile.am
  --- rpm/tools/Makefile.am     3 Jun 2009 09:20:58 -0000       2.126
  +++ rpm/tools/Makefile.am     14 Jun 2009 16:13:21 -0000      2.127
  @@ -18,9 +18,9 @@
        @WITH_PCRE_CPPFLAGS@ \
        @WITH_XAR_CPPFLAGS@
   
  -EXTRA_DIST = hashtab.h
  +EXTRA_DIST = augtool.h hashtab.h
   
  -EXTRA_PROGRAMS = rpmkey debugedit
  +EXTRA_PROGRAMS = augtool debugedit rpmkey
   
   RPMMISC_LDADD_COMMON = \
        $(top_builddir)/misc/librpmmisc.la \
  @@ -50,6 +50,9 @@
        rpmcmp rpmdeps @WITH_KEYUTILS_RPMKEY@ @WITH_LIBELF_DEBUGEDIT@
   dist_man_MANS =              rpmgrep.1
   
  +augtool_SOURCES =    augtool.c
  +augtool_LDADD =              $(RPM_LDADD_COMMON) -lreadline
  +
   debugedit_SOURCES =  debugedit.c hashtab.c
   debugedit_LDADD =    $(RPM_LDADD_COMMON)
   
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/tools/augtool.c
  ============================================================================
  $ cvs diff -u -r0 -r2.1 augtool.c
  --- /dev/null 2009-06-14 18:11:00 +0200
  +++ augtool.c 2009-06-14 18:13:21 +0200
  @@ -0,0 +1,717 @@
  +/*
  + * augtool.c:
  + *
  + * Copyright (C) 2007, 2008 Red Hat 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 2.1 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, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  + *
  + * Author: David Lutterkort <dlut...@redhat.com>
  + */
  +
  +#include <config.h>
  +#include "augeas.h"
  +#include "augtool.h"
  +
  +#include <readline/readline.h>
  +#include <readline/history.h>
  +#include <argz.h>
  +#include <getopt.h>
  +#include <limits.h>
  +#include <ctype.h>
  +
  +struct command {
  +    const char *name;
  +    int minargs;
  +    int maxargs;
  +    int(*handler) (char *args[]);
  +    const char *synopsis;
  +    const char *help;
  +};
  +
  +static const struct command const commands[];
  +
  +static augeas *aug = NULL;
  +static const char *const progname = "augtool";
  +static unsigned int flags = AUG_NONE;
  +const char *root = NULL;
  +char *loadpath = NULL;
  +
  +
  +static char *cleanstr(char *path, const char sep) {
  +    if (path == NULL || strlen(path) == 0)
  +        return path;
  +    char *e = path + strlen(path) - 1;
  +    while (e >= path && (*e == sep || isspace(*e)))
  +        *e-- = '\0';
  +    return path;
  +}
  +
  +static char *cleanpath(char *path) {
  +    return cleanstr(path, SEP);
  +}
  +
  +/*
  + * Dup PATH and split it into a directory and basename. The returned value
  + * points to the copy of PATH. Adding strlen(PATH)+1 to it gives the
  + * basename.
  + *
  + * If PATH can not be split, returns NULL
  + */
  +ATTRIBUTE_UNUSED
  +static char *pathsplit(const char *path) {
  +    char *ppath = strdup(path);
  +    char *pend = strrchr(ppath, SEP);
  +
  +    if (pend == NULL || pend == ppath) {
  +        free(ppath);
  +        return NULL;
  +    }
  +    *pend = '\0';
  +    return ppath;
  +}
  +
  +static char *ls_pattern(const char *path) {
  +    char *q;
  +    int r;
  +
  +    if (path[strlen(path)-1] == SEP)
  +        r = asprintf(&q, "%s*", path);
  +    else
  +        r = asprintf(&q, "%s/*", path);
  +    if (r == -1)
  +        return NULL;
  +    return q;
  +}
  +
  +static int child_count(const char *path) {
  +    char *q = ls_pattern(path);
  +    int cnt;
  +
  +    if (q == NULL)
  +        return 0;
  +    cnt = aug_match(aug, q, NULL);
  +    free(q);
  +    return cnt;
  +}
  +
  +static int cmd_ls(char *args[]) {
  +    int cnt;
  +    char *path = cleanpath(args[0]);
  +    char **paths;
  +    int i;
  +
  +    path = ls_pattern(path);
  +    if (path == NULL)
  +        return -1;
  +    cnt = aug_match(aug, path, &paths);
  +    for (i=0; i < cnt; i++) {
  +        const char *val;
  +        const char *basnam = strrchr(paths[i], SEP);
  +        int dir = child_count(paths[i]);
  +        aug_get(aug, paths[i], &val);
  +        basnam = (basnam == NULL) ? paths[i] : basnam + 1;
  +        if (val == NULL)
  +            val = "(none)";
  +        printf("%s%s= %s\n", basnam, dir ? "/ " : " ", val);
  +        free(paths[i]);
  +    }
  +    if (cnt > 0)
  +        free(paths);
  +    free(path);
  +    return 0;
  +}
  +
  +static int cmd_match(char *args[]) {
  +    int cnt;
  +    const char *pattern = cleanpath(args[0]);
  +    char **matches;
  +    int filter = (args[1] != NULL) && (strlen(args[1]) > 0);
  +    int result = 0;
  +    int i;
  +
  +    cnt = aug_match(aug, pattern, &matches);
  +    if (cnt < 0) {
  +        printf("  (error matching %s)\n", pattern);
  +        result = -1;
  +        goto done;
  +    }
  +    if (cnt == 0) {
  +        printf("  (no matches)\n");
  +        goto done;
  +    }
  +
  +    for (i=0; i < cnt; i++) {
  +        const char *val;
  +        aug_get(aug, matches[i], &val);
  +        if (val == NULL)
  +            val = "(none)";
  +        if (filter) {
  +            if (STREQ(args[1], val))
  +                printf("%s\n", matches[i]);
  +        } else {
  +            printf("%s = %s\n", matches[i], val);
  +        }
  +    }
  + done:
  +    for (i=0; i < cnt; i++)
  +        free(matches[i]);
  +    free(matches);
  +    return result;
  +}
  +
  +static int cmd_rm(char *args[]) {
  +    int cnt;
  +    const char *path = cleanpath(args[0]);
  +    printf("rm : %s", path);
  +    cnt = aug_rm(aug, path);
  +    printf(" %d\n", cnt);
  +    return 0;
  +}
  +
  +static int cmd_mv(char *args[]) {
  +    const char *src = cleanpath(args[0]);
  +    const char *dst = cleanpath(args[1]);
  +    int r;
  +
  +    r = aug_mv(aug, src, dst);
  +    if (r == -1)
  +        printf("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_set(char *args[]) {
  +    const char *path = cleanpath(args[0]);
  +    const char *val = args[1];
  +    int r;
  +
  +    r = aug_set(aug, path, val);
  +    if (r == -1)
  +        printf ("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_defvar(char *args[]) {
  +    const char *name = args[0];
  +    const char *path = cleanpath(args[1]);
  +    int r;
  +
  +    r = aug_defvar(aug, name, path);
  +    if (r == -1)
  +        printf ("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_defnode(char *args[]) {
  +    const char *name = args[0];
  +    const char *path = cleanpath(args[1]);
  +    const char *value = args[2];
  +    int r;
  +
  +    /* Our simple minded line parser treats non-existant and empty values
  +     * the same. We choose to take the empty string to mean NULL */
  +    if (value != NULL && strlen(value) == 0)
  +        value = NULL;
  +    r = aug_defnode(aug, name, path, value, NULL);
  +    if (r == -1)
  +        printf ("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_clear(char *args[]) {
  +    const char *path = cleanpath(args[0]);
  +    int r;
  +
  +    r = aug_set(aug, path, NULL);
  +    if (r == -1)
  +        printf ("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_get(char *args[]) {
  +    const char *path = cleanpath(args[0]);
  +    const char *val;
  +
  +    printf("%s", path);
  +    if (aug_get(aug, path, &val) != 1) {
  +        printf(" (o)\n");
  +    } else if (val == NULL) {
  +        printf(" (none)\n");
  +    } else {
  +        printf(" = %s\n", val);
  +    }
  +    return 0;
  +}
  +
  +static int cmd_print(char *args[]) {
  +    return aug_print(aug, stdout, cleanpath(args[0]));
  +}
  +
  +static int cmd_save(ATTRIBUTE_UNUSED char *args[]) {
  +    int r;
  +    r = aug_save(aug);
  +    if (r == -1) {
  +        printf("Saving failed\n");
  +    } else {
  +        r = aug_match(aug, "/augeas/events/saved", NULL);
  +        if (r > 0) {
  +            printf("Saved %d file(s)\n", r);
  +        } else if (r < 0) {
  +            printf("Error during match: %d\n", r);
  +        }
  +    }
  +    return r;
  +}
  +
  +static int cmd_load(ATTRIBUTE_UNUSED char *args[]) {
  +    int r;
  +    r = aug_load(aug);
  +    if (r == -1) {
  +        printf("Loading failed\n");
  +    } else {
  +        r = aug_match(aug, "/augeas/events/saved", NULL);
  +        if (r > 0) {
  +            printf("Saved %d file(s)\n", r);
  +        } else if (r < 0) {
  +            printf("Error during match: %d\n", r);
  +        }
  +    }
  +    return r;
  +}
  +
  +static int cmd_ins(char *args[]) {
  +    const char *label = args[0];
  +    const char *where = args[1];
  +    const char *path = cleanpath(args[2]);
  +    int before;
  +    int r;
  +
  +    if (STREQ(where, "after"))
  +        before = 0;
  +    else if (STREQ(where, "before"))
  +        before = 1;
  +    else {
  +        printf("The <WHERE> argument must be either 'before' or 'after'.");
  +        return -1;
  +    }
  +
  +    r = aug_insert(aug, path, label, before);
  +    if (r == -1)
  +        printf ("Failed\n");
  +    return r;
  +}
  +
  +static int cmd_help(ATTRIBUTE_UNUSED char *args[]) {
  +    const struct command *c;
  +
  +    printf("Commands:\n\n");
  +    printf("    exit, quit\n        Exit the program\n\n");
  +    for (c=commands; c->name != NULL; c++) {
  +        printf("    %s\n        %s\n\n", c->synopsis, c->help);
  +    }
  +    printf("\nEnvironment:\n\n");
  +    printf("    AUGEAS_ROOT\n        the file system root, defaults to 
'/'\n\n");
  +    printf("    AUGEAS_LENS_LIB\n        colon separated list of directories 
with lenses,\n\
  +        defaults to " AUGEAS_LENS_DIR "\n\n");
  +    return 0;
  +}
  +
  +static int chk_args(const struct command *cmd, int maxargs, char *args[]) {
  +    int i;
  +
  +    for (i=0; i < cmd->minargs; i++) {
  +        if (args[i] == NULL || strlen(args[i]) == 0) {
  +            fprintf(stderr, "Not enough arguments for %s\n", cmd->name);
  +            return -1;
  +        }
  +    }
  +    for (i = cmd->maxargs; i < maxargs; i++) {
  +        if (args[i] != NULL && strlen(args[i]) > 0) {
  +            fprintf(stderr, "Too many arguments for %s\n", cmd->name);
  +            return -1;
  +        }
  +    }
  +    return 0;
  +}
  +
  +static char *nexttoken(char **line) {
  +    char *r, *s;
  +    char quot = '\0';
  +
  +    s = *line;
  +
  +    while (*s && isblank(*s)) s+= 1;
  +    if (*s == '\'' || *s == '"') {
  +        quot = *s;
  +        s += 1;
  +    }
  +    r = s;
  +    while (*s) {
  +        if ((quot && *s == quot) || (!quot && isblank(*s)))
  +            break;
  +        s += 1;
  +    }
  +    if (*s)
  +        *s++ = '\0';
  +    *line = s;
  +    return r;
  +}
  +
  +static char *parseline(char *line, int maxargs, char *args[]) {
  +    char *cmd;
  +    int argc;
  +
  +    MEMZERO(args, maxargs);
  +    cmd = nexttoken(&line);
  +
  +    for (argc=0; argc < maxargs; argc++) {
  +        args[argc] = nexttoken(&line);
  +    }
  +
  +    if (*line) {
  +        fprintf(stderr, "Too many arguments: '%s' not used\n", line);
  +    }
  +    return cmd;
  +}
  +
  +static const struct command const commands[] = {
  +    { "ls",  1, 1, cmd_ls, "ls <PATH>",
  +      "List the direct children of PATH"
  +    },
  +    { "match",  1, 2, cmd_match, "match <PATH> [<VALUE>]",
  +      "Find all paths that match the path expression PATH. If VALUE is 
given,\n"
  +      "        only the matching paths whose value equals VALUE are printed"
  +    },
  +    { "rm",  1, 1, cmd_rm, "rm <PATH>",
  +      "Delete PATH and all its children from the tree"
  +    },
  +    { "mv", 2, 2, cmd_mv, "mv <SRC> <DST>",
  +      "Move node SRC to DST. SRC must match exactly one node in the tree.\n"
  +      "        DST must either match exactly one node in the tree, or may 
not\n"
  +      "        exist yet. If DST exists already, it and all its descendants 
are\n"
  +      "        deleted. If DST does not exist yet, it and all its missing \n"
  +      "        ancestors are created." },
  +    { "set", 1, 2, cmd_set, "set <PATH> <VALUE>",
  +      "Associate VALUE with PATH. If PATH is not in the tree yet,\n"
  +      "        it and all its ancestors will be created. These new tree 
entries\n"
  +      "        will appear last amongst their siblings"
  +    },
  +    { "clear", 1, 1, cmd_clear, "clear <PATH>",
  +      "Set the value for PATH to NULL. If PATH is not in the tree yet,\n"
  +      "        it and all its ancestors will be created. These new tree 
entries\n"
  +      "        will appear last amongst their siblings"
  +    },
  +    { "get", 1, 1, cmd_get, "get <PATH>",
  +      "Print the value associated with PATH"
  +    },
  +    { "print", 0, 1, cmd_print, "print [<PATH>]",
  +      "Print entries in the tree. If PATH is given, printing starts there,\n"
  +      "        otherwise the whole tree is printed"
  +    },
  +    { "ins", 3, 3, cmd_ins, "ins <LABEL> <WHERE> <PATH>",
  +      "Insert a new node with label LABEL right before or after PATH into\n"
  +     "        the tree. WHERE must be either 'before' or 'after'."
  +    },
  +    { "save", 0, 0, cmd_save, "save",
  +      "Save all pending changes to disk. For now, files are not 
overwritten.\n"
  +      "        Instead, new files with extension .augnew are created"
  +    },
  +    { "load", 0, 0, cmd_load, "load",
  +      "Load files accordig to the transforms in /augeas/load."
  +    },
  +    { "defvar", 2, 2, cmd_defvar, "defvar <NAME> <EXPR>",
  +      "Define the variable NAME to the result of evalutating EXPR. The\n"
  +      "        variable can be used in path expressions as $NAME. Note that 
EXPR\n"
  +      "        is evaluated when the variable is defined, not when it is 
used."
  +    },
  +    { "defnode", 2, 3, cmd_defnode, "defnode <NAME> <EXPR> [<VALUE>]",
  +      "Define the variable NAME to the result of evalutating EXPR, which\n"
  +      "        must be a nodeset. If no node matching EXPR exists yet, one\n"
  +      "        is created and NAME will refer to it. If VALUE is given, 
this\n"
  +      "        is the same as 'set EXPR VALUE'; if VALUE is not given, the\n"
  +      "        node is created as if with 'clear EXPR' would and NAME 
refers\n"
  +      "        to that node."
  +    },
  +    { "help", 0, 0, cmd_help, "help",
  +      "Print this help text"
  +    },
  +    { NULL, -1, -1, NULL, NULL, NULL }
  +};
  +
  +static int run_command(char *cmd, int maxargs, char **args) {
  +    int r = 0;
  +    const struct command *c;
  +
  +    if (STREQ("exit", cmd) || STREQ("quit", cmd)) {
  +        exit(EXIT_SUCCESS);
  +    }
  +    for (c = commands; c->name; c++) {
  +        if (STREQ(cmd, c->name))
  +            break;
  +    }
  +    if (c->name) {
  +        r = chk_args(c, maxargs, args);
  +        if (r == 0) {
  +            r = (*c->handler)(args);
  +        }
  +    } else {
  +        fprintf(stderr, "Unknown command '%s'\n", cmd);
  +        r = -1;
  +    }
  +
  +    return r;
  +}
  +
  +static char *readline_path_generator(const char *text, int state) {
  +    static int current = 0;
  +    static char **children = NULL;
  +    static int nchildren = 0;
  +
  +    if (state == 0) {
  +        char *end = strrchr(text, SEP);
  +        char *path;
  +        if (end == NULL) {
  +            if ((path = strdup("/*")) == NULL)
  +                return NULL;
  +        } else {
  +            end += 1;
  +            CALLOC(path, end - text + 2);
  +            if (path == NULL)
  +                return NULL;
  +            strncpy(path, text, end - text);
  +            strcat(path, "*");
  +        }
  +
  +        for (;current < nchildren; current++)
  +            free((void *) children[current]);
  +        free((void *) children);
  +        nchildren = aug_match(aug, path, &children);
  +        current = 0;
  +        free(path);
  +    }
  +
  +    while (current < nchildren) {
  +        char *child = children[current];
  +        current += 1;
  +        if (STREQLEN(child, text, strlen(text))) {
  +            if (child_count(child) > 0) {
  +                char *c = realloc(child, strlen(child)+2);
  +                if (c == NULL)
  +                    return NULL;
  +                child = c;
  +                strcat(child, "/");
  +            }
  +            rl_filename_completion_desired = 1;
  +            rl_completion_append_character = '\0';
  +            return child;
  +        } else {
  +            free(child);
  +        }
  +    }
  +    return NULL;
  +}
  +
  +static char *readline_command_generator(const char *text, int state) {
  +    static int current = 0;
  +    const char *name;
  +
  +    if (state == 0)
  +        current = 0;
  +
  +    rl_completion_append_character = ' ';
  +    while ((name = commands[current].name) != NULL) {
  +        current += 1;
  +        if (STREQLEN(text, name, strlen(text)))
  +            return strdup(name);
  +    }
  +    return NULL;
  +}
  +
  +#define      HAVE_RL_COMPLETION_MATCHES      /* XXX no AutoFu yet */
  +#ifndef HAVE_RL_COMPLETION_MATCHES
  +typedef char *rl_compentry_func_t(const char *, int);
  +static char **rl_completion_matches(ATTRIBUTE_UNUSED const char *text,
  +                           ATTRIBUTE_UNUSED rl_compentry_func_t *func) {
  +    return NULL;
  +}
  +#endif
  +
  +static char **readline_completion(const char *text, int start,
  +                                  ATTRIBUTE_UNUSED int end) {
  +    if (start == 0)
  +        return rl_completion_matches(text, readline_command_generator);
  +    else
  +        return rl_completion_matches(text, readline_path_generator);
  +
  +    return NULL;
  +}
  +
  +static void readline_init(void) {
  +    rl_readline_name = "augtool";
  +    rl_attempted_completion_function = readline_completion;
  +    rl_completion_entry_function = readline_path_generator;
  +}
  +
  +__attribute__((noreturn))
  +static void usage(void) {
  +    fprintf(stderr, "Usage: %s [OPTIONS] [COMMAND]\n", progname);
  +    fprintf(stderr, "Load the Augeas tree and modify it. If no COMMAND is 
given, run interactively\n");
  +    fprintf(stderr, "Run '%s help' to get a list of possible commands.\n",
  +            progname);
  +    fprintf(stderr, "\nOptions:\n\n");
  +    fprintf(stderr, "  -c, --typecheck    typecheck lenses\n");
  +    fprintf(stderr, "  -b, --backup       preserve originals of modified 
files with\n"
  +                    "                     extension '.augsave'\n");
  +    fprintf(stderr, "  -n, --new          save changes in files with 
extension '.augnew',\n"
  +                    "                     leave original unchanged\n");
  +    fprintf(stderr, "  -r, --root ROOT    use ROOT as the root of the 
filesystem\n");
  +    fprintf(stderr, "  -I, --include DIR  search DIR for modules; can be 
given mutiple times\n");
  +    fprintf(stderr, "  --nostdinc         do not search the builtin default 
directories for modules\n");
  +    fprintf(stderr, "  --noload           do not load any files into the 
tree on startup\n");
  +    fprintf(stderr, "  --noautoload       do not autoload modules from the 
search path\n");
  +
  +    exit(EXIT_FAILURE);
  +}
  +
  +static void parse_opts(int argc, char **argv) {
  +    int opt;
  +    size_t loadpathlen = 0;
  +    enum {
  +        VAL_NO_STDINC = CHAR_MAX + 1,
  +        VAL_NO_LOAD = VAL_NO_STDINC + 1,
  +        VAL_NO_AUTOLOAD = VAL_NO_LOAD + 1
  +    };
  +    struct option options[] = {
  +        { "help",      0, 0, 'h' },
  +        { "typecheck", 0, 0, 'c' },
  +        { "backup",    0, 0, 'b' },
  +        { "new",       0, 0, 'n' },
  +        { "root",      1, 0, 'r' },
  +        { "include",   1, 0, 'I' },
  +        { "nostdinc",  0, 0, VAL_NO_STDINC },
  +        { "noload",    0, 0, VAL_NO_LOAD },
  +        { "noautoload", 0, 0, VAL_NO_AUTOLOAD },
  +        { 0, 0, 0, 0}
  +    };
  +    int idx;
  +
  +    while ((opt = getopt_long(argc, argv, "hnbcr:I:", options, &idx)) != -1) 
{
  +        switch(opt) {
  +        case 'c':
  +            flags |= AUG_TYPE_CHECK;
  +            break;
  +        case 'b':
  +            flags |= AUG_SAVE_BACKUP;
  +            break;
  +        case 'n':
  +            flags |= AUG_SAVE_NEWFILE;
  +            break;
  +        case 'h':
  +            usage();
  +            break;
  +        case 'r':
  +            root = optarg;
  +            break;
  +        case 'I':
  +            argz_add(&loadpath, &loadpathlen, optarg);
  +            break;
  +        case VAL_NO_STDINC:
  +            flags |= AUG_NO_STDINC;
  +            break;
  +        case VAL_NO_LOAD:
  +            flags |= AUG_NO_LOAD;
  +            break;
  +        case VAL_NO_AUTOLOAD:
  +            flags |= AUG_NO_MODL_AUTOLOAD;
  +            break;
  +        default:
  +            usage();
  +            break;
  +        }
  +    }
  +    argz_stringify(loadpath, loadpathlen, PATH_SEP_CHAR);
  +}
  +
  +static int main_loop(void) {
  +    static const int maxargs = 3;
  +    char *line = NULL;
  +    char *cmd, *args[maxargs];
  +    int ret = 0;
  +    size_t len = 0;
  +
  +    while(1) {
  +        char *dup_line;
  +
  +        if (isatty(fileno(stdin))) {
  +            line = readline("augtool> ");
  +        } else if (getline(&line, &len, stdin) == -1) {
  +            return ret;
  +        }
  +        cleanstr(line, '\n');
  +        if (line == NULL) {
  +            printf("\n");
  +            return ret;
  +        }
  +        if (line[0] == '#')
  +            continue;
  +
  +        dup_line = strdup(line);
  +        if (dup_line == NULL) {
  +            fprintf(stderr, "Out of memory\n");
  +            return -1;
  +        }
  +
  +        cmd = parseline(dup_line, maxargs, args);
  +        if (cmd != NULL && strlen(cmd) > 0) {
  +            int r;
  +            r = run_command(cmd, maxargs, args);
  +            if (r < 0)
  +                ret = -1;
  +            if (isatty(fileno(stdin)))
  +                add_history(line);
  +        }
  +        free(dup_line);
  +    }
  +}
  +
  +int main(int argc, char **argv) {
  +    int r;
  +
  +    parse_opts(argc, argv);
  +
  +    aug = aug_init(root, loadpath, flags);
  +    if (aug == NULL) {
  +        fprintf(stderr, "Failed to initialize Augeas\n");
  +        exit(EXIT_FAILURE);
  +    }
  +    readline_init();
  +    if (optind < argc) {
  +        // Accept one command from the command line
  +        r = run_command(argv[optind], argc - optind, argv+optind+1);
  +    } else {
  +        r = main_loop();
  +    }
  +
  +    return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
  +}
  +
  +
  +/*
  + * Local variables:
  + *  indent-tabs-mode: nil
  + *  c-indent-level: 4
  + *  c-basic-offset: 4
  + *  tab-width: 4
  + * End:
  + */
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/tools/augtool.h
  ============================================================================
  $ cvs diff -u -r0 -r2.1 augtool.h
  --- /dev/null 2009-06-14 18:11:00 +0200
  +++ augtool.h 2009-06-14 18:13:21 +0200
  @@ -0,0 +1,525 @@
  +/*
  + * internal.h: Useful definitions
  + *
  + * Copyright (C) 2007, 2008 Red Hat 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 2.1 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, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  + *
  + * Author: David Lutterkort <dlut...@redhat.com>
  + */
  +
  +#ifndef H_AUGTOOL
  +#define H_AUGTOOL
  +
  +#include <stdio.h>
  +#include <string.h>
  +#include <strings.h>
  +#include <stdlib.h>
  +#include <stdbool.h>
  +#include <unistd.h>
  +#include <errno.h>
  +#include <assert.h>
  +
  +/* ===== list.h */
  +
  +#define list_append(head, tail)                                         \
  +    do {                                                                \
  +        if ((head) == NULL) {                                           \
  +            head = tail;                                                \
  +            break;                                                      \
  +        }                                                               \
  +        typeof(head) _p;                                                \
  +        for (_p = (head); _p->next != NULL; _p = _p->next);             \
  +        _p->next = (tail);                                              \
  +    } while (0)
  +
  +#define list_for_each(iter, list)                                       \
  +    for (typeof(list) (iter) = list; (iter) != NULL; (iter) = (iter)->next)
  +
  +#define list_remove(elt, list)                                          \
  +    do {                                                                \
  +        typeof(elt) _e = (elt);                                         \
  +        if (_e == (list)) {                                             \
  +            (list) = _e->next;                                          \
  +        } else {                                                        \
  +            typeof(_e) _p;                                              \
  +            for (_p = (list); _p != NULL && _p->next != _e; _p = _p->next); \
  +            if (_p != NULL)                                             \
  +                _p->next = _e->next;                                    \
  +        }                                                               \
  +        _e->next = NULL;                                                \
  +    } while(0)
  +
  +/* Insert NEW in list LIST before element AC. NEW->next must be null,
  +   and ELT must really be on LIST, otherwise chaos will ensue
  +*/
  +#define list_insert_before(new, elt, list)                              \
  +    do {                                                                \
  +        if ((list) == NULL) {                                           \
  +            (list) = (new);                                             \
  +        } else if ((elt) == (list)) {                                   \
  +            (new)->next = (elt);                                        \
  +            (list) = (new);                                             \
  +        } else {                                                        \
  +            typeof(elt) _p;                                             \
  +            for (_p = (list); _p != NULL && _p->next != (elt); _p = 
_p->next); \
  +            if (_p != NULL) {                                           \
  +                (new)->next = (elt);                                    \
  +                _p->next = (new);                                       \
  +            }                                                           \
  +        }                                                               \
  +    } while(0)
  +
  +#define list_free(list)                                                 \
  +    while ((list) != NULL) {                                            \
  +        typeof(list) _p = list;                                         \
  +        (list) = (list)->next;                                          \
  +        free((void *) _p);                                              \
  +    }
  +
  +#define list_length(len, list)                                          \
  +    do {                                                                \
  +        typeof(list) _p;                                                \
  +        for (len=0, _p = (list); _p != NULL; len += 1, _p = _p->next);  \
  +    } while(0)
  +
  +/* Make ELT the new head of LIST and set LIST to it */
  +#define list_cons(list, elt)                                            \
  +    do {                                                                \
  +        typeof(elt) _e = (elt);                                         \
  +        _e->next = (list);                                              \
  +        (list) = _e;                                                    \
  +    } while(0)
  +
  +#define list_reverse(list)                                              \
  +    do {                                                                \
  +        typeof(list) _head = (list);                                    \
  +        typeof(list) _prev = NULL;                                      \
  +        while (_head != NULL) {                                         \
  +            typeof(list) _next = _head->next;                           \
  +            _head->next = _prev;                                        \
  +            _prev = _head;                                              \
  +            _head = _next;                                              \
  +        }                                                               \
  +        (list) = _prev;                                                 \
  +    } while (0)
  +
  +/* Append ELT to the end of LIST. TAIL must be NULL or a pointer to
  +   the last element of LIST
  +*/
  +#define list_tail_cons(list, tail, elt)                                 \
  +    do {                                                                \
  +        if ((list) == NULL) {                                           \
  +            (list) = (elt);                                             \
  +            (tail) = (list);                                            \
  +        } else {                                                        \
  +            if ((tail) == NULL)                                         \
  +                for ((tail) = (list); (tail)->next != NULL;             \
  +                     (tail) = (tail)->next);                            \
  +            (tail)->next = (elt);                                       \
  +            (tail) = (elt);                                             \
  +        }                                                               \
  +    } while(0)
  +
  +/* ===== datadir.h */
  +#define DATADIR "/usr/share"
  +
  +/* ===== internal.h */
  +
  +/*
  + * Various parameters about env vars, special tree nodes etc.
  + */
  +
  +/* Define: AUGEAS_LENS_DIR
  + * The default location for lens definitions */
  +#define AUGEAS_LENS_DIR DATADIR "/augeas/lenses"
  +
  +/* The directory where we install lenses distribute with Augeas */
  +#define AUGEAS_LENS_DIST_DIR DATADIR "/augeas/lenses/dist"
  +
  +/* Define: AUGEAS_ROOT_ENV
  + * The env var that points to the chroot holding files we may modify.
  + * Mostly useful for testing */
  +#define AUGEAS_ROOT_ENV "AUGEAS_ROOT"
  +
  +/* Define: AUGEAS_FILES_TREE
  + * The root for actual file contents */
  +#define AUGEAS_FILES_TREE "/files"
  +
  +/* Define: AUGEAS_META_TREE
  + * Augeas reports some information in this subtree */
  +#define AUGEAS_META_TREE "/augeas"
  +
  +/* Define: AUGEAS_META_FILES
  + * Information about files */
  +#define AUGEAS_META_FILES AUGEAS_META_TREE AUGEAS_FILES_TREE
  +
  +/* Define: AUGEAS_META_ROOT
  + * The root directory */
  +#define AUGEAS_META_ROOT AUGEAS_META_TREE "/root"
  +
  +/* Define: AUGEAS_META_SAVE_MODE
  + * How we save files. One of 'backup', 'overwrite' or 'newfile' */
  +#define AUGEAS_META_SAVE_MODE AUGEAS_META_TREE "/save"
  +
  +/* Define: AUGEAS_CLONE_IF_RENAME_FAILS
  + * Control what save does when renaming the temporary file to its final
  + * destination fails with EXDEV or EBUSY: when this tree node exists, copy
  + * the file contents. If it is not present, simply give up and report an
  + * error.  */
  +#define AUGEAS_COPY_IF_RENAME_FAILS \
  +    AUGEAS_META_SAVE_MODE "/copy_if_rename_fails"
  +
  +/* A hierarchy where we record certain 'events', e.g. which tree
  + * nodes actually gotsaved into files */
  +#define AUGEAS_EVENTS AUGEAS_META_TREE "/events"
  +
  +#define AUGEAS_EVENTS_SAVED AUGEAS_EVENTS "/saved"
  +
  +/* Where to put information about parsing of path expressions */
  +#define AUGEAS_META_PATHX AUGEAS_META_TREE "/pathx"
  +
  +/* Define: AUGEAS_LENS_ENV
  + * Name of env var that contains list of paths to search for additional
  +   spec files */
  +#define AUGEAS_LENS_ENV "AUGEAS_LENS_LIB"
  +
  +/* Define: MAX_ENV_SIZE
  + * Fairly arbitrary bound on the length of the path we
  + *  accept from AUGEAS_SPEC_ENV */
  +#define MAX_ENV_SIZE 4096
  +
  +/* Define: PATH_SEP_CHAR
  + * Character separating paths in a list of paths */
  +#define PATH_SEP_CHAR ':'
  +
  +/* Constants for setting the save mode via the augeas path at
  + * AUGEAS_META_SAVE_MODE */
  +#define AUG_SAVE_BACKUP_TEXT "backup"
  +#define AUG_SAVE_NEWFILE_TEXT "newfile"
  +#define AUG_SAVE_NOOP_TEXT "noop"
  +#define AUG_SAVE_OVERWRITE_TEXT "overwrite"
  +
  +#ifdef __GNUC__
  +
  +#ifndef __GNUC_PREREQ
  +#define __GNUC_PREREQ(maj,min) 0
  +#endif
  +
  +/**
  + * ATTRIBUTE_UNUSED:
  + *
  + * Macro to flag conciously unused parameters to functions
  + */
  +#ifndef ATTRIBUTE_UNUSED
  +#define ATTRIBUTE_UNUSED __attribute__((__unused__))
  +#endif
  +
  +/**
  + * ATTRIBUTE_FORMAT
  + *
  + * Macro used to check printf/scanf-like functions, if compiling
  + * with gcc.
  + */
  +#ifndef ATTRIBUTE_FORMAT
  +#define ATTRIBUTE_FORMAT(args...) __attribute__((__format__ (args)))
  +#endif
  +
  +#ifndef ATTRIBUTE_PURE
  +#define ATTRIBUTE_PURE __attribute__((pure))
  +#endif
  +
  +#ifndef ATTRIBUTE_RETURN_CHECK
  +#if __GNUC_PREREQ (3, 4)
  +#define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__))
  +#else
  +#define ATTRIBUTE_RETURN_CHECK
  +#endif
  +#endif
  +
  +#else
  +#define ATTRIBUTE_UNUSED
  +#define ATTRIBUTE_FORMAT(...)
  +#define ATTRIBUTE_PURE
  +#define ATTRIBUTE_RETURN_CHECK
  +#endif                                   /* __GNUC__ */
  +
  +#define ARRAY_CARDINALITY(array) (sizeof (array) / sizeof *(array))
  +
  +/* String equality tests, suggested by Jim Meyering. */
  +#define STREQ(a,b) (strcmp((a),(b)) == 0)
  +#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
  +#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
  +#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
  +#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
  +#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
  +#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
  +
  +ATTRIBUTE_PURE
  +static inline int streqv(const char *a, const char *b) {
  +    if (a == NULL || b == NULL)
  +        return a == b;
  +    return STREQ(a,b);
  +}
  +
  +/* Path length and comparison */
  +
  +#define SEP '/'
  +
  +/* Length of PATH without any trailing '/' */
  +ATTRIBUTE_PURE
  +static inline int pathlen(const char *path) {
  +    int len = strlen(path);
  +
  +    if (len > 0 && path[len-1] == SEP)
  +        len--;
  +
  +    return len;
  +}
  +
  +/* Return 1 if P1 is a prefix of P2. P1 as a string must have length <= P2 */
  +ATTRIBUTE_PURE
  +static inline int pathprefix(const char *p1, const char *p2) {
  +    if (p1 == NULL || p2 == NULL)
  +        return 0;
  +    int l1 = pathlen(p1);
  +
  +    return STREQLEN(p1, p2, l1) && (p2[l1] == '\0' || p2[l1] == SEP);
  +}
  +
  +static inline int pathendswith(const char *path, const char *basenam) {
  +    const char *p = strrchr(path, SEP);
  +    if (p == NULL)
  +        return 0;
  +    return streqv(p+1, basenam);
  +}
  +
  +/* Join NSEG path components (passed as const char *) into one PATH.
  +   Allocate as needed. Return 0 on success, -1 on failure */
  +int pathjoin(char **path, int nseg, ...);
  +
  +/* Call calloc to allocate an array of N instances of *VAR */
  +#define CALLOC(Var,N) do { (Var) = calloc ((N), sizeof (*(Var))); } while (0)
  +
  +#define MEMZERO(ptr, n) memset((ptr), 0, (n) * sizeof(*(ptr)));
  +
  +/**
  + * TODO:
  + *
  + * macro to flag unimplemented blocks
  + */
  +#define TODO                                                                 
\
  +    fprintf(stderr, "%s:%d Unimplemented block\n",                   \
  +            __FILE__, __LINE__);
  +
  +#define FIXME(msg, args ...)                            \
  +    do {                                                \
  +        fprintf(stderr, "%s:%d Fixme: ",                \
  +                __FILE__, __LINE__);                    \
  +      fprintf(stderr, msg, ## args);                    \
  +      fputc('\n', stderr);                              \
  +    } while(0)
  +
  +/*
  + * Internal data structures
  + */
  +
  +// internal.c
  +
  +/* Function: escape
  + * Escape nonprintable characters within TEXT, similar to how it's done in
  + * C string literals. Caller must free the returned string.
  + */
  +char *escape(const char *text, int cnt);
  +
  +/* Function: unescape */
  +char *unescape(const char *s, int len);
  +
  +/* Function: print_chars */
  +int print_chars(FILE *out, const char *text, int cnt);
  +
  +/* Function: print_pos
  + * Print a pretty representation of being at position POS within TEXT */
  +void print_pos(FILE *out, const char *text, int pos);
  +char *format_pos(const char *text, int pos);
  +
  +/* Function: read_file
  + * Read the contents of file PATH and return them as one long string. The
  + * caller must free the result. Return NULL if any error occurs.
  + */
  +char* read_file(const char *path);
  +
  +/* Get the error message for ERRNUM in a threadsafe way. Based on libvirt's
  + * virStrError
  + */
  +const char *xstrerror(int errnum, char *buf, size_t len);
  +
  +/* Struct: augeas
  + * The data structure representing a connection to Augeas. */
  +struct augeas {
  +    struct tree      *origin;     /* Actual tree root is origin->children */
  +    const char       *root;       /* Filesystem root for all files */
  +                                  /* always ends with '/' */
  +    unsigned int      flags;      /* Flags passed to AUG_INIT */
  +    struct module    *modules;    /* Loaded modules */
  +    size_t            nmodpath;
  +    char             *modpathz;   /* The search path for modules as a
  +                                     glibc argz vector */
  +    struct pathx_symtab *symtab;
  +};
  +
  +/* Struct: tree
  + * An entry in the global config tree. The data structure allows associating
  + * values with interior nodes, but the API currently marks that as an error.
  + *
  + * To make dealing with parents uniform, even for the root, we create
  + * standalone trees with a fake root, called origin. That root is generally
  + * not referenced from anywhere. Standalone trees should be created with
  + * MAKE_TREE_ORIGIN.
  + *
  + * The DIRTY flag is used to track which parts of the tree might need to be
  + * saved. For any node that is marked dirty, all of its ancestors must be
  + * marked dirty, too. Instead of setting this flag directly, the function
  + * TREE_MARK_DIRTY in augeas.c should be used (and only functions in that
  + * file should have a need to mark nodes as dirty)
  + */
  +struct tree {
  +    struct tree *next;
  +    struct tree *parent;     /* Points to self for root */
  +    char        *label;      /* Last component of PATH */
  +    struct tree *children;   /* List of children through NEXT */
  +    char        *value;
  +    int          dirty;
  +};
  +
  +/* The opaque structure used to represent path expressions. API's
  + * using STRUCT PATHX are declared farther below
  + */
  +struct pathx;
  +
  +#define ROOT_P(t) ((t) != NULL && (t)->parent == (t)->parent->parent)
  +
  +/* Function: make_tree
  + * Allocate a new tree node with the given LABEL, VALUE, and CHILDREN,
  + * which are not copied. The new tree is marked as dirty
  + */
  +struct tree *make_tree(char *label, char *value,
  +                       struct tree *parent, struct tree *children);
  +
  +/* Mark a tree as a standalone tree; this creates a fake parent for ROOT,
  + * so that even ROOT has a parent. A new node with only child ROOT is
  + * returned on success, and NULL on failure.
  + */
  +struct tree  *make_tree_origin(struct tree *root);
  +
  +int tree_replace(struct tree *origin, const char *path, struct tree *sub);
  +/* Make a new tree node and append it to parent's children */
  +struct tree *tree_append(struct tree *parent, char *label, char *value);
  +
  +int tree_rm(struct pathx *p);
  +int tree_unlink(struct tree *tree);
  +struct tree *tree_set(struct pathx *p, const char *value);
  +int tree_insert(struct pathx *p, const char *label, int before);
  +int free_tree(struct tree *tree);
  +int dump_tree(FILE *out, struct tree *tree);
  +int tree_equal(const struct tree *t1, const struct tree *t2);
  +char *path_expand(struct tree *tree, const char *ppath);
  +char *path_of_tree(struct tree *tree);
  +
  +/* Struct: memstream
  + * Wrappers to simulate OPEN_MEMSTREAM where that's not available. The
  + * STREAM member is opened by INIT_MEMSTREAM and closed by
  + * CLOSE_MEMSTREAM. The BUF is allocated automatically, but can not be used
  + * until after CLOSE_MEMSTREAM has been called. It is the callers
  + * responsibility to free up BUF.
  + */
  +struct memstream {
  +    FILE   *stream;
  +    char   *buf;
  +    size_t size;
  +};
  +
  +/* Function: init_memstream
  + * Initialize a memstream. On systems that have OPEN_MEMSTREAM, it is used
  + * to open MS->STREAM. On systems without OPEN_MEMSTREAM, MS->STREAM is
  + * backed by a temporary file.
  + *
  + * MS must be allocated in advance; INIT_MEMSTREAM initializes it.
  + */
  +int init_memstream(struct memstream *ms);
  +
  +/* Function: close_memstream
  + * Close a memstream. After calling this, MS->STREAM can not be used
  + * anymore and a string representing whatever was written to it is
  + * available in MS->BUF. The caller must free MS->BUF.
  + *
  + * The caller must free the MEMSTREAM structure.
  + */
  +int close_memstream(struct memstream *ms);
  +
  +/*
  + * Path expressions
  + */
  +
  +typedef enum {
  +    PATHX_NOERROR = 0,
  +    PATHX_ENAME,
  +    PATHX_ESTRING,
  +    PATHX_ENUMBER,
  +    PATHX_EDELIM,
  +    PATHX_ENOEQUAL,
  +    PATHX_ENOMEM,
  +    PATHX_EPRED,
  +    PATHX_EPAREN,
  +    PATHX_ESLASH,
  +    PATHX_EINTERNAL,
  +    PATHX_ETYPE,
  +    PATHX_ENOVAR,
  +    PATHX_EEND,
  +    PATHX_ENONODES
  +} pathx_errcode_t;
  +
  +struct pathx;
  +struct pathx_symtab;
  +
  +const char *pathx_error(struct pathx *pathx, const char **txt, int *pos);
  +
  +/* Parse the string PATH into a path expression PX that will be evaluated
  + * against the tree ORIGIN.
  + *
  + * If NEED_NODESET is true, the resulting path expression must evaluate toa
  + * nodeset, otherwise it can evaluate to a value of any type.
  + *
  + * Returns 0 on success, and -1 on error
  + */
  +int pathx_parse(const struct tree *origin, const char *path,
  +                bool need_nodeset,
  +                struct pathx_symtab *symtab,
  +                struct pathx **px);
  +struct tree *pathx_first(struct pathx *path);
  +struct tree *pathx_next(struct pathx *path);
  +int pathx_find_one(struct pathx *path, struct tree **match);
  +int pathx_expand_tree(struct pathx *path, struct tree **tree);
  +void free_pathx(struct pathx *path);
  +
  +int pathx_symtab_init(struct pathx_symtab **symtab);
  +int pathx_symtab_define(struct pathx_symtab **symtab,
  +                        const char *name, struct pathx *px);
  +int pathx_symtab_undefine(struct pathx_symtab **symtab, const char *name);
  +void pathx_symtab_remove_descendants(struct pathx *pathx,
  +                                     const struct tree *tree);
  +void free_symtab(struct pathx_symtab *symtab);
  +
  +#endif       /* H_AUGTOOL */
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org

Reply via email to