Implement new DBM dump format.
The new format, called "C", allows programmers to create input data for use by mu load using conventional means. It represents both key and content as C strings (hence its name), with usual C (literal and octal) escapes to represent non-printable characters. * mu/dbm.c (IOBUF_REREAD,IOBUF_EOF): New constants. (iobuf) <state>: New member. (input_eof): New macro. (input_getline): Use iobuf.state to detect EOF. (input_ungetline): Reset state only if it is 0. (format_tab): New format "C". (write_quoted_string,C_writer,C_read_datum) (C_reader): New functions to implement the C dump format. * libmailutils/tests/testsuite.at: Minor change.
Showing
2 changed files
with
189 additions
and
16 deletions
... | @@ -76,6 +76,8 @@ m4_include([fromflt.at]) | ... | @@ -76,6 +76,8 @@ m4_include([fromflt.at]) |
76 | m4_include([inline-comment.at]) | 76 | m4_include([inline-comment.at]) |
77 | m4_include([hdrflt.at]) | 77 | m4_include([hdrflt.at]) |
78 | m4_include([linecon.at]) | 78 | m4_include([linecon.at]) |
79 | |||
80 | AT_BANNER(Debug Specification) | ||
79 | m4_include([debugspec.at]) | 81 | m4_include([debugspec.at]) |
80 | 82 | ||
81 | m4_include([fsaf.at]) | 83 | m4_include([fsaf.at]) |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -209,13 +209,16 @@ set_db_ownership (mu_dbm_file_t db) | ... | @@ -209,13 +209,16 @@ set_db_ownership (mu_dbm_file_t db) |
209 | } | 209 | } |
210 | 210 | ||
211 | 211 | ||
212 | #define IOBUF_REREAD 1 | ||
213 | #define IOBUF_EOF 2 | ||
214 | |||
212 | struct iobuf | 215 | struct iobuf |
213 | { | 216 | { |
214 | mu_stream_t stream; | 217 | mu_stream_t stream; |
215 | char *buffer; | 218 | char *buffer; |
216 | size_t bufsize; | 219 | size_t bufsize; |
217 | size_t length; | 220 | size_t length; |
218 | int read; | 221 | int flag; /* 0 or one of the IOBUF_ constants above. */ |
219 | }; | 222 | }; |
220 | 223 | ||
221 | static int is_dbm_directive (struct iobuf *input); | 224 | static int is_dbm_directive (struct iobuf *input); |
... | @@ -224,15 +227,25 @@ static int is_ignored_directive (const char *name); | ... | @@ -224,15 +227,25 @@ static int is_ignored_directive (const char *name); |
224 | static int set_directive (char *val); | 227 | static int set_directive (char *val); |
225 | static void print_header (const char *name, mu_stream_t str); | 228 | static void print_header (const char *name, mu_stream_t str); |
226 | 229 | ||
230 | #define input_eof(iob) ((iob)->flag == IOBUF_EOF) | ||
231 | |||
227 | static int | 232 | static int |
228 | input_getline (struct iobuf *inp) | 233 | input_getline (struct iobuf *inp) |
229 | { | 234 | { |
230 | int rc; | 235 | int rc; |
231 | size_t len; | 236 | size_t len; |
232 | 237 | ||
233 | if (inp->read) | 238 | switch (inp->flag) |
234 | { | 239 | { |
235 | inp->read = 0; | 240 | case 0: |
241 | break; | ||
242 | |||
243 | case IOBUF_REREAD: | ||
244 | inp->flag = 0; | ||
245 | return 0; | ||
246 | |||
247 | case IOBUF_EOF: | ||
248 | inp->length = 0; | ||
236 | return 0; | 249 | return 0; |
237 | } | 250 | } |
238 | 251 | ||
... | @@ -243,6 +256,7 @@ input_getline (struct iobuf *inp) | ... | @@ -243,6 +256,7 @@ input_getline (struct iobuf *inp) |
243 | return rc; | 256 | return rc; |
244 | if (len == 0) | 257 | if (len == 0) |
245 | { | 258 | { |
259 | inp->flag = IOBUF_EOF; | ||
246 | inp->length = 0; | 260 | inp->length = 0; |
247 | break; | 261 | break; |
248 | } | 262 | } |
... | @@ -270,7 +284,8 @@ input_getline (struct iobuf *inp) | ... | @@ -270,7 +284,8 @@ input_getline (struct iobuf *inp) |
270 | static void | 284 | static void |
271 | input_ungetline (struct iobuf *inp) | 285 | input_ungetline (struct iobuf *inp) |
272 | { | 286 | { |
273 | inp->read = 1; | 287 | if (inp->flag == 0) |
288 | inp->flag = IOBUF_REREAD; | ||
274 | } | 289 | } |
275 | 290 | ||
276 | static size_t | 291 | static size_t |
... | @@ -298,6 +313,13 @@ static int ascii_writer (struct iobuf *, void *data, | ... | @@ -298,6 +313,13 @@ static int ascii_writer (struct iobuf *, void *data, |
298 | struct mu_dbm_datum const *key, | 313 | struct mu_dbm_datum const *key, |
299 | struct mu_dbm_datum const *content); | 314 | struct mu_dbm_datum const *content); |
300 | 315 | ||
316 | static int C_reader (struct iobuf *, void *data, | ||
317 | struct mu_dbm_datum *key, | ||
318 | struct mu_dbm_datum *content); | ||
319 | static int C_writer (struct iobuf *, void *data, | ||
320 | struct mu_dbm_datum const *key, | ||
321 | struct mu_dbm_datum const *content); | ||
322 | |||
301 | static void newfmt_init (struct xfer_format *fmt, | 323 | static void newfmt_init (struct xfer_format *fmt, |
302 | const char *version, struct iobuf *iop, int wr); | 324 | const char *version, struct iobuf *iop, int wr); |
303 | 325 | ||
... | @@ -309,14 +331,15 @@ static int newfmt_writer (struct iobuf *, void *data, | ... | @@ -309,14 +331,15 @@ static int newfmt_writer (struct iobuf *, void *data, |
309 | struct mu_dbm_datum const *content); | 331 | struct mu_dbm_datum const *content); |
310 | 332 | ||
311 | static struct xfer_format format_tab[] = { | 333 | static struct xfer_format format_tab[] = { |
334 | { "C", NULL, C_reader, C_writer, NULL }, | ||
312 | { "0.0", NULL, ascii_reader, ascii_writer, NULL }, | 335 | { "0.0", NULL, ascii_reader, ascii_writer, NULL }, |
313 | { "1.0", newfmt_init, newfmt_reader, newfmt_writer, NULL }, | 336 | { "1.0", newfmt_init, newfmt_reader, newfmt_writer, NULL }, |
314 | { NULL } | 337 | { NULL } |
315 | }; | 338 | }; |
316 | 339 | ||
317 | #define DEFAULT_LIST_FORMAT (&format_tab[0]) | 340 | #define DEFAULT_LIST_FORMAT (&format_tab[1]) |
318 | #define DEFAULT_DUMP_FORMAT (&format_tab[1]) | 341 | #define DEFAULT_DUMP_FORMAT (&format_tab[2]) |
319 | #define DEFAULT_LOAD_FORMAT (&format_tab[0]) | 342 | #define DEFAULT_LOAD_FORMAT (&format_tab[1]) |
320 | 343 | ||
321 | static struct xfer_format *format; | 344 | static struct xfer_format *format; |
322 | static const char *dump_format_version; | 345 | static const char *dump_format_version; |
... | @@ -405,8 +428,13 @@ ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED, | ... | @@ -405,8 +428,13 @@ ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED, |
405 | mu_error ("%s", mu_strerror (rc)); | 428 | mu_error ("%s", mu_strerror (rc)); |
406 | return -1; | 429 | return -1; |
407 | } | 430 | } |
408 | if (input_length (inp) == 0) | 431 | if (input_eof (inp)) |
409 | return 1; | 432 | return 1; |
433 | if (input_length (inp) == 0) | ||
434 | { | ||
435 | key->mu_dsize = 0; | ||
436 | return 0; | ||
437 | } | ||
410 | kstr = mu_str_stripws (inp->buffer); | 438 | kstr = mu_str_stripws (inp->buffer); |
411 | val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE); | 439 | val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE); |
412 | *val++ = 0; | 440 | *val++ = 0; |
... | @@ -424,6 +452,150 @@ ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED, | ... | @@ -424,6 +452,150 @@ ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED, |
424 | return 0; | 452 | return 0; |
425 | } | 453 | } |
426 | 454 | ||
455 | void | ||
456 | write_quoted_string (mu_stream_t stream, char *str, size_t len) | ||
457 | { | ||
458 | for (; len; str++, len--) | ||
459 | { | ||
460 | if (*str == '"') | ||
461 | { | ||
462 | mu_stream_write (stream, "\\", 1, NULL); | ||
463 | mu_stream_write (stream, str, 1, NULL); | ||
464 | } | ||
465 | else if (*str != '\t' && *str != '\\' && mu_isprint (*str)) | ||
466 | mu_stream_write (stream, str, 1, NULL); | ||
467 | else | ||
468 | { | ||
469 | int c = mu_wordsplit_c_quote_char (*str); | ||
470 | |||
471 | mu_stream_write (stream, "\\", 1, NULL); | ||
472 | if (c != -1) | ||
473 | mu_stream_write (stream, str, 1, NULL); | ||
474 | else | ||
475 | mu_stream_printf (stream, "%03o", *(unsigned char *) str); | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | static int | ||
481 | C_writer (struct iobuf *iop, void *data MU_ARG_UNUSED, | ||
482 | struct mu_dbm_datum const *key, | ||
483 | struct mu_dbm_datum const *content) | ||
484 | { | ||
485 | write_quoted_string (iop->stream, key->mu_dptr, key->mu_dsize); | ||
486 | mu_stream_write (iop->stream, "\n", 1, NULL); | ||
487 | write_quoted_string (iop->stream, content->mu_dptr, content->mu_dsize); | ||
488 | mu_stream_write (iop->stream, "\n\n", 2, NULL); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | #define ISODIGIT(c) ((c) >= '0' && c < '8') | ||
493 | #define OCTVAL(c) ((c) - '0') | ||
494 | |||
495 | static int | ||
496 | C_read_datum (struct iobuf *inp, struct mu_dbm_datum *datum) | ||
497 | { | ||
498 | size_t i = 0; | ||
499 | char *base, *ptr; | ||
500 | size_t length; | ||
501 | int rc; | ||
502 | |||
503 | free (datum->mu_dptr); | ||
504 | memset (datum, 0, sizeof (*datum)); | ||
505 | |||
506 | rc = input_getline (inp); | ||
507 | if (rc) | ||
508 | { | ||
509 | mu_error ("%s", mu_strerror (rc)); | ||
510 | return -1; | ||
511 | } | ||
512 | if (input_eof (inp)) | ||
513 | return 1; | ||
514 | if ((length = input_length (inp)) == 0) | ||
515 | { | ||
516 | mu_error (_("empty line")); | ||
517 | return -1; | ||
518 | } | ||
519 | |||
520 | memset (datum, 0, sizeof (*datum)); | ||
521 | datum->mu_dptr = ptr = xmalloc (length); | ||
522 | base = inp->buffer; | ||
523 | for (i = 0; i < length; ptr++) | ||
524 | { | ||
525 | if (base[i] == '\\') | ||
526 | { | ||
527 | if (++i >= length) | ||
528 | { | ||
529 | mu_error (_("unfinished string")); | ||
530 | return -1; | ||
531 | } | ||
532 | else if (ISODIGIT (base[i])) | ||
533 | { | ||
534 | unsigned c; | ||
535 | |||
536 | if (i + 3 > length) | ||
537 | { | ||
538 | mu_error (_("unfinished string")); | ||
539 | return -1; | ||
540 | } | ||
541 | c = OCTVAL (base[i]); | ||
542 | c <<= 3; | ||
543 | c |= OCTVAL (base[i + 1]); | ||
544 | c <<= 3; | ||
545 | c |= OCTVAL (base[i + 2]); | ||
546 | *ptr = c; | ||
547 | i += 3; | ||
548 | } | ||
549 | else | ||
550 | { | ||
551 | int c = mu_wordsplit_c_unquote_char (base[i]); | ||
552 | if (c == -1) | ||
553 | { | ||
554 | mu_error (_("invalid escape sequence (\\%c)"), base[i]); | ||
555 | return -1; | ||
556 | } | ||
557 | *ptr = c; | ||
558 | } | ||
559 | } | ||
560 | else | ||
561 | *ptr = base[i++]; | ||
562 | } | ||
563 | datum->mu_dsize = ptr - datum->mu_dptr; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int | ||
568 | C_reader (struct iobuf *inp, void *data MU_ARG_UNUSED, | ||
569 | struct mu_dbm_datum *key, | ||
570 | struct mu_dbm_datum *content) | ||
571 | { | ||
572 | int rc; | ||
573 | |||
574 | rc = C_read_datum (inp, key); | ||
575 | if (rc < 0) | ||
576 | exit (EX_DATAERR); | ||
577 | else if (rc == 1) | ||
578 | return 1; | ||
579 | |||
580 | if (C_read_datum (inp, content)) | ||
581 | exit (EX_DATAERR); | ||
582 | |||
583 | rc = input_getline (inp); | ||
584 | if (rc) | ||
585 | { | ||
586 | mu_error ("%s", mu_strerror (rc)); | ||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | if (input_length (inp) != 0) | ||
591 | { | ||
592 | mu_error (_("unrecognized line")); | ||
593 | return -1; | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
427 | static void | 599 | static void |
428 | newfmt_init (struct xfer_format *fmt, const char *version, | 600 | newfmt_init (struct xfer_format *fmt, const char *version, |
429 | struct iobuf *iop, int wr) | 601 | struct iobuf *iop, int wr) |
... | @@ -465,15 +637,16 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, | ... | @@ -465,15 +637,16 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, |
465 | unsigned char *ptr, *out; | 637 | unsigned char *ptr, *out; |
466 | size_t len; | 638 | size_t len; |
467 | 639 | ||
468 | mu_dbm_datum_free (datum); | 640 | free (datum->mu_dptr); |
469 | 641 | memset (datum, 0, sizeof (*datum)); | |
642 | |||
470 | rc = input_getline (iop); | 643 | rc = input_getline (iop); |
471 | if (rc) | 644 | if (rc) |
472 | { | 645 | { |
473 | mu_error ("%s", mu_strerror (rc)); | 646 | mu_error ("%s", mu_strerror (rc)); |
474 | exit (EX_IOERR); | 647 | exit (EX_IOERR); |
475 | } | 648 | } |
476 | if (iop->length == 0) | 649 | if (input_eof (iop)) |
477 | return 1; | 650 | return 1; |
478 | 651 | ||
479 | if (!is_len_directive (iop)) | 652 | if (!is_len_directive (iop)) |
... | @@ -505,7 +678,7 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, | ... | @@ -505,7 +678,7 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, |
505 | mu_error ("%s", mu_strerror (rc)); | 678 | mu_error ("%s", mu_strerror (rc)); |
506 | exit (EX_IOERR); | 679 | exit (EX_IOERR); |
507 | } | 680 | } |
508 | if (iop->length == 0) | 681 | if (input_eof (iop)) |
509 | break; | 682 | break; |
510 | if (is_len_directive (iop)) | 683 | if (is_len_directive (iop)) |
511 | { | 684 | { |
... | @@ -524,8 +697,6 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, | ... | @@ -524,8 +697,6 @@ newfmt_read_datum (struct iobuf *iop, mu_opool_t pool, |
524 | exit (EX_SOFTWARE); | 697 | exit (EX_SOFTWARE); |
525 | } | 698 | } |
526 | 699 | ||
527 | mu_dbm_datum_free (datum); | ||
528 | |||
529 | datum->mu_dptr = (void*) out; | 700 | datum->mu_dptr = (void*) out; |
530 | return 0; | 701 | return 0; |
531 | } | 702 | } |
... | @@ -559,7 +730,7 @@ newfmt_write_datum (struct iobuf *iop, struct mu_dbm_datum const *datum) | ... | @@ -559,7 +730,7 @@ newfmt_write_datum (struct iobuf *iop, struct mu_dbm_datum const *datum) |
559 | exit (EX_SOFTWARE); | 730 | exit (EX_SOFTWARE); |
560 | } | 731 | } |
561 | mu_stream_write (iop->stream, iop->buffer, iop->bufsize, NULL); | 732 | mu_stream_write (iop->stream, iop->buffer, iop->bufsize, NULL); |
562 | free (iop->buffer); // FIXME | 733 | free (iop->buffer); /* FIXME */ |
563 | mu_stream_write (iop->stream, "\n", 1, NULL); | 734 | mu_stream_write (iop->stream, "\n", 1, NULL); |
564 | } | 735 | } |
565 | 736 | ||
... | @@ -1220,7 +1391,7 @@ add_records (int mode, int replace) | ... | @@ -1220,7 +1391,7 @@ add_records (int mode, int replace) |
1220 | input.buffer = NULL; | 1391 | input.buffer = NULL; |
1221 | input.bufsize = 0; | 1392 | input.bufsize = 0; |
1222 | input.length = 0; | 1393 | input.length = 0; |
1223 | input.read = 0; | 1394 | input.flag = 0; |
1224 | input.stream = instream; | 1395 | input.stream = instream; |
1225 | 1396 | ||
1226 | /* Read directive header */ | 1397 | /* Read directive header */ | ... | ... |
-
Please register or sign in to post a comment