text: /*
   * Copyright (c) 2016 Eric Haszlakiewicz
   *
   * This is free software; you can redistribute it and/or modify
   * it under the terms of the MIT license. See COPYING for details.
   */
  
  #include <stdio.h>
  
  #include "config.h"
  #include "json_inttypes.h"
  #include "json_object.h"
  #include "json_visit.h"
  #include "linkhash.h"
  
  static int _json_c_visit(json_object *jso, json_object *parent_jso,
                           const char *jso_key, size_t *jso_index,
                           json_c_visit_userfunc *userfunc, void *userarg);
  
  int json_c_visit(json_object *jso, int future_flags,
                   json_c_visit_userfunc *userfunc, void *userarg)
  {
  	int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg);
  
  	(void)future_flags;
  
  	switch(ret)
  	{
  	case JSON_C_VISIT_RETURN_CONTINUE:
  	case JSON_C_VISIT_RETURN_SKIP:
  	case JSON_C_VISIT_RETURN_POP:
  	case JSON_C_VISIT_RETURN_STOP:
  		return 0;
  	default:
  		return JSON_C_VISIT_RETURN_ERROR;
  	}
  }
  static int _json_c_visit(json_object *jso, json_object *parent_jso,
                           const char *jso_key, size_t *jso_index,
                           json_c_visit_userfunc *userfunc, void *userarg)
  {
  	int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg);
  	switch(userret)
  	{
  	case JSON_C_VISIT_RETURN_CONTINUE:
  		break;
  	case JSON_C_VISIT_RETURN_SKIP:
  	case JSON_C_VISIT_RETURN_POP:
  	case JSON_C_VISIT_RETURN_STOP:
  	case JSON_C_VISIT_RETURN_ERROR:
  		return userret;
  	default:
  		fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret);
  		return JSON_C_VISIT_RETURN_ERROR;
  	}
  
  	switch(json_object_get_type(jso))
  	{
  	case json_type_null:
  	case json_type_boolean:
  	case json_type_double:
  	case json_type_int:
  	case json_type_string:
  		// we already called userfunc above, move on to the next object
  		return JSON_C_VISIT_RETURN_CONTINUE;
  
  	case json_type_object:
  	{
  		json_object_object_foreach(jso, key, child)
  		{
  			userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg);
  			if (userret == JSON_C_VISIT_RETURN_POP)
  				break;
  			if (userret == JSON_C_VISIT_RETURN_STOP ||
  				userret == JSON_C_VISIT_RETURN_ERROR)
  				return userret;
  			if (userret != JSON_C_VISIT_RETURN_CONTINUE &&
  				userret != JSON_C_VISIT_RETURN_SKIP)
  			{
  				fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret);
  				return JSON_C_VISIT_RETURN_ERROR;
  			}
  		}
  		break;
  	}
  	case json_type_array:
  	{
  		size_t array_len = json_object_array_length(jso);
  		size_t ii;
  		for (ii = 0; ii < array_len; ii++)
  		{
  			json_object *child = json_object_array_get_idx(jso, ii);
  			userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg);
  			if (userret == JSON_C_VISIT_RETURN_POP)
  				break;
  			if (userret == JSON_C_VISIT_RETURN_STOP ||
  				userret == JSON_C_VISIT_RETURN_ERROR)
  				return userret;
  			if (userret != JSON_C_VISIT_RETURN_CONTINUE &&
  				userret != JSON_C_VISIT_RETURN_SKIP)
  			{
  				fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret);
  				return JSON_C_VISIT_RETURN_ERROR;
  			}
  		}
  		break;
  	}
  	default:
  		fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", json_object_get_type(jso));
  		return JSON_C_VISIT_RETURN_ERROR;
  	}
  
  	// Call userfunc for the second type on container types, after all
  	//  members of the container have been visited.
  	// Non-container types will have already returned before this point.
  
  	userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg);
  	switch(userret)
  	{
  	case JSON_C_VISIT_RETURN_SKIP:
  	case JSON_C_VISIT_RETURN_POP:
  		// These are not really sensible during JSON_C_VISIT_SECOND, 
  		// but map them to JSON_C_VISIT_CONTINUE anyway.
  		// FALLTHROUGH
  	case JSON_C_VISIT_RETURN_CONTINUE:
  		return JSON_C_VISIT_RETURN_CONTINUE;
  	case JSON_C_VISIT_RETURN_STOP:
  	case JSON_C_VISIT_RETURN_ERROR:
  		return userret;
  	default:
  		fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret);
  		return JSON_C_VISIT_RETURN_ERROR;
  	}
  	// NOTREACHED
  }
  
  