Commit 1b475f7e 1b475f7ea7e8b2d6168622f9bc2dd95950179237 by Sergey Poznyakoff

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.
1 parent c6ed0dba
...@@ -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 */
......