Skip to content

Instantly share code, notes, and snippets.

@gitaaron
Created April 6, 2018 13:02
Show Gist options
  • Save gitaaron/4349183c3ec6d223a0073b87b9c2da8b to your computer and use it in GitHub Desktop.
Save gitaaron/4349183c3ec6d223a0073b87b9c2da8b to your computer and use it in GitHub Desktop.
//XC1CPLLE JOB NOTIFY=&SYSUID,
// REGION=0M,MSGLEVEL=1,MSGCLASS=H
//*
//* Location of sample source and output datasets.
// SET SRC=HWTJXC1 < INPUT ... REQUIRED
// SET SAMPLIB=SYS1.SAMPLIB < INPUT ... REQUIRED
// SET LOADLIB=HWTJ.SAMPLE.LOAD < OUTPUT LOAD MODULE
// SET CSSLIB=SYS1.CSSLIB < CSSLIB DATA SET
//* C\C++ Compiler Options
// SET CRUN= < COMPILER RUNTIME OPTIONS
// SET CPARM='CXX' < COMPILER OPTIONS
//* Pre-linker and Linker options.
// SET PLANG='EDCPMSGE' < PRE-LINKER MESSAGE NAME
// SET PPARM='NOER' < PRE-LINKER OPTIONS
// SET LPARM='AMODE=31' < LINK EDIT OPTIONS
//* Location of C libraries required for compile, pre-link and link.
// SET LIBPRFX='CEE' < PREFIX FOR LIBRARY DSN
// SET LNGPRFX='CBC' < PREFIX FOR LANGUAGE DSN
//* Dataset attributes for temporary files.
// SET SYSLBLK='3200' < BLOCKSIZE FOR &&LOADSET
// SET DCB80='(RECFM=FB,LRECL=80,BLKSIZE=3200)' <DCB FOR LRECL 80
// SET DCB3200='(RECFM=FB,LRECL=3200,BLKSIZE=12800)' < DCB LRECL 3200
// SET TUNIT='SYSDA' < UNIT FOR TEMPORARY FILES
// SET TSPACE='(32000,(30,30))' < SIZE FOR TEMPORARY FILES
//*-------------------------------------------------------------------
//* COMPILE STEP:
//*-------------------------------------------------------------------
//COMPILE EXEC PGM=CCNDRVR,
// PARM=('&CRUN/&CPARM'),COND=(8,LT)
//*
//* STEPLIB DD specifies the location of the compiler and runtime libraries.
//*
//STEPLIB DD DSN=&LIBPRFX..SCEERUN2,DISP=SHR
// DD DSN=&LIBPRFX..SCEERUN,DISP=SHR
// DD DSN=&LNGPRFX..SCCNCMP,DISP=SHR
//*
//* SYSLIB DD specifies the location of the IBM-supplied C header (hwtjic).
//*
//SYSLIB DD DSN=SIEAHDR.H
//*
//* SYSIN DD specifies the source member to be compiled.
//*
//SYSIN DD DSN=&SAMPLIB(&SRC),DISP=SHR
//*
//* SYSLIN DD specifies the output location of the object module generated
//* by the compile step.
//*
//SYSLIN DD DSN=&&LOADSET,UNIT=&TUNIT.,
// DISP=(MOD,PASS),SPACE=(TRK,(3,3)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=&SYSLBLK)
//SYSPRINT DD SYSOUT=*
//*
//*-------------------------------------------------------------
//* PRE-LINKEDIT STEP:
//*-------------------------------------------------------------
//PLKED EXEC PGM=EDCPRLK,
// PARM='&PPARM',COND=(4,LT,COMPILE)
//STEPLIB DD DSN=&LIBPRFX..SCEERUN2,DISP=SHR
// DD DSN=&LIBPRFX..SCEERUN,DISP=SHR
//SYSMSGS DD DSN=&LIBPRFX..SCEEMSGP(&PLANG),DISP=SHR
//SYSLIB DD DSN=&LIBPRFX..SCEEOBJ,DISP=SHR,UNIT=,VOL=SER=
// DD DSN=&LIBPRFX..SCEECPP,DISP=SHR,UNIT=,VOL=SER=
//*
//* SYSIN DD specifies the object module generated by the compile step as
//* input to the prelinker.
//*
//SYSIN DD DSN=*.COMPILE.SYSLIN,DISP=(MOD,DELETE)
//*
//* SYSMOD DD specifies the output dataset to contain the prelinked object
//* module generated by the prelinker.
//*
//SYSMOD DD DSN=&&PLKSET,UNIT=&TUNIT.,DISP=(NEW,PASS),
// SPACE=&TSPACE.,DCB=(RECFM=FB,LRECL=80,BLKSIZE=&SYSLBLK)
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//*
//*-------------------------------------------------------------------
//* LINKEDIT STEP:
//*-------------------------------------------------------------------
//LKED EXEC PGM=HEWL,COND=((4,LT,COMPILE),(4,LT,PLKED)),
// PARM='&LPARM'
//SYSLIB DD DSN=&LIBPRFX..SCEELKED,DISP=SHR
// DD DSN=&LOADLIB,DISP=SHR
// DD DSN=&CSSLIB,DISP=SHR
//*
//* SYSLIN DD specifies the prelinked object module as input to the linker.
//*
//SYSLIN DD DSN=*.PLKED.SYSMOD,DISP=(OLD,DELETE)
//*
//* SYSLMOD DD specifies the output dataset to contain the load module
//* generated by the linker.
//*
//SYSLMOD DD DSN=&LOADLIB(&SRC),DISP=SHR
//SYSUT1 DD UNIT=&TUNIT.,SPACE=&TSPACE.
//SYSPRINT DD SYSOUT=*
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **
* Sample JCL to execute the program. *
*---------------------------------------------------------------------*
* THIS JCL IS WRITTEN TO EXECUTE THE JSON C SAMPLE REGARDLESS OF HOW *
* THE SAMPLE WAS COMPILED OR LINKED. *
*---------------------------------------------------------------------*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//XC1RUN JOB NOTIFY=????????,
// MSGLEVEL=1,MSGCLASS=H
//EX1 EXEC PGM=HWTJXC1,REGION=1M
//*
//STEPLIB DD DSN=HWTJ.SAMPLE.LOAD,DISP=SHR
//SYSPRINT DD SYSOUT=*
//*
/*--------------------------------------------------------------------*
* REFERENCE: *
* See the z/OS MVS Programming: Callable Services for *
* High-Level Languages publication for more information *
* regarding the usage of JSON Parser APIs. *
* *
* Change Activity: *
* $L0 ME28544 HBB77A0 140930 PDJM z/OS Client Web Enablement Toolkit *
* JSON Parser *
* $L1 ME28918 HBB77A0 150228 PDLH Support for HWTJGNUV service *
* $01 OA49002 HBB7790 151210 PDLH: Corrected JCL in prolog *
* END OF SPECIFICATIONS * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hwtjic.h> /* JSON interface declaration file */
/* -----------------------------------------------------------------*/
/* Type definitions for storing parsed JSON data. */
/* -----------------------------------------------------------------*/
typedef struct {
char *name;
char *id;
char *years_of_service;
bool is_full_time;
} employee_record;
/* -----------------------------------------------------------------*/
/* Function prototypes */
/* -----------------------------------------------------------------*/
bool init_parser();
bool parse_json_text(const char *jtext);
bool insert_new_employee();
bool insert_boolean_entry(HWTJ_HANDLE_TYPE employee_entry);
bool process_employees_array();
void store_and_print_employee_info(HWTJ_HANDLE_TYPE employee_entry,
employee_record employee);
void find_tester_skill(HWTJ_HANDLE_TYPE employee_entry);
bool do_cleanup();
void traverse_json_entry(HWTJ_HANDLE_TYPE entry_handle, int indent_level);
void traverse_object(HWTJ_HANDLE_TYPE object_handle, int indent_level);
void traverse_array(HWTJ_HANDLE_TYPE array_handle, int indent_level);
char *find_string(HWTJ_HANDLE_TYPE object, char *search_string);
char *find_number(HWTJ_HANDLE_TYPE object, char *search_string);
bool find_boolean(HWTJ_HANDLE_TYPE object, char *search_string);
HWTJ_HANDLE_TYPE find_array(HWTJ_HANDLE_TYPE object, char *search_string);
HWTJ_HANDLE_TYPE find_object(HWTJ_HANDLE_TYPE object, char *search_string);
void *find_value(HWTJ_HANDLE_TYPE object, char *name,
HWTJ_JTYPE_TYPE expected_type);
void *do_get_value(HWTJ_HANDLE_TYPE object,
HWTJ_JTYPE_TYPE type);
bool has_skill(HWTJ_HANDLE_TYPE skills_array, char *job_role);
char *to_json_string();
void display_error(char *msg);
void print_employee_record(employee_record *record);
/* ----------------------------------------------------------------- */
/* Global Variables */
/* ----------------------------------------------------------------- */
/* A parser instance is required for all JSON callable services. */
HWTJ_PARSERHANDLE_TYPE parser_instance;
/* A structure for storing reason codes and error descriptions. */
HWTJ_DIAGAREA_TYPE diag_area;
/* A return code to store the result of each service call. */
int return_code;
/* A buffer to store the serialized JSON text string. */
static char *modified_json_string = NULL;
/* A flag variable to indiciate employee has 10 or more years of
* service.
*/
bool employee_with_seniority = false;
/*
* --------------------------------------------------------------------
* Sample JSON data
* --------------------------------------------------------------------
* Our sample JSON data represents an array of employee records. The
* array is stored as a name:value pair, where the name of the array is
* the literal string "employees" and the value is the actual array
* data. Each array entry represents an employee record. Each entry is
* itself an object containing several name:value pairs. The names
* contained in each array entry are described below along with the data
* types of the corresponding values.
*
* "name": <string>
* "employee_id": <string>
* "years_of_service": <number>
* "skills": <array>
* "full_time": <boolean>
* "contact": <object>
*
* In this example, the JSON data is available to the program as a
* static string. In practice, however, the data may originate from any
* external source such as a text file, an HTTP request, or a database
* record.
*/
static const char *JSON_TEXT =
"{"
"\"employees\": ["
"{"
"\"name\": \"john doe\","
"\"employee_id\": \"ab3f560r\","
"\"years_of_service\": 3,"
"\"skills\": ["
"\"tester\","
"\"support\""
"],"
"\"full_time\": true,"
"\"contact\": {"
"\"address\": {"
"\"street\": \"10 IBM Road\","
"\"city\": \"Poughkeepsie\","
"\"state\": \"NY\""
"}"
"}"
"},"
"{"
"\"name\": \"Jane Smith\","
"\"employee_id\": \"3f56ab7t\","
"\"years_of_service\": 7,"
"\"skills\": ["
"\"developer\","
"\"manager\""
"],"
"\"full_time\": true,"
"\"contact\": {"
"\"email\": \"jsmith@email.com\","
"\"phone\": \"555-444-3210\""
"}"
"},"
"{"
"\"name\": \"Fred Flynn\","
"\"employee_id\": \"ab3f569q\","
"\"years_of_service\": 10,"
"\"skills\": ["
"\"support\""
"],"
"\"full_time\": false,"
"\"contact\": {"
"\"email\": ["
"\"flynn@email.com\","
"\"ff55@bedrock.net\""
"]"
"}"
"}"
"]"
"}";
/* Used for return value buffer for the get object entry service (hwtjgoen). */
#define MIN_NAME_LENGTH 100
/* Used to specify the max work area size to parser init service (hwtjinit). */
#define MAX_WORKAREA_SIZE 0 /* Zero = No limit (IBM recommended value) */
/* Used to specify the maximum buffer size for serialize service (hwtjseri). */
#define MAX_BUFFER_SIZE 1000;
int main(void) {
/* Create a new parser instance. */
if (!init_parser()) {
return -1;
}
/* Parse the sample JSON text. */
if(!parse_json_text(JSON_TEXT)) {
do_cleanup();
return -1;
}
/* Insert a new employee entry into the employee array. */
if (!insert_new_employee()) {
do_cleanup();
return -1;
}
/*
* At this point, we've parsed the sample JSON data, inserted the
* "Hank Hacker" employee entry into the employees array, and added the
* "full_time" boolean field into the new employee entry. Now, we are going
* to iterate through the employees array and perform additional processing
* on each employee entry.
*/
if (!process_employees_array()) {
do_cleanup();
return -1;
}
/*
* At this point, we've made several modifications to the original
* JSON data. Now suppose we need to include the JSON data as part of an HTTP
* request or response. We first need to obtain a JSON-formatted text string
* containing the modifications we've made. This can be accomplished with the
* hwtjseri service, which generates a syntactically-correct JSON string
* using the data from our parser instance.
*/
/* Retrieve the serialized JSON text string. */
modified_json_string = to_json_string();
/* If serialize failed then exit. */
if (modified_json_string == NULL) {
do_cleanup();
return -1;
}
/* Free memory held by parser. */
if (!do_cleanup()) {
return -1;
}
/* Indicate successful program exit. */
return 0;
}
/*
* Method: init_parser
*
* Initializes the global parser_instance variable.
*
* Services Used:
*
* HWTJINIT: Provides a handle to a parse instance which is then used in
* subsequent service calls. The HWTJINIT service must be invoked
* before invoking any other parsing service.
*/
bool init_parser() {
/* Declare a variable to hold the return value. */
bool success = false;
/* Initialize the parser work area and retrieve a handle to a parser
* instance.
*/
hwtjinit(&return_code,
MAX_WORKAREA_SIZE, /* size (in bytes) of the parser work area (input) */
parser_instance,
&diag_area);
if (return_code == HWTJ_OK) {
printf("SUCCESS: Parser initialized.\n");
success = true;
} else {
display_error("Parser initialization failed.");
}
return success;
}
/*
* Method: parse_json_text
*
* Parses the sample JSON data.
*
* Services Used:
*
* HWTJPARS: Builds an internal representation of the specified JSON string.
* This allows efficient search, traversal, and modification of
* the JSON data.
*
* USAGE: HWTJPARS does not make a local copy of the JSON source string.
* Therefore, the caller must ensure that the provided source
* string remains unmodified for the duration of the parser
* instance. If the source string is modified, subsequent service
* calls may result in unexpected behavior.
*/
bool parse_json_text(const char *jtext) {
/* Declare a variable to hold the return variable. */
bool success = false;
/* Parse the sample JSON text string. Parse scans the JSON text string and
* creates an internal representation of the JSON data suitable for search
* and create operations.
*/
hwtjpars(&return_code,
parser_instance,
(char *)&jtext, /* JSON text string address(input) */
strlen(jtext), /* JSON text string length (input) */
&diag_area);
if (return_code == HWTJ_OK) {
printf("SUCCESS: JSON data parsed.\n");
success = true;
} else {
display_error("Unable to parse JSON data.");
}
return success;
}
/*
* Method: insert_new_employee
*
* Demonstrates the create service by inserting a new employee entry into the
* employees array and creating a new name:value pair within the new employee
* entry. Returns true if both create calls result in an HWTJ_OK return code.
*
* This method demonstrates two approaches for inserting new JSON data
* into an existing JSON text stream. First, a new employee entry is inserted
* into the employees array using a single call to hwtjcren. This is
* accomplished by passing in a stand-alone (syntactically correct) JSON
* text string and specifying HWTJ_JSONTEXTVALUETYPE as the EntryValueType.
* Note that the same result could have been achieved by issuing several calls
* to hwtjcren: one to insert an object and subsequent calls to insert
* each field using the appropriate entryValueType.
*
* Next, a boolean value is inserted into the newly created employee by
* specifying HWTJ_TRUEVALUETYPE as the entryValueType. Because the entry
* value of true is implied by the entryValueType, the entryValueAddr
* parm is left blank by specifying 0. The name portion of the name:value pair
* is specified by the entryNameAddr parm.
*
* Services Used:
*
* HWTJCREN: Create/insert a JSON entry into an existing JSON text stream.
*/
bool insert_new_employee() {
/* Declare a variable to hold the return value. */
bool success = false;
/* Create stand-alone JSON text for the new employee entry. */
char *new_employee_json =
"{"
"\"name\": \"Hank Hacker\","
"\"employee_id\": \"D08d45WY\","
"\"years_of_service\": 25,"
"\"skills\": ["
"\"developer\","
"\"tester\","
"\"manager\""
"],"
"\"contact\": {"
"\"email\": ["
"\"hankh@email.com\","
"\"hh87@leethax.net\""
"],"
"\"phone\": {"
"\"home\": \"555-567-8912\","
"\"mobile\": \"555-234-3234\","
"\"work\": {"
"\"number\": \"555-777-3444\","
"\"ext\": \"888\""
"}"
"}"
"}"
"}";
/* Retrieve the employee array located at the top-level of the JSON data. */
HWTJ_HANDLE_TYPE employee_array = find_array(0, "employees");
/* Confirm that the employees array was found. */
if (return_code == HWTJ_OK) {
/* Declare a handle to hold the resulting employee object. */
HWTJ_HANDLE_TYPE new_employee_handle;
/* HWTJCREN requires a name address of 0 in this case. */
char *entryNameAddr = 0;
/* This call to HWTJCREN inserts the JSON data for the "Hank Hacker"
* employee entry directly into the employee array. The
* employee-array-handle parameter specifies the "insertion point" -- the
* object/array that will contain this entry. The entryValueType
* parameter specifies the format of the incoming data. In this case,
* HWTJ_JSONTEXTVALUETYPE is specified because the data to be inserted is
* valid JSON text. Note that the original JSON string is not modified by
* HWTJCREN. The serialize service (HWTJSERI) can be used to obtain a new
* JSON text string which will include the new "Hank Hacker" array entry
*/
hwtjcren(&return_code,
parser_instance,
employee_array, /* handle to the insertion point (input) */
(char *)&entryNameAddr, /* name of the object (input)*/
0, /* length of the name (input) */
HWTJ_JSONTEXTVALUETYPE, /* type of data to be inserted (input) */
(char *)&new_employee_json, /* JSON text string address (input) */
strlen(new_employee_json), /* JSON text string length (input) */
&new_employee_handle, /* handle to the new entry (output) */
&diag_area);
/* Confirm that the create was successful. */
if (return_code == HWTJ_OK) {
printf("SUCCESS: "
"Inserted \"Hank Hacker\" employee entry into the employees array.\n");
/* Declare and initialize a string to hold the name of the field. */
char *field_name = "full_time";
/* Declare a handle to the resulting name:value pair. */
HWTJ_HANDLE_TYPE field_handle;
/* HWTJCREN requires a value address of 0 in this case. */
char *entryValueAddr = 0;
/* This call to HWTJCREN inserts a new name:value pair into the
* "Hank Hacker" employee entry. We use the object handle that was
* returned from the prior call to HWTJCREN as the insertion point for
* this call. In this case, specifying HWTJ_TRUEVALUETYPE as the
* entryValueType serves a dual purpose: it indicates the data type of
* the value portion of the name:value pair, and it specifies
* a boolean value of true as the value.
*/
hwtjcren(&return_code,
parser_instance,
new_employee_handle, /* handle to the "Hank Hacker" object */
(char *)&field_name, /* name portion of the name:value pair */
strlen(field_name), /* length of the name string */
HWTJ_TRUEVALUETYPE, /* value portion of the name:value pair */
(char *)&entryValueAddr, /* set to 0, value is implied */
0, /* length of the value (0 in this case) */
&field_handle, /* handle to the newly inserted name:value pair */
&diag_area);
/* Confirm that the create was successful. */
if (return_code == HWTJ_OK) {
printf("SUCCESS: "
"Inserted \"full_time\":true entry into the new employee entry.\n");
success = true;
} else {
display_error(
"Unable to insert name:value pair into new employee entry.");
}
} else {
display_error(
"Unable to insert employee entry into employees array.");
}
} else {
display_error("Unable to retrieve employees array from JSON text.");
}
return success;
}
/*
* Method: process_employees_array
*
* Loops through the employees array, retrieves each name:value pair, and
* prints each value. The employee contact information field is only printed if
* the employee has experience as a tester, which is determined by the
* has_skill subroutine. Returns true if each service call results in an
* HWTJ_OK return code.
*
* Services Used:
*
* HWTJGAEN - Retrieves a handle to an array entry.
* HWTJGNUE - Gets the number of entries in a JSON object or array.
*/
bool process_employees_array() {
/* Declare a variable to hold the return value. */
bool success = false;
/* Get the employee array located at the top-level of the JSON data. */
HWTJ_HANDLE_TYPE employee_array = find_array(0, "employees");
/* Declare a variable to hold the value returned by hwtjgnue. */
int num_of_employees = 0;
/* Use HWTJGNUE to get the number of entries in the employees array. This
* service is used in conjunction with the HWTJGAEN service to process each
* entry in the employees array.
*/
hwtjgnue(&return_code,
parser_instance,
employee_array, /* array or object handle (input) */
&num_of_employees, /* number of entries in the array/object (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Declare an array of employee_record structs. */
employee_record employees[num_of_employees];
/* Declare a handle to hold the current array entry being processed. */
HWTJ_HANDLE_TYPE employee_entry;
/* Use the value returned by hwtjgnue to loop thru the employees array. */
for (int i=0; i < num_of_employees && return_code == HWTJ_OK; i+=1) {
/* Retrieve the i-th entry from the employee array. */
hwtjgaen(&return_code,
parser_instance,
employee_array, /* handle to the employee array (input) */
i, /* index into the employee array (input) */
&employee_entry, /* handle to the array entry (output) */
&diag_area);
/* Extract the employee information from the JSON data and display it. */
store_and_print_employee_info(employee_entry, employees[i]);
if (employee_with_seniority) {
printf("ALERT! Employee has 10 or more years of service.\n");
employee_with_seniority = false; /* Reset */
}
/* Search this employee entry for the tester skill and print the result.*/
find_tester_skill(employee_entry);
}
/* Confirm that the loop did not terminate abnormally. */
if (return_code == HWTJ_OK) {
success = true;
}
} else {
display_error("Unable to retrieve number of entries from employee "
"array");
}
return success;
}
/*
* Method: store_and_print_employee_information
*
* Retrieves the name, employee_id, years_of_service, and full_time entries
* from the specified employee entry. The data is stored in an employee struct
* and displayed.
*/
void store_and_print_employee_info(HWTJ_HANDLE_TYPE employee_entry,
employee_record employee) {
/* Use "find_*" to retrieve each field from the employee entry.*/
char *employee_name = find_string(employee_entry, "name");
char *employee_id = find_string(employee_entry, "employee_id");
char *years_of_service = find_number(employee_entry, "years_of_service");
bool is_full_time = find_boolean(employee_entry, "full_time");
/* Store the employee data in an employee struct. */
employee.name = employee_name;
employee.id = employee_id;
employee.years_of_service = years_of_service;
employee.is_full_time = is_full_time;
/* Print the employee record. */
print_employee_record(&employee);
}
/*
* Method: find_tester_skill
*
* Determines whether the specified employee has the "tester" skill.
* Each employee has provided different types of contact information. We want
* to know all of the employees contact information so we use traverse_object
* to "auto-discover" the data. The search services may not work in this case
* because the data is unpredictable.
*/
void find_tester_skill(HWTJ_HANDLE_TYPE employee_entry) {
char *required_skill = "tester";
/* Locate the "skills" array for this employee. */
HWTJ_HANDLE_TYPE skills_array = find_array(employee_entry, "skills");
HWTJ_HANDLE_TYPE contact_info = NULL;
if (has_skill(skills_array, required_skill)) {
printf("ALERT! Employee has experience as a %s. ", required_skill);
printf("Printing Contact Information.\n");
/* Retrieve the contact info object. */
contact_info = find_object(employee_entry, "contact");
/* Traverse the contact info object and print out each name:value pair. */
traverse_object(contact_info, 0);
}
}
/*
* Method: do_cleanup
*
* Performs cleanup by freeing memory used by the parser and invalidating the
* parser handle.
*
* Services Used:
*
* HWTJTERM: Terminates a parser instance and frees the storage allocated
* by the parse services.
*
* USAGE: The third parameter to hwtjterm is used to specify the
* behavior of terminate if the parser is determined to be stuck
* in an "in-use" state. IBM recommends using the HWTJ_NOFORCE
* option in most cases. Because our sample is not multi-threaded,
* the risk of the parser getting stuck in an "in-use" state is
* low. Therefore, we provide a value of HWTJ_NOFORCE for the
* force option.
*
* NOTE: Consider enhancing this sample to postpone the call to the
* terminate service when a prior service call resulted in a return code of
* HWTJ_UNEXPECTED_ERROR. This will allow appropriate action to be taken to
* dump the work area storage for subsequent analysis by the IBM support
* center. Once the dump has been taken, terminate can be issued to free the
* storage from the user's address space.
*/
bool do_cleanup() {
/* Declare a variable to hold the return value. */
bool success = false;
/*
* On the first attempt, try to terminate with the force option disabled.
* This is the IBM recommended value for the force option. If the parser is
* in an inuse state, further cleanup processing is done in the following
* EVALUATE statement. A parser can be in an INUSE state if a prior service
* call encountered an unexpected error that caused it to exit abnormally, or
* if the parser-handle is used in a multi-threaded application.
*/
if (return_code != HWTJ_PARSERHANDLE_INUSE) {
/* Perform cleanup. */
hwtjterm(&return_code, parser_instance, HWTJ_NOFORCE, &diag_area);
}
/* Determine whether further cleanup processing is necessary. */
switch (return_code) {
case HWTJ_OK:
printf("SUCCESS: Parser work area freed.\n");
success = true;
break;
case HWTJ_PARSERHANDLE_INUSE:
display_error("Unable to perform cleanup.\n "
"Retrying cleanup with HWTJ_FORCE option enabled.");
/* Attempt to force cleanup. Use with caution as recommended in the
* parser documentation
*/
hwtjterm(&return_code, parser_instance, HWTJ_FORCE, &diag_area);
/* Check if cleanup was successful. */
if (return_code == HWTJ_OK) {
printf("SUCCESS: Parser work area freed using force option.\n");
success = true;
} else {
display_error("Unable to perform cleanup with HWTJ_FORCE option "
"enabled.\nCould not free parser work area.");
}
break;
default:
display_error("Unable to perform cleanup.\n "
"Could not free parser work area.");
}
/* Release the memory allocated for the serialized JSON data. */
if (modified_json_string) {
free(modified_json_string);
modified_json_string = NULL;
}
return success;
}
/*
* Method: find_string
*
* Searches the specified JSON object for a name:value pair where the name
* matches the specified search string and the value type is string. This is a
* convenience method that can be used when the structure of the JSON data is
* known beforehand.
*
* Input: - A handle of type object or array.
* - A string used as the search parameter.
*
* Output: If a match is found, the string value of the name:value pair is
* returned.
*/
char *find_string(HWTJ_HANDLE_TYPE object, char *search_string) {
return (char *) find_value(object, search_string, HWTJ_STRING_TYPE);
}
/*
* Method: find_number
*
* Searches the specified JSON object for a name:value pair where the name
* matches the specified search string and the value type is number. This is a
* convenience method that can be used when the structure of the JSON data is
* known beforehand.
*
* Input: - A handle of type object or array.
* - A string used as the search parameter.
*
* Output: If a match is found, the number value of the name:value pair is
* returned.
*
* Notes: The JSON spec (RFC 4627) allows numbers to be specified in several
* different formats (e.g. 3.00, 3.0e+2). This sample program makes no effort
* to convert JSON numeric data into the appropriate C data type -- all numeric
* data is treated as string data.
*/
char *find_number(HWTJ_HANDLE_TYPE object, char *search_string) {
return (char *) find_value(object, search_string, HWTJ_NUMBER_TYPE);
}
/*
* Method: find_boolean
*
* Searches the specified JSON object for a name:value pair where the name
* matches the specified search string and the value type is boolean. This is a
* convenience method that can be used when the structure of the JSON data is
* known beforehand.
*
* Input: - A handle of type object or array.
* - A string used as the search parameter.
*
* Output: If a match is found, the boolean value of the name:value pair is
* returned.
*/
bool find_boolean(HWTJ_HANDLE_TYPE object, char *search_string) {
HWTJ_BOOLEANVALUE_TYPE *bool_val_addr = NULL;
bool_val_addr = (HWTJ_BOOLEANVALUE_TYPE *)
find_value(object, search_string, HWTJ_BOOLEAN_TYPE);
return (*bool_val_addr == HWTJ_TRUE) ? true : false;
}
/*
* Method: find_array
*
* Searches the specified JSON object for a name:value pair where the name
* matches the specified search string and the value type is array. This is a
* convenience method that can be used when the structure of the JSON data is
* known beforehand.
*
* Input: - A handle of type object or array.
* - A string used as the search parameter.
*
* Output: If a match is found, a handle to the array value of the name:value
* pair is returned.
*/
HWTJ_HANDLE_TYPE find_array(HWTJ_HANDLE_TYPE object, char *search_string) {
HWTJ_HANDLE_TYPE *array_handle_addr =
(HWTJ_HANDLE_TYPE *) find_value(object, search_string, HWTJ_ARRAY_TYPE);
return *array_handle_addr;
}
/*
* Method: find_object
*
* Searches the specified JSON object for a name:value pair where the name
* matches the specified search string and the value type is object. This is a
* convenience method that can be used when the structure of the JSON data is
* known beforehand.
*
* Input: - A handle of type object or array.
* - A string used as the search parameter.
*
* Output: If a match is found, a handle to the object value of the name:value
* pair is returned.
*/
HWTJ_HANDLE_TYPE find_object(HWTJ_HANDLE_TYPE object, char *search_string) {
HWTJ_HANDLE_TYPE *obj_handle_addr = (HWTJ_HANDLE_TYPE *)
find_value(object, search_string, HWTJ_OBJECT_TYPE);
return *obj_handle_addr;
}
/*
* Method: find_value
*
* Searches the specified object for a name:value pair whose name matches the
* the specified search string. This is a utility method used by the "find"
* routines to easily search and retrieve a value from an object when the name
* and value type is known.
*
* Input: - A handle of type object or array.
* - A string used as a search parameter.
* - A JSON type as defined in the IBM-provided C interface definition
* file.
*
* Output: A pointer to the value is returned.
*
* Services Used:
* HWTJGJST: Gets the JSON type associated with a specified object or entry
* handle.
* HWTJSRCH: Finds a particular name string within the JSON text.
*
*/
void *find_value(HWTJ_HANDLE_TYPE object_to_search, char *name,
HWTJ_JTYPE_TYPE expected_value_type) {
/* Declare a handle to store a pointer to value. */
void *value_addr = NULL;
/* Declare a variable to hold the value if a match is found. */
HWTJ_HANDLE_TYPE value_handle = 0;
/* Search the specified object for the specified name. */
hwtjsrch(&return_code,
parser_instance,
HWTJ_SEARCHTYPE_OBJECT, /* limit the search scope */
(char *)&name, /* search string address */
strlen(name), /* search string length */
object_to_search, /* handle of object to search */
0, /* starting point of the search */
&value_handle, /* search result handle (output) */
&diag_area);
/* Check that the search found a result. */
if (return_code == HWTJ_OK) {
/* Declare a variable to hold the entry type returned by hwtjgjst. */
HWTJ_JTYPE_TYPE entry_type;
/* Get the object's type. */
hwtjgjst(&return_code,
parser_instance,
value_handle, /* handle to the value whose type to check (input) */
&entry_type, /* value type constant returned by hwtjgjst (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Verify that the returned handle has the expected type. */
if (entry_type == expected_value_type) {
value_addr = do_get_value(value_handle, entry_type);
} else {
printf("Error occurred while searching for %s\nThe name was found, "
"but the value was not of the expected type.\n", name);
printf("Expected type: %d\nActual type: %d\n",
expected_value_type, entry_type);
}
} else {
display_error("ERROR: Unable to retrieve JSON type.");
}
} else {
printf("ERROR: Search failed for name \"%s\". "
"Name was not found in the specified object.\n", name);
}
/*
* At this point, if the search did not return a match, or the
* expected type did not match the actual type, the value_addr
* output parm is still set to NULL. Otherwise, value_addr
* points to the appropriate address. The caller is responsible
* for casting the void pointer to the appropriate pointer type.
*/
return value_addr;
}
/*
* Method: do_get_value
*
* Retrieves the specified value by calling the appropriate service using the
* value of the specified HWTJ_JTYPE_TYPE.
*
* Input: - A value handle.
* - A valid entry type as defined in the IBM-provided C interface
* definition file.
*
* Services Used:
* HWTJGVAL: Retrieves the value of string or number entry.
* HWTJGBOV: Retrieves the value of a boolean entry.
*/
void *do_get_value(HWTJ_HANDLE_TYPE value_handle,
HWTJ_JTYPE_TYPE entry_type) {
/* Declare a variable to hold the pointer to the copy. */
void *value_addr = NULL;
/*
* The following checks determine the value's type and set
* the value_addr output parm appropriately.
*
* In the case of a string or number type, the source text is
* copied into a new buffer, and the value_addr output parm is
* set to the address of this buffer.
*
* In the case of a boolean value type, the HWTJ_TRUE/HWTJ_FALSE
* value is converted to a bool type and the value_addr output
* parm is set to the address of the bool value.
*
* In the case of an object or array type, the value_addr output
* parm is set to the address of the object or array handle.
*/
/* Determine the value type. */
if ((entry_type == HWTJ_STRING_TYPE) ||
(entry_type == HWTJ_NUMBER_TYPE)) {
/* Declare a variable to store the length returned by hwtjgval. */
int value_length = 0;
/* Declare a variable to store the address returned by hwtjgval. */
int string_value_addr = 0;
/* Issue hwtjgval to get the address and length of the string. */
hwtjgval(&return_code,
parser_instance,
value_handle, /* handle to a value (input) */
&string_value_addr, /* value address (output) */
&value_length, /* returned value length (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Allocate memory to store a copy of the string + null terminator. */
value_addr = malloc(value_length + 1);
/* Copy the JSON source text to the local variable. */
strncpy((char *)value_addr, (char *)string_value_addr, value_length);
/* Append the null-terminator. */
strcat((char *)value_addr, "\0");
if (entry_type == HWTJ_NUMBER_TYPE) {
int num_value = 0;
int *num_value_ptr = &num_value;
HWTJ_VALDESCRIPTOR_TYPE value_desc = 0;
/* Issue HWTJGNUV to get the binary representation
* of the number value.
*/
hwtjgnuv(&return_code,
parser_instance,
value_handle,
&num_value_ptr, /* pointer to output buffer */
sizeof(num_value), /* size of output buffer */
&value_desc, /* indicates 2's comp or BFP */
&diag_area);
if (return_code == HWTJ_OK) {
/* Verify that the converted value is an integer type.
This check can be skipped if you are confident that
the numeric data will only be specified as integer
data.
*/
if (value_desc == HWTJ_INTEGER_VALUE && num_value >= 10) {
employee_with_seniority = true;
}
} else {
display_error("An error occurred in Do_Get_Value. "
"HWTJGNUV failed.");
}
}
} else {
display_error("Unable to retrieve value.");
}
} else if (entry_type == HWTJ_BOOLEAN_TYPE) {
/* Declare a variable to store the value returned by hwtjgbov. */
HWTJ_BOOLEANVALUE_TYPE hwtj_boolean;
/* Retrieve the value and store it in a local variable. */
hwtjgbov(&return_code,
parser_instance,
value_handle, /* handle to the value (input) */
&hwtj_boolean, /* boolean value returned by hwtjgbov (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Store the address of the boolean value in our return value. */
value_addr = (void*)&hwtj_boolean;
} else {
display_error("Unable to retrieve boolean value.");
}
} else if ((entry_type == HWTJ_ARRAY_TYPE) ||
(entry_type == HWTJ_OBJECT_TYPE)) {
/* Store the address of the handle in our return variable. */
value_addr = &value_handle;
}
return value_addr;
}
/*
* Method: traverse_json_entry
*
* Performs a recursive, depth-first traversal of the specified JSON entry.
* When the provided handle is an array or object type, it is passed to the
* appropriate traversal subroutine (traverse_object or traverse_array). When
* the provided handle is a primitive type (i.e. string, number, bool,
* or null type) the value is retrieved and displayed.
*
* Usage: This subroutine demonstrates a common way for "auto-discovering"
* JSON data. It is especially useful when the data is unpredictable,
* i.e. not guaranteed to contain particular name:value pairs. The
* auto-discovery services contrast with the search services, which are
* based on the principle that the JSON data is predictable and is
* guaranteed to contain specific name:value pairs. As always,
* there is no one-size fits all solution and the traversal method that
* makes the most sense will depend on the structure of the JSON data.
*
*
* Input:
* - A value handle.
* - An integer used to format the printed JSON data.
*
* Output: None
*
* Services Used:
*
* HWTJGJST: Get the JSON type associated with a specified object or entry
* handle.
*
*/
void traverse_json_entry(HWTJ_HANDLE_TYPE entry_handle, int indent_level) {
/* Declare a variable to hold the value returned by hwtjgjst. */
HWTJ_JTYPE_TYPE entry_type;
/* In order to properly traverse this JSON entry, we first must determine the
* entry type.
*/
hwtjgjst(&return_code,
parser_instance,
entry_handle, /* handle to a JSON entry (input) */
&entry_type, /* value type of the handle (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/*
* Switch on the object's type. For primitive types (string, number,
* boolean, null) the value is displayed. For object and array types, the
* handle is passed to the appropriate traversal method.
*/
switch (entry_type) {
case HWTJ_OBJECT_TYPE: {
traverse_object(entry_handle, indent_level + 2);
break;
}
case HWTJ_ARRAY_TYPE: {
traverse_array(entry_handle, indent_level + 2);
break;
}
case HWTJ_STRING_TYPE: {
/* Declare a pointer to store the string value. */
char *string_value_addr = NULL;
/* Get the string value. */
string_value_addr =
(char *)do_get_value(entry_handle, HWTJ_STRING_TYPE);
if (string_value_addr != NULL) {
/*
* Display the value. The indent value is used to left-pad the
* printed string with spaces.
*/
printf("%*s\n", indent_level + strlen(string_value_addr),
string_value_addr);
}
break;
}
case HWTJ_NUMBER_TYPE: {
/* Declare a pointer to store the value address. */
char *num_value_addr = NULL;
/* Get the value. */
num_value_addr = (char *)do_get_value(entry_handle, HWTJ_NUMBER_TYPE);
if (num_value_addr != NULL) {
/*
* Display the value. The indent value is used to left-pad the
* printed string with spaces.
*/
printf("%*s\n", indent_level + strlen(num_value_addr),
num_value_addr);
}
break;
}
case HWTJ_BOOLEAN_TYPE: {
/* Declare a pointer to store the value address. */
HWTJ_BOOLEANVALUE_TYPE *bool_value_addr = NULL;
/* Get a pointer to the boolean value. */
bool_value_addr = (HWTJ_BOOLEANVALUE_TYPE*)
do_get_value(entry_handle, HWTJ_BOOLEAN_TYPE);
if (bool_value_addr != NULL) { /* Display the value. */
printf("%*d\n", indent_level + 4, *bool_value_addr);
}
break;
}
case HWTJ_NULL_TYPE: {
printf("null\n");
break;
}
default: {
/* If we've reached this point there is a problem. */
printf("unknown type\n");
break;
}
}/* end switch. */
} else {
display_error("Unable to retrieve JSON type.");
}
}
/*
* Method: traverse_object
*
* Traverses the specified object. Traversal is accomplished by retrieving each
* name:value pair contained within the object and passing it to
* traverse_json_entry.
*
* Services Used:
*
* HWTJGNUE: Gets the number of entries in an object.
* HWTJGOEN: Retrieves a name:value pair from an object.
*
* Usage: These services can be used together to loop thru each name:value
* pair contained within an object. The value returned by hwtjgnue is
* used as a loop control variable, and hwtjgoen is used to retrieve
* each name:value pair.
*/
void traverse_object(HWTJ_HANDLE_TYPE object_handle, int indent_level) {
/* Declare a variable to hold the value returned by hwtjgnue. */
int num_of_entries = 0;
/* In order to traverse this object, first get the number of name:value pairs
* in the object. The HWTJGNUE service can be used in conjunction with
* HWTJGOEN to visit each entry in an object.*/
hwtjgnue(&return_code,
parser_instance,
object_handle, /* object handle (input) */
&num_of_entries, /* number of name:value pairs (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Declare a variable to hold the current object entry for processing. */
HWTJ_HANDLE_TYPE entry_value_handle;
/* Declare a buffer to hold the name returned by hwtjgoen. */
char *entry_name_buffer = (char *) malloc(MIN_NAME_LENGTH);
/* Declare a variable to hold the actual length returned by hwtjgoen. */
int actual_name_length = 0;
/* Use the get object entry service to retrieve the next name:value pair.
* The HWTJGOEN service requires an output buffer to store the name portion
* of the name:value pair. If the buffer is not large enough to store the
* name, a warning code is returned and the actualNameLen output parameter
* contains the actual length of the name string. The HWTJGOEN service can
* then be re-issued with a buffer of sufficient size to store the name.
*/
for (int i = 0; i < num_of_entries && return_code == HWTJ_OK; i += 1) {
/* Get the next name:value pair. */
hwtjgoen(&return_code,
parser_instance,
object_handle, /* handle to the object (input) */
i, /* index into the object (input) */
(char *)&entry_name_buffer, /* entry name buffer (output) */
MIN_NAME_LENGTH, /* length of the provided buffer (input) */
&entry_value_handle, /* handle to the value portion (output) */
&actual_name_length, /* actual length of the name (output) */
&diag_area);
/*
* Check if the provided buffer was large enough to hold the name.
* If not, increase the buffer size to the amount returned by hwtjgoen.
*/
if (return_code == HWTJ_BUFFER_TOO_SMALL) {
/* Use the returned length to increase the buffer size. */
entry_name_buffer = (char *)realloc(entry_name_buffer,
actual_name_length * sizeof(char));
/* Confirm that the allocation was successful. */
if (entry_name_buffer != NULL) {
/* Re-issue hwtjgoen to retrieve the complete object entry name. */
hwtjgoen(&return_code,
parser_instance,
object_handle,
i,
(char *)&entry_name_buffer,
actual_name_length,
&entry_value_handle,
&actual_name_length,
&diag_area);
if (return_code != HWTJ_OK) {
display_error("Unable to retrieve object entry.");
}
}
}
if (return_code == HWTJ_OK) {
/* Print the entry name (left-padded with spaces). */
printf("%*s:\n", indent_level + actual_name_length, entry_name_buffer);
/* Traverse the value portion of this object. */
traverse_json_entry(entry_value_handle, indent_level + 2);
} else {
display_error("Unable to retrieve object entry.");
}
}
} else {
display_error("Unable to retrieve the number of entries from object.");
}
}
/*
* Method: traverse_array
*
* Traverses the specified array. Traversal is accomplished by retrieving each
* array entry and passing it to traverse_json_entry.
*
* Services Used:
*
* HWTJGNUE: Gets the number of entries in an array or object.
* HWTJGAEN: Retrieves a handle to an array entry using an index value.
*
* Usage: These services are normally combined in order to loop over each
* entry in an array. The value returned by hwtjgnue is used as a
* loop control variable, and hwtjgaen is used to retrieve each entry
* contained within the array.
*
*/
void traverse_array(HWTJ_HANDLE_TYPE array_handle, int indent_level) {
/* Declare a variable to hold the value returned from hwtjgnue. */
int num_of_entries = 0;
/* In order to traverse this array, first determine how many values are
* contained in the array using the HWTJGNUE service. The HWTJGNUE service
* can be used in conjunction with HWTJGAEN to visit each value in an array.
*/
hwtjgnue(&return_code,
parser_instance,
array_handle, /* handle to the array (input) */
&num_of_entries, /* number of array entries (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Declare a variable to hold the current array entry. */
HWTJ_HANDLE_TYPE array_entry_handle;
/* Begin the loop to process each array entry. */
for (int i = 0; i < num_of_entries && return_code == HWTJ_OK; i += 1) {
/* Get the next array entry. */
hwtjgaen(&return_code,
parser_instance,
array_handle, /* handle to the array (input) */
i, /* index into the array (input) */
&array_entry_handle, /* handle to the i-th entry (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Traverse this array entry. */
traverse_json_entry(array_entry_handle, indent_level + 2);
} else {
display_error("Unable to retrieve array entry.");
}
}
} else {
display_error("Unable to retrieve the number of entries from array.");
}
}
/*
* Method: has_skill
*
* Determines whether the specified array contains an entry whose value matches
* the specified search string. Returns true if the array contains an entry
* matching the specified skill, returns false otherwise.
*
* Input: - An array handle
* - A string used as a search parameter.
*
* Output: Returns true if the array contains a string value entry that matches
* the specified search string.
*
* Services Used:
*
* HWTJGJST: Get the JSON type associated with a specified object or entry
* handle.
* HWTJGNUE: Gets the number of entries in an array or object.
* HWTJGAEN: Retrieves a handle to an array entry using an index value.
* HWTJGVAL: Retrieves the value of string or number entry.
*
*/
bool has_skill(HWTJ_HANDLE_TYPE skills_array, char *skill) {
/* A flag variable to indiciate whether a match was found. */
bool is_match = false;
HWTJ_JTYPE_TYPE entry_type;
/* Issue hwtjgjst to retrieve the object's type. */
hwtjgjst(&return_code,
parser_instance,
skills_array, /* handle to the value whose type to check (input) */
&entry_type, /* value type constant returned by hwtjgjst (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Verify that the type is an array. */
if (entry_type != HWTJ_ARRAY_TYPE) {
return false;
}
/* Next, verify that the user passed a search string. */
if (skill && strlen(skill) <= 0) {
return false;
}
/* Retrieve each string value in the job roles array. */
int num_of_skills = 0;
hwtjgnue(&return_code,
parser_instance,
skills_array, /* handle to an array or object (input) */
&num_of_skills, /* number of entries in the array (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Get the string value of each entry. */
for (int i=0; i < num_of_skills && !is_match && return_code == HWTJ_OK;
i+=1) {
/* A handle to hold the array entry returned by hwtjgaen. */
HWTJ_HANDLE_TYPE skills_entry;
/* Get the next array entry. */
hwtjgaen(&return_code,
parser_instance,
skills_array, /* handle to the array (input) */
i, /* index into the array (input) */
&skills_entry, /* handle to the i-th entry (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* We are expecting each entry to be a string, but we will check
the type to be sure, because null values are valid as well. */
hwtjgjst(&return_code,
parser_instance,
skills_entry, /* value handle (input) */
&entry_type, /* value type constant (output) */
&diag_area);
/* Again, we are expecting string types, but just to be sure. */
if (return_code == HWTJ_OK && entry_type == HWTJ_STRING_TYPE) {
/* Get the string value. */
int entry_value_length = 0;
int *entry_value_addr = NULL;
/* Issue hwtjgval to get the address and length of the string. */
hwtjgval(&return_code,
parser_instance,
skills_entry, /* value handle (input) */
(int*)&entry_value_addr, /* output buffer address */
&entry_value_length, /* actual value length (output) */
&diag_area);
if (return_code == HWTJ_OK) {
/* Does this job role match the specified job role? */
is_match =
!strncmp(skill, (char *)entry_value_addr, strlen(skill));
} else {
display_error("Unable to retrieve value from array.");
}
}
} else {
display_error("Unable to retrieve array entry.");
}
} /* end for loop */
} else {
display_error("Unable to retrieve number of entries in array.");
}
} else {
display_error("Unable to retrieve JSON type.");
}
/* Return the result of the search to the caller. */
return is_match;
}
/*
* Method: to_json_string
*
* Returns a pointer to the serialized version of the JSON data. If an an error
* occurs during serialization a NULL pointer is returned.
*
* Services Used:
*
* HWTJSERI: Generates a JSON text string representing the data .
*
* USAGE: The serialize service generates a JSON-formatted text string using
* the data available through the provided parser handle. It is
* especially useful after using the create services to modify
* or insert additional JSON data.
*/
char *to_json_string() {
/* Declare a variable to hold the returned length. */
int actual_length = 0;
/* Specify the buffer size input variable. */
int buffer_size = MAX_BUFFER_SIZE;
/* Allocate memory to store the serialized text. */
char *serialized_text_buffer = (char *)malloc(buffer_size);
/* Generate a JSON formatted text string using the current state of the JSON
* data. The JSON text returned by the serialize service (HWTJSERI) will
* include all modifications and insertions done through the create service
* (HWTJCREN). If the provided output buffer is not large enough to contain
* the entire serialized text string, a warning return code is returned and
* the actual-output-length parameter is set to to the actual size required
* by the buffer. This value can be used to increase the buffer size to the
* required amount. The HWTJSERI can be called again to obtain the complete
* serialized text string.
*/
hwtjseri(&return_code,
parser_instance,
(char *)&serialized_text_buffer, /* buffer address (output) */
buffer_size, /* output buffer size (input) */
&actual_length, /* actual size of serialized JSON text (output) */
&diag_area);
/* Determine whether serialize returned successfully. */
if (return_code == HWTJ_OK) {
printf("SUCCESS: JSON data serialized.\n");
} else if (return_code == HWTJ_BUFFER_TOO_SMALL) {
/* If the error occurred because the provided buffer was too small,
use the returned length to increase the buffer size. */
serialized_text_buffer = (char *)realloc(serialized_text_buffer,
actual_length);
/* Confirm that the allocation was successful. */
if (serialized_text_buffer != NULL) {
buffer_size = actual_length;
/* Re-issue hwtjseri to retrieve complete serialized text string. */
hwtjseri(&return_code,
parser_instance,
(char *)&serialized_text_buffer, /* buffer address (input) */
buffer_size, /* output buffer size (input) */
&actual_length, /* actual size of serialized JSON text (output) */
&diag_area);
if (return_code != HWTJ_OK) {
display_error("Unable to serialize JSON data.");
}
}
} else {
display_error("Unable to serialize JSON data.");
}
return serialized_text_buffer;
}
/*
* Method: display_error
*
* A helper method for displaying error diagnostic information.
*/
void display_error(char *msg) {
printf("ERROR: %s\n", msg);
printf("Return Code: %d\n", return_code);
printf("Reason Code: %d\n", diag_area.ReasonCode);
printf("Reason Text: %s\n", diag_area.ReasonDesc);
}
/*
* Method: print_employee_record
*
* A helper method for displaying an employee record struct.
*/
void print_employee_record(employee_record *rec) {
printf(" * * * EMPLOYEE ENTRY * * *\n");
printf("NAME: %s\n", rec->name);
printf("ID: %s\n", rec->id);
printf("YEARS: %s\n", rec->years_of_service);
printf("FULLTIME: %s\n", rec->is_full_time ? "true" : "false");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment