/*
 * augeas.h: public headers for augeas
 *
 * Copyright (C) 2007-2016 David Lutterkort
 *
 * 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 <dlutter@redhat.com>
 */

#include <stdio.h>
#include <libxml/tree.h>

#ifndef AUGEAS_H_
#define AUGEAS_H_

typedef struct augeas augeas;

/* Enum: aug_flags
 *
 * Flags to influence the behavior of Augeas. Pass a bitmask of these flags
 * to AUG_INIT.
 */
enum aug_flags {
    AUG_NONE = 0,
    AUG_SAVE_BACKUP  = (1 << 0),  /* Keep the original file with a
                                     .augsave extension */
    AUG_SAVE_NEWFILE = (1 << 1),  /* Save changes into a file with
                                     extension .augnew, and do not
                                     overwrite the original file. Takes
                                     precedence over AUG_SAVE_BACKUP */
    AUG_TYPE_CHECK   = (1 << 2),  /* Typecheck lenses; since it can be very
                                     expensive it is not done by default */
    AUG_NO_STDINC    = (1 << 3),   /* Do not use the builtin load path for
                                     modules */
    AUG_SAVE_NOOP    = (1 << 4),  /* Make save a no-op process, just record
                                     what would have changed */
    AUG_NO_LOAD      = (1 << 5),  /* Do not load the tree from AUG_INIT */
    AUG_NO_MODL_AUTOLOAD = (1 << 6),
    AUG_ENABLE_SPAN  = (1 << 7),  /* Track the span in the input of nodes */
    AUG_NO_ERR_CLOSE = (1 << 8),  /* Do not close automatically when
                                     encountering error during aug_init */
    AUG_TRACE_MODULE_LOADING = (1 << 9) /* For use by augparse -t */
};

