Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/dbutil/tdumputil.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/tdumputil.c - utilities for tab-separated, etc. files */
3
/*
4
* Copyright (C) 2015 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include "k5-int.h"
34
#include "k5-platform.h" /* for vasprintf */
35
#include <assert.h>
36
#include <stdarg.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "tdumputil.h"
42
43
/*
44
* Structure describing flavor of a tabular output format.
45
*
46
* fieldsep is the field separator
47
*
48
* recordsep is the record/line separator
49
*
50
* quotechar begins and ends a quoted field. If an instance of quotechar
51
* occurs within a quoted field value, it is doubled.
52
*
53
* Values are only quoted if they contain fieldsep, recordsep, or quotechar.
54
*/
55
struct flavor {
56
int fieldsep; /* field separator */
57
int recordsep; /* record separator */
58
int quotechar; /* quote character */
59
};
60
61
struct rechandle {
62
FILE *fh;
63
const char *rectype;
64
int do_sep;
65
struct flavor flavor;
66
};
67
68
static const struct flavor tabsep = {
69
'\t', /* fieldsep */
70
'\n', /* recordsep */
71
'\0' /* quotechar */
72
};
73
74
static const struct flavor csv = {
75
',', /* fieldsep */
76
'\n', /* recordsep */
77
'"' /* quotechar */
78
};
79
80
/*
81
* Double any quote characters present in a quoted field.
82
*/
83
static char *
84
qquote(struct flavor *fl, const char *s)
85
{
86
const char *sp;
87
struct k5buf buf;
88
89
k5_buf_init_dynamic(&buf);
90
for (sp = s; *sp != '\0'; sp++) {
91
k5_buf_add_len(&buf, sp, 1);
92
if (*sp == fl->quotechar)
93
k5_buf_add_len(&buf, sp, 1);
94
}
95
return k5_buf_cstring(&buf);
96
}
97
98
/*
99
* Write an optionally quoted field.
100
*/
101
static int
102
writequoted(struct rechandle *h, const char *fmt, va_list ap)
103
{
104
int doquote = 0, ret;
105
char *s = NULL, *qs = NULL;
106
struct flavor fl = h->flavor;
107
108
assert(fl.quotechar != '\0');
109
ret = vasprintf(&s, fmt, ap);
110
if (ret < 0)
111
return ret;
112
if (strchr(s, fl.fieldsep) != NULL)
113
doquote = 1;
114
if (strchr(s, fl.recordsep) != NULL)
115
doquote = 1;
116
if (strchr(s, fl.quotechar) != NULL)
117
doquote = 1;
118
119
if (doquote) {
120
qs = qquote(&fl, s);
121
if (qs == NULL) {
122
ret = -1;
123
goto cleanup;
124
}
125
ret = fprintf(h->fh, "%c%s%c", fl.quotechar, qs, fl.quotechar);
126
} else {
127
ret = fprintf(h->fh, "%s", s);
128
}
129
cleanup:
130
free(s);
131
free(qs);
132
return ret;
133
}
134
135
/*
136
* Return a rechandle with the requested file handle and rectype.
137
*
138
* rectype must be a valid pointer for the entire lifetime of the rechandle (or
139
* null)
140
*/
141
static struct rechandle *
142
rechandle_common(FILE *fh, const char *rectype)
143
{
144
struct rechandle *h = calloc(1, sizeof(*h));
145
146
if (h == NULL)
147
return NULL;
148
h->fh = fh;
149
h->rectype = rectype;
150
h->do_sep = 0;
151
return h;
152
}
153
154
/*
155
* Return a rechandle for tab-separated output.
156
*/
157
struct rechandle *
158
rechandle_tabsep(FILE *fh, const char *rectype)
159
{
160
struct rechandle *h = rechandle_common(fh, rectype);
161
162
if (h == NULL)
163
return NULL;
164
h->flavor = tabsep;
165
return h;
166
}
167
168
/*
169
* Return a rechandle for CSV output.
170
*/
171
struct rechandle *
172
rechandle_csv(FILE *fh, const char *rectype)
173
{
174
struct rechandle *h = rechandle_common(fh, rectype);
175
176
if (h == NULL)
177
return NULL;
178
h->flavor = csv;
179
return h;
180
}
181
182
/*
183
* Free a rechandle.
184
*/
185
void
186
rechandle_free(struct rechandle *h)
187
{
188
free(h);
189
}
190
191
/*
192
* Start a record. This includes writing a record type prefix (rectype) if
193
* specified.
194
*/
195
int
196
startrec(struct rechandle *h)
197
{
198
if (h->rectype == NULL) {
199
h->do_sep = 0;
200
return 0;
201
}
202
h->do_sep = 1;
203
return fputs(h->rectype, h->fh);
204
}
205
206
/*
207
* Write a single field of a record. This includes writing a separator
208
* character, if appropriate.
209
*/
210
int
211
writefield(struct rechandle *h, const char *fmt, ...)
212
{
213
int ret = 0;
214
va_list ap;
215
struct flavor fl = h->flavor;
216
217
if (h->do_sep) {
218
ret = fputc(fl.fieldsep, h->fh);
219
if (ret < 0)
220
return ret;
221
}
222
h->do_sep = 1;
223
va_start(ap, fmt);
224
if (fl.quotechar == '\0')
225
ret = vfprintf(h->fh, fmt, ap);
226
else
227
ret = writequoted(h, fmt, ap);
228
va_end(ap);
229
return ret;
230
}
231
232
/*
233
* Finish a record (line).
234
*/
235
int
236
endrec(struct rechandle *h)
237
{
238
int ret = 0;
239
struct flavor fl = h->flavor;
240
241
ret = fputc(fl.recordsep, h->fh);
242
h->do_sep = 0;
243
return ret;
244
}
245
246
/*
247
* Write a header line if h->rectype is null. (If rectype is set, it will be
248
* prefixed to output lines, most likely in a mixed record type output file, so
249
* it doesn't make sense to output a header line in that case.)
250
*/
251
int
252
writeheader(struct rechandle *h, char * const *a)
253
{
254
int ret = 0;
255
char * const *p;
256
257
if (h->rectype != NULL)
258
return 0;
259
for (p = a; *p != NULL; p++) {
260
ret = writefield(h, "%s", *p);
261
if (ret < 0)
262
return ret;
263
}
264
ret = endrec(h);
265
return ret;
266
}
267
268