Dealing with errors

There are a number of ways to deal with errors when using the decoder functions.

Many of the functions return a status. For example, pps_decoder_get_string() returns PPS_DECODER_OK if it succeeds, and another value otherwise. While you can take the traditional approach by checking the return value of each function and then taking the appropriate action, this isn't the preferred method because it tends to be verbose and no more effective than the alternatives.

One way of handling errors is the "all or nothing" approach. In some cases, a PPS message (or JSON string), is expected to contain a particular set of attributes; if any are missing, it's considered an error. In this case, you can attempt to extract all the attributes expected and just check the final status of the pps_decoder_t structure. For example, if you need a message to contain the three attributes name, size, and serial_no, you could do this:

pps_decoder_get_string(decoder, "name", &name);
pps_decoder_get_int(decoder, "size", &size);
pps_decoder_get_string(decoder, "serial_no", &serial_no);
      
if ( pps_decoder_status(decoder, true) != PPS_DECODER_OK ) {
   printf("Bad message\n");
   . . .
}       

In this case, rather than individually check whether each attribute was fetched successfully, we just check at the end that everything was OK.

The above method of error handling works fine in many cases, but sometimes there's no fixed set of attributes that must always be included. So another way of handling errors is to pre-initialize all variables, extract values from the PPS data, and just use the results. If an attribute was missing or of the wrong type, the corresponding variable is left with the value it was initialized with. For example:

char *name = NULL;
int size = -1;
char *serial_no = NULL;
      
pps_decoder_get_string(decoder, "name", &name);
pps_decoder_get_int(decoder, "size", &size);
pps_decoder_get_string(decoder, "serial_no", &serial_no);
      
if ( name != NULL ) {
. . .
}   

You can, of course, use some hybrid of the two approaches. For example, you might fetch all mandatory attributes first, checking that the final status is OK, and then fetch all optional attributes, relying on having initialized your variables with appropriate default values.