#ifdef __cplusplus
extern "C" {
#endif

/* Function: aug_init
 *
 * Initialize the library.
 *
 * Use ROOT as the filesystem root. If ROOT is NULL, use the value of the
 * environment variable AUGEAS_ROOT. If that doesn't exist eitehr, use "/".
 *
 * LOADPATH is a colon-separated list of directories that modules should be
 * searched in. This is in addition to the standard load path and the
 * directories in AUGEAS_LENS_LIB. LOADPATH can be NULL, indicating that
 * nothing should be added to the load path.
 *
 * FLAGS is a bitmask made up of values from AUG_FLAGS. The flag
 * AUG_NO_ERR_CLOSE can be used to get more information on why
 * initialization failed. If it is set in FLAGS, the caller must check that
 * aug_error returns AUG_NOERROR before using the returned augeas handle
 * for any other operation. If the handle reports any error, the caller
 * should only call the aug_error functions an aug_close on this handle.
 *
 * Returns:
 * a handle to the Augeas tree upon success. If initialization fails,
 * returns NULL if AUG_NO_ERR_CLOSE is not set in FLAGS. If
 * AUG_NO_ERR_CLOSE is set, might return an Augeas handle even on
 * failure. In that case, caller must check for errors using augeas_error,
 * and, if an error is reported, only use the handle with the aug_error
 * functions and aug_close.
 */
augeas *aug_init(const char *root, const char *loadpath, unsigned int flags);

/* Function: aug_defvar
 *
 * Define a variable NAME whose value is the result of evaluating EXPR. If
 * a variable NAME already exists, its name will be replaced with the
 * result of evaluating EXPR.  Context will not be applied to EXPR.
 *
 * If EXPR is NULL, the variable NAME will be removed if it is defined.
 *
 * Path variables can be used in path expressions later on by prefixing
 * them with '$'.
 *
 * Returns -1 on error; on success, returns 0 if EXPR evaluates to anything
 * other than a nodeset, and the number of nodes if EXPR evaluates to a
 * nodeset
 */
int aug_defvar(augeas *aug, const char *name, const char *expr);

/* Function: aug_defnode
 *
 * Define a variable NAME whose value is the result of evaluating EXPR,
 * which must be non-NULL and evaluate to a nodeset. If a variable NAME
 * already exists, its name will be replaced with the result of evaluating
 * EXPR.
 *
 * If EXPR evaluates to an empty nodeset, a node is created, equivalent to
 * calling AUG_SET(AUG, EXPR, VALUE) and NAME will be the nodeset containing
 * that single node.
 *
 * If CREATED is non-NULL, it is set to 1 if a node was created, and 0 if
 * it already existed.
 *
 * Returns -1 on error; on success, returns the number of nodes in the
 * nodeset
 */
int aug_defnode(augeas *aug, const char *name, const char *expr,
                const char *value, int *created);

/* Function: aug_get
 *
 * Lookup the value associated with PATH. VALUE can be NULL, in which case
 * it is ignored. If VALUE is not NULL, it is used to return a pointer to
 * the value associated with PATH if PATH matches exactly one node. If PATH
 * matches no nodes or more than one node, *VALUE is set to NULL. Note that
 * it is perfectly legal for nodes to have a NULL value, and that that by
 * itself does not indicate an error.
 *
 * The string *VALUE must not be freed by the caller, and is valid as long
 * as its node remains unchanged.
 *
 * Returns:
 * 1 if there is exactly one node matching PATH, 0 if there is none,
 * and a negative value if there is more than one node matching PATH, or if
 * PATH is not a legal path expression.
 */
int aug_get(const augeas *aug, const char *path, const char **value);

/* Function: aug_label
 *
 * Lookup the label associated with PATH. LABEL can be NULL, in which case
 * it is ignored. If LABEL is not NULL, it is used to return a pointer to
 * the value associated with PATH if PATH matches exactly one node. If PATH
 * matches no nodes or more than one node, *LABEL is set to NULL.
 *
 * The string *LABEL must not be freed by the caller, and is valid as long
 * as its node remains unchanged.
 *
 * Returns:
 * 1 if there is exactly one node matching PATH, 0 if there is none,
 * and a negative value if there is more than one node matching PATH, or if
 * PATH is not a legal path expression.
 */
int aug_label(const augeas *aug, const char *path, const char **label);

/* Function: aug_set
 *
 * Set the value associated with PATH to VALUE. VALUE is copied into the
 * internal data structure, and the caller is responsible for freeing
 * it. Intermediate entries are created if they don't exist.
 *
 * Returns:
 * 0 on success, -1 on error. It is an error if more than one node
 * matches PATH.
 */
int aug_set(augeas *aug, const char *path, const char *value);

/* Function: aug_setm
 *
 * Set the value of multiple nodes in one operation. Find or create a node
 * matching SUB by interpreting SUB as a path expression relative to each
 * node matching BASE. SUB may be NULL, in which case all the nodes
 * matching BASE will be modified.
 *
 * Returns:
 * number of modified nodes on success, -1 on error
 */
int aug_setm(augeas *aug, const char *base, const char *sub, const char *value);

/* Function: aug_span
 *
 * Get the span according to input file of the node associated with PATH. If
 * the node is associated with a file, the filename, label and value start and
 * end positions are set, and return value is 0. The caller is responsible for
 * freeing returned filename. If an argument for return value is NULL, then the
 * corresponding value is not set. If the node associated with PATH doesn't
 * belong to a file or is doesn't exists, filename and span are not set and
 * return value is -1.
 *
 * Returns:
 * 0 on success with filename, label_start, label_stop, value_start, value_end,
 *   span_start, span_end
 * -1 on error
 */

int aug_span(augeas *aug, const char *path, char **filename,
        unsigned int *label_start, unsigned int *label_end,
        unsigned int *value_start, unsigned int *value_end,
        unsigned int *span_start, unsigned int *span_end);

/* Function: aug_insert
 *
 * Create a new sibling LABEL for PATH by inserting into the tree just
 * before PATH if BEFORE == 1 or just after PATH if BEFORE == 0.
 *
 * PATH must match exactly one existing node in the tree, and LABEL must be
 * a label, i.e. not contain a '/', '*' or end with a bracketed index
 * '[N]'.
 *
 * Returns:
 * 0 on success, and -1 if the insertion fails.
 */
int aug_insert(augeas *aug, const char *path, const char *label, int before);

/* Function: aug_rm
 *
 * Remove path and all its children. Returns the number of entries removed.
 * All nodes that match PATH, and their descendants, are removed.
 */
int aug_rm(augeas *aug, const char *path);

/* Function: aug_mv
 *
 * Move the node SRC to DST. SRC must match exactly one node in the
 * tree. DST must either match exactly one node in the tree, or may not
 * exist yet. If DST exists already, it and all its descendants are
 * deleted. If DST does not exist yet, it and all its missing ancestors are
 * created.
 *
 * Note that the node SRC always becomes the node DST: when you move /a/b
 * to /x, the node /a/b is now called /x, no matter whether /x existed
 * initially or not.
 *
 * Returns:
 * 0 on success and -1 on failure.
 */
int aug_mv(augeas *aug, const char *src, const char *dst);

/* Function: aug_cp
 *
 * Copy the node SRC to DST. SRC must match exactly one node in the
 * tree. DST must either match exactly one node in the tree, or may not
 * exist yet. If DST exists already, it and all its descendants are
 * deleted. If DST does not exist yet, it and all its missing ancestors are
 * created.
 *
 * Returns:
 * 0 on success and -1 on failure.
 */
int aug_cp(augeas *aug, const char *src, const char *dst);

/* Function: aug_rename
 *
 * Rename the label of all nodes matching SRC to LBL.
 *
 * Returns:
 * The number of nodes renamed on success and -1 on failure.
 */
int aug_rename(augeas *aug, const char *src, const char *lbl);

/* Function: aug_match
 *
 * Returns:
 * the number of matches of the path expression PATH in AUG. If
 * MATCHES is non-NULL, an array with the returned number of elements will
 * be allocated and filled with the paths of the matches. The caller must
 * free both the array and the entries in it. The returned paths are
 * sufficiently qualified to make sure that they match exactly one node in
 * the current tree.
 *
 * If MATCHES is NULL, nothing is allocated and only the number
 * of matches is returned.
 *
 * Returns -1 on error, or the total number of matches (which might be 0).
 *
 * Path expressions:
 * Path expressions use a very simple subset of XPath: the path PATH
 * consists of a number of segments, separated by '/'; each segment can
 * either be a '*', matching any tree node, or a string, optionally
 * followed by an index in brackets, matching tree nodes labelled with
 * exactly that string. If no index is specified, the expression matches
 * all nodes with that label; the index can be a positive number N, which
 * matches exactly the Nth node with that label (counting from 1), or the
 * special expression 'last()' which matches the last node with the given
 * label. All matches are done in fixed positions in the tree, and nothing
 * matches more than one path segment.
 *
 */
int aug_match(const augeas *aug, const char *path, char ***matches);

/* Function: aug_save
 *
 * Write all pending changes to disk.
 *
 * Returns:
 * -1 if an error is encountered,
 * 0 on success. Only files that had any changes made to them are written.
 *
 * If AUG_SAVE_NEWFILE is set in the FLAGS passed to AUG_INIT, create
 * changed files as new files with the extension ".augnew", and leave the
 * original file unmodified.
 *
 * Otherwise, if AUG_SAVE_BACKUP is set in the FLAGS passed to AUG_INIT,
 * move the original file to a new file with extension ".augsave".
 *
 * If neither of these flags is set, overwrite the original file.
 */
int aug_save(augeas *aug);

/* Function: aug_load
 *
 * Load files into the tree. Which files to load and what lenses to use on
 * them is specified under /augeas/load in the tree; each entry
 * /augeas/load/NAME specifies a 'transform', by having itself exactly one
 * child 'lens' and any number of children labelled 'incl' and 'excl'. The
 * value of NAME has no meaning.
 *
 * The 'lens' grandchild of /augeas/load specifies which lens to use, and
 * can either be the fully qualified name of a lens 'Module.lens' or
 * '@Module'. The latter form means that the lens from the transform marked
 * for autoloading in MODULE should be used.
 *
 * The 'incl' and 'excl' grandchildren of /augeas/load indicate which files
 * to transform. Their value are used as glob patterns. Any file that
 * matches at least one 'incl' pattern and no 'excl' pattern is
 * transformed. The order of 'incl' and 'excl' entries is irrelevant.
 *
 * When AUG_INIT is first called, it populates /augeas/load with the
 * transforms marked for autoloading in all the modules it finds.
 *
 * Before loading any files, AUG_LOAD will remove everything underneath
 * /augeas/files and /files, regardless of whether any entries have been
 * modified or not.
 *
 * Returns -1 on error, 0 on success. Note that success includes the case
 * where some files could not be loaded. Details of such files can be found
 * as '/augeas//error'.
 */
int aug_load(augeas *aug);

/* Function: aug_text_store
 *
 * Use the value of node NODE as a string and transform it into a tree
 * using the lens LENS and store it in the tree at PATH, which will be
 * overwritten. PATH and NODE are path expressions.
 *
 * Returns:
 * 0 on success, or a negative value on failure
 */
int aug_text_store(augeas *aug, const char *lens, const char *node,
                   const char *path);

/* Function: aug_text_retrieve
 *
 * Transform the tree at PATH into a string using lens LENS and store it in
 * the node NODE_OUT, assuming the tree was initially generated using the
 * value of node NODE_IN. PATH, NODE_IN, and NODE_OUT are path expressions.
 *
 * Returns:
 * 0 on success, or a negative value on failure
 */
int aug_text_retrieve(struct augeas *aug, const char *lens,
                      const char *node_in, const char *path,
                      const char *node_out);

/* Function: aug_escape_name
 *
 * Escape special characters in a string such that it can be used as part
 * of a path expressions and only matches a node named exactly
 * IN. Characters that have special meanings in path expressions, such as
 * '[' and ']' are prefixed with a '\\'. Note that this function assumes
 * that it is passed a name, not a path, and will therefore escape '/',
 * too.
 *
 * On return, *OUT is NULL if IN does not need any escaping at all, and
 * points to an escaped copy of IN otherwise.
 *
 * Returns:
 * 0 on success, or a negative value on failure
 */
int aug_escape_name(augeas *aug, const char *in, char **out);

/* Function: aug_print
 *
 * Print each node matching PATH and its descendants to OUT.
 *
 * Returns:
 * 0 on success, or a negative value on failure
 */
int aug_print(const augeas *aug, FILE *out, const char *path);

/* Function: aug_source
 *
 * For the node matching PATH, return the path to the node representing the
 * file to which PATH belongs. If PATH belongs to a file, *FILE_PATH will
 * contain the path to the toplevel node of that file underneath /files. If
 * it does not, *FILE_PATH will be NULL.
 *
 * The caller is responsible for freeing *FILE_PATH
 *
 * Returns:
 * 0 on success, or a negative value on failure. It is an error if PATH
 * matches more than one node.
 */
int aug_source(const augeas *aug, const char *path, char **file_path);

/* Function: aug_preview
 *
 * Return the contents of the file that would be written for the file associated with path
 * If there is no file corresponfing to PATH, *OUT will be NULL.
 * The caller is responsible for freeing *OUT
 *
 * Returns:
 * 0 on success, -1 on error
 */
int aug_preview(augeas *aug, const char *path, char **out);

/* Function: aug_to_xml
 *
 * Turn the Augeas tree(s) matching PATH into an XML tree XMLDOC. The
 * parameter FLAGS is currently unused and must be set to 0.
 *
 * Returns:
 * 0 on success, or a negative value on failure
 *
 * In case of failure, *xmldoc is set to NULL
 */
int aug_to_xml(const augeas *aug, const char *path, xmlNode **xmldoc,
               unsigned int flags);

/*
 * Function: aug_transform
 *
 * Add a transform for FILE using LENS.
 * EXCL specifies if this the file is to be included (0)
 * or excluded (1) from the LENS.
 * The LENS maybe be a module name or a full lens name.
 * If a module name is given, then lns will be the lens assumed.
 *
 * Returns:
 * 1 on success, -1 on failure
 */
int aug_transform(augeas *aug, const char *lens, const char *file, int excl);

/*
 * Function: aug_load_file
 *
 * Load a FILE using the lens that would ordinarily be used by aug_load,
 * i.e. the lens whose autoload statement matches the FILE. Similar to
 * aug_load, this function returns successfully even if FILE does not exist
 * or if the FILE can not be processed by the associated lens. It is an
 * error though if no lens can be found to process FILE. In that case, the
 * error code in AUG will be set to AUG_ENOLENS.
 *
 * Returns:
 * 0 on success, -1 on failure
 */
int aug_load_file(augeas *aug, const char *file);

/*
 * Function: aug_srun
 *
 * Run one or more newline-separated commands. The output of the commands
 * will be printed to OUT. Running just 'help' will print what commands are
 * available. Commands accepted by this are identical to what augtool
 * accepts.
 *
 * Returns:
 * the number of executed commands on success, -1 on failure, and -2 if a
 * 'quit' command was encountered
 */
int aug_srun(augeas *aug, FILE *out, const char *text);

/* Function: aug_close
 *
 * Close this Augeas instance and free any storage associated with
 * it. After running AUG_CLOSE, AUG is invalid and can not be used for any
 * more operations.
 */
void aug_close(augeas *aug);

// We can't put //* into the examples in these comments since the C
// preprocessor complains about that. So we'll resort to the equivalent but
// more wordy notation /descendant::*

/*
 * Function: aug_ns_attr
 *
 * Look up the ith node in the variable VAR and retrieve information about
 * it. Set *VALUE to the value of the node, *LABEL to its label, and
 * *FILE_PATH to the path of the file it belongs to, or to NULL if that
 * node does not belong to a file. It is permissible to pass NULL for any
 * of these variables to indicate that the caller is not interested in that
 * attribute.
 *
 * It is assumed that VAR was defined with a path expression evaluating to
 * a nodeset, like '/files/etc/hosts/descendant::*'. This function is
 * equivalent to, but faster than, aug_get(aug, "$VAR[I+1]", value),
 * respectively the corresponding calls to aug_label and aug_source. Note
 * that the index is 0-based, not 1-based.
 *
 * If VAR does not exist, or is not a nodeset, or if it has fewer than I
 * nodes, this call fails.
 *
 * The caller is responsible for freeing *FILE_PATH, but must not free
 * *VALUE or *LABEL. Those pointers are only valid up to the next call to a
 * function in this API that might modify the tree.
 *
 * Returns:
 * 1 on success (for consistency with aug_get), a negative value on failure
 */
int aug_ns_attr(const augeas* aug, const char *var, int i,
                const char **value, const char **label, char **file_path);

/*
 * Function: aug_ns_label
 *
 * Look up the LABEL and its INDEX amongst its siblings for the ith node in
 * variable VAR. (See aug_ns_attr for details of what is expected of VAR)
 *
 * Either of LABEL and INDEX may be NULL. The *INDEX will be set to the
 * number of siblings + 1 of the node $VAR[I+1] that precede it and have
 * the same label if there are at least two siblings with that label. If
 * the node $VAR[I+1] does not have any siblings with the same label as
 * itself, *INDEX will be set to 0.
 *
 * The caller must not free *LABEL. The pointer is only valid up to the
 * next call to a function in this API that might modify the tree.
 *
 * Returns:
 * 1 on success (for consistency with aug_get), a negative value on failure
 */
int aug_ns_label(const augeas *aug, const char *var, int i,
                 const char **label, int *index);

/*
 * Function: aug_ns_value
 *
 * Look up the VALUE of the ith node in variable VAR. (See aug_ns_attr for
 * details of what is expected of VAR)
 *
 * The caller must not free *VALUE. The pointer is only valid up to the
 * next call to a function in this API that might modify the tree.
 *
 * Returns:
 * 1 on success (for consistency with aug_get), a negative value on failure
 */
int aug_ns_value(const augeas *aug, const char *var, int i,
                 const char **value);

/*
 * Function: aug_ns_count
 *
 * Return the number of nodes in variable VAR. (See aug_ns_attr for details
 * of what is expected of VAR)
 *
 * Returns: the number of nodes in VAR, or a negative value on failure
 */
int aug_ns_count(const augeas *aug, const char *var);

/*
 * Function: aug_ns_count
 *
 * Put the fully qualified path to the ith node in VAR into *PATH. (See
 * aug_ns_attr for details of what is expected of VAR)
 *
 * The caller is responsible for freeing *PATH, which is allocated by this
 * function.
 *
 * Returns: 1 on success (for consistency with aug_get), a negative value
 * on failure
 */
int aug_ns_path(const augeas *aug, const char *var, int i, char **path);

/*
 * Error reporting
 */

typedef enum {
    AUG_NOERROR,        /* No error */
    AUG_ENOMEM,         /* Out of memory */
    AUG_EINTERNAL,      /* Internal error (bug) */
    AUG_EPATHX,         /* Invalid path expression */
    AUG_ENOMATCH,       /* No match for path expression */
    AUG_EMMATCH,        /* Too many matches for path expression */
    AUG_ESYNTAX,        /* Syntax error in lens file */
    AUG_ENOLENS,        /* Lens lookup failed */
    AUG_EMXFM,          /* Multiple transforms */
    AUG_ENOSPAN,        /* No span for this node */
    AUG_EMVDESC,        /* Cannot move node into its descendant */
    AUG_ECMDRUN,        /* Failed to execute command */
    AUG_EBADARG,        /* Invalid argument in function call */
    AUG_ELABEL,         /* Invalid label */
    AUG_ECPDESC,        /* Cannot copy node into its descendant */
    AUG_EFILEACCESS     /* Cannot open or read a file */
} aug_errcode_t;

/* Return the error code from the last API call */
int aug_error(augeas *aug);

/* Return a human-readable message for the error code */
const char *aug_error_message(augeas *aug);

/* Return a human-readable message elaborating the error code; might be
 * NULL. For example, when the error code is AUG_EPATHX, this will explain
 * how the path expression is invalid */
const char *aug_error_minor_message(augeas *aug);

/* Return details about the error, which might be NULL. For example, for
 * AUG_EPATHX, indicates where in the path expression the error
 * occurred. The returned value can only be used until the next API call
 */
const char *aug_error_details(augeas *aug);


#ifdef __cplusplus
}
#endif

#endif


/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */
