## vim: ft=makocpp <% api = java_api nat = c_api.get_name project_type = capi.get_name('gpr_project') str_array_type = capi.get_name('string_array_ptr') scn_var_type = capi.get_name('gpr_project_scenario_variable') sig_base = "com/adacore/" + ctx.lib_name.lower + "/" + ctx.lib_name.camel ptr_sig = sig_base + "$PointerWrapper" %> void add_error_to_diagnostics( JNIEnv *env, jstring error, jobject diagnostics ) { // Get the "add" method of the list jclass clazz = (*env)->GetObjectClass(env, diagnostics); jmethodID add_id = (*env)-> GetMethodID( env, clazz, "add", "(Ljava/lang/Object;)Z" ); // Call the "add" method with the Java string to add it to the diagnostics (*env)->CallVoidMethod(env, diagnostics, add_id, error); } // Unwrap a scenario variable in the given pointer void ScenarioVariable_unwrap( JNIEnv *env, jobject scenario_variable, ${scn_var_type} *scenario_variables_native_ref ) { // Get the Java class jclass clazz = (*env)->GetObjectClass(env, scenario_variable); % for field in ('name', 'value'): // Get the field ids jfieldID ${field}_field = (*env)->GetFieldID( env, clazz, "${field}", "Ljava/lang/String;" ); // Get the field values jstring ${field} = (jstring) (*env)->GetObjectField( env, scenario_variable, ${field}_field ); // Get the native values const char *${field}_native = (*env)->GetStringUTFChars( env, ${field}, NULL ); int ${field}_native_length = (*env)->GetStringUTFLength( env, ${field} ); // Allocate the buffer in the result structure scenario_variables_native_ref->${field} = calloc(${field}_native_length, sizeof(char)); for(int i = 0; i < ${field}_native_length; i++) { scenario_variables_native_ref->${field}[i] = ${field}_native[i]; } // Release the source chararcter pointer (*env)->ReleaseStringUTFChars(env, ${field}, ${field}_native); % endfor } // Release the given native scenario variable void ScenarioVariable_release( ${scn_var_type} scenario_variable_native ) { free(scenario_variable_native.name); free(scenario_variable_native.value); } // Load a gpr project ${api.jni_func_sig("gpr_project_load", "jobject")}( JNIEnv *env, jclass jni_lib, jstring project_file, jobjectArray scenario_variables, jstring target, jstring runtime, jobject diagnostics ) { // Create the scenario variable array ${scn_var_type} *scenario_variables_native = NULL; int scenario_variables_length = 0; if(scenario_variables != NULL) { // Get the scenario variable length scenario_variables_length = (*env)->GetArrayLength(env, scenario_variables); if(scenario_variables_length > 0) { // Allocate the scenario variable array int size = scenario_variables_length + 1; scenario_variables_native = (${scn_var_type}*) calloc( (size_t) size, (size_t) sizeof(${scn_var_type}) ); // Unwrap all scenario variables in the native array for(int i = 0; i < scenario_variables_length; i++) { jobject scenario_variable = (*env)->GetObjectArrayElement( env, scenario_variables, (jsize) i ); ScenarioVariable_unwrap( env, scenario_variable, &scenario_variables_native[i] ); } } } // Translate the arguments to C values const char *project_file_c = to_c_string(env, project_file); const char *target_c = to_c_string(env, target); const char *runtime_c = to_c_string(env, runtime); // Call the native function to create the project ${project_type} res = NULL; ${str_array_type} errors = NULL; ${nat("gpr_project_load")}( project_file_c, scenario_variables_native, target_c, runtime_c, &res, &errors ); // Free the scenario variables if(scenario_variables_native != NULL) { for(int i = 0; i < scenario_variables_length; i++) { ScenarioVariable_release(scenario_variables_native[i]); } free(scenario_variables_native); } // Free the translated strings (*env)->ReleaseStringUTFChars(env, project_file, project_file_c); (*env)->ReleaseStringUTFChars(env, target, target_c); (*env)->ReleaseStringUTFChars(env, runtime, runtime_c); // The `errors` pointer is not allocated if an exception was raised during // project file loading. if (errors != NULL) { // Handle the errors for(int i = 0 ; i < errors->length ; i++) { const char *error = errors->c_ptr[i]; jstring j_error = (*env)->NewStringUTF(env, error); add_error_to_diagnostics(env, j_error, diagnostics); } // Free the error array ${nat("free_string_array")}(errors); } // Return the pointer return PointerWrapper_wrap(env, (void *) res); } // Free a gpr project ${api.jni_func_sig("gpr_project_free", "void")}( JNIEnv *env, jclass jni_lib, jobject project ) { // Do the native call ${nat("gpr_project_free")}((${project_type}) get_reference(env, project)); } // Get the unit provider from a gpr project ${api.jni_func_sig("gpr_project_create_unit_provider", "jobject")}( JNIEnv *env, jclass jni_lib, jobject project, jstring subproject ) { const char* subproject_c = NULL; if (subproject != NULL) { subproject_c = (*env)->GetStringUTFChars(env, subproject, NULL); } // Call the native function ${unit_provider_type} res = ${nat("gpr_project_create_unit_provider")}( (${project_type}) get_reference(env, project), subproject_c ); // Free all temporarily allocated memory if (subproject_c != NULL) { (*env)->ReleaseStringUTFChars(env, subproject, subproject_c); } // Return the new unit provider return UnitProvider_wrap(env, res); } // Get the list of the files of a project ${api.jni_func_sig("gpr_project_source_files", "jobjectArray")}( JNIEnv *env, jclass jni_lib, jobject project, jint mode, jobjectArray subprojects ) { jobjectArray result_java = NULL; /* Convert the Java array of subprojects ("subprojects" argument) into the required C array (subproject_count/subprojects_c). */ jsize subproject_count = 0; const char** subprojects_c = NULL; if (subprojects != NULL) { subproject_count = (*env)->GetArrayLength (env, subprojects); subprojects_c = calloc (subproject_count, sizeof (char*)); } for (int i = 0; i < subproject_count; ++i) { jstring subproject = (jstring) (*env)->GetObjectArrayElement (env, subprojects, i); subprojects_c[i] = (*env)->GetStringUTFChars (env, subproject, NULL); } /* Call the C API. In case of failure, return NULL and let the caller propagate the native exception into the Java world. */ ${str_array_type} result_c = ${nat("gpr_project_source_files")} ( (${project_type}) get_reference (env, project), (int) mode, subprojects_c, subproject_count ); if (${nat("get_last_exception")} () != NULL) goto error; /* Create the Java array result and initialize it. */ jclass clazz = (*env)->FindClass (env, "java/lang/String"); result_java = (*env)->NewObjectArray (env, (jsize) result_c->length, clazz, NULL); for (int i = 0 ; i < result_c->length ; i++) { jstring source_file = to_j_string (env, result_c->c_ptr[i]); (*env)->SetObjectArrayElement (env, result_java, (jsize) i, (jobject) source_file); } /* Now that the Java result is ready, release the C result. */ ${nat("free_string_array")} (result_c); error: /* Release subprojects_c. */ for (int i = 0; i < subproject_count; ++i) { jstring subproject = (jstring) (*env)->GetObjectArrayElement(env, subprojects, i); (*env)->ReleaseStringUTFChars (env, subproject, subprojects_c[i]); } free (subprojects_c); return result_java; } ${c_doc("libadalang.gpr_project_create_context", lang="java")} ${api.jni_func_sig("gpr_project_create_context", "jobject")}( JNIEnv *env, jclass jni_lib, jobject project, jstring subproject, jobject event_handler, jboolean with_trivia, jint tab_stop ) { const char *subproject_c = NULL; if (subproject != NULL) subproject_c = (*env)->GetStringUTFChars (env, subproject, NULL); ${event_handler_type} event_handler_c = NULL; if (event_handler != NULL) event_handler_c = EventHandler_unwrap (env, event_handler); /* Manually allocate a C-level analysis context so that we can initialize it ourselves. */ ${analysis_context_type} ctx_c = ${nat("allocate_analysis_context")} (); /* Create the Java wrapper, so that we have one ready for event handler callbacks triggered during context initialization. */ jobject ctx = AnalysisContext_wrap (env, ctx_c); /* The wrapper created its own ownership share: release ours. */ ${nat("context_decref")} (ctx_c); /* TODO: attach extra wrappers to the analysis context wrapper so that wrappers ("project" and "event_handler") live at least as long as the analysis context. */ /* Finally, initialize the analysis context. Note that this step may raise an exception: in that case, the analysis context is considered not initialized: release it. */ ${nat("gpr_project_initialize_context")} ( (${project_type}) get_reference (env, project), ctx_c, subproject_c, event_handler_c, (int) with_trivia, (int) tab_stop ); if (subproject_c != NULL) (*env)->ReleaseStringUTFChars (env, subproject, subproject_c); const ${exception_type} *exc_c = ${nat("get_last_exception")} (); if (exc_c != NULL) { jthrowable exc = LangkitException_wrap (env, *exc_c); ${nat("context_decref")} (ctx_c); (*env)->Throw (env, exc); } return ctx; } // Create an auto provider reference ${api.jni_func_sig("create_auto_provider", "jobject")}( JNIEnv *env, jclass jni_lib, jobjectArray source_files, jstring charset ) { // Retrieve the number of files N jsize source_file_count = (*env)->GetArrayLength(env, source_files); // Allocate an array of N+1 element (the last one should be the null pointer), // indicating the end of the C array. const char** source_files_c = calloc(source_file_count + 1, sizeof(char*)); for (int i = 0; i < source_file_count; ++i) { jstring source_file = (jstring) (*env)->GetObjectArrayElement( env, source_files, i ); source_files_c[i] = (*env)->GetStringUTFChars(env, source_file, NULL); } const char* charset_c = NULL; if (charset != NULL) { charset_c = (*env)->GetStringUTFChars(env, charset, NULL); } // Create the auto provider ${unit_provider_type} res = ${nat("create_auto_provider")}( source_files_c, charset_c ); // Free all temporarily allocated memory if (charset_c != NULL) { (*env)->ReleaseStringUTFChars(env, charset, charset_c); } for (int i = 0; i < source_file_count; ++i) { jstring source_file = (jstring) (*env)->GetObjectArrayElement( env, source_files, i ); (*env)->ReleaseStringUTFChars(env, source_file, source_files_c[i]); } free(source_files_c); // Return the new unit provider return UnitProvider_wrap(env, res); } ${api.jni_func_sig("set_config_pragmas_mapping", "void")}( JNIEnv *env, jclass jni_lib, jobject context, jobject global_pragmas, jobjectArray local_pragmas ) { ada_analysis_context context_c; ada_analysis_unit global_pragmas_c; ada_analysis_unit *local_pragmas_c; int i, size; context_c = AnalysisContext_unwrap (env, context); global_pragmas_c = (global_pragmas == NULL) ? NULL : AnalysisUnit_unwrap (env, global_pragmas); size = (*env)->GetArrayLength (env, local_pragmas); local_pragmas_c = calloc (size, sizeof (ada_analysis_unit)); for (i = 0; i < size; ++i) { jobject unit_java = (*env)->GetObjectArrayElement (env, local_pragmas, (jsize) i); ada_analysis_unit unit_c; unit_c = (unit_java == NULL) ? NULL : AnalysisUnit_unwrap (env, unit_java); local_pragmas_c[i] = unit_c; } ${nat("set_config_pragmas_mapping")} (context_c, global_pragmas_c, local_pragmas_c); free (local_pragmas_c); }