Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2016 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : : #include "openvswitch/dynamic-string.h"
19 : : #include <inttypes.h>
20 : : #include <stdlib.h>
21 : : #include <string.h>
22 : : #include <time.h>
23 : : #include "timeval.h"
24 : : #include "util.h"
25 : :
26 : : /* Initializes 'ds' as an empty string buffer. */
27 : : void
28 : 884047 : ds_init(struct ds *ds)
29 : : {
30 : 884047 : ds->string = NULL;
31 : 884047 : ds->length = 0;
32 : 884047 : ds->allocated = 0;
33 : 884047 : }
34 : :
35 : : /* Sets 'ds''s length to 0, effectively clearing any existing content. Does
36 : : * not free any memory. */
37 : : void
38 : 41404605 : ds_clear(struct ds *ds)
39 : : {
40 : 41404605 : ds->length = 0;
41 : 41404605 : }
42 : :
43 : : /* Reduces 'ds''s length to no more than 'new_length'. (If its length is
44 : : * already 'new_length' or less, does nothing.) */
45 : : void
46 : 0 : ds_truncate(struct ds *ds, size_t new_length)
47 : : {
48 [ # # ]: 0 : if (ds->length > new_length) {
49 : 0 : ds->length = new_length;
50 : 0 : ds->string[new_length] = '\0';
51 : : }
52 : 0 : }
53 : :
54 : : /* Ensures that at least 'min_length + 1' bytes (including space for a null
55 : : * terminator) are allocated for ds->string, allocating or reallocating memory
56 : : * as necessary. */
57 : : void
58 : 5670032 : ds_reserve(struct ds *ds, size_t min_length)
59 : : {
60 [ + + ][ + + ]: 5670032 : if (min_length > ds->allocated || !ds->string) {
61 : 2242175 : ds->allocated += MAX(min_length, ds->allocated);
62 : 2242175 : ds->allocated = MAX(8, ds->allocated);
63 : 2242175 : ds->string = xrealloc(ds->string, ds->allocated + 1);
64 : : }
65 : 5670032 : }
66 : :
67 : : /* Appends space for 'n' bytes to the end of 'ds->string', increasing
68 : : * 'ds->length' by the same amount, and returns the first appended byte. The
69 : : * caller should fill in all 'n' bytes starting at the return value. */
70 : : char *
71 : 4880144 : ds_put_uninit(struct ds *ds, size_t n)
72 : : {
73 : 4880144 : ds_reserve(ds, ds->length + n);
74 : 4880144 : ds->length += n;
75 : 4880144 : ds->string[ds->length] = '\0';
76 : 4880144 : return &ds->string[ds->length - n];
77 : : }
78 : :
79 : : void
80 : 1200101 : ds_put_char__(struct ds *ds, char c)
81 : : {
82 : 1200101 : *ds_put_uninit(ds, 1) = c;
83 : 1200101 : }
84 : :
85 : : /* Appends unicode code point 'uc' to 'ds' in UTF-8 encoding. */
86 : : void
87 : 11 : ds_put_utf8(struct ds *ds, int uc)
88 : : {
89 [ + + ]: 11 : if (uc <= 0x7f) {
90 : 9 : ds_put_char(ds, uc);
91 [ - + ]: 2 : } else if (uc <= 0x7ff) {
92 : 0 : ds_put_char(ds, 0xc0 | (uc >> 6));
93 : 0 : ds_put_char(ds, 0x80 | (uc & 0x3f));
94 [ - + ]: 2 : } else if (uc <= 0xffff) {
95 : 0 : ds_put_char(ds, 0xe0 | (uc >> 12));
96 : 0 : ds_put_char(ds, 0x80 | ((uc >> 6) & 0x3f));
97 : 0 : ds_put_char(ds, 0x80 | (uc & 0x3f));
98 [ + - ]: 2 : } else if (uc <= 0x10ffff) {
99 : 2 : ds_put_char(ds, 0xf0 | (uc >> 18));
100 : 2 : ds_put_char(ds, 0x80 | ((uc >> 12) & 0x3f));
101 : 2 : ds_put_char(ds, 0x80 | ((uc >> 6) & 0x3f));
102 : 2 : ds_put_char(ds, 0x80 | (uc & 0x3f));
103 : : } else {
104 : : /* Invalid code point. Insert the Unicode general substitute
105 : : * REPLACEMENT CHARACTER. */
106 : 0 : ds_put_utf8(ds, 0xfffd);
107 : : }
108 : 11 : }
109 : :
110 : : void
111 : 44871 : ds_put_char_multiple(struct ds *ds, char c, size_t n)
112 : : {
113 : 44871 : memset(ds_put_uninit(ds, n), c, n);
114 : 44871 : }
115 : :
116 : : void
117 : 88 : ds_put_buffer(struct ds *ds, const char *s, size_t n)
118 : : {
119 : 88 : memcpy(ds_put_uninit(ds, n), s, n);
120 : 88 : }
121 : :
122 : : void
123 : 3440616 : ds_put_cstr(struct ds *ds, const char *s)
124 : : {
125 : 3440616 : size_t s_len = strlen(s);
126 : 3440616 : memcpy(ds_put_uninit(ds, s_len), s, s_len);
127 : 3440616 : }
128 : :
129 : : void
130 : 714 : ds_put_and_free_cstr(struct ds *ds, char *s)
131 : : {
132 : 714 : ds_put_cstr(ds, s);
133 : 714 : free(s);
134 : 714 : }
135 : :
136 : : void
137 : 19742572 : ds_put_format(struct ds *ds, const char *format, ...)
138 : : {
139 : : va_list args;
140 : :
141 : 19742572 : va_start(args, format);
142 : 19742572 : ds_put_format_valist(ds, format, args);
143 : 19742573 : va_end(args);
144 : 19742573 : }
145 : :
146 : : void
147 : 19949147 : ds_put_format_valist(struct ds *ds, const char *format, va_list args_)
148 : : {
149 : : va_list args;
150 : : size_t available;
151 : : int needed;
152 : :
153 : 19949147 : va_copy(args, args_);
154 [ + + ]: 19949147 : available = ds->string ? ds->allocated - ds->length + 1 : 0;
155 : 19949147 : needed = vsnprintf(&ds->string[ds->length], available, format, args);
156 : 19949147 : va_end(args);
157 : :
158 [ + + ]: 19949147 : if (needed < available) {
159 : 19632115 : ds->length += needed;
160 : : } else {
161 : 317032 : ds_reserve(ds, ds->length + needed);
162 : :
163 : 317032 : va_copy(args, args_);
164 : 317032 : available = ds->allocated - ds->length + 1;
165 : 317032 : needed = vsnprintf(&ds->string[ds->length], available, format, args);
166 : 317032 : va_end(args);
167 : :
168 [ - + ]: 317032 : ovs_assert(needed < available);
169 : 317032 : ds->length += needed;
170 : : }
171 : 19949147 : }
172 : :
173 : : void
174 : 2 : ds_put_printable(struct ds *ds, const char *s, size_t n)
175 : : {
176 : 2 : ds_reserve(ds, ds->length + n);
177 [ + + ]: 24 : while (n-- > 0) {
178 : 22 : unsigned char c = *s++;
179 [ + + ][ + - ]: 22 : if (c < 0x20 || c > 0x7e || c == '\\' || c == '"') {
[ + - ][ - + ]
180 : 2 : ds_put_format(ds, "\\%03o", (int) c);
181 : : } else {
182 : 20 : ds_put_char(ds, c);
183 : : }
184 : : }
185 : 2 : }
186 : :
187 : : /* Writes the current time with optional millisecond resolution to 'string'
188 : : * based on 'template'.
189 : : * The current time is either localtime or UTC based on 'utc'. */
190 : : void
191 : 98949 : ds_put_strftime_msec(struct ds *ds, const char *template, long long int when,
192 : : bool utc)
193 : : {
194 : : struct tm_msec tm;
195 [ + - ]: 98949 : if (utc) {
196 : 98949 : gmtime_msec(when, &tm);
197 : : } else {
198 : 0 : localtime_msec(when, &tm);
199 : : }
200 : :
201 : : for (;;) {
202 [ + - ]: 98949 : size_t avail = ds->string ? ds->allocated - ds->length + 1 : 0;
203 : 98949 : size_t used = strftime_msec(&ds->string[ds->length], avail, template,
204 : : &tm);
205 [ + - ]: 98949 : if (used) {
206 : 98949 : ds->length += used;
207 : 98949 : return;
208 : : }
209 [ # # ]: 0 : ds_reserve(ds, ds->length + (avail < 32 ? 64 : 2 * avail));
210 : 98949 : }
211 : : }
212 : :
213 : : /* Returns a malloc()'d string for time 'when' based on 'template', in local
214 : : * time or UTC based on 'utc'. */
215 : : char *
216 : 0 : xastrftime_msec(const char *template, long long int when, bool utc)
217 : : {
218 : : struct ds s;
219 : :
220 : 0 : ds_init(&s);
221 : 0 : ds_put_strftime_msec(&s, template, when, utc);
222 : 0 : return s.string;
223 : : }
224 : :
225 : : int
226 : 28862 : ds_get_line(struct ds *ds, FILE *file)
227 : : {
228 : 28862 : ds_clear(ds);
229 : : for (;;) {
230 : 1709200 : int c = getc(file);
231 [ + + ]: 1709200 : if (c == EOF) {
232 [ + + ]: 4933 : return ds->length ? 0 : EOF;
233 [ + + ]: 1704267 : } else if (c == '\n') {
234 : 23929 : return 0;
235 : : } else {
236 : 1680338 : ds_put_char(ds, c);
237 : : }
238 : 1680338 : }
239 : : }
240 : :
241 : : /* Reads a line from 'file' into 'ds', clearing anything initially in 'ds'.
242 : : * Deletes comments introduced by "#" and skips lines that contains only white
243 : : * space (after deleting comments).
244 : : *
245 : : * If 'line_numberp' is nonnull, increments '*line_numberp' by the number of
246 : : * lines read from 'file'.
247 : : *
248 : : * Returns 0 if successful, EOF if no non-blank line was found. */
249 : : int
250 : 22320 : ds_get_preprocessed_line(struct ds *ds, FILE *file, int *line_numberp)
251 : : {
252 [ + + ]: 22638 : while (!ds_get_line(ds, file)) {
253 : 22282 : char *line = ds_cstr(ds);
254 : : char *comment;
255 : :
256 [ + + ]: 22282 : if (line_numberp) {
257 : 21834 : ++*line_numberp;
258 : : }
259 : :
260 : : /* Delete comments. */
261 : 22282 : comment = strchr(line, '#');
262 [ + + ]: 22282 : if (comment) {
263 : 31 : *comment = '\0';
264 : : }
265 : :
266 : : /* Return successfully unless the line is all spaces. */
267 [ + + ]: 22282 : if (line[strspn(line, " \t\n")] != '\0') {
268 : 21964 : return 0;
269 : : }
270 : : }
271 : 356 : return EOF;
272 : : }
273 : :
274 : : /* Reads a line from 'file' into 'ds' and does some preprocessing on it:
275 : : *
276 : : * - If the line begins with #, prints it on stdout and reads the next line.
277 : : *
278 : : * - Otherwise, if the line contains an # somewhere else, strips it and
279 : : * everything following it (as a comment).
280 : : *
281 : : * - If (after comment removal) the line contains only white space, prints
282 : : * a blank line on stdout and reads the next line.
283 : : *
284 : : * - Otherwise, returns the line to the caller.
285 : : *
286 : : * This is useful in some of the OVS tests, where we want to check that parsing
287 : : * and then re-formatting some kind of data does not change it, but we also
288 : : * want to be able to put comments in the input.
289 : : *
290 : : * Returns 0 if successful, EOF if no non-blank line was found. */
291 : : int
292 : 1382 : ds_get_test_line(struct ds *ds, FILE *file)
293 : : {
294 : : for (;;) {
295 : : char *s, *comment;
296 : : int retval;
297 : :
298 : 1697 : retval = ds_get_line(ds, file);
299 [ + + ]: 1697 : if (retval) {
300 : 50 : return retval;
301 : : }
302 : :
303 : 1647 : s = ds_cstr(ds);
304 [ + + ]: 1647 : if (*s == '#') {
305 : 127 : puts(s);
306 : 127 : continue;
307 : : }
308 : :
309 : 1520 : comment = strchr(s, '#');
310 [ + + ]: 1520 : if (comment) {
311 : 26 : *comment = '\0';
312 : : }
313 [ + + ]: 1520 : if (s[strspn(s, " \t\n")] == '\0') {
314 : 188 : putchar('\n');
315 : 188 : continue;
316 : : }
317 : :
318 : 1332 : return 0;
319 : 315 : }
320 : : }
321 : :
322 : : char *
323 : 16483051 : ds_cstr(struct ds *ds)
324 : : {
325 [ + + ]: 16483051 : if (!ds->string) {
326 : 9351 : ds_reserve(ds, 0);
327 : : }
328 : 16483051 : ds->string[ds->length] = '\0';
329 : 16483051 : return ds->string;
330 : : }
331 : :
332 : : const char *
333 : 4121 : ds_cstr_ro(const struct ds *ds)
334 : : {
335 : 4121 : return ds_cstr(CONST_CAST(struct ds *, ds));
336 : : }
337 : :
338 : : /* Returns a null-terminated string representing the current contents of 'ds',
339 : : * which the caller is expected to free with free(), then clears the contents
340 : : * of 'ds'. */
341 : : char *
342 : 223186 : ds_steal_cstr(struct ds *ds)
343 : : {
344 : 223186 : char *s = ds_cstr(ds);
345 : 223186 : ds_init(ds);
346 : 223186 : return s;
347 : : }
348 : :
349 : : void
350 : 303693 : ds_destroy(struct ds *ds)
351 : : {
352 : 303693 : free(ds->string);
353 : 303693 : }
354 : :
355 : : /* Swaps the content of 'a' and 'b'. */
356 : : void
357 : 43761 : ds_swap(struct ds *a, struct ds *b)
358 : : {
359 : 43761 : struct ds temp = *a;
360 : 43761 : *a = *b;
361 : 43761 : *b = temp;
362 : 43761 : }
363 : :
364 : : void
365 : 108476 : ds_put_hex(struct ds *ds, const void *buf_, size_t size)
366 : : {
367 : 108476 : const uint8_t *buf = buf_;
368 : 108476 : bool printed = false;
369 : : int i;
370 : :
371 [ + + ]: 12908687 : for (i = 0; i < size; i++) {
372 : 12800211 : uint8_t val = buf[i];
373 [ + + ][ + + ]: 12800211 : if (val || printed) {
374 [ + + ]: 78512 : if (!printed) {
375 : 71817 : ds_put_format(ds, "0x%"PRIx8, val);
376 : : } else {
377 : 6695 : ds_put_format(ds, "%02"PRIx8, val);
378 : : }
379 : 78512 : printed = true;
380 : : }
381 : : }
382 [ + + ]: 108476 : if (!printed) {
383 : 36659 : ds_put_char(ds, '0');
384 : : }
385 : 108476 : }
386 : :
387 : : /* Writes the 'size' bytes in 'buf' to 'string' as hex bytes arranged 16 per
388 : : * line. Numeric offsets are also included, starting at 'ofs' for the first
389 : : * byte in 'buf'. If 'ascii' is true then the corresponding ASCII characters
390 : : * are also rendered alongside. */
391 : : void
392 : 1219 : ds_put_hex_dump(struct ds *ds, const void *buf_, size_t size,
393 : : uintptr_t ofs, bool ascii)
394 : : {
395 : 1219 : const uint8_t *buf = buf_;
396 : 1219 : const size_t per_line = 16; /* Maximum bytes per line. */
397 : :
398 [ + + ]: 5985 : while (size > 0) {
399 : : size_t start, end, n;
400 : : size_t i;
401 : :
402 : : /* Number of bytes on this line. */
403 : 4766 : start = ofs % per_line;
404 : 4766 : end = per_line;
405 [ + + ]: 4766 : if (end - start > size)
406 : 66 : end = start + size;
407 : 4766 : n = end - start;
408 : :
409 : : /* Print line. */
410 : 4766 : ds_put_format(ds, "%08"PRIxMAX" ",
411 : 4766 : (uintmax_t) ROUND_DOWN(ofs, per_line));
412 [ - + ]: 4766 : for (i = 0; i < start; i++) {
413 : 0 : ds_put_format(ds, " ");
414 : : }
415 [ + + ]: 80675 : for (; i < end; i++) {
416 [ + + ]: 75909 : ds_put_format(ds, "%02x%c",
417 : 151818 : buf[i - start], i == per_line / 2 - 1? '-' : ' ');
418 : : }
419 [ + + ]: 4766 : if (ascii) {
420 [ + + ]: 4772 : for (; i < per_line; i++)
421 : 173 : ds_put_format(ds, " ");
422 : 4599 : ds_put_format(ds, "|");
423 [ - + ]: 4599 : for (i = 0; i < start; i++)
424 : 0 : ds_put_format(ds, " ");
425 [ + + ]: 78010 : for (; i < end; i++) {
426 : 73411 : int c = buf[i - start];
427 [ + + ][ + + ]: 73411 : ds_put_char(ds, c >= 32 && c < 127 ? c : '.');
428 : : }
429 [ + + ]: 4772 : for (; i < per_line; i++)
430 : 173 : ds_put_format(ds, " ");
431 : 4599 : ds_put_format(ds, "|");
432 : : } else {
433 : 167 : ds_chomp(ds, ' ');
434 : : }
435 : 4766 : ds_put_format(ds, "\n");
436 : :
437 : 4766 : ofs += n;
438 : 4766 : buf += n;
439 : 4766 : size -= n;
440 : : }
441 : 1219 : }
442 : :
443 : : int
444 : 134042 : ds_last(const struct ds *ds)
445 : : {
446 [ + - ]: 134042 : return ds->length > 0 ? (unsigned char) ds->string[ds->length - 1] : EOF;
447 : : }
448 : :
449 : : bool
450 : 165574 : ds_chomp(struct ds *ds, int c)
451 : : {
452 [ + + ][ + + ]: 165574 : if (ds->length > 0 && ds->string[ds->length - 1] == (char) c) {
453 : 164545 : ds->string[--ds->length] = '\0';
454 : 164545 : return true;
455 : : } else {
456 : 1029 : return false;
457 : : }
458 : : }
459 : :
460 : : void
461 : 0 : ds_clone(struct ds *dst, struct ds *source)
462 : : {
463 : 0 : dst->length = source->length;
464 : 0 : dst->allocated = dst->length;
465 : 0 : dst->string = xmalloc(dst->allocated + 1);
466 : 0 : memcpy(dst->string, source->string, dst->allocated + 1);
467 : 0 : }
|