Code examples

# Reading and decoding bulletins

/*
* input - BUFR and CREX input examples
*
* Copyright (C) 2011 ARPA-SIM <urpsim@smr.arpa.emr.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Enrico Zini <enrico@enricozini.com>
*/
#include <wreport/bulletin.h>
#include "options.h"
using namespace wreport;
// Read all BUFR messages from a file
void read_bufr_raw(const Options& opts, const char* fname, RawHandler& handler)
{
// Open the input file
FILE* in = fopen(fname, "rb");
if (in == NULL)
error_system::throwf("opening file %s", fname);
// Use a generic try/catch block to ensure we always close the input file,
// even in case of errors
try {
// String used to hold raw data read from the input file
std::string raw_data;
// (optional) offset of the start of the BUFR message read, which we
// pass to the decoder to have nicer error messages
off_t offset;
// Read all BUFR data in the input file, one message at a time. Extra
// data before and after each BUFR message is skipped.
// fname and offset are optional and we pass them just to have nicer
// error messages.
while (BufrBulletin::read(in, raw_data, fname, &offset))
handler.handle_raw_bufr(raw_data, fname, offset);
// Cleanup
fclose(in);
} catch (...) {
fclose(in);
throw;
}
}
/*
* Read all CREX messages from a file
*
* Note that the code is basically the same as with reading BUFRs, with only
* two changes:
* - it uses a CrexBulletin instead of a BufrBulletin
* - it uses CrexBulletin::read instead of BufrBulletin::read
*/
void read_crex_raw(const Options& opts, const char* fname, RawHandler& handler)
{
// Open the input file
FILE* in = fopen(fname, "rt");
if (in == NULL)
error_system::throwf("opening file %s", fname);
// Use a generic try/catch block to ensure we always close the input file,
// even in case of errors
try {
// Create a CREX bulletin
unique_ptr<Bulletin> bulletin(CrexBulletin::create());
// String used to hold raw data read from the input file
string raw_data;
// (optional) offset of the start of the CREX message read, which we
// pass to the decoder to have nicer error messages
off_t offset;
// Read all CREX data in the input file, one message at a time. Extra
// data before and after each CREX message is skipped.
// fname and offset are optional and we pass them just to have nicer
// error messages.
while (CrexBulletin::read(in, raw_data, fname, &offset))
handler.handle_raw_crex(raw_data, fname, offset);
// Cleanup
fclose(in);
} catch (...) {
fclose(in);
throw;
}
}
wreport::BufrBulletin::read
static bool read(FILE *in, std::string &buf, const char *fname=0, off_t *offset=0)
Read an encoded BUFR message from a stream.
wreport::CrexBulletin::read
static bool read(FILE *in, std::string &buf, const char *fname=0, off_t *offset=0)
Read an encoded BUFR message from a stream.
wreport::CrexBulletin::create
static std::unique_ptr< CrexBulletin > create()
To prevent breaking ABI if new members are added to bulletins, direct construction is discouraged in ...
wreport::error_system::throwf
static void throwf(const char *fmt,...) WREPORT_THROWF_ATTRS(1
Throw the exception, building the message printf-style.
wreport::bulletin
The bulletin namespace contains bulletin implementation details, internals and utility functions.
Definition input.h:13
wreport
String functions.
Definition benchmark.h:13
options.h
Configuration variables to control configurable aspects of wreport's behaviour.

# Creating bulletins

/*
* makebuoy - Example on how to create a buoy BUFR message
*
* Copyright (C) 2011 ARPA-SIM <urpsim@smr.arpa.emr.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Enrico Zini <enrico@enricozini.com>
*/
#include <wreport/bulletin.h>
#include <cstring>
void do_makebuoy()
{
// Create a blank BUFR bulletin
unique_ptr<BufrBulletin> bulletin(BufrBulletin::create());
// * Fill up metadata
// BUFR edition number
bulletin->edition_number = 4;
// Master table number is 0 by default
// bulletin->master_table_number = 0;
// Data category information
bulletin->data_category = 1;
bulletin->data_subcategory = 21;
bulletin->data_subcategory_local = 255;
// Reference time
bulletin->rep_year = 2011;
bulletin->rep_month = 10;
bulletin->rep_day = 3;
bulletin->rep_hour = 17;
bulletin->rep_minute = 0;
bulletin->rep_second = 0;
// Originating centre information
bulletin->originating_centre = 98; // ECMWF
bulletin->originating_subcentre = 0;
// B table version used by the message
bulletin->master_table_version_number = 14;
bulletin->master_table_version_number_local = 0;
// Compression is still not supported when encoding BUFR
bulletin->compression = false;
// Update sequence number is 0 by default
// bulletin->update_sequence_number = 0;
// Optional section
bulletin->optional_section = "test";
// * Fill up data descriptor section
// There is only one descriptor in this case, but one can push_back as many
// as one likes
bulletin->datadesc.push_back(WR_VAR(3, 8, 3)); // D08003
// * Fill up the data section
// Load encoding tables
bulletin->load_tables();
// Create the first (and only) subset
Subset& s = bulletin->obtain_subset(0);
// Add variables to the subset, as dictated by the data descriptor section
s.store_variable_i(WR_VAR(0, 1, 5), 65602);
s.store_variable_d(WR_VAR(0, 1, 12), 12.0);
s.store_variable_d(WR_VAR(0, 1, 13), 0.2);
s.store_variable_i(WR_VAR(0, 2, 1), 0);
s.store_variable_i(WR_VAR(0, 4, 1), 2011);
s.store_variable_i(WR_VAR(0, 4, 2), 10);
s.store_variable_i(WR_VAR(0, 4, 3), 3);
s.store_variable_i(WR_VAR(0, 4, 4), 17);
s.store_variable_i(WR_VAR(0, 4, 5), 0);
s.store_variable_d(WR_VAR(0, 5, 2), 59.03);
s.store_variable_d(WR_VAR(0, 6, 2), -2.99);
s.store_variable_d(WR_VAR(0, 10, 4), 99520.0);
s.store_variable_d(WR_VAR(0, 10, 51), 99520.0);
s.store_variable_d(WR_VAR(0, 10, 61), 310);
s.store_variable_i(WR_VAR(0, 10, 63), 7);
s.store_variable_undef(WR_VAR(0, 11, 11));
s.store_variable_undef(WR_VAR(0, 11, 12));
s.store_variable_d(WR_VAR(0, 12, 4), 278.5);
s.store_variable_undef(WR_VAR(0, 12, 6));
s.store_variable_undef(WR_VAR(0, 13, 3));
s.store_variable_undef(WR_VAR(0, 20, 1));
s.store_variable_undef(WR_VAR(0, 20, 3));
s.store_variable_undef(WR_VAR(0, 20, 4));
s.store_variable_undef(WR_VAR(0, 20, 5));
s.store_variable_undef(WR_VAR(0, 20, 10));
s.store_variable_undef(WR_VAR(0, 8, 2));
s.store_variable_undef(WR_VAR(0, 20, 11));
s.store_variable_undef(WR_VAR(0, 20, 13));
s.store_variable_undef(WR_VAR(0, 20, 12));
s.store_variable_undef(WR_VAR(0, 20, 12));
s.store_variable_undef(WR_VAR(0, 20, 12));
s.store_variable_d(WR_VAR(0, 22, 42), 280.8);
// Encode the BUFR
string encoded = bulletin->encode();
// Output the BUFR
if (fwrite(encoded.data(), encoded.size(), 1, stdout) != 1)
perror("cannot write BUFR to standard output");
}
wreport::BufrBulletin::create
static std::unique_ptr< BufrBulletin > create()
To prevent breaking ABI if new members are added to bulletins, direct construction is discouraged in ...
wreport::Subset
Represent a BUFR/CREX data subset as a list of decoded variables.
Definition subset.h:13
wreport::Subset::store_variable_i
void store_variable_i(Varcode code, int val)
Store a new variable in the message, providing its value as an int.
wreport::Subset::store_variable_undef
void store_variable_undef(Varcode code)
Store a new, undefined variable in the message.
wreport::Subset::store_variable_d
void store_variable_d(Varcode code, double val)
Store a new variable in the message, providing its value as a double.
WR_VAR
#define WR_VAR(f, x, y)
Create a WMO variable code from its F, X and Y components.
Definition varinfo.h:67

# Printing bulletin contents

/*
* output - output bulletin contents
*
* Copyright (C) 2011 ARPA-SIM <urpsim@smr.arpa.emr.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Enrico Zini <enrico@enricozini.com>
*/
#include <wreport/bulletin.h>
#include <wreport/bulletin/dds-scanfeatures.h>
#include "options.h"
#include <cstring>
struct PrintContents : public BulletinFullHandler
{
FILE* out;
PrintContents(FILE* out=stderr) : out(out) {}
void handle(wreport::Bulletin& b) override
{
b.print(out);
}
};
struct PrintTrace : public BulletinFullHandler
{
FILE* out;
PrintTrace(FILE* out=stderr) : out(out) {}
void handle_raw_bufr(const std::string& raw_data, const char* fname, long offset) override
{
try {
// Decode the raw data. fname and offset are optional and we pass
// them just to have nicer error messages
auto bulletin = wreport::BufrBulletin::decode_verbose(raw_data, out, fname, offset);
// Do something with the decoded information
handle(*bulletin);
} catch (std::exception& e) {
fprintf(stderr, "%s:%ld:%s\n", fname, offset, e.what());
}
}
void handle(wreport::Bulletin& b) override {}
};
struct PrintStructure : public BulletinFullHandler
{
FILE* out;
PrintStructure(FILE* out=stderr) : out(out) {}
void handle(wreport::Bulletin& b) override
{
b.print_structured(out);
}
};
struct PrintDDS : public BulletinHeadHandler
{
FILE* out;
PrintDDS(FILE* out=stderr) : out(out) {}
void handle(wreport::Bulletin& b) override
{
b.print_datadesc(out);
}
};
struct PrintTables : public BulletinHeadHandler
{
FILE* out;
bool header_printed;
PrintTables(FILE* out=stderr) : out(out), header_printed(false) {}
void handle(wreport::Bulletin& b) override
{
if (const BufrBulletin* m = dynamic_cast<const BufrBulletin*>(&b))
{
if (!header_printed)
{
fprintf(out, "%-*s\tOffset\tCentre\tSubc.\tMaster\tLocal\n", (int)b.fname.size(), "Filename");
header_printed = true;
}
fprintf(out, "%s\t%zd\t%d\t%d\t%d\t%d\n",
b.fname.c_str(), b.offset,
m->originating_centre, m->originating_subcentre,
m->master_table_version_number, m->master_table_version_number_local);
}
else if (const CrexBulletin* m = dynamic_cast<const CrexBulletin*>(&b))
{
if (!header_printed)
{
fprintf(out, "Filename\tOffset\tMaster\tEdition\tTable\n");
header_printed = true;
}
fprintf(out, "%s\t%zd\t%d\t%d\t%d\n",
b.fname.c_str(), b.offset,
m->master_table_number, m->edition_number, m->master_table_version_number);
}
else
{
fprintf(out, "%s\t%zd\tunknown message type\n",
b.fname.c_str(), b.offset);
}
}
};
struct PrintFeatures : public BulletinHeadHandler
{
FILE* out;
PrintFeatures(FILE* out=stderr) : out(out) {}
void handle(wreport::Bulletin& b) override
{
bulletin::ScanFeatures scan(b.tables, b.datadesc);
scan.run();
fprintf(out, "%s:%zd:", b.fname.c_str(), b.offset);
bool first = true;
for (const auto& f: scan.features)
if (first)
{
fprintf(out, "%s", f.c_str());
first = false;
} else
fprintf(out, ",%s", f.c_str());
fprintf(out, "\n");
}
};
wreport::BufrBulletin::decode_verbose
static std::unique_ptr< BufrBulletin > decode_verbose(const std::string &raw, FILE *out, const char *fname="(memory)", size_t offset=0)
Parse an encoded BUFR message, printing decoding information.
wreport::Bulletin
Storage for the decoded data of a BUFR or CREX message.
Definition bulletin.h:30
wreport::Bulletin::print_structured
void print_structured(FILE *out) const
Dump the contents of this bulletin, in a more structured way.
wreport::Bulletin::datadesc
std::vector< Varcode > datadesc
Parsed data descriptor section.
Definition bulletin.h:119
wreport::Bulletin::offset
off_t offset
File offset of the start of the message.
Definition bulletin.h:48
wreport::Bulletin::tables
Tables tables
Varcode and opcode tables used for encoding or decoding.
Definition bulletin.h:116
wreport::Bulletin::fname
std::string fname
Input file name (optional).
Definition bulletin.h:39
wreport::Bulletin::print_datadesc
void print_datadesc(FILE *out, unsigned indent=0) const
Pretty-print the data descriptor section.
wreport::Bulletin::print
void print(FILE *out) const
Dump the contents of this bulletin.

# Printing library configuration

/*
* info - print library configuration
*
* Copyright (C) 2011 ARPA-SIM <urpsim@smr.arpa.emr.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Enrico Zini <enrico@enricozini.com>
*/
#include <cstdlib>
// Print information about the library
void do_info()
{
printf("Tables search paths (tried in order):\n");
printf("Extra tables directory: %s (env var WREPORT_EXTRA_TABLES)\n", getenv("WREPORT_EXTRA_TABLES"));
printf("System tables directory: %s (env var WREPORT_TABLES)\n", getenv("WREPORT_TABLES"));
printf("Compiled-in default tables directory: %s\n", TABLE_DIR);
}

# Iterating bulletin contents

/*
* iterate - iterate bulletin contents
*
* Copyright (C) 2011 ARPA-SIM <urpsim@smr.arpa.emr.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author: Enrico Zini <enrico@enricozini.com>
*/
struct PrintVars : public BulletinFullHandler
{
FILE* out;
const std::vector<wreport::Varcode>& codes;
PrintVars(const std::vector<wreport::Varcode>& codes, FILE* out=stdout)
: out(out), codes(codes) {}
const Var* find_varcode(const wreport::Subset& subset, Varcode code)
{
for (size_t i = 0; i < subset.size(); ++i)
if (subset[i].code() == code)
return &subset[i];
return NULL;
}
void handle(wreport::Bulletin& b) override
{
for (size_t sset = 0; sset < b.subsets.size(); ++sset)
{
fprintf(out, "%s:%zd:", b.fname.c_str(), sset + 1);
for (size_t i = 0; i < codes.size(); ++i)
{
const Var* var = find_varcode(b.subsets[sset], codes[i]);
if (var)
{
string formatted = var->format();
fprintf(out, "\t%s", formatted.c_str());
}
}
putc('\n', out);
}
}
};
wreport::Bulletin::subsets
std::vector< Subset > subsets
Decoded variables.
Definition bulletin.h:122
wreport::Var
A physical variable.
Definition var.h:25
wreport::Var::format
std::string format(const char *ifundef="") const
Create a formatted string representation of the variable value.
wreport::Varcode
uint16_t Varcode
Holds the WMO variable code of a variable.
Definition fwd.h:12