LCOV - code coverage report
Current view: top level - src - midas_c_compat.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 269 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 83 0

            Line data    Source code
       1              : #include "midas_c_compat.h"
       2              : #include "midas.h"
       3              : #include "mrpc.h"
       4              : #include "msystem.h"
       5              : #include <vector>
       6              : #include <string>
       7              : #include "string.h"
       8              : #include "stdlib.h"
       9              : #include "stdarg.h"
      10              : #include "history.h"
      11              : 
      12              : /*
      13              : We define a simple free function to ensure that python clients can
      14              : free any memory that was allocated by midas. We define it as part
      15              : of this library (rather than importing libc directly in python) to
      16              : ensure that the same version of libc is used for the alloc and free.
      17              : */
      18            0 : void c_free(void* mem) {
      19            0 :    free(mem);
      20            0 : }
      21              : 
      22            0 : void c_free_list(void** mem_list, int arr_len) {
      23            0 :    for (int i = 0; i < arr_len; i++) {
      24            0 :       free(mem_list[i]);
      25              :    }
      26              : 
      27            0 :    free(mem_list);
      28            0 : }
      29              : 
      30              : /*
      31              : Copies the content for src to dest (at most dest_size bytes).
      32              : dest should already have been allocated to the correct size.
      33              : If the destination is not large enough to hold the entire src
      34              : string, we return DB_TRUNCATED; otherwise we return SUCCESS.
      35              : 
      36              : In general it's preferable to accept a char** from python rather than
      37              : a buffer of a fixed size. Although python must then remember to free
      38              : the memory we allocated.
      39              :  */
      40            0 : INT copy_string_to_c(std::string src, char* dest, DWORD dest_size) {
      41            0 :    strncpy(dest, src.c_str(), dest_size);
      42              : 
      43            0 :    if (src.size() > dest_size) {
      44            0 :       return DB_TRUNCATED;
      45              :    }
      46              : 
      47            0 :    return SUCCESS;
      48              : }
      49              : 
      50              : /*
      51              : Copies the content of vec into an array of type 'T' at dest. Will malloc the
      52              : memory needed, so you must later call c_free() on dest. Fills dest_len with
      53              : the size of the vector.
      54              :  */
      55            0 : template <class T> INT copy_vector_to_c(std::vector<T> vec, void** dest, int& dest_len) {
      56            0 :    dest_len = vec.size();
      57            0 :    *dest = malloc(sizeof(T) * dest_len);
      58            0 :    std::copy(vec.begin(), vec.end(), (T*)*dest);
      59            0 :    return SUCCESS;
      60              : }
      61              : 
      62              : /*
      63              : Copies the content of vec into an array of char* at dest. Will malloc the
      64              : memory needed for each string (and for the array itself), so you must later call
      65              : c_free_list() on dest. Fills dest_len with the size of the vector.
      66              :  */
      67            0 : INT copy_vector_string_to_c(std::vector<std::string> vec, char*** dest, int& dest_len) {
      68            0 :    dest_len = vec.size();
      69            0 :    *dest = (char**) malloc(sizeof(char*) * dest_len);
      70              : 
      71            0 :    for (int i = 0; i < dest_len; i++) {
      72            0 :       (*dest)[i] = strdup(vec[i].c_str());
      73              :    }
      74              : 
      75            0 :    return SUCCESS;
      76              : }
      77              : 
      78              : /*
      79              : Example of how one could wrap a midas function that returns/fills a std::string.
      80              : In this version we accept a buffer of a specified size from the user.
      81              : 
      82              : The python code would be:
      83              : ```
      84              : buffer = ctypes.create_string_buffer(64)
      85              : lib.c_example_string_c_bufsize(buffer, 64)
      86              : py_str = buffer.value.decode("utf-8")
      87              : ```
      88              :  */
      89            0 : INT c_example_string_c_bufsize(char* buffer, DWORD buffer_size) {
      90            0 :    std::string retval("My string that would come from a C++ function");
      91            0 :    return copy_string_to_c(retval, buffer, buffer_size);
      92            0 : }
      93              : 
      94              : /*
      95              : Example of how one could wrap a midas function that returns/fills a std::string.
      96              : In this version we allocate memory for the C char array. The caller must later
      97              : free this memory themselves.
      98              : 
      99              : The python code would be (note the final free!):
     100              : ```
     101              : buffer = ctypes.c_char_p()
     102              : lib.c_example_string_c_alloc(ctypes.byref(buffer))
     103              : py_str = buffer.value.decode("utf-8")
     104              : lib.c_free(buffer)
     105              : ```
     106              :  */
     107            0 : INT c_example_string_c_alloc(char** dest) {
     108            0 :    std::string retval("My string that would come from a C++ function");
     109            0 :    *dest = strdup(retval.c_str());
     110            0 :    return SUCCESS;
     111            0 : }
     112              : 
     113              : /*
     114              : Example of how one could wrap a midas function that returns/fills a std::vector.
     115              : In this version we allocate memory for the C array. The caller must later
     116              : free this memory themselves.
     117              : 
     118              : The python code would be (note the final free!):
     119              : ```
     120              : import ctypes
     121              : import midas.client
     122              : 
     123              : client = midas.client.MidasClient("pytest")
     124              : lib = client.lib
     125              : 
     126              : arr = ctypes.c_void_p()
     127              : arr_len = ctypes.c_int()
     128              : lib.c_example_vector(ctypes.byref(arr), ctypes.byref(arr_len))
     129              : casted = ctypes.cast(arr, ctypes.POINTER(ctypes.c_float))
     130              : py_list = casted[:arr_len.value]
     131              : lib.c_free(arr)
     132              : ```
     133              :  */
     134            0 : INT c_example_vector(void** dest, int& dest_len) {
     135            0 :    std::vector<float> retvec;
     136            0 :    for (int i = 0; i < 10; i++) {
     137            0 :       retvec.push_back(i/3.);
     138              :    }
     139              : 
     140            0 :    return copy_vector_to_c(retvec, dest, dest_len);
     141            0 : }
     142              : 
     143              : /*
     144              : Example of how one could wrap a midas function that returns/fills a std::vector.
     145              : In this version we allocate memory for the C array. The caller must later
     146              : free this memory themselves.
     147              : 
     148              : The python code would be (note the final free!):
     149              : ```
     150              : import ctypes
     151              : import midas.client
     152              : client = midas.client.MidasClient("pytest")
     153              : lib = client.lib
     154              : 
     155              : arr = ctypes.POINTER(ctypes.c_char_p)()
     156              : arr_len = ctypes.c_int()
     157              : lib.c_example_string_vector(ctypes.byref(arr), ctypes.byref(arr_len))
     158              : casted = ctypes.cast(arr, ctypes.POINTER(ctypes.c_char_p))
     159              : py_list = [casted[i].decode("utf-8") for i in range(arr_len.value)]
     160              : lib.c_free_list(arr, arr_len)
     161              : ```
     162              :  */
     163            0 : INT c_example_string_vector(char*** dest, int& dest_len) {
     164            0 :    std::vector<std::string> retvec;
     165            0 :    retvec.push_back("Hello");
     166            0 :    retvec.push_back("world!");
     167              : 
     168            0 :    return copy_vector_string_to_c(retvec, dest, dest_len);
     169            0 : }
     170              : 
     171            0 : INT c_al_trigger_alarm(const char *alarm_name, const char *alarm_message, const char *default_class, const char *cond_str, INT type) {
     172            0 :    return al_trigger_alarm(alarm_name, alarm_message, default_class, cond_str, type);
     173              : }
     174              : 
     175            0 : INT c_al_reset_alarm(const char *alarm_name) {
     176            0 :    return al_reset_alarm(alarm_name);
     177              : }
     178              : 
     179            0 : INT c_al_define_odb_alarm(const char *name, const char *condition, const char *aclass, const char *message) {
     180            0 :    return al_define_odb_alarm(name, condition, aclass, message);
     181              : }
     182              : 
     183            0 : INT c_bm_flush_cache(INT buffer_handle, INT async_flag) {
     184            0 :    return bm_flush_cache(buffer_handle, async_flag);
     185              : }
     186              : 
     187            0 : INT c_bm_open_buffer(const char *buffer_name, INT buffer_size, INT * buffer_handle) {
     188            0 :    return bm_open_buffer(buffer_name, buffer_size, buffer_handle);
     189              : }
     190              : 
     191            0 : INT c_bm_receive_event(INT buffer_handle, void *destination, INT * buf_size, INT async_flag) {
     192            0 :    return bm_receive_event(buffer_handle, destination, buf_size, async_flag);
     193              : }
     194              : 
     195            0 : INT c_bm_remove_event_request(INT buffer_handle, INT request_id) {
     196            0 :    return bm_remove_event_request(buffer_handle, request_id);
     197              : }
     198              : 
     199            0 : INT c_bm_request_event(INT buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, INT * request_id) {
     200              :    // Final argument is function pointer that python lib doesn't need.
     201            0 :    return bm_request_event(buffer_handle, event_id, trigger_mask, sampling_type, request_id, 0);
     202              : }
     203              : 
     204            0 : INT c_cm_check_deferred_transition(void) {
     205            0 :    return cm_check_deferred_transition();
     206              : }
     207              : 
     208            0 : INT c_cm_connect_client(const char *client_name, HNDLE * hConn) {
     209            0 :    return cm_connect_client(client_name, hConn);
     210              : }
     211              : 
     212            0 : INT c_cm_connect_experiment(const char *host_name, const char *exp_name, const char *client_name, void (*func) (char *)) {
     213            0 :    return cm_connect_experiment(host_name, exp_name, client_name, func);
     214              : }
     215              : 
     216            0 : INT c_cm_deregister_transition(INT transition) {
     217            0 :    return cm_deregister_transition(transition);
     218              : }
     219              : 
     220            0 : INT c_cm_disconnect_client(HNDLE hConn, BOOL bShutdown) {
     221            0 :    return cm_disconnect_client(hConn, bShutdown);
     222              : }
     223              : 
     224            0 : INT c_cm_disconnect_experiment() {
     225            0 :    return cm_disconnect_experiment();
     226              : }
     227              : 
     228            0 : INT c_cm_exist(const char *name, BOOL bUnique) {
     229            0 :    return cm_exist(name, bUnique);
     230              : }
     231              : 
     232            0 : INT c_cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size) {
     233            0 :    return cm_get_environment(host_name, host_name_size, exp_name, exp_name_size);
     234              : }
     235              : 
     236            0 : INT c_cm_get_experiment_database(HNDLE * hDB, HNDLE * hKeyClient) {
     237            0 :    return cm_get_experiment_database(hDB, hKeyClient);
     238              : }
     239              : 
     240            0 : INT c_cm_get_path(char *path, int path_size) {
     241            0 :    std::string str_path = cm_get_path();
     242            0 :    return copy_string_to_c(str_path, path, path_size);
     243            0 : }
     244              : 
     245            0 : const char* c_cm_get_revision(void) {
     246              :    // If this changes to returning a string, do:
     247              :    // return strdup(cm_get_revision().c_str());
     248            0 :    return cm_get_revision();
     249              : }
     250              : 
     251            0 : const char* c_cm_get_version(void) {
     252              :    // If this changes to returning a string, do:
     253              :    // return strdup(cm_get_version().c_str());
     254            0 :    return cm_get_version();
     255              : }
     256              : 
     257            0 : INT c_cm_msg(INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format, ...) {
     258              :    va_list argptr;
     259              :    char message[1000];
     260            0 :    va_start(argptr, format);
     261            0 :    vsnprintf(message, 1000, (char *) format, argptr);
     262            0 :    va_end(argptr);
     263            0 :    return cm_msg1(message_type, filename, line, facility, routine, "%s", message);
     264              : }
     265              : 
     266              : /*
     267              : Remember to call c_free_list on the dest afterwards. E.g.:
     268              : ```
     269              : import ctypes
     270              : import midas.client
     271              : lib = midas.client.MidasClient("pytest").lib
     272              : 
     273              : arr = ctypes.POINTER(ctypes.c_char_p)()
     274              : arr_len = ctypes.c_int()
     275              : lib.c_cm_msg_facilities(ctypes.byref(arr), ctypes.byref(arr_len))
     276              : casted = ctypes.cast(arr, ctypes.POINTER(ctypes.c_char_p))
     277              : py_list = [casted[i].decode("utf-8") for i in range(arr_len.value)]
     278              : lib.c_free_list(arr, arr_len)
     279              : ```
     280              : */
     281            0 : INT c_cm_msg_facilities(char*** dest, int& dest_len) {
     282            0 :    std::vector<std::string> retvec;
     283            0 :    INT retcode = cm_msg_facilities(&retvec);
     284            0 :    if (retcode == SUCCESS) {
     285            0 :       return copy_vector_string_to_c(retvec, dest, dest_len);
     286              :    } else {
     287            0 :       return retcode;
     288              :    }
     289            0 : }
     290              : 
     291            0 : INT c_cm_msg_register(EVENT_HANDLER *func) {
     292            0 :    return cm_msg_register(func);
     293              : }
     294              : 
     295            0 : INT c_cm_msg_retrieve2(const char *facility, uint64_t before, INT min_messages, char **messages, int *num_messages_read) {
     296              :    // Python ctypes doesn't know the size of time_t, so just accept a uint64_t and convert here.
     297            0 :    time_t t = before;
     298            0 :    INT retval = cm_msg_retrieve2(facility, t, min_messages, messages, num_messages_read);
     299            0 :    return retval;
     300              : }
     301              : 
     302            0 : INT c_cm_msg_open_buffer() {
     303            0 :    return cm_msg_open_buffer();
     304              : }
     305              : 
     306            0 : INT c_cm_msg_close_buffer() {
     307            0 :    return cm_msg_close_buffer();
     308              : }
     309              : 
     310            0 : INT c_cm_register_deferred_transition(INT transition, BOOL(*func) (INT, BOOL)) {
     311            0 :    return cm_register_deferred_transition(transition, func);
     312              : }
     313              : 
     314            0 : INT c_cm_register_function(INT id, INT(*func) (INT, void **)) {
     315            0 :    return cm_register_function(id, func);
     316              : }
     317              : 
     318            0 : INT c_cm_register_transition(INT transition, INT(*func) (INT, char *), int sequence_number) {
     319            0 :    return cm_register_transition(transition, func, sequence_number);
     320              : }
     321              : 
     322            0 : INT c_cm_set_transition_sequence(INT transition, INT sequence_number) {
     323            0 :    return cm_set_transition_sequence(transition, sequence_number);
     324              : }
     325              : 
     326            0 : INT c_cm_shutdown(const char *name, BOOL bUnique) {
     327            0 :    return cm_shutdown(name, bUnique);
     328              : }
     329              : 
     330            0 : INT c_cm_start_watchdog_thread(void) {
     331            0 :    return cm_start_watchdog_thread();
     332              : }
     333              : 
     334            0 : INT c_cm_stop_watchdog_thread(void) {
     335            0 :    return cm_stop_watchdog_thread();
     336              : }
     337              : 
     338            0 : INT c_cm_transition(INT transition, INT run_number, char *error, INT strsize, INT async_flag, INT debug_flag) {
     339            0 :    return cm_transition(transition, run_number, error, strsize, async_flag, debug_flag);
     340              : }
     341              : 
     342            0 : INT c_cm_yield(INT millisec) {
     343            0 :    return cm_yield(millisec);
     344              : }
     345              : 
     346            0 : INT c_db_close_record(HNDLE hdb, HNDLE hkey) {
     347            0 :    return db_close_record(hdb, hkey);
     348              : }
     349              : 
     350            0 : INT c_db_copy_json_ls(HNDLE hDB, HNDLE hKey, char **buffer, int* buffer_size, int* buffer_end) {
     351            0 :    return db_copy_json_ls(hDB, hKey, buffer, buffer_size, buffer_end);
     352              : }
     353              : 
     354            0 : INT c_db_copy_json_save(HNDLE hDB, HNDLE hKey, char **buffer, int* buffer_size, int* buffer_end) {
     355            0 :    return db_copy_json_save(hDB, hKey, buffer, buffer_size, buffer_end);
     356              : }
     357              : 
     358            0 : INT c_db_create_key(HNDLE hdb, HNDLE key_handle, const char *key_name, DWORD type) {
     359            0 :    return db_create_key(hdb, key_handle, key_name, type);
     360              : }
     361              : 
     362            0 : INT c_db_create_link(HNDLE hdb, HNDLE key_handle, const char *link_name, const char *destination) {
     363            0 :    return db_create_link(hdb, key_handle, link_name, destination);
     364              : }
     365              : 
     366            0 : INT c_db_delete_key(HNDLE database_handle, HNDLE key_handle, BOOL follow_links) {
     367            0 :    return db_delete_key(database_handle, key_handle, follow_links);
     368              : }
     369              : 
     370            0 : INT c_db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE * subkey_handle) {
     371            0 :         return db_enum_key(hDB, hKey, idx, subkey_handle);
     372              : }
     373              : 
     374            0 : INT c_db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE * subkey_handle) {
     375            0 :    return db_enum_link(hDB, hKey, idx, subkey_handle);
     376              : }
     377              : 
     378            0 : INT c_db_find_key(HNDLE hdb, HNDLE hkey, const char *name, HNDLE * hsubkey) {
     379            0 :    return db_find_key(hdb, hkey, name, hsubkey);
     380              : }
     381              : 
     382            0 : INT c_db_find_link(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE * subhKey) {
     383            0 :    return db_find_link(hDB, hKey, key_name, subhKey);
     384              : }
     385              : 
     386            0 : INT c_db_get_key(HNDLE hdb, HNDLE key_handle, KEY * key) {
     387            0 :    return db_get_key(hdb, key_handle, key);
     388              : }
     389              : 
     390            0 : INT c_db_get_link_data(HNDLE hdb, HNDLE key_handle, void *data, INT * buf_size, DWORD type) {
     391            0 :    return db_get_link_data(hdb, key_handle, data, buf_size, type);
     392              : }
     393              : 
     394            0 : INT c_db_get_parent(HNDLE hDB, HNDLE hKey, HNDLE * parenthKey) {
     395            0 :    return db_get_parent(hDB, hKey, parenthKey);
     396              : }
     397              : 
     398            0 : INT c_db_get_value(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, void *data, INT * size, DWORD type, BOOL create) {
     399            0 :    return db_get_value(hdb, hKeyRoot, key_name, data, size, type, create);
     400              : }
     401              : 
     402            0 : INT c_db_open_record(HNDLE hdb, HNDLE hkey, void *ptr, INT rec_size, WORD access, void (*dispatcher) (INT, INT, void *), void *info) {
     403            0 :    return db_open_record(hdb, hkey, ptr, rec_size, access, dispatcher, info);
     404              : }
     405              : 
     406            0 : INT c_db_rename_key(HNDLE hDB, HNDLE hKey, const char *name) {
     407            0 :    return db_rename_key(hDB, hKey, name);
     408              : }
     409              : 
     410            0 : INT c_db_reorder_key(HNDLE hDB, HNDLE hKey, INT index) {
     411            0 :    return db_reorder_key(hDB, hKey, index);
     412              : }
     413              : 
     414            0 : INT c_db_resize_string(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, int num_values, int max_string_size) {
     415            0 :    return db_resize_string(hDB, hKeyRoot, key_name, num_values, max_string_size);
     416              : }
     417              : 
     418            0 : INT c_db_set_link_data(HNDLE hdb, HNDLE key_handle, void *data, INT buf_size, int num_values, DWORD type) {
     419            0 :    return db_set_link_data(hdb, key_handle, data, buf_size, num_values, type);
     420              : }
     421              : 
     422            0 : INT c_db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values) {
     423            0 :    return db_set_num_values(hDB, hKey, num_values);
     424              : }
     425              : 
     426            0 : INT c_db_set_data(HNDLE hdb, HNDLE hKeyRoot, const void *data, INT size, INT num_values, DWORD type) {
     427            0 :    return db_set_data(hdb, hKeyRoot, data, size, num_values, type);
     428              : }
     429              : 
     430            0 : INT c_db_set_value(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, const void *data, INT size, INT num_values, DWORD type) {
     431            0 :    return db_set_value(hdb, hKeyRoot, key_name, data, size, num_values, type);
     432              : }
     433              : 
     434            0 : INT c_db_set_value_index(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT index, DWORD type, BOOL truncate) {
     435            0 :    return db_set_value_index(hDB, hKeyRoot, key_name, data, data_size, index, type, truncate);
     436              : }
     437              : 
     438            0 : INT c_db_unwatch(HNDLE hDB, HNDLE hKey) {
     439            0 :    return db_unwatch(hDB, hKey);
     440              : }
     441              : 
     442            0 : INT c_db_watch(HNDLE hDB, HNDLE hKey, void (*dispatcher) (INT, INT, INT, void*), void* info) {
     443            0 :    return db_watch(hDB, hKey, dispatcher, info);
     444              : }
     445              : 
     446            0 : INT c_jrpc_client_call(HNDLE hconn, char* cmd, char* args, char* buf, int buf_length) {
     447              :    // Specialized version of rpc_client_call that just deals with RPC_JRPC,
     448              :    // so we don't have to worry about variable arg lists.
     449              :    // You must already have malloc'd buf to be big enough for buf_length.
     450            0 :    return rpc_client_call(hconn, RPC_JRPC, cmd, args, buf, buf_length);
     451              : }
     452              : 
     453            0 : INT c_brpc_client_call(HNDLE hconn, char* cmd, char* args, char* buf, int& buf_length) {
     454              :    // Specialized version of rpc_client_call that just deals with RPC_BRPC,
     455              :    // so we don't have to worry about variable arg lists.
     456              :    // You must already have malloc'd buf to be big enough for buf_length.
     457            0 :    return rpc_client_call(hconn, RPC_BRPC, cmd, args, buf, &buf_length);
     458              : }
     459              : 
     460            0 : INT c_rpc_flush_event(void) {
     461            0 :    return rpc_flush_event();
     462              : }
     463              : 
     464            0 : INT c_rpc_is_remote(void) {
     465            0 :         return rpc_is_remote();
     466              : }
     467              : 
     468            0 : INT c_rpc_send_event(INT buffer_handle, const EVENT_HEADER *event, INT buf_size, INT async_flag, INT mode) {
     469            0 :    return rpc_send_event(buffer_handle, event, buf_size, async_flag, mode);
     470              : }
     471              : 
     472            0 : INT c_rpc_server_shutdown() {
     473            0 :    return rpc_server_shutdown();
     474              : }
     475              : 
     476            0 : INT c_ss_daemon_init(BOOL keep_stdout) {
     477            0 :    return ss_daemon_init(keep_stdout);
     478              : }
     479              : 
     480            0 : INT c_ss_exec(char* cmd, INT* child_pid) {
     481            0 :    return ss_exec(cmd, child_pid);
     482              : }
     483              : 
     484            0 : INT c_ss_suspend_reset_server_acceptions() {
     485            0 :    return ss_suspend_set_server_acceptions(nullptr);
     486              : }
     487              : 
     488              : MidasHistoryInterface* mh = nullptr;
     489              : 
     490            0 : INT c_connect_history_if_needed(HNDLE hDB, bool debug=false) {
     491            0 :    INT status = SUCCESS;
     492              : 
     493            0 :    if (mh == nullptr) {
     494            0 :       status = hs_get_history(hDB, 0, HS_GET_DEFAULT|HS_GET_READER|HS_GET_INACTIVE, debug, &mh);
     495              :    }
     496              : 
     497            0 :    return status;
     498              : }
     499              : 
     500            0 : INT c_hs_get_events(HNDLE hDB, char*** dest, int& dest_len) {
     501            0 :    INT status = c_connect_history_if_needed(hDB);
     502              : 
     503            0 :    if (status != SUCCESS) {
     504            0 :       return status;
     505              :    }
     506              : 
     507            0 :    time_t t = 0;
     508            0 :    std::vector<std::string> events;
     509              : 
     510            0 :    status = mh->hs_get_events(t, &events);
     511              : 
     512            0 :    if (status != SUCCESS) {
     513            0 :       return status;
     514              :    }
     515              : 
     516            0 :    return copy_vector_string_to_c(events, dest, dest_len);
     517            0 : }
     518              :  
     519            0 : INT c_hs_get_tags(HNDLE hDB, char* event_name, char*** dest_names, void** dest_types, void** dest_n_data, int& dest_len) {     
     520            0 :    INT status = c_connect_history_if_needed(hDB);
     521              : 
     522            0 :    if (status != SUCCESS) {
     523            0 :       return status;
     524              :    }
     525              :    
     526            0 :    time_t t = 0;
     527            0 :    std::vector<TAG> tags;
     528            0 :    status = mh->hs_get_tags(event_name, t, &tags);
     529              : 
     530            0 :    if (status != SUCCESS) {
     531            0 :       return status;
     532              :    }
     533              : 
     534            0 :    std::vector<std::string> tag_names;
     535            0 :    std::vector<DWORD> tag_types;
     536            0 :    std::vector<DWORD> tag_n_data;
     537              : 
     538            0 :    for (auto& tag : tags) {
     539            0 :       tag_names.push_back(tag.name);
     540            0 :       tag_types.push_back(tag.type);
     541            0 :       tag_n_data.push_back(tag.n_data);
     542              :    }
     543              : 
     544            0 :    copy_vector_string_to_c(tag_names, dest_names, dest_len);
     545            0 :    copy_vector_to_c(tag_types, dest_types, dest_len);
     546            0 :    copy_vector_to_c(tag_n_data, dest_n_data, dest_len);
     547            0 :    return SUCCESS;
     548            0 : }
     549              : 
     550            0 : INT c_hs_read(HNDLE hDB, 
     551              :               uint32_t start_time, uint32_t end_time, uint32_t interval_secs, 
     552              :               char* event_name, char* tag_name, int idx_start, int nvars,
     553              :               void** num_entries, void** times, void** values, void** hs_status) {
     554              :    // Note this function varies from hs_read() for the times/tbuffer and values/vbuffer
     555              :    // parameters! To simplify passing between python/C, we concatenate all the data for
     556              :    // all variables into one array, rather than using a 2D array.
     557              :    // So num_entries and hs_status are length "nvars", while 
     558              :    // times and values are length "sum of num_entries".
     559            0 :    INT status = c_connect_history_if_needed(hDB);
     560              : 
     561            0 :    if (status != SUCCESS) {
     562            0 :       return status;
     563              :    }
     564              : 
     565            0 :    const char** event_names = (const char**)calloc(nvars, sizeof(const char*));
     566            0 :    const char** var_names = (const char**)calloc(nvars, sizeof(const char*));
     567            0 :    int* indices = (int*)calloc(nvars, sizeof(int));
     568              : 
     569            0 :    for (int i = 0; i < nvars; i++) {
     570            0 :       event_names[i] = event_name;
     571            0 :       var_names[i] = tag_name;
     572            0 :       indices[i] = idx_start + i;
     573              :    }
     574              : 
     575            0 :    *num_entries = calloc(nvars, sizeof(int));
     576            0 :    time_t** tbuffer_int = (time_t**)calloc(nvars, sizeof(time_t*));
     577            0 :    double** vbuffer_int = (double**)calloc(nvars, sizeof(double*));
     578            0 :    *hs_status = calloc(nvars, sizeof(int));
     579              : 
     580            0 :    status = mh->hs_read(start_time, end_time, interval_secs, nvars, event_names, var_names, indices, (int*)*num_entries, tbuffer_int, vbuffer_int, (int*)*hs_status);
     581              : 
     582              :    // Simplify passing back to python by concatenating timestamp buffers into
     583              :    // a single buffer rather than 2-D array. Same for value buffers.
     584            0 :    size_t tot_len = 0;
     585              : 
     586            0 :    for (int i = 0; i < nvars; i++) {
     587            0 :       tot_len += ((int*)(*num_entries))[i];
     588              :    }
     589              : 
     590            0 :    if (tot_len > 0) {
     591            0 :       *times = calloc(tot_len, sizeof(uint32_t));
     592            0 :       *values = calloc(tot_len, sizeof(double));
     593              : 
     594            0 :       uint32_t* cast_tbuffer = (uint32_t*)*times;
     595            0 :       double* cast_vbuffer = (double*)*values;
     596            0 :       size_t offset = 0;
     597              : 
     598            0 :       for (int i = 0; i < nvars; i++) {
     599            0 :          size_t this_n = ((int*)(*num_entries))[i];
     600            0 :          for (int n = 0; n < (int) this_n; n++) {
     601              :             // Deal with time_t vs uint32_t possibly being different sizes
     602              :             // by manually copying values rather than doing a memcpy.
     603            0 :             cast_tbuffer[offset+n] = tbuffer_int[i][n];
     604            0 :             cast_vbuffer[offset+n] = vbuffer_int[i][n];
     605              :          }
     606              :       
     607            0 :          offset += this_n;
     608              :       }
     609              :    }
     610              : 
     611            0 :    free(tbuffer_int);
     612            0 :    free(vbuffer_int);
     613            0 :    free(event_names);
     614            0 :    free(var_names);
     615            0 :    free(indices);
     616              : 
     617            0 :    return status;
     618              : }
        

Generated by: LCOV version 2.0-1