Blame src/internal.c

Packit Service a2ae7a
/*
Packit Service a2ae7a
 * internal.c: internal data structures and helpers
Packit Service a2ae7a
 *
Packit Service a2ae7a
 * Copyright (C) 2007-2016 David Lutterkort
Packit Service a2ae7a
 *
Packit Service a2ae7a
 * This library is free software; you can redistribute it and/or
Packit Service a2ae7a
 * modify it under the terms of the GNU Lesser General Public
Packit Service a2ae7a
 * License as published by the Free Software Foundation; either
Packit Service a2ae7a
 * version 2.1 of the License, or (at your option) any later version.
Packit Service a2ae7a
 *
Packit Service a2ae7a
 * This library is distributed in the hope that it will be useful,
Packit Service a2ae7a
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2ae7a
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service a2ae7a
 * Lesser General Public License for more details.
Packit Service a2ae7a
 *
Packit Service a2ae7a
 * You should have received a copy of the GNU Lesser General Public
Packit Service a2ae7a
 * License along with this library; if not, write to the Free Software
Packit Service a2ae7a
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
Packit Service a2ae7a
 *
Packit Service a2ae7a
 * Author: David Lutterkort <dlutter@redhat.com>
Packit Service a2ae7a
 */
Packit Service a2ae7a
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include <ctype.h>
Packit Service a2ae7a
#include <stdio.h>
Packit Service a2ae7a
#include <stdarg.h>
Packit Service a2ae7a
#include <locale.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include "internal.h"
Packit Service a2ae7a
#include "memory.h"
Packit Service a2ae7a
#include "fa.h"
Packit Service a2ae7a
Packit Service a2ae7a
#ifndef MIN
Packit Service a2ae7a
# define MIN(a, b) ((a) < (b) ? (a) : (b))
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* Cap file reads somwhat arbitrarily at 32 MB */
Packit Service a2ae7a
#define MAX_READ_LEN (32*1024*1024)
Packit Service a2ae7a
Packit Service a2ae7a
int pathjoin(char **path, int nseg, ...) {
Packit Service a2ae7a
    va_list ap;
Packit Service a2ae7a
Packit Service a2ae7a
    va_start(ap, nseg);
Packit Service a2ae7a
    for (int i=0; i < nseg; i++) {
Packit Service a2ae7a
        const char *seg = va_arg(ap, const char *);
Packit Service a2ae7a
        if (seg == NULL)
Packit Service a2ae7a
            seg = "()";
Packit Service a2ae7a
        int len = strlen(seg) + 1;
Packit Service a2ae7a
Packit Service a2ae7a
        if (*path != NULL) {
Packit Service a2ae7a
            len += strlen(*path) + 1;
Packit Service a2ae7a
            if (REALLOC_N(*path, len) == -1) {
Packit Service a2ae7a
                FREE(*path);
Packit Service a2ae7a
                va_end(ap);
Packit Service a2ae7a
                return -1;
Packit Service a2ae7a
            }
Packit Service a2ae7a
            if (strlen(*path) == 0 || (*path)[strlen(*path)-1] != SEP)
Packit Service a2ae7a
                strcat(*path, "/");
Packit Service a2ae7a
            if (seg[0] == SEP)
Packit Service a2ae7a
                seg += 1;
Packit Service a2ae7a
            strcat(*path, seg);
Packit Service a2ae7a
        } else {
Packit Service a2ae7a
            if ((*path = malloc(len)) == NULL) {
Packit Service a2ae7a
                va_end(ap);
Packit Service a2ae7a
                return -1;
Packit Service a2ae7a
            }
Packit Service a2ae7a
            strcpy(*path, seg);
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
    va_end(ap);
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* Like gnulib's fread_file, but read no more than the specified maximum
Packit Service a2ae7a
   number of bytes.  If the length of the input is <= max_len, and
Packit Service a2ae7a
   upon error while reading that data, it works just like fread_file.
Packit Service a2ae7a
Packit Service a2ae7a
   Taken verbatim from libvirt's util.c
Packit Service a2ae7a
*/
Packit Service a2ae7a
Packit Service a2ae7a
static char *
Packit Service a2ae7a
fread_file_lim (FILE *stream, size_t max_len, size_t *length)
Packit Service a2ae7a
{
Packit Service a2ae7a
    char *buf = NULL;
Packit Service a2ae7a
    size_t alloc = 0;
Packit Service a2ae7a
    size_t size = 0;
Packit Service a2ae7a
    int save_errno;
Packit Service a2ae7a
Packit Service a2ae7a
    for (;;) {
Packit Service a2ae7a
        size_t count;
Packit Service a2ae7a
        size_t requested;
Packit Service a2ae7a
Packit Service a2ae7a
        if (size + BUFSIZ + 1 > alloc) {
Packit Service a2ae7a
            char *new_buf;
Packit Service a2ae7a
Packit Service a2ae7a
            alloc += alloc / 2;
Packit Service a2ae7a
            if (alloc < size + BUFSIZ + 1)
Packit Service a2ae7a
                alloc = size + BUFSIZ + 1;
Packit Service a2ae7a
Packit Service a2ae7a
            new_buf = realloc (buf, alloc);
Packit Service a2ae7a
            if (!new_buf) {
Packit Service a2ae7a
                save_errno = errno;
Packit Service a2ae7a
                break;
Packit Service a2ae7a
            }
Packit Service a2ae7a
Packit Service a2ae7a
            buf = new_buf;
Packit Service a2ae7a
        }
Packit Service a2ae7a
Packit Service a2ae7a
        /* Ensure that (size + requested <= max_len); */
Packit Service a2ae7a
        requested = MIN (size < max_len ? max_len - size : 0,
Packit Service a2ae7a
                         alloc - size - 1);
Packit Service a2ae7a
        count = fread (buf + size, 1, requested, stream);
Packit Service a2ae7a
        size += count;
Packit Service a2ae7a
Packit Service a2ae7a
        if (count != requested || requested == 0) {
Packit Service a2ae7a
            save_errno = errno;
Packit Service a2ae7a
            if (ferror (stream))
Packit Service a2ae7a
                break;
Packit Service a2ae7a
            buf[size] = '\0';
Packit Service a2ae7a
            *length = size;
Packit Service a2ae7a
            return buf;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
    free (buf);
Packit Service a2ae7a
    errno = save_errno;
Packit Service a2ae7a
    return NULL;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char* xfread_file(FILE *fp) {
Packit Service a2ae7a
    char *result;
Packit Service a2ae7a
    size_t len;
Packit Service a2ae7a
Packit Service a2ae7a
    if (!fp)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    result = fread_file_lim(fp, MAX_READ_LEN, &len;;
Packit Service a2ae7a
Packit Service a2ae7a
    if (result != NULL
Packit Service a2ae7a
        && len <= MAX_READ_LEN
Packit Service a2ae7a
        && (int) len == len)
Packit Service a2ae7a
        return result;
Packit Service a2ae7a
Packit Service a2ae7a
    free(result);
Packit Service a2ae7a
    return NULL;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char* xread_file(const char *path) {
Packit Service a2ae7a
    FILE *fp;
Packit Service a2ae7a
    char *result;
Packit Service a2ae7a
Packit Service a2ae7a
    fp = fopen(path, "r");
Packit Service a2ae7a
    if (!fp)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    result = xfread_file(fp);
Packit Service a2ae7a
    fclose(fp);
Packit Service a2ae7a
Packit Service a2ae7a
    return result;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/*
Packit Service a2ae7a
 * Escape/unescape of string literals
Packit Service a2ae7a
 */
Packit Service a2ae7a
static const char *const escape_chars = "\a\b\t\n\v\f\r";
Packit Service a2ae7a
static const char *const escape_names = "abtnvfr";
Packit Service a2ae7a
Packit Service a2ae7a
char *unescape(const char *s, int len, const char *extra) {
Packit Service a2ae7a
    size_t size;
Packit Service a2ae7a
    const char *n;
Packit Service a2ae7a
    char *result, *t;
Packit Service a2ae7a
    int i;
Packit Service a2ae7a
Packit Service a2ae7a
    if (len < 0 || len > strlen(s))
Packit Service a2ae7a
        len = strlen(s);
Packit Service a2ae7a
Packit Service a2ae7a
    size = 0;
Packit Service a2ae7a
    for (i=0; i < len; i++, size++) {
Packit Service a2ae7a
        if (s[i] == '\\' && strchr(escape_names, s[i+1])) {
Packit Service a2ae7a
            i += 1;
Packit Service a2ae7a
        } else if (s[i] == '\\' && extra && strchr(extra, s[i+1])) {
Packit Service a2ae7a
            i += 1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
    if (ALLOC_N(result, size + 1) < 0)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    for (i = 0, t = result; i < len; i++, size++) {
Packit Service a2ae7a
        if (s[i] == '\\' && (n = strchr(escape_names, s[i+1])) != NULL) {
Packit Service a2ae7a
            *t++ = escape_chars[n - escape_names];
Packit Service a2ae7a
            i += 1;
Packit Service a2ae7a
        } else if (s[i] == '\\' && extra && strchr(extra, s[i+1]) != NULL) {
Packit Service a2ae7a
            *t++ = s[i+1];
Packit Service a2ae7a
            i += 1;
Packit Service a2ae7a
        } else {
Packit Service a2ae7a
            *t++ = s[i];
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
    return result;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char *escape(const char *text, int cnt, const char *extra) {
Packit Service a2ae7a
Packit Service a2ae7a
    int len = 0;
Packit Service a2ae7a
    char *esc = NULL, *e;
Packit Service a2ae7a
Packit Service a2ae7a
    if (cnt < 0 || cnt > strlen(text))
Packit Service a2ae7a
        cnt = strlen(text);
Packit Service a2ae7a
Packit Service a2ae7a
    for (int i=0; i < cnt; i++) {
Packit Service a2ae7a
        if (text[i] && (strchr(escape_chars, text[i]) != NULL))
Packit Service a2ae7a
            len += 2;  /* Escaped as '\x' */
Packit Service a2ae7a
        else if (text[i] && extra && (strchr(extra, text[i]) != NULL))
Packit Service a2ae7a
            len += 2;  /* Escaped as '\x' */
Packit Service a2ae7a
        else if (! isprint(text[i]))
Packit Service a2ae7a
            len += 4;  /* Escaped as '\ooo' */
Packit Service a2ae7a
        else
Packit Service a2ae7a
            len += 1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    if (ALLOC_N(esc, len+1) < 0)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
    e = esc;
Packit Service a2ae7a
    for (int i=0; i < cnt; i++) {
Packit Service a2ae7a
        char *p;
Packit Service a2ae7a
        if (text[i] && ((p = strchr(escape_chars, text[i])) != NULL)) {
Packit Service a2ae7a
            *e++ = '\\';
Packit Service a2ae7a
            *e++ = escape_names[p - escape_chars];
Packit Service a2ae7a
        } else if (text[i] && extra && (strchr(extra, text[i]) != NULL)) {
Packit Service a2ae7a
            *e++ = '\\';
Packit Service a2ae7a
            *e++ = text[i];
Packit Service a2ae7a
        } else if (! isprint(text[i])) {
Packit Service a2ae7a
            sprintf(e, "\\%03o", (unsigned char) text[i]);
Packit Service a2ae7a
            e += 4;
Packit Service a2ae7a
        } else {
Packit Service a2ae7a
            *e++ = text[i];
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
    return esc;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int print_chars(FILE *out, const char *text, int cnt) {
Packit Service a2ae7a
    int total = 0;
Packit Service a2ae7a
    char *esc;
Packit Service a2ae7a
Packit Service a2ae7a
    if (text == NULL) {
Packit Service a2ae7a
        fprintf(out, "nil");
Packit Service a2ae7a
        return 3;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    if (cnt < 0)
Packit Service a2ae7a
        cnt = strlen(text);
Packit Service a2ae7a
Packit Service a2ae7a
    esc = escape(text, cnt, "\"");
Packit Service a2ae7a
    total = strlen(esc);
Packit Service a2ae7a
    if (out != NULL)
Packit Service a2ae7a
        fprintf(out, "%s", esc);
Packit Service a2ae7a
    free(esc);
Packit Service a2ae7a
Packit Service a2ae7a
    return total;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char *format_pos(const char *text, int pos) {
Packit Service a2ae7a
    static const int window = 28;
Packit Service a2ae7a
    char *buf = NULL, *left = NULL, *right = NULL;
Packit Service a2ae7a
    int before = pos;
Packit Service a2ae7a
    int llen, rlen;
Packit Service a2ae7a
    int r;
Packit Service a2ae7a
Packit Service a2ae7a
    if (before > window)
Packit Service a2ae7a
        before = window;
Packit Service a2ae7a
    left = escape(text + pos - before, before, NULL);
Packit Service a2ae7a
    if (left == NULL)
Packit Service a2ae7a
        goto done;
Packit Service a2ae7a
    right = escape(text + pos, window, NULL);
Packit Service a2ae7a
    if (right == NULL)
Packit Service a2ae7a
        goto done;
Packit Service a2ae7a
Packit Service a2ae7a
    llen = strlen(left);
Packit Service a2ae7a
    rlen = strlen(right);
Packit Service a2ae7a
    if (llen < window && rlen < window) {
Packit Service a2ae7a
        r = asprintf(&buf, "%*s%s|=|%s%-*s\n", window - llen, "<", left,
Packit Service a2ae7a
                     right, window - rlen, ">");
Packit Service a2ae7a
    } else if (strlen(left) < window) {
Packit Service a2ae7a
        r = asprintf(&buf, "%*s%s|=|%s>\n", window - llen, "<", left, right);
Packit Service a2ae7a
    } else if (strlen(right) < window) {
Packit Service a2ae7a
        r = asprintf(&buf, "<%s|=|%s%-*s\n", left, right, window - rlen, ">");
Packit Service a2ae7a
    } else {
Packit Service a2ae7a
        r = asprintf(&buf, "<%s|=|%s>\n", left, right);
Packit Service a2ae7a
    }
Packit Service a2ae7a
    if (r < 0) {
Packit Service a2ae7a
        buf = NULL;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
 done:
Packit Service a2ae7a
    free(left);
Packit Service a2ae7a
    free(right);
Packit Service a2ae7a
    return buf;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
void print_pos(FILE *out, const char *text, int pos) {
Packit Service a2ae7a
    char *format = format_pos(text, pos);
Packit Service a2ae7a
Packit Service a2ae7a
    if (format != NULL) {
Packit Service a2ae7a
        fputs(format, out);
Packit Service a2ae7a
        FREE(format);
Packit Service a2ae7a
    }
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int __aug_init_memstream(struct memstream *ms) {
Packit Service a2ae7a
    MEMZERO(ms, 1);
Packit Service a2ae7a
#if HAVE_OPEN_MEMSTREAM
Packit Service a2ae7a
    ms->stream = open_memstream(&(ms->buf), &(ms->size));
Packit Service a2ae7a
    return ms->stream == NULL ? -1 : 0;
Packit Service a2ae7a
#else
Packit Service a2ae7a
    ms->stream = tmpfile();
Packit Service a2ae7a
    if (ms->stream == NULL) {
Packit Service a2ae7a
        return -1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
#endif
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int __aug_close_memstream(struct memstream *ms) {
Packit Service a2ae7a
#if !HAVE_OPEN_MEMSTREAM
Packit Service a2ae7a
    rewind(ms->stream);
Packit Service a2ae7a
    ms->buf = fread_file_lim(ms->stream, MAX_READ_LEN, &(ms->size));
Packit Service a2ae7a
#endif
Packit Service a2ae7a
    if (fclose(ms->stream) == EOF) {
Packit Service a2ae7a
        FREE(ms->buf);
Packit Service a2ae7a
        ms->size = 0;
Packit Service a2ae7a
        return -1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int tree_sibling_index(struct tree *tree) {
Packit Service a2ae7a
    struct tree *siblings = tree->parent->children;
Packit Service a2ae7a
Packit Service a2ae7a
    int cnt = 0, ind = 0;
Packit Service a2ae7a
Packit Service a2ae7a
    list_for_each(t, siblings) {
Packit Service a2ae7a
        if (streqv(t->label, tree->label)) {
Packit Service a2ae7a
            cnt += 1;
Packit Service a2ae7a
            if (t == tree)
Packit Service a2ae7a
                ind = cnt;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
    if (cnt > 1) {
Packit Service a2ae7a
        return ind;
Packit Service a2ae7a
    } else {
Packit Service a2ae7a
        return 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char *path_expand(struct tree *tree, const char *ppath) {
Packit Service a2ae7a
    char *path;
Packit Service a2ae7a
    const char *label;
Packit Service a2ae7a
    char *escaped = NULL;
Packit Service a2ae7a
    int r;
Packit Service a2ae7a
Packit Service a2ae7a
    int ind = tree_sibling_index(tree);
Packit Service a2ae7a
Packit Service a2ae7a
    if (ppath == NULL)
Packit Service a2ae7a
        ppath = "";
Packit Service a2ae7a
Packit Service a2ae7a
    if (tree->label == NULL)
Packit Service a2ae7a
        label = "(none)";
Packit Service a2ae7a
    else
Packit Service a2ae7a
        label = tree->label;
Packit Service a2ae7a
Packit Service a2ae7a
    r = pathx_escape_name(label, &escaped);
Packit Service a2ae7a
    if (r < 0)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    if (escaped != NULL)
Packit Service a2ae7a
        label = escaped;
Packit Service a2ae7a
Packit Service a2ae7a
    if (ind > 0) {
Packit Service a2ae7a
        r = asprintf(&path, "%s/%s[%d]", ppath, label, ind);
Packit Service a2ae7a
    } else {
Packit Service a2ae7a
        r = asprintf(&path, "%s/%s", ppath, label);
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
    free(escaped);
Packit Service a2ae7a
Packit Service a2ae7a
    if (r == -1)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
    return path;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char *path_of_tree(struct tree *tree) {
Packit Service a2ae7a
    int depth, i;
Packit Service a2ae7a
    struct tree *t, **anc;
Packit Service a2ae7a
    char *path = NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    for (t = tree, depth = 1; ! ROOT_P(t); depth++, t = t->parent);
Packit Service a2ae7a
    if (ALLOC_N(anc, depth) < 0)
Packit Service a2ae7a
        return NULL;
Packit Service a2ae7a
Packit Service a2ae7a
    for (t = tree, i = depth - 1; i >= 0; i--, t = t->parent)
Packit Service a2ae7a
        anc[i] = t;
Packit Service a2ae7a
Packit Service a2ae7a
    for (i = 0; i < depth; i++) {
Packit Service a2ae7a
        char *p = path_expand(anc[i], path);
Packit Service a2ae7a
        free(path);
Packit Service a2ae7a
        path = p;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    FREE(anc);
Packit Service a2ae7a
    return path;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* User-facing path cleaning */
Packit Service a2ae7a
static char *cleanstr(char *path, const char sep) {
Packit Service a2ae7a
    if (path == NULL || strlen(path) == 0)
Packit Service a2ae7a
        return path;
Packit Service a2ae7a
    char *e = path + strlen(path) - 1;
Packit Service a2ae7a
    while (e >= path && (*e == sep || isspace(*e)))
Packit Service a2ae7a
        *e-- = '\0';
Packit Service a2ae7a
    return path;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
char *cleanpath(char *path) {
Packit Service a2ae7a
    if (path == NULL || strlen(path) == 0)
Packit Service a2ae7a
        return path;
Packit Service a2ae7a
    if (STREQ(path, "/"))
Packit Service a2ae7a
        return path;
Packit Service a2ae7a
    return cleanstr(path, SEP);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
const char *xstrerror(int errnum, char *buf, size_t len) {
Packit Service a2ae7a
#ifdef HAVE_STRERROR_R
Packit Service a2ae7a
# ifdef __USE_GNU
Packit Service a2ae7a
    /* Annoying linux specific API contract */
Packit Service a2ae7a
    return strerror_r(errnum, buf, len);
Packit Service a2ae7a
# else
Packit Service a2ae7a
    strerror_r(errnum, buf, len);
Packit Service a2ae7a
    return buf;
Packit Service a2ae7a
# endif
Packit Service a2ae7a
#else
Packit Service a2ae7a
    int n = snprintf(buf, len, "errno=%d", errnum);
Packit Service a2ae7a
    return (0 < n && n < len
Packit Service a2ae7a
            ? buf : "internal error: buffer too small in xstrerror");
Packit Service a2ae7a
#endif
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
int xasprintf(char **strp, const char *format, ...) {
Packit Service a2ae7a
  va_list args;
Packit Service a2ae7a
  int result;
Packit Service a2ae7a
Packit Service a2ae7a
  va_start (args, format);
Packit Service a2ae7a
  result = vasprintf (strp, format, args);
Packit Service a2ae7a
  va_end (args);
Packit Service a2ae7a
  if (result < 0)
Packit Service a2ae7a
      *strp = NULL;
Packit Service a2ae7a
  return result;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
/* From libvirt's src/xen/block_stats.c */
Packit Service a2ae7a
int xstrtoint64(char const *s, int base, int64_t *result) {
Packit Service a2ae7a
    long long int lli;
Packit Service a2ae7a
    char *p;
Packit Service a2ae7a
Packit Service a2ae7a
    errno = 0;
Packit Service a2ae7a
    lli = strtoll(s, &p, base);
Packit Service a2ae7a
    if (errno || !(*p == 0 || *p == '\n') || p == s || (int64_t) lli != lli)
Packit Service a2ae7a
        return -1;
Packit Service a2ae7a
    *result = lli;
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
void calc_line_ofs(const char *text, size_t pos, size_t *line, size_t *ofs) {
Packit Service a2ae7a
    *line = 1;
Packit Service a2ae7a
    *ofs = 0;
Packit Service a2ae7a
    for (const char *t = text; t < text + pos; t++) {
Packit Service a2ae7a
        *ofs += 1;
Packit Service a2ae7a
        if (*t == '\n') {
Packit Service a2ae7a
            *ofs = 0;
Packit Service a2ae7a
            *line += 1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#if HAVE_USELOCALE
Packit Service a2ae7a
int regexp_c_locale(ATTRIBUTE_UNUSED char **u, ATTRIBUTE_UNUSED size_t *len) {
Packit Service a2ae7a
    /* On systems with uselocale, we are ok, since we make sure that we
Packit Service a2ae7a
     * switch to the "C" locale any time we enter through the public API
Packit Service a2ae7a
     */
Packit Service a2ae7a
    return 0;
Packit Service a2ae7a
}
Packit Service a2ae7a
#else
Packit Service a2ae7a
int regexp_c_locale(char **u, size_t *len) {
Packit Service a2ae7a
    /* Without uselocale, we need to expand character ranges */
Packit Service a2ae7a
    int r;
Packit Service a2ae7a
    char *s = *u;
Packit Service a2ae7a
    size_t s_len, u_len;
Packit Service a2ae7a
    if (len == NULL) {
Packit Service a2ae7a
        len = &u_len;
Packit Service a2ae7a
        s_len = strlen(s);
Packit Service a2ae7a
    } else {
Packit Service a2ae7a
        s_len = *len;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    r = fa_expand_char_ranges(s, s_len, u, len);
Packit Service a2ae7a
    if (r != 0) {
Packit Service a2ae7a
        *u = s;
Packit Service a2ae7a
        *len = s_len;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    if (r < 0)
Packit Service a2ae7a
        return -1;
Packit Service a2ae7a
    /* Syntax errors will be caught when the result is compiled */
Packit Service a2ae7a
    if (r > 0)
Packit Service a2ae7a
        return 0;
Packit Service a2ae7a
    free(s);
Packit Service a2ae7a
    return 1;
Packit Service a2ae7a
}
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
#if ENABLE_DEBUG
Packit Service a2ae7a
bool debugging(const char *category) {
Packit Service a2ae7a
    const char *debug = getenv("AUGEAS_DEBUG");
Packit Service a2ae7a
    const char *s;
Packit Service a2ae7a
Packit Service a2ae7a
    if (debug == NULL)
Packit Service a2ae7a
        return false;
Packit Service a2ae7a
Packit Service a2ae7a
    for (s = debug; s != NULL; ) {
Packit Service a2ae7a
        if (STREQLEN(s, category, strlen(category)))
Packit Service a2ae7a
            return true;
Packit Service a2ae7a
        s = strchr(s, ':');
Packit Service a2ae7a
        if (s != NULL)
Packit Service a2ae7a
            s+=1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
    return false;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
FILE *debug_fopen(const char *format, ...) {
Packit Service a2ae7a
    va_list ap;
Packit Service a2ae7a
    FILE *result = NULL;
Packit Service a2ae7a
    const char *dir;
Packit Service a2ae7a
    char *name = NULL, *path = NULL;
Packit Service a2ae7a
    int r;
Packit Service a2ae7a
Packit Service a2ae7a
    dir = getenv("AUGEAS_DEBUG_DIR");
Packit Service a2ae7a
    if (dir == NULL)
Packit Service a2ae7a
        goto error;
Packit Service a2ae7a
Packit Service a2ae7a
    va_start(ap, format);
Packit Service a2ae7a
    r = vasprintf(&name, format, ap);
Packit Service a2ae7a
    va_end(ap);
Packit Service a2ae7a
    if (r < 0)
Packit Service a2ae7a
        goto error;
Packit Service a2ae7a
Packit Service a2ae7a
    r = xasprintf(&path, "%s/%s", dir, name);
Packit Service a2ae7a
    if (r < 0)
Packit Service a2ae7a
        goto error;
Packit Service a2ae7a
Packit Service a2ae7a
    result = fopen(path, "w");
Packit Service a2ae7a
Packit Service a2ae7a
 error:
Packit Service a2ae7a
    free(name);
Packit Service a2ae7a
    free(path);
Packit Service a2ae7a
    return result;
Packit Service a2ae7a
}
Packit Service a2ae7a
#endif
Packit Service a2ae7a
/*
Packit Service a2ae7a
 * Local variables:
Packit Service a2ae7a
 *  indent-tabs-mode: nil
Packit Service a2ae7a
 *  c-indent-level: 4
Packit Service a2ae7a
 *  c-basic-offset: 4
Packit Service a2ae7a
 *  tab-width: 4
Packit Service a2ae7a
 * End:
Packit Service a2ae7a
 */