Path: blob/main/crypto/krb5/src/kadmin/dbutil/tdumputil.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* kdc/tdumputil.c - utilities for tab-separated, etc. files */2/*3* Copyright (C) 2015 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include "k5-int.h"33#include "k5-platform.h" /* for vasprintf */34#include <assert.h>35#include <stdarg.h>36#include <stdio.h>37#include <stdlib.h>38#include <string.h>3940#include "tdumputil.h"4142/*43* Structure describing flavor of a tabular output format.44*45* fieldsep is the field separator46*47* recordsep is the record/line separator48*49* quotechar begins and ends a quoted field. If an instance of quotechar50* occurs within a quoted field value, it is doubled.51*52* Values are only quoted if they contain fieldsep, recordsep, or quotechar.53*/54struct flavor {55int fieldsep; /* field separator */56int recordsep; /* record separator */57int quotechar; /* quote character */58};5960struct rechandle {61FILE *fh;62const char *rectype;63int do_sep;64struct flavor flavor;65};6667static const struct flavor tabsep = {68'\t', /* fieldsep */69'\n', /* recordsep */70'\0' /* quotechar */71};7273static const struct flavor csv = {74',', /* fieldsep */75'\n', /* recordsep */76'"' /* quotechar */77};7879/*80* Double any quote characters present in a quoted field.81*/82static char *83qquote(struct flavor *fl, const char *s)84{85const char *sp;86struct k5buf buf;8788k5_buf_init_dynamic(&buf);89for (sp = s; *sp != '\0'; sp++) {90k5_buf_add_len(&buf, sp, 1);91if (*sp == fl->quotechar)92k5_buf_add_len(&buf, sp, 1);93}94return k5_buf_cstring(&buf);95}9697/*98* Write an optionally quoted field.99*/100static int101writequoted(struct rechandle *h, const char *fmt, va_list ap)102{103int doquote = 0, ret;104char *s = NULL, *qs = NULL;105struct flavor fl = h->flavor;106107assert(fl.quotechar != '\0');108ret = vasprintf(&s, fmt, ap);109if (ret < 0)110return ret;111if (strchr(s, fl.fieldsep) != NULL)112doquote = 1;113if (strchr(s, fl.recordsep) != NULL)114doquote = 1;115if (strchr(s, fl.quotechar) != NULL)116doquote = 1;117118if (doquote) {119qs = qquote(&fl, s);120if (qs == NULL) {121ret = -1;122goto cleanup;123}124ret = fprintf(h->fh, "%c%s%c", fl.quotechar, qs, fl.quotechar);125} else {126ret = fprintf(h->fh, "%s", s);127}128cleanup:129free(s);130free(qs);131return ret;132}133134/*135* Return a rechandle with the requested file handle and rectype.136*137* rectype must be a valid pointer for the entire lifetime of the rechandle (or138* null)139*/140static struct rechandle *141rechandle_common(FILE *fh, const char *rectype)142{143struct rechandle *h = calloc(1, sizeof(*h));144145if (h == NULL)146return NULL;147h->fh = fh;148h->rectype = rectype;149h->do_sep = 0;150return h;151}152153/*154* Return a rechandle for tab-separated output.155*/156struct rechandle *157rechandle_tabsep(FILE *fh, const char *rectype)158{159struct rechandle *h = rechandle_common(fh, rectype);160161if (h == NULL)162return NULL;163h->flavor = tabsep;164return h;165}166167/*168* Return a rechandle for CSV output.169*/170struct rechandle *171rechandle_csv(FILE *fh, const char *rectype)172{173struct rechandle *h = rechandle_common(fh, rectype);174175if (h == NULL)176return NULL;177h->flavor = csv;178return h;179}180181/*182* Free a rechandle.183*/184void185rechandle_free(struct rechandle *h)186{187free(h);188}189190/*191* Start a record. This includes writing a record type prefix (rectype) if192* specified.193*/194int195startrec(struct rechandle *h)196{197if (h->rectype == NULL) {198h->do_sep = 0;199return 0;200}201h->do_sep = 1;202return fputs(h->rectype, h->fh);203}204205/*206* Write a single field of a record. This includes writing a separator207* character, if appropriate.208*/209int210writefield(struct rechandle *h, const char *fmt, ...)211{212int ret = 0;213va_list ap;214struct flavor fl = h->flavor;215216if (h->do_sep) {217ret = fputc(fl.fieldsep, h->fh);218if (ret < 0)219return ret;220}221h->do_sep = 1;222va_start(ap, fmt);223if (fl.quotechar == '\0')224ret = vfprintf(h->fh, fmt, ap);225else226ret = writequoted(h, fmt, ap);227va_end(ap);228return ret;229}230231/*232* Finish a record (line).233*/234int235endrec(struct rechandle *h)236{237int ret = 0;238struct flavor fl = h->flavor;239240ret = fputc(fl.recordsep, h->fh);241h->do_sep = 0;242return ret;243}244245/*246* Write a header line if h->rectype is null. (If rectype is set, it will be247* prefixed to output lines, most likely in a mixed record type output file, so248* it doesn't make sense to output a header line in that case.)249*/250int251writeheader(struct rechandle *h, char * const *a)252{253int ret = 0;254char * const *p;255256if (h->rectype != NULL)257return 0;258for (p = a; *p != NULL; p++) {259ret = writefield(h, "%s", *p);260if (ret < 0)261return ret;262}263ret = endrec(h);264return ret;265}266267268