Commit c1ef8d5b authored by Per Cederqvist's avatar Per Cederqvist

Introduce datafile format version 3. A textstat contains

"generation" and "reclamation" fields.
* src/include/kom-types.h (Text_stat): Added fields generation
and reclamation.
* src/server/simple-cache.c (cached_get_text): Handle text file
generation 0 in the old-fashioned way.  Added a #warning about
other generations.  Check return value of fseek.
(cached_create_text): Added a #warning about nonzero generations
of the text file.
(cached_create_text): Initialize generation and reclamation.
(save_one_conf): Do a file copy only if the formats of file A and
B are the same.  Otherwise, parse the object into a temporary
object and re-serialize it.
(save_one_pers): Ditto.
(save_one_text): Ditto.
(init_cache): Handle data file format 3.
* src/server/ram-parse.c (fparse_text_stat_3): New static function.
(fparse_text_stat_2): Set generation and reclamation to 0.
(fparse_text_stat_0): Ditto.
(fparse_info): Handle data file format 3.
(fparse_conference): Ditto.
(fparse_person): Ditto.
(fparse_membership): Ditto.
(fparse_membership_list): Ditto.
(fparse_text_stat): Ditto.
(fparse_member): Ditto.
* src/server/ram-output.c (foutput_info): Handle data file format 3.
(foutput_text_stat_3): New static function.
(foutput_person): Ditto.
(foutput_conference): Ditto.
(foutput_text_stat): Ditto.
(foutput_membership): Ditto.
(foutput_membership_list): Ditto.
(foutput_member): Ditto.
(foutput_conf_type): Ditto.
* src/server/ram-io.c (output_format): Initialize it to 3.
(dbfile_open_read): Handle data file format 3.
* src/server/memory.c (copy_text_stat): Handle generation and
reclamation.
(init_text_stat): Initialize generation and reclamation.
* src/server/membership.c (read_ranges_postcondition): Use data
file format 3 when dumping a membership to stderr.
* src/server/dbck.c (main): Handle data file format 3.
* src/server/dbck-cache.c (cached_get_text): Handle text file
generation 0 in the old-fashioned way.  Added a #warning about
other generations.
(cached_flush_text): Flush a generation 0 text file.  Added a
#warning about other generations.
(sync_output_header): Handle data file format 3.
(cache_sync_all): Ditto.
(init_cache): Ditto.
* src/server/testsuite/test-l2g.c (main): Use data
file format 3 when reading an Local2Global structure from stdin,
or writing it to stdout.
parent 554e4c59
2006-11-06 Per Cederqvist <ceder@lysator.liu.se>
Introduce datafile format version 3. A textstat contains
"generation" and "reclamation" fields.
* src/include/kom-types.h (Text_stat): Added fields generation
and reclamation.
* src/server/simple-cache.c (cached_get_text): Handle text file
generation 0 in the old-fashioned way. Added a #warning about
other generations. Check return value of fseek.
(cached_create_text): Added a #warning about nonzero generations
of the text file.
(cached_create_text): Initialize generation and reclamation.
(save_one_conf): Do a file copy only if the formats of file A and
B are the same. Otherwise, parse the object into a temporary
object and re-serialize it.
(save_one_pers): Ditto.
(save_one_text): Ditto.
(init_cache): Handle data file format 3.
* src/server/ram-parse.c (fparse_text_stat_3): New static function.
(fparse_text_stat_2): Set generation and reclamation to 0.
(fparse_text_stat_0): Ditto.
(fparse_info): Handle data file format 3.
(fparse_conference): Ditto.
(fparse_person): Ditto.
(fparse_membership): Ditto.
(fparse_membership_list): Ditto.
(fparse_text_stat): Ditto.
(fparse_member): Ditto.
* src/server/ram-output.c (foutput_info): Handle data file format 3.
(foutput_text_stat_3): New static function.
(foutput_person): Ditto.
(foutput_conference): Ditto.
(foutput_text_stat): Ditto.
(foutput_membership): Ditto.
(foutput_membership_list): Ditto.
(foutput_member): Ditto.
(foutput_conf_type): Ditto.
* src/server/ram-io.c (output_format): Initialize it to 3.
(dbfile_open_read): Handle data file format 3.
* src/server/memory.c (copy_text_stat): Handle generation and
reclamation.
(init_text_stat): Initialize generation and reclamation.
* src/server/membership.c (read_ranges_postcondition): Use data
file format 3 when dumping a membership to stderr.
* src/server/dbck.c (main): Handle data file format 3.
* src/server/dbck-cache.c (cached_get_text): Handle text file
generation 0 in the old-fashioned way. Added a #warning about
other generations.
(cached_flush_text): Flush a generation 0 text file. Added a
#warning about other generations.
(sync_output_header): Handle data file format 3.
(cache_sync_all): Ditto.
(init_cache): Ditto.
* src/server/testsuite/test-l2g.c (main): Use data
file format 3 when reading an Local2Global structure from stdin,
or writing it to stdout.
2006-10-20 Per Cederqvist <ceder@lysator.liu.se>
Wrap all file pointers that refer to the database files inside a
......
......@@ -214,6 +214,8 @@ typedef unsigned long Garb_nice;
/* Struct for text status */
typedef struct {
Time creation_time;
long generation;
long reclamation;
long file_pos; /* Start of the text in the text file. */
Pers_no author;
unsigned short no_of_lines;
......
......@@ -329,7 +329,7 @@ cached_get_text( Text_no text )
if ( text_arr[ text ] == NULL )
return EMPTY_STRING;
else
else if (text_arr[text]->generation == 0)
{
the_string.string = tmp_alloc( text_arr[text]->no_of_chars );
the_string.len = text_arr[text]->no_of_chars;
......@@ -344,6 +344,11 @@ cached_get_text( Text_no text )
return the_string;
}
else
{
#warning Generation > 0 not yet handled
return EMPTY_STRING;
}
}
extern Text_stat * /* NULL on error */
......@@ -418,6 +423,9 @@ cached_flush_text(Text_no text_no,
}
fseek(new_text_file, 0, SEEK_END);
#warning Generation > 0 not yet handled
text_arr[ text_no ]->generation = 0;
text_arr[ text_no ]->reclamation = 0;
text_arr[ text_no ]->file_pos = ftell(new_text_file);
if ( fwrite(message.string, sizeof(char), message.len, new_text_file)
......@@ -538,6 +546,7 @@ sync_output_header(struct dbfile* fp, const char *state)
fprintf(fp->fp, "%s:%05d\n", state, fp->format);
break;
case 2:
case 3:
foutput_header(fp, state, 1);
break;
default:
......@@ -612,6 +621,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
sync_output_header(fp, "DIRTY");
fprintf(fp->fp, "#C %d\n", next_free_num);
fprintf(fp->fp, "#T %ld\n", next_text_num);
......@@ -639,6 +649,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
if (conf_arr[ic] != NULL)
{
fprintf(fp->fp, "C %lu", (unsigned long)ic);
......@@ -673,6 +684,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
if (pers_arr[ic] != NULL )
{
fprintf(fp->fp, "P %lu", (unsigned long)ic);
......@@ -703,6 +715,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
break;
default:
restart_kom("Unknown output file format: %d\n", fp->format);
......@@ -725,6 +738,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
if (text_arr[it] != NULL)
{
fprintf(fp->fp, "T %lu", it);
......@@ -752,6 +766,7 @@ cache_sync_all(void)
break;
case 1:
case 2:
case 3:
break;
default:
restart_kom("Unknown output file format: %d\n", fp->format);
......@@ -900,6 +915,7 @@ init_cache(void)
kom_log("Data file version is '%d'\n", fp->format);
break;
case 2:
case 3:
fparse_set_pos(fp, 33);
if (vflag)
kom_log("Data file version is '%d'\n", fp->format);
......@@ -919,7 +935,8 @@ init_cache(void)
for ( i = 1;
(fp->format == 0 && i < next_free_num && !feof(fp->fp)) ||
(fp->format == 1 && !done) ||
(fp->format == 2 && !done);
(fp->format == 2 && !done) ||
(fp->format == 3 && !done);
i++ )
{
num = i;
......@@ -938,6 +955,7 @@ init_cache(void)
case 1:
case 2:
case 3:
done = 1;
break;
......@@ -955,6 +973,7 @@ init_cache(void)
break;
case 1:
case 2:
case 3:
restart_kom("@ record in data file version %d at %ld.\n",
fp->format, dbfile_ftell(fp));
break;
......@@ -973,6 +992,7 @@ init_cache(void)
break;
case 1:
case 2:
case 3:
if (fparse_info(fp, &kom_info) != OK)
restart_kom("Invalid I record in data file version %d at %ld.\n",
fp->format, dbfile_ftell(fp));
......@@ -1024,6 +1044,7 @@ init_cache(void)
case 1:
case 2:
case 3:
num = fparse_long(fp);
if (conf_arr[num])
free_conference(conf_arr[num]);
......@@ -1051,6 +1072,7 @@ init_cache(void)
case 1:
case 2:
case 3:
num = fparse_long(fp);
if (pers_arr[num])
free_person(pers_arr[num]);
......@@ -1076,6 +1098,7 @@ init_cache(void)
case 1:
case 2:
case 3:
num = fparse_long(fp);
if (text_arr[num])
free_text_stat(text_arr[num]);
......@@ -1114,6 +1137,7 @@ init_cache(void)
break;
case 1:
case 2:
case 3:
restart_kom("+ record in data file version %d at %ld.\n",
fp->format, dbfile_ftell(fp));
break;
......@@ -1133,6 +1157,7 @@ init_cache(void)
case 1:
case 2:
case 3:
switch (c = dbfile_getc(fp))
{
case 'C':
......@@ -1167,6 +1192,7 @@ init_cache(void)
case 1:
case 2:
case 3:
switch(c = dbfile_getc(fp))
{
case 'C':
......
......@@ -76,9 +76,9 @@
#include "kom-errno.h"
#include "manipulate.h"
#include "version-info.h"
#include "unused.h"
#include "ram-io.h"
#include "ram-output.h"
#include "unused.h"
#include "local-to-global.h"
#include "lockdb.h"
#include "linkansi.h"
......@@ -1575,6 +1575,7 @@ main (int argc,
case 0:
case 1:
case 2:
case 3:
break;
default:
restart_kom("%s: unsupported output format %d\n",
......
......@@ -1472,7 +1472,7 @@ read_ranges_postcondition(Membership *m,
{
struct dbfile stderr_wrapper;
stderr_wrapper.fp = stderr;
stderr_wrapper.format = 2;
stderr_wrapper.format = 3;
kom_log("%s(): (%d) Person %lu has a corrupt membership:\n",
func, ++log_no, (unsigned long)ACTPERS);
......
......@@ -608,6 +608,8 @@ copy_text_stat(const Text_stat *t)
c = alloc_text_stat();
c->creation_time = t->creation_time;
c->generation = t->generation;
c->reclamation = t->reclamation;
c->file_pos = t->file_pos;
c->author = t->author;
c->no_of_lines = t->no_of_lines;
......@@ -626,6 +628,8 @@ void
init_text_stat (Text_stat *t)
{
t->creation_time = NO_TIME;
t->generation = 0;
t->reclamation = 0;
t->file_pos = 0;
t->author = 0;
t->no_of_lines = 0;
......
......@@ -40,7 +40,7 @@
#include "log.h"
/* The native output format is defined here. */
static int output_format = 2;
static int output_format = 3;
static long nr_dbfile_objects = 0;
static long nr_dbfile_files = 0;
......@@ -125,6 +125,7 @@ dbfile_open_read(const char *filename)
case 0:
case 1:
case 2:
case 3:
break;
default:
restart_kom("unknown input format selected: %d\n", res->format);
......
......@@ -115,6 +115,7 @@ void foutput_info(struct dbfile *fp, Info *info)
foutput_info_0(fp, info);
break;
case 2:
case 3:
foutput_info_2(fp, info);
break;
default:
......@@ -192,6 +193,7 @@ foutput_person (struct dbfile *fp,
foutput_person_0(fp, person);
break;
case 2:
case 3:
foutput_person_2(fp, person);
break;
default:
......@@ -284,6 +286,7 @@ void foutput_conference(struct dbfile *fp,
foutput_conference_1(fp, conf_c);
break;
case 2:
case 3:
foutput_conference_2(fp, conf_c);
break;
default:
......@@ -349,6 +352,37 @@ foutput_text_stat_2(struct dbfile *fp,
foutput_aux_item_list(fp, &t_stat->aux_item_list);
}
static void
foutput_text_stat_3(struct dbfile *fp,
Text_stat *t_stat)
{
int i;
foutput_time(fp, t_stat->creation_time);
foutput_ulong((unsigned long) t_stat->author, fp);
foutput_ulong((unsigned long) t_stat->generation, fp);
foutput_ulong((unsigned long) t_stat->reclamation, fp);
foutput_ulong((unsigned long) t_stat->file_pos, fp);
foutput_ulong((unsigned long) t_stat->no_of_lines, fp);
foutput_ulong((unsigned long) t_stat->no_of_chars, fp);
foutput_ulong((unsigned long) t_stat->no_of_marks, fp);
foutput_ulong((unsigned long) t_stat->no_of_misc, fp);
if ( t_stat->misc_items != NULL && t_stat->no_of_misc > 0 )
{
foutput_array_start(fp);
for ( i = 0; i < t_stat->no_of_misc; i++ )
foutput_misc_info(fp, t_stat->misc_items[ i ]);
foutput_array_end(fp);
}
else
foutput_array_nodata(fp);
foutput_ulong((unsigned long) t_stat->highest_aux, fp);
foutput_aux_item_list(fp, &t_stat->aux_item_list);
}
void
foutput_text_stat(struct dbfile *fp,
Text_stat *t_stat)
......@@ -362,6 +396,9 @@ foutput_text_stat(struct dbfile *fp,
case 2:
foutput_text_stat_2(fp, t_stat);
break;
case 3:
foutput_text_stat_3(fp, t_stat);
break;
default:
restart_kom("unknown database format: %d\n", fp->format);
break;
......@@ -545,6 +582,7 @@ foutput_membership(struct dbfile *fp,
foutput_membership_0(fp, mship);
break;
case 2:
case 3:
foutput_membership_2(fp, mship);
break;
default:
......@@ -710,6 +748,7 @@ foutput_membership_list(struct dbfile * fp,
foutput_membership_list_0(fp, mlist);
break;
case 2:
case 3:
foutput_membership_list_2(fp, mlist);
break;
default:
......@@ -774,6 +813,7 @@ foutput_member(struct dbfile *fp,
foutput_member_0(fp, member);
break;
case 2:
case 3:
foutput_member_2(fp, member);
break;
default:
......@@ -819,6 +859,7 @@ foutput_conf_type (struct dbfile *fp,
break;
case 1:
case 2:
case 3:
foutput_conf_type_1(fp, type);
break;
default:
......
......@@ -149,6 +149,7 @@ fparse_info(struct dbfile *fp, Info *info)
return fparse_info_0(fp, info);
break;
case 2:
case 3:
return fparse_info_2(fp, info);
break;
default:
......@@ -279,6 +280,7 @@ fparse_conference(struct dbfile *fp,
return fparse_conference_0(fp, result);
break;
case 2:
case 3:
return fparse_conference_2(fp, result);
break;
default:
......@@ -417,6 +419,7 @@ fparse_person(struct dbfile *fp,
return fparse_person_0(fp, result);
break;
case 2:
case 3:
return fparse_person_2(fp, result);
break;
default:
......@@ -590,6 +593,7 @@ fparse_membership(struct dbfile *fp,
return fparse_membership_0(fp, mship);
break;
case 2:
case 3:
return fparse_membership_2(fp, mship);
break;
default:
......@@ -795,6 +799,7 @@ fparse_membership_list(struct dbfile *fp,
return fparse_membership_list_0(fp, result);
break;
case 2:
case 3:
return fparse_membership_list_2(fp, result);
break;
default:
......@@ -1026,6 +1031,124 @@ fparse_mark_list(struct dbfile *fp,
return OK;
}
static Success
fparse_text_stat_3(struct dbfile *fp,
Text_stat *result)
{
int i;
int c;
if ( fparse_long_errors != 0 )
{
kom_log("fparse_text_stat(): fparse_long_errors == %d on entry. Reset.\n",
fparse_long_errors);
fparse_long_errors = 0;
}
result->creation_time = fparse_time(fp);
result->author = fparse_long(fp);
result->generation = fparse_long(fp);
result->reclamation = fparse_long(fp);
result->file_pos = fparse_long(fp);
result->no_of_lines = fparse_long(fp);
result->no_of_chars = fparse_long(fp);
result->no_of_marks = fparse_long(fp);
result->no_of_misc = fparse_long(fp);
if ( fparse_long_errors != 0 )
{
kom_log("%s(): %d fparse_long_errors before 'misc_items' (3). Reset.\n",
"fparse_text_stat",
fparse_long_errors);
fparse_long_errors = 0;
return FAILURE;
}
if ( result->no_of_misc > 0 )
{
fskipwhite(fp);
switch( c = dbfile_getc(fp) )
{
case '{':
result->misc_items = REALLOC(result->misc_items,
(result->no_of_misc
* sizeof(Misc_info)));
if ( result->misc_items == NULL )
{
err_stat = 0;
kom_errno = KOM_OUT_OF_MEMORY;
return FAILURE;
}
for ( i = 0; i < result->no_of_misc; i++)
if ( fparse_misc_info(fp, &result->misc_items[ i ]) != OK )
return FAILURE;
fskipwhite(fp);
if ( (c = dbfile_getc(fp)) != '}' )
{
kom_log("fparse_text_stat(): expected '}' at pos %ld.\n",
dbfile_ftell(fp));
err_stat = 16;
kom_errno = KOM_LDB_ERR;
return FAILURE;
}
break;
case '@':
case '+':
dbfile_ungetc(fp, c);
kom_log("fparse_text_stat(): got '%c'; expected '{' or '*'\n.", c);
kom_log("Character ungetc'd and interpreted as a '*' at %ld.\n",
dbfile_ftell(fp));
/* Fall through */
case '*':
if ( result->misc_items != NULL )
{
sfree(result->misc_items);
result->misc_items = NULL;
}
break;
default:
kom_log("fparse_text_stat(): expected '*' or '}' at pos %ld.\n",
dbfile_ftell(fp));
err_stat = 17;
kom_errno = KOM_LDB_ERR;
return FAILURE;
}
}
else
{
fskipwhite(fp);
if ( (c = dbfile_getc(fp)) != '*' )
{
kom_log("fparse_text_stat(): expected '*' at pos %ld.\n",
dbfile_ftell(fp));
err_stat = 18;
kom_errno = KOM_LDB_ERR;
return FAILURE;
}
if ( result->misc_items != NULL )
{
sfree(result->misc_items);
result->misc_items = NULL;
}
}
result->highest_aux = fparse_long(fp);
if (fparse_aux_item_list(fp, &result->aux_item_list) != OK)
return FAILURE;
fskipwhite(fp);
return OK;
}
static Success
fparse_text_stat_2(struct dbfile *fp,
Text_stat *result)
......@@ -1043,6 +1166,8 @@ fparse_text_stat_2(struct dbfile *fp,
result->creation_time = fparse_time(fp);
result->author = fparse_long(fp);
result->generation = 0;
result->reclamation = 0;
result->file_pos = fparse_long(fp);
result->no_of_lines = fparse_long(fp);
result->no_of_chars = fparse_long(fp);
......@@ -1159,6 +1284,8 @@ fparse_text_stat_0(struct dbfile *fp,
result->creation_time = fparse_time(fp);
result->author = fparse_long(fp);
result->generation = 0;
result->reclamation = 0;
result->file_pos = fparse_long(fp);
result->no_of_lines = fparse_long(fp);
result->no_of_chars = fparse_long(fp);
......@@ -1270,6 +1397,9 @@ fparse_text_stat(struct dbfile *fp,
case 2:
return fparse_text_stat_2(fp, result);
break;
case 3:
return fparse_text_stat_3(fp, result);
break;
default:
restart_kom("unknown input format: %d\n", fp->format);
return FAILURE;
......@@ -1487,6 +1617,7 @@ fparse_member(struct dbfile *fp,
return fparse_member_0(fp, result);
break;
case 2:
case 3:
return fparse_member_2(fp, result);
break;
default:
......
......@@ -1052,12 +1052,17 @@ cached_get_text( Text_no text )
if ( (t_stat = cached_get_text_stat (text)) == NULL )
return EMPTY_STRING;
else
else if (t_stat->generation == 0)
{
LOGACC(lt_text_mass, text);
the_string.string = tmp_alloc( t_stat->no_of_chars );
the_string.len = t_stat->no_of_chars;
fseek(text_file, t_stat->file_pos, SEEK_SET);
if (fseek(text_file, t_stat->file_pos, SEEK_SET) != 0)
{
kom_log("Failed to seek to %ld in text mass file: %s.\n",
t_stat->file_pos, strerror(errno));
return EMPTY_STRING;
}
if ( fread(the_string.string, sizeof(char), the_string.len, text_file)
!= (size_t)the_string.len )
......@@ -1069,6 +1074,11 @@ cached_get_text( Text_no text )
return the_string;
}
else
{
#warning Generation > 0 not yet handled
restart_kom("Only generation 0 is handled.\n");
}
}
......@@ -1140,6 +1150,7 @@ cached_create_text(const String message)
tno = next_text_num++;
#warning Generation > 0 not yet handled
TRACE2("cached_create_text (len=%lu)\n", message.len);
if ( tno >= param.max_text )
......@@ -1216,6 +1227,8 @@ cached_create_text(const String message)
((Text_stat *)node->ptr)->no_of_marks = 0;
((Text_stat *)node->ptr)->no_of_lines = 0;
((Text_stat *)node->ptr)->no_of_chars = 0;
((Text_stat *)node->ptr)->generation = 0;
((Text_stat *)node->ptr)->reclamation = 0;
((Text_stat *)node->ptr)->file_pos = file_pos;
text_set_mru( tno );
......@@ -2112,10 +2125,21 @@ save_one_conf(void)
{
write_conf(file_b, cn->ptr, sync_next);
}
else
else if ( file_a->format == file_b->format )
{
copy_file(file_a, file_b, cn->pos, cn->size - 1, sync_next);
}
else
{
Conference *tmp = read_conference(file_a, cn->pos, cn->size);
if (tmp == NULL)
{
restart_kom("Failed to read old conference at %ld.\n",
cn->pos);
}
write_conf(file_b, tmp, sync_next);
free_conference(tmp);
}
foutput_newline(file_b);
#ifdef FASTSAVE
......@@ -2180,10 +2204,21 @@ save_one_pers(void)
{
write_pers(file_b, cn->ptr, sync_next);
}
else
else if ( file_a->format == file_b->format )
{
copy_file(file_a, file_b, cn->pos, cn->size - 1, sync_next);
}
else
{
Person *tmp = read_person(file_a, cn->pos, cn->size);
if (tmp == NULL)
{
restart_kom("Failed to read old person at %ld.\n",
cn->pos);
}
write_pers(file_b, tmp, sync_next);
free_person(tmp);
}
foutput_newline(file_b);
cn->size_b = dbfile_ftell(file_b) - cn->pos_b;
......@@ -2312,10 +2347,21 @@ save_one_text(void)
{
write_text(file_b, cn->ptr, sync_next);
}
else
else if ( file_a->format == file_b->format )
{
copy_file(file_a, file_b, cn->pos, cn->size - 1, sync_next);
}
else
{
Text_stat *tmp = read_text_stat(file_a, cn->pos, cn->size);
if (tmp == NULL)
{
restart_kom("Failed to read old text_stat at %ld.\n",
cn->pos);
}
write_text(file_b, tmp, sync_next);
free_text_stat(tmp);
}
foutput_newline(file_b);
#ifdef FASTSAVE
......@@ -2682,9 +2728,10 @@ init_cache(void)
{
case 0:
case 1:
restart_kom("You need to run dbck to convert your datafile to version 2.\n");
restart_kom("You need to run dbck to convert your datafile to version 2 or 3.\n");
break;
case 2:
case 3:
/*
* Read timestamp
*/
......
......@@ -277,7 +277,7 @@ main(void)
int c;
struct dbfile stdin_wrapper;
stdin_wrapper.fp = stdin;
stdin_wrapper.format = 2;
stdin_wrapper.format = 3;
l2g_read(&stdin_wrapper, &maps[num[0]]);
if ((c = getchar()) != '\n')
{
......@@ -299,7 +299,7 @@ main(void)
{
struct dbfile stdout_wrapper;
stdout_wrapper.fp = stdout;
stdout_wrapper.format = 2;