diff options
Diffstat (limited to 'src/kadmin/dbutil/tdumputil.c')
| -rw-r--r-- | src/kadmin/dbutil/tdumputil.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/src/kadmin/dbutil/tdumputil.c b/src/kadmin/dbutil/tdumputil.c new file mode 100644 index 000000000000..2c14d5670e08 --- /dev/null +++ b/src/kadmin/dbutil/tdumputil.c @@ -0,0 +1,266 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* kdc/tdumputil.c - utilities for tab-separated, etc. files */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "k5-platform.h" /* for vasprintf */ +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tdumputil.h" + +/* + * Structure describing flavor of a tabular output format. + * + * fieldsep is the field separator + * + * recordsep is the record/line separator + * + * quotechar begins and ends a quoted field. If an instance of quotechar + * occurs within a quoted field value, it is doubled. + * + * Values are only quoted if they contain fieldsep, recordsep, or quotechar. + */ +struct flavor { + int fieldsep; /* field separator */ + int recordsep; /* record separator */ + int quotechar; /* quote character */ +}; + +struct rechandle { + FILE *fh; + const char *rectype; + int do_sep; + struct flavor flavor; +}; + +static const struct flavor tabsep = { + '\t', /* fieldsep */ + '\n', /* recordsep */ + '\0' /* quotechar */ +}; + +static const struct flavor csv = { + ',', /* fieldsep */ + '\n', /* recordsep */ + '"' /* quotechar */ +}; + +/* + * Double any quote characters present in a quoted field. + */ +static char * +qquote(struct flavor *fl, const char *s) +{ + const char *sp; + struct k5buf buf; + + k5_buf_init_dynamic(&buf); + for (sp = s; *sp != '\0'; sp++) { + k5_buf_add_len(&buf, sp, 1); + if (*sp == fl->quotechar) + k5_buf_add_len(&buf, sp, 1); + } + return buf.data; +} + +/* + * Write an optionally quoted field. + */ +static int +writequoted(struct rechandle *h, const char *fmt, va_list ap) +{ + int doquote = 0, ret; + char *s = NULL, *qs = NULL; + struct flavor fl = h->flavor; + + assert(fl.quotechar != '\0'); + ret = vasprintf(&s, fmt, ap); + if (ret < 0) + return ret; + if (strchr(s, fl.fieldsep) != NULL) + doquote = 1; + if (strchr(s, fl.recordsep) != NULL) + doquote = 1; + if (strchr(s, fl.quotechar) != NULL) + doquote = 1; + + if (doquote) { + qs = qquote(&fl, s); + if (qs == NULL) { + ret = -1; + goto cleanup; + } + ret = fprintf(h->fh, "%c%s%c", fl.quotechar, qs, fl.quotechar); + } else { + ret = fprintf(h->fh, "%s", s); + } +cleanup: + free(s); + free(qs); + return ret; +} + +/* + * Return a rechandle with the requested file handle and rectype. + * + * rectype must be a valid pointer for the entire lifetime of the rechandle (or + * null) + */ +static struct rechandle * +rechandle_common(FILE *fh, const char *rectype) +{ + struct rechandle *h = calloc(1, sizeof(*h)); + + if (h == NULL) + return NULL; + h->fh = fh; + h->rectype = rectype; + h->do_sep = 0; + return h; +} + +/* + * Return a rechandle for tab-separated output. + */ +struct rechandle * +rechandle_tabsep(FILE *fh, const char *rectype) +{ + struct rechandle *h = rechandle_common(fh, rectype); + + if (h == NULL) + return NULL; + h->flavor = tabsep; + return h; +} + +/* + * Return a rechandle for CSV output. + */ +struct rechandle * +rechandle_csv(FILE *fh, const char *rectype) +{ + struct rechandle *h = rechandle_common(fh, rectype); + + if (h == NULL) + return NULL; + h->flavor = csv; + return h; +} + +/* + * Free a rechandle. + */ +void +rechandle_free(struct rechandle *h) +{ + free(h); +} + +/* + * Start a record. This includes writing a record type prefix (rectype) if + * specified. + */ +int +startrec(struct rechandle *h) +{ + if (h->rectype == NULL) { + h->do_sep = 0; + return 0; + } + h->do_sep = 1; + return fputs(h->rectype, h->fh); +} + +/* + * Write a single field of a record. This includes writing a separator + * character, if appropriate. + */ +int +writefield(struct rechandle *h, const char *fmt, ...) +{ + int ret = 0; + va_list ap; + struct flavor fl = h->flavor; + + if (h->do_sep) { + ret = fputc(fl.fieldsep, h->fh); + if (ret < 0) + return ret; + } + h->do_sep = 1; + va_start(ap, fmt); + if (fl.quotechar == '\0') + ret = vfprintf(h->fh, fmt, ap); + else + ret = writequoted(h, fmt, ap); + va_end(ap); + return ret; +} + +/* + * Finish a record (line). + */ +int +endrec(struct rechandle *h) +{ + int ret = 0; + struct flavor fl = h->flavor; + + ret = fputc(fl.recordsep, h->fh); + h->do_sep = 0; + return ret; +} + +/* + * Write a header line if h->rectype is null. (If rectype is set, it will be + * prefixed to output lines, most likely in a mixed record type output file, so + * it doesn't make sense to output a header line in that case.) + */ +int +writeheader(struct rechandle *h, char * const *a) +{ + int ret = 0; + char * const *p; + + if (h->rectype != NULL) + return 0; + for (p = a; *p != NULL; p++) { + ret = writefield(h, "%s", *p); + if (ret < 0) + return ret; + } + ret = endrec(h); + return ret; +} |